aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2012-02-28 07:56:31 -0500
committerWolfram Sang <wsa@the-dreams.de>2013-03-24 05:30:54 -0400
commit5f9296ba21b3c395e53dd84e7ff9578f97f24295 (patch)
treeddc02adbdaa1b703b04aeee9b8d8f1ca13fa2443 /drivers/i2c
parentee5c27440cc24d62ec463cce4c000bb32c5692c7 (diff)
i2c: Add bus recovery infrastructure
Add i2c bus recovery infrastructure to i2c adapters as specified in the i2c protocol Rev. 03 section 3.1.16 titled "Bus clear". http://www.nxp.com/documents/user_manual/UM10204.pdf Sometimes during operation i2c bus hangs and we need to give dummy clocks to slave device to start the transfer again. Now we may have capability in the bus controller to generate these clocks or platform may have gpio pins which can be toggled to generate dummy clocks. This patch supports both. This patch also adds in generic bus recovery routines gpio or scl line based which can be used by bus controller. In addition controller driver may provide its own version of the bus recovery routine. This doesn't support multi-master recovery for now. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> [wsa: changed gpio type to int and minor reformatting] Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/i2c-core.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index f7dfe878a51b..0d873ba2e82e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -27,7 +27,9 @@
27 27
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/delay.h>
30#include <linux/errno.h> 31#include <linux/errno.h>
32#include <linux/gpio.h>
31#include <linux/slab.h> 33#include <linux/slab.h>
32#include <linux/i2c.h> 34#include <linux/i2c.h>
33#include <linux/init.h> 35#include <linux/init.h>
@@ -109,6 +111,130 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
109#define i2c_device_uevent NULL 111#define i2c_device_uevent NULL
110#endif /* CONFIG_HOTPLUG */ 112#endif /* CONFIG_HOTPLUG */
111 113
114/* i2c bus recovery routines */
115static int get_scl_gpio_value(struct i2c_adapter *adap)
116{
117 return gpio_get_value(adap->bus_recovery_info->scl_gpio);
118}
119
120static void set_scl_gpio_value(struct i2c_adapter *adap, int val)
121{
122 gpio_set_value(adap->bus_recovery_info->scl_gpio, val);
123}
124
125static int get_sda_gpio_value(struct i2c_adapter *adap)
126{
127 return gpio_get_value(adap->bus_recovery_info->sda_gpio);
128}
129
130static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap)
131{
132 struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
133 struct device *dev = &adap->dev;
134 int ret = 0;
135
136 ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN |
137 GPIOF_OUT_INIT_HIGH, "i2c-scl");
138 if (ret) {
139 dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio);
140 return ret;
141 }
142
143 if (bri->get_sda) {
144 if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) {
145 /* work without SDA polling */
146 dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n",
147 bri->sda_gpio);
148 bri->get_sda = NULL;
149 }
150 }
151
152 return ret;
153}
154
155static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap)
156{
157 struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
158
159 if (bri->get_sda)
160 gpio_free(bri->sda_gpio);
161
162 gpio_free(bri->scl_gpio);
163}
164
165/*
166 * We are generating clock pulses. ndelay() determines durating of clk pulses.
167 * We will generate clock with rate 100 KHz and so duration of both clock levels
168 * is: delay in ns = (10^6 / 100) / 2
169 */
170#define RECOVERY_NDELAY 5000
171#define RECOVERY_CLK_CNT 9
172
173static int i2c_generic_recovery(struct i2c_adapter *adap)
174{
175 struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
176 int i = 0, val = 1, ret = 0;
177
178 if (bri->prepare_recovery)
179 bri->prepare_recovery(bri);
180
181 /*
182 * By this time SCL is high, as we need to give 9 falling-rising edges
183 */
184 while (i++ < RECOVERY_CLK_CNT * 2) {
185 if (val) {
186 /* Break if SDA is high */
187 if (bri->get_sda && bri->get_sda(adap))
188 break;
189 /* SCL shouldn't be low here */
190 if (!bri->get_scl(adap)) {
191 dev_err(&adap->dev,
192 "SCL is stuck low, exit recovery\n");
193 ret = -EBUSY;
194 break;
195 }
196 }
197
198 val = !val;
199 bri->set_scl(adap, val);
200 ndelay(RECOVERY_NDELAY);
201 }
202
203 if (bri->unprepare_recovery)
204 bri->unprepare_recovery(bri);
205
206 return ret;
207}
208
209int i2c_generic_scl_recovery(struct i2c_adapter *adap)
210{
211 adap->bus_recovery_info->set_scl(adap, 1);
212 return i2c_generic_recovery(adap);
213}
214
215int i2c_generic_gpio_recovery(struct i2c_adapter *adap)
216{
217 int ret;
218
219 ret = i2c_get_gpios_for_recovery(adap);
220 if (ret)
221 return ret;
222
223 ret = i2c_generic_recovery(adap);
224 i2c_put_gpios_for_recovery(adap);
225
226 return ret;
227}
228
229int i2c_recover_bus(struct i2c_adapter *adap)
230{
231 if (!adap->bus_recovery_info)
232 return -EOPNOTSUPP;
233
234 dev_dbg(&adap->dev, "Trying i2c bus recovery\n");
235 return adap->bus_recovery_info->recover_bus(adap);
236}
237
112static int i2c_device_probe(struct device *dev) 238static int i2c_device_probe(struct device *dev)
113{ 239{
114 struct i2c_client *client = i2c_verify_client(dev); 240 struct i2c_client *client = i2c_verify_client(dev);
@@ -902,6 +1028,39 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
902 "Failed to create compatibility class link\n"); 1028 "Failed to create compatibility class link\n");
903#endif 1029#endif
904 1030
1031 /* bus recovery specific initialization */
1032 if (adap->bus_recovery_info) {
1033 struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
1034
1035 if (!bri->recover_bus) {
1036 dev_err(&adap->dev, "No recover_bus() found, not using recovery\n");
1037 adap->bus_recovery_info = NULL;
1038 goto exit_recovery;
1039 }
1040
1041 /* Generic GPIO recovery */
1042 if (bri->recover_bus == i2c_generic_gpio_recovery) {
1043 if (!gpio_is_valid(bri->scl_gpio)) {
1044 dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n");
1045 adap->bus_recovery_info = NULL;
1046 goto exit_recovery;
1047 }
1048
1049 if (gpio_is_valid(bri->sda_gpio))
1050 bri->get_sda = get_sda_gpio_value;
1051 else
1052 bri->get_sda = NULL;
1053
1054 bri->get_scl = get_scl_gpio_value;
1055 bri->set_scl = set_scl_gpio_value;
1056 } else if (!bri->set_scl || !bri->get_scl) {
1057 /* Generic SCL recovery */
1058 dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n");
1059 adap->bus_recovery_info = NULL;
1060 }
1061 }
1062
1063exit_recovery:
905 /* create pre-declared device nodes */ 1064 /* create pre-declared device nodes */
906 if (adap->nr < __i2c_first_dynamic_bus_num) 1065 if (adap->nr < __i2c_first_dynamic_bus_num)
907 i2c_scan_static_board_info(adap); 1066 i2c_scan_static_board_info(adap);