blob: 413aaa6ba314d73a44295531c95593fabf7ca189 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassb725dc42015-08-03 08:19:22 -06002/*
3 * Copyright (c) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glassb725dc42015-08-03 08:19:22 -06005 */
6
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
10#include <i2c.h>
11#include <asm/gpio.h>
12
13DECLARE_GLOBAL_DATA_PTR;
14
15struct 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
23int 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
36int 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;
83err:
84 return ret;
85}
86
87static 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;
Simon Glasse160f7d2017-01-17 16:52:55 -070091 int node = dev_of_offset(dev);
Simon Glassb725dc42015-08-03 08:19:22 -060092 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
111err_ec_gpio:
112 dm_gpio_free(dev, &priv->ap_claim);
113err:
114 debug("%s: ret=%d\n", __func__, ret);
115 return ret;
116}
117
118static 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
128static const struct i2c_mux_ops i2c_arbitrator_ops = {
129 .select = i2c_arbitrator_select,
130 .deselect = i2c_arbitrator_deselect,
131};
132
133static const struct udevice_id i2c_arbitrator_ids[] = {
134 { .compatible = "i2c-arb-gpio-challenge" },
135 { }
136};
137
138U_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};