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