mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	 2febc5dda3
			
		
	
	
		2febc5dda3
		
	
	
	
	
		
			
			With linux/acpi.h (in spi/spi.h) no longer implicitly including of.h, add an explicit include of of.h to fix the following errors: drivers/fpga/lattice-sysconfig-spi.c:146:35: error: implicit declaration of function 'of_match_ptr' [-Werror=implicit-function-declaration] Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Rob Herring <robh@kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
		
			
				
	
	
		
			153 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * Lattice FPGA programming over slave SPI sysCONFIG interface.
 | |
|  */
 | |
| 
 | |
| #include <linux/of.h>
 | |
| #include <linux/spi/spi.h>
 | |
| 
 | |
| #include "lattice-sysconfig.h"
 | |
| 
 | |
| static const u32 ecp5_spi_max_speed_hz = 60000000;
 | |
| 
 | |
| static int sysconfig_spi_cmd_transfer(struct sysconfig_priv *priv,
 | |
| 				      const void *tx_buf, size_t tx_len,
 | |
| 				      void *rx_buf, size_t rx_len)
 | |
| {
 | |
| 	struct spi_device *spi = to_spi_device(priv->dev);
 | |
| 
 | |
| 	return spi_write_then_read(spi, tx_buf, tx_len, rx_buf, rx_len);
 | |
| }
 | |
| 
 | |
| static int sysconfig_spi_bitstream_burst_init(struct sysconfig_priv *priv)
 | |
| {
 | |
| 	const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
 | |
| 	struct spi_device *spi = to_spi_device(priv->dev);
 | |
| 	struct spi_transfer xfer = {};
 | |
| 	struct spi_message msg;
 | |
| 	size_t buf_len;
 | |
| 	void *buf;
 | |
| 	int ret;
 | |
| 
 | |
| 	buf_len = sizeof(lsc_bitstream_burst);
 | |
| 
 | |
| 	buf = kmemdup(lsc_bitstream_burst, buf_len, GFP_KERNEL);
 | |
| 	if (!buf)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	xfer.len = buf_len;
 | |
| 	xfer.tx_buf = buf;
 | |
| 	xfer.cs_change = 1;
 | |
| 
 | |
| 	spi_message_init_with_transfers(&msg, &xfer, 1);
 | |
| 
 | |
| 	/*
 | |
| 	 * Lock SPI bus for exclusive usage until FPGA programming is done.
 | |
| 	 * SPI bus will be released in sysconfig_spi_bitstream_burst_complete().
 | |
| 	 */
 | |
| 	spi_bus_lock(spi->controller);
 | |
| 
 | |
| 	ret = spi_sync_locked(spi, &msg);
 | |
| 	if (ret)
 | |
| 		spi_bus_unlock(spi->controller);
 | |
| 
 | |
| 	kfree(buf);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int sysconfig_spi_bitstream_burst_write(struct sysconfig_priv *priv,
 | |
| 					       const char *buf, size_t len)
 | |
| {
 | |
| 	struct spi_device *spi = to_spi_device(priv->dev);
 | |
| 	struct spi_transfer xfer = {
 | |
| 		.tx_buf = buf,
 | |
| 		.len = len,
 | |
| 		.cs_change = 1,
 | |
| 	};
 | |
| 	struct spi_message msg;
 | |
| 
 | |
| 	spi_message_init_with_transfers(&msg, &xfer, 1);
 | |
| 
 | |
| 	return spi_sync_locked(spi, &msg);
 | |
| }
 | |
| 
 | |
| static int sysconfig_spi_bitstream_burst_complete(struct sysconfig_priv *priv)
 | |
| {
 | |
| 	struct spi_device *spi = to_spi_device(priv->dev);
 | |
| 
 | |
| 	/* Bitstream burst write is done, release SPI bus */
 | |
| 	spi_bus_unlock(spi->controller);
 | |
| 
 | |
| 	/* Toggle CS to finish bitstream write */
 | |
| 	return spi_write(spi, NULL, 0);
 | |
| }
 | |
| 
 | |
| static int sysconfig_spi_probe(struct spi_device *spi)
 | |
| {
 | |
| 	const struct spi_device_id *dev_id;
 | |
| 	struct device *dev = &spi->dev;
 | |
| 	struct sysconfig_priv *priv;
 | |
| 	const u32 *spi_max_speed;
 | |
| 
 | |
| 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 | |
| 	if (!priv)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	spi_max_speed = device_get_match_data(dev);
 | |
| 	if (!spi_max_speed) {
 | |
| 		dev_id = spi_get_device_id(spi);
 | |
| 		if (!dev_id)
 | |
| 			return -ENODEV;
 | |
| 
 | |
| 		spi_max_speed = (const u32 *)dev_id->driver_data;
 | |
| 	}
 | |
| 
 | |
| 	if (!spi_max_speed)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	if (spi->max_speed_hz > *spi_max_speed) {
 | |
| 		dev_err(dev, "SPI speed %u is too high, maximum speed is %u\n",
 | |
| 			spi->max_speed_hz, *spi_max_speed);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	priv->dev = dev;
 | |
| 	priv->command_transfer = sysconfig_spi_cmd_transfer;
 | |
| 	priv->bitstream_burst_write_init = sysconfig_spi_bitstream_burst_init;
 | |
| 	priv->bitstream_burst_write = sysconfig_spi_bitstream_burst_write;
 | |
| 	priv->bitstream_burst_write_complete = sysconfig_spi_bitstream_burst_complete;
 | |
| 
 | |
| 	return sysconfig_probe(priv);
 | |
| }
 | |
| 
 | |
| static const struct spi_device_id sysconfig_spi_ids[] = {
 | |
| 	{
 | |
| 		.name = "sysconfig-ecp5",
 | |
| 		.driver_data = (kernel_ulong_t)&ecp5_spi_max_speed_hz,
 | |
| 	}, {},
 | |
| };
 | |
| MODULE_DEVICE_TABLE(spi, sysconfig_spi_ids);
 | |
| 
 | |
| #if IS_ENABLED(CONFIG_OF)
 | |
| static const struct of_device_id sysconfig_of_ids[] = {
 | |
| 	{
 | |
| 		.compatible = "lattice,sysconfig-ecp5",
 | |
| 		.data = &ecp5_spi_max_speed_hz,
 | |
| 	}, {},
 | |
| };
 | |
| MODULE_DEVICE_TABLE(of, sysconfig_of_ids);
 | |
| #endif /* IS_ENABLED(CONFIG_OF) */
 | |
| 
 | |
| static struct spi_driver lattice_sysconfig_driver = {
 | |
| 	.probe = sysconfig_spi_probe,
 | |
| 	.id_table = sysconfig_spi_ids,
 | |
| 	.driver = {
 | |
| 		.name = "lattice_sysconfig_spi_fpga_mgr",
 | |
| 		.of_match_table = of_match_ptr(sysconfig_of_ids),
 | |
| 	},
 | |
| };
 | |
| module_spi_driver(lattice_sysconfig_driver);
 | |
| 
 | |
| MODULE_DESCRIPTION("Lattice sysCONFIG Slave SPI FPGA Manager");
 | |
| MODULE_LICENSE("GPL");
 |