diff options
author | Jon Medhurst <tixy@linaro.org> | 2017-04-05 11:22:41 +0100 |
---|---|---|
committer | Kumar Gala <kumar.gala@linaro.org> | 2017-04-28 15:26:40 -0500 |
commit | 5b04bd9aa477d9fb30d5fa3a5cc8c0bda8c8baac (patch) | |
tree | e19cbc8823ef72811d5f769cdcb879e35b1edf61 | |
parent | 08185647530088db145be37e6ab1d9e51ce6dd21 (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/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/Kconfig.gpio | 158 | ||||
-rw-r--r-- | drivers/i2c/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/i2c_gpio.c | 149 |
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 |