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 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 37 * i2c children. 38 */ 39 typedef struct Pca954xState { 40 SMBusDevice parent; 41 42 uint8_t control; 43 44 bool enabled[PCA9548_CHANNEL_COUNT]; 45 I2CBus *bus[PCA9548_CHANNEL_COUNT]; 46 } Pca954xState; 47 48 /* 49 * struct Pca954xClass - The pca954x class object. 50 * @nchans: The number of i2c channels this device has. 51 */ 52 typedef struct Pca954xClass { 53 SMBusDeviceClass parent; 54 55 uint8_t nchans; 56 } Pca954xClass; 57 58 #define TYPE_PCA954X "pca954x" 59 OBJECT_DECLARE_TYPE(Pca954xState, Pca954xClass, PCA954X) 60 61 /* 62 * For each channel, if it's enabled, recursively call match on those children. 63 */ 64 static bool pca954x_match(I2CSlave *candidate, uint8_t address, 65 bool broadcast, 66 I2CNodeList *current_devs) 67 { 68 Pca954xState *mux = PCA954X(candidate); 69 Pca954xClass *mc = PCA954X_GET_CLASS(mux); 70 int i; 71 72 /* They are talking to the mux itself (or all devices enabled). */ 73 if ((candidate->address == address) || broadcast) { 74 I2CNode *node = g_malloc(sizeof(struct I2CNode)); 75 node->elt = candidate; 76 QLIST_INSERT_HEAD(current_devs, node, next); 77 if (!broadcast) { 78 return true; 79 } 80 } 81 82 for (i = 0; i < mc->nchans; i++) { 83 if (!mux->enabled[i]) { 84 continue; 85 } 86 87 if (i2c_scan_bus(mux->bus[i], address, broadcast, 88 current_devs)) { 89 if (!broadcast) { 90 return true; 91 } 92 } 93 } 94 95 /* If we arrived here we didn't find a match, return broadcast. */ 96 return broadcast; 97 } 98 99 static void pca954x_enable_channel(Pca954xState *s, uint8_t enable_mask) 100 { 101 Pca954xClass *mc = PCA954X_GET_CLASS(s); 102 int i; 103 104 /* 105 * For each channel, check if their bit is set in enable_mask and if yes, 106 * enable it, otherwise disable, hide it. 107 */ 108 for (i = 0; i < mc->nchans; i++) { 109 if (enable_mask & (1 << i)) { 110 s->enabled[i] = true; 111 } else { 112 s->enabled[i] = false; 113 } 114 } 115 } 116 117 static void pca954x_write(Pca954xState *s, uint8_t data) 118 { 119 s->control = data; 120 pca954x_enable_channel(s, data); 121 122 trace_pca954x_write_bytes(data); 123 } 124 125 static int pca954x_write_data(SMBusDevice *d, uint8_t *buf, uint8_t len) 126 { 127 Pca954xState *s = PCA954X(d); 128 129 if (len == 0) { 130 qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); 131 return -1; 132 } 133 134 /* 135 * len should be 1, because they write one byte to enable/disable channels. 136 */ 137 if (len > 1) { 138 qemu_log_mask(LOG_GUEST_ERROR, 139 "%s: extra data after channel selection mask\n", 140 __func__); 141 return -1; 142 } 143 144 pca954x_write(s, buf[0]); 145 return 0; 146 } 147 148 static uint8_t pca954x_read_byte(SMBusDevice *d) 149 { 150 Pca954xState *s = PCA954X(d); 151 uint8_t data = s->control; 152 trace_pca954x_read_data(data); 153 return data; 154 } 155 156 static void pca954x_enter_reset(Object *obj, ResetType type) 157 { 158 Pca954xState *s = PCA954X(obj); 159 /* Reset will disable all channels. */ 160 pca954x_write(s, 0); 161 } 162 163 I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel) 164 { 165 Pca954xClass *pc = PCA954X_GET_CLASS(mux); 166 Pca954xState *pca954x = PCA954X(mux); 167 168 g_assert(channel < pc->nchans); 169 return pca954x->bus[channel]; 170 } 171 172 static void pca9546_class_init(ObjectClass *klass, void *data) 173 { 174 Pca954xClass *s = PCA954X_CLASS(klass); 175 s->nchans = PCA9546_CHANNEL_COUNT; 176 } 177 178 static void pca9548_class_init(ObjectClass *klass, void *data) 179 { 180 Pca954xClass *s = PCA954X_CLASS(klass); 181 s->nchans = PCA9548_CHANNEL_COUNT; 182 } 183 184 static void pca954x_init(Object *obj) 185 { 186 Pca954xState *s = PCA954X(obj); 187 Pca954xClass *c = PCA954X_GET_CLASS(obj); 188 int i; 189 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); 193 194 /* start all channels as disabled. */ 195 s->enabled[i] = false; 196 s->bus[i] = i2c_init_bus(DEVICE(s), bus_name); 197 } 198 } 199 200 static void pca954x_class_init(ObjectClass *klass, void *data) 201 { 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); 206 207 sc->match_and_add = pca954x_match; 208 209 rc->phases.enter = pca954x_enter_reset; 210 211 dc->desc = "Pca954x i2c-mux"; 212 213 k->write_data = pca954x_write_data; 214 k->receive_byte = pca954x_read_byte; 215 } 216 217 static const TypeInfo pca954x_info[] = { 218 { 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, 225 .abstract = true, 226 }, 227 { 228 .name = TYPE_PCA9546, 229 .parent = TYPE_PCA954X, 230 .class_init = pca9546_class_init, 231 }, 232 { 233 .name = TYPE_PCA9548, 234 .parent = TYPE_PCA954X, 235 .class_init = pca9548_class_init, 236 }, 237 }; 238 239 DEFINE_TYPES(pca954x_info) 240