xref: /openbmc/u-boot/drivers/i2c/muxes/pca954x.c (revision 0dfe3ffe)
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