1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <i2c.h>
11 #include <asm/gpio.h>
12
13 DECLARE_GLOBAL_DATA_PTR;
14
15 struct i2c_arbitrator_priv {
16 struct gpio_desc ap_claim;
17 struct gpio_desc ec_claim;
18 uint slew_delay_us;
19 uint wait_retry_ms;
20 uint wait_free_ms;
21 };
22
i2c_arbitrator_deselect(struct udevice * mux,struct udevice * bus,uint channel)23 int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
24 uint channel)
25 {
26 struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
27 int ret;
28
29 debug("%s: %s\n", __func__, mux->name);
30 ret = dm_gpio_set_value(&priv->ap_claim, 0);
31 udelay(priv->slew_delay_us);
32
33 return ret;
34 }
35
i2c_arbitrator_select(struct udevice * mux,struct udevice * bus,uint channel)36 int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
37 uint channel)
38 {
39 struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
40 unsigned start;
41 int ret;
42
43 debug("%s: %s\n", __func__, mux->name);
44 /* Start a round of trying to claim the bus */
45 start = get_timer(0);
46 do {
47 unsigned start_retry;
48 int waiting = 0;
49
50 /* Indicate that we want to claim the bus */
51 ret = dm_gpio_set_value(&priv->ap_claim, 1);
52 if (ret)
53 goto err;
54 udelay(priv->slew_delay_us);
55
56 /* Wait for the EC to release it */
57 start_retry = get_timer(0);
58 while (get_timer(start_retry) < priv->wait_retry_ms) {
59 ret = dm_gpio_get_value(&priv->ec_claim);
60 if (ret < 0) {
61 goto err;
62 } else if (!ret) {
63 /* We got it, so return */
64 return 0;
65 }
66
67 if (!waiting)
68 waiting = 1;
69 }
70
71 /* It didn't release, so give up, wait, and try again */
72 ret = dm_gpio_set_value(&priv->ap_claim, 0);
73 if (ret)
74 goto err;
75
76 mdelay(priv->wait_retry_ms);
77 } while (get_timer(start) < priv->wait_free_ms);
78
79 /* Give up, release our claim */
80 printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
81 ret = -ETIMEDOUT;
82 ret = 0;
83 err:
84 return ret;
85 }
86
i2c_arbitrator_probe(struct udevice * dev)87 static int i2c_arbitrator_probe(struct udevice *dev)
88 {
89 struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
90 const void *blob = gd->fdt_blob;
91 int node = dev_of_offset(dev);
92 int ret;
93
94 debug("%s: %s\n", __func__, dev->name);
95 priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
96 priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
97 1000;
98 priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
99 1000;
100 ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
101 GPIOD_IS_OUT);
102 if (ret)
103 goto err;
104 ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
105 GPIOD_IS_IN);
106 if (ret)
107 goto err_ec_gpio;
108
109 return 0;
110
111 err_ec_gpio:
112 dm_gpio_free(dev, &priv->ap_claim);
113 err:
114 debug("%s: ret=%d\n", __func__, ret);
115 return ret;
116 }
117
i2c_arbitrator_remove(struct udevice * dev)118 static int i2c_arbitrator_remove(struct udevice *dev)
119 {
120 struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
121
122 dm_gpio_free(dev, &priv->ap_claim);
123 dm_gpio_free(dev, &priv->ec_claim);
124
125 return 0;
126 }
127
128 static const struct i2c_mux_ops i2c_arbitrator_ops = {
129 .select = i2c_arbitrator_select,
130 .deselect = i2c_arbitrator_deselect,
131 };
132
133 static const struct udevice_id i2c_arbitrator_ids[] = {
134 { .compatible = "i2c-arb-gpio-challenge" },
135 { }
136 };
137
138 U_BOOT_DRIVER(i2c_arbitrator) = {
139 .name = "i2c_arbitrator",
140 .id = UCLASS_I2C_MUX,
141 .of_match = i2c_arbitrator_ids,
142 .probe = i2c_arbitrator_probe,
143 .remove = i2c_arbitrator_remove,
144 .ops = &i2c_arbitrator_ops,
145 .priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv),
146 };
147