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