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