]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/imx-common/i2c.c
Merge branch 'master' of git://git.denx.de/u-boot-usb
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / imx-common / i2c.c
1 /*
2  * Copyright (C) 2012 Boundary Devices Inc.
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 #include <common.h>
23 #include <asm/arch/clock.h>
24 #include <asm/arch/imx-regs.h>
25 #include <asm/errno.h>
26 #include <asm/gpio.h>
27 #include <asm/imx-common/mxc_i2c.h>
28 #include <watchdog.h>
29
30 static int force_idle_bus(void *priv)
31 {
32         int i;
33         int sda, scl;
34         ulong elapsed, start_time;
35         struct i2c_pads_info *p = (struct i2c_pads_info *)priv;
36         int ret = 0;
37
38         gpio_direction_input(p->sda.gp);
39         gpio_direction_input(p->scl.gp);
40
41         imx_iomux_v3_setup_pad(p->sda.gpio_mode);
42         imx_iomux_v3_setup_pad(p->scl.gpio_mode);
43
44         sda = gpio_get_value(p->sda.gp);
45         scl = gpio_get_value(p->scl.gp);
46         if ((sda & scl) == 1)
47                 goto exit;              /* Bus is idle already */
48
49         printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__,
50                 sda, scl, p->sda.gp, p->scl.gp);
51         /* Send high and low on the SCL line */
52         for (i = 0; i < 9; i++) {
53                 gpio_direction_output(p->scl.gp, 0);
54                 udelay(50);
55                 gpio_direction_input(p->scl.gp);
56                 udelay(50);
57         }
58         start_time = get_timer(0);
59         for (;;) {
60                 sda = gpio_get_value(p->sda.gp);
61                 scl = gpio_get_value(p->scl.gp);
62                 if ((sda & scl) == 1)
63                         break;
64                 WATCHDOG_RESET();
65                 elapsed = get_timer(start_time);
66                 if (elapsed > (CONFIG_SYS_HZ / 5)) {    /* .2 seconds */
67                         ret = -EBUSY;
68                         printf("%s: failed to clear bus, sda=%d scl=%d\n",
69                                         __func__, sda, scl);
70                         break;
71                 }
72         }
73 exit:
74         imx_iomux_v3_setup_pad(p->sda.i2c_mode);
75         imx_iomux_v3_setup_pad(p->scl.i2c_mode);
76         return ret;
77 }
78
79 static void * const i2c_bases[] = {
80         (void *)I2C1_BASE_ADDR,
81         (void *)I2C2_BASE_ADDR,
82 #ifdef I2C3_BASE_ADDR
83         (void *)I2C3_BASE_ADDR,
84 #endif
85 };
86
87 /* i2c_index can be from 0 - 2 */
88 void setup_i2c(unsigned i2c_index, int speed, int slave_addr,
89                 struct i2c_pads_info *p)
90 {
91         if (i2c_index >= ARRAY_SIZE(i2c_bases))
92                 return;
93         /* Enable i2c clock */
94         enable_i2c_clk(1, i2c_index);
95         /* Make sure bus is idle */
96         force_idle_bus(p);
97         bus_i2c_init(i2c_bases[i2c_index], speed, slave_addr,
98                         force_idle_bus, p);
99 }