xref: /rk3399_ARM-atf/drivers/gpio/gpio_spi.c (revision 7e848540159ba8fbb0577c76e4dc0c5bbc542489)
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 spi_plat gpio_spidev;
17 
gpio_spi_delay_us(void)18 static void gpio_spi_delay_us(void)
19 {
20 	udelay(gpio_spidev.gpio_data.spi_delay_us);
21 }
22 
gpio_spi_miso(void)23 static int gpio_spi_miso(void)
24 {
25 	return gpio_get_value(gpio_spidev.gpio_data.miso_gpio);
26 }
27 
gpio_spi_sclk(int bit)28 static void gpio_spi_sclk(int bit)
29 {
30 	gpio_set_value(gpio_spidev.gpio_data.sclk_gpio, bit);
31 }
32 
gpio_spi_mosi(int bit)33 static void gpio_spi_mosi(int bit)
34 {
35 	gpio_set_value(gpio_spidev.gpio_data.mosi_gpio, bit);
36 }
37 
gpio_spi_cs(int bit)38 static void gpio_spi_cs(int bit)
39 {
40 	gpio_set_value(gpio_spidev.gpio_data.cs_gpio, bit);
41 }
42 
gpio_spi_start(void)43 static void gpio_spi_start(void)
44 {
45 	gpio_spi_cs(1);
46 	gpio_spi_sclk(0);
47 	gpio_spi_cs(0);
48 }
49 
gpio_spi_stop(void)50 static void gpio_spi_stop(void)
51 {
52 	gpio_spi_cs(1);
53 }
54 
55 /* set sclk to a known state (0) before performing any further action */
gpio_spi_get_access(void)56 static void gpio_spi_get_access(void)
57 {
58 	gpio_spi_sclk(0);
59 }
60 
xfer(unsigned int bytes,const void * out,void * in,int cpol,int cpha)61 static void xfer(unsigned int bytes, const void *out, void *in, int cpol, int cpha)
62 {
63 	for (unsigned int j = 0U; j < bytes; j++) {
64 		unsigned char in_byte  = 0U;
65 		unsigned char out_byte = (out != NULL) ? *(const uint8_t *)out++ : 0xFF;
66 
67 		for (int i = 7; i >= 0; i--) {
68 			if (cpha) {
69 				gpio_spi_sclk(!cpol);
70 			}
71 
72 			gpio_spi_mosi(!!(out_byte & (1 << i)));
73 
74 			gpio_spi_delay_us();
75 			gpio_spi_sclk(cpha ? cpol : !cpol);
76 			gpio_spi_delay_us();
77 
78 			in_byte |= gpio_spi_miso() << i;
79 
80 			if (!cpha) {
81 				gpio_spi_sclk(cpol);
82 			}
83 		}
84 
85 		if (in != NULL) {
86 			*(uint8_t *)in++ = in_byte;
87 		}
88 	}
89 }
90 
gpio_spi_xfer(unsigned int bytes,const void * out,void * in)91 static int gpio_spi_xfer(unsigned int bytes, const void *out, void *in)
92 {
93 	if ((out == NULL) && (in == NULL)) {
94 		return -1;
95 	}
96 
97 	switch (gpio_spidev.gpio_data.spi_mode) {
98 	case 0:
99 		xfer(bytes, out, in, 0, 0);
100 		break;
101 	case 1:
102 		xfer(bytes, out, in, 0, 1);
103 		break;
104 	case 2:
105 		xfer(bytes, out, in, 1, 0);
106 		break;
107 	case 3:
108 		xfer(bytes, out, in, 1, 1);
109 		break;
110 	default:
111 		return -1;
112 	}
113 
114 	return 0;
115 }
116 
117 struct spi_ops gpio_spidev_ops = {
118 	.get_access	= gpio_spi_get_access,
119 	.start		= gpio_spi_start,
120 	.stop		= gpio_spi_stop,
121 	.xfer		= gpio_spi_xfer,
122 };
123 
gpio_spi_init(struct gpio_spi_data * gpio_spi_data)124 struct spi_plat *gpio_spi_init(struct gpio_spi_data *gpio_spi_data)
125 {
126 	gpio_spidev.gpio_data = *gpio_spi_data;
127 	gpio_spidev.ops = &gpio_spidev_ops;
128 
129 	return &gpio_spidev;
130 }
131