Commit | Line | Data |
---|---|---|
75a6faf6 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
061c97d1 | 2 | /* |
d1ddca78 | 3 | * Xilinx Spartan6 and 7 Series Slave Serial SPI Driver |
061c97d1 AG |
4 | * |
5 | * Copyright (C) 2017 DENX Software Engineering | |
6 | * | |
7 | * Anatolij Gustschin <agust@denx.de> | |
8 | * | |
061c97d1 AG |
9 | * Manage Xilinx FPGA firmware that is loaded over SPI using |
10 | * the slave serial configuration interface. | |
11 | */ | |
12 | ||
a52e3a9d CP |
13 | #include "xilinx-core.h" |
14 | ||
061c97d1 AG |
15 | #include <linux/module.h> |
16 | #include <linux/mod_devicetable.h> | |
17 | #include <linux/of.h> | |
18 | #include <linux/spi/spi.h> | |
061c97d1 | 19 | |
a52e3a9d | 20 | static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf, |
061c97d1 AG |
21 | size_t count) |
22 | { | |
a52e3a9d | 23 | struct spi_device *spi = to_spi_device(core->dev); |
061c97d1 AG |
24 | const char *fw_data = buf; |
25 | const char *fw_data_end = fw_data + count; | |
26 | ||
27 | while (fw_data < fw_data_end) { | |
28 | size_t remaining, stride; | |
29 | int ret; | |
30 | ||
31 | remaining = fw_data_end - fw_data; | |
32 | stride = min_t(size_t, remaining, SZ_4K); | |
33 | ||
a52e3a9d | 34 | ret = spi_write(spi, fw_data, stride); |
061c97d1 | 35 | if (ret) { |
a52e3a9d | 36 | dev_err(core->dev, "SPI error in firmware write: %d\n", |
061c97d1 AG |
37 | ret); |
38 | return ret; | |
39 | } | |
40 | fw_data += stride; | |
41 | } | |
42 | ||
43 | return 0; | |
44 | } | |
45 | ||
061c97d1 AG |
46 | static int xilinx_spi_probe(struct spi_device *spi) |
47 | { | |
a52e3a9d | 48 | struct xilinx_fpga_core *core; |
061c97d1 | 49 | |
a52e3a9d CP |
50 | core = devm_kzalloc(&spi->dev, sizeof(*core), GFP_KERNEL); |
51 | if (!core) | |
061c97d1 AG |
52 | return -ENOMEM; |
53 | ||
a52e3a9d CP |
54 | core->dev = &spi->dev; |
55 | core->write = xilinx_spi_write; | |
061c97d1 | 56 | |
a52e3a9d | 57 | return xilinx_core_probe(core); |
061c97d1 AG |
58 | } |
59 | ||
1aa3fc69 | 60 | #ifdef CONFIG_OF |
061c97d1 | 61 | static const struct of_device_id xlnx_spi_of_match[] = { |
a52e3a9d CP |
62 | { |
63 | .compatible = "xlnx,fpga-slave-serial", | |
64 | }, | |
061c97d1 AG |
65 | {} |
66 | }; | |
67 | MODULE_DEVICE_TABLE(of, xlnx_spi_of_match); | |
1aa3fc69 | 68 | #endif |
061c97d1 AG |
69 | |
70 | static struct spi_driver xilinx_slave_spi_driver = { | |
71 | .driver = { | |
72 | .name = "xlnx-slave-spi", | |
73 | .of_match_table = of_match_ptr(xlnx_spi_of_match), | |
74 | }, | |
75 | .probe = xilinx_spi_probe, | |
061c97d1 AG |
76 | }; |
77 | ||
78 | module_spi_driver(xilinx_slave_spi_driver) | |
79 | ||
80 | MODULE_LICENSE("GPL v2"); | |
81 | MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); | |
82 | MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SPI"); |