1 /* 2 * I2C multiplexer using GPIO API 3 * 4 * Copyright 2017 NXP 5 * 6 * Peng Fan <peng.fan@nxp.com> 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <asm/io.h> 12 #include <asm-generic/gpio.h> 13 #include <common.h> 14 #include <dm.h> 15 #include <dm/pinctrl.h> 16 #include <fdtdec.h> 17 #include <i2c.h> 18 #include <linux/errno.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 /** 23 * struct i2c_mux_gpio_priv - private data for i2c mux gpio 24 * 25 * @values: the reg value of each child node 26 * @n_values: num of regs 27 * @gpios: the mux-gpios array 28 * @n_gpios: num of gpios in mux-gpios 29 * @idle: the value of idle-state 30 */ 31 struct i2c_mux_gpio_priv { 32 u32 *values; 33 int n_values; 34 struct gpio_desc *gpios; 35 int n_gpios; 36 u32 idle; 37 }; 38 39 40 static int i2c_mux_gpio_select(struct udevice *dev, struct udevice *bus, 41 uint channel) 42 { 43 struct i2c_mux_gpio_priv *priv = dev_get_priv(dev); 44 int i, ret; 45 46 for (i = 0; i < priv->n_gpios; i++) { 47 ret = dm_gpio_set_value(&priv->gpios[i], (channel >> i) & 1); 48 if (ret) 49 return ret; 50 } 51 52 return 0; 53 } 54 55 static int i2c_mux_gpio_deselect(struct udevice *dev, struct udevice *bus, 56 uint channel) 57 { 58 struct i2c_mux_gpio_priv *priv = dev_get_priv(dev); 59 int i, ret; 60 61 for (i = 0; i < priv->n_gpios; i++) { 62 ret = dm_gpio_set_value(&priv->gpios[i], (priv->idle >> i) & 1); 63 if (ret) 64 return ret; 65 } 66 67 return 0; 68 } 69 70 static int i2c_mux_gpio_probe(struct udevice *dev) 71 { 72 const void *fdt = gd->fdt_blob; 73 int node = dev_of_offset(dev); 74 struct i2c_mux_gpio_priv *mux = dev_get_priv(dev); 75 struct gpio_desc *gpios; 76 u32 *values; 77 int i = 0, subnode, ret; 78 79 mux->n_values = fdtdec_get_child_count(fdt, node); 80 values = devm_kzalloc(dev, sizeof(*mux->values) * mux->n_values, 81 GFP_KERNEL); 82 if (!values) { 83 dev_err(dev, "Cannot alloc values array"); 84 return -ENOMEM; 85 } 86 87 fdt_for_each_subnode(subnode, fdt, node) { 88 *(values + i) = fdtdec_get_uint(fdt, subnode, "reg", -1); 89 i++; 90 } 91 92 mux->values = values; 93 94 mux->idle = fdtdec_get_uint(fdt, node, "idle-state", -1); 95 96 mux->n_gpios = gpio_get_list_count(dev, "mux-gpios"); 97 if (mux->n_gpios < 0) { 98 dev_err(dev, "Missing mux-gpios property\n"); 99 return -EINVAL; 100 } 101 102 gpios = devm_kzalloc(dev, sizeof(struct gpio_desc) * mux->n_gpios, 103 GFP_KERNEL); 104 if (!gpios) { 105 dev_err(dev, "Cannot allocate gpios array\n"); 106 return -ENOMEM; 107 } 108 109 ret = gpio_request_list_by_name(dev, "mux-gpios", gpios, mux->n_gpios, 110 GPIOD_IS_OUT_ACTIVE); 111 if (ret <= 0) { 112 dev_err(dev, "Failed to request mux-gpios\n"); 113 return ret; 114 } 115 116 mux->gpios = gpios; 117 118 return 0; 119 } 120 121 static const struct i2c_mux_ops i2c_mux_gpio_ops = { 122 .select = i2c_mux_gpio_select, 123 .deselect = i2c_mux_gpio_deselect, 124 }; 125 126 static const struct udevice_id i2c_mux_gpio_ids[] = { 127 { .compatible = "i2c-mux-gpio", }, 128 {} 129 }; 130 131 U_BOOT_DRIVER(i2c_mux_gpio) = { 132 .name = "i2c_mux_gpio", 133 .id = UCLASS_I2C_MUX, 134 .of_match = i2c_mux_gpio_ids, 135 .ops = &i2c_mux_gpio_ops, 136 .probe = i2c_mux_gpio_probe, 137 .priv_auto_alloc_size = sizeof(struct i2c_mux_gpio_priv), 138 }; 139