1 /*
2 * PCA9554 I/O port
3 *
4 * Copyright (c) 2023, IBM Corporation.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "qemu/log.h"
11 #include "qemu/module.h"
12 #include "qemu/bitops.h"
13 #include "hw/qdev-properties.h"
14 #include "hw/gpio/pca9554.h"
15 #include "hw/gpio/pca9554_regs.h"
16 #include "hw/irq.h"
17 #include "migration/vmstate.h"
18 #include "qapi/error.h"
19 #include "qapi/visitor.h"
20 #include "trace.h"
21 #include "qom/object.h"
22
23 struct PCA9554Class {
24 /*< private >*/
25 I2CSlaveClass parent_class;
26 /*< public >*/
27 };
28 typedef struct PCA9554Class PCA9554Class;
29
30 DECLARE_CLASS_CHECKERS(PCA9554Class, PCA9554,
31 TYPE_PCA9554)
32
33 #define PCA9554_PIN_LOW 0x0
34 #define PCA9554_PIN_HIZ 0x1
35
36 static const char *pin_state[] = {"low", "high"};
37
pca9554_update_pin_input(PCA9554State * s)38 static void pca9554_update_pin_input(PCA9554State *s)
39 {
40 int i;
41 uint8_t config = s->regs[PCA9554_CONFIG];
42 uint8_t output = s->regs[PCA9554_OUTPUT];
43 uint8_t internal_state = config | output;
44
45 for (i = 0; i < PCA9554_PIN_COUNT; i++) {
46 uint8_t bit_mask = 1 << i;
47 uint8_t internal_pin_state = (internal_state >> i) & 0x1;
48 uint8_t old_value = s->regs[PCA9554_INPUT] & bit_mask;
49 uint8_t new_value;
50
51 switch (internal_pin_state) {
52 case PCA9554_PIN_LOW:
53 s->regs[PCA9554_INPUT] &= ~bit_mask;
54 break;
55 case PCA9554_PIN_HIZ:
56 /*
57 * pullup sets it to a logical 1 unless
58 * external device drives it low.
59 */
60 if (s->ext_state[i] == PCA9554_PIN_LOW) {
61 s->regs[PCA9554_INPUT] &= ~bit_mask;
62 } else {
63 s->regs[PCA9554_INPUT] |= bit_mask;
64 }
65 break;
66 default:
67 break;
68 }
69
70 /* update irq state only if pin state changed */
71 new_value = s->regs[PCA9554_INPUT] & bit_mask;
72 if (new_value != old_value) {
73 if (new_value) {
74 /* changed from 0 to 1 */
75 qemu_set_irq(s->gpio_out[i], 1);
76 } else {
77 /* changed from 1 to 0 */
78 qemu_set_irq(s->gpio_out[i], 0);
79 }
80 }
81 }
82 }
83
pca9554_read(PCA9554State * s,uint8_t reg)84 static uint8_t pca9554_read(PCA9554State *s, uint8_t reg)
85 {
86 switch (reg) {
87 case PCA9554_INPUT:
88 return s->regs[PCA9554_INPUT] ^ s->regs[PCA9554_POLARITY];
89 case PCA9554_OUTPUT:
90 case PCA9554_POLARITY:
91 case PCA9554_CONFIG:
92 return s->regs[reg];
93 default:
94 qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected read to register %d\n",
95 __func__, reg);
96 return 0xFF;
97 }
98 }
99
pca9554_write(PCA9554State * s,uint8_t reg,uint8_t data)100 static void pca9554_write(PCA9554State *s, uint8_t reg, uint8_t data)
101 {
102 switch (reg) {
103 case PCA9554_OUTPUT:
104 case PCA9554_CONFIG:
105 s->regs[reg] = data;
106 pca9554_update_pin_input(s);
107 break;
108 case PCA9554_POLARITY:
109 s->regs[reg] = data;
110 break;
111 case PCA9554_INPUT:
112 default:
113 qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected write to register %d\n",
114 __func__, reg);
115 }
116 }
117
pca9554_recv(I2CSlave * i2c)118 static uint8_t pca9554_recv(I2CSlave *i2c)
119 {
120 PCA9554State *s = PCA9554(i2c);
121
122 return pca9554_read(s, s->pointer & 0x3);
123 }
124
pca9554_send(I2CSlave * i2c,uint8_t data)125 static int pca9554_send(I2CSlave *i2c, uint8_t data)
126 {
127 PCA9554State *s = PCA9554(i2c);
128
129 /* First byte sent by is the register address */
130 if (s->len == 0) {
131 s->pointer = data;
132 s->len++;
133 } else {
134 pca9554_write(s, s->pointer & 0x3, data);
135 }
136
137 return 0;
138 }
139
pca9554_event(I2CSlave * i2c,enum i2c_event event)140 static int pca9554_event(I2CSlave *i2c, enum i2c_event event)
141 {
142 PCA9554State *s = PCA9554(i2c);
143
144 s->len = 0;
145 return 0;
146 }
147
pca9554_get_pin(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)148 static void pca9554_get_pin(Object *obj, Visitor *v, const char *name,
149 void *opaque, Error **errp)
150 {
151 PCA9554State *s = PCA9554(obj);
152 int pin, rc;
153 uint8_t state;
154
155 rc = sscanf(name, "pin%2d", &pin);
156 if (rc != 1) {
157 error_setg(errp, "%s: error reading %s", __func__, name);
158 return;
159 }
160 if (pin < 0 || pin >= PCA9554_PIN_COUNT) {
161 error_setg(errp, "%s invalid pin %s", __func__, name);
162 return;
163 }
164
165 state = pca9554_read(s, PCA9554_CONFIG);
166 state |= pca9554_read(s, PCA9554_OUTPUT);
167 state = (state >> pin) & 0x1;
168 visit_type_str(v, name, (char **)&pin_state[state], errp);
169 }
170
pca9554_set_pin(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)171 static void pca9554_set_pin(Object *obj, Visitor *v, const char *name,
172 void *opaque, Error **errp)
173 {
174 PCA9554State *s = PCA9554(obj);
175 int pin, rc, val;
176 uint8_t state, mask;
177 char *state_str;
178
179 if (!visit_type_str(v, name, &state_str, errp)) {
180 return;
181 }
182 rc = sscanf(name, "pin%2d", &pin);
183 if (rc != 1) {
184 error_setg(errp, "%s: error reading %s", __func__, name);
185 return;
186 }
187 if (pin < 0 || pin >= PCA9554_PIN_COUNT) {
188 error_setg(errp, "%s invalid pin %s", __func__, name);
189 return;
190 }
191
192 for (state = 0; state < ARRAY_SIZE(pin_state); state++) {
193 if (!strcmp(state_str, pin_state[state])) {
194 break;
195 }
196 }
197 if (state >= ARRAY_SIZE(pin_state)) {
198 error_setg(errp, "%s invalid pin state %s", __func__, state_str);
199 return;
200 }
201
202 /* First, modify the output register bit */
203 val = pca9554_read(s, PCA9554_OUTPUT);
204 mask = 0x1 << pin;
205 if (state == PCA9554_PIN_LOW) {
206 val &= ~(mask);
207 } else {
208 val |= mask;
209 }
210 pca9554_write(s, PCA9554_OUTPUT, val);
211
212 /* Then, clear the config register bit for output mode */
213 val = pca9554_read(s, PCA9554_CONFIG);
214 val &= ~mask;
215 pca9554_write(s, PCA9554_CONFIG, val);
216 }
217
218 static const VMStateDescription pca9554_vmstate = {
219 .name = "PCA9554",
220 .version_id = 0,
221 .minimum_version_id = 0,
222 .fields = (VMStateField[]) {
223 VMSTATE_UINT8(len, PCA9554State),
224 VMSTATE_UINT8(pointer, PCA9554State),
225 VMSTATE_UINT8_ARRAY(regs, PCA9554State, PCA9554_NR_REGS),
226 VMSTATE_UINT8_ARRAY(ext_state, PCA9554State, PCA9554_PIN_COUNT),
227 VMSTATE_I2C_SLAVE(i2c, PCA9554State),
228 VMSTATE_END_OF_LIST()
229 }
230 };
231
pca9554_reset(DeviceState * dev)232 static void pca9554_reset(DeviceState *dev)
233 {
234 PCA9554State *s = PCA9554(dev);
235
236 s->regs[PCA9554_INPUT] = 0xFF;
237 s->regs[PCA9554_OUTPUT] = 0xFF;
238 s->regs[PCA9554_POLARITY] = 0x0; /* No pins are inverted */
239 s->regs[PCA9554_CONFIG] = 0xFF; /* All pins are inputs */
240
241 memset(s->ext_state, PCA9554_PIN_HIZ, PCA9554_PIN_COUNT);
242 pca9554_update_pin_input(s);
243
244 s->pointer = 0x0;
245 s->len = 0;
246 }
247
pca9554_initfn(Object * obj)248 static void pca9554_initfn(Object *obj)
249 {
250 int pin;
251
252 for (pin = 0; pin < PCA9554_PIN_COUNT; pin++) {
253 char *name;
254
255 name = g_strdup_printf("pin%d", pin);
256 object_property_add(obj, name, "bool", pca9554_get_pin, pca9554_set_pin,
257 NULL, NULL);
258 g_free(name);
259 }
260 }
261
pca9554_set_ext_state(PCA9554State * s,int pin,int level)262 static void pca9554_set_ext_state(PCA9554State *s, int pin, int level)
263 {
264 if (s->ext_state[pin] != level) {
265 s->ext_state[pin] = level;
266 pca9554_update_pin_input(s);
267 }
268 }
269
pca9554_gpio_in_handler(void * opaque,int pin,int level)270 static void pca9554_gpio_in_handler(void *opaque, int pin, int level)
271 {
272
273 PCA9554State *s = PCA9554(opaque);
274
275 assert((pin >= 0) && (pin < PCA9554_PIN_COUNT));
276 pca9554_set_ext_state(s, pin, level);
277 }
278
pca9554_realize(DeviceState * dev,Error ** errp)279 static void pca9554_realize(DeviceState *dev, Error **errp)
280 {
281 PCA9554State *s = PCA9554(dev);
282
283 if (!s->description) {
284 s->description = g_strdup("pca9554");
285 }
286
287 qdev_init_gpio_out(dev, s->gpio_out, PCA9554_PIN_COUNT);
288 qdev_init_gpio_in(dev, pca9554_gpio_in_handler, PCA9554_PIN_COUNT);
289 }
290
291 static const Property pca9554_properties[] = {
292 DEFINE_PROP_STRING("description", PCA9554State, description),
293 };
294
pca9554_class_init(ObjectClass * klass,const void * data)295 static void pca9554_class_init(ObjectClass *klass, const void *data)
296 {
297 DeviceClass *dc = DEVICE_CLASS(klass);
298 I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
299
300 k->event = pca9554_event;
301 k->recv = pca9554_recv;
302 k->send = pca9554_send;
303 dc->realize = pca9554_realize;
304 device_class_set_legacy_reset(dc, pca9554_reset);
305 dc->vmsd = &pca9554_vmstate;
306 device_class_set_props(dc, pca9554_properties);
307 }
308
309 static const TypeInfo pca9554_info = {
310 .name = TYPE_PCA9554,
311 .parent = TYPE_I2C_SLAVE,
312 .instance_init = pca9554_initfn,
313 .instance_size = sizeof(PCA9554State),
314 .class_init = pca9554_class_init,
315 .class_size = sizeof(PCA9554Class),
316 .abstract = false,
317 };
318
pca9554_register_types(void)319 static void pca9554_register_types(void)
320 {
321 type_register_static(&pca9554_info);
322 }
323
324 type_init(pca9554_register_types)
325