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