brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · eecf9ea Raw
348 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * NXP SC18IS602/603 SPI driver4 *5 * Copyright (C) Guenter Roeck <linux@roeck-us.net>6 */7 8#include <linux/kernel.h>9#include <linux/err.h>10#include <linux/module.h>11#include <linux/spi/spi.h>12#include <linux/i2c.h>13#include <linux/delay.h>14#include <linux/pm_runtime.h>15#include <linux/of.h>16#include <linux/platform_data/sc18is602.h>17#include <linux/gpio/consumer.h>18 19enum chips { sc18is602, sc18is602b, sc18is603 };20 21#define SC18IS602_BUFSIZ		20022#define SC18IS602_CLOCK			737200023 24#define SC18IS602_MODE_CPHA		BIT(2)25#define SC18IS602_MODE_CPOL		BIT(3)26#define SC18IS602_MODE_LSB_FIRST	BIT(5)27#define SC18IS602_MODE_CLOCK_DIV_4	0x028#define SC18IS602_MODE_CLOCK_DIV_16	0x129#define SC18IS602_MODE_CLOCK_DIV_64	0x230#define SC18IS602_MODE_CLOCK_DIV_128	0x331 32struct sc18is602 {33	struct spi_controller	*host;34	struct device		*dev;35	u8			ctrl;36	u32			freq;37	u32			speed;38 39	/* I2C data */40	struct i2c_client	*client;41	enum chips		id;42	u8			buffer[SC18IS602_BUFSIZ + 1];43	int			tlen;	/* Data queued for tx in buffer */44	int			rindex;	/* Receive data index in buffer */45 46	struct gpio_desc	*reset;47};48 49static int sc18is602_wait_ready(struct sc18is602 *hw, int len)50{51	int i, err;52	int usecs = 1000000 * len / hw->speed + 1;53	u8 dummy[1];54 55	for (i = 0; i < 10; i++) {56		err = i2c_master_recv(hw->client, dummy, 1);57		if (err >= 0)58			return 0;59		usleep_range(usecs, usecs * 2);60	}61	return -ETIMEDOUT;62}63 64static int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg,65			  struct spi_transfer *t, bool do_transfer)66{67	unsigned int len = t->len;68	int ret;69 70	if (hw->tlen == 0) {71		/* First byte (I2C command) is chip select */72		hw->buffer[0] = 1 << spi_get_chipselect(msg->spi, 0);73		hw->tlen = 1;74		hw->rindex = 0;75	}76	/*77	 * We can not immediately send data to the chip, since each I2C message78	 * resembles a full SPI message (from CS active to CS inactive).79	 * Enqueue messages up to the first read or until do_transfer is true.80	 */81	if (t->tx_buf) {82		memcpy(&hw->buffer[hw->tlen], t->tx_buf, len);83		hw->tlen += len;84		if (t->rx_buf)85			do_transfer = true;86		else87			hw->rindex = hw->tlen - 1;88	} else if (t->rx_buf) {89		/*90		 * For receive-only transfers we still need to perform a dummy91		 * write to receive data from the SPI chip.92		 * Read data starts at the end of transmit data (minus 1 to93		 * account for CS).94		 */95		hw->rindex = hw->tlen - 1;96		memset(&hw->buffer[hw->tlen], 0, len);97		hw->tlen += len;98		do_transfer = true;99	}100 101	if (do_transfer && hw->tlen > 1) {102		ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ);103		if (ret < 0)104			return ret;105		ret = i2c_master_send(hw->client, hw->buffer, hw->tlen);106		if (ret < 0)107			return ret;108		if (ret != hw->tlen)109			return -EIO;110 111		if (t->rx_buf) {112			int rlen = hw->rindex + len;113 114			ret = sc18is602_wait_ready(hw, hw->tlen);115			if (ret < 0)116				return ret;117			ret = i2c_master_recv(hw->client, hw->buffer, rlen);118			if (ret < 0)119				return ret;120			if (ret != rlen)121				return -EIO;122			memcpy(t->rx_buf, &hw->buffer[hw->rindex], len);123		}124		hw->tlen = 0;125	}126	return len;127}128 129static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)130{131	u8 ctrl = 0;132	int ret;133 134	if (mode & SPI_CPHA)135		ctrl |= SC18IS602_MODE_CPHA;136	if (mode & SPI_CPOL)137		ctrl |= SC18IS602_MODE_CPOL;138	if (mode & SPI_LSB_FIRST)139		ctrl |= SC18IS602_MODE_LSB_FIRST;140 141	/* Find the closest clock speed */142	if (hz >= hw->freq / 4) {143		ctrl |= SC18IS602_MODE_CLOCK_DIV_4;144		hw->speed = hw->freq / 4;145	} else if (hz >= hw->freq / 16) {146		ctrl |= SC18IS602_MODE_CLOCK_DIV_16;147		hw->speed = hw->freq / 16;148	} else if (hz >= hw->freq / 64) {149		ctrl |= SC18IS602_MODE_CLOCK_DIV_64;150		hw->speed = hw->freq / 64;151	} else {152		ctrl |= SC18IS602_MODE_CLOCK_DIV_128;153		hw->speed = hw->freq / 128;154	}155 156	/*157	 * Don't do anything if the control value did not change. The initial158	 * value of 0xff for hw->ctrl ensures that the correct mode will be set159	 * with the first call to this function.160	 */161	if (ctrl == hw->ctrl)162		return 0;163 164	ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl);165	if (ret < 0)166		return ret;167 168	hw->ctrl = ctrl;169 170	return 0;171}172 173static int sc18is602_check_transfer(struct spi_device *spi,174				    struct spi_transfer *t, int tlen)175{176	if (t && t->len + tlen > SC18IS602_BUFSIZ + 1)177		return -EINVAL;178 179	return 0;180}181 182static int sc18is602_transfer_one(struct spi_controller *host,183				  struct spi_message *m)184{185	struct sc18is602 *hw = spi_controller_get_devdata(host);186	struct spi_device *spi = m->spi;187	struct spi_transfer *t;188	int status = 0;189 190	hw->tlen = 0;191	list_for_each_entry(t, &m->transfers, transfer_list) {192		bool do_transfer;193 194		status = sc18is602_check_transfer(spi, t, hw->tlen);195		if (status < 0)196			break;197 198		status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode);199		if (status < 0)200			break;201 202		do_transfer = t->cs_change || list_is_last(&t->transfer_list,203							   &m->transfers);204 205		if (t->len) {206			status = sc18is602_txrx(hw, m, t, do_transfer);207			if (status < 0)208				break;209			m->actual_length += status;210		}211		status = 0;212 213		spi_transfer_delay_exec(t);214	}215	m->status = status;216	spi_finalize_current_message(host);217 218	return status;219}220 221static size_t sc18is602_max_transfer_size(struct spi_device *spi)222{223	return SC18IS602_BUFSIZ;224}225 226static int sc18is602_setup(struct spi_device *spi)227{228	struct sc18is602 *hw = spi_controller_get_devdata(spi->controller);229 230	/* SC18IS602 does not support CS2 */231	if (hw->id == sc18is602 && (spi_get_chipselect(spi, 0) == 2))232		return -ENXIO;233 234	return 0;235}236 237static int sc18is602_probe(struct i2c_client *client)238{239	const struct i2c_device_id *id = i2c_client_get_device_id(client);240	struct device *dev = &client->dev;241	struct device_node *np = dev->of_node;242	struct sc18is602_platform_data *pdata = dev_get_platdata(dev);243	struct sc18is602 *hw;244	struct spi_controller *host;245 246	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |247				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA))248		return -EINVAL;249 250	host = devm_spi_alloc_host(dev, sizeof(struct sc18is602));251	if (!host)252		return -ENOMEM;253 254	hw = spi_controller_get_devdata(host);255	i2c_set_clientdata(client, hw);256 257	/* assert reset and then release */258	hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);259	if (IS_ERR(hw->reset))260		return PTR_ERR(hw->reset);261	gpiod_set_value_cansleep(hw->reset, 0);262 263	hw->host = host;264	hw->client = client;265	hw->dev = dev;266	hw->ctrl = 0xff;267 268	if (client->dev.of_node)269		hw->id = (uintptr_t)of_device_get_match_data(&client->dev);270	else271		hw->id = id->driver_data;272 273	switch (hw->id) {274	case sc18is602:275	case sc18is602b:276		host->num_chipselect = 4;277		hw->freq = SC18IS602_CLOCK;278		break;279	case sc18is603:280		host->num_chipselect = 2;281		if (pdata) {282			hw->freq = pdata->clock_frequency;283		} else {284			const __be32 *val;285			int len;286 287			val = of_get_property(np, "clock-frequency", &len);288			if (val && len >= sizeof(__be32))289				hw->freq = be32_to_cpup(val);290		}291		if (!hw->freq)292			hw->freq = SC18IS602_CLOCK;293		break;294	}295	host->bus_num = np ? -1 : client->adapter->nr;296	host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;297	host->bits_per_word_mask = SPI_BPW_MASK(8);298	host->setup = sc18is602_setup;299	host->transfer_one_message = sc18is602_transfer_one;300	host->max_transfer_size = sc18is602_max_transfer_size;301	host->max_message_size = sc18is602_max_transfer_size;302	host->dev.of_node = np;303	host->min_speed_hz = hw->freq / 128;304	host->max_speed_hz = hw->freq / 4;305 306	return devm_spi_register_controller(dev, host);307}308 309static const struct i2c_device_id sc18is602_id[] = {310	{ "sc18is602", sc18is602 },311	{ "sc18is602b", sc18is602b },312	{ "sc18is603", sc18is603 },313	{ }314};315MODULE_DEVICE_TABLE(i2c, sc18is602_id);316 317static const struct of_device_id sc18is602_of_match[] __maybe_unused = {318	{319		.compatible = "nxp,sc18is602",320		.data = (void *)sc18is602321	},322	{323		.compatible = "nxp,sc18is602b",324		.data = (void *)sc18is602b325	},326	{327		.compatible = "nxp,sc18is603",328		.data = (void *)sc18is603329	},330	{ },331};332MODULE_DEVICE_TABLE(of, sc18is602_of_match);333 334static struct i2c_driver sc18is602_driver = {335	.driver = {336		.name = "sc18is602",337		.of_match_table = of_match_ptr(sc18is602_of_match),338	},339	.probe = sc18is602_probe,340	.id_table = sc18is602_id,341};342 343module_i2c_driver(sc18is602_driver);344 345MODULE_DESCRIPTION("SC18IS602/603 SPI Host Driver");346MODULE_AUTHOR("Guenter Roeck");347MODULE_LICENSE("GPL");348