Home | History | Annotate | Download | only in muxes
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2015 - 2016 Xilinx, Inc.
      4  * Copyright (C) 2017 National Instruments Corp
      5  * Written by Michal Simek
      6  */
      7 
      8 #include <common.h>
      9 #include <dm.h>
     10 #include <errno.h>
     11 #include <i2c.h>
     12 
     13 #include <asm-generic/gpio.h>
     14 
     15 DECLARE_GLOBAL_DATA_PTR;
     16 
     17 enum pca_type {
     18 	PCA9544,
     19 	PCA9547,
     20 	PCA9548
     21 };
     22 
     23 struct chip_desc {
     24 	u8 enable;
     25 	enum muxtype {
     26 		pca954x_ismux = 0,
     27 		pca954x_isswi,
     28 	} muxtype;
     29 	u32 width;
     30 };
     31 
     32 struct pca954x_priv {
     33 	u32 addr; /* I2C mux address */
     34 	u32 width; /* I2C mux width - number of busses */
     35 	struct gpio_desc gpio_mux_reset;
     36 };
     37 
     38 static const struct chip_desc chips[] = {
     39 	[PCA9544] = {
     40 		.enable = 0x4,
     41 		.muxtype = pca954x_ismux,
     42 		.width = 4,
     43 	},
     44 	[PCA9547] = {
     45 		.enable = 0x8,
     46 		.muxtype = pca954x_ismux,
     47 		.width = 8,
     48 	},
     49 	[PCA9548] = {
     50 		.enable = 0x8,
     51 		.muxtype = pca954x_isswi,
     52 		.width = 8,
     53 	},
     54 };
     55 
     56 static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
     57 			    uint channel)
     58 {
     59 	struct pca954x_priv *priv = dev_get_priv(mux);
     60 	uchar byte = 0;
     61 
     62 	return dm_i2c_write(mux, priv->addr, &byte, 1);
     63 }
     64 
     65 static int pca954x_select(struct udevice *mux, struct udevice *bus,
     66 			  uint channel)
     67 {
     68 	struct pca954x_priv *priv = dev_get_priv(mux);
     69 	const struct chip_desc *chip = &chips[dev_get_driver_data(mux)];
     70 	uchar byte;
     71 
     72 	if (chip->muxtype == pca954x_ismux)
     73 		byte = channel | chip->enable;
     74 	else
     75 		byte = 1 << channel;
     76 
     77 	return dm_i2c_write(mux, priv->addr, &byte, 1);
     78 }
     79 
     80 static const struct i2c_mux_ops pca954x_ops = {
     81 	.select = pca954x_select,
     82 	.deselect = pca954x_deselect,
     83 };
     84 
     85 static const struct udevice_id pca954x_ids[] = {
     86 	{ .compatible = "nxp,pca9544", .data = PCA9544 },
     87 	{ .compatible = "nxp,pca9547", .data = PCA9547 },
     88 	{ .compatible = "nxp,pca9548", .data = PCA9548 },
     89 	{ }
     90 };
     91 
     92 static int pca954x_ofdata_to_platdata(struct udevice *dev)
     93 {
     94 	struct pca954x_priv *priv = dev_get_priv(dev);
     95 	const struct chip_desc *chip = &chips[dev_get_driver_data(dev)];
     96 
     97 	priv->addr = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", 0);
     98 	if (!priv->addr) {
     99 		debug("MUX not found\n");
    100 		return -ENODEV;
    101 	}
    102 	priv->width = chip->width;
    103 
    104 	if (!priv->width) {
    105 		debug("No I2C MUX width specified\n");
    106 		return -EINVAL;
    107 	}
    108 
    109 	debug("Device %s at 0x%x with width %d\n",
    110 	      dev->name, priv->addr, priv->width);
    111 
    112 	return 0;
    113 }
    114 
    115 static int pca954x_probe(struct udevice *dev)
    116 {
    117 	if (IS_ENABLED(CONFIG_DM_GPIO)) {
    118 		struct pca954x_priv *priv = dev_get_priv(dev);
    119 		int err;
    120 
    121 		err = gpio_request_by_name(dev, "reset-gpios", 0,
    122 				&priv->gpio_mux_reset, GPIOD_IS_OUT);
    123 
    124 		/* it's optional so only bail if we get a real error */
    125 		if (err && (err != -ENOENT))
    126 			return err;
    127 
    128 		/* dm will take care of polarity */
    129 		if (dm_gpio_is_valid(&priv->gpio_mux_reset))
    130 			dm_gpio_set_value(&priv->gpio_mux_reset, 0);
    131 	}
    132 
    133 	return 0;
    134 }
    135 
    136 static int pca954x_remove(struct udevice *dev)
    137 {
    138 	if (IS_ENABLED(CONFIG_DM_GPIO)) {
    139 		struct pca954x_priv *priv = dev_get_priv(dev);
    140 
    141 		if (dm_gpio_is_valid(&priv->gpio_mux_reset))
    142 			dm_gpio_free(dev, &priv->gpio_mux_reset);
    143 	}
    144 
    145 	return 0;
    146 }
    147 
    148 U_BOOT_DRIVER(pca954x) = {
    149 	.name = "pca954x",
    150 	.id = UCLASS_I2C_MUX,
    151 	.of_match = pca954x_ids,
    152 	.probe = pca954x_probe,
    153 	.remove = pca954x_remove,
    154 	.ops = &pca954x_ops,
    155 	.ofdata_to_platdata = pca954x_ofdata_to_platdata,
    156 	.priv_auto_alloc_size = sizeof(struct pca954x_priv),
    157 };
    158