From b7f625840267b18ef1011cba0085bb7e237d76f7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 5 Jan 2015 23:45:59 +0100 Subject: i2c: add quirk checks to core Let the core do the checks if HW quirks prevent a transfer. Saves code from drivers and adds consistency. Signed-off-by: Wolfram Sang Tested-by: Ray Jui Tested-by: Ivan T. Ivanov Tested-by: Neelesh Gupta Tested-By: Ludovic Desroches --- drivers/i2c/i2c-core.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 210cf4874cb7..57a86f4aab43 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1929,6 +1929,65 @@ module_exit(i2c_exit); * ---------------------------------------------------- */ +/* Check if val is exceeding the quirk IFF quirk is non 0 */ +#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk))) + +static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg) +{ + dev_err_ratelimited(&adap->dev, "adapter quirk: %s (addr 0x%04x, size %u, %s)\n", + err_msg, msg->addr, msg->len, + msg->flags & I2C_M_RD ? "read" : "write"); + return -EOPNOTSUPP; +} + +static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + const struct i2c_adapter_quirks *q = adap->quirks; + int max_num = q->max_num_msgs, i; + bool do_len_check = true; + + if (q->flags & I2C_AQ_COMB) { + max_num = 2; + + /* special checks for combined messages */ + if (num == 2) { + if (q->flags & I2C_AQ_COMB_WRITE_FIRST && msgs[0].flags & I2C_M_RD) + return i2c_quirk_error(adap, &msgs[0], "1st comb msg must be write"); + + if (q->flags & I2C_AQ_COMB_READ_SECOND && !(msgs[1].flags & I2C_M_RD)) + return i2c_quirk_error(adap, &msgs[1], "2nd comb msg must be read"); + + if (q->flags & I2C_AQ_COMB_SAME_ADDR && msgs[0].addr != msgs[1].addr) + return i2c_quirk_error(adap, &msgs[0], "comb msg only to same addr"); + + if (i2c_quirk_exceeded(msgs[0].len, q->max_comb_1st_msg_len)) + return i2c_quirk_error(adap, &msgs[0], "msg too long"); + + if (i2c_quirk_exceeded(msgs[1].len, q->max_comb_2nd_msg_len)) + return i2c_quirk_error(adap, &msgs[1], "msg too long"); + + do_len_check = false; + } + } + + if (i2c_quirk_exceeded(num, max_num)) + return i2c_quirk_error(adap, &msgs[0], "too many messages"); + + for (i = 0; i < num; i++) { + u16 len = msgs[i].len; + + if (msgs[i].flags & I2C_M_RD) { + if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len)) + return i2c_quirk_error(adap, &msgs[i], "msg too long"); + } else { + if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len)) + return i2c_quirk_error(adap, &msgs[i], "msg too long"); + } + } + + return 0; +} + /** * __i2c_transfer - unlocked flavor of i2c_transfer * @adap: Handle to I2C bus @@ -1946,6 +2005,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try; + if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) + return -EOPNOTSUPP; + /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from * being executed when not needed. -- cgit v1.2.3 From 03bde7c31a360f814ca42101d60563b1b803dca1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 12 Mar 2015 17:17:59 +0100 Subject: i2c: busses with dynamic ids should start after fixed ids for DT Make sure dynamic ids do not interfere with fixed ones and let them start after the highest fixed id. This patch might cause different bus-numbers than before for dynamic ids, however it fixes a bug. Assume: - fixed id0 defers probe - fixed id1 succeeds and registers a muxed bus with dynamic id - muxed bus gets id0 - fixed id0 wants to probe again, but its fixed id is gone now - fixed id0 probe fails With this patch, the fixed ids are always reserved in the DT case. For legacy board init, we already have a mechanism like this in i2c_register_board_info(). Reported-by: Bob Feretich Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 57a86f4aab43..fe80f85896e2 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1878,6 +1878,13 @@ static int __init i2c_init(void) { int retval; + retval = of_alias_get_highest_id("i2c"); + + down_write(&__i2c_board_lock); + if (retval >= __i2c_first_dynamic_bus_num) + __i2c_first_dynamic_bus_num = retval + 1; + up_write(&__i2c_board_lock); + retval = bus_register(&i2c_bus_type); if (retval) return retval; -- cgit v1.2.3 From 2b2190a375d796a5ad9ec557cb51269f36b264d4 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 6 Apr 2015 15:38:39 +0300 Subject: i2c: change input parameter to i2c_adapter for prepare/unprepare_recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch changes type of input parameter for prepare/unprepare_recovery() callbacks from struct i2c_bus_recovery_info * to struct i2c_adapter *. This allows to simplify implementation of these callbacks and avoid type conversations from i2c_bus_recovery_info to i2c_adapter. The i2c_bus_recovery_info can be simply retrieved from struct i2c_adapter which contains pointer on it. There are no users currently, so this is safe to do. Acked-by: Uwe Kleine-König Acked-by: Alexander Sverdlin Signed-off-by: Grygorii Strashko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 4 ++-- include/linux/i2c.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index fe80f85896e2..617a19acf76a 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -561,7 +561,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) int i = 0, val = 1, ret = 0; if (bri->prepare_recovery) - bri->prepare_recovery(bri); + bri->prepare_recovery(adap); /* * By this time SCL is high, as we need to give 9 falling-rising edges @@ -586,7 +586,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) } if (bri->unprepare_recovery) - bri->unprepare_recovery(bri); + bri->unprepare_recovery(adap); return ret; } diff --git a/include/linux/i2c.h b/include/linux/i2c.h index c5e4bb2c5759..898033f41d76 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -435,8 +435,8 @@ struct i2c_bus_recovery_info { void (*set_scl)(struct i2c_adapter *, int val); int (*get_sda)(struct i2c_adapter *); - void (*prepare_recovery)(struct i2c_bus_recovery_info *bri); - void (*unprepare_recovery)(struct i2c_bus_recovery_info *bri); + void (*prepare_recovery)(struct i2c_adapter *); + void (*unprepare_recovery)(struct i2c_adapter *); /* gpio recovery */ int scl_gpio; -- cgit v1.2.3