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 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 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 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 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 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 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 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 */ 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 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 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 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