File indexing completed on 2025-05-11 08:24:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <bsp.h>
0037 #include <dev/spi/spi.h>
0038 #include <dev/spi/spi-gpio.h>
0039
0040 struct spi_gpio_bus {
0041 spi_bus base;
0042 const struct spi_gpio_params *p;
0043 };
0044
0045 static int spi_gpio_check_msg(
0046 struct spi_gpio_bus *bus,
0047 const spi_ioc_transfer *msg
0048 )
0049 {
0050
0051
0052
0053
0054
0055
0056 if ((msg->mode & ~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0 ||
0057 (msg->bits_per_word != 8) ||
0058 (msg->delay_usecs != 0) ||
0059 (msg->cs >= SPI_GPIO_MAX_CS) ||
0060 (bus->p->set_cs[msg->cs] == NULL)) {
0061 return -EINVAL;
0062 }
0063
0064 return 0;
0065 }
0066
0067 static int spi_gpio_transfer_msg(
0068 struct spi_gpio_bus *bus,
0069 const spi_ioc_transfer *msg
0070 )
0071 {
0072 uint8_t cs = msg->cs;
0073 bool clk_idle = ((msg->mode & SPI_CPOL) != 0);
0074 bool cpha = ((msg->mode & SPI_CPHA) != 0);
0075 const uint8_t *tx_buf = msg->tx_buf;
0076 uint8_t *rx_buf = msg->rx_buf;
0077 size_t len = msg->len;
0078 int i;
0079 int rv;
0080
0081 rv = spi_gpio_check_msg(bus, msg);
0082 if (rv != 0) {
0083 return rv;
0084 }
0085
0086
0087
0088
0089
0090
0091 for (i = 0; i < SPI_GPIO_MAX_CS; ++i) {
0092 if (i != cs && bus->p->set_cs[i] != NULL) {
0093 bus->p->set_cs[i](bus->p->set_cs_arg[i], bus->p->cs_idle[i]);
0094 }
0095 }
0096
0097
0098 bus->p->set_clk(bus->p->set_clk_arg, clk_idle);
0099
0100
0101 bus->p->set_cs[cs](bus->p->set_cs_arg[cs], !bus->p->cs_idle[cs]);
0102
0103 while (len > 0) {
0104 uint8_t out = 0xff;
0105 uint8_t in = 0;
0106 size_t ctr;
0107
0108 --len;
0109
0110 if (tx_buf != NULL) {
0111 out = *tx_buf;
0112 ++tx_buf;
0113 }
0114
0115
0116
0117
0118
0119
0120
0121 for (ctr = 0; ctr < sizeof(out) * 8; ++ctr) {
0122 bool d_out;
0123 bool d_in;
0124
0125 if (cpha) {
0126 bus->p->set_clk(bus->p->set_clk_arg, !clk_idle);
0127 }
0128
0129 d_out = ((out & 0x80) != 0);
0130 out <<= 1;
0131 bus->p->set_mosi(bus->p->set_mosi_arg, d_out);
0132
0133 d_in = bus->p->get_miso(bus->p->get_miso_arg);
0134 in = (in << 1) | (d_in ? 1 : 0);
0135
0136 if (!cpha) {
0137 bus->p->set_clk(bus->p->set_clk_arg, !clk_idle);
0138 }
0139 bus->p->set_clk(bus->p->set_clk_arg, clk_idle);
0140 }
0141
0142 if (rx_buf != NULL) {
0143 *rx_buf = in;
0144 ++rx_buf;
0145 }
0146 }
0147
0148
0149 if (msg->cs_change) {
0150 bus->p->set_cs[cs](bus->p->set_cs_arg[cs], bus->p->cs_idle[cs]);
0151 }
0152
0153 return 0;
0154 }
0155
0156 static int spi_gpio_transfer(
0157 spi_bus *base,
0158 const spi_ioc_transfer *msgs,
0159 uint32_t n
0160 )
0161 {
0162 struct spi_gpio_bus *bus;
0163 bus = (struct spi_gpio_bus *) base;
0164 int rv = 0;
0165
0166 while (n > 0 && rv == 0) {
0167 rv = spi_gpio_transfer_msg(bus, msgs);
0168 --n;
0169 ++msgs;
0170 };
0171
0172 return rv;
0173 }
0174
0175 static void spi_gpio_destroy(spi_bus *base)
0176 {
0177 struct spi_gpio_bus *bus;
0178 bus = (struct spi_gpio_bus *) base;
0179 spi_bus_destroy_and_free(&bus->base);
0180 }
0181
0182 static int spi_gpio_setup(spi_bus *base)
0183 {
0184 struct spi_gpio_bus *bus;
0185 bus = (struct spi_gpio_bus *) base;
0186 struct spi_ioc_transfer msg = {
0187 .speed_hz = base->speed_hz,
0188 .delay_usecs = base->delay_usecs,
0189 .bits_per_word = base->bits_per_word,
0190 .mode = base->mode,
0191 .cs = base->cs,
0192 };
0193
0194 return spi_gpio_check_msg(bus, &msg);
0195 }
0196
0197 rtems_status_code
0198 spi_gpio_init(const char* device, const struct spi_gpio_params *params)
0199 {
0200 struct spi_gpio_bus *bus;
0201 int eno;
0202
0203 if (device == NULL || params == NULL) {
0204 return RTEMS_INVALID_ADDRESS;
0205 }
0206
0207 bus = (struct spi_gpio_bus*) spi_bus_alloc_and_init(sizeof(*bus));
0208 if (bus == NULL) {
0209 return RTEMS_UNSATISFIED;
0210 }
0211
0212 bus->p = params;
0213
0214 bus->base.transfer = spi_gpio_transfer;
0215 bus->base.destroy = spi_gpio_destroy;
0216 bus->base.setup = spi_gpio_setup;
0217
0218 eno = spi_bus_register(&bus->base, device);
0219 if (eno != 0) {
0220 spi_bus_destroy_and_free(&bus->base);
0221 return RTEMS_UNSATISFIED;
0222 }
0223
0224 return RTEMS_SUCCESSFUL;
0225 }