diff options
author | Arksine <arksine.code@gmail.com> | 2020-01-09 19:25:51 -0500 |
---|---|---|
committer | KevinOConnor <kevin@koconnor.net> | 2020-01-13 22:29:50 -0500 |
commit | 20ba3964661840fe1d5ba65b57014f21c63ed9c4 (patch) | |
tree | fff28b72048a4a695b2e82ee827961475a0d8c33 /src/linux/i2c.c | |
parent | 5fe9dd5a5036e528d6180ef629d38d454e4744a3 (diff) | |
download | kutter-20ba3964661840fe1d5ba65b57014f21c63ed9c4.tar.gz kutter-20ba3964661840fe1d5ba65b57014f21c63ed9c4.tar.xz kutter-20ba3964661840fe1d5ba65b57014f21c63ed9c4.zip |
linux: implement i2c
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
Diffstat (limited to 'src/linux/i2c.c')
-rw-r--r-- | src/linux/i2c.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/linux/i2c.c b/src/linux/i2c.c new file mode 100644 index 00000000..b8e8f253 --- /dev/null +++ b/src/linux/i2c.c @@ -0,0 +1,101 @@ +// Linux i2c implementation +// +// Copyright (C) 2020 Eric Callahan <arksine.code@gmail.com> +// +// This file may be distributed under the terms of the GNU GPLv3 license. +#include <fcntl.h> // open +#include <linux/i2c-dev.h> // I2C_SLAVE +#include <stdio.h> // snprintf +#include <sys/ioctl.h> // ioctl +#include <unistd.h> // write +#include "gpio.h" // i2c_setup +#include "command.h" // shutdown +#include "internal.h" // report_errno +#include "sched.h" // sched_shutdown + +DECL_ENUMERATION_RANGE("i2c_bus", "i2c.0", 0, 2); + +struct i2c_s { + uint32_t bus; + uint8_t addr; + int fd; +}; + +static struct i2c_s devices[16]; +static int devices_count; + +static int +i2c_open(uint32_t bus, uint8_t addr) +{ + // Find existing device (if already opened) + int i; + for (i=0; i<devices_count; i++) { + if (devices[i].bus == bus && devices[i].addr == addr) { + return devices[i].fd; + } + } + + char fname[256]; + snprintf(fname, sizeof(fname), "/dev/i2c-%d", bus); + int fd = open(fname, O_RDWR|O_CLOEXEC); + if (fd < 0) { + report_errno("open i2c", fd); + goto fail; + } + int ret = ioctl(fd, I2C_SLAVE, addr); + if (ret < 0) { + report_errno("ioctl i2c", fd); + goto fail; + } + ret = set_non_blocking(fd); + if (ret < 0) + goto fail; + + devices[devices_count].bus = bus; + devices[devices_count].addr = addr; + devices[devices_count].fd = fd; + devices_count++; + + return fd; + +fail: + if (fd >= 0) + close(fd); + shutdown("Unable to open i2c device"); +} + +struct i2c_config +i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr) +{ + // Note: The rate is set by the kernel driver, for a Raspberry Pi this + // is done with the following setting in /boot/config.txt: + // + // dtparam=i2c_baudrate=<rate> + + int fd = i2c_open(bus, addr); + return (struct i2c_config){.fd=fd}; +} + +void +i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *data) +{ + int ret = write(config.fd, data, write_len); + if (ret != write_len) { + if (ret < 0) + report_errno("write value i2c", ret); + try_shutdown("Unable write i2c device"); + } +} + +void +i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg + , uint8_t read_len, uint8_t *data) +{ + i2c_write(config, reg_len, reg); + int ret = read(config.fd, data, read_len); + if (ret != read_len) { + if (ret < 0) + report_errno("read value i2c", ret); + try_shutdown("Unable to read i2c device"); + } +} |