aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorArksine <arksine.code@gmail.com>2020-01-09 19:25:51 -0500
committerKevinOConnor <kevin@koconnor.net>2020-01-13 22:29:50 -0500
commit20ba3964661840fe1d5ba65b57014f21c63ed9c4 (patch)
treefff28b72048a4a695b2e82ee827961475a0d8c33 /src
parent5fe9dd5a5036e528d6180ef629d38d454e4744a3 (diff)
downloadkutter-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')
-rw-r--r--src/linux/Kconfig1
-rw-r--r--src/linux/Makefile2
-rw-r--r--src/linux/gpio.h9
-rw-r--r--src/linux/i2c.c101
4 files changed, 112 insertions, 1 deletions
diff --git a/src/linux/Kconfig b/src/linux/Kconfig
index 0ae58516..53fb22fe 100644
--- a/src/linux/Kconfig
+++ b/src/linux/Kconfig
@@ -9,6 +9,7 @@ config LINUX_SELECT
select HAVE_GPIO_ADC
select HAVE_GPIO_SPI
select HAVE_GPIO_HARD_PWM
+ select HAVE_GPIO_I2C
config BOARD_DIRECTORY
string
diff --git a/src/linux/Makefile b/src/linux/Makefile
index 4ceed5f3..5cc9c69a 100644
--- a/src/linux/Makefile
+++ b/src/linux/Makefile
@@ -4,7 +4,7 @@ dirs-y += src/linux src/generic
src-y += linux/main.c linux/timer.c linux/console.c linux/watchdog.c
src-y += linux/pca9685.c linux/spidev.c linux/analog.c linux/hard_pwm.c
-src-y += generic/crc16_ccitt.c generic/alloc.c
+src-y += linux/i2c.c generic/crc16_ccitt.c generic/alloc.c
CFLAGS_klipper.elf += -lutil
diff --git a/src/linux/gpio.h b/src/linux/gpio.h
index d177581c..32e76bf5 100644
--- a/src/linux/gpio.h
+++ b/src/linux/gpio.h
@@ -35,4 +35,13 @@ struct gpio_pwm {
struct gpio_pwm gpio_pwm_setup(uint8_t pin, uint32_t cycle_time, uint16_t val);
void gpio_pwm_write(struct gpio_pwm g, uint16_t val);
+struct i2c_config {
+ int fd;
+};
+
+struct i2c_config i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr);
+void i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write);
+void i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
+ , uint8_t read_len, uint8_t *read);
+
#endif // gpio.h
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");
+ }
+}