18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NXP SC18IS602/603 SPI driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) Guenter Roeck <linux@roeck-us.net> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_data/sc18is602.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cienum chips { sc18is602, sc18is602b, sc18is603 }; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SC18IS602_BUFSIZ 200 238c2ecf20Sopenharmony_ci#define SC18IS602_CLOCK 7372000 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define SC18IS602_MODE_CPHA BIT(2) 268c2ecf20Sopenharmony_ci#define SC18IS602_MODE_CPOL BIT(3) 278c2ecf20Sopenharmony_ci#define SC18IS602_MODE_LSB_FIRST BIT(5) 288c2ecf20Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_4 0x0 298c2ecf20Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_16 0x1 308c2ecf20Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_64 0x2 318c2ecf20Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_128 0x3 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct sc18is602 { 348c2ecf20Sopenharmony_ci struct spi_master *master; 358c2ecf20Sopenharmony_ci struct device *dev; 368c2ecf20Sopenharmony_ci u8 ctrl; 378c2ecf20Sopenharmony_ci u32 freq; 388c2ecf20Sopenharmony_ci u32 speed; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* I2C data */ 418c2ecf20Sopenharmony_ci struct i2c_client *client; 428c2ecf20Sopenharmony_ci enum chips id; 438c2ecf20Sopenharmony_ci u8 buffer[SC18IS602_BUFSIZ + 1]; 448c2ecf20Sopenharmony_ci int tlen; /* Data queued for tx in buffer */ 458c2ecf20Sopenharmony_ci int rindex; /* Receive data index in buffer */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci struct gpio_desc *reset; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int sc18is602_wait_ready(struct sc18is602 *hw, int len) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci int i, err; 538c2ecf20Sopenharmony_ci int usecs = 1000000 * len / hw->speed + 1; 548c2ecf20Sopenharmony_ci u8 dummy[1]; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 578c2ecf20Sopenharmony_ci err = i2c_master_recv(hw->client, dummy, 1); 588c2ecf20Sopenharmony_ci if (err >= 0) 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci usleep_range(usecs, usecs * 2); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci return -ETIMEDOUT; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg, 668c2ecf20Sopenharmony_ci struct spi_transfer *t, bool do_transfer) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci unsigned int len = t->len; 698c2ecf20Sopenharmony_ci int ret; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (hw->tlen == 0) { 728c2ecf20Sopenharmony_ci /* First byte (I2C command) is chip select */ 738c2ecf20Sopenharmony_ci hw->buffer[0] = 1 << msg->spi->chip_select; 748c2ecf20Sopenharmony_ci hw->tlen = 1; 758c2ecf20Sopenharmony_ci hw->rindex = 0; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * We can not immediately send data to the chip, since each I2C message 798c2ecf20Sopenharmony_ci * resembles a full SPI message (from CS active to CS inactive). 808c2ecf20Sopenharmony_ci * Enqueue messages up to the first read or until do_transfer is true. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci if (t->tx_buf) { 838c2ecf20Sopenharmony_ci memcpy(&hw->buffer[hw->tlen], t->tx_buf, len); 848c2ecf20Sopenharmony_ci hw->tlen += len; 858c2ecf20Sopenharmony_ci if (t->rx_buf) 868c2ecf20Sopenharmony_ci do_transfer = true; 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci hw->rindex = hw->tlen - 1; 898c2ecf20Sopenharmony_ci } else if (t->rx_buf) { 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * For receive-only transfers we still need to perform a dummy 928c2ecf20Sopenharmony_ci * write to receive data from the SPI chip. 938c2ecf20Sopenharmony_ci * Read data starts at the end of transmit data (minus 1 to 948c2ecf20Sopenharmony_ci * account for CS). 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci hw->rindex = hw->tlen - 1; 978c2ecf20Sopenharmony_ci memset(&hw->buffer[hw->tlen], 0, len); 988c2ecf20Sopenharmony_ci hw->tlen += len; 998c2ecf20Sopenharmony_ci do_transfer = true; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (do_transfer && hw->tlen > 1) { 1038c2ecf20Sopenharmony_ci ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ); 1048c2ecf20Sopenharmony_ci if (ret < 0) 1058c2ecf20Sopenharmony_ci return ret; 1068c2ecf20Sopenharmony_ci ret = i2c_master_send(hw->client, hw->buffer, hw->tlen); 1078c2ecf20Sopenharmony_ci if (ret < 0) 1088c2ecf20Sopenharmony_ci return ret; 1098c2ecf20Sopenharmony_ci if (ret != hw->tlen) 1108c2ecf20Sopenharmony_ci return -EIO; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (t->rx_buf) { 1138c2ecf20Sopenharmony_ci int rlen = hw->rindex + len; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ret = sc18is602_wait_ready(hw, hw->tlen); 1168c2ecf20Sopenharmony_ci if (ret < 0) 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci ret = i2c_master_recv(hw->client, hw->buffer, rlen); 1198c2ecf20Sopenharmony_ci if (ret < 0) 1208c2ecf20Sopenharmony_ci return ret; 1218c2ecf20Sopenharmony_ci if (ret != rlen) 1228c2ecf20Sopenharmony_ci return -EIO; 1238c2ecf20Sopenharmony_ci memcpy(t->rx_buf, &hw->buffer[hw->rindex], len); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci hw->tlen = 0; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci return len; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci u8 ctrl = 0; 1338c2ecf20Sopenharmony_ci int ret; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (mode & SPI_CPHA) 1368c2ecf20Sopenharmony_ci ctrl |= SC18IS602_MODE_CPHA; 1378c2ecf20Sopenharmony_ci if (mode & SPI_CPOL) 1388c2ecf20Sopenharmony_ci ctrl |= SC18IS602_MODE_CPOL; 1398c2ecf20Sopenharmony_ci if (mode & SPI_LSB_FIRST) 1408c2ecf20Sopenharmony_ci ctrl |= SC18IS602_MODE_LSB_FIRST; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* Find the closest clock speed */ 1438c2ecf20Sopenharmony_ci if (hz >= hw->freq / 4) { 1448c2ecf20Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_4; 1458c2ecf20Sopenharmony_ci hw->speed = hw->freq / 4; 1468c2ecf20Sopenharmony_ci } else if (hz >= hw->freq / 16) { 1478c2ecf20Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_16; 1488c2ecf20Sopenharmony_ci hw->speed = hw->freq / 16; 1498c2ecf20Sopenharmony_ci } else if (hz >= hw->freq / 64) { 1508c2ecf20Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_64; 1518c2ecf20Sopenharmony_ci hw->speed = hw->freq / 64; 1528c2ecf20Sopenharmony_ci } else { 1538c2ecf20Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_128; 1548c2ecf20Sopenharmony_ci hw->speed = hw->freq / 128; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* 1588c2ecf20Sopenharmony_ci * Don't do anything if the control value did not change. The initial 1598c2ecf20Sopenharmony_ci * value of 0xff for hw->ctrl ensures that the correct mode will be set 1608c2ecf20Sopenharmony_ci * with the first call to this function. 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci if (ctrl == hw->ctrl) 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl); 1668c2ecf20Sopenharmony_ci if (ret < 0) 1678c2ecf20Sopenharmony_ci return ret; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci hw->ctrl = ctrl; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int sc18is602_check_transfer(struct spi_device *spi, 1758c2ecf20Sopenharmony_ci struct spi_transfer *t, int tlen) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if (t && t->len + tlen > SC18IS602_BUFSIZ) 1788c2ecf20Sopenharmony_ci return -EINVAL; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int sc18is602_transfer_one(struct spi_master *master, 1848c2ecf20Sopenharmony_ci struct spi_message *m) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct sc18is602 *hw = spi_master_get_devdata(master); 1878c2ecf20Sopenharmony_ci struct spi_device *spi = m->spi; 1888c2ecf20Sopenharmony_ci struct spi_transfer *t; 1898c2ecf20Sopenharmony_ci int status = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci hw->tlen = 0; 1928c2ecf20Sopenharmony_ci list_for_each_entry(t, &m->transfers, transfer_list) { 1938c2ecf20Sopenharmony_ci bool do_transfer; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci status = sc18is602_check_transfer(spi, t, hw->tlen); 1968c2ecf20Sopenharmony_ci if (status < 0) 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode); 2008c2ecf20Sopenharmony_ci if (status < 0) 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci do_transfer = t->cs_change || list_is_last(&t->transfer_list, 2048c2ecf20Sopenharmony_ci &m->transfers); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (t->len) { 2078c2ecf20Sopenharmony_ci status = sc18is602_txrx(hw, m, t, do_transfer); 2088c2ecf20Sopenharmony_ci if (status < 0) 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci m->actual_length += status; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci status = 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci spi_transfer_delay_exec(t); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci m->status = status; 2178c2ecf20Sopenharmony_ci spi_finalize_current_message(master); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return status; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int sc18is602_setup(struct spi_device *spi) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct sc18is602 *hw = spi_master_get_devdata(spi->master); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* SC18IS602 does not support CS2 */ 2278c2ecf20Sopenharmony_ci if (hw->id == sc18is602 && spi->chip_select == 2) 2288c2ecf20Sopenharmony_ci return -ENXIO; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int sc18is602_probe(struct i2c_client *client, 2348c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 2378c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 2388c2ecf20Sopenharmony_ci struct sc18is602_platform_data *pdata = dev_get_platdata(dev); 2398c2ecf20Sopenharmony_ci struct sc18is602 *hw; 2408c2ecf20Sopenharmony_ci struct spi_master *master; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | 2438c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci master = devm_spi_alloc_master(dev, sizeof(struct sc18is602)); 2478c2ecf20Sopenharmony_ci if (!master) 2488c2ecf20Sopenharmony_ci return -ENOMEM; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci hw = spi_master_get_devdata(master); 2518c2ecf20Sopenharmony_ci i2c_set_clientdata(client, hw); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* assert reset and then release */ 2548c2ecf20Sopenharmony_ci hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 2558c2ecf20Sopenharmony_ci if (IS_ERR(hw->reset)) 2568c2ecf20Sopenharmony_ci return PTR_ERR(hw->reset); 2578c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(hw->reset, 0); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci hw->master = master; 2608c2ecf20Sopenharmony_ci hw->client = client; 2618c2ecf20Sopenharmony_ci hw->dev = dev; 2628c2ecf20Sopenharmony_ci hw->ctrl = 0xff; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (client->dev.of_node) 2658c2ecf20Sopenharmony_ci hw->id = (enum chips)of_device_get_match_data(&client->dev); 2668c2ecf20Sopenharmony_ci else 2678c2ecf20Sopenharmony_ci hw->id = id->driver_data; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci switch (hw->id) { 2708c2ecf20Sopenharmony_ci case sc18is602: 2718c2ecf20Sopenharmony_ci case sc18is602b: 2728c2ecf20Sopenharmony_ci master->num_chipselect = 4; 2738c2ecf20Sopenharmony_ci hw->freq = SC18IS602_CLOCK; 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci case sc18is603: 2768c2ecf20Sopenharmony_ci master->num_chipselect = 2; 2778c2ecf20Sopenharmony_ci if (pdata) { 2788c2ecf20Sopenharmony_ci hw->freq = pdata->clock_frequency; 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci const __be32 *val; 2818c2ecf20Sopenharmony_ci int len; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci val = of_get_property(np, "clock-frequency", &len); 2848c2ecf20Sopenharmony_ci if (val && len >= sizeof(__be32)) 2858c2ecf20Sopenharmony_ci hw->freq = be32_to_cpup(val); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci if (!hw->freq) 2888c2ecf20Sopenharmony_ci hw->freq = SC18IS602_CLOCK; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci master->bus_num = np ? -1 : client->adapter->nr; 2928c2ecf20Sopenharmony_ci master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; 2938c2ecf20Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_MASK(8); 2948c2ecf20Sopenharmony_ci master->setup = sc18is602_setup; 2958c2ecf20Sopenharmony_ci master->transfer_one_message = sc18is602_transfer_one; 2968c2ecf20Sopenharmony_ci master->dev.of_node = np; 2978c2ecf20Sopenharmony_ci master->min_speed_hz = hw->freq / 128; 2988c2ecf20Sopenharmony_ci master->max_speed_hz = hw->freq / 4; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return devm_spi_register_master(dev, master); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const struct i2c_device_id sc18is602_id[] = { 3048c2ecf20Sopenharmony_ci { "sc18is602", sc18is602 }, 3058c2ecf20Sopenharmony_ci { "sc18is602b", sc18is602b }, 3068c2ecf20Sopenharmony_ci { "sc18is603", sc18is603 }, 3078c2ecf20Sopenharmony_ci { } 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sc18is602_id); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic const struct of_device_id sc18is602_of_match[] = { 3128c2ecf20Sopenharmony_ci { 3138c2ecf20Sopenharmony_ci .compatible = "nxp,sc18is602", 3148c2ecf20Sopenharmony_ci .data = (void *)sc18is602 3158c2ecf20Sopenharmony_ci }, 3168c2ecf20Sopenharmony_ci { 3178c2ecf20Sopenharmony_ci .compatible = "nxp,sc18is602b", 3188c2ecf20Sopenharmony_ci .data = (void *)sc18is602b 3198c2ecf20Sopenharmony_ci }, 3208c2ecf20Sopenharmony_ci { 3218c2ecf20Sopenharmony_ci .compatible = "nxp,sc18is603", 3228c2ecf20Sopenharmony_ci .data = (void *)sc18is603 3238c2ecf20Sopenharmony_ci }, 3248c2ecf20Sopenharmony_ci { }, 3258c2ecf20Sopenharmony_ci}; 3268c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sc18is602_of_match); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic struct i2c_driver sc18is602_driver = { 3298c2ecf20Sopenharmony_ci .driver = { 3308c2ecf20Sopenharmony_ci .name = "sc18is602", 3318c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(sc18is602_of_match), 3328c2ecf20Sopenharmony_ci }, 3338c2ecf20Sopenharmony_ci .probe = sc18is602_probe, 3348c2ecf20Sopenharmony_ci .id_table = sc18is602_id, 3358c2ecf20Sopenharmony_ci}; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cimodule_i2c_driver(sc18is602_driver); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SC18IS602/603 SPI Master Driver"); 3408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Guenter Roeck"); 3418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 342