blob: 2913b419299e067cd92dd610ca8ed74b4066fc34 [file] [log] [blame]
Abhi Singh3c545702024-11-18 10:29:36 -06001/*
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
16static struct spi_plat gpio_spidev;
17
18static void gpio_spi_delay_us(void)
19{
20 udelay(gpio_spidev.gpio_data.spi_delay_us);
21}
22
23static int gpio_spi_miso(void)
24{
25 return gpio_get_value(gpio_spidev.gpio_data.miso_gpio);
26}
27
28static void gpio_spi_sclk(int bit)
29{
30 gpio_set_value(gpio_spidev.gpio_data.sclk_gpio, bit);
31}
32
33static void gpio_spi_mosi(int bit)
34{
35 gpio_set_value(gpio_spidev.gpio_data.mosi_gpio, bit);
36}
37
38static void gpio_spi_cs(int bit)
39{
40 gpio_set_value(gpio_spidev.gpio_data.cs_gpio, bit);
41}
42
43static void gpio_spi_start(void)
44{
45 gpio_spi_cs(1);
46 gpio_spi_sclk(0);
47 gpio_spi_cs(0);
48}
49
50static 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 */
56static void gpio_spi_get_access(void)
57{
58 gpio_spi_sclk(0);
59}
60
61static 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
91static 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
117struct 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
124struct 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}