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