18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2011-2016 Synaptics Incorporated 48c2ecf20Sopenharmony_ci * Copyright (c) 2011 Unixphere 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/rmi.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include "rmi_driver.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define RMI_SPI_DEFAULT_XFER_BUF_SIZE 64 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define RMI_PAGE_SELECT_REGISTER 0x00FF 188c2ecf20Sopenharmony_ci#define RMI_SPI_PAGE(addr) (((addr) >> 8) & 0x80) 198c2ecf20Sopenharmony_ci#define RMI_SPI_XFER_SIZE_LIMIT 255 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define BUFFER_SIZE_INCREMENT 32 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cienum rmi_spi_op { 248c2ecf20Sopenharmony_ci RMI_SPI_WRITE = 0, 258c2ecf20Sopenharmony_ci RMI_SPI_READ, 268c2ecf20Sopenharmony_ci RMI_SPI_V2_READ_UNIFIED, 278c2ecf20Sopenharmony_ci RMI_SPI_V2_READ_SPLIT, 288c2ecf20Sopenharmony_ci RMI_SPI_V2_WRITE, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct rmi_spi_cmd { 328c2ecf20Sopenharmony_ci enum rmi_spi_op op; 338c2ecf20Sopenharmony_ci u16 addr; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct rmi_spi_xport { 378c2ecf20Sopenharmony_ci struct rmi_transport_dev xport; 388c2ecf20Sopenharmony_ci struct spi_device *spi; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci struct mutex page_mutex; 418c2ecf20Sopenharmony_ci int page; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci u8 *rx_buf; 448c2ecf20Sopenharmony_ci u8 *tx_buf; 458c2ecf20Sopenharmony_ci int xfer_buf_size; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci struct spi_transfer *rx_xfers; 488c2ecf20Sopenharmony_ci struct spi_transfer *tx_xfers; 498c2ecf20Sopenharmony_ci int rx_xfer_count; 508c2ecf20Sopenharmony_ci int tx_xfer_count; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int rmi_spi_manage_pools(struct rmi_spi_xport *rmi_spi, int len) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct spi_device *spi = rmi_spi->spi; 568c2ecf20Sopenharmony_ci int buf_size = rmi_spi->xfer_buf_size 578c2ecf20Sopenharmony_ci ? rmi_spi->xfer_buf_size : RMI_SPI_DEFAULT_XFER_BUF_SIZE; 588c2ecf20Sopenharmony_ci struct spi_transfer *xfer_buf; 598c2ecf20Sopenharmony_ci void *buf; 608c2ecf20Sopenharmony_ci void *tmp; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci while (buf_size < len) 638c2ecf20Sopenharmony_ci buf_size *= 2; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (buf_size > RMI_SPI_XFER_SIZE_LIMIT) 668c2ecf20Sopenharmony_ci buf_size = RMI_SPI_XFER_SIZE_LIMIT; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci tmp = rmi_spi->rx_buf; 698c2ecf20Sopenharmony_ci buf = devm_kcalloc(&spi->dev, buf_size, 2, 708c2ecf20Sopenharmony_ci GFP_KERNEL | GFP_DMA); 718c2ecf20Sopenharmony_ci if (!buf) 728c2ecf20Sopenharmony_ci return -ENOMEM; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci rmi_spi->rx_buf = buf; 758c2ecf20Sopenharmony_ci rmi_spi->tx_buf = &rmi_spi->rx_buf[buf_size]; 768c2ecf20Sopenharmony_ci rmi_spi->xfer_buf_size = buf_size; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (tmp) 798c2ecf20Sopenharmony_ci devm_kfree(&spi->dev, tmp); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (rmi_spi->xport.pdata.spi_data.read_delay_us) 828c2ecf20Sopenharmony_ci rmi_spi->rx_xfer_count = buf_size; 838c2ecf20Sopenharmony_ci else 848c2ecf20Sopenharmony_ci rmi_spi->rx_xfer_count = 1; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (rmi_spi->xport.pdata.spi_data.write_delay_us) 878c2ecf20Sopenharmony_ci rmi_spi->tx_xfer_count = buf_size; 888c2ecf20Sopenharmony_ci else 898c2ecf20Sopenharmony_ci rmi_spi->tx_xfer_count = 1; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * Allocate a pool of spi_transfer buffers for devices which need 938c2ecf20Sopenharmony_ci * per byte delays. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci tmp = rmi_spi->rx_xfers; 968c2ecf20Sopenharmony_ci xfer_buf = devm_kcalloc(&spi->dev, 978c2ecf20Sopenharmony_ci rmi_spi->rx_xfer_count + rmi_spi->tx_xfer_count, 988c2ecf20Sopenharmony_ci sizeof(struct spi_transfer), 998c2ecf20Sopenharmony_ci GFP_KERNEL); 1008c2ecf20Sopenharmony_ci if (!xfer_buf) 1018c2ecf20Sopenharmony_ci return -ENOMEM; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci rmi_spi->rx_xfers = xfer_buf; 1048c2ecf20Sopenharmony_ci rmi_spi->tx_xfers = &xfer_buf[rmi_spi->rx_xfer_count]; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (tmp) 1078c2ecf20Sopenharmony_ci devm_kfree(&spi->dev, tmp); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi, 1138c2ecf20Sopenharmony_ci const struct rmi_spi_cmd *cmd, const u8 *tx_buf, 1148c2ecf20Sopenharmony_ci int tx_len, u8 *rx_buf, int rx_len) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct spi_device *spi = rmi_spi->spi; 1178c2ecf20Sopenharmony_ci struct rmi_device_platform_data_spi *spi_data = 1188c2ecf20Sopenharmony_ci &rmi_spi->xport.pdata.spi_data; 1198c2ecf20Sopenharmony_ci struct spi_message msg; 1208c2ecf20Sopenharmony_ci struct spi_transfer *xfer; 1218c2ecf20Sopenharmony_ci int ret = 0; 1228c2ecf20Sopenharmony_ci int len; 1238c2ecf20Sopenharmony_ci int cmd_len = 0; 1248c2ecf20Sopenharmony_ci int total_tx_len; 1258c2ecf20Sopenharmony_ci int i; 1268c2ecf20Sopenharmony_ci u16 addr = cmd->addr; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci spi_message_init(&msg); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci switch (cmd->op) { 1318c2ecf20Sopenharmony_ci case RMI_SPI_WRITE: 1328c2ecf20Sopenharmony_ci case RMI_SPI_READ: 1338c2ecf20Sopenharmony_ci cmd_len += 2; 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci case RMI_SPI_V2_READ_UNIFIED: 1368c2ecf20Sopenharmony_ci case RMI_SPI_V2_READ_SPLIT: 1378c2ecf20Sopenharmony_ci case RMI_SPI_V2_WRITE: 1388c2ecf20Sopenharmony_ci cmd_len += 4; 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci total_tx_len = cmd_len + tx_len; 1438c2ecf20Sopenharmony_ci len = max(total_tx_len, rx_len); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (len > RMI_SPI_XFER_SIZE_LIMIT) 1468c2ecf20Sopenharmony_ci return -EINVAL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (rmi_spi->xfer_buf_size < len) { 1498c2ecf20Sopenharmony_ci ret = rmi_spi_manage_pools(rmi_spi, len); 1508c2ecf20Sopenharmony_ci if (ret < 0) 1518c2ecf20Sopenharmony_ci return ret; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (addr == 0) 1558c2ecf20Sopenharmony_ci /* 1568c2ecf20Sopenharmony_ci * SPI needs an address. Use 0x7FF if we want to keep 1578c2ecf20Sopenharmony_ci * reading from the last position of the register pointer. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci addr = 0x7FF; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci switch (cmd->op) { 1628c2ecf20Sopenharmony_ci case RMI_SPI_WRITE: 1638c2ecf20Sopenharmony_ci rmi_spi->tx_buf[0] = (addr >> 8); 1648c2ecf20Sopenharmony_ci rmi_spi->tx_buf[1] = addr & 0xFF; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci case RMI_SPI_READ: 1678c2ecf20Sopenharmony_ci rmi_spi->tx_buf[0] = (addr >> 8) | 0x80; 1688c2ecf20Sopenharmony_ci rmi_spi->tx_buf[1] = addr & 0xFF; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case RMI_SPI_V2_READ_UNIFIED: 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci case RMI_SPI_V2_READ_SPLIT: 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci case RMI_SPI_V2_WRITE: 1758c2ecf20Sopenharmony_ci rmi_spi->tx_buf[0] = 0x40; 1768c2ecf20Sopenharmony_ci rmi_spi->tx_buf[1] = (addr >> 8) & 0xFF; 1778c2ecf20Sopenharmony_ci rmi_spi->tx_buf[2] = addr & 0xFF; 1788c2ecf20Sopenharmony_ci rmi_spi->tx_buf[3] = tx_len; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (tx_buf) 1838c2ecf20Sopenharmony_ci memcpy(&rmi_spi->tx_buf[cmd_len], tx_buf, tx_len); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (rmi_spi->tx_xfer_count > 1) { 1868c2ecf20Sopenharmony_ci for (i = 0; i < total_tx_len; i++) { 1878c2ecf20Sopenharmony_ci xfer = &rmi_spi->tx_xfers[i]; 1888c2ecf20Sopenharmony_ci memset(xfer, 0, sizeof(struct spi_transfer)); 1898c2ecf20Sopenharmony_ci xfer->tx_buf = &rmi_spi->tx_buf[i]; 1908c2ecf20Sopenharmony_ci xfer->len = 1; 1918c2ecf20Sopenharmony_ci xfer->delay_usecs = spi_data->write_delay_us; 1928c2ecf20Sopenharmony_ci spi_message_add_tail(xfer, &msg); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci } else { 1958c2ecf20Sopenharmony_ci xfer = rmi_spi->tx_xfers; 1968c2ecf20Sopenharmony_ci memset(xfer, 0, sizeof(struct spi_transfer)); 1978c2ecf20Sopenharmony_ci xfer->tx_buf = rmi_spi->tx_buf; 1988c2ecf20Sopenharmony_ci xfer->len = total_tx_len; 1998c2ecf20Sopenharmony_ci spi_message_add_tail(xfer, &msg); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_XPORT, &spi->dev, "%s: cmd: %s tx_buf len: %d tx_buf: %*ph\n", 2038c2ecf20Sopenharmony_ci __func__, cmd->op == RMI_SPI_WRITE ? "WRITE" : "READ", 2048c2ecf20Sopenharmony_ci total_tx_len, total_tx_len, rmi_spi->tx_buf); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (rx_buf) { 2078c2ecf20Sopenharmony_ci if (rmi_spi->rx_xfer_count > 1) { 2088c2ecf20Sopenharmony_ci for (i = 0; i < rx_len; i++) { 2098c2ecf20Sopenharmony_ci xfer = &rmi_spi->rx_xfers[i]; 2108c2ecf20Sopenharmony_ci memset(xfer, 0, sizeof(struct spi_transfer)); 2118c2ecf20Sopenharmony_ci xfer->rx_buf = &rmi_spi->rx_buf[i]; 2128c2ecf20Sopenharmony_ci xfer->len = 1; 2138c2ecf20Sopenharmony_ci xfer->delay_usecs = spi_data->read_delay_us; 2148c2ecf20Sopenharmony_ci spi_message_add_tail(xfer, &msg); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci xfer = rmi_spi->rx_xfers; 2188c2ecf20Sopenharmony_ci memset(xfer, 0, sizeof(struct spi_transfer)); 2198c2ecf20Sopenharmony_ci xfer->rx_buf = rmi_spi->rx_buf; 2208c2ecf20Sopenharmony_ci xfer->len = rx_len; 2218c2ecf20Sopenharmony_ci spi_message_add_tail(xfer, &msg); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = spi_sync(spi, &msg); 2268c2ecf20Sopenharmony_ci if (ret < 0) { 2278c2ecf20Sopenharmony_ci dev_err(&spi->dev, "spi xfer failed: %d\n", ret); 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (rx_buf) { 2328c2ecf20Sopenharmony_ci memcpy(rx_buf, rmi_spi->rx_buf, rx_len); 2338c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_XPORT, &spi->dev, "%s: (%d) %*ph\n", 2348c2ecf20Sopenharmony_ci __func__, rx_len, rx_len, rx_buf); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* 2418c2ecf20Sopenharmony_ci * rmi_set_page - Set RMI page 2428c2ecf20Sopenharmony_ci * @xport: The pointer to the rmi_transport_dev struct 2438c2ecf20Sopenharmony_ci * @page: The new page address. 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * RMI devices have 16-bit addressing, but some of the transport 2468c2ecf20Sopenharmony_ci * implementations (like SMBus) only have 8-bit addressing. So RMI implements 2478c2ecf20Sopenharmony_ci * a page address at 0xff of every page so we can reliable page addresses 2488c2ecf20Sopenharmony_ci * every 256 registers. 2498c2ecf20Sopenharmony_ci * 2508c2ecf20Sopenharmony_ci * The page_mutex lock must be held when this function is entered. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * Returns zero on success, non-zero on failure. 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic int rmi_set_page(struct rmi_spi_xport *rmi_spi, u8 page) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct rmi_spi_cmd cmd; 2578c2ecf20Sopenharmony_ci int ret; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci cmd.op = RMI_SPI_WRITE; 2608c2ecf20Sopenharmony_ci cmd.addr = RMI_PAGE_SELECT_REGISTER; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ret = rmi_spi_xfer(rmi_spi, &cmd, &page, 1, NULL, 0); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (ret) 2658c2ecf20Sopenharmony_ci rmi_spi->page = page; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return ret; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int rmi_spi_write_block(struct rmi_transport_dev *xport, u16 addr, 2718c2ecf20Sopenharmony_ci const void *buf, size_t len) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi = 2748c2ecf20Sopenharmony_ci container_of(xport, struct rmi_spi_xport, xport); 2758c2ecf20Sopenharmony_ci struct rmi_spi_cmd cmd; 2768c2ecf20Sopenharmony_ci int ret; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci mutex_lock(&rmi_spi->page_mutex); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (RMI_SPI_PAGE(addr) != rmi_spi->page) { 2818c2ecf20Sopenharmony_ci ret = rmi_set_page(rmi_spi, RMI_SPI_PAGE(addr)); 2828c2ecf20Sopenharmony_ci if (ret) 2838c2ecf20Sopenharmony_ci goto exit; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci cmd.op = RMI_SPI_WRITE; 2878c2ecf20Sopenharmony_ci cmd.addr = addr; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ret = rmi_spi_xfer(rmi_spi, &cmd, buf, len, NULL, 0); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciexit: 2928c2ecf20Sopenharmony_ci mutex_unlock(&rmi_spi->page_mutex); 2938c2ecf20Sopenharmony_ci return ret; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int rmi_spi_read_block(struct rmi_transport_dev *xport, u16 addr, 2978c2ecf20Sopenharmony_ci void *buf, size_t len) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi = 3008c2ecf20Sopenharmony_ci container_of(xport, struct rmi_spi_xport, xport); 3018c2ecf20Sopenharmony_ci struct rmi_spi_cmd cmd; 3028c2ecf20Sopenharmony_ci int ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci mutex_lock(&rmi_spi->page_mutex); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (RMI_SPI_PAGE(addr) != rmi_spi->page) { 3078c2ecf20Sopenharmony_ci ret = rmi_set_page(rmi_spi, RMI_SPI_PAGE(addr)); 3088c2ecf20Sopenharmony_ci if (ret) 3098c2ecf20Sopenharmony_ci goto exit; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci cmd.op = RMI_SPI_READ; 3138c2ecf20Sopenharmony_ci cmd.addr = addr; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ret = rmi_spi_xfer(rmi_spi, &cmd, NULL, 0, buf, len); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciexit: 3188c2ecf20Sopenharmony_ci mutex_unlock(&rmi_spi->page_mutex); 3198c2ecf20Sopenharmony_ci return ret; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic const struct rmi_transport_ops rmi_spi_ops = { 3238c2ecf20Sopenharmony_ci .write_block = rmi_spi_write_block, 3248c2ecf20Sopenharmony_ci .read_block = rmi_spi_read_block, 3258c2ecf20Sopenharmony_ci}; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 3288c2ecf20Sopenharmony_cistatic int rmi_spi_of_probe(struct spi_device *spi, 3298c2ecf20Sopenharmony_ci struct rmi_device_platform_data *pdata) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct device *dev = &spi->dev; 3328c2ecf20Sopenharmony_ci int retval; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci retval = rmi_of_property_read_u32(dev, 3358c2ecf20Sopenharmony_ci &pdata->spi_data.read_delay_us, 3368c2ecf20Sopenharmony_ci "spi-rx-delay-us", 1); 3378c2ecf20Sopenharmony_ci if (retval) 3388c2ecf20Sopenharmony_ci return retval; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci retval = rmi_of_property_read_u32(dev, 3418c2ecf20Sopenharmony_ci &pdata->spi_data.write_delay_us, 3428c2ecf20Sopenharmony_ci "spi-tx-delay-us", 1); 3438c2ecf20Sopenharmony_ci if (retval) 3448c2ecf20Sopenharmony_ci return retval; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const struct of_device_id rmi_spi_of_match[] = { 3508c2ecf20Sopenharmony_ci { .compatible = "syna,rmi4-spi" }, 3518c2ecf20Sopenharmony_ci {}, 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rmi_spi_of_match); 3548c2ecf20Sopenharmony_ci#else 3558c2ecf20Sopenharmony_cistatic inline int rmi_spi_of_probe(struct spi_device *spi, 3568c2ecf20Sopenharmony_ci struct rmi_device_platform_data *pdata) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci return -ENODEV; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci#endif 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic void rmi_spi_unregister_transport(void *data) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi = data; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci rmi_unregister_transport_device(&rmi_spi->xport); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int rmi_spi_probe(struct spi_device *spi) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi; 3728c2ecf20Sopenharmony_ci struct rmi_device_platform_data *pdata; 3738c2ecf20Sopenharmony_ci struct rmi_device_platform_data *spi_pdata = spi->dev.platform_data; 3748c2ecf20Sopenharmony_ci int error; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) 3778c2ecf20Sopenharmony_ci return -EINVAL; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci rmi_spi = devm_kzalloc(&spi->dev, sizeof(struct rmi_spi_xport), 3808c2ecf20Sopenharmony_ci GFP_KERNEL); 3818c2ecf20Sopenharmony_ci if (!rmi_spi) 3828c2ecf20Sopenharmony_ci return -ENOMEM; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci pdata = &rmi_spi->xport.pdata; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (spi->dev.of_node) { 3878c2ecf20Sopenharmony_ci error = rmi_spi_of_probe(spi, pdata); 3888c2ecf20Sopenharmony_ci if (error) 3898c2ecf20Sopenharmony_ci return error; 3908c2ecf20Sopenharmony_ci } else if (spi_pdata) { 3918c2ecf20Sopenharmony_ci *pdata = *spi_pdata; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (pdata->spi_data.bits_per_word) 3958c2ecf20Sopenharmony_ci spi->bits_per_word = pdata->spi_data.bits_per_word; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (pdata->spi_data.mode) 3988c2ecf20Sopenharmony_ci spi->mode = pdata->spi_data.mode; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci error = spi_setup(spi); 4018c2ecf20Sopenharmony_ci if (error < 0) { 4028c2ecf20Sopenharmony_ci dev_err(&spi->dev, "spi_setup failed!\n"); 4038c2ecf20Sopenharmony_ci return error; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci pdata->irq = spi->irq; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci rmi_spi->spi = spi; 4098c2ecf20Sopenharmony_ci mutex_init(&rmi_spi->page_mutex); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci rmi_spi->xport.dev = &spi->dev; 4128c2ecf20Sopenharmony_ci rmi_spi->xport.proto_name = "spi"; 4138c2ecf20Sopenharmony_ci rmi_spi->xport.ops = &rmi_spi_ops; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci spi_set_drvdata(spi, rmi_spi); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci error = rmi_spi_manage_pools(rmi_spi, RMI_SPI_DEFAULT_XFER_BUF_SIZE); 4188c2ecf20Sopenharmony_ci if (error) 4198c2ecf20Sopenharmony_ci return error; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* 4228c2ecf20Sopenharmony_ci * Setting the page to zero will (a) make sure the PSR is in a 4238c2ecf20Sopenharmony_ci * known state, and (b) make sure we can talk to the device. 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci error = rmi_set_page(rmi_spi, 0); 4268c2ecf20Sopenharmony_ci if (error) { 4278c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to set page select to 0.\n"); 4288c2ecf20Sopenharmony_ci return error; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dev_info(&spi->dev, "registering SPI-connected sensor\n"); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci error = rmi_register_transport_device(&rmi_spi->xport); 4348c2ecf20Sopenharmony_ci if (error) { 4358c2ecf20Sopenharmony_ci dev_err(&spi->dev, "failed to register sensor: %d\n", error); 4368c2ecf20Sopenharmony_ci return error; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci error = devm_add_action_or_reset(&spi->dev, 4408c2ecf20Sopenharmony_ci rmi_spi_unregister_transport, 4418c2ecf20Sopenharmony_ci rmi_spi); 4428c2ecf20Sopenharmony_ci if (error) 4438c2ecf20Sopenharmony_ci return error; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return 0; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4498c2ecf20Sopenharmony_cistatic int rmi_spi_suspend(struct device *dev) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 4528c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); 4538c2ecf20Sopenharmony_ci int ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true); 4568c2ecf20Sopenharmony_ci if (ret) 4578c2ecf20Sopenharmony_ci dev_warn(dev, "Failed to resume device: %d\n", ret); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return ret; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int rmi_spi_resume(struct device *dev) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 4658c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); 4668c2ecf20Sopenharmony_ci int ret; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true); 4698c2ecf20Sopenharmony_ci if (ret) 4708c2ecf20Sopenharmony_ci dev_warn(dev, "Failed to resume device: %d\n", ret); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci#endif 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4778c2ecf20Sopenharmony_cistatic int rmi_spi_runtime_suspend(struct device *dev) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 4808c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); 4818c2ecf20Sopenharmony_ci int ret; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false); 4848c2ecf20Sopenharmony_ci if (ret) 4858c2ecf20Sopenharmony_ci dev_warn(dev, "Failed to resume device: %d\n", ret); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int rmi_spi_runtime_resume(struct device *dev) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 4938c2ecf20Sopenharmony_ci struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); 4948c2ecf20Sopenharmony_ci int ret; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false); 4978c2ecf20Sopenharmony_ci if (ret) 4988c2ecf20Sopenharmony_ci dev_warn(dev, "Failed to resume device: %d\n", ret); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci#endif 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rmi_spi_pm = { 5058c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(rmi_spi_suspend, rmi_spi_resume) 5068c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(rmi_spi_runtime_suspend, rmi_spi_runtime_resume, 5078c2ecf20Sopenharmony_ci NULL) 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic const struct spi_device_id rmi_id[] = { 5118c2ecf20Sopenharmony_ci { "rmi4_spi", 0 }, 5128c2ecf20Sopenharmony_ci { } 5138c2ecf20Sopenharmony_ci}; 5148c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, rmi_id); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic struct spi_driver rmi_spi_driver = { 5178c2ecf20Sopenharmony_ci .driver = { 5188c2ecf20Sopenharmony_ci .name = "rmi4_spi", 5198c2ecf20Sopenharmony_ci .pm = &rmi_spi_pm, 5208c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(rmi_spi_of_match), 5218c2ecf20Sopenharmony_ci }, 5228c2ecf20Sopenharmony_ci .id_table = rmi_id, 5238c2ecf20Sopenharmony_ci .probe = rmi_spi_probe, 5248c2ecf20Sopenharmony_ci}; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cimodule_spi_driver(rmi_spi_driver); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>"); 5298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>"); 5308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RMI SPI driver"); 5318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 532