162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP SC18IS602/603 SPI driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) Guenter Roeck <linux@roeck-us.net> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/spi/spi.h> 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/platform_data/sc18is602.h> 1762306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cienum chips { sc18is602, sc18is602b, sc18is603 }; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define SC18IS602_BUFSIZ 200 2262306a36Sopenharmony_ci#define SC18IS602_CLOCK 7372000 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define SC18IS602_MODE_CPHA BIT(2) 2562306a36Sopenharmony_ci#define SC18IS602_MODE_CPOL BIT(3) 2662306a36Sopenharmony_ci#define SC18IS602_MODE_LSB_FIRST BIT(5) 2762306a36Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_4 0x0 2862306a36Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_16 0x1 2962306a36Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_64 0x2 3062306a36Sopenharmony_ci#define SC18IS602_MODE_CLOCK_DIV_128 0x3 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct sc18is602 { 3362306a36Sopenharmony_ci struct spi_controller *host; 3462306a36Sopenharmony_ci struct device *dev; 3562306a36Sopenharmony_ci u8 ctrl; 3662306a36Sopenharmony_ci u32 freq; 3762306a36Sopenharmony_ci u32 speed; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* I2C data */ 4062306a36Sopenharmony_ci struct i2c_client *client; 4162306a36Sopenharmony_ci enum chips id; 4262306a36Sopenharmony_ci u8 buffer[SC18IS602_BUFSIZ + 1]; 4362306a36Sopenharmony_ci int tlen; /* Data queued for tx in buffer */ 4462306a36Sopenharmony_ci int rindex; /* Receive data index in buffer */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci struct gpio_desc *reset; 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int sc18is602_wait_ready(struct sc18is602 *hw, int len) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci int i, err; 5262306a36Sopenharmony_ci int usecs = 1000000 * len / hw->speed + 1; 5362306a36Sopenharmony_ci u8 dummy[1]; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 5662306a36Sopenharmony_ci err = i2c_master_recv(hw->client, dummy, 1); 5762306a36Sopenharmony_ci if (err >= 0) 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci usleep_range(usecs, usecs * 2); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci return -ETIMEDOUT; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg, 6562306a36Sopenharmony_ci struct spi_transfer *t, bool do_transfer) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci unsigned int len = t->len; 6862306a36Sopenharmony_ci int ret; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (hw->tlen == 0) { 7162306a36Sopenharmony_ci /* First byte (I2C command) is chip select */ 7262306a36Sopenharmony_ci hw->buffer[0] = 1 << spi_get_chipselect(msg->spi, 0); 7362306a36Sopenharmony_ci hw->tlen = 1; 7462306a36Sopenharmony_ci hw->rindex = 0; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * We can not immediately send data to the chip, since each I2C message 7862306a36Sopenharmony_ci * resembles a full SPI message (from CS active to CS inactive). 7962306a36Sopenharmony_ci * Enqueue messages up to the first read or until do_transfer is true. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci if (t->tx_buf) { 8262306a36Sopenharmony_ci memcpy(&hw->buffer[hw->tlen], t->tx_buf, len); 8362306a36Sopenharmony_ci hw->tlen += len; 8462306a36Sopenharmony_ci if (t->rx_buf) 8562306a36Sopenharmony_ci do_transfer = true; 8662306a36Sopenharmony_ci else 8762306a36Sopenharmony_ci hw->rindex = hw->tlen - 1; 8862306a36Sopenharmony_ci } else if (t->rx_buf) { 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * For receive-only transfers we still need to perform a dummy 9162306a36Sopenharmony_ci * write to receive data from the SPI chip. 9262306a36Sopenharmony_ci * Read data starts at the end of transmit data (minus 1 to 9362306a36Sopenharmony_ci * account for CS). 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci hw->rindex = hw->tlen - 1; 9662306a36Sopenharmony_ci memset(&hw->buffer[hw->tlen], 0, len); 9762306a36Sopenharmony_ci hw->tlen += len; 9862306a36Sopenharmony_ci do_transfer = true; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (do_transfer && hw->tlen > 1) { 10262306a36Sopenharmony_ci ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ); 10362306a36Sopenharmony_ci if (ret < 0) 10462306a36Sopenharmony_ci return ret; 10562306a36Sopenharmony_ci ret = i2c_master_send(hw->client, hw->buffer, hw->tlen); 10662306a36Sopenharmony_ci if (ret < 0) 10762306a36Sopenharmony_ci return ret; 10862306a36Sopenharmony_ci if (ret != hw->tlen) 10962306a36Sopenharmony_ci return -EIO; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (t->rx_buf) { 11262306a36Sopenharmony_ci int rlen = hw->rindex + len; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ret = sc18is602_wait_ready(hw, hw->tlen); 11562306a36Sopenharmony_ci if (ret < 0) 11662306a36Sopenharmony_ci return ret; 11762306a36Sopenharmony_ci ret = i2c_master_recv(hw->client, hw->buffer, rlen); 11862306a36Sopenharmony_ci if (ret < 0) 11962306a36Sopenharmony_ci return ret; 12062306a36Sopenharmony_ci if (ret != rlen) 12162306a36Sopenharmony_ci return -EIO; 12262306a36Sopenharmony_ci memcpy(t->rx_buf, &hw->buffer[hw->rindex], len); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci hw->tlen = 0; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci return len; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci u8 ctrl = 0; 13262306a36Sopenharmony_ci int ret; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (mode & SPI_CPHA) 13562306a36Sopenharmony_ci ctrl |= SC18IS602_MODE_CPHA; 13662306a36Sopenharmony_ci if (mode & SPI_CPOL) 13762306a36Sopenharmony_ci ctrl |= SC18IS602_MODE_CPOL; 13862306a36Sopenharmony_ci if (mode & SPI_LSB_FIRST) 13962306a36Sopenharmony_ci ctrl |= SC18IS602_MODE_LSB_FIRST; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Find the closest clock speed */ 14262306a36Sopenharmony_ci if (hz >= hw->freq / 4) { 14362306a36Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_4; 14462306a36Sopenharmony_ci hw->speed = hw->freq / 4; 14562306a36Sopenharmony_ci } else if (hz >= hw->freq / 16) { 14662306a36Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_16; 14762306a36Sopenharmony_ci hw->speed = hw->freq / 16; 14862306a36Sopenharmony_ci } else if (hz >= hw->freq / 64) { 14962306a36Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_64; 15062306a36Sopenharmony_ci hw->speed = hw->freq / 64; 15162306a36Sopenharmony_ci } else { 15262306a36Sopenharmony_ci ctrl |= SC18IS602_MODE_CLOCK_DIV_128; 15362306a36Sopenharmony_ci hw->speed = hw->freq / 128; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * Don't do anything if the control value did not change. The initial 15862306a36Sopenharmony_ci * value of 0xff for hw->ctrl ensures that the correct mode will be set 15962306a36Sopenharmony_ci * with the first call to this function. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci if (ctrl == hw->ctrl) 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl); 16562306a36Sopenharmony_ci if (ret < 0) 16662306a36Sopenharmony_ci return ret; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci hw->ctrl = ctrl; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int sc18is602_check_transfer(struct spi_device *spi, 17462306a36Sopenharmony_ci struct spi_transfer *t, int tlen) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci if (t && t->len + tlen > SC18IS602_BUFSIZ + 1) 17762306a36Sopenharmony_ci return -EINVAL; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int sc18is602_transfer_one(struct spi_controller *host, 18362306a36Sopenharmony_ci struct spi_message *m) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct sc18is602 *hw = spi_controller_get_devdata(host); 18662306a36Sopenharmony_ci struct spi_device *spi = m->spi; 18762306a36Sopenharmony_ci struct spi_transfer *t; 18862306a36Sopenharmony_ci int status = 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci hw->tlen = 0; 19162306a36Sopenharmony_ci list_for_each_entry(t, &m->transfers, transfer_list) { 19262306a36Sopenharmony_ci bool do_transfer; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci status = sc18is602_check_transfer(spi, t, hw->tlen); 19562306a36Sopenharmony_ci if (status < 0) 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode); 19962306a36Sopenharmony_ci if (status < 0) 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci do_transfer = t->cs_change || list_is_last(&t->transfer_list, 20362306a36Sopenharmony_ci &m->transfers); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (t->len) { 20662306a36Sopenharmony_ci status = sc18is602_txrx(hw, m, t, do_transfer); 20762306a36Sopenharmony_ci if (status < 0) 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci m->actual_length += status; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci status = 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci spi_transfer_delay_exec(t); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci m->status = status; 21662306a36Sopenharmony_ci spi_finalize_current_message(host); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return status; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic size_t sc18is602_max_transfer_size(struct spi_device *spi) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci return SC18IS602_BUFSIZ; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int sc18is602_setup(struct spi_device *spi) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct sc18is602 *hw = spi_controller_get_devdata(spi->controller); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* SC18IS602 does not support CS2 */ 23162306a36Sopenharmony_ci if (hw->id == sc18is602 && (spi_get_chipselect(spi, 0) == 2)) 23262306a36Sopenharmony_ci return -ENXIO; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int sc18is602_probe(struct i2c_client *client) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci const struct i2c_device_id *id = i2c_client_get_device_id(client); 24062306a36Sopenharmony_ci struct device *dev = &client->dev; 24162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 24262306a36Sopenharmony_ci struct sc18is602_platform_data *pdata = dev_get_platdata(dev); 24362306a36Sopenharmony_ci struct sc18is602 *hw; 24462306a36Sopenharmony_ci struct spi_controller *host; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | 24762306a36Sopenharmony_ci I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 24862306a36Sopenharmony_ci return -EINVAL; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci host = devm_spi_alloc_host(dev, sizeof(struct sc18is602)); 25162306a36Sopenharmony_ci if (!host) 25262306a36Sopenharmony_ci return -ENOMEM; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci hw = spi_controller_get_devdata(host); 25562306a36Sopenharmony_ci i2c_set_clientdata(client, hw); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* assert reset and then release */ 25862306a36Sopenharmony_ci hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 25962306a36Sopenharmony_ci if (IS_ERR(hw->reset)) 26062306a36Sopenharmony_ci return PTR_ERR(hw->reset); 26162306a36Sopenharmony_ci gpiod_set_value_cansleep(hw->reset, 0); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci hw->host = host; 26462306a36Sopenharmony_ci hw->client = client; 26562306a36Sopenharmony_ci hw->dev = dev; 26662306a36Sopenharmony_ci hw->ctrl = 0xff; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (client->dev.of_node) 26962306a36Sopenharmony_ci hw->id = (uintptr_t)of_device_get_match_data(&client->dev); 27062306a36Sopenharmony_ci else 27162306a36Sopenharmony_ci hw->id = id->driver_data; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci switch (hw->id) { 27462306a36Sopenharmony_ci case sc18is602: 27562306a36Sopenharmony_ci case sc18is602b: 27662306a36Sopenharmony_ci host->num_chipselect = 4; 27762306a36Sopenharmony_ci hw->freq = SC18IS602_CLOCK; 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case sc18is603: 28062306a36Sopenharmony_ci host->num_chipselect = 2; 28162306a36Sopenharmony_ci if (pdata) { 28262306a36Sopenharmony_ci hw->freq = pdata->clock_frequency; 28362306a36Sopenharmony_ci } else { 28462306a36Sopenharmony_ci const __be32 *val; 28562306a36Sopenharmony_ci int len; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci val = of_get_property(np, "clock-frequency", &len); 28862306a36Sopenharmony_ci if (val && len >= sizeof(__be32)) 28962306a36Sopenharmony_ci hw->freq = be32_to_cpup(val); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci if (!hw->freq) 29262306a36Sopenharmony_ci hw->freq = SC18IS602_CLOCK; 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci host->bus_num = np ? -1 : client->adapter->nr; 29662306a36Sopenharmony_ci host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; 29762306a36Sopenharmony_ci host->bits_per_word_mask = SPI_BPW_MASK(8); 29862306a36Sopenharmony_ci host->setup = sc18is602_setup; 29962306a36Sopenharmony_ci host->transfer_one_message = sc18is602_transfer_one; 30062306a36Sopenharmony_ci host->max_transfer_size = sc18is602_max_transfer_size; 30162306a36Sopenharmony_ci host->max_message_size = sc18is602_max_transfer_size; 30262306a36Sopenharmony_ci host->dev.of_node = np; 30362306a36Sopenharmony_ci host->min_speed_hz = hw->freq / 128; 30462306a36Sopenharmony_ci host->max_speed_hz = hw->freq / 4; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return devm_spi_register_controller(dev, host); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic const struct i2c_device_id sc18is602_id[] = { 31062306a36Sopenharmony_ci { "sc18is602", sc18is602 }, 31162306a36Sopenharmony_ci { "sc18is602b", sc18is602b }, 31262306a36Sopenharmony_ci { "sc18is603", sc18is603 }, 31362306a36Sopenharmony_ci { } 31462306a36Sopenharmony_ci}; 31562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sc18is602_id); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic const struct of_device_id sc18is602_of_match[] __maybe_unused = { 31862306a36Sopenharmony_ci { 31962306a36Sopenharmony_ci .compatible = "nxp,sc18is602", 32062306a36Sopenharmony_ci .data = (void *)sc18is602 32162306a36Sopenharmony_ci }, 32262306a36Sopenharmony_ci { 32362306a36Sopenharmony_ci .compatible = "nxp,sc18is602b", 32462306a36Sopenharmony_ci .data = (void *)sc18is602b 32562306a36Sopenharmony_ci }, 32662306a36Sopenharmony_ci { 32762306a36Sopenharmony_ci .compatible = "nxp,sc18is603", 32862306a36Sopenharmony_ci .data = (void *)sc18is603 32962306a36Sopenharmony_ci }, 33062306a36Sopenharmony_ci { }, 33162306a36Sopenharmony_ci}; 33262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sc18is602_of_match); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic struct i2c_driver sc18is602_driver = { 33562306a36Sopenharmony_ci .driver = { 33662306a36Sopenharmony_ci .name = "sc18is602", 33762306a36Sopenharmony_ci .of_match_table = of_match_ptr(sc18is602_of_match), 33862306a36Sopenharmony_ci }, 33962306a36Sopenharmony_ci .probe = sc18is602_probe, 34062306a36Sopenharmony_ci .id_table = sc18is602_id, 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cimodule_i2c_driver(sc18is602_driver); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ciMODULE_DESCRIPTION("SC18IS602/603 SPI Host Driver"); 34662306a36Sopenharmony_ciMODULE_AUTHOR("Guenter Roeck"); 34762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 348