1 /* 2 * Copyright (C) 2015 - 2016 Xilinx, Inc. 3 * Written by Michal Simek 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <i2c.h> 12 #include <asm/gpio.h> 13 14 DECLARE_GLOBAL_DATA_PTR; 15 16 enum pca_type { 17 PCA9544, 18 PCA9547, 19 PCA9548 20 }; 21 22 struct chip_desc { 23 u8 enable; 24 enum muxtype { 25 pca954x_ismux = 0, 26 pca954x_isswi, 27 } muxtype; 28 }; 29 30 struct pca954x_priv { 31 u32 addr; /* I2C mux address */ 32 u32 width; /* I2C mux width - number of busses */ 33 }; 34 35 static const struct chip_desc chips[] = { 36 [PCA9544] = { 37 .enable = 0x4, 38 .muxtype = pca954x_ismux, 39 }, 40 [PCA9547] = { 41 .enable = 0x8, 42 .muxtype = pca954x_ismux, 43 }, 44 [PCA9548] = { 45 .enable = 0x8, 46 .muxtype = pca954x_isswi, 47 }, 48 }; 49 50 static int pca954x_deselect(struct udevice *mux, struct udevice *bus, 51 uint channel) 52 { 53 struct pca954x_priv *priv = dev_get_priv(mux); 54 uchar byte = 0; 55 56 return dm_i2c_write(mux, priv->addr, &byte, 1); 57 } 58 59 static int pca954x_select(struct udevice *mux, struct udevice *bus, 60 uint channel) 61 { 62 struct pca954x_priv *priv = dev_get_priv(mux); 63 const struct chip_desc *chip = &chips[dev_get_driver_data(mux)]; 64 uchar byte; 65 66 if (chip->muxtype == pca954x_ismux) 67 byte = channel | chip->enable; 68 else 69 byte = 1 << channel; 70 71 return dm_i2c_write(mux, priv->addr, &byte, 1); 72 } 73 74 static const struct i2c_mux_ops pca954x_ops = { 75 .select = pca954x_select, 76 .deselect = pca954x_deselect, 77 }; 78 79 static const struct udevice_id pca954x_ids[] = { 80 { .compatible = "nxp,pca9544", .data = PCA9544 }, 81 { .compatible = "nxp,pca9547", .data = PCA9547 }, 82 { .compatible = "nxp,pca9548", .data = PCA9548 }, 83 { } 84 }; 85 86 static int pca954x_ofdata_to_platdata(struct udevice *dev) 87 { 88 struct pca954x_priv *priv = dev_get_priv(dev); 89 90 priv->addr = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", 0); 91 if (!priv->addr) { 92 debug("MUX not found\n"); 93 return -ENODEV; 94 } 95 priv->width = dev_get_driver_data(dev); 96 97 if (!priv->width) { 98 debug("No I2C MUX width specified\n"); 99 return -EINVAL; 100 } 101 102 debug("Device %s at 0x%x with width %d\n", 103 dev->name, priv->addr, priv->width); 104 105 return 0; 106 } 107 108 U_BOOT_DRIVER(pca954x) = { 109 .name = "pca954x", 110 .id = UCLASS_I2C_MUX, 111 .of_match = pca954x_ids, 112 .ops = &pca954x_ops, 113 .ofdata_to_platdata = pca954x_ofdata_to_platdata, 114 .priv_auto_alloc_size = sizeof(struct pca954x_priv), 115 }; 116