xref: /rk3399_ARM-atf/drivers/gpio/gpio_spi.c (revision 30a60389204f9ec44c890854e62ec1e0506cb9b9)
1 /*
2  * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdint.h>
8 #include <stdlib.h>
9 
10 #include <common/debug.h>
11 #include <drivers/delay_timer.h>
12 #include <drivers/gpio.h>
13 #include <drivers/gpio_spi.h>
14 #include <platform_def.h>
15 
16 static struct gpio_spi_config config;
17 
18 static struct spi_plat gpio_spidev;
19 
20 static uint32_t gpio_spi_get_delay_us(void)
21 {
22 	/* Delay used twice per clock cycle,
23 	 * high and low.
24 	 */
25 	return 500000 / config.spi_max_clock;
26 }
27 
28 static int gpio_spi_miso(void)
29 {
30 	return gpio_get_value(config.miso_gpio);
31 }
32 
33 static void gpio_spi_sclk(int bit)
34 {
35 	gpio_set_value(config.sclk_gpio, bit);
36 }
37 
38 static void gpio_spi_mosi(int bit)
39 {
40 	gpio_set_value(config.mosi_gpio, bit);
41 }
42 
43 static void gpio_spi_cs(int bit)
44 {
45 	gpio_set_value(config.cs_gpio, bit);
46 }
47 
48 static void gpio_spi_start(struct spi_priv *context)
49 {
50 	gpio_spi_cs(1);
51 	gpio_spi_sclk(0);
52 	gpio_spi_cs(0);
53 }
54 
55 static void gpio_spi_stop(struct spi_priv *context)
56 {
57 	gpio_spi_cs(1);
58 }
59 
60 /* set sclk to a known state (0) before performing any further action */
61 static int gpio_spi_get_access(struct spi_priv *context)
62 {
63 	gpio_spi_sclk(0);
64 	return 0;
65 }
66 
67 static void gpio_spi_release_access(struct spi_priv *context)
68 {
69 	/* No locking in this driver */
70 }
71 static void xfer(unsigned int bytes, const void *out, void *in, int cpol, int cpha)
72 {
73 	uint32_t delay_us = gpio_spi_get_delay_us();
74 	for (unsigned int j = 0U; j < bytes; j++) {
75 		unsigned char in_byte  = 0U;
76 		unsigned char out_byte = (out != NULL) ? *(const uint8_t *)out++ : 0xFF;
77 
78 		for (int i = 7; i >= 0; i--) {
79 			if (cpha) {
80 				gpio_spi_sclk(!cpol);
81 			}
82 
83 			gpio_spi_mosi(!!(out_byte & (1 << i)));
84 
85 			udelay(delay_us);
86 			gpio_spi_sclk(cpha ? cpol : !cpol);
87 			udelay(delay_us);
88 
89 			in_byte |= gpio_spi_miso() << i;
90 
91 			if (!cpha) {
92 				gpio_spi_sclk(cpol);
93 			}
94 		}
95 
96 		if (in != NULL) {
97 			*(uint8_t *)in++ = in_byte;
98 		}
99 	}
100 }
101 
102 static int gpio_spi_xfer(struct spi_priv *context, unsigned int bytes,
103 			 const void *out, void *in)
104 {
105 	if ((out == NULL) && (in == NULL)) {
106 		return -1;
107 	}
108 
109 	switch (config.spi_mode) {
110 	case 0:
111 		xfer(bytes, out, in, 0, 0);
112 		break;
113 	case 1:
114 		xfer(bytes, out, in, 0, 1);
115 		break;
116 	case 2:
117 		xfer(bytes, out, in, 1, 0);
118 		break;
119 	case 3:
120 		xfer(bytes, out, in, 1, 1);
121 		break;
122 	default:
123 		return -1;
124 	}
125 
126 	return 0;
127 }
128 
129 struct spi_ops gpio_spidev_ops = {
130 	.get_access = gpio_spi_get_access,
131 	.release_access = gpio_spi_release_access,
132 	.start = gpio_spi_start,
133 	.stop = gpio_spi_stop,
134 	.xfer = gpio_spi_xfer,
135 };
136 
137 struct spi_plat *gpio_spi_init(const struct gpio_spi_config *gpio_spi_data)
138 {
139 	gpio_spidev.priv = NULL; // No context, only one device supported
140 	config = *gpio_spi_data;
141 	gpio_spidev.ops = &gpio_spidev_ops;
142 
143 	gpio_set_value(gpio_spi_data->cs_gpio, 1);
144 	gpio_set_direction(gpio_spi_data->cs_gpio, GPIO_DIR_OUT);
145 
146 	gpio_set_value(gpio_spi_data->sclk_gpio, 0);
147 	gpio_set_direction(gpio_spi_data->sclk_gpio, GPIO_DIR_OUT);
148 
149 	gpio_set_value(gpio_spi_data->mosi_gpio, 1);
150 	gpio_set_direction(gpio_spi_data->mosi_gpio, GPIO_DIR_OUT);
151 
152 	gpio_set_direction(gpio_spi_data->miso_gpio, GPIO_DIR_IN);
153 
154 	return &gpio_spidev;
155 }
156