diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-04 10:57:43 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-04 10:57:43 -0800 |
commit | 4141cf676b9e345d3ddeb1710dd3156a09c50244 (patch) | |
tree | 4b2b6249e99efdd47eafa5780f106d593f64708b /drivers/i2c/i2c-core-base.c | |
parent | 3462ac57033e79a87dbae2497773f22b9c536fbc (diff) | |
parent | e38c85644e11c6dc5a39305c96b617f63403423d (diff) |
Merge branch 'i2c/for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"I2C has the following changes for you:
- new flag to mark DMA safe buffers in i2c_msg. Also, some
infrastructure around it. And docs.
- huge refactoring of the at24 driver led by the new maintainer
Bartosz
- update I2C bus recovery to send STOP after recovery
- conversion from gpio to gpiod for I2C bus recovery
- adding a fault-injector to the i2c-gpio driver
- lots of small driver improvements, and bigger ones to
i2c-sh_mobile"
* 'i2c/for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (99 commits)
i2c: mv64xxx: Add myself as maintainer for this driver
i2c: mv64xxx: Fix clock resource by adding an optional bus clock
i2c: mv64xxx: Remove useless test before clk_disable_unprepare
i2c: mxs: use true and false for boolean values
i2c: meson: update doc description to fix build warnings
i2c: meson: add configurable divider factors
dt-bindings: i2c: update documentation for the Meson-AXG
i2c: imx-lpi2c: add runtime pm support
i2c: rcar: fix some trivial typos in comments
i2c: davinci: fix the cpufreq transition
i2c: rk3x: add proper kerneldoc header
i2c: rk3x: account for const type of of_device_id.data
i2c: acorn: remove outdated path from file header
i2c: acorn: add MODULE_LICENSE tag
i2c: rcar: implement bus recovery
i2c: send STOP after successful bus recovery
i2c: ensure SDA is released in recovery if SDA is controllable
i2c: add 'set_sda' to bus_recovery_info
i2c: add identifier in declarations for i2c_bus_recovery
i2c: make kerneldoc about bus recovery more precise
...
Diffstat (limited to 'drivers/i2c/i2c-core-base.c')
-rw-r--r-- | drivers/i2c/i2c-core-base.c | 212 |
1 files changed, 96 insertions, 116 deletions
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index f7829a74140c..5a00bf443d06 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -27,7 +27,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/i2c-smbus.h> #include <linux/idr.h> @@ -134,52 +134,22 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) /* i2c bus recovery routines */ static int get_scl_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->scl_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->scl_gpiod); } static void set_scl_gpio_value(struct i2c_adapter *adap, int val) { - gpio_set_value(adap->bus_recovery_info->scl_gpio, val); + gpiod_set_value_cansleep(adap->bus_recovery_info->scl_gpiod, val); } static int get_sda_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->sda_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } -static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) +static void set_sda_gpio_value(struct i2c_adapter *adap, int val) { - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - struct device *dev = &adap->dev; - int ret = 0; - - ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN | - GPIOF_OUT_INIT_HIGH, "i2c-scl"); - if (ret) { - dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); - return ret; - } - - if (bri->get_sda) { - if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { - /* work without SDA polling */ - dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n", - bri->sda_gpio); - bri->get_sda = NULL; - } - } - - return ret; -} - -static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) -{ - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - - if (bri->get_sda) - gpio_free(bri->sda_gpio); - - gpio_free(bri->scl_gpio); + gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val); } /* @@ -190,7 +160,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) #define RECOVERY_NDELAY 5000 #define RECOVERY_CLK_CNT 9 -static int i2c_generic_recovery(struct i2c_adapter *adap) +int i2c_generic_scl_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; int i = 0, val = 1, ret = 0; @@ -199,6 +169,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) bri->prepare_recovery(adap); bri->set_scl(adap, val); + if (bri->set_sda) + bri->set_sda(adap, 1); ndelay(RECOVERY_NDELAY); /* @@ -227,33 +199,25 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) if (bri->get_sda && !bri->get_sda(adap)) ret = -EBUSY; + /* If all went well, send STOP for a sane bus state. */ + if (ret == 0 && bri->set_sda) { + bri->set_scl(adap, 0); + ndelay(RECOVERY_NDELAY / 2); + bri->set_sda(adap, 0); + ndelay(RECOVERY_NDELAY / 2); + bri->set_scl(adap, 1); + ndelay(RECOVERY_NDELAY / 2); + bri->set_sda(adap, 1); + ndelay(RECOVERY_NDELAY / 2); + } + if (bri->unprepare_recovery) bri->unprepare_recovery(adap); return ret; } - -int i2c_generic_scl_recovery(struct i2c_adapter *adap) -{ - return i2c_generic_recovery(adap); -} EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); -int i2c_generic_gpio_recovery(struct i2c_adapter *adap) -{ - int ret; - - ret = i2c_get_gpios_for_recovery(adap); - if (ret) - return ret; - - ret = i2c_generic_recovery(adap); - i2c_put_gpios_for_recovery(adap); - - return ret; -} -EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery); - int i2c_recover_bus(struct i2c_adapter *adap) { if (!adap->bus_recovery_info) @@ -277,21 +241,19 @@ static void i2c_init_recovery(struct i2c_adapter *adap) goto err; } - /* Generic GPIO recovery */ - if (bri->recover_bus == i2c_generic_gpio_recovery) { - if (!gpio_is_valid(bri->scl_gpio)) { - err_str = "invalid SCL gpio"; - goto err; - } - - if (gpio_is_valid(bri->sda_gpio)) - bri->get_sda = get_sda_gpio_value; - else - bri->get_sda = NULL; - + if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_recovery) { bri->get_scl = get_scl_gpio_value; bri->set_scl = set_scl_gpio_value; - } else if (bri->recover_bus == i2c_generic_scl_recovery) { + if (bri->sda_gpiod) { + bri->get_sda = get_sda_gpio_value; + /* FIXME: add proper flag instead of '0' once available */ + if (gpiod_get_direction(bri->sda_gpiod) == 0) + bri->set_sda = set_sda_gpio_value; + } + return; + } + + if (bri->recover_bus == i2c_generic_scl_recovery) { /* Generic SCL recovery */ if (!bri->set_scl || !bri->get_scl) { err_str = "no {get|set}_scl() found"; @@ -1976,63 +1938,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) EXPORT_SYMBOL(i2c_transfer); /** - * i2c_master_send - issue a single I2C message in master transmit mode - * @client: Handle to slave device - * @buf: Data that will be written to the slave - * @count: How many bytes to write, must be less than 64k since msg.len is u16 - * - * Returns negative errno, or else the number of bytes written. - */ -int i2c_master_send(const struct i2c_client *client, const char *buf, int count) -{ - int ret; - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.len = count; - msg.buf = (char *)buf; - - ret = i2c_transfer(adap, &msg, 1); - - /* - * If everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1) ? count : ret; -} -EXPORT_SYMBOL(i2c_master_send); - -/** - * i2c_master_recv - issue a single I2C message in master receive mode + * i2c_transfer_buffer_flags - issue a single I2C message transferring data + * to/from a buffer * @client: Handle to slave device - * @buf: Where to store data read from slave - * @count: How many bytes to read, must be less than 64k since msg.len is u16 + * @buf: Where the data is stored + * @count: How many bytes to transfer, must be less than 64k since msg.len is u16 + * @flags: The flags to be used for the message, e.g. I2C_M_RD for reads * - * Returns negative errno, or else the number of bytes read. + * Returns negative errno, or else the number of bytes transferred. */ -int i2c_master_recv(const struct i2c_client *client, char *buf, int count) +int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, + int count, u16 flags) { - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; int ret; + struct i2c_msg msg = { + .addr = client->addr, + .flags = flags | (client->flags & I2C_M_TEN), + .len = count, + .buf = buf, + }; - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.flags |= I2C_M_RD; - msg.len = count; - msg.buf = buf; - - ret = i2c_transfer(adap, &msg, 1); + ret = i2c_transfer(client->adapter, &msg, 1); /* - * If everything went ok (i.e. 1 msg received), return #bytes received, - * else error code. + * If everything went ok (i.e. 1 msg transferred), return #bytes + * transferred, else error code. */ return (ret == 1) ? count : ret; } -EXPORT_SYMBOL(i2c_master_recv); +EXPORT_SYMBOL(i2c_transfer_buffer_flags); /* ---------------------------------------------------- * the i2c address scanning function @@ -2265,6 +2199,52 @@ void i2c_put_adapter(struct i2c_adapter *adap) } EXPORT_SYMBOL(i2c_put_adapter); +/** + * i2c_get_dma_safe_msg_buf() - get a DMA safe buffer for the given i2c_msg + * @msg: the message to be checked + * @threshold: the minimum number of bytes for which using DMA makes sense + * + * Return: NULL if a DMA safe buffer was not obtained. Use msg->buf with PIO. + * Or a valid pointer to be used with DMA. After use, release it by + * calling i2c_release_dma_safe_msg_buf(). + * + * This function must only be called from process context! + */ +u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold) +{ + if (msg->len < threshold) + return NULL; + + if (msg->flags & I2C_M_DMA_SAFE) + return msg->buf; + + pr_debug("using bounce buffer for addr=0x%02x, len=%d\n", + msg->addr, msg->len); + + if (msg->flags & I2C_M_RD) + return kzalloc(msg->len, GFP_KERNEL); + else + return kmemdup(msg->buf, msg->len, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf); + +/** + * i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg + * @msg: the message to be synced with + * @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL. + */ +void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf) +{ + if (!buf || buf == msg->buf) + return; + + if (msg->flags & I2C_M_RD) + memcpy(msg->buf, buf, msg->len); + + kfree(buf); +} +EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf); + MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_LICENSE("GPL"); |