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