• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /* Compile this driver in place of common/spi.c for bitbang testing.
4    NOTE: Also need to adjust board-specific code for GPIO pinmux! */
5 
6 #include <assert.h>
7 #include <gpio.h>
8 #include <soc/spi.h>
9 #include <spi_bitbang.h>
10 #include <spi_flash.h>
11 #include <stddef.h>
12 
13 struct rockchip_bitbang_slave {
14 	struct spi_bitbang_ops ops;
15 	gpio_t miso;
16 	gpio_t mosi;
17 	gpio_t clk;
18 	gpio_t cs;
19 };
20 
get_miso(const struct spi_bitbang_ops * ops)21 static int get_miso(const struct spi_bitbang_ops *ops)
22 {
23 	const struct rockchip_bitbang_slave *slave =
24 		container_of(ops, const struct rockchip_bitbang_slave, ops);
25 	return gpio_get(slave->miso);
26 }
27 
set_mosi(const struct spi_bitbang_ops * ops,int value)28 static void set_mosi(const struct spi_bitbang_ops *ops, int value)
29 {
30 	const struct rockchip_bitbang_slave *slave =
31 		container_of(ops, const struct rockchip_bitbang_slave, ops);
32 	gpio_set(slave->mosi, value);
33 }
34 
set_clk(const struct spi_bitbang_ops * ops,int value)35 static void set_clk(const struct spi_bitbang_ops *ops, int value)
36 {
37 	const struct rockchip_bitbang_slave *slave =
38 		container_of(ops, const struct rockchip_bitbang_slave, ops);
39 	gpio_set(slave->clk, value);
40 }
41 
set_cs(const struct spi_bitbang_ops * ops,int value)42 static void set_cs(const struct spi_bitbang_ops *ops, int value)
43 {
44 	const struct rockchip_bitbang_slave *slave =
45 		container_of(ops, const struct rockchip_bitbang_slave, ops);
46 	gpio_set(slave->cs, value);
47 }
48 
49 /* Can't use GPIO() here because of bug in GCC version used by ChromiumOS. */
50 static const struct rockchip_bitbang_slave slaves[] = {
51 	[0] = {
52 		.ops = { get_miso, set_mosi, set_clk, set_cs },
53 		.miso	= { .port = 3, .bank = GPIO_A, .idx = 4 },
54 		.mosi	= { .port = 3, .bank = GPIO_A, .idx = 5 },
55 		.clk	= { .port = 3, .bank = GPIO_A, .idx = 6 },
56 		.cs	= { .port = 3, .bank = GPIO_A, .idx = 7 },
57 	},
58 	[1]	= {
59 		.ops = { get_miso, set_mosi, set_clk, set_cs },
60 		.miso	= { .port = 1, .bank = GPIO_A, .idx = 7 },
61 		.mosi	= { .port = 1, .bank = GPIO_B, .idx = 0 },
62 		.clk	= { .port = 1, .bank = GPIO_B, .idx = 1 },
63 		.cs	= { .port = 1, .bank = GPIO_B, .idx = 2 },
64 	},
65 	[2]	= {
66 		.ops = { get_miso, set_mosi, set_clk, set_cs },
67 		.miso	= { .port = 2, .bank = GPIO_B, .idx = 1 },
68 		.mosi	= { .port = 2, .bank = GPIO_B, .idx = 2 },
69 		.clk	= { .port = 2, .bank = GPIO_B, .idx = 3 },
70 		.cs	= { .port = 2, .bank = GPIO_B, .idx = 4 },
71 	},
72 	[3]	= {
73 		.ops = { get_miso, set_mosi, set_clk, set_cs },
74 		.miso	= { .port = 1, .bank = GPIO_B, .idx = 7 },
75 		.mosi	= { .port = 1, .bank = GPIO_C, .idx = 0 },
76 		.clk	= { .port = 1, .bank = GPIO_C, .idx = 1 },
77 		.cs	= { .port = 1, .bank = GPIO_C, .idx = 2 },
78 	},
79 	[4]	= {
80 		.ops = { get_miso, set_mosi, set_clk, set_cs },
81 		.miso	= { .port = 3, .bank = GPIO_A, .idx = 0 },
82 		.mosi	= { .port = 3, .bank = GPIO_A, .idx = 1 },
83 		.clk	= { .port = 3, .bank = GPIO_A, .idx = 2 },
84 		.cs	= { .port = 3, .bank = GPIO_A, .idx = 3 },
85 	},
86 	[5]	= {
87 		.ops = { get_miso, set_mosi, set_clk, set_cs },
88 		.miso	= { .port = 2, .bank = GPIO_C, .idx = 4 },
89 		.mosi	= { .port = 2, .bank = GPIO_C, .idx = 5 },
90 		.clk	= { .port = 2, .bank = GPIO_C, .idx = 6 },
91 		.cs	= { .port = 2, .bank = GPIO_C, .idx = 7 },
92 	},
93 };
94 
rockchip_spi_init(unsigned int bus,unsigned int ignored_speed_hz)95 void rockchip_spi_init(unsigned int bus, unsigned int ignored_speed_hz)
96 {
97 	assert(bus >= 0 && bus < ARRAY_SIZE(slaves));
98 
99 	gpio_output(slaves[bus].cs, 1);
100 	gpio_output(slaves[bus].clk, 0);
101 	gpio_input(slaves[bus].miso);
102 	gpio_output(slaves[bus].mosi, 0);
103 }
104 
rockchip_spi_set_sample_delay(unsigned int bus,unsigned int delay_ns)105 void rockchip_spi_set_sample_delay(unsigned int bus, unsigned int delay_ns)
106 {
107 	/* not supported, and not necessary for slow bitbang speeds */
108 }
109 
spi_ctrlr_claim_bus(const struct spi_slave * slave)110 static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
111 {
112 	assert(slave->bus >= 0 && slave->bus < ARRAY_SIZE(slaves));
113 	return spi_bitbang_claim_bus(&slaves[slave->bus].ops);
114 }
115 
spi_ctrlr_release_bus(const struct spi_slave * slave)116 static void spi_ctrlr_release_bus(const struct spi_slave *slave)
117 {
118 	assert(slave->bus >= 0 && slave->bus < ARRAY_SIZE(slaves));
119 	spi_bitbang_release_bus(&slaves[slave->bus].ops);
120 }
121 
spi_ctrlr_xfer(const struct spi_slave * slave,const void * dout,size_t bytes_out,void * din,size_t bytes_in)122 static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
123 			  size_t bytes_out, void *din, size_t bytes_in)
124 {
125 	assert(slave->bus >= 0 && slave->bus < ARRAY_SIZE(slaves));
126 	return spi_bitbang_xfer(&slaves[slave->bus].ops,
127 				dout, bytes_out, din, bytes_in);
128 }
129 
130 static const struct spi_ctrlr spi_ctrlr = {
131 	.claim_bus = spi_ctrlr_claim_bus,
132 	.release_bus = spi_ctrlr_release_bus,
133 	.xfer = spi_ctrlr_xfer,
134 	.max_xfer_size = 65535,
135 };
136 
137 const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
138 	{
139 		.ctrlr = &spi_ctrlr,
140 		.bus_start = 0,
141 		.bus_end = ARRAY_SIZE(slaves) - 1,
142 	},
143 };
144 
145 const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);
146