2 * I2C multiplexer for PCA954x series of I2C multiplexer/switch chips.
4 * Copyright 2021 Google LLC
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "qemu/osdep.h"
18 #include "qapi/error.h"
19 #include "hw/i2c/i2c.h"
20 #include "hw/i2c/i2c_mux_pca954x.h"
21 #include "hw/i2c/smbus_slave.h"
22 #include "hw/qdev-core.h"
23 #include "hw/sysbus.h"
25 #include "qemu/module.h"
26 #include "qemu/queue.h"
27 #include "qom/object.h"
30 #define PCA9548_CHANNEL_COUNT 8
31 #define PCA9546_CHANNEL_COUNT 4
34 * struct Pca954xState - The pca954x state object.
35 * @control: The value written to the mux control.
36 * @channel: The set of i2c channel buses that act as channels which own the
39 typedef struct Pca954xState
{
44 bool enabled
[PCA9548_CHANNEL_COUNT
];
45 I2CBus
*bus
[PCA9548_CHANNEL_COUNT
];
49 * struct Pca954xClass - The pca954x class object.
50 * @nchans: The number of i2c channels this device has.
52 typedef struct Pca954xClass
{
53 SMBusDeviceClass parent
;
58 #define TYPE_PCA954X "pca954x"
59 OBJECT_DECLARE_TYPE(Pca954xState
, Pca954xClass
, PCA954X
)
62 * For each channel, if it's enabled, recursively call match on those children.
64 static bool pca954x_match(I2CSlave
*candidate
, uint8_t address
,
66 I2CNodeList
*current_devs
)
68 Pca954xState
*mux
= PCA954X(candidate
);
69 Pca954xClass
*mc
= PCA954X_GET_CLASS(mux
);
72 /* They are talking to the mux itself (or all devices enabled). */
73 if ((candidate
->address
== address
) || broadcast
) {
74 I2CNode
*node
= g_new(struct I2CNode
, 1);
75 node
->elt
= candidate
;
76 QLIST_INSERT_HEAD(current_devs
, node
, next
);
82 for (i
= 0; i
< mc
->nchans
; i
++) {
83 if (!mux
->enabled
[i
]) {
87 if (i2c_scan_bus(mux
->bus
[i
], address
, broadcast
,
95 /* If we arrived here we didn't find a match, return broadcast. */
99 static void pca954x_enable_channel(Pca954xState
*s
, uint8_t enable_mask
)
101 Pca954xClass
*mc
= PCA954X_GET_CLASS(s
);
105 * For each channel, check if their bit is set in enable_mask and if yes,
106 * enable it, otherwise disable, hide it.
108 for (i
= 0; i
< mc
->nchans
; i
++) {
109 if (enable_mask
& (1 << i
)) {
110 s
->enabled
[i
] = true;
112 s
->enabled
[i
] = false;
117 static void pca954x_write(Pca954xState
*s
, uint8_t data
)
120 pca954x_enable_channel(s
, data
);
122 trace_pca954x_write_bytes(data
);
125 static int pca954x_write_data(SMBusDevice
*d
, uint8_t *buf
, uint8_t len
)
127 Pca954xState
*s
= PCA954X(d
);
130 qemu_log_mask(LOG_GUEST_ERROR
, "%s: writing empty data\n", __func__
);
135 * len should be 1, because they write one byte to enable/disable channels.
138 qemu_log_mask(LOG_GUEST_ERROR
,
139 "%s: extra data after channel selection mask\n",
144 pca954x_write(s
, buf
[0]);
148 static uint8_t pca954x_read_byte(SMBusDevice
*d
)
150 Pca954xState
*s
= PCA954X(d
);
151 uint8_t data
= s
->control
;
152 trace_pca954x_read_data(data
);
156 static void pca954x_enter_reset(Object
*obj
, ResetType type
)
158 Pca954xState
*s
= PCA954X(obj
);
159 /* Reset will disable all channels. */
163 I2CBus
*pca954x_i2c_get_bus(I2CSlave
*mux
, uint8_t channel
)
165 Pca954xClass
*pc
= PCA954X_GET_CLASS(mux
);
166 Pca954xState
*pca954x
= PCA954X(mux
);
168 g_assert(channel
< pc
->nchans
);
169 return pca954x
->bus
[channel
];
172 static void pca9546_class_init(ObjectClass
*klass
, void *data
)
174 Pca954xClass
*s
= PCA954X_CLASS(klass
);
175 s
->nchans
= PCA9546_CHANNEL_COUNT
;
178 static void pca9548_class_init(ObjectClass
*klass
, void *data
)
180 Pca954xClass
*s
= PCA954X_CLASS(klass
);
181 s
->nchans
= PCA9548_CHANNEL_COUNT
;
184 static void pca954x_init(Object
*obj
)
186 Pca954xState
*s
= PCA954X(obj
);
187 Pca954xClass
*c
= PCA954X_GET_CLASS(obj
);
190 /* SMBus modules. Cannot fail. */
191 for (i
= 0; i
< c
->nchans
; i
++) {
192 g_autofree gchar
*bus_name
= g_strdup_printf("i2c.%d", i
);
194 /* start all channels as disabled. */
195 s
->enabled
[i
] = false;
196 s
->bus
[i
] = i2c_init_bus(DEVICE(s
), bus_name
);
200 static void pca954x_class_init(ObjectClass
*klass
, void *data
)
202 I2CSlaveClass
*sc
= I2C_SLAVE_CLASS(klass
);
203 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
204 DeviceClass
*dc
= DEVICE_CLASS(klass
);
205 SMBusDeviceClass
*k
= SMBUS_DEVICE_CLASS(klass
);
207 sc
->match_and_add
= pca954x_match
;
209 rc
->phases
.enter
= pca954x_enter_reset
;
211 dc
->desc
= "Pca954x i2c-mux";
213 k
->write_data
= pca954x_write_data
;
214 k
->receive_byte
= pca954x_read_byte
;
217 static const TypeInfo pca954x_info
[] = {
219 .name
= TYPE_PCA954X
,
220 .parent
= TYPE_SMBUS_DEVICE
,
221 .instance_size
= sizeof(Pca954xState
),
222 .instance_init
= pca954x_init
,
223 .class_size
= sizeof(Pca954xClass
),
224 .class_init
= pca954x_class_init
,
228 .name
= TYPE_PCA9546
,
229 .parent
= TYPE_PCA954X
,
230 .class_init
= pca9546_class_init
,
233 .name
= TYPE_PCA9548
,
234 .parent
= TYPE_PCA954X
,
235 .class_init
= pca9548_class_init
,
239 DEFINE_TYPES(pca954x_info
)