]>
Commit | Line | Data |
---|---|---|
cc54a0f7 TK |
1 | /* |
2 | * Copyright (C) 2012 Boundary Devices Inc. | |
3 | * | |
1a459660 | 4 | * SPDX-License-Identifier: GPL-2.0+ |
cc54a0f7 TK |
5 | */ |
6 | #include <common.h> | |
c6f3f323 | 7 | #include <malloc.h> |
cc54a0f7 TK |
8 | #include <asm/arch/clock.h> |
9 | #include <asm/arch/imx-regs.h> | |
1221ce45 | 10 | #include <linux/errno.h> |
cc54a0f7 TK |
11 | #include <asm/gpio.h> |
12 | #include <asm/imx-common/mxc_i2c.h> | |
13 | #include <watchdog.h> | |
14 | ||
71204e95 | 15 | int force_idle_bus(void *priv) |
cc54a0f7 TK |
16 | { |
17 | int i; | |
18 | int sda, scl; | |
19 | ulong elapsed, start_time; | |
20 | struct i2c_pads_info *p = (struct i2c_pads_info *)priv; | |
21 | int ret = 0; | |
22 | ||
23 | gpio_direction_input(p->sda.gp); | |
24 | gpio_direction_input(p->scl.gp); | |
25 | ||
26 | imx_iomux_v3_setup_pad(p->sda.gpio_mode); | |
27 | imx_iomux_v3_setup_pad(p->scl.gpio_mode); | |
28 | ||
29 | sda = gpio_get_value(p->sda.gp); | |
30 | scl = gpio_get_value(p->scl.gp); | |
31 | if ((sda & scl) == 1) | |
32 | goto exit; /* Bus is idle already */ | |
33 | ||
34 | printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__, | |
35 | sda, scl, p->sda.gp, p->scl.gp); | |
36 | /* Send high and low on the SCL line */ | |
37 | for (i = 0; i < 9; i++) { | |
38 | gpio_direction_output(p->scl.gp, 0); | |
39 | udelay(50); | |
40 | gpio_direction_input(p->scl.gp); | |
41 | udelay(50); | |
42 | } | |
43 | start_time = get_timer(0); | |
44 | for (;;) { | |
45 | sda = gpio_get_value(p->sda.gp); | |
46 | scl = gpio_get_value(p->scl.gp); | |
47 | if ((sda & scl) == 1) | |
48 | break; | |
49 | WATCHDOG_RESET(); | |
50 | elapsed = get_timer(start_time); | |
51 | if (elapsed > (CONFIG_SYS_HZ / 5)) { /* .2 seconds */ | |
52 | ret = -EBUSY; | |
53 | printf("%s: failed to clear bus, sda=%d scl=%d\n", | |
54 | __func__, sda, scl); | |
55 | break; | |
56 | } | |
57 | } | |
58 | exit: | |
59 | imx_iomux_v3_setup_pad(p->sda.i2c_mode); | |
60 | imx_iomux_v3_setup_pad(p->scl.i2c_mode); | |
61 | return ret; | |
62 | } | |
63 | ||
64 | static void * const i2c_bases[] = { | |
65 | (void *)I2C1_BASE_ADDR, | |
66 | (void *)I2C2_BASE_ADDR, | |
67 | #ifdef I2C3_BASE_ADDR | |
68 | (void *)I2C3_BASE_ADDR, | |
69 | #endif | |
21a26940 HS |
70 | #ifdef I2C4_BASE_ADDR |
71 | (void *)I2C4_BASE_ADDR, | |
72 | #endif | |
cc54a0f7 TK |
73 | }; |
74 | ||
21a26940 | 75 | /* i2c_index can be from 0 - 3 */ |
edbf8b4f SG |
76 | int setup_i2c(unsigned i2c_index, int speed, int slave_addr, |
77 | struct i2c_pads_info *p) | |
cc54a0f7 | 78 | { |
cd3c5896 | 79 | char name[9]; |
edbf8b4f SG |
80 | int ret; |
81 | ||
cc54a0f7 | 82 | if (i2c_index >= ARRAY_SIZE(i2c_bases)) |
edbf8b4f | 83 | return -EINVAL; |
c6f3f323 | 84 | |
cd3c5896 MV |
85 | snprintf(name, sizeof(name), "i2c_sda%01d", i2c_index); |
86 | ret = gpio_request(p->sda.gp, name); | |
c6f3f323 | 87 | if (ret) |
cd3c5896 | 88 | return ret; |
c6f3f323 | 89 | |
cd3c5896 MV |
90 | snprintf(name, sizeof(name), "i2c_scl%01d", i2c_index); |
91 | ret = gpio_request(p->scl.gp, name); | |
c6f3f323 | 92 | if (ret) |
cd3c5896 | 93 | goto err_req; |
c6f3f323 | 94 | |
cc54a0f7 | 95 | /* Enable i2c clock */ |
edbf8b4f SG |
96 | ret = enable_i2c_clk(1, i2c_index); |
97 | if (ret) | |
98 | goto err_clk; | |
99 | ||
cc54a0f7 | 100 | /* Make sure bus is idle */ |
edbf8b4f SG |
101 | ret = force_idle_bus(p); |
102 | if (ret) | |
103 | goto err_idle; | |
104 | ||
71204e95 PF |
105 | #ifndef CONFIG_DM_I2C |
106 | bus_i2c_init(i2c_index, speed, slave_addr, force_idle_bus, p); | |
107 | #endif | |
edbf8b4f SG |
108 | |
109 | return 0; | |
110 | ||
111 | err_idle: | |
112 | err_clk: | |
c6f3f323 | 113 | gpio_free(p->scl.gp); |
cd3c5896 | 114 | err_req: |
c6f3f323 | 115 | gpio_free(p->sda.gp); |
c6f3f323 | 116 | |
edbf8b4f | 117 | return ret; |
cc54a0f7 | 118 | } |