1.1 --- a/pkg/devices/Control Sat Oct 14 22:02:07 2023 +0200
1.2 +++ b/pkg/devices/Control Tue Oct 24 17:15:40 2023 +0200
1.3 @@ -39,5 +39,6 @@
1.4 provides: libdrivers-panel-loader
1.5 provides: libdrivers-panel-qi_lb60
1.6 provides: libdrivers-pwm
1.7 +provides: libdrivers-spi
1.8 requires: libc libc_be_l4re libdl l4re_c libio libipc
1.9 Maintainer: paul@boddie.org.uk
2.1 --- a/pkg/devices/lib/Makefile Sat Oct 14 22:02:07 2023 +0200
2.2 +++ b/pkg/devices/lib/Makefile Tue Oct 24 17:15:40 2023 +0200
2.3 @@ -1,7 +1,7 @@
2.4 PKGDIR ?= ..
2.5 L4DIR ?= $(PKGDIR)/../..
2.6
2.7 -TARGET := common cpm dma gpio hdmi i2c keypad lcd panel pwm
2.8 +TARGET := common cpm dma gpio hdmi i2c keypad lcd panel pwm spi
2.9
2.10 include $(L4DIR)/mk/subdir.mk
2.11
2.12 @@ -14,3 +14,4 @@
2.13 lcd: common
2.14 panel: lcd
2.15 pwm: common
2.16 +spi: common
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/pkg/devices/lib/spi/Makefile Tue Oct 24 17:15:40 2023 +0200
3.3 @@ -0,0 +1,8 @@
3.4 +PKGDIR ?= ../..
3.5 +L4DIR ?= $(PKGDIR)/../..
3.6 +
3.7 +TARGET := include src
3.8 +
3.9 +include $(L4DIR)/mk/subdir.mk
3.10 +
3.11 +src: include
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/pkg/devices/lib/spi/include/Makefile Tue Oct 24 17:15:40 2023 +0200
4.3 @@ -0,0 +1,4 @@
4.4 +PKGDIR = ../../..
4.5 +L4DIR ?= $(PKGDIR)/../..
4.6 +
4.7 +include $(L4DIR)/mk/include.mk
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/pkg/devices/lib/spi/include/spi-gpio.h Tue Oct 24 17:15:40 2023 +0200
5.3 @@ -0,0 +1,69 @@
5.4 +/*
5.5 + * Perform SPI communication using GPIO operations.
5.6 + *
5.7 + * Copyright (C) 2018, 2020, 2023 Paul Boddie <paul@boddie.org.uk>
5.8 + *
5.9 + * This program is free software; you can redistribute it and/or
5.10 + * modify it under the terms of the GNU General Public License as
5.11 + * published by the Free Software Foundation; either version 2 of
5.12 + * the License, or (at your option) any later version.
5.13 + *
5.14 + * This program is distributed in the hope that it will be useful,
5.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.17 + * GNU General Public License for more details.
5.18 + *
5.19 + * You should have received a copy of the GNU General Public License
5.20 + * along with this program; if not, write to the Free Software
5.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
5.22 + * Boston, MA 02110-1301, USA
5.23 + */
5.24 +
5.25 +#include <l4/devices/gpio.h>
5.26 +#include <stdint.h>
5.27 +
5.28 +#pragma once
5.29 +
5.30 +
5.31 +
5.32 +#ifdef __cplusplus
5.33 +
5.34 +/* SPI peripheral device. */
5.35 +
5.36 +class Spi_gpio
5.37 +{
5.38 + Hw::Gpio_chip *_clock_device;
5.39 + int _clock_pin;
5.40 + Hw::Gpio_chip *_data_device;
5.41 + int _data_pin;
5.42 + Hw::Gpio_chip *_enable_device;
5.43 + int _enable_pin;
5.44 + uint32_t _frequency;
5.45 +
5.46 +public:
5.47 + /* Associate the device with a particular memory region. */
5.48 +
5.49 + explicit Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin,
5.50 + Hw::Gpio_chip *data_device, int data_pin,
5.51 + Hw::Gpio_chip *enable_device, int enable_pin,
5.52 + uint32_t frequency = 0);
5.53 +
5.54 + void send(int bytes, uint8_t data[]);
5.55 +};
5.56 +
5.57 +#endif /* __cplusplus */
5.58 +
5.59 +
5.60 +
5.61 +/* C language interface. */
5.62 +
5.63 +EXTERN_C_BEGIN
5.64 +
5.65 +void *spi_gpio_get_channel(void *clock_chip, int clock_pin,
5.66 + void *data_chip, int data_pin,
5.67 + void *enable_chip, int enable_pin,
5.68 + uint32_t frequency);
5.69 +
5.70 +void spi_gpio_send(void *channel, int bytes, uint8_t data[]);
5.71 +
5.72 +EXTERN_C_END
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/pkg/devices/lib/spi/src/Makefile Tue Oct 24 17:15:40 2023 +0200
6.3 @@ -0,0 +1,13 @@
6.4 +PKGDIR ?= ../../..
6.5 +L4DIR ?= $(PKGDIR)/../..
6.6 +
6.7 +TARGET = libspi.o.a libspi.o.so
6.8 +PC_FILENAME := libdrivers-spi
6.9 +
6.10 +SRC_CC := gpio.cc
6.11 +
6.12 +PRIVATE_INCDIR += $(PKGDIR)/lib/spi/include
6.13 +
6.14 +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common libdrivers-gpio
6.15 +
6.16 +include $(L4DIR)/mk/lib.mk
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/pkg/devices/lib/spi/src/gpio.cc Tue Oct 24 17:15:40 2023 +0200
7.3 @@ -0,0 +1,116 @@
7.4 +/*
7.5 + * Perform SPI communication using GPIO operations.
7.6 + *
7.7 + * Copyright (C) 2018, 2020, 2023 Paul Boddie <paul@boddie.org.uk>
7.8 + *
7.9 + * This program is free software; you can redistribute it and/or
7.10 + * modify it under the terms of the GNU General Public License as
7.11 + * published by the Free Software Foundation; either version 2 of
7.12 + * the License, or (at your option) any later version.
7.13 + *
7.14 + * This program is distributed in the hope that it will be useful,
7.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.17 + * GNU General Public License for more details.
7.18 + *
7.19 + * You should have received a copy of the GNU General Public License
7.20 + * along with this program; if not, write to the Free Software
7.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
7.22 + * Boston, MA 02110-1301, USA
7.23 + */
7.24 +
7.25 +#include <l4/devices/spi-gpio.h>
7.26 +#include <time.h>
7.27 +
7.28 +
7.29 +
7.30 +Spi_gpio::Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin,
7.31 + Hw::Gpio_chip *data_device, int data_pin,
7.32 + Hw::Gpio_chip *enable_device, int enable_pin,
7.33 + uint32_t frequency)
7.34 +: _clock_device(clock_device),
7.35 + _clock_pin(clock_pin),
7.36 + _data_device(data_device),
7.37 + _data_pin(data_pin),
7.38 + _enable_device(enable_device),
7.39 + _enable_pin(enable_pin),
7.40 + _frequency(frequency)
7.41 +{
7.42 + _clock_device->setup(_clock_pin, Hw::Gpio_chip::Output, 1);
7.43 + _data_device->setup(_data_pin, Hw::Gpio_chip::Output, 0);
7.44 + _enable_device->setup(_enable_pin, Hw::Gpio_chip::Output, 1);
7.45 +}
7.46 +
7.47 +/* Send a SPI command. */
7.48 +
7.49 +void Spi_gpio::send(int bytes, uint8_t data[])
7.50 +{
7.51 + struct timespec ts;
7.52 + uint8_t mask;
7.53 + int bit, byte;
7.54 +
7.55 + if (_frequency)
7.56 + {
7.57 + ts.tv_sec = 0;
7.58 + ts.tv_nsec = 1000000000 / _frequency;
7.59 + }
7.60 +
7.61 + /* Initialise pin levels. */
7.62 +
7.63 + _enable_device->set(_enable_pin, 1);
7.64 + _clock_device->set(_clock_pin, 1);
7.65 + _data_device->set(_data_pin, 0);
7.66 +
7.67 + /* Enter the transmission state. */
7.68 +
7.69 + _enable_device->set(_enable_pin, 0);
7.70 +
7.71 + /* Clock data using the clock and data outputs. */
7.72 +
7.73 + for (byte = 0; byte < bytes; byte++)
7.74 + {
7.75 + mask = 0x80;
7.76 +
7.77 + for (bit = 0; bit < 8; bit++)
7.78 + {
7.79 + /* NOTE: Data presented on falling clock level and sampled on rising clock
7.80 + level. This is SPI mode 3, or 0 given that the enable level is
7.81 + driven low immediately before the first bit is presented. */
7.82 +
7.83 + _clock_device->set(_clock_pin, 0);
7.84 + _data_device->set(_data_pin, data[byte] & mask ? 1 : 0);
7.85 +
7.86 + if (_frequency)
7.87 + nanosleep(&ts, NULL);
7.88 +
7.89 + _clock_device->set(_clock_pin, 1);
7.90 +
7.91 + if (_frequency)
7.92 + nanosleep(&ts, NULL);
7.93 +
7.94 + mask >>= 1;
7.95 + }
7.96 + }
7.97 +
7.98 + _enable_device->set(_enable_pin, 1);
7.99 +}
7.100 +
7.101 +
7.102 +
7.103 +/* C language interface. */
7.104 +
7.105 +void *spi_gpio_get_channel(void *clock_chip, int clock_pin,
7.106 + void *data_chip, int data_pin,
7.107 + void *enable_chip, int enable_pin,
7.108 + uint32_t frequency)
7.109 +{
7.110 + return (void *) new Spi_gpio(reinterpret_cast<Hw::Gpio_chip *>(clock_chip), clock_pin,
7.111 + reinterpret_cast<Hw::Gpio_chip *>(data_chip), data_pin,
7.112 + reinterpret_cast<Hw::Gpio_chip *>(enable_chip), enable_pin,
7.113 + frequency);
7.114 +}
7.115 +
7.116 +void spi_gpio_send(void *channel, int bytes, uint8_t data[])
7.117 +{
7.118 + static_cast<Spi_gpio *>(channel)->send(bytes, data);
7.119 +}
8.1 --- a/pkg/devices/spi/src/jz4740/Makefile Sat Oct 14 22:02:07 2023 +0200
8.2 +++ b/pkg/devices/spi/src/jz4740/Makefile Tue Oct 24 17:15:40 2023 +0200
8.3 @@ -27,7 +27,7 @@
8.4
8.5 SRC_CC = $(SERVER_INTERFACES_SRC_CC) $(PLAIN_SRC_CC)
8.6
8.7 -REQUIRES_LIBS = l4re_c l4re_c-util libdevice-util libdrivers-gpio libipc
8.8 +REQUIRES_LIBS = l4re_c l4re_c-util libdevice-util libdrivers-gpio libdrivers-spi libipc
8.9
8.10 PRIVATE_INCDIR = $(PKGDIR)/spi/include $(PKGDIR)/util/include \
8.11 $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
9.1 --- a/pkg/devices/spi/src/jz4740/spi-jz4740.cc Sat Oct 14 22:02:07 2023 +0200
9.2 +++ b/pkg/devices/spi/src/jz4740/spi-jz4740.cc Tue Oct 24 17:15:40 2023 +0200
9.3 @@ -20,6 +20,7 @@
9.4 */
9.5
9.6 #include <l4/devices/gpio-jz4740.h>
9.7 +#include <l4/devices/spi-gpio.h>
9.8 #include <l4/devices/memory.h>
9.9
9.10 #include <l4/re/env.h>
9.11 @@ -54,20 +55,13 @@
9.12
9.13 class SPI_server : public SPI
9.14 {
9.15 - Gpio_jz4740_chip *_clock_device = 0, *_data_device = 0, *_enable_device = 0;
9.16 - int _clock_pin, _data_pin, _enable_pin;
9.17 + Spi_gpio *_spi;
9.18
9.19 public:
9.20 /* Associate the device with a particular memory region. */
9.21
9.22 - explicit SPI_server(Gpio_jz4740_chip *clock_device,
9.23 - Gpio_jz4740_chip *data_device,
9.24 - Gpio_jz4740_chip *enable_device,
9.25 - int clock_pin, int data_pin, int enable_pin)
9.26 - : _clock_device(clock_device),
9.27 - _data_device(data_device),
9.28 - _enable_device(enable_device),
9.29 - _clock_pin(clock_pin), _data_pin(data_pin), _enable_pin(enable_pin)
9.30 + explicit SPI_server(Spi_gpio *spi)
9.31 + : _spi(spi)
9.32 {
9.33 }
9.34
9.35 @@ -75,31 +69,15 @@
9.36
9.37 long send(int bits, int data)
9.38 {
9.39 - uint32_t mask = 1 << (bits - 1);
9.40 - int bit;
9.41 -
9.42 - /* Initialise pin levels. */
9.43 + int bytes = (bits + 7) / 8;
9.44 + uint8_t buffer[bytes];
9.45
9.46 - _enable_device->set(_enable_pin, 1);
9.47 - _clock_device->set(_clock_pin, 1);
9.48 - _data_device->set(_data_pin, 0);
9.49 -
9.50 - /* Enter the transmission state. */
9.51 + /* Convert the data into a sequence of bytes. */
9.52
9.53 - _enable_device->set(_enable_pin, 0);
9.54 -
9.55 - /* Clock data using the clock and data outputs. */
9.56 -
9.57 - for (bit = 0; bit < bits; bit++)
9.58 - {
9.59 - _clock_device->set(_clock_pin, 0);
9.60 - _data_device->set(_data_pin, data & mask ? 1 : 0);
9.61 - _clock_device->set(_clock_pin, 1);
9.62 - mask >>= 1;
9.63 - }
9.64 + for (int byte = bytes; byte > 0; byte--)
9.65 + buffer[byte - 1] = (data >> ((byte - 1) * 8)) & 0xff;
9.66
9.67 - _enable_device->set(_enable_pin, 1);
9.68 -
9.69 + _spi->send(bytes, buffer);
9.70 return L4_EOK;
9.71 }
9.72 };
9.73 @@ -182,10 +160,14 @@
9.74
9.75 gpio_port_enable.setup(enable_pin, Hw::Gpio_chip::Output, 0);
9.76
9.77 + /* Create an object for SPI communication. */
9.78 +
9.79 + Spi_gpio spi(&gpio_port_clock, clock_pin, &gpio_port_data, data_pin,
9.80 + &gpio_port_enable, enable_pin);
9.81 +
9.82 /* Initialise and register a new server object. */
9.83
9.84 - SPI_server obj(&gpio_port_clock, &gpio_port_data, &gpio_port_enable,
9.85 - clock_pin, data_pin, enable_pin);
9.86 + SPI_server obj(&spi);
9.87
9.88 /* Bind and start the IPC server loop. */
9.89