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