xref: /qemu/hw/gpio/bcm2835_gpio.c (revision 64552b6be4758d3a774f7787b294543ccebd5358)
1d72fc9dcSClement Deschamps /*
2d72fc9dcSClement Deschamps  * Raspberry Pi (BCM2835) GPIO Controller
3d72fc9dcSClement Deschamps  *
4d72fc9dcSClement Deschamps  * Copyright (c) 2017 Antfield SAS
5d72fc9dcSClement Deschamps  *
6d72fc9dcSClement Deschamps  * Authors:
7d72fc9dcSClement Deschamps  *  Clement Deschamps <clement.deschamps@antfield.fr>
8d72fc9dcSClement Deschamps  *  Luc Michel <luc.michel@antfield.fr>
9d72fc9dcSClement Deschamps  *
10d72fc9dcSClement Deschamps  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11d72fc9dcSClement Deschamps  * See the COPYING file in the top-level directory.
12d72fc9dcSClement Deschamps  */
13d72fc9dcSClement Deschamps 
14d72fc9dcSClement Deschamps #include "qemu/osdep.h"
15d72fc9dcSClement Deschamps #include "qemu/log.h"
160b8fa32fSMarkus Armbruster #include "qemu/module.h"
17d72fc9dcSClement Deschamps #include "qemu/timer.h"
18d72fc9dcSClement Deschamps #include "qapi/error.h"
19d72fc9dcSClement Deschamps #include "hw/sysbus.h"
20d72fc9dcSClement Deschamps #include "hw/sd/sd.h"
21d72fc9dcSClement Deschamps #include "hw/gpio/bcm2835_gpio.h"
22*64552b6bSMarkus Armbruster #include "hw/irq.h"
23d72fc9dcSClement Deschamps 
24d72fc9dcSClement Deschamps #define GPFSEL0   0x00
25d72fc9dcSClement Deschamps #define GPFSEL1   0x04
26d72fc9dcSClement Deschamps #define GPFSEL2   0x08
27d72fc9dcSClement Deschamps #define GPFSEL3   0x0C
28d72fc9dcSClement Deschamps #define GPFSEL4   0x10
29d72fc9dcSClement Deschamps #define GPFSEL5   0x14
30d72fc9dcSClement Deschamps #define GPSET0    0x1C
31d72fc9dcSClement Deschamps #define GPSET1    0x20
32d72fc9dcSClement Deschamps #define GPCLR0    0x28
33d72fc9dcSClement Deschamps #define GPCLR1    0x2C
34d72fc9dcSClement Deschamps #define GPLEV0    0x34
35d72fc9dcSClement Deschamps #define GPLEV1    0x38
36d72fc9dcSClement Deschamps #define GPEDS0    0x40
37d72fc9dcSClement Deschamps #define GPEDS1    0x44
38d72fc9dcSClement Deschamps #define GPREN0    0x4C
39d72fc9dcSClement Deschamps #define GPREN1    0x50
40d72fc9dcSClement Deschamps #define GPFEN0    0x58
41d72fc9dcSClement Deschamps #define GPFEN1    0x5C
42d72fc9dcSClement Deschamps #define GPHEN0    0x64
43d72fc9dcSClement Deschamps #define GPHEN1    0x68
44d72fc9dcSClement Deschamps #define GPLEN0    0x70
45d72fc9dcSClement Deschamps #define GPLEN1    0x74
46d72fc9dcSClement Deschamps #define GPAREN0   0x7C
47d72fc9dcSClement Deschamps #define GPAREN1   0x80
48d72fc9dcSClement Deschamps #define GPAFEN0   0x88
49d72fc9dcSClement Deschamps #define GPAFEN1   0x8C
50d72fc9dcSClement Deschamps #define GPPUD     0x94
51d72fc9dcSClement Deschamps #define GPPUDCLK0 0x98
52d72fc9dcSClement Deschamps #define GPPUDCLK1 0x9C
53d72fc9dcSClement Deschamps 
54d72fc9dcSClement Deschamps static uint32_t gpfsel_get(BCM2835GpioState *s, uint8_t reg)
55d72fc9dcSClement Deschamps {
56d72fc9dcSClement Deschamps     int i;
57d72fc9dcSClement Deschamps     uint32_t value = 0;
58d72fc9dcSClement Deschamps     for (i = 0; i < 10; i++) {
59d72fc9dcSClement Deschamps         uint32_t index = 10 * reg + i;
60d72fc9dcSClement Deschamps         if (index < sizeof(s->fsel)) {
61d72fc9dcSClement Deschamps             value |= (s->fsel[index] & 0x7) << (3 * i);
62d72fc9dcSClement Deschamps         }
63d72fc9dcSClement Deschamps     }
64d72fc9dcSClement Deschamps     return value;
65d72fc9dcSClement Deschamps }
66d72fc9dcSClement Deschamps 
67d72fc9dcSClement Deschamps static void gpfsel_set(BCM2835GpioState *s, uint8_t reg, uint32_t value)
68d72fc9dcSClement Deschamps {
69d72fc9dcSClement Deschamps     int i;
70d72fc9dcSClement Deschamps     for (i = 0; i < 10; i++) {
71d72fc9dcSClement Deschamps         uint32_t index = 10 * reg + i;
72d72fc9dcSClement Deschamps         if (index < sizeof(s->fsel)) {
73d72fc9dcSClement Deschamps             int fsel = (value >> (3 * i)) & 0x7;
74d72fc9dcSClement Deschamps             s->fsel[index] = fsel;
75d72fc9dcSClement Deschamps         }
76d72fc9dcSClement Deschamps     }
77d72fc9dcSClement Deschamps 
78d72fc9dcSClement Deschamps     /* SD controller selection (48-53) */
79d72fc9dcSClement Deschamps     if (s->sd_fsel != 0
80d72fc9dcSClement Deschamps             && (s->fsel[48] == 0) /* SD_CLK_R */
81d72fc9dcSClement Deschamps             && (s->fsel[49] == 0) /* SD_CMD_R */
82d72fc9dcSClement Deschamps             && (s->fsel[50] == 0) /* SD_DATA0_R */
83d72fc9dcSClement Deschamps             && (s->fsel[51] == 0) /* SD_DATA1_R */
84d72fc9dcSClement Deschamps             && (s->fsel[52] == 0) /* SD_DATA2_R */
85d72fc9dcSClement Deschamps             && (s->fsel[53] == 0) /* SD_DATA3_R */
86d72fc9dcSClement Deschamps             ) {
87d72fc9dcSClement Deschamps         /* SDHCI controller selected */
88d72fc9dcSClement Deschamps         sdbus_reparent_card(s->sdbus_sdhost, s->sdbus_sdhci);
89d72fc9dcSClement Deschamps         s->sd_fsel = 0;
90d72fc9dcSClement Deschamps     } else if (s->sd_fsel != 4
91d72fc9dcSClement Deschamps             && (s->fsel[48] == 4) /* SD_CLK_R */
92d72fc9dcSClement Deschamps             && (s->fsel[49] == 4) /* SD_CMD_R */
93d72fc9dcSClement Deschamps             && (s->fsel[50] == 4) /* SD_DATA0_R */
94d72fc9dcSClement Deschamps             && (s->fsel[51] == 4) /* SD_DATA1_R */
95d72fc9dcSClement Deschamps             && (s->fsel[52] == 4) /* SD_DATA2_R */
96d72fc9dcSClement Deschamps             && (s->fsel[53] == 4) /* SD_DATA3_R */
97d72fc9dcSClement Deschamps             ) {
98d72fc9dcSClement Deschamps         /* SDHost controller selected */
99d72fc9dcSClement Deschamps         sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost);
100d72fc9dcSClement Deschamps         s->sd_fsel = 4;
101d72fc9dcSClement Deschamps     }
102d72fc9dcSClement Deschamps }
103d72fc9dcSClement Deschamps 
104d72fc9dcSClement Deschamps static int gpfsel_is_out(BCM2835GpioState *s, int index)
105d72fc9dcSClement Deschamps {
106d72fc9dcSClement Deschamps     if (index >= 0 && index < 54) {
107d72fc9dcSClement Deschamps         return s->fsel[index] == 1;
108d72fc9dcSClement Deschamps     }
109d72fc9dcSClement Deschamps     return 0;
110d72fc9dcSClement Deschamps }
111d72fc9dcSClement Deschamps 
112d72fc9dcSClement Deschamps static void gpset(BCM2835GpioState *s,
113d72fc9dcSClement Deschamps         uint32_t val, uint8_t start, uint8_t count, uint32_t *lev)
114d72fc9dcSClement Deschamps {
115d72fc9dcSClement Deschamps     uint32_t changes = val & ~*lev;
116d72fc9dcSClement Deschamps     uint32_t cur = 1;
117d72fc9dcSClement Deschamps 
118d72fc9dcSClement Deschamps     int i;
119d72fc9dcSClement Deschamps     for (i = 0; i < count; i++) {
120d72fc9dcSClement Deschamps         if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
121d72fc9dcSClement Deschamps             qemu_set_irq(s->out[start + i], 1);
122d72fc9dcSClement Deschamps         }
123d72fc9dcSClement Deschamps         cur <<= 1;
124d72fc9dcSClement Deschamps     }
125d72fc9dcSClement Deschamps 
126d72fc9dcSClement Deschamps     *lev |= val;
127d72fc9dcSClement Deschamps }
128d72fc9dcSClement Deschamps 
129d72fc9dcSClement Deschamps static void gpclr(BCM2835GpioState *s,
130d72fc9dcSClement Deschamps         uint32_t val, uint8_t start, uint8_t count, uint32_t *lev)
131d72fc9dcSClement Deschamps {
132d72fc9dcSClement Deschamps     uint32_t changes = val & *lev;
133d72fc9dcSClement Deschamps     uint32_t cur = 1;
134d72fc9dcSClement Deschamps 
135d72fc9dcSClement Deschamps     int i;
136d72fc9dcSClement Deschamps     for (i = 0; i < count; i++) {
137d72fc9dcSClement Deschamps         if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
138d72fc9dcSClement Deschamps             qemu_set_irq(s->out[start + i], 0);
139d72fc9dcSClement Deschamps         }
140d72fc9dcSClement Deschamps         cur <<= 1;
141d72fc9dcSClement Deschamps     }
142d72fc9dcSClement Deschamps 
143d72fc9dcSClement Deschamps     *lev &= ~val;
144d72fc9dcSClement Deschamps }
145d72fc9dcSClement Deschamps 
146d72fc9dcSClement Deschamps static uint64_t bcm2835_gpio_read(void *opaque, hwaddr offset,
147d72fc9dcSClement Deschamps         unsigned size)
148d72fc9dcSClement Deschamps {
149d72fc9dcSClement Deschamps     BCM2835GpioState *s = (BCM2835GpioState *)opaque;
150d72fc9dcSClement Deschamps 
151d72fc9dcSClement Deschamps     switch (offset) {
152d72fc9dcSClement Deschamps     case GPFSEL0:
153d72fc9dcSClement Deschamps     case GPFSEL1:
154d72fc9dcSClement Deschamps     case GPFSEL2:
155d72fc9dcSClement Deschamps     case GPFSEL3:
156d72fc9dcSClement Deschamps     case GPFSEL4:
157d72fc9dcSClement Deschamps     case GPFSEL5:
158d72fc9dcSClement Deschamps         return gpfsel_get(s, offset / 4);
159d72fc9dcSClement Deschamps     case GPSET0:
160d72fc9dcSClement Deschamps     case GPSET1:
161d72fc9dcSClement Deschamps         /* Write Only */
162d72fc9dcSClement Deschamps         return 0;
163d72fc9dcSClement Deschamps     case GPCLR0:
164d72fc9dcSClement Deschamps     case GPCLR1:
165d72fc9dcSClement Deschamps         /* Write Only */
166d72fc9dcSClement Deschamps         return 0;
167d72fc9dcSClement Deschamps     case GPLEV0:
168d72fc9dcSClement Deschamps         return s->lev0;
169d72fc9dcSClement Deschamps     case GPLEV1:
170d72fc9dcSClement Deschamps         return s->lev1;
171d72fc9dcSClement Deschamps     case GPEDS0:
172d72fc9dcSClement Deschamps     case GPEDS1:
173d72fc9dcSClement Deschamps     case GPREN0:
174d72fc9dcSClement Deschamps     case GPREN1:
175d72fc9dcSClement Deschamps     case GPFEN0:
176d72fc9dcSClement Deschamps     case GPFEN1:
177d72fc9dcSClement Deschamps     case GPHEN0:
178d72fc9dcSClement Deschamps     case GPHEN1:
179d72fc9dcSClement Deschamps     case GPLEN0:
180d72fc9dcSClement Deschamps     case GPLEN1:
181d72fc9dcSClement Deschamps     case GPAREN0:
182d72fc9dcSClement Deschamps     case GPAREN1:
183d72fc9dcSClement Deschamps     case GPAFEN0:
184d72fc9dcSClement Deschamps     case GPAFEN1:
185d72fc9dcSClement Deschamps     case GPPUD:
186d72fc9dcSClement Deschamps     case GPPUDCLK0:
187d72fc9dcSClement Deschamps     case GPPUDCLK1:
188d72fc9dcSClement Deschamps         /* Not implemented */
189d72fc9dcSClement Deschamps         return 0;
190d72fc9dcSClement Deschamps     default:
191d72fc9dcSClement Deschamps         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
192d72fc9dcSClement Deschamps                 __func__, offset);
193d72fc9dcSClement Deschamps         break;
194d72fc9dcSClement Deschamps     }
195d72fc9dcSClement Deschamps 
196d72fc9dcSClement Deschamps     return 0;
197d72fc9dcSClement Deschamps }
198d72fc9dcSClement Deschamps 
199d72fc9dcSClement Deschamps static void bcm2835_gpio_write(void *opaque, hwaddr offset,
200d72fc9dcSClement Deschamps         uint64_t value, unsigned size)
201d72fc9dcSClement Deschamps {
202d72fc9dcSClement Deschamps     BCM2835GpioState *s = (BCM2835GpioState *)opaque;
203d72fc9dcSClement Deschamps 
204d72fc9dcSClement Deschamps     switch (offset) {
205d72fc9dcSClement Deschamps     case GPFSEL0:
206d72fc9dcSClement Deschamps     case GPFSEL1:
207d72fc9dcSClement Deschamps     case GPFSEL2:
208d72fc9dcSClement Deschamps     case GPFSEL3:
209d72fc9dcSClement Deschamps     case GPFSEL4:
210d72fc9dcSClement Deschamps     case GPFSEL5:
211d72fc9dcSClement Deschamps         gpfsel_set(s, offset / 4, value);
212d72fc9dcSClement Deschamps         break;
213d72fc9dcSClement Deschamps     case GPSET0:
214d72fc9dcSClement Deschamps         gpset(s, value, 0, 32, &s->lev0);
215d72fc9dcSClement Deschamps         break;
216d72fc9dcSClement Deschamps     case GPSET1:
217d72fc9dcSClement Deschamps         gpset(s, value, 32, 22, &s->lev1);
218d72fc9dcSClement Deschamps         break;
219d72fc9dcSClement Deschamps     case GPCLR0:
220d72fc9dcSClement Deschamps         gpclr(s, value, 0, 32, &s->lev0);
221d72fc9dcSClement Deschamps         break;
222d72fc9dcSClement Deschamps     case GPCLR1:
223d72fc9dcSClement Deschamps         gpclr(s, value, 32, 22, &s->lev1);
224d72fc9dcSClement Deschamps         break;
225d72fc9dcSClement Deschamps     case GPLEV0:
226d72fc9dcSClement Deschamps     case GPLEV1:
227d72fc9dcSClement Deschamps         /* Read Only */
228d72fc9dcSClement Deschamps         break;
229d72fc9dcSClement Deschamps     case GPEDS0:
230d72fc9dcSClement Deschamps     case GPEDS1:
231d72fc9dcSClement Deschamps     case GPREN0:
232d72fc9dcSClement Deschamps     case GPREN1:
233d72fc9dcSClement Deschamps     case GPFEN0:
234d72fc9dcSClement Deschamps     case GPFEN1:
235d72fc9dcSClement Deschamps     case GPHEN0:
236d72fc9dcSClement Deschamps     case GPHEN1:
237d72fc9dcSClement Deschamps     case GPLEN0:
238d72fc9dcSClement Deschamps     case GPLEN1:
239d72fc9dcSClement Deschamps     case GPAREN0:
240d72fc9dcSClement Deschamps     case GPAREN1:
241d72fc9dcSClement Deschamps     case GPAFEN0:
242d72fc9dcSClement Deschamps     case GPAFEN1:
243d72fc9dcSClement Deschamps     case GPPUD:
244d72fc9dcSClement Deschamps     case GPPUDCLK0:
245d72fc9dcSClement Deschamps     case GPPUDCLK1:
246d72fc9dcSClement Deschamps         /* Not implemented */
247d72fc9dcSClement Deschamps         break;
248d72fc9dcSClement Deschamps     default:
249d72fc9dcSClement Deschamps         goto err_out;
250d72fc9dcSClement Deschamps     }
251d72fc9dcSClement Deschamps     return;
252d72fc9dcSClement Deschamps 
253d72fc9dcSClement Deschamps err_out:
254d72fc9dcSClement Deschamps     qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
255d72fc9dcSClement Deschamps             __func__, offset);
256d72fc9dcSClement Deschamps }
257d72fc9dcSClement Deschamps 
258d72fc9dcSClement Deschamps static void bcm2835_gpio_reset(DeviceState *dev)
259d72fc9dcSClement Deschamps {
260d72fc9dcSClement Deschamps     BCM2835GpioState *s = BCM2835_GPIO(dev);
261d72fc9dcSClement Deschamps 
262d72fc9dcSClement Deschamps     int i;
263d72fc9dcSClement Deschamps     for (i = 0; i < 6; i++) {
264d72fc9dcSClement Deschamps         gpfsel_set(s, i, 0);
265d72fc9dcSClement Deschamps     }
266d72fc9dcSClement Deschamps 
267d72fc9dcSClement Deschamps     s->sd_fsel = 0;
268d72fc9dcSClement Deschamps 
269d72fc9dcSClement Deschamps     /* SDHCI is selected by default */
270d72fc9dcSClement Deschamps     sdbus_reparent_card(&s->sdbus, s->sdbus_sdhci);
271d72fc9dcSClement Deschamps 
272d72fc9dcSClement Deschamps     s->lev0 = 0;
273d72fc9dcSClement Deschamps     s->lev1 = 0;
274d72fc9dcSClement Deschamps }
275d72fc9dcSClement Deschamps 
276d72fc9dcSClement Deschamps static const MemoryRegionOps bcm2835_gpio_ops = {
277d72fc9dcSClement Deschamps     .read = bcm2835_gpio_read,
278d72fc9dcSClement Deschamps     .write = bcm2835_gpio_write,
279d72fc9dcSClement Deschamps     .endianness = DEVICE_NATIVE_ENDIAN,
280d72fc9dcSClement Deschamps };
281d72fc9dcSClement Deschamps 
282d72fc9dcSClement Deschamps static const VMStateDescription vmstate_bcm2835_gpio = {
283d72fc9dcSClement Deschamps     .name = "bcm2835_gpio",
284d72fc9dcSClement Deschamps     .version_id = 1,
285d72fc9dcSClement Deschamps     .minimum_version_id = 1,
286d72fc9dcSClement Deschamps     .fields = (VMStateField[]) {
287d72fc9dcSClement Deschamps         VMSTATE_UINT8_ARRAY(fsel, BCM2835GpioState, 54),
288d72fc9dcSClement Deschamps         VMSTATE_UINT32(lev0, BCM2835GpioState),
289d72fc9dcSClement Deschamps         VMSTATE_UINT32(lev1, BCM2835GpioState),
290d72fc9dcSClement Deschamps         VMSTATE_UINT8(sd_fsel, BCM2835GpioState),
291d72fc9dcSClement Deschamps         VMSTATE_END_OF_LIST()
292d72fc9dcSClement Deschamps     }
293d72fc9dcSClement Deschamps };
294d72fc9dcSClement Deschamps 
295d72fc9dcSClement Deschamps static void bcm2835_gpio_init(Object *obj)
296d72fc9dcSClement Deschamps {
297d72fc9dcSClement Deschamps     BCM2835GpioState *s = BCM2835_GPIO(obj);
298d72fc9dcSClement Deschamps     DeviceState *dev = DEVICE(obj);
299d72fc9dcSClement Deschamps     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
300d72fc9dcSClement Deschamps 
301d72fc9dcSClement Deschamps     qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
302d72fc9dcSClement Deschamps                         TYPE_SD_BUS, DEVICE(s), "sd-bus");
303d72fc9dcSClement Deschamps 
304d72fc9dcSClement Deschamps     memory_region_init_io(&s->iomem, obj,
305d72fc9dcSClement Deschamps             &bcm2835_gpio_ops, s, "bcm2835_gpio", 0x1000);
306d72fc9dcSClement Deschamps     sysbus_init_mmio(sbd, &s->iomem);
307d72fc9dcSClement Deschamps     qdev_init_gpio_out(dev, s->out, 54);
308d72fc9dcSClement Deschamps }
309d72fc9dcSClement Deschamps 
310d72fc9dcSClement Deschamps static void bcm2835_gpio_realize(DeviceState *dev, Error **errp)
311d72fc9dcSClement Deschamps {
312d72fc9dcSClement Deschamps     BCM2835GpioState *s = BCM2835_GPIO(dev);
313d72fc9dcSClement Deschamps     Object *obj;
314d72fc9dcSClement Deschamps     Error *err = NULL;
315d72fc9dcSClement Deschamps 
316d72fc9dcSClement Deschamps     obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &err);
317d72fc9dcSClement Deschamps     if (obj == NULL) {
318d72fc9dcSClement Deschamps         error_setg(errp, "%s: required sdhci link not found: %s",
319d72fc9dcSClement Deschamps                 __func__, error_get_pretty(err));
320d72fc9dcSClement Deschamps         return;
321d72fc9dcSClement Deschamps     }
322d72fc9dcSClement Deschamps     s->sdbus_sdhci = SD_BUS(obj);
323d72fc9dcSClement Deschamps 
324d72fc9dcSClement Deschamps     obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &err);
325d72fc9dcSClement Deschamps     if (obj == NULL) {
326d72fc9dcSClement Deschamps         error_setg(errp, "%s: required sdhost link not found: %s",
327d72fc9dcSClement Deschamps                 __func__, error_get_pretty(err));
328d72fc9dcSClement Deschamps         return;
329d72fc9dcSClement Deschamps     }
330d72fc9dcSClement Deschamps     s->sdbus_sdhost = SD_BUS(obj);
331d72fc9dcSClement Deschamps }
332d72fc9dcSClement Deschamps 
333d72fc9dcSClement Deschamps static void bcm2835_gpio_class_init(ObjectClass *klass, void *data)
334d72fc9dcSClement Deschamps {
335d72fc9dcSClement Deschamps     DeviceClass *dc = DEVICE_CLASS(klass);
336d72fc9dcSClement Deschamps 
337d72fc9dcSClement Deschamps     dc->vmsd = &vmstate_bcm2835_gpio;
338d72fc9dcSClement Deschamps     dc->realize = &bcm2835_gpio_realize;
339d72fc9dcSClement Deschamps     dc->reset = &bcm2835_gpio_reset;
340d72fc9dcSClement Deschamps }
341d72fc9dcSClement Deschamps 
342d72fc9dcSClement Deschamps static const TypeInfo bcm2835_gpio_info = {
343d72fc9dcSClement Deschamps     .name          = TYPE_BCM2835_GPIO,
344d72fc9dcSClement Deschamps     .parent        = TYPE_SYS_BUS_DEVICE,
345d72fc9dcSClement Deschamps     .instance_size = sizeof(BCM2835GpioState),
346d72fc9dcSClement Deschamps     .instance_init = bcm2835_gpio_init,
347d72fc9dcSClement Deschamps     .class_init    = bcm2835_gpio_class_init,
348d72fc9dcSClement Deschamps };
349d72fc9dcSClement Deschamps 
350d72fc9dcSClement Deschamps static void bcm2835_gpio_register_types(void)
351d72fc9dcSClement Deschamps {
352d72fc9dcSClement Deschamps     type_register_static(&bcm2835_gpio_info);
353d72fc9dcSClement Deschamps }
354d72fc9dcSClement Deschamps 
355d72fc9dcSClement Deschamps type_init(bcm2835_gpio_register_types)
356