summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Medhurst <tixy@linaro.org>2017-04-05 11:22:41 +0100
committerKumar Gala <kumar.gala@linaro.org>2017-04-28 15:26:40 -0500
commit5b04bd9aa477d9fb30d5fa3a5cc8c0bda8c8baac (patch)
treee19cbc8823ef72811d5f769cdcb879e35b1edf61
parent08185647530088db145be37e6ab1d9e51ce6dd21 (diff)
i2c: i2c_gpio: Driver for software driven I2C using GPIO lines
This driver implements an I2C interface by driving two GPIO lines under software control. Change-Id: Ie49cc67aed6acb30086ee851041fe2470da241cf Signed-off-by: Jon Medhurst <tixy@linaro.org>
-rw-r--r--drivers/i2c/Kconfig1
-rw-r--r--drivers/i2c/Kconfig.gpio158
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/i2c_gpio.c149
4 files changed, 309 insertions, 0 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 5968e936a..30d59fe24 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -112,6 +112,7 @@ config I2C_BITBANG
help
Enable library used for software driven (bit banging) I2C support
+source "drivers/i2c/Kconfig.gpio"
config I2C_INIT_PRIORITY
int
diff --git a/drivers/i2c/Kconfig.gpio b/drivers/i2c/Kconfig.gpio
new file mode 100644
index 000000000..4501d1f87
--- /dev/null
+++ b/drivers/i2c/Kconfig.gpio
@@ -0,0 +1,158 @@
+#
+# Copyright (c) 2017 Linaro Ltd.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+config I2C_GPIO
+ bool "GPIO bit banging I2C support"
+ depends on I2C
+ select I2C_BITBANG
+ default n
+ help
+ Enable software driven (bit banging) I2C support using GPIO pins
+
+# ---------- Port 0 ----------
+
+config I2C_GPIO_0
+ bool "Enable GPIO Bit Bang I2C device 0"
+ default n
+ depends on I2C_GPIO
+ help
+ This tells the driver to configure the I2C device at boot, depending
+ on the additional configuration options below.
+
+config I2C_GPIO_0_NAME
+ string "GPIO Bit Bang I2C device 0 device name"
+ default "I2C_0"
+ depends on I2C_GPIO_0
+ help
+ This is the device name for the I2C device, and is included in the
+ device struct.
+
+config I2C_GPIO_0_GPIO
+ string "Bit Bang I2C device 0 GPIO name"
+ depends on I2C_GPIO_0
+ help
+ This is the name of the GPIO device that controls the I2C lines.
+
+config I2C_GPIO_0_SCL_PIN
+ int "Bit Bang I2C device 0 GPIO pin number for SCL"
+ depends on I2C_GPIO_0
+ help
+ This is the GPIO pin number for the I2S SCL line
+
+config I2C_GPIO_0_SDA_PIN
+ int "Bit Bang I2C device 0 GPIO pin number for SDA"
+ depends on I2C_GPIO_0
+ help
+ This is the GPIO pin number for the I2S SDA line
+
+# ---------- Port 1 ----------
+
+config I2C_GPIO_1
+ bool "Enable GPIO Bit Bang I2C device 1"
+ default n
+ depends on I2C_GPIO
+ help
+ This tells the driver to configure the I2C device at boot, depending
+ on the additional configuration options below.
+
+config I2C_GPIO_1_NAME
+ string "Bit Bang I2C device 1 device name"
+ default "I2C_1"
+ depends on I2C_GPIO_1
+ help
+ This is the device name for the I2C device, and is included in the
+ device struct.
+
+config I2C_GPIO_1_GPIO
+ string "Bit Bang I2C device 1 GPIO name"
+ depends on I2C_GPIO_1
+ help
+ This is the name of the GPIO device that controls the I2C lines.
+
+config I2C_GPIO_1_SCL_PIN
+ int "Bit Bang I2C device 1 GPIO pin number for SCL"
+ depends on I2C_GPIO_1
+ help
+ This is the GPIO pin number for the I2S SCL line
+
+config I2C_GPIO_1_SDA_PIN
+ int "Bit Bang I2C device 1 GPIO pin number for SDA"
+ depends on I2C_GPIO_1
+ help
+ This is the GPIO pin number for the I2S SDA line
+
+# ---------- Port 2 ----------
+
+config I2C_GPIO_2
+ bool "Enable GPIO Bit Bang I2C device 2"
+ default n
+ depends on I2C_GPIO
+ help
+ This tells the driver to configure the I2C device at boot, depending
+ on the additional configuration options below.
+
+config I2C_GPIO_2_NAME
+ string "Bit Bang I2C device 2 device name"
+ default "I2C_2"
+ depends on I2C_GPIO_2
+ help
+ This is the device name for the I2C device, and is included in the
+ device struct.
+
+config I2C_GPIO_2_GPIO
+ string "Bit Bang I2C device 2 GPIO name"
+ depends on I2C_GPIO_2
+ help
+ This is the name of the GPIO device that controls the I2C lines.
+
+config I2C_GPIO_2_SCL_PIN
+ int "Bit Bang I2C device 2 GPIO pin number for SCL"
+ depends on I2C_GPIO_2
+ help
+ This is the GPIO pin number for the I2S SCL line
+
+config I2C_GPIO_2_SDA_PIN
+ int "Bit Bang I2C device 2 GPIO pin number for SDA"
+ depends on I2C_GPIO_2
+ help
+ This is the GPIO pin number for the I2S SDA line
+
+# ---------- Port 3 ----------
+
+config I2C_GPIO_3
+ bool "Enable GPIO Bit Bang I2C device 3"
+ default n
+ depends on I2C_GPIO
+ help
+ This tells the driver to configure the I2C device at boot, depending
+ on the additional configuration options below.
+
+config I2C_GPIO_3_NAME
+ string "Bit Bang I2C device 3 device name"
+ default "I2C_3"
+ depends on I2C_GPIO_3
+ help
+ This is the device name for the I2C device, and is included in the
+ device struct.
+
+config I2C_GPIO_3_GPIO
+ string "Bit Bang I2C device 3 GPIO name"
+ depends on I2C_GPIO_3
+ help
+ This is the name of the GPIO device that controls the I2C lines.
+
+config I2C_GPIO_3_SCL_PIN
+ int "Bit Bang I2C device 3 GPIO pin number for SCL"
+ depends on I2C_GPIO_3
+ help
+ This is the GPIO pin number for the I2S SCL line
+
+config I2C_GPIO_3_SDA_PIN
+ int "Bit Bang I2C device 3 GPIO pin number for SDA"
+ depends on I2C_GPIO_3
+ help
+ This is the GPIO pin number for the I2S SDA line
+
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index f500583a7..b3db3e81d 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_I2C_ATMEL_SAM3) += i2c_atmel_sam3.o
obj-$(CONFIG_I2C_BITBANG) += i2c_bitbang.o
obj-$(CONFIG_I2C_DW) += i2c_dw.o
+obj-$(CONFIG_I2C_GPIO) += i2c_gpio.o
obj-$(CONFIG_I2C_MCUX) += i2c_mcux.o
obj-$(CONFIG_I2C_NRF5) += i2c_nrf5.o
obj-$(CONFIG_I2C_QMSI) += i2c_qmsi.o
diff --git a/drivers/i2c/i2c_gpio.c b/drivers/i2c/i2c_gpio.c
new file mode 100644
index 000000000..3d69e0c1d
--- /dev/null
+++ b/drivers/i2c/i2c_gpio.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 Linaro Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * @brief Driver for software driven I2C using GPIO lines
+ *
+ * This driver implements an I2C interface by driving two GPIO lines under
+ * software control. The GPIO pins used must be preconfigured to to a suitable
+ * state, i.e. the SDA pin as open-colector/open-drain with a pull-up resistor
+ * (possibly as an external component attached to the pin). When the SDA pin
+ * is read it must return the state of the physical hardware line, not just the
+ * last state written to it for output.
+ *
+ * The SCL pin should be configued in the same manner as SDA, or, if it is known
+ * that the hardware attached to pin doesn't attempt clock stretching, then the
+ * SCL pin may be a push/pull output.
+ */
+
+#include <device.h>
+#include <errno.h>
+#include <gpio.h>
+#include <i2c.h>
+#include <i2c_bitbang.h>
+
+/* Driver config */
+struct i2c_gpio_config {
+ char *gpio_name;
+ u8_t scl_pin;
+ u8_t sda_pin;
+};
+
+/* Driver instance data */
+struct i2c_gpio_context {
+ struct i2c_bitbang bitbang; /* Bit-bang library data */
+ struct device *gpio; /* GPIO used for I2C lines */
+ u8_t scl_pin; /* Pin on gpio used for SCL line */
+ u8_t sda_pin; /* Pin on gpio used for SDA line */
+};
+
+static void i2c_gpio_set_scl(void *io_context, int state)
+{
+ struct i2c_gpio_context *context = io_context;
+
+ gpio_pin_write(context->gpio, context->scl_pin, state);
+}
+
+static void i2c_gpio_set_sda(void *io_context, int state)
+{
+ struct i2c_gpio_context *context = io_context;
+
+ gpio_pin_write(context->gpio, context->sda_pin, state);
+}
+
+static int i2c_gpio_get_sda(void *io_context)
+{
+ struct i2c_gpio_context *context = io_context;
+ u32_t state = 1; /* Default high as that would be a NACK */
+
+ gpio_pin_read(context->gpio, context->sda_pin, &state);
+ return state;
+}
+
+static const struct i2c_bitbang_io io_fns = {
+ .set_scl = &i2c_gpio_set_scl,
+ .set_sda = &i2c_gpio_set_sda,
+ .get_sda = &i2c_gpio_get_sda,
+};
+
+static int i2c_gpio_configure(struct device *dev, u32_t dev_config)
+{
+ struct i2c_gpio_context *context = dev->driver_data;
+
+ return i2c_bitbang_configure(&context->bitbang, dev_config);
+}
+
+static int i2c_gpio_transfer(struct device *dev, struct i2c_msg *msgs,
+ u8_t num_msgs, u16_t slave_address)
+{
+ struct i2c_gpio_context *context = dev->driver_data;
+
+ return i2c_bitbang_transfer(&context->bitbang, msgs, num_msgs,
+ slave_address);
+}
+
+static struct i2c_driver_api api = {
+ .configure = i2c_gpio_configure,
+ .transfer = i2c_gpio_transfer,
+};
+
+static int i2c_gpio_init(struct device *dev)
+{
+ struct i2c_gpio_context *context = dev->driver_data;
+ const struct i2c_gpio_config *config = dev->config->config_info;
+
+ context->gpio = device_get_binding(config->gpio_name);
+ if (!context->gpio) {
+ return -EINVAL;
+ }
+ context->sda_pin = config->sda_pin;
+ context->scl_pin = config->scl_pin;
+
+ i2c_bitbang_init(&context->bitbang, &io_fns, context);
+
+ /*
+ * Set driver_api at very end of init so if we return early with error
+ * then the device can't be found later by device_get_binding. This is
+ * important because driver framework ignores errors from init
+ * functions.
+ */
+ dev->driver_api = &api;
+
+ return 0;
+}
+
+#define DEFINE_I2C_GPIO(_num) \
+ \
+static struct i2c_gpio_context i2c_gpio_dev_data_##_num; \
+ \
+static const struct i2c_gpio_config i2c_gpio_dev_cfg_##_num = { \
+ .gpio_name = CONFIG_I2C_GPIO_##_num##_GPIO, \
+ .scl_pin = CONFIG_I2C_GPIO_##_num##_SCL_PIN, \
+ .sda_pin = CONFIG_I2C_GPIO_##_num##_SDA_PIN, \
+}; \
+ \
+DEVICE_INIT(i2c_gpio_##_num, CONFIG_I2C_GPIO_##_num##_NAME, \
+ i2c_gpio_init, \
+ &i2c_gpio_dev_data_##_num, \
+ &i2c_gpio_dev_cfg_##_num, \
+ PRE_KERNEL_2, CONFIG_I2C_INIT_PRIORITY)
+
+#ifdef CONFIG_I2C_GPIO_0
+DEFINE_I2C_GPIO(0);
+#endif
+
+#ifdef CONFIG_I2C_GPIO_1
+DEFINE_I2C_GPIO(1);
+#endif
+
+#ifdef CONFIG_I2C_GPIO_2
+DEFINE_I2C_GPIO(2);
+#endif
+
+#ifdef CONFIG_I2C_GPIO_3
+DEFINE_I2C_GPIO(3);
+#endif