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