Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/i2c/muxes/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  i2c-mux-gpio.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * I2C multiplexer using GPIO API
 *
 * Peter Korsgaard <peter.korsgaard@barco.com>
 */


#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/platform_data/i2c-mux-gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

struct gpiomux {
 struct i2c_mux_gpio_platform_data data;
 int ngpios;
 struct gpio_desc **gpios;
};

static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned int val)
{
 DECLARE_BITMAP(values, BITS_PER_TYPE(val));

 values[0] = val;

 gpiod_set_array_value_cansleep(mux->ngpios, mux->gpios, NULL, values);
}

static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
{
 struct gpiomux *mux = i2c_mux_priv(muxc);

 i2c_mux_gpio_set(mux, chan);

 if (mux->data.settle_time)
  fsleep(mux->data.settle_time);

 return 0;
}

static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
{
 struct gpiomux *mux = i2c_mux_priv(muxc);

 i2c_mux_gpio_set(mux, mux->data.idle);

 return 0;
}

static int i2c_mux_gpio_probe_fw(struct gpiomux *mux,
     struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct fwnode_handle *fwnode = dev_fwnode(dev);
 struct device_node *np = dev->of_node;
 struct device_node *adapter_np;
 struct i2c_adapter *adapter = NULL;
 struct fwnode_handle *child;
 unsigned int *values;
 int rc, i = 0;

 if (is_of_node(fwnode)) {
  if (!np)
   return -ENODEV;

  adapter_np = of_parse_phandle(np, "i2c-parent", 0);
  if (!adapter_np) {
   dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
   return -ENODEV;
  }
  adapter = of_find_i2c_adapter_by_node(adapter_np);
  of_node_put(adapter_np);

 } else if (is_acpi_node(fwnode)) {
  /*
 * In ACPI land the mux should be a direct child of the i2c
 * bus it muxes.
 */

  acpi_handle dev_handle = ACPI_HANDLE(dev->parent);

  adapter = i2c_acpi_find_adapter_by_handle(dev_handle);
 }

 if (!adapter)
  return -EPROBE_DEFER;

 mux->data.parent = i2c_adapter_id(adapter);
 put_device(&adapter->dev);

 mux->data.n_values = device_get_child_node_count(dev);
 values = devm_kcalloc(dev,
         mux->data.n_values, sizeof(*mux->data.values),
         GFP_KERNEL);
 if (!values) {
  dev_err(dev, "Cannot allocate values array");
  return -ENOMEM;
 }

 device_for_each_child_node(dev, child) {
  if (is_of_node(child)) {
   fwnode_property_read_u32(child, "reg", values + i);
  } else if (is_acpi_node(child)) {
   rc = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), values + i);
   if (rc) {
    fwnode_handle_put(child);
    return dev_err_probe(dev, rc, "Cannot get address\n");
   }
  }

  i++;
 }
 mux->data.values = values;

 if (device_property_read_u32(dev, "idle-state", &mux->data.idle))
  mux->data.idle = I2C_MUX_GPIO_NO_IDLE;

 device_property_read_u32(dev, "settle-time-us", &mux->data.settle_time);

 return 0;
}

static int i2c_mux_gpio_probe(struct platform_device *pdev)
{
 struct i2c_mux_core *muxc;
 struct gpiomux *mux;
 struct i2c_adapter *parent;
 struct i2c_adapter *root;
 unsigned int initial_state;
 int i, ngpios, ret;

 mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
 if (!mux)
  return -ENOMEM;

 if (!dev_get_platdata(&pdev->dev)) {
  ret = i2c_mux_gpio_probe_fw(mux, pdev);
  if (ret < 0)
   return ret;
 } else {
  memcpy(&mux->data, dev_get_platdata(&pdev->dev),
   sizeof(mux->data));
 }

 ngpios = gpiod_count(&pdev->dev, "mux");
 if (ngpios <= 0) {
  dev_err(&pdev->dev, "no valid gpios provided\n");
  return ngpios ?: -EINVAL;
 }
 mux->ngpios = ngpios;

 parent = i2c_get_adapter(mux->data.parent);
 if (!parent)
  return -EPROBE_DEFER;

 muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values,
        array_size(ngpios, sizeof(*mux->gpios)), 0,
        i2c_mux_gpio_select, NULL);
 if (!muxc) {
  ret = -ENOMEM;
  goto alloc_failed;
 }
 mux->gpios = muxc->priv;
 muxc->priv = mux;

 platform_set_drvdata(pdev, muxc);

 root = i2c_root_adapter(&parent->dev);

 muxc->mux_locked = true;

 if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
  initial_state = mux->data.idle;
  muxc->deselect = i2c_mux_gpio_deselect;
 } else {
  initial_state = mux->data.values[0];
 }

 for (i = 0; i < ngpios; i++) {
  struct gpio_device *gdev;
  struct device *dev;
  struct gpio_desc *gpiod;
  enum gpiod_flags flag;

  if (initial_state & BIT(i))
   flag = GPIOD_OUT_HIGH;
  else
   flag = GPIOD_OUT_LOW;
  gpiod = devm_gpiod_get_index(&pdev->dev, "mux", i, flag);
  if (IS_ERR(gpiod)) {
   ret = PTR_ERR(gpiod);
   goto alloc_failed;
  }

  mux->gpios[i] = gpiod;

  if (!muxc->mux_locked)
   continue;

  gdev = gpiod_to_gpio_device(gpiod);
  dev = gpio_device_to_device(gdev);
  muxc->mux_locked = i2c_root_adapter(dev) == root;
 }

 if (muxc->mux_locked)
  dev_info(&pdev->dev, "mux-locked i2c mux\n");

 for (i = 0; i < mux->data.n_values; i++) {
  u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;

  ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i]);
  if (ret)
   goto add_adapter_failed;
 }

 dev_info(&pdev->dev, "%d port mux on %s adapter\n",
   mux->data.n_values, parent->name);

 return 0;

add_adapter_failed:
 i2c_mux_del_adapters(muxc);
alloc_failed:
 i2c_put_adapter(parent);

 return ret;
}

static void i2c_mux_gpio_remove(struct platform_device *pdev)
{
 struct i2c_mux_core *muxc = platform_get_drvdata(pdev);

 i2c_mux_del_adapters(muxc);
 i2c_put_adapter(muxc->parent);
}

static const struct of_device_id i2c_mux_gpio_of_match[] = {
 { .compatible = "i2c-mux-gpio", },
 {},
};
MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match);

static struct platform_driver i2c_mux_gpio_driver = {
 .probe = i2c_mux_gpio_probe,
 .remove = i2c_mux_gpio_remove,
 .driver = {
  .name = "i2c-mux-gpio",
  .of_match_table = i2c_mux_gpio_of_match,
 },
};

module_platform_driver(i2c_mux_gpio_driver);

MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
MODULE_AUTHOR("Peter Korsgaard ");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:i2c-mux-gpio");

Messung V0.5
C=80 H=93 G=86

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.