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 18 static void gpio_spi_delay_us(void) 19 { 20 udelay(gpio_spidev.gpio_data.spi_delay_us); 21 } 22 23 static int gpio_spi_miso(void) 24 { 25 return gpio_get_value(gpio_spidev.gpio_data.miso_gpio); 26 } 27 28 static void gpio_spi_sclk(int bit) 29 { 30 gpio_set_value(gpio_spidev.gpio_data.sclk_gpio, bit); 31 } 32 33 static void gpio_spi_mosi(int bit) 34 { 35 gpio_set_value(gpio_spidev.gpio_data.mosi_gpio, bit); 36 } 37 38 static void gpio_spi_cs(int bit) 39 { 40 gpio_set_value(gpio_spidev.gpio_data.cs_gpio, bit); 41 } 42 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 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 */ 56 static void gpio_spi_get_access(void) 57 { 58 gpio_spi_sclk(0); 59 } 60 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 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 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