xref: /qemu/hw/gpio/pca9552.c (revision 736132e455eea08e37fe21b4140b8088f2c0956b)
15141d415SCédric Le Goater /*
25141d415SCédric Le Goater  * PCA9552 I2C LED blinker
35141d415SCédric Le Goater  *
45141d415SCédric Le Goater  *     https://www.nxp.com/docs/en/application-note/AN264.pdf
55141d415SCédric Le Goater  *
65141d415SCédric Le Goater  * Copyright (c) 2017-2018, IBM Corporation.
7*736132e4SPhilippe Mathieu-Daudé  * Copyright (c) 2020 Philippe Mathieu-Daudé
85141d415SCédric Le Goater  *
95141d415SCédric Le Goater  * This work is licensed under the terms of the GNU GPL, version 2 or
105141d415SCédric Le Goater  * later. See the COPYING file in the top-level directory.
115141d415SCédric Le Goater  */
125141d415SCédric Le Goater 
135141d415SCédric Le Goater #include "qemu/osdep.h"
145141d415SCédric Le Goater #include "qemu/log.h"
150b8fa32fSMarkus Armbruster #include "qemu/module.h"
165141d415SCédric Le Goater #include "hw/misc/pca9552.h"
175141d415SCédric Le Goater #include "hw/misc/pca9552_regs.h"
18d6454270SMarkus Armbruster #include "migration/vmstate.h"
19a90d8f84SJoel Stanley #include "qapi/error.h"
20a90d8f84SJoel Stanley #include "qapi/visitor.h"
215141d415SCédric Le Goater 
22*736132e4SPhilippe Mathieu-Daudé typedef struct PCA955xClass {
23*736132e4SPhilippe Mathieu-Daudé     /*< private >*/
24*736132e4SPhilippe Mathieu-Daudé     I2CSlaveClass parent_class;
25*736132e4SPhilippe Mathieu-Daudé     /*< public >*/
26*736132e4SPhilippe Mathieu-Daudé 
27*736132e4SPhilippe Mathieu-Daudé     uint8_t pin_count;
28*736132e4SPhilippe Mathieu-Daudé     uint8_t max_reg;
29*736132e4SPhilippe Mathieu-Daudé } PCA955xClass;
30*736132e4SPhilippe Mathieu-Daudé 
31*736132e4SPhilippe Mathieu-Daudé #define PCA955X_CLASS(klass) \
32*736132e4SPhilippe Mathieu-Daudé     OBJECT_CLASS_CHECK(PCA955xClass, (klass), TYPE_PCA955X)
33*736132e4SPhilippe Mathieu-Daudé #define PCA955X_GET_CLASS(obj) \
34*736132e4SPhilippe Mathieu-Daudé     OBJECT_GET_CLASS(PCA955xClass, (obj), TYPE_PCA955X)
35*736132e4SPhilippe Mathieu-Daudé 
365141d415SCédric Le Goater #define PCA9552_LED_ON   0x0
375141d415SCédric Le Goater #define PCA9552_LED_OFF  0x1
385141d415SCédric Le Goater #define PCA9552_LED_PWM0 0x2
395141d415SCédric Le Goater #define PCA9552_LED_PWM1 0x3
405141d415SCédric Le Goater 
41a90d8f84SJoel Stanley static const char *led_state[] = {"on", "off", "pwm0", "pwm1"};
42a90d8f84SJoel Stanley 
43ec17228aSPhilippe Mathieu-Daudé static uint8_t pca955x_pin_get_config(PCA955xState *s, int pin)
445141d415SCédric Le Goater {
455141d415SCédric Le Goater     uint8_t reg   = PCA9552_LS0 + (pin / 4);
465141d415SCédric Le Goater     uint8_t shift = (pin % 4) << 1;
475141d415SCédric Le Goater 
485141d415SCédric Le Goater     return extract32(s->regs[reg], shift, 2);
495141d415SCédric Le Goater }
505141d415SCédric Le Goater 
51ec17228aSPhilippe Mathieu-Daudé static void pca955x_update_pin_input(PCA955xState *s)
525141d415SCédric Le Goater {
53*736132e4SPhilippe Mathieu-Daudé     PCA955xClass *k = PCA955X_GET_CLASS(s);
545141d415SCédric Le Goater     int i;
555141d415SCédric Le Goater 
56*736132e4SPhilippe Mathieu-Daudé     for (i = 0; i < k->pin_count; i++) {
575141d415SCédric Le Goater         uint8_t input_reg = PCA9552_INPUT0 + (i / 8);
585141d415SCédric Le Goater         uint8_t input_shift = (i % 8);
59ec17228aSPhilippe Mathieu-Daudé         uint8_t config = pca955x_pin_get_config(s, i);
605141d415SCédric Le Goater 
615141d415SCédric Le Goater         switch (config) {
625141d415SCédric Le Goater         case PCA9552_LED_ON:
635141d415SCédric Le Goater             s->regs[input_reg] |= 1 << input_shift;
645141d415SCédric Le Goater             break;
655141d415SCédric Le Goater         case PCA9552_LED_OFF:
665141d415SCédric Le Goater             s->regs[input_reg] &= ~(1 << input_shift);
675141d415SCédric Le Goater             break;
685141d415SCédric Le Goater         case PCA9552_LED_PWM0:
695141d415SCédric Le Goater         case PCA9552_LED_PWM1:
705141d415SCédric Le Goater             /* TODO */
715141d415SCédric Le Goater         default:
725141d415SCédric Le Goater             break;
735141d415SCédric Le Goater         }
745141d415SCédric Le Goater     }
755141d415SCédric Le Goater }
765141d415SCédric Le Goater 
77ec17228aSPhilippe Mathieu-Daudé static uint8_t pca955x_read(PCA955xState *s, uint8_t reg)
785141d415SCédric Le Goater {
795141d415SCédric Le Goater     switch (reg) {
805141d415SCédric Le Goater     case PCA9552_INPUT0:
815141d415SCédric Le Goater     case PCA9552_INPUT1:
825141d415SCédric Le Goater     case PCA9552_PSC0:
835141d415SCédric Le Goater     case PCA9552_PWM0:
845141d415SCédric Le Goater     case PCA9552_PSC1:
855141d415SCédric Le Goater     case PCA9552_PWM1:
865141d415SCédric Le Goater     case PCA9552_LS0:
875141d415SCédric Le Goater     case PCA9552_LS1:
885141d415SCédric Le Goater     case PCA9552_LS2:
895141d415SCédric Le Goater     case PCA9552_LS3:
905141d415SCédric Le Goater         return s->regs[reg];
915141d415SCédric Le Goater     default:
925141d415SCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected read to register %d\n",
935141d415SCédric Le Goater                       __func__, reg);
945141d415SCédric Le Goater         return 0xFF;
955141d415SCédric Le Goater     }
965141d415SCédric Le Goater }
975141d415SCédric Le Goater 
98ec17228aSPhilippe Mathieu-Daudé static void pca955x_write(PCA955xState *s, uint8_t reg, uint8_t data)
995141d415SCédric Le Goater {
1005141d415SCédric Le Goater     switch (reg) {
1015141d415SCédric Le Goater     case PCA9552_PSC0:
1025141d415SCédric Le Goater     case PCA9552_PWM0:
1035141d415SCédric Le Goater     case PCA9552_PSC1:
1045141d415SCédric Le Goater     case PCA9552_PWM1:
1055141d415SCédric Le Goater         s->regs[reg] = data;
1065141d415SCédric Le Goater         break;
1075141d415SCédric Le Goater 
1085141d415SCédric Le Goater     case PCA9552_LS0:
1095141d415SCédric Le Goater     case PCA9552_LS1:
1105141d415SCédric Le Goater     case PCA9552_LS2:
1115141d415SCédric Le Goater     case PCA9552_LS3:
1125141d415SCédric Le Goater         s->regs[reg] = data;
113ec17228aSPhilippe Mathieu-Daudé         pca955x_update_pin_input(s);
1145141d415SCédric Le Goater         break;
1155141d415SCédric Le Goater 
1165141d415SCédric Le Goater     case PCA9552_INPUT0:
1175141d415SCédric Le Goater     case PCA9552_INPUT1:
1185141d415SCédric Le Goater     default:
1195141d415SCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected write to register %d\n",
1205141d415SCédric Le Goater                       __func__, reg);
1215141d415SCédric Le Goater     }
1225141d415SCédric Le Goater }
1235141d415SCédric Le Goater 
1245141d415SCédric Le Goater /*
1255141d415SCédric Le Goater  * When Auto-Increment is on, the register address is incremented
1265141d415SCédric Le Goater  * after each byte is sent to or received by the device. The index
1275141d415SCédric Le Goater  * rollovers to 0 when the maximum register address is reached.
1285141d415SCédric Le Goater  */
129ec17228aSPhilippe Mathieu-Daudé static void pca955x_autoinc(PCA955xState *s)
1305141d415SCédric Le Goater {
131*736132e4SPhilippe Mathieu-Daudé     PCA955xClass *k = PCA955X_GET_CLASS(s);
132*736132e4SPhilippe Mathieu-Daudé 
1335141d415SCédric Le Goater     if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) {
1345141d415SCédric Le Goater         uint8_t reg = s->pointer & 0xf;
1355141d415SCédric Le Goater 
136*736132e4SPhilippe Mathieu-Daudé         reg = (reg + 1) % (k->max_reg + 1);
1375141d415SCédric Le Goater         s->pointer = reg | PCA9552_AUTOINC;
1385141d415SCédric Le Goater     }
1395141d415SCédric Le Goater }
1405141d415SCédric Le Goater 
141ec17228aSPhilippe Mathieu-Daudé static uint8_t pca955x_recv(I2CSlave *i2c)
1425141d415SCédric Le Goater {
143ec17228aSPhilippe Mathieu-Daudé     PCA955xState *s = PCA955X(i2c);
1445141d415SCédric Le Goater     uint8_t ret;
1455141d415SCédric Le Goater 
146ec17228aSPhilippe Mathieu-Daudé     ret = pca955x_read(s, s->pointer & 0xf);
1475141d415SCédric Le Goater 
1485141d415SCédric Le Goater     /*
1495141d415SCédric Le Goater      * From the Specs:
1505141d415SCédric Le Goater      *
1515141d415SCédric Le Goater      *     Important Note: When a Read sequence is initiated and the
1525141d415SCédric Le Goater      *     AI bit is set to Logic Level 1, the Read Sequence MUST
1535141d415SCédric Le Goater      *     start by a register different from 0.
1545141d415SCédric Le Goater      *
1555141d415SCédric Le Goater      * I don't know what should be done in this case, so throw an
1565141d415SCédric Le Goater      * error.
1575141d415SCédric Le Goater      */
1585141d415SCédric Le Goater     if (s->pointer == PCA9552_AUTOINC) {
1595141d415SCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR,
1605141d415SCédric Le Goater                       "%s: Autoincrement read starting with register 0\n",
1615141d415SCédric Le Goater                       __func__);
1625141d415SCédric Le Goater     }
1635141d415SCédric Le Goater 
164ec17228aSPhilippe Mathieu-Daudé     pca955x_autoinc(s);
1655141d415SCédric Le Goater 
1665141d415SCédric Le Goater     return ret;
1675141d415SCédric Le Goater }
1685141d415SCédric Le Goater 
169ec17228aSPhilippe Mathieu-Daudé static int pca955x_send(I2CSlave *i2c, uint8_t data)
1705141d415SCédric Le Goater {
171ec17228aSPhilippe Mathieu-Daudé     PCA955xState *s = PCA955X(i2c);
1725141d415SCédric Le Goater 
1735141d415SCédric Le Goater     /* First byte sent by is the register address */
1745141d415SCédric Le Goater     if (s->len == 0) {
1755141d415SCédric Le Goater         s->pointer = data;
1765141d415SCédric Le Goater         s->len++;
1775141d415SCédric Le Goater     } else {
178ec17228aSPhilippe Mathieu-Daudé         pca955x_write(s, s->pointer & 0xf, data);
1795141d415SCédric Le Goater 
180ec17228aSPhilippe Mathieu-Daudé         pca955x_autoinc(s);
1815141d415SCédric Le Goater     }
1825141d415SCédric Le Goater 
1835141d415SCédric Le Goater     return 0;
1845141d415SCédric Le Goater }
1855141d415SCédric Le Goater 
186ec17228aSPhilippe Mathieu-Daudé static int pca955x_event(I2CSlave *i2c, enum i2c_event event)
1875141d415SCédric Le Goater {
188ec17228aSPhilippe Mathieu-Daudé     PCA955xState *s = PCA955X(i2c);
1895141d415SCédric Le Goater 
1905141d415SCédric Le Goater     s->len = 0;
1915141d415SCédric Le Goater     return 0;
1925141d415SCédric Le Goater }
1935141d415SCédric Le Goater 
194ec17228aSPhilippe Mathieu-Daudé static void pca955x_get_led(Object *obj, Visitor *v, const char *name,
195a90d8f84SJoel Stanley                             void *opaque, Error **errp)
196a90d8f84SJoel Stanley {
197*736132e4SPhilippe Mathieu-Daudé     PCA955xClass *k = PCA955X_GET_CLASS(obj);
198ec17228aSPhilippe Mathieu-Daudé     PCA955xState *s = PCA955X(obj);
199a90d8f84SJoel Stanley     int led, rc, reg;
200a90d8f84SJoel Stanley     uint8_t state;
201a90d8f84SJoel Stanley 
202a90d8f84SJoel Stanley     rc = sscanf(name, "led%2d", &led);
203a90d8f84SJoel Stanley     if (rc != 1) {
204a90d8f84SJoel Stanley         error_setg(errp, "%s: error reading %s", __func__, name);
205a90d8f84SJoel Stanley         return;
206a90d8f84SJoel Stanley     }
207*736132e4SPhilippe Mathieu-Daudé     if (led < 0 || led > k->pin_count) {
208a90d8f84SJoel Stanley         error_setg(errp, "%s invalid led %s", __func__, name);
209a90d8f84SJoel Stanley         return;
210a90d8f84SJoel Stanley     }
211a90d8f84SJoel Stanley     /*
212a90d8f84SJoel Stanley      * Get the LSx register as the qom interface should expose the device
213a90d8f84SJoel Stanley      * state, not the modeled 'input line' behaviour which would come from
214a90d8f84SJoel Stanley      * reading the INPUTx reg
215a90d8f84SJoel Stanley      */
216a90d8f84SJoel Stanley     reg = PCA9552_LS0 + led / 4;
217ec17228aSPhilippe Mathieu-Daudé     state = (pca955x_read(s, reg) >> (led % 8)) & 0x3;
218a90d8f84SJoel Stanley     visit_type_str(v, name, (char **)&led_state[state], errp);
219a90d8f84SJoel Stanley }
220a90d8f84SJoel Stanley 
221a90d8f84SJoel Stanley /*
222a90d8f84SJoel Stanley  * Return an LED selector register value based on an existing one, with
223a90d8f84SJoel Stanley  * the appropriate 2-bit state value set for the given LED number (0-3).
224a90d8f84SJoel Stanley  */
225a90d8f84SJoel Stanley static inline uint8_t pca955x_ledsel(uint8_t oldval, int led_num, int state)
226a90d8f84SJoel Stanley {
227a90d8f84SJoel Stanley         return (oldval & (~(0x3 << (led_num << 1)))) |
228a90d8f84SJoel Stanley                 ((state & 0x3) << (led_num << 1));
229a90d8f84SJoel Stanley }
230a90d8f84SJoel Stanley 
231ec17228aSPhilippe Mathieu-Daudé static void pca955x_set_led(Object *obj, Visitor *v, const char *name,
232a90d8f84SJoel Stanley                             void *opaque, Error **errp)
233a90d8f84SJoel Stanley {
234*736132e4SPhilippe Mathieu-Daudé     PCA955xClass *k = PCA955X_GET_CLASS(obj);
235ec17228aSPhilippe Mathieu-Daudé     PCA955xState *s = PCA955X(obj);
236a90d8f84SJoel Stanley     Error *local_err = NULL;
237a90d8f84SJoel Stanley     int led, rc, reg, val;
238a90d8f84SJoel Stanley     uint8_t state;
239a90d8f84SJoel Stanley     char *state_str;
240a90d8f84SJoel Stanley 
241a90d8f84SJoel Stanley     visit_type_str(v, name, &state_str, &local_err);
242a90d8f84SJoel Stanley     if (local_err) {
243a90d8f84SJoel Stanley         error_propagate(errp, local_err);
244a90d8f84SJoel Stanley         return;
245a90d8f84SJoel Stanley     }
246a90d8f84SJoel Stanley     rc = sscanf(name, "led%2d", &led);
247a90d8f84SJoel Stanley     if (rc != 1) {
248a90d8f84SJoel Stanley         error_setg(errp, "%s: error reading %s", __func__, name);
249a90d8f84SJoel Stanley         return;
250a90d8f84SJoel Stanley     }
251*736132e4SPhilippe Mathieu-Daudé     if (led < 0 || led > k->pin_count) {
252a90d8f84SJoel Stanley         error_setg(errp, "%s invalid led %s", __func__, name);
253a90d8f84SJoel Stanley         return;
254a90d8f84SJoel Stanley     }
255a90d8f84SJoel Stanley 
256a90d8f84SJoel Stanley     for (state = 0; state < ARRAY_SIZE(led_state); state++) {
257a90d8f84SJoel Stanley         if (!strcmp(state_str, led_state[state])) {
258a90d8f84SJoel Stanley             break;
259a90d8f84SJoel Stanley         }
260a90d8f84SJoel Stanley     }
261a90d8f84SJoel Stanley     if (state >= ARRAY_SIZE(led_state)) {
262a90d8f84SJoel Stanley         error_setg(errp, "%s invalid led state %s", __func__, state_str);
263a90d8f84SJoel Stanley         return;
264a90d8f84SJoel Stanley     }
265a90d8f84SJoel Stanley 
266a90d8f84SJoel Stanley     reg = PCA9552_LS0 + led / 4;
267ec17228aSPhilippe Mathieu-Daudé     val = pca955x_read(s, reg);
268a90d8f84SJoel Stanley     val = pca955x_ledsel(val, led % 4, state);
269ec17228aSPhilippe Mathieu-Daudé     pca955x_write(s, reg, val);
270a90d8f84SJoel Stanley }
271a90d8f84SJoel Stanley 
2725141d415SCédric Le Goater static const VMStateDescription pca9552_vmstate = {
2735141d415SCédric Le Goater     .name = "PCA9552",
2745141d415SCédric Le Goater     .version_id = 0,
2755141d415SCédric Le Goater     .minimum_version_id = 0,
2765141d415SCédric Le Goater     .fields = (VMStateField[]) {
277ec17228aSPhilippe Mathieu-Daudé         VMSTATE_UINT8(len, PCA955xState),
278ec17228aSPhilippe Mathieu-Daudé         VMSTATE_UINT8(pointer, PCA955xState),
279ec17228aSPhilippe Mathieu-Daudé         VMSTATE_UINT8_ARRAY(regs, PCA955xState, PCA955X_NR_REGS),
280ec17228aSPhilippe Mathieu-Daudé         VMSTATE_I2C_SLAVE(i2c, PCA955xState),
2815141d415SCédric Le Goater         VMSTATE_END_OF_LIST()
2825141d415SCédric Le Goater     }
2835141d415SCédric Le Goater };
2845141d415SCédric Le Goater 
2855141d415SCédric Le Goater static void pca9552_reset(DeviceState *dev)
2865141d415SCédric Le Goater {
287ec17228aSPhilippe Mathieu-Daudé     PCA955xState *s = PCA955X(dev);
2885141d415SCédric Le Goater 
2895141d415SCédric Le Goater     s->regs[PCA9552_PSC0] = 0xFF;
2905141d415SCédric Le Goater     s->regs[PCA9552_PWM0] = 0x80;
2915141d415SCédric Le Goater     s->regs[PCA9552_PSC1] = 0xFF;
2925141d415SCédric Le Goater     s->regs[PCA9552_PWM1] = 0x80;
2935141d415SCédric Le Goater     s->regs[PCA9552_LS0] = 0x55; /* all OFF */
2945141d415SCédric Le Goater     s->regs[PCA9552_LS1] = 0x55;
2955141d415SCédric Le Goater     s->regs[PCA9552_LS2] = 0x55;
2965141d415SCédric Le Goater     s->regs[PCA9552_LS3] = 0x55;
2975141d415SCédric Le Goater 
298ec17228aSPhilippe Mathieu-Daudé     pca955x_update_pin_input(s);
2995141d415SCédric Le Goater 
3005141d415SCédric Le Goater     s->pointer = 0xFF;
3015141d415SCédric Le Goater     s->len = 0;
3025141d415SCédric Le Goater }
3035141d415SCédric Le Goater 
304ec17228aSPhilippe Mathieu-Daudé static void pca955x_initfn(Object *obj)
3055141d415SCédric Le Goater {
306*736132e4SPhilippe Mathieu-Daudé     PCA955xClass *k = PCA955X_GET_CLASS(obj);
307a90d8f84SJoel Stanley     int led;
3085141d415SCédric Le Goater 
309*736132e4SPhilippe Mathieu-Daudé     assert(k->pin_count <= PCA955X_PIN_COUNT_MAX);
310*736132e4SPhilippe Mathieu-Daudé     for (led = 0; led < k->pin_count; led++) {
311a90d8f84SJoel Stanley         char *name;
312a90d8f84SJoel Stanley 
313a90d8f84SJoel Stanley         name = g_strdup_printf("led%d", led);
314ec17228aSPhilippe Mathieu-Daudé         object_property_add(obj, name, "bool", pca955x_get_led, pca955x_set_led,
315d2623129SMarkus Armbruster                             NULL, NULL);
316a90d8f84SJoel Stanley         g_free(name);
317a90d8f84SJoel Stanley     }
3185141d415SCédric Le Goater }
3195141d415SCédric Le Goater 
320*736132e4SPhilippe Mathieu-Daudé static void pca955x_class_init(ObjectClass *klass, void *data)
3215141d415SCédric Le Goater {
3225141d415SCédric Le Goater     I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
3235141d415SCédric Le Goater 
324ec17228aSPhilippe Mathieu-Daudé     k->event = pca955x_event;
325ec17228aSPhilippe Mathieu-Daudé     k->recv = pca955x_recv;
326ec17228aSPhilippe Mathieu-Daudé     k->send = pca955x_send;
327*736132e4SPhilippe Mathieu-Daudé }
328*736132e4SPhilippe Mathieu-Daudé 
329*736132e4SPhilippe Mathieu-Daudé static const TypeInfo pca955x_info = {
330*736132e4SPhilippe Mathieu-Daudé     .name          = TYPE_PCA955X,
331*736132e4SPhilippe Mathieu-Daudé     .parent        = TYPE_I2C_SLAVE,
332*736132e4SPhilippe Mathieu-Daudé     .instance_init = pca955x_initfn,
333*736132e4SPhilippe Mathieu-Daudé     .instance_size = sizeof(PCA955xState),
334*736132e4SPhilippe Mathieu-Daudé     .class_init    = pca955x_class_init,
335*736132e4SPhilippe Mathieu-Daudé     .abstract      = true,
336*736132e4SPhilippe Mathieu-Daudé };
337*736132e4SPhilippe Mathieu-Daudé 
338*736132e4SPhilippe Mathieu-Daudé static void pca9552_class_init(ObjectClass *oc, void *data)
339*736132e4SPhilippe Mathieu-Daudé {
340*736132e4SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(oc);
341*736132e4SPhilippe Mathieu-Daudé     PCA955xClass *pc = PCA955X_CLASS(oc);
342*736132e4SPhilippe Mathieu-Daudé 
3435141d415SCédric Le Goater     dc->reset = pca9552_reset;
3445141d415SCédric Le Goater     dc->vmsd = &pca9552_vmstate;
345*736132e4SPhilippe Mathieu-Daudé     pc->max_reg = PCA9552_LS3;
346*736132e4SPhilippe Mathieu-Daudé     pc->pin_count = 16;
3475141d415SCédric Le Goater }
3485141d415SCédric Le Goater 
3495141d415SCédric Le Goater static const TypeInfo pca9552_info = {
3505141d415SCédric Le Goater     .name          = TYPE_PCA9552,
351*736132e4SPhilippe Mathieu-Daudé     .parent        = TYPE_PCA955X,
3525141d415SCédric Le Goater     .class_init    = pca9552_class_init,
3535141d415SCédric Le Goater };
3545141d415SCédric Le Goater 
355ec17228aSPhilippe Mathieu-Daudé static void pca955x_register_types(void)
3565141d415SCédric Le Goater {
357*736132e4SPhilippe Mathieu-Daudé     type_register_static(&pca955x_info);
3585141d415SCédric Le Goater     type_register_static(&pca9552_info);
3595141d415SCédric Le Goater }
3605141d415SCédric Le Goater 
361ec17228aSPhilippe Mathieu-Daudé type_init(pca955x_register_types)
362