mirror of https://github.com/Desuuuu/klipper.git
linux: implement i2c
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
5fe9dd5a50
commit
20ba396466
|
@ -9,6 +9,7 @@ config LINUX_SELECT
|
||||||
select HAVE_GPIO_ADC
|
select HAVE_GPIO_ADC
|
||||||
select HAVE_GPIO_SPI
|
select HAVE_GPIO_SPI
|
||||||
select HAVE_GPIO_HARD_PWM
|
select HAVE_GPIO_HARD_PWM
|
||||||
|
select HAVE_GPIO_I2C
|
||||||
|
|
||||||
config BOARD_DIRECTORY
|
config BOARD_DIRECTORY
|
||||||
string
|
string
|
||||||
|
|
|
@ -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/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 += 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
|
CFLAGS_klipper.elf += -lutil
|
||||||
|
|
||||||
|
|
|
@ -35,4 +35,13 @@ struct gpio_pwm {
|
||||||
struct gpio_pwm gpio_pwm_setup(uint8_t pin, uint32_t cycle_time, uint16_t val);
|
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);
|
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
|
#endif // gpio.h
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue