1 /*
2 * Copyright (c) 2025-2026, 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 tpm_spi_plat gpio_spidev;
19
gpio_spi_get_delay_us(void)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
gpio_spi_miso(void)28 static int gpio_spi_miso(void)
29 {
30 return gpio_get_value(config.miso_gpio);
31 }
32
gpio_spi_sclk(int bit)33 static void gpio_spi_sclk(int bit)
34 {
35 gpio_set_value(config.sclk_gpio, bit);
36 }
37
gpio_spi_mosi(int bit)38 static void gpio_spi_mosi(int bit)
39 {
40 gpio_set_value(config.mosi_gpio, bit);
41 }
42
gpio_spi_cs(int bit)43 static void gpio_spi_cs(int bit)
44 {
45 gpio_set_value(config.cs_gpio, bit);
46 }
47
gpio_spi_start(struct tpm_spi_priv * context)48 static void gpio_spi_start(struct tpm_spi_priv *context)
49 {
50 gpio_spi_cs(1);
51 gpio_spi_sclk(0);
52 gpio_spi_cs(0);
53 }
54
gpio_spi_stop(struct tpm_spi_priv * context)55 static void gpio_spi_stop(struct tpm_spi_priv *context)
56 {
57 gpio_spi_cs(1);
58 }
59
60 /* set sclk to a known state (0) before performing any further action */
gpio_spi_get_access(struct tpm_spi_priv * context)61 static int gpio_spi_get_access(struct tpm_spi_priv *context)
62 {
63 gpio_spi_sclk(0);
64 return 0;
65 }
66
gpio_spi_release_access(struct tpm_spi_priv * context)67 static void gpio_spi_release_access(struct tpm_spi_priv *context)
68 {
69 /* No locking in this driver */
70 }
71
xfer(unsigned int bytes,const void * out,void * in,int cpol,int cpha)72 static void xfer(unsigned int bytes, const void *out, void *in, int cpol, int cpha)
73 {
74 uint32_t delay_us = gpio_spi_get_delay_us();
75 for (unsigned int j = 0U; j < bytes; j++) {
76 unsigned char in_byte = 0U;
77 unsigned char out_byte = (out != NULL) ? *(const uint8_t *)out++ : 0xFF;
78
79 for (int i = 7; i >= 0; i--) {
80 if (cpha) {
81 gpio_spi_sclk(!cpol);
82 }
83
84 gpio_spi_mosi(!!(out_byte & (1 << i)));
85
86 udelay(delay_us);
87 gpio_spi_sclk(cpha ? cpol : !cpol);
88 udelay(delay_us);
89
90 in_byte |= gpio_spi_miso() << i;
91
92 if (!cpha) {
93 gpio_spi_sclk(cpol);
94 }
95 }
96
97 if (in != NULL) {
98 *(uint8_t *)in++ = in_byte;
99 }
100 }
101 }
102
gpio_spi_xfer(struct tpm_spi_priv * context,unsigned int bytes,const uint8_t * out,uint8_t * in)103 static int gpio_spi_xfer(struct tpm_spi_priv *context, unsigned int bytes,
104 const uint8_t *out, uint8_t *in)
105 {
106 if ((out == NULL) && (in == NULL)) {
107 return -1;
108 }
109
110 switch (config.spi_mode) {
111 case 0:
112 xfer(bytes, out, in, 0, 0);
113 break;
114 case 1:
115 xfer(bytes, out, in, 0, 1);
116 break;
117 case 2:
118 xfer(bytes, out, in, 1, 0);
119 break;
120 case 3:
121 xfer(bytes, out, in, 1, 1);
122 break;
123 default:
124 return -1;
125 }
126
127 return 0;
128 }
129
130 struct tpm_spi_ops gpio_spidev_ops = {
131 .get_access = gpio_spi_get_access,
132 .release_access = gpio_spi_release_access,
133 .start = gpio_spi_start,
134 .stop = gpio_spi_stop,
135 .xfer = gpio_spi_xfer,
136 };
137
gpio_spi_init(const struct gpio_spi_config * gpio_spi_data)138 struct tpm_spi_plat *gpio_spi_init(const struct gpio_spi_config *gpio_spi_data)
139 {
140 gpio_spidev.priv = NULL; // No context, only one device supported
141 config = *gpio_spi_data;
142 gpio_spidev.ops = &gpio_spidev_ops;
143
144 gpio_set_value(gpio_spi_data->cs_gpio, 1);
145 gpio_set_direction(gpio_spi_data->cs_gpio, GPIO_DIR_OUT);
146
147 gpio_set_value(gpio_spi_data->sclk_gpio, 0);
148 gpio_set_direction(gpio_spi_data->sclk_gpio, GPIO_DIR_OUT);
149
150 gpio_set_value(gpio_spi_data->mosi_gpio, 1);
151 gpio_set_direction(gpio_spi_data->mosi_gpio, GPIO_DIR_OUT);
152
153 gpio_set_direction(gpio_spi_data->miso_gpio, GPIO_DIR_IN);
154
155 return &gpio_spidev;
156 }
157