Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Lattice FPGA programming over slave SPI sysCONFIG interface.
  4 */
  5
  6#include <linux/spi/spi.h>
  7
  8#include "lattice-sysconfig.h"
  9
 10static const u32 ecp5_spi_max_speed_hz = 60000000;
 11
 12static int sysconfig_spi_cmd_transfer(struct sysconfig_priv *priv,
 13				      const void *tx_buf, size_t tx_len,
 14				      void *rx_buf, size_t rx_len)
 15{
 16	struct spi_device *spi = to_spi_device(priv->dev);
 17
 18	return spi_write_then_read(spi, tx_buf, tx_len, rx_buf, rx_len);
 19}
 20
 21static int sysconfig_spi_bitstream_burst_init(struct sysconfig_priv *priv)
 22{
 23	const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
 24	struct spi_device *spi = to_spi_device(priv->dev);
 25	struct spi_transfer xfer = {};
 26	struct spi_message msg;
 27	size_t buf_len;
 28	void *buf;
 29	int ret;
 30
 31	buf_len = sizeof(lsc_bitstream_burst);
 32
 33	buf = kmemdup(lsc_bitstream_burst, buf_len, GFP_KERNEL);
 34	if (!buf)
 35		return -ENOMEM;
 36
 37	xfer.len = buf_len;
 38	xfer.tx_buf = buf;
 39	xfer.cs_change = 1;
 40
 41	spi_message_init_with_transfers(&msg, &xfer, 1);
 42
 43	/*
 44	 * Lock SPI bus for exclusive usage until FPGA programming is done.
 45	 * SPI bus will be released in sysconfig_spi_bitstream_burst_complete().
 46	 */
 47	spi_bus_lock(spi->controller);
 48
 49	ret = spi_sync_locked(spi, &msg);
 50	if (ret)
 51		spi_bus_unlock(spi->controller);
 52
 53	kfree(buf);
 54
 55	return ret;
 56}
 57
 58static int sysconfig_spi_bitstream_burst_write(struct sysconfig_priv *priv,
 59					       const char *buf, size_t len)
 60{
 61	struct spi_device *spi = to_spi_device(priv->dev);
 62	struct spi_transfer xfer = {
 63		.tx_buf = buf,
 64		.len = len,
 65		.cs_change = 1,
 66	};
 67	struct spi_message msg;
 68
 69	spi_message_init_with_transfers(&msg, &xfer, 1);
 70
 71	return spi_sync_locked(spi, &msg);
 72}
 73
 74static int sysconfig_spi_bitstream_burst_complete(struct sysconfig_priv *priv)
 75{
 76	struct spi_device *spi = to_spi_device(priv->dev);
 77
 78	/* Bitstream burst write is done, release SPI bus */
 79	spi_bus_unlock(spi->controller);
 80
 81	/* Toggle CS to finish bitstream write */
 82	return spi_write(spi, NULL, 0);
 83}
 84
 85static int sysconfig_spi_probe(struct spi_device *spi)
 86{
 87	const struct spi_device_id *dev_id;
 88	struct device *dev = &spi->dev;
 89	struct sysconfig_priv *priv;
 90	const u32 *spi_max_speed;
 91
 92	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 93	if (!priv)
 94		return -ENOMEM;
 95
 96	spi_max_speed = device_get_match_data(dev);
 97	if (!spi_max_speed) {
 98		dev_id = spi_get_device_id(spi);
 99		if (!dev_id)
100			return -ENODEV;
101
102		spi_max_speed = (const u32 *)dev_id->driver_data;
103	}
104
105	if (!spi_max_speed)
106		return -EINVAL;
107
108	if (spi->max_speed_hz > *spi_max_speed) {
109		dev_err(dev, "SPI speed %u is too high, maximum speed is %u\n",
110			spi->max_speed_hz, *spi_max_speed);
111		return -EINVAL;
112	}
113
114	priv->dev = dev;
115	priv->command_transfer = sysconfig_spi_cmd_transfer;
116	priv->bitstream_burst_write_init = sysconfig_spi_bitstream_burst_init;
117	priv->bitstream_burst_write = sysconfig_spi_bitstream_burst_write;
118	priv->bitstream_burst_write_complete = sysconfig_spi_bitstream_burst_complete;
119
120	return sysconfig_probe(priv);
121}
122
123static const struct spi_device_id sysconfig_spi_ids[] = {
124	{
125		.name = "sysconfig-ecp5",
126		.driver_data = (kernel_ulong_t)&ecp5_spi_max_speed_hz,
127	}, {},
128};
129MODULE_DEVICE_TABLE(spi, sysconfig_spi_ids);
130
131#if IS_ENABLED(CONFIG_OF)
132static const struct of_device_id sysconfig_of_ids[] = {
133	{
134		.compatible = "lattice,sysconfig-ecp5",
135		.data = &ecp5_spi_max_speed_hz,
136	}, {},
137};
138MODULE_DEVICE_TABLE(of, sysconfig_of_ids);
139#endif /* IS_ENABLED(CONFIG_OF) */
140
141static struct spi_driver lattice_sysconfig_driver = {
142	.probe = sysconfig_spi_probe,
143	.id_table = sysconfig_spi_ids,
144	.driver = {
145		.name = "lattice_sysconfig_spi_fpga_mgr",
146		.of_match_table = of_match_ptr(sysconfig_of_ids),
147	},
148};
149module_spi_driver(lattice_sysconfig_driver);
150
151MODULE_DESCRIPTION("Lattice sysCONFIG Slave SPI FPGA Manager");
152MODULE_LICENSE("GPL");