| /* | 
 |  * 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 configured 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 |