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