1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/devices/lib/i2c/include/i2c-gpio.h Sat Oct 14 01:56:53 2023 +0200
1.3 @@ -0,0 +1,76 @@
1.4 +/*
1.5 + * Manual GPIO-based I2C communication.
1.6 + *
1.7 + * Copyright (C) 2013, 2023 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#pragma once
1.26 +
1.27 +#include <l4/devices/gpio.h>
1.28 +#include <stdint.h>
1.29 +
1.30 +/* I2C modifiers. */
1.31 +
1.32 +#define I2C_READ 1
1.33 +#define I2C_WRITE 0
1.34 +
1.35 +#ifdef __cplusplus
1.36 +
1.37 +class I2c_gpio
1.38 +{
1.39 + Hw::Gpio_chip *_scl_chip;
1.40 + int I2C_SCL;
1.41 + Hw::Gpio_chip *_sda_chip;
1.42 + int I2C_SDA;
1.43 +
1.44 + void CLR(int pin);
1.45 + void SET(int pin);
1.46 + void IN(int pin);
1.47 + int PIN(int pin);
1.48 + void wait();
1.49 +
1.50 +public:
1.51 + explicit I2c_gpio(Hw::Gpio_chip *scl_chip, int scl, Hw::Gpio_chip *sda_chip, int sda);
1.52 +
1.53 + void start();
1.54 + void stop();
1.55 + void ack(bool ack);
1.56 + uint8_t recv();
1.57 + void recvmany(uint8_t *data, uint8_t len);
1.58 + bool send(uint8_t data);
1.59 + bool sendmany(uint8_t *data, uint8_t len);
1.60 +};
1.61 +
1.62 +#endif /* __cplusplus */
1.63 +
1.64 +
1.65 +
1.66 +/* C language interface. */
1.67 +
1.68 +EXTERN_C_BEGIN
1.69 +
1.70 +void *i2c_gpio_get_channel(void *scl_chip, int scl, void *sda_chip, int sda);
1.71 +void i2c_gpio_start(void *channel);
1.72 +void i2c_gpio_stop(void *channel);
1.73 +void i2c_gpio_ack(void *channel, bool ack);
1.74 +uint8_t i2c_gpio_recv(void *channel);
1.75 +void i2c_gpio_recvmany(void *channel, uint8_t *data, uint8_t len);
1.76 +bool i2c_gpio_send(void *channel, uint8_t data);
1.77 +bool i2c_gpio_sendmany(void *channel, uint8_t *data, uint8_t len);
1.78 +
1.79 +EXTERN_C_END
2.1 --- a/pkg/devices/lib/i2c/src/Makefile Sat Oct 14 01:53:25 2023 +0200
2.2 +++ b/pkg/devices/lib/i2c/src/Makefile Sat Oct 14 01:56:53 2023 +0200
2.3 @@ -4,10 +4,10 @@
2.4 TARGET = libi2c.o.a libi2c.o.so
2.5 PC_FILENAME := libdrivers-i2c
2.6
2.7 -SRC_CC := jz4730.cc jz4780.cc x1600.cc
2.8 +SRC_CC := jz4730.cc jz4780.cc x1600.cc gpio.cc
2.9
2.10 PRIVATE_INCDIR += $(PKGDIR)/lib/i2c/include
2.11
2.12 -REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common
2.13 +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common libdrivers-gpio
2.14
2.15 include $(L4DIR)/mk/lib.mk
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/pkg/devices/lib/i2c/src/gpio.cc Sat Oct 14 01:56:53 2023 +0200
3.3 @@ -0,0 +1,243 @@
3.4 +/*
3.5 + * Manual GPIO-based I2C communication.
3.6 + *
3.7 + * Copyright (C) 2013, 2023 Paul Boddie <paul@boddie.org.uk>
3.8 + *
3.9 + * This program is free software; you can redistribute it and/or
3.10 + * modify it under the terms of the GNU General Public License as
3.11 + * published by the Free Software Foundation; either version 2 of
3.12 + * the License, or (at your option) any later version.
3.13 + *
3.14 + * This program is distributed in the hope that it will be useful,
3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.17 + * GNU General Public License for more details.
3.18 + *
3.19 + * You should have received a copy of the GNU General Public License
3.20 + * along with this program; if not, write to the Free Software
3.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
3.22 + * Boston, MA 02110-1301, USA
3.23 + */
3.24 +
3.25 +#include <unistd.h>
3.26 +#include "i2c-gpio.h"
3.27 +
3.28 +/* Declare the pins for initial I2C communications. */
3.29 +
3.30 +I2c_gpio::I2c_gpio(Hw::Gpio_chip *scl_chip, int scl, Hw::Gpio_chip *sda_chip, int sda)
3.31 +{
3.32 + _scl_chip = scl_chip;
3.33 + _sda_chip = sda_chip;
3.34 + I2C_SCL = scl;
3.35 + I2C_SDA = sda;
3.36 +}
3.37 +
3.38 +void I2c_gpio::CLR(int pin)
3.39 +{
3.40 + (pin == I2C_SCL ? _scl_chip : _sda_chip)->setup(pin, Hw::Gpio_chip::Output, 0);
3.41 +}
3.42 +
3.43 +void I2c_gpio::SET(int pin)
3.44 +{
3.45 + (pin == I2C_SCL ? _scl_chip : _sda_chip)->setup(pin, Hw::Gpio_chip::Output, 1);
3.46 +}
3.47 +
3.48 +void I2c_gpio::IN(int pin)
3.49 +{
3.50 + (pin == I2C_SCL ? _scl_chip : _sda_chip)->setup(pin, Hw::Gpio_chip::Input, 0);
3.51 +}
3.52 +
3.53 +int I2c_gpio::PIN(int pin)
3.54 +{
3.55 + return (pin == I2C_SCL ? _scl_chip : _sda_chip)->get(pin);
3.56 +}
3.57 +
3.58 +void I2c_gpio::wait()
3.59 +{
3.60 + usleep(4);
3.61 +}
3.62 +
3.63 +/* Initiate an I2C transaction. */
3.64 +
3.65 +void I2c_gpio::start()
3.66 +{
3.67 + /* Set up the data signal. */
3.68 +
3.69 + CLR(I2C_SCL);
3.70 + wait();
3.71 + SET(I2C_SDA);
3.72 +
3.73 + /* During a clock pulse, produce the start condition. */
3.74 +
3.75 + SET(I2C_SCL);
3.76 + wait();
3.77 + CLR(I2C_SDA);
3.78 +}
3.79 +
3.80 +/* Terminate an I2C transaction. */
3.81 +
3.82 +void I2c_gpio::stop()
3.83 +{
3.84 + /* Set up the data signal. */
3.85 +
3.86 + CLR(I2C_SCL);
3.87 + wait();
3.88 + CLR(I2C_SDA);
3.89 +
3.90 + /* During a clock pulse, produce the stop condition. */
3.91 +
3.92 + SET(I2C_SCL);
3.93 + wait();
3.94 + SET(I2C_SDA);
3.95 +}
3.96 +
3.97 +/* Send an I2C acknowledgement to a transmitting device. */
3.98 +
3.99 +void I2c_gpio::ack(bool ack)
3.100 +{
3.101 + if (ack)
3.102 + CLR(I2C_SDA);
3.103 + else
3.104 + SET(I2C_SDA);
3.105 +
3.106 + SET(I2C_SCL);
3.107 + wait();
3.108 + CLR(I2C_SCL);
3.109 +
3.110 + IN(I2C_SDA);
3.111 +}
3.112 +
3.113 +/* Receive a single byte from an I2C device as part of a transaction. */
3.114 +
3.115 +uint8_t I2c_gpio::recv()
3.116 +{
3.117 + uint8_t mask, result = 0;
3.118 +
3.119 + IN(I2C_SDA);
3.120 + CLR(I2C_SCL);
3.121 +
3.122 + for (mask = 0x80; mask; mask >>= 1)
3.123 + {
3.124 + SET(I2C_SCL);
3.125 + wait();
3.126 +
3.127 + if (PIN(I2C_SDA))
3.128 + result |= mask;
3.129 +
3.130 + CLR(I2C_SCL);
3.131 + wait();
3.132 + }
3.133 +
3.134 + return result;
3.135 +}
3.136 +
3.137 +/* Receive into a buffer a transmission of the given length in bytes. */
3.138 +
3.139 +void I2c_gpio::recvmany(uint8_t *data, uint8_t len)
3.140 +{
3.141 + uint8_t *end = data + len;
3.142 +
3.143 + for (; data != end; data++, len--)
3.144 + {
3.145 + *data = recv();
3.146 + ack(len > 1);
3.147 + }
3.148 +}
3.149 +
3.150 +/* Send a single byte of data to an I2C device as part of a transaction,
3.151 + returning whether the transmission succeeded. */
3.152 +
3.153 +bool I2c_gpio::send(uint8_t data)
3.154 +{
3.155 + uint8_t mask;
3.156 + bool status;
3.157 +
3.158 + CLR(I2C_SCL);
3.159 +
3.160 + for (mask = 0x80; mask; mask >>= 1)
3.161 + {
3.162 + wait();
3.163 +
3.164 + if (data & mask)
3.165 + SET(I2C_SDA);
3.166 + else
3.167 + CLR(I2C_SDA);
3.168 +
3.169 + SET(I2C_SCL);
3.170 + wait();
3.171 + CLR(I2C_SCL);
3.172 + }
3.173 +
3.174 + /* Wait for acknowledgement, failing if none is given. */
3.175 +
3.176 + IN(I2C_SDA);
3.177 + SET(I2C_SCL);
3.178 + wait();
3.179 +
3.180 + status = PIN(I2C_SDA);
3.181 + CLR(I2C_SCL);
3.182 + return !status;
3.183 +}
3.184 +
3.185 +/* Send from the buffer provided a transmission with the given length to an I2C
3.186 + device. */
3.187 +
3.188 +bool I2c_gpio::sendmany(uint8_t *data, uint8_t len)
3.189 +{
3.190 + uint8_t *end = data + len;
3.191 +
3.192 + for (; data != end; data++)
3.193 + {
3.194 + if (!send(*data))
3.195 + return false;
3.196 +
3.197 + /* NOTE: Should test for the slave holding the clock signal low. */
3.198 + }
3.199 +
3.200 + return true;
3.201 +}
3.202 +
3.203 +
3.204 +
3.205 +// C language interface functions.
3.206 +
3.207 +void *i2c_gpio_get_channel(void *scl_chip, int scl, void *sda_chip, int sda)
3.208 +{
3.209 + return (void *) new I2c_gpio(reinterpret_cast<Hw::Gpio_chip *>(scl_chip), scl,
3.210 + reinterpret_cast<Hw::Gpio_chip *>(sda_chip), sda);
3.211 +}
3.212 +
3.213 +void i2c_gpio_start(void *channel)
3.214 +{
3.215 + static_cast<I2c_gpio *>(channel)->start();
3.216 +}
3.217 +
3.218 +void i2c_gpio_stop(void *channel)
3.219 +{
3.220 + static_cast<I2c_gpio *>(channel)->stop();
3.221 +}
3.222 +
3.223 +void i2c_gpio_ack(void *channel, bool ack)
3.224 +{
3.225 + static_cast<I2c_gpio *>(channel)->ack(ack);
3.226 +}
3.227 +
3.228 +uint8_t i2c_gpio_recv(void *channel)
3.229 +{
3.230 + return static_cast<I2c_gpio *>(channel)->recv();
3.231 +}
3.232 +
3.233 +void i2c_gpio_recvmany(void *channel, uint8_t *data, uint8_t len)
3.234 +{
3.235 + static_cast<I2c_gpio *>(channel)->recvmany(data, len);
3.236 +}
3.237 +
3.238 +bool i2c_gpio_send(void *channel, uint8_t data)
3.239 +{
3.240 + return static_cast<I2c_gpio *>(channel)->send(data);
3.241 +}
3.242 +
3.243 +bool i2c_gpio_sendmany(void *channel, uint8_t *data, uint8_t len)
3.244 +{
3.245 + return static_cast<I2c_gpio *>(channel)->sendmany(data, len);
3.246 +}