Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: rk3x: support master_xfer_atomic

Enable i2c transactions in irq disabled contexts like poweroff where the
PMIC is connected via i2c.

Signed-off-by: John Keeping <john@metanate.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Wolfram Sang <wsa@kernel.org>

authored by

John Keeping and committed by
Wolfram Sang
f3e2bd71 f80531c8

+35 -4
+35 -4
drivers/i2c/busses/i2c-rk3x.c
··· 10 10 #include <linux/module.h> 11 11 #include <linux/i2c.h> 12 12 #include <linux/interrupt.h> 13 + #include <linux/iopoll.h> 13 14 #include <linux/errno.h> 14 15 #include <linux/err.h> 15 16 #include <linux/platform_device.h> ··· 1041 1040 return ret; 1042 1041 } 1043 1042 1044 - static int rk3x_i2c_xfer(struct i2c_adapter *adap, 1045 - struct i2c_msg *msgs, int num) 1043 + static int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c) 1044 + { 1045 + ktime_t timeout = ktime_add_ms(ktime_get(), WAIT_TIMEOUT); 1046 + 1047 + while (READ_ONCE(i2c->busy) && 1048 + ktime_compare(ktime_get(), timeout) < 0) { 1049 + udelay(5); 1050 + rk3x_i2c_irq(0, i2c); 1051 + } 1052 + 1053 + return !i2c->busy; 1054 + } 1055 + 1056 + static int rk3x_i2c_xfer_common(struct i2c_adapter *adap, 1057 + struct i2c_msg *msgs, int num, bool polling) 1046 1058 { 1047 1059 struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; 1048 1060 unsigned long timeout, flags; ··· 1089 1075 1090 1076 rk3x_i2c_start(i2c); 1091 1077 1092 - timeout = wait_event_timeout(i2c->wait, !i2c->busy, 1093 - msecs_to_jiffies(WAIT_TIMEOUT)); 1078 + if (!polling) { 1079 + timeout = wait_event_timeout(i2c->wait, !i2c->busy, 1080 + msecs_to_jiffies(WAIT_TIMEOUT)); 1081 + } else { 1082 + timeout = rk3x_i2c_wait_xfer_poll(i2c); 1083 + } 1094 1084 1095 1085 spin_lock_irqsave(&i2c->lock, flags); 1096 1086 ··· 1128 1110 return ret < 0 ? ret : num; 1129 1111 } 1130 1112 1113 + static int rk3x_i2c_xfer(struct i2c_adapter *adap, 1114 + struct i2c_msg *msgs, int num) 1115 + { 1116 + return rk3x_i2c_xfer_common(adap, msgs, num, false); 1117 + } 1118 + 1119 + static int rk3x_i2c_xfer_polling(struct i2c_adapter *adap, 1120 + struct i2c_msg *msgs, int num) 1121 + { 1122 + return rk3x_i2c_xfer_common(adap, msgs, num, true); 1123 + } 1124 + 1131 1125 static __maybe_unused int rk3x_i2c_resume(struct device *dev) 1132 1126 { 1133 1127 struct rk3x_i2c *i2c = dev_get_drvdata(dev); ··· 1156 1126 1157 1127 static const struct i2c_algorithm rk3x_i2c_algorithm = { 1158 1128 .master_xfer = rk3x_i2c_xfer, 1129 + .master_xfer_atomic = rk3x_i2c_xfer_polling, 1159 1130 .functionality = rk3x_i2c_func, 1160 1131 }; 1161 1132