i2c_mux_pca954x.c (7753B)
1/* 2 * I2C multiplexer for PCA954x series of I2C multiplexer/switch chips. 3 * 4 * Copyright 2021 Google LLC 5 * 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. 10 * 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 14 * for more details. 15 */ 16 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" 24#include "qemu/log.h" 25#include "qemu/module.h" 26#include "qemu/queue.h" 27#include "qom/object.h" 28#include "trace.h" 29 30#define PCA9548_CHANNEL_COUNT 8 31#define PCA9546_CHANNEL_COUNT 4 32 33/* 34 * struct Pca954xChannel - The i2c mux device will have N of these states 35 * that own the i2c channel bus. 36 * @bus: The owned channel bus. 37 * @enabled: Is this channel active? 38 */ 39typedef struct Pca954xChannel { 40 SysBusDevice parent; 41 42 I2CBus *bus; 43 44 bool enabled; 45} Pca954xChannel; 46 47#define TYPE_PCA954X_CHANNEL "pca954x-channel" 48#define PCA954X_CHANNEL(obj) \ 49 OBJECT_CHECK(Pca954xChannel, (obj), TYPE_PCA954X_CHANNEL) 50 51/* 52 * struct Pca954xState - The pca954x state object. 53 * @control: The value written to the mux control. 54 * @channel: The set of i2c channel buses that act as channels which own the 55 * i2c children. 56 */ 57typedef struct Pca954xState { 58 SMBusDevice parent; 59 60 uint8_t control; 61 62 /* The channel i2c buses. */ 63 Pca954xChannel channel[PCA9548_CHANNEL_COUNT]; 64} Pca954xState; 65 66/* 67 * struct Pca954xClass - The pca954x class object. 68 * @nchans: The number of i2c channels this device has. 69 */ 70typedef struct Pca954xClass { 71 SMBusDeviceClass parent; 72 73 uint8_t nchans; 74} Pca954xClass; 75 76#define TYPE_PCA954X "pca954x" 77OBJECT_DECLARE_TYPE(Pca954xState, Pca954xClass, PCA954X) 78 79/* 80 * For each channel, if it's enabled, recursively call match on those children. 81 */ 82static bool pca954x_match(I2CSlave *candidate, uint8_t address, 83 bool broadcast, 84 I2CNodeList *current_devs) 85{ 86 Pca954xState *mux = PCA954X(candidate); 87 Pca954xClass *mc = PCA954X_GET_CLASS(mux); 88 int i; 89 90 /* They are talking to the mux itself (or all devices enabled). */ 91 if ((candidate->address == address) || broadcast) { 92 I2CNode *node = g_malloc(sizeof(struct I2CNode)); 93 node->elt = candidate; 94 QLIST_INSERT_HEAD(current_devs, node, next); 95 if (!broadcast) { 96 return true; 97 } 98 } 99 100 for (i = 0; i < mc->nchans; i++) { 101 if (!mux->channel[i].enabled) { 102 continue; 103 } 104 105 if (i2c_scan_bus(mux->channel[i].bus, address, broadcast, 106 current_devs)) { 107 if (!broadcast) { 108 return true; 109 } 110 } 111 } 112 113 /* If we arrived here we didn't find a match, return broadcast. */ 114 return broadcast; 115} 116 117static void pca954x_enable_channel(Pca954xState *s, uint8_t enable_mask) 118{ 119 Pca954xClass *mc = PCA954X_GET_CLASS(s); 120 int i; 121 122 /* 123 * For each channel, check if their bit is set in enable_mask and if yes, 124 * enable it, otherwise disable, hide it. 125 */ 126 for (i = 0; i < mc->nchans; i++) { 127 if (enable_mask & (1 << i)) { 128 s->channel[i].enabled = true; 129 } else { 130 s->channel[i].enabled = false; 131 } 132 } 133} 134 135static void pca954x_write(Pca954xState *s, uint8_t data) 136{ 137 s->control = data; 138 pca954x_enable_channel(s, data); 139 140 trace_pca954x_write_bytes(data); 141} 142 143static int pca954x_write_data(SMBusDevice *d, uint8_t *buf, uint8_t len) 144{ 145 Pca954xState *s = PCA954X(d); 146 147 if (len == 0) { 148 qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); 149 return -1; 150 } 151 152 /* 153 * len should be 1, because they write one byte to enable/disable channels. 154 */ 155 if (len > 1) { 156 qemu_log_mask(LOG_GUEST_ERROR, 157 "%s: extra data after channel selection mask\n", 158 __func__); 159 return -1; 160 } 161 162 pca954x_write(s, buf[0]); 163 return 0; 164} 165 166static uint8_t pca954x_read_byte(SMBusDevice *d) 167{ 168 Pca954xState *s = PCA954X(d); 169 uint8_t data = s->control; 170 trace_pca954x_read_data(data); 171 return data; 172} 173 174static void pca954x_enter_reset(Object *obj, ResetType type) 175{ 176 Pca954xState *s = PCA954X(obj); 177 /* Reset will disable all channels. */ 178 pca954x_write(s, 0); 179} 180 181I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel) 182{ 183 Pca954xClass *pc = PCA954X_GET_CLASS(mux); 184 Pca954xState *pca954x = PCA954X(mux); 185 186 g_assert(channel < pc->nchans); 187 return I2C_BUS(qdev_get_child_bus(DEVICE(&pca954x->channel[channel]), 188 "i2c-bus")); 189} 190 191static void pca954x_channel_init(Object *obj) 192{ 193 Pca954xChannel *s = PCA954X_CHANNEL(obj); 194 s->bus = i2c_init_bus(DEVICE(s), "i2c-bus"); 195 196 /* Start all channels as disabled. */ 197 s->enabled = false; 198} 199 200static void pca954x_channel_class_init(ObjectClass *klass, void *data) 201{ 202 DeviceClass *dc = DEVICE_CLASS(klass); 203 dc->desc = "Pca954x Channel"; 204} 205 206static void pca9546_class_init(ObjectClass *klass, void *data) 207{ 208 Pca954xClass *s = PCA954X_CLASS(klass); 209 s->nchans = PCA9546_CHANNEL_COUNT; 210} 211 212static void pca9548_class_init(ObjectClass *klass, void *data) 213{ 214 Pca954xClass *s = PCA954X_CLASS(klass); 215 s->nchans = PCA9548_CHANNEL_COUNT; 216} 217 218static void pca954x_realize(DeviceState *dev, Error **errp) 219{ 220 Pca954xState *s = PCA954X(dev); 221 Pca954xClass *c = PCA954X_GET_CLASS(s); 222 int i; 223 224 /* SMBus modules. Cannot fail. */ 225 for (i = 0; i < c->nchans; i++) { 226 sysbus_realize(SYS_BUS_DEVICE(&s->channel[i]), &error_abort); 227 } 228} 229 230static void pca954x_init(Object *obj) 231{ 232 Pca954xState *s = PCA954X(obj); 233 Pca954xClass *c = PCA954X_GET_CLASS(obj); 234 int i; 235 236 /* Only initialize the children we expect. */ 237 for (i = 0; i < c->nchans; i++) { 238 object_initialize_child(obj, "channel[*]", &s->channel[i], 239 TYPE_PCA954X_CHANNEL); 240 } 241} 242 243static void pca954x_class_init(ObjectClass *klass, void *data) 244{ 245 I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 246 ResettableClass *rc = RESETTABLE_CLASS(klass); 247 DeviceClass *dc = DEVICE_CLASS(klass); 248 SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass); 249 250 sc->match_and_add = pca954x_match; 251 252 rc->phases.enter = pca954x_enter_reset; 253 254 dc->desc = "Pca954x i2c-mux"; 255 dc->realize = pca954x_realize; 256 257 k->write_data = pca954x_write_data; 258 k->receive_byte = pca954x_read_byte; 259} 260 261static const TypeInfo pca954x_info[] = { 262 { 263 .name = TYPE_PCA954X, 264 .parent = TYPE_SMBUS_DEVICE, 265 .instance_size = sizeof(Pca954xState), 266 .instance_init = pca954x_init, 267 .class_size = sizeof(Pca954xClass), 268 .class_init = pca954x_class_init, 269 .abstract = true, 270 }, 271 { 272 .name = TYPE_PCA9546, 273 .parent = TYPE_PCA954X, 274 .class_init = pca9546_class_init, 275 }, 276 { 277 .name = TYPE_PCA9548, 278 .parent = TYPE_PCA954X, 279 .class_init = pca9548_class_init, 280 }, 281 { 282 .name = TYPE_PCA954X_CHANNEL, 283 .parent = TYPE_SYS_BUS_DEVICE, 284 .class_init = pca954x_channel_class_init, 285 .instance_size = sizeof(Pca954xChannel), 286 .instance_init = pca954x_channel_init, 287 } 288}; 289 290DEFINE_TYPES(pca954x_info)