1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 23ce8859eSGuenter Roeck /* 33ce8859eSGuenter Roeck * NXP SC18IS602/603 SPI driver 43ce8859eSGuenter Roeck * 53ce8859eSGuenter Roeck * Copyright (C) Guenter Roeck <linux@roeck-us.net> 63ce8859eSGuenter Roeck */ 73ce8859eSGuenter Roeck 83ce8859eSGuenter Roeck #include <linux/kernel.h> 93ce8859eSGuenter Roeck #include <linux/err.h> 103ce8859eSGuenter Roeck #include <linux/module.h> 113ce8859eSGuenter Roeck #include <linux/spi/spi.h> 123ce8859eSGuenter Roeck #include <linux/i2c.h> 133ce8859eSGuenter Roeck #include <linux/delay.h> 143ce8859eSGuenter Roeck #include <linux/pm_runtime.h> 153ce8859eSGuenter Roeck #include <linux/of.h> 163ce8859eSGuenter Roeck #include <linux/platform_data/sc18is602.h> 17f9900801SPhil Reid #include <linux/gpio/consumer.h> 183ce8859eSGuenter Roeck 193ce8859eSGuenter Roeck enum chips { sc18is602, sc18is602b, sc18is603 }; 203ce8859eSGuenter Roeck 213ce8859eSGuenter Roeck #define SC18IS602_BUFSIZ 200 223ce8859eSGuenter Roeck #define SC18IS602_CLOCK 7372000 233ce8859eSGuenter Roeck 243ce8859eSGuenter Roeck #define SC18IS602_MODE_CPHA BIT(2) 253ce8859eSGuenter Roeck #define SC18IS602_MODE_CPOL BIT(3) 263ce8859eSGuenter Roeck #define SC18IS602_MODE_LSB_FIRST BIT(5) 273ce8859eSGuenter Roeck #define SC18IS602_MODE_CLOCK_DIV_4 0x0 283ce8859eSGuenter Roeck #define SC18IS602_MODE_CLOCK_DIV_16 0x1 293ce8859eSGuenter Roeck #define SC18IS602_MODE_CLOCK_DIV_64 0x2 303ce8859eSGuenter Roeck #define SC18IS602_MODE_CLOCK_DIV_128 0x3 313ce8859eSGuenter Roeck 323ce8859eSGuenter Roeck struct sc18is602 { 333ce8859eSGuenter Roeck struct spi_master *master; 343ce8859eSGuenter Roeck struct device *dev; 353ce8859eSGuenter Roeck u8 ctrl; 363ce8859eSGuenter Roeck u32 freq; 373ce8859eSGuenter Roeck u32 speed; 383ce8859eSGuenter Roeck 393ce8859eSGuenter Roeck /* I2C data */ 403ce8859eSGuenter Roeck struct i2c_client *client; 413ce8859eSGuenter Roeck enum chips id; 423ce8859eSGuenter Roeck u8 buffer[SC18IS602_BUFSIZ + 1]; 433ce8859eSGuenter Roeck int tlen; /* Data queued for tx in buffer */ 443ce8859eSGuenter Roeck int rindex; /* Receive data index in buffer */ 45f9900801SPhil Reid 46f9900801SPhil Reid struct gpio_desc *reset; 473ce8859eSGuenter Roeck }; 483ce8859eSGuenter Roeck 493ce8859eSGuenter Roeck static int sc18is602_wait_ready(struct sc18is602 *hw, int len) 503ce8859eSGuenter Roeck { 513ce8859eSGuenter Roeck int i, err; 523ce8859eSGuenter Roeck int usecs = 1000000 * len / hw->speed + 1; 533ce8859eSGuenter Roeck u8 dummy[1]; 543ce8859eSGuenter Roeck 553ce8859eSGuenter Roeck for (i = 0; i < 10; i++) { 563ce8859eSGuenter Roeck err = i2c_master_recv(hw->client, dummy, 1); 573ce8859eSGuenter Roeck if (err >= 0) 583ce8859eSGuenter Roeck return 0; 593ce8859eSGuenter Roeck usleep_range(usecs, usecs * 2); 603ce8859eSGuenter Roeck } 613ce8859eSGuenter Roeck return -ETIMEDOUT; 623ce8859eSGuenter Roeck } 633ce8859eSGuenter Roeck 643ce8859eSGuenter Roeck static int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg, 653ce8859eSGuenter Roeck struct spi_transfer *t, bool do_transfer) 663ce8859eSGuenter Roeck { 673ce8859eSGuenter Roeck unsigned int len = t->len; 683ce8859eSGuenter Roeck int ret; 693ce8859eSGuenter Roeck 703ce8859eSGuenter Roeck if (hw->tlen == 0) { 713ce8859eSGuenter Roeck /* First byte (I2C command) is chip select */ 729e264f3fSAmit Kumar Mahapatra via Alsa-devel hw->buffer[0] = 1 << spi_get_chipselect(msg->spi, 0); 733ce8859eSGuenter Roeck hw->tlen = 1; 743ce8859eSGuenter Roeck hw->rindex = 0; 753ce8859eSGuenter Roeck } 763ce8859eSGuenter Roeck /* 773ce8859eSGuenter Roeck * We can not immediately send data to the chip, since each I2C message 783ce8859eSGuenter Roeck * resembles a full SPI message (from CS active to CS inactive). 793ce8859eSGuenter Roeck * Enqueue messages up to the first read or until do_transfer is true. 803ce8859eSGuenter Roeck */ 813ce8859eSGuenter Roeck if (t->tx_buf) { 823ce8859eSGuenter Roeck memcpy(&hw->buffer[hw->tlen], t->tx_buf, len); 833ce8859eSGuenter Roeck hw->tlen += len; 843ce8859eSGuenter Roeck if (t->rx_buf) 853ce8859eSGuenter Roeck do_transfer = true; 863ce8859eSGuenter Roeck else 873ce8859eSGuenter Roeck hw->rindex = hw->tlen - 1; 883ce8859eSGuenter Roeck } else if (t->rx_buf) { 893ce8859eSGuenter Roeck /* 903ce8859eSGuenter Roeck * For receive-only transfers we still need to perform a dummy 913ce8859eSGuenter Roeck * write to receive data from the SPI chip. 923ce8859eSGuenter Roeck * Read data starts at the end of transmit data (minus 1 to 933ce8859eSGuenter Roeck * account for CS). 943ce8859eSGuenter Roeck */ 953ce8859eSGuenter Roeck hw->rindex = hw->tlen - 1; 963ce8859eSGuenter Roeck memset(&hw->buffer[hw->tlen], 0, len); 973ce8859eSGuenter Roeck hw->tlen += len; 983ce8859eSGuenter Roeck do_transfer = true; 993ce8859eSGuenter Roeck } 1003ce8859eSGuenter Roeck 1013ce8859eSGuenter Roeck if (do_transfer && hw->tlen > 1) { 1023ce8859eSGuenter Roeck ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ); 1033ce8859eSGuenter Roeck if (ret < 0) 1043ce8859eSGuenter Roeck return ret; 1053ce8859eSGuenter Roeck ret = i2c_master_send(hw->client, hw->buffer, hw->tlen); 1063ce8859eSGuenter Roeck if (ret < 0) 1073ce8859eSGuenter Roeck return ret; 1083ce8859eSGuenter Roeck if (ret != hw->tlen) 1093ce8859eSGuenter Roeck return -EIO; 1103ce8859eSGuenter Roeck 1113ce8859eSGuenter Roeck if (t->rx_buf) { 1123ce8859eSGuenter Roeck int rlen = hw->rindex + len; 1133ce8859eSGuenter Roeck 1143ce8859eSGuenter Roeck ret = sc18is602_wait_ready(hw, hw->tlen); 1153ce8859eSGuenter Roeck if (ret < 0) 1163ce8859eSGuenter Roeck return ret; 1173ce8859eSGuenter Roeck ret = i2c_master_recv(hw->client, hw->buffer, rlen); 1183ce8859eSGuenter Roeck if (ret < 0) 1193ce8859eSGuenter Roeck return ret; 1203ce8859eSGuenter Roeck if (ret != rlen) 1213ce8859eSGuenter Roeck return -EIO; 1223ce8859eSGuenter Roeck memcpy(t->rx_buf, &hw->buffer[hw->rindex], len); 1233ce8859eSGuenter Roeck } 1243ce8859eSGuenter Roeck hw->tlen = 0; 1253ce8859eSGuenter Roeck } 1263ce8859eSGuenter Roeck return len; 1273ce8859eSGuenter Roeck } 1283ce8859eSGuenter Roeck 1293ce8859eSGuenter Roeck static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) 1303ce8859eSGuenter Roeck { 1313ce8859eSGuenter Roeck u8 ctrl = 0; 1323ce8859eSGuenter Roeck int ret; 1333ce8859eSGuenter Roeck 1343ce8859eSGuenter Roeck if (mode & SPI_CPHA) 1353ce8859eSGuenter Roeck ctrl |= SC18IS602_MODE_CPHA; 1363ce8859eSGuenter Roeck if (mode & SPI_CPOL) 1373ce8859eSGuenter Roeck ctrl |= SC18IS602_MODE_CPOL; 1383ce8859eSGuenter Roeck if (mode & SPI_LSB_FIRST) 1393ce8859eSGuenter Roeck ctrl |= SC18IS602_MODE_LSB_FIRST; 1403ce8859eSGuenter Roeck 1413ce8859eSGuenter Roeck /* Find the closest clock speed */ 1423ce8859eSGuenter Roeck if (hz >= hw->freq / 4) { 1433ce8859eSGuenter Roeck ctrl |= SC18IS602_MODE_CLOCK_DIV_4; 1443ce8859eSGuenter Roeck hw->speed = hw->freq / 4; 1453ce8859eSGuenter Roeck } else if (hz >= hw->freq / 16) { 1463ce8859eSGuenter Roeck ctrl |= SC18IS602_MODE_CLOCK_DIV_16; 1473ce8859eSGuenter Roeck hw->speed = hw->freq / 16; 1483ce8859eSGuenter Roeck } else if (hz >= hw->freq / 64) { 1493ce8859eSGuenter Roeck ctrl |= SC18IS602_MODE_CLOCK_DIV_64; 1503ce8859eSGuenter Roeck hw->speed = hw->freq / 64; 1513ce8859eSGuenter Roeck } else { 1523ce8859eSGuenter Roeck ctrl |= SC18IS602_MODE_CLOCK_DIV_128; 1533ce8859eSGuenter Roeck hw->speed = hw->freq / 128; 1543ce8859eSGuenter Roeck } 1553ce8859eSGuenter Roeck 1563ce8859eSGuenter Roeck /* 1573ce8859eSGuenter Roeck * Don't do anything if the control value did not change. The initial 1583ce8859eSGuenter Roeck * value of 0xff for hw->ctrl ensures that the correct mode will be set 1593ce8859eSGuenter Roeck * with the first call to this function. 1603ce8859eSGuenter Roeck */ 1613ce8859eSGuenter Roeck if (ctrl == hw->ctrl) 1623ce8859eSGuenter Roeck return 0; 1633ce8859eSGuenter Roeck 1643ce8859eSGuenter Roeck ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl); 1653ce8859eSGuenter Roeck if (ret < 0) 1663ce8859eSGuenter Roeck return ret; 1673ce8859eSGuenter Roeck 1683ce8859eSGuenter Roeck hw->ctrl = ctrl; 1693ce8859eSGuenter Roeck 1703ce8859eSGuenter Roeck return 0; 1713ce8859eSGuenter Roeck } 1723ce8859eSGuenter Roeck 1733ce8859eSGuenter Roeck static int sc18is602_check_transfer(struct spi_device *spi, 1743ce8859eSGuenter Roeck struct spi_transfer *t, int tlen) 1753ce8859eSGuenter Roeck { 176bda7db1dSVladimir Oltean if (t && t->len + tlen > SC18IS602_BUFSIZ + 1) 1773ce8859eSGuenter Roeck return -EINVAL; 1783ce8859eSGuenter Roeck 1793ce8859eSGuenter Roeck return 0; 1803ce8859eSGuenter Roeck } 1813ce8859eSGuenter Roeck 1823ce8859eSGuenter Roeck static int sc18is602_transfer_one(struct spi_master *master, 1833ce8859eSGuenter Roeck struct spi_message *m) 1843ce8859eSGuenter Roeck { 1853ce8859eSGuenter Roeck struct sc18is602 *hw = spi_master_get_devdata(master); 1863ce8859eSGuenter Roeck struct spi_device *spi = m->spi; 1873ce8859eSGuenter Roeck struct spi_transfer *t; 1883ce8859eSGuenter Roeck int status = 0; 1893ce8859eSGuenter Roeck 1903ce8859eSGuenter Roeck hw->tlen = 0; 1913ce8859eSGuenter Roeck list_for_each_entry(t, &m->transfers, transfer_list) { 1923ce8859eSGuenter Roeck bool do_transfer; 1933ce8859eSGuenter Roeck 1943ce8859eSGuenter Roeck status = sc18is602_check_transfer(spi, t, hw->tlen); 1953ce8859eSGuenter Roeck if (status < 0) 1963ce8859eSGuenter Roeck break; 1973ce8859eSGuenter Roeck 19809e99bcaSAxel Lin status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode); 1993ce8859eSGuenter Roeck if (status < 0) 2003ce8859eSGuenter Roeck break; 2013ce8859eSGuenter Roeck 2023ce8859eSGuenter Roeck do_transfer = t->cs_change || list_is_last(&t->transfer_list, 2033ce8859eSGuenter Roeck &m->transfers); 2043ce8859eSGuenter Roeck 2053ce8859eSGuenter Roeck if (t->len) { 2063ce8859eSGuenter Roeck status = sc18is602_txrx(hw, m, t, do_transfer); 2073ce8859eSGuenter Roeck if (status < 0) 2083ce8859eSGuenter Roeck break; 2093ce8859eSGuenter Roeck m->actual_length += status; 2103ce8859eSGuenter Roeck } 2113ce8859eSGuenter Roeck status = 0; 2123ce8859eSGuenter Roeck 213e74dc5c7SAlexandru Ardelean spi_transfer_delay_exec(t); 2143ce8859eSGuenter Roeck } 2153ce8859eSGuenter Roeck m->status = status; 2163ce8859eSGuenter Roeck spi_finalize_current_message(master); 2173ce8859eSGuenter Roeck 2183ce8859eSGuenter Roeck return status; 2193ce8859eSGuenter Roeck } 2203ce8859eSGuenter Roeck 221b4e46c99SVladimir Oltean static size_t sc18is602_max_transfer_size(struct spi_device *spi) 222b4e46c99SVladimir Oltean { 223b4e46c99SVladimir Oltean return SC18IS602_BUFSIZ; 224b4e46c99SVladimir Oltean } 225b4e46c99SVladimir Oltean 226c5c67e31SAxel Lin static int sc18is602_setup(struct spi_device *spi) 227c5c67e31SAxel Lin { 228c5c67e31SAxel Lin struct sc18is602 *hw = spi_master_get_devdata(spi->master); 229c5c67e31SAxel Lin 230c5c67e31SAxel Lin /* SC18IS602 does not support CS2 */ 2319e264f3fSAmit Kumar Mahapatra via Alsa-devel if (hw->id == sc18is602 && (spi_get_chipselect(spi, 0) == 2)) 232c5c67e31SAxel Lin return -ENXIO; 233c5c67e31SAxel Lin 234c5c67e31SAxel Lin return 0; 235c5c67e31SAxel Lin } 236c5c67e31SAxel Lin 237c7f635bcSUwe Kleine-König static int sc18is602_probe(struct i2c_client *client) 2383ce8859eSGuenter Roeck { 239c7f635bcSUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client); 2403ce8859eSGuenter Roeck struct device *dev = &client->dev; 2413ce8859eSGuenter Roeck struct device_node *np = dev->of_node; 2423ce8859eSGuenter Roeck struct sc18is602_platform_data *pdata = dev_get_platdata(dev); 2433ce8859eSGuenter Roeck struct sc18is602 *hw; 2443ce8859eSGuenter Roeck struct spi_master *master; 2453ce8859eSGuenter Roeck 2463ce8859eSGuenter Roeck if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | 2473ce8859eSGuenter Roeck I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 24858ed90deSGuenter Roeck return -EINVAL; 2493ce8859eSGuenter Roeck 2505b8c8846SLukas Wunner master = devm_spi_alloc_master(dev, sizeof(struct sc18is602)); 2513ce8859eSGuenter Roeck if (!master) 2523ce8859eSGuenter Roeck return -ENOMEM; 2533ce8859eSGuenter Roeck 2543ce8859eSGuenter Roeck hw = spi_master_get_devdata(master); 2553ce8859eSGuenter Roeck i2c_set_clientdata(client, hw); 2563ce8859eSGuenter Roeck 257f9900801SPhil Reid /* assert reset and then release */ 258f9900801SPhil Reid hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 259f9900801SPhil Reid if (IS_ERR(hw->reset)) 260f9900801SPhil Reid return PTR_ERR(hw->reset); 26176cce7e3SPhil Reid gpiod_set_value_cansleep(hw->reset, 0); 262f9900801SPhil Reid 2633ce8859eSGuenter Roeck hw->master = master; 2643ce8859eSGuenter Roeck hw->client = client; 2653ce8859eSGuenter Roeck hw->dev = dev; 2663ce8859eSGuenter Roeck hw->ctrl = 0xff; 2673ce8859eSGuenter Roeck 26868c97b92SJavier Martinez Canillas if (client->dev.of_node) 269*0f9440a6SKrzysztof Kozlowski hw->id = (uintptr_t)of_device_get_match_data(&client->dev); 27068c97b92SJavier Martinez Canillas else 2713ce8859eSGuenter Roeck hw->id = id->driver_data; 2723ce8859eSGuenter Roeck 2733ce8859eSGuenter Roeck switch (hw->id) { 2743ce8859eSGuenter Roeck case sc18is602: 2753ce8859eSGuenter Roeck case sc18is602b: 2763ce8859eSGuenter Roeck master->num_chipselect = 4; 2773ce8859eSGuenter Roeck hw->freq = SC18IS602_CLOCK; 2783ce8859eSGuenter Roeck break; 2793ce8859eSGuenter Roeck case sc18is603: 2803ce8859eSGuenter Roeck master->num_chipselect = 2; 2813ce8859eSGuenter Roeck if (pdata) { 2823ce8859eSGuenter Roeck hw->freq = pdata->clock_frequency; 2833ce8859eSGuenter Roeck } else { 2843ce8859eSGuenter Roeck const __be32 *val; 2853ce8859eSGuenter Roeck int len; 2863ce8859eSGuenter Roeck 2873ce8859eSGuenter Roeck val = of_get_property(np, "clock-frequency", &len); 2883ce8859eSGuenter Roeck if (val && len >= sizeof(__be32)) 2893ce8859eSGuenter Roeck hw->freq = be32_to_cpup(val); 2903ce8859eSGuenter Roeck } 2913ce8859eSGuenter Roeck if (!hw->freq) 2923ce8859eSGuenter Roeck hw->freq = SC18IS602_CLOCK; 2933ce8859eSGuenter Roeck break; 2943ce8859eSGuenter Roeck } 295b4e27545SGuenter Roeck master->bus_num = np ? -1 : client->adapter->nr; 2963ce8859eSGuenter Roeck master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; 297463654ceSAxel Lin master->bits_per_word_mask = SPI_BPW_MASK(8); 298c5c67e31SAxel Lin master->setup = sc18is602_setup; 2993ce8859eSGuenter Roeck master->transfer_one_message = sc18is602_transfer_one; 300b4e46c99SVladimir Oltean master->max_transfer_size = sc18is602_max_transfer_size; 301b4e46c99SVladimir Oltean master->max_message_size = sc18is602_max_transfer_size; 3023ce8859eSGuenter Roeck master->dev.of_node = np; 30309e99bcaSAxel Lin master->min_speed_hz = hw->freq / 128; 30409e99bcaSAxel Lin master->max_speed_hz = hw->freq / 4; 3053ce8859eSGuenter Roeck 3065b8c8846SLukas Wunner return devm_spi_register_master(dev, master); 3073ce8859eSGuenter Roeck } 3083ce8859eSGuenter Roeck 3093ce8859eSGuenter Roeck static const struct i2c_device_id sc18is602_id[] = { 3103ce8859eSGuenter Roeck { "sc18is602", sc18is602 }, 3113ce8859eSGuenter Roeck { "sc18is602b", sc18is602b }, 3123ce8859eSGuenter Roeck { "sc18is603", sc18is603 }, 3133ce8859eSGuenter Roeck { } 3143ce8859eSGuenter Roeck }; 3153ce8859eSGuenter Roeck MODULE_DEVICE_TABLE(i2c, sc18is602_id); 3163ce8859eSGuenter Roeck 317833f4330SKrzysztof Kozlowski static const struct of_device_id sc18is602_of_match[] __maybe_unused = { 31868c97b92SJavier Martinez Canillas { 31968c97b92SJavier Martinez Canillas .compatible = "nxp,sc18is602", 32068c97b92SJavier Martinez Canillas .data = (void *)sc18is602 32168c97b92SJavier Martinez Canillas }, 32268c97b92SJavier Martinez Canillas { 32368c97b92SJavier Martinez Canillas .compatible = "nxp,sc18is602b", 32468c97b92SJavier Martinez Canillas .data = (void *)sc18is602b 32568c97b92SJavier Martinez Canillas }, 32668c97b92SJavier Martinez Canillas { 32768c97b92SJavier Martinez Canillas .compatible = "nxp,sc18is603", 32868c97b92SJavier Martinez Canillas .data = (void *)sc18is603 32968c97b92SJavier Martinez Canillas }, 33068c97b92SJavier Martinez Canillas { }, 33168c97b92SJavier Martinez Canillas }; 33268c97b92SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, sc18is602_of_match); 33368c97b92SJavier Martinez Canillas 3343ce8859eSGuenter Roeck static struct i2c_driver sc18is602_driver = { 3353ce8859eSGuenter Roeck .driver = { 3363ce8859eSGuenter Roeck .name = "sc18is602", 33768c97b92SJavier Martinez Canillas .of_match_table = of_match_ptr(sc18is602_of_match), 3383ce8859eSGuenter Roeck }, 3393e39448aSUwe Kleine-König .probe = sc18is602_probe, 3403ce8859eSGuenter Roeck .id_table = sc18is602_id, 3413ce8859eSGuenter Roeck }; 3423ce8859eSGuenter Roeck 3433ce8859eSGuenter Roeck module_i2c_driver(sc18is602_driver); 3443ce8859eSGuenter Roeck 3456d75145bSChristophe JAILLET MODULE_DESCRIPTION("SC18IS602/603 SPI Master Driver"); 3463ce8859eSGuenter Roeck MODULE_AUTHOR("Guenter Roeck"); 3473ce8859eSGuenter Roeck MODULE_LICENSE("GPL"); 348