]> git.sur5r.net Git - u-boot/blob - drivers/i2c/muxes/pca954x.c
drivers/i2c/muxes/pca954x: Add pca9547 I2C mux support
[u-boot] / drivers / i2c / muxes / pca954x.c
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 };