qemu
1/*
2* TI OMAP processors GPIO emulation.
3*
4* Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
5* Copyright (C) 2007-2009 Nokia Corporation
6*
7* This program is free software; you can redistribute it and/or
8* modify it under the terms of the GNU General Public License as
9* published by the Free Software Foundation; either version 2 or
10* (at your option) version 3 of the License.
11*
12* This program is distributed in the hope that it will be useful,
13* but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15* GNU General Public License for more details.
16*
17* You should have received a copy of the GNU General Public License along
18* with this program; if not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "qemu/osdep.h"22#include "qemu/log.h"23#include "hw/irq.h"24#include "hw/qdev-properties.h"25#include "hw/arm/omap.h"26#include "hw/sysbus.h"27#include "qemu/error-report.h"28#include "qemu/module.h"29#include "qapi/error.h"30
31struct omap_gpio_s {32qemu_irq irq;33qemu_irq handler[16];34
35uint16_t inputs;36uint16_t outputs;37uint16_t dir;38uint16_t edge;39uint16_t mask;40uint16_t ints;41uint16_t pins;42};43
44struct Omap1GpioState {45SysBusDevice parent_obj;46
47MemoryRegion iomem;48int mpu_model;49void *clk;50struct omap_gpio_s omap1;51};52
53/* General-Purpose I/O of OMAP1 */
54static void omap_gpio_set(void *opaque, int line, int level)55{
56Omap1GpioState *p = opaque;57struct omap_gpio_s *s = &p->omap1;58uint16_t prev = s->inputs;59
60if (level)61s->inputs |= 1 << line;62else63s->inputs &= ~(1 << line);64
65if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &66(1 << line) & s->dir & ~s->mask) {67s->ints |= 1 << line;68qemu_irq_raise(s->irq);69}70}
71
72static uint64_t omap_gpio_read(void *opaque, hwaddr addr,73unsigned size)74{
75struct omap_gpio_s *s = opaque;76int offset = addr & OMAP_MPUI_REG_MASK;77
78if (size != 2) {79return omap_badwidth_read16(opaque, addr);80}81
82switch (offset) {83case 0x00: /* DATA_INPUT */84return s->inputs & s->pins;85
86case 0x04: /* DATA_OUTPUT */87return s->outputs;88
89case 0x08: /* DIRECTION_CONTROL */90return s->dir;91
92case 0x0c: /* INTERRUPT_CONTROL */93return s->edge;94
95case 0x10: /* INTERRUPT_MASK */96return s->mask;97
98case 0x14: /* INTERRUPT_STATUS */99return s->ints;100
101case 0x18: /* PIN_CONTROL (not in OMAP310) */102OMAP_BAD_REG(addr);103return s->pins;104}105
106OMAP_BAD_REG(addr);107return 0;108}
109
110static void omap_gpio_write(void *opaque, hwaddr addr,111uint64_t value, unsigned size)112{
113struct omap_gpio_s *s = opaque;114int offset = addr & OMAP_MPUI_REG_MASK;115uint16_t diff;116int ln;117
118if (size != 2) {119omap_badwidth_write16(opaque, addr, value);120return;121}122
123switch (offset) {124case 0x00: /* DATA_INPUT */125OMAP_RO_REG(addr);126return;127
128case 0x04: /* DATA_OUTPUT */129diff = (s->outputs ^ value) & ~s->dir;130s->outputs = value;131while ((ln = ctz32(diff)) != 32) {132if (s->handler[ln])133qemu_set_irq(s->handler[ln], (value >> ln) & 1);134diff &= ~(1 << ln);135}136break;137
138case 0x08: /* DIRECTION_CONTROL */139diff = s->outputs & (s->dir ^ value);140s->dir = value;141
142value = s->outputs & ~s->dir;143while ((ln = ctz32(diff)) != 32) {144if (s->handler[ln])145qemu_set_irq(s->handler[ln], (value >> ln) & 1);146diff &= ~(1 << ln);147}148break;149
150case 0x0c: /* INTERRUPT_CONTROL */151s->edge = value;152break;153
154case 0x10: /* INTERRUPT_MASK */155s->mask = value;156break;157
158case 0x14: /* INTERRUPT_STATUS */159s->ints &= ~value;160if (!s->ints)161qemu_irq_lower(s->irq);162break;163
164case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */165OMAP_BAD_REG(addr);166s->pins = value;167break;168
169default:170OMAP_BAD_REG(addr);171return;172}173}
174
175/* *Some* sources say the memory region is 32-bit. */
176static const MemoryRegionOps omap_gpio_ops = {177.read = omap_gpio_read,178.write = omap_gpio_write,179.endianness = DEVICE_NATIVE_ENDIAN,180};181
182static void omap_gpio_reset(struct omap_gpio_s *s)183{
184s->inputs = 0;185s->outputs = ~0;186s->dir = ~0;187s->edge = ~0;188s->mask = ~0;189s->ints = 0;190s->pins = ~0;191}
192
193struct omap2_gpio_s {194qemu_irq irq[2];195qemu_irq wkup;196qemu_irq *handler;197MemoryRegion iomem;198
199uint8_t revision;200uint8_t config[2];201uint32_t inputs;202uint32_t outputs;203uint32_t dir;204uint32_t level[2];205uint32_t edge[2];206uint32_t mask[2];207uint32_t wumask;208uint32_t ints[2];209uint32_t debounce;210uint8_t delay;211};212
213struct Omap2GpioState {214SysBusDevice parent_obj;215
216MemoryRegion iomem;217int mpu_model;218void *iclk;219void *fclk[6];220int modulecount;221struct omap2_gpio_s *modules;222qemu_irq *handler;223int autoidle;224int gpo;225};226
227/* General-Purpose Interface of OMAP2/3 */
228static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,229int line)230{
231qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);232}
233
234static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)235{
236if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */237return;238if (!(s->config[0] & (3 << 3))) /* Force Idle */239return;240if (!(s->wumask & (1 << line)))241return;242
243qemu_irq_raise(s->wkup);244}
245
246static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,247uint32_t diff)248{
249int ln;250
251s->outputs ^= diff;252diff &= ~s->dir;253while ((ln = ctz32(diff)) != 32) {254qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);255diff &= ~(1 << ln);256}257}
258
259static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)260{
261s->ints[line] |= s->dir &262((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));263omap2_gpio_module_int_update(s, line);264}
265
266static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)267{
268s->ints[0] |= 1 << line;269omap2_gpio_module_int_update(s, 0);270s->ints[1] |= 1 << line;271omap2_gpio_module_int_update(s, 1);272omap2_gpio_module_wake(s, line);273}
274
275static void omap2_gpio_set(void *opaque, int line, int level)276{
277Omap2GpioState *p = opaque;278struct omap2_gpio_s *s = &p->modules[line >> 5];279
280line &= 31;281if (level) {282if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))283omap2_gpio_module_int(s, line);284s->inputs |= 1 << line;285} else {286if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))287omap2_gpio_module_int(s, line);288s->inputs &= ~(1 << line);289}290}
291
292static void omap2_gpio_module_reset(struct omap2_gpio_s *s)293{
294s->config[0] = 0;295s->config[1] = 2;296s->ints[0] = 0;297s->ints[1] = 0;298s->mask[0] = 0;299s->mask[1] = 0;300s->wumask = 0;301s->dir = ~0;302s->level[0] = 0;303s->level[1] = 0;304s->edge[0] = 0;305s->edge[1] = 0;306s->debounce = 0;307s->delay = 0;308}
309
310static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr)311{
312struct omap2_gpio_s *s = opaque;313
314switch (addr) {315case 0x00: /* GPIO_REVISION */316return s->revision;317
318case 0x10: /* GPIO_SYSCONFIG */319return s->config[0];320
321case 0x14: /* GPIO_SYSSTATUS */322return 0x01;323
324case 0x18: /* GPIO_IRQSTATUS1 */325return s->ints[0];326
327case 0x1c: /* GPIO_IRQENABLE1 */328case 0x60: /* GPIO_CLEARIRQENABLE1 */329case 0x64: /* GPIO_SETIRQENABLE1 */330return s->mask[0];331
332case 0x20: /* GPIO_WAKEUPENABLE */333case 0x80: /* GPIO_CLEARWKUENA */334case 0x84: /* GPIO_SETWKUENA */335return s->wumask;336
337case 0x28: /* GPIO_IRQSTATUS2 */338return s->ints[1];339
340case 0x2c: /* GPIO_IRQENABLE2 */341case 0x70: /* GPIO_CLEARIRQENABLE2 */342case 0x74: /* GPIO_SETIREQNEABLE2 */343return s->mask[1];344
345case 0x30: /* GPIO_CTRL */346return s->config[1];347
348case 0x34: /* GPIO_OE */349return s->dir;350
351case 0x38: /* GPIO_DATAIN */352return s->inputs;353
354case 0x3c: /* GPIO_DATAOUT */355case 0x90: /* GPIO_CLEARDATAOUT */356case 0x94: /* GPIO_SETDATAOUT */357return s->outputs;358
359case 0x40: /* GPIO_LEVELDETECT0 */360return s->level[0];361
362case 0x44: /* GPIO_LEVELDETECT1 */363return s->level[1];364
365case 0x48: /* GPIO_RISINGDETECT */366return s->edge[0];367
368case 0x4c: /* GPIO_FALLINGDETECT */369return s->edge[1];370
371case 0x50: /* GPIO_DEBOUNCENABLE */372return s->debounce;373
374case 0x54: /* GPIO_DEBOUNCINGTIME */375return s->delay;376}377
378OMAP_BAD_REG(addr);379return 0;380}
381
382static void omap2_gpio_module_write(void *opaque, hwaddr addr,383uint32_t value)384{
385struct omap2_gpio_s *s = opaque;386uint32_t diff;387int ln;388
389switch (addr) {390case 0x00: /* GPIO_REVISION */391case 0x14: /* GPIO_SYSSTATUS */392case 0x38: /* GPIO_DATAIN */393OMAP_RO_REG(addr);394break;395
396case 0x10: /* GPIO_SYSCONFIG */397if (((value >> 3) & 3) == 3) {398qemu_log_mask(LOG_GUEST_ERROR,399"%s: Illegal IDLEMODE value: 3\n", __func__);400}401if (value & 2)402omap2_gpio_module_reset(s);403s->config[0] = value & 0x1d;404break;405
406case 0x18: /* GPIO_IRQSTATUS1 */407if (s->ints[0] & value) {408s->ints[0] &= ~value;409omap2_gpio_module_level_update(s, 0);410}411break;412
413case 0x1c: /* GPIO_IRQENABLE1 */414s->mask[0] = value;415omap2_gpio_module_int_update(s, 0);416break;417
418case 0x20: /* GPIO_WAKEUPENABLE */419s->wumask = value;420break;421
422case 0x28: /* GPIO_IRQSTATUS2 */423if (s->ints[1] & value) {424s->ints[1] &= ~value;425omap2_gpio_module_level_update(s, 1);426}427break;428
429case 0x2c: /* GPIO_IRQENABLE2 */430s->mask[1] = value;431omap2_gpio_module_int_update(s, 1);432break;433
434case 0x30: /* GPIO_CTRL */435s->config[1] = value & 7;436break;437
438case 0x34: /* GPIO_OE */439diff = s->outputs & (s->dir ^ value);440s->dir = value;441
442value = s->outputs & ~s->dir;443while ((ln = ctz32(diff)) != 32) {444diff &= ~(1 << ln);445qemu_set_irq(s->handler[ln], (value >> ln) & 1);446}447
448omap2_gpio_module_level_update(s, 0);449omap2_gpio_module_level_update(s, 1);450break;451
452case 0x3c: /* GPIO_DATAOUT */453omap2_gpio_module_out_update(s, s->outputs ^ value);454break;455
456case 0x40: /* GPIO_LEVELDETECT0 */457s->level[0] = value;458omap2_gpio_module_level_update(s, 0);459omap2_gpio_module_level_update(s, 1);460break;461
462case 0x44: /* GPIO_LEVELDETECT1 */463s->level[1] = value;464omap2_gpio_module_level_update(s, 0);465omap2_gpio_module_level_update(s, 1);466break;467
468case 0x48: /* GPIO_RISINGDETECT */469s->edge[0] = value;470break;471
472case 0x4c: /* GPIO_FALLINGDETECT */473s->edge[1] = value;474break;475
476case 0x50: /* GPIO_DEBOUNCENABLE */477s->debounce = value;478break;479
480case 0x54: /* GPIO_DEBOUNCINGTIME */481s->delay = value;482break;483
484case 0x60: /* GPIO_CLEARIRQENABLE1 */485s->mask[0] &= ~value;486omap2_gpio_module_int_update(s, 0);487break;488
489case 0x64: /* GPIO_SETIRQENABLE1 */490s->mask[0] |= value;491omap2_gpio_module_int_update(s, 0);492break;493
494case 0x70: /* GPIO_CLEARIRQENABLE2 */495s->mask[1] &= ~value;496omap2_gpio_module_int_update(s, 1);497break;498
499case 0x74: /* GPIO_SETIREQNEABLE2 */500s->mask[1] |= value;501omap2_gpio_module_int_update(s, 1);502break;503
504case 0x80: /* GPIO_CLEARWKUENA */505s->wumask &= ~value;506break;507
508case 0x84: /* GPIO_SETWKUENA */509s->wumask |= value;510break;511
512case 0x90: /* GPIO_CLEARDATAOUT */513omap2_gpio_module_out_update(s, s->outputs & value);514break;515
516case 0x94: /* GPIO_SETDATAOUT */517omap2_gpio_module_out_update(s, ~s->outputs & value);518break;519
520default:521OMAP_BAD_REG(addr);522return;523}524}
525
526static uint64_t omap2_gpio_module_readp(void *opaque, hwaddr addr,527unsigned size)528{
529return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);530}
531
532static void omap2_gpio_module_writep(void *opaque, hwaddr addr,533uint64_t value, unsigned size)534{
535uint32_t cur = 0;536uint32_t mask = 0xffff;537
538if (size == 4) {539omap2_gpio_module_write(opaque, addr, value);540return;541}542
543switch (addr & ~3) {544case 0x00: /* GPIO_REVISION */545case 0x14: /* GPIO_SYSSTATUS */546case 0x38: /* GPIO_DATAIN */547OMAP_RO_REG(addr);548break;549
550case 0x10: /* GPIO_SYSCONFIG */551case 0x1c: /* GPIO_IRQENABLE1 */552case 0x20: /* GPIO_WAKEUPENABLE */553case 0x2c: /* GPIO_IRQENABLE2 */554case 0x30: /* GPIO_CTRL */555case 0x34: /* GPIO_OE */556case 0x3c: /* GPIO_DATAOUT */557case 0x40: /* GPIO_LEVELDETECT0 */558case 0x44: /* GPIO_LEVELDETECT1 */559case 0x48: /* GPIO_RISINGDETECT */560case 0x4c: /* GPIO_FALLINGDETECT */561case 0x50: /* GPIO_DEBOUNCENABLE */562case 0x54: /* GPIO_DEBOUNCINGTIME */563cur = omap2_gpio_module_read(opaque, addr & ~3) &564~(mask << ((addr & 3) << 3));565
566/* Fall through. */567case 0x18: /* GPIO_IRQSTATUS1 */568case 0x28: /* GPIO_IRQSTATUS2 */569case 0x60: /* GPIO_CLEARIRQENABLE1 */570case 0x64: /* GPIO_SETIRQENABLE1 */571case 0x70: /* GPIO_CLEARIRQENABLE2 */572case 0x74: /* GPIO_SETIREQNEABLE2 */573case 0x80: /* GPIO_CLEARWKUENA */574case 0x84: /* GPIO_SETWKUENA */575case 0x90: /* GPIO_CLEARDATAOUT */576case 0x94: /* GPIO_SETDATAOUT */577value <<= (addr & 3) << 3;578omap2_gpio_module_write(opaque, addr, cur | value);579break;580
581default:582OMAP_BAD_REG(addr);583return;584}585}
586
587static const MemoryRegionOps omap2_gpio_module_ops = {588.read = omap2_gpio_module_readp,589.write = omap2_gpio_module_writep,590.valid.min_access_size = 1,591.valid.max_access_size = 4,592.endianness = DEVICE_NATIVE_ENDIAN,593};594
595static void omap_gpif_reset(DeviceState *dev)596{
597Omap1GpioState *s = OMAP1_GPIO(dev);598
599omap_gpio_reset(&s->omap1);600}
601
602static void omap2_gpif_reset(DeviceState *dev)603{
604Omap2GpioState *s = OMAP2_GPIO(dev);605int i;606
607for (i = 0; i < s->modulecount; i++) {608omap2_gpio_module_reset(&s->modules[i]);609}610s->autoidle = 0;611s->gpo = 0;612}
613
614static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, unsigned size)615{
616Omap2GpioState *s = opaque;617
618switch (addr) {619case 0x00: /* IPGENERICOCPSPL_REVISION */620return 0x18;621
622case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */623return s->autoidle;624
625case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */626return 0x01;627
628case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */629return 0x00;630
631case 0x40: /* IPGENERICOCPSPL_GPO */632return s->gpo;633
634case 0x50: /* IPGENERICOCPSPL_GPI */635return 0x00;636}637
638OMAP_BAD_REG(addr);639return 0;640}
641
642static void omap2_gpif_top_write(void *opaque, hwaddr addr,643uint64_t value, unsigned size)644{
645Omap2GpioState *s = opaque;646
647switch (addr) {648case 0x00: /* IPGENERICOCPSPL_REVISION */649case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */650case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */651case 0x50: /* IPGENERICOCPSPL_GPI */652OMAP_RO_REG(addr);653break;654
655case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */656if (value & (1 << 1)) /* SOFTRESET */657omap2_gpif_reset(DEVICE(s));658s->autoidle = value & 1;659break;660
661case 0x40: /* IPGENERICOCPSPL_GPO */662s->gpo = value & 1;663break;664
665default:666OMAP_BAD_REG(addr);667return;668}669}
670
671static const MemoryRegionOps omap2_gpif_top_ops = {672.read = omap2_gpif_top_read,673.write = omap2_gpif_top_write,674.endianness = DEVICE_NATIVE_ENDIAN,675};676
677static void omap_gpio_init(Object *obj)678{
679DeviceState *dev = DEVICE(obj);680Omap1GpioState *s = OMAP1_GPIO(obj);681SysBusDevice *sbd = SYS_BUS_DEVICE(obj);682
683qdev_init_gpio_in(dev, omap_gpio_set, 16);684qdev_init_gpio_out(dev, s->omap1.handler, 16);685sysbus_init_irq(sbd, &s->omap1.irq);686memory_region_init_io(&s->iomem, obj, &omap_gpio_ops, &s->omap1,687"omap.gpio", 0x1000);688sysbus_init_mmio(sbd, &s->iomem);689}
690
691static void omap_gpio_realize(DeviceState *dev, Error **errp)692{
693Omap1GpioState *s = OMAP1_GPIO(dev);694
695if (!s->clk) {696error_setg(errp, "omap-gpio: clk not connected");697}698}
699
700static void omap2_gpio_realize(DeviceState *dev, Error **errp)701{
702Omap2GpioState *s = OMAP2_GPIO(dev);703SysBusDevice *sbd = SYS_BUS_DEVICE(dev);704int i;705
706if (!s->iclk) {707error_setg(errp, "omap2-gpio: iclk not connected");708return;709}710
711s->modulecount = s->mpu_model < omap2430 ? 4712: s->mpu_model < omap3430 ? 5713: 6;714
715if (s->mpu_model < omap3430) {716memory_region_init_io(&s->iomem, OBJECT(dev), &omap2_gpif_top_ops, s,717"omap2.gpio", 0x1000);718sysbus_init_mmio(sbd, &s->iomem);719}720
721s->modules = g_new0(struct omap2_gpio_s, s->modulecount);722s->handler = g_new0(qemu_irq, s->modulecount * 32);723qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32);724qdev_init_gpio_out(dev, s->handler, s->modulecount * 32);725
726for (i = 0; i < s->modulecount; i++) {727struct omap2_gpio_s *m = &s->modules[i];728
729if (!s->fclk[i]) {730error_setg(errp, "omap2-gpio: fclk%d not connected", i);731return;732}733
734m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;735m->handler = &s->handler[i * 32];736sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */737sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */738sysbus_init_irq(sbd, &m->wkup);739memory_region_init_io(&m->iomem, OBJECT(dev), &omap2_gpio_module_ops, m,740"omap.gpio-module", 0x1000);741sysbus_init_mmio(sbd, &m->iomem);742}743}
744
745void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk)746{
747gpio->clk = clk;748}
749
750static Property omap_gpio_properties[] = {751DEFINE_PROP_INT32("mpu_model", Omap1GpioState, mpu_model, 0),752DEFINE_PROP_END_OF_LIST(),753};754
755static void omap_gpio_class_init(ObjectClass *klass, void *data)756{
757DeviceClass *dc = DEVICE_CLASS(klass);758
759dc->realize = omap_gpio_realize;760dc->reset = omap_gpif_reset;761device_class_set_props(dc, omap_gpio_properties);762/* Reason: pointer property "clk" */763dc->user_creatable = false;764}
765
766static const TypeInfo omap_gpio_info = {767.name = TYPE_OMAP1_GPIO,768.parent = TYPE_SYS_BUS_DEVICE,769.instance_size = sizeof(Omap1GpioState),770.instance_init = omap_gpio_init,771.class_init = omap_gpio_class_init,772};773
774void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk)775{
776gpio->iclk = clk;777}
778
779void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk)780{
781assert(i <= 5);782gpio->fclk[i] = clk;783}
784
785static Property omap2_gpio_properties[] = {786DEFINE_PROP_INT32("mpu_model", Omap2GpioState, mpu_model, 0),787DEFINE_PROP_END_OF_LIST(),788};789
790static void omap2_gpio_class_init(ObjectClass *klass, void *data)791{
792DeviceClass *dc = DEVICE_CLASS(klass);793
794dc->realize = omap2_gpio_realize;795dc->reset = omap2_gpif_reset;796device_class_set_props(dc, omap2_gpio_properties);797/* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */798dc->user_creatable = false;799}
800
801static const TypeInfo omap2_gpio_info = {802.name = TYPE_OMAP2_GPIO,803.parent = TYPE_SYS_BUS_DEVICE,804.instance_size = sizeof(Omap2GpioState),805.class_init = omap2_gpio_class_init,806};807
808static void omap_gpio_register_types(void)809{
810type_register_static(&omap_gpio_info);811type_register_static(&omap2_gpio_info);812}
813
814type_init(omap_gpio_register_types)815