/* SPDX-License-Identifier: GPL-2.0-only */ /* Compile this driver in place of common/spi.c for bitbang testing. NOTE: Also need to adjust board-specific code for GPIO pinmux! */ #include <assert.h> #include <gpio.h> #include <soc/spi.h> #include <spi_bitbang.h> #include <spi_flash.h> #include <stddef.h> struct rockchip_bitbang_slave { struct spi_bitbang_ops ops; gpio_t miso; gpio_t mosi; gpio_t clk; gpio_t cs; }; static int get_miso(const struct spi_bitbang_ops *ops) { const struct rockchip_bitbang_slave *slave = container_of(ops, const struct rockchip_bitbang_slave, ops); return gpio_get(slave->miso); } static void set_mosi(const struct spi_bitbang_ops *ops, int value) { const struct rockchip_bitbang_slave *slave = container_of(ops, const struct rockchip_bitbang_slave, ops); gpio_set(slave->mosi, value); } static void set_clk(const struct spi_bitbang_ops *ops, int value) { const struct rockchip_bitbang_slave *slave = container_of(ops, const struct rockchip_bitbang_slave, ops); gpio_set(slave->clk, value); } static void set_cs(const struct spi_bitbang_ops *ops, int value) { const struct rockchip_bitbang_slave *slave = container_of(ops, const struct rockchip_bitbang_slave, ops); gpio_set(slave->cs, value); } /* Can't use GPIO() here because of bug in GCC version used by ChromiumOS. */ static const struct rockchip_bitbang_slave slaves[] = { [0] = { .ops = { get_miso, set_mosi, set_clk, set_cs }, .miso = { .port = 3, .bank = GPIO_A, .idx = 4 }, .mosi = { .port = 3, .bank = GPIO_A, .idx = 5 }, .clk = { .port = 3, .bank = GPIO_A, .idx = 6 }, .cs = { .port = 3, .bank = GPIO_A, .idx = 7 }, }, [1] = { .ops = { get_miso, set_mosi, set_clk, set_cs }, .miso = { .port = 1, .bank = GPIO_A, .idx = 7 }, .mosi = { .port = 1, .bank = GPIO_B, .idx = 0 }, .clk = { .port = 1, .bank = GPIO_B, .idx = 1 }, .cs = { .port = 1, .bank = GPIO_B, .idx = 2 }, }, [2] = { .ops = { get_miso, set_mosi, set_clk, set_cs }, .miso = { .port = 2, .bank = GPIO_B, .idx = 1 }, .mosi = { .port = 2, .bank = GPIO_B, .idx = 2 }, .clk = { .port = 2, .bank = GPIO_B, .idx = 3 }, .cs = { .port = 2, .bank = GPIO_B, .idx = 4 }, }, [3] = { .ops = { get_miso, set_mosi, set_clk, set_cs }, .miso = { .port = 1, .bank = GPIO_B, .idx = 7 }, .mosi = { .port = 1, .bank = GPIO_C, .idx = 0 }, .clk = { .port = 1, .bank = GPIO_C, .idx = 1 }, .cs = { .port = 1, .bank = GPIO_C, .idx = 2 }, }, [4] = { .ops = { get_miso, set_mosi, set_clk, set_cs }, .miso = { .port = 3, .bank = GPIO_A, .idx = 0 }, .mosi = { .port = 3, .bank = GPIO_A, .idx = 1 }, .clk = { .port = 3, .bank = GPIO_A, .idx = 2 }, .cs = { .port = 3, .bank = GPIO_A, .idx = 3 }, }, [5] = { .ops = { get_miso, set_mosi, set_clk, set_cs }, .miso = { .port = 2, .bank = GPIO_C, .idx = 4 }, .mosi = { .port = 2, .bank = GPIO_C, .idx = 5 }, .clk = { .port = 2, .bank = GPIO_C, .idx = 6 }, .cs = { .port = 2, .bank = GPIO_C, .idx = 7 }, }, }; void rockchip_spi_init(unsigned int bus, unsigned int ignored_speed_hz) { assert(bus >= 0 && bus < ARRAY_SIZE(slaves)); gpio_output(slaves[bus].cs, 1); gpio_output(slaves[bus].clk, 0); gpio_input(slaves[bus].miso); gpio_output(slaves[bus].mosi, 0); } void rockchip_spi_set_sample_delay(unsigned int bus, unsigned int delay_ns) { /* not supported, and not necessary for slow bitbang speeds */ } static int spi_ctrlr_claim_bus(const struct spi_slave *slave) { assert(slave->bus >= 0 && slave->bus < ARRAY_SIZE(slaves)); return spi_bitbang_claim_bus(&slaves[slave->bus].ops); } static void spi_ctrlr_release_bus(const struct spi_slave *slave) { assert(slave->bus >= 0 && slave->bus < ARRAY_SIZE(slaves)); spi_bitbang_release_bus(&slaves[slave->bus].ops); } static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, size_t bytes_out, void *din, size_t bytes_in) { assert(slave->bus >= 0 && slave->bus < ARRAY_SIZE(slaves)); return spi_bitbang_xfer(&slaves[slave->bus].ops, dout, bytes_out, din, bytes_in); } static const struct spi_ctrlr spi_ctrlr = { .claim_bus = spi_ctrlr_claim_bus, .release_bus = spi_ctrlr_release_bus, .xfer = spi_ctrlr_xfer, .max_xfer_size = 65535, }; const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { { .ctrlr = &spi_ctrlr, .bus_start = 0, .bus_end = ARRAY_SIZE(slaves) - 1, }, }; const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);