/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (c) 2008 by Michael Sevakis
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#ifndef GPIO_IMX31_H
#define GPIO_IMX31_H

/* Static registration mechanism for imx31 GPIO interrupts */
#define USE_GPIO1_EVENTS (1 << 0)
#define USE_GPIO2_EVENTS (1 << 1)
#define USE_GPIO3_EVENTS (1 << 2)

/* Module logical indexes */
enum gpio_module_number
{
    GPIO1_NUM,      /* ID  0..31 */
    GPIO2_NUM,      /* ID 32..63 */
    GPIO3_NUM,      /* ID 64..95 */
    GPIO_NUM_GPIO,
};

enum gpio_id
{
    /* GPIO1 */
    GPIO1_0_ID = 0,
    GPIO1_1_ID,
    GPIO1_2_ID,
    GPIO1_3_ID,
    GPIO1_4_ID,
    GPIO1_5_ID,
    GPIO1_6_ID,
    GPIO1_7_ID,
    GPIO1_8_ID,
    GPIO1_9_ID,
    GPIO1_10_ID,
    GPIO1_11_ID,
    GPIO1_12_ID,
    GPIO1_13_ID,
    GPIO1_14_ID,
    GPIO1_15_ID,
    GPIO1_16_ID,
    GPIO1_17_ID,
    GPIO1_18_ID,
    GPIO1_19_ID,
    GPIO1_20_ID,
    GPIO1_21_ID,
    GPIO1_22_ID,
    GPIO1_23_ID,
    GPIO1_24_ID,
    GPIO1_25_ID,
    GPIO1_26_ID,
    GPIO1_27_ID,
    GPIO1_28_ID,
    GPIO1_29_ID,
    GPIO1_30_ID,
    GPIO1_31_ID,
    /* GPIO2 */
    GPIO2_0_ID = 32,
    GPIO2_1_ID,
    GPIO2_2_ID,
    GPIO2_3_ID,
    GPIO2_4_ID,
    GPIO2_5_ID,
    GPIO2_6_ID,
    GPIO2_7_ID,
    GPIO2_8_ID,
    GPIO2_9_ID,
    GPIO2_10_ID,
    GPIO2_11_ID,
    GPIO2_12_ID,
    GPIO2_13_ID,
    GPIO2_14_ID,
    GPIO2_15_ID,
    GPIO2_16_ID,
    GPIO2_17_ID,
    GPIO2_18_ID,
    GPIO2_19_ID,
    GPIO2_20_ID,
    GPIO2_21_ID,
    GPIO2_22_ID,
    GPIO2_23_ID,
    GPIO2_24_ID,
    GPIO2_25_ID,
    GPIO2_26_ID,
    GPIO2_27_ID,
    GPIO2_28_ID,
    GPIO2_29_ID,
    GPIO2_30_ID,
    GPIO2_31_ID,
    /* GPIO3 */
    GPIO3_0_ID = 64,
    GPIO3_1_ID,
    GPIO3_2_ID,
    GPIO3_3_ID,
    GPIO3_4_ID,
    GPIO3_5_ID,
    GPIO3_6_ID,
    GPIO3_7_ID,
    GPIO3_8_ID,
    GPIO3_9_ID,
    GPIO3_10_ID,
    GPIO3_11_ID,
    GPIO3_12_ID,
    GPIO3_13_ID,
    GPIO3_14_ID,
    GPIO3_15_ID,
    GPIO3_16_ID,
    GPIO3_17_ID,
    GPIO3_18_ID,
    GPIO3_19_ID,
    GPIO3_20_ID,
    GPIO3_21_ID,
    GPIO3_22_ID,
    GPIO3_23_ID,
    GPIO3_24_ID,
    GPIO3_25_ID,
    GPIO3_26_ID,
    GPIO3_27_ID,
    GPIO3_28_ID,
    GPIO3_29_ID,
    GPIO3_30_ID,
    GPIO3_31_ID,
};

/* Possible values for gpio interrupt line config */
enum gpio_int_sense
{
    GPIO_SENSE_LOW_LEVEL,  /* High-level sensitive */
    GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */
    GPIO_SENSE_RISING,     /* Rising-edge sensitive */
    GPIO_SENSE_FALLING,    /* Falling-edge sensitive */
    GPIO_SENSE_EDGE_SEL,   /* Detect any edge */
};

/* Handlers will be called in declared order for a given module
   Handlers of same module should be grouped together; module order
   doesn't matter */
#ifdef DEFINE_GPIO_VECTOR_TABLE

/* Describes a single event for a pin */
struct gpio_event
{
    uint8_t id;             /* GPIOx_y_ID */
    uint8_t sense;          /* GPIO_SENSE_x */
    void (*callback)(void); /* GPIOx_y_EVENT_CB */
};

#define GPIO_VECTOR_TBL_START() \
    static FORCE_INLINE uintptr_t __gpio_event_vector_tbl(int __what) \
    {                                                                 \
        static const struct gpio_event __tbl[] = {

#define GPIO_EVENT_VECTOR(__name, __sense) \
            { .id       = (__name##_ID),                   \
              .sense    = (__sense),                       \
              .callback = ({ void __name##_EVENT_CB(void); \
                             __name##_EVENT_CB; }) },

#define GPIO_VECTOR_TBL_END() \
        };                                              \
        switch (__what)                                 \
        {                                               \
            default: return (uintptr_t)__tbl;           \
            case  1: return (uintptr_t)ARRAYLEN(__tbl); \
        }                                               \
    }

#define gpio_event_vector_tbl \
    ((const struct gpio_event *)__gpio_event_vector_tbl(0))

#define gpio_event_vector_tbl_len \
    ((unsigned int)__gpio_event_vector_tbl(1))

#endif /* DEFINE_GPIO_VECTOR_TABLE */

#define GPIO_BASE_ADDR \
    (volatile unsigned long * const [GPIO_NUM_GPIO]) { \
        (volatile unsigned long *)GPIO1_BASE_ADDR,     \
        (volatile unsigned long *)GPIO2_BASE_ADDR,     \
        (volatile unsigned long *)GPIO3_BASE_ADDR }

#define GPIO_DR       (0x00 / sizeof (unsigned long)) /* 00h        */
#define GPIO_GDIR     (0x04 / sizeof (unsigned long)) /* 04h        */
#define GPIO_PSR      (0x08 / sizeof (unsigned long)) /* 08h        */
#define GPIO_ICR      (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */
#define GPIO_IMR      (0x14 / sizeof (unsigned long)) /* 14h        */
#define GPIO_ISR      (0x18 / sizeof (unsigned long)) /* 18h        */
#define GPIO_EDGE_SEL (0x1C / sizeof (unsigned long)) /* 1Ch        */

void gpio_init(void);
bool gpio_enable_event(enum gpio_id id, bool enable);

static FORCE_INLINE void gpio_int_clear(enum gpio_id id)
    { GPIO_BASE_ADDR[id / 32][GPIO_ISR] = 1ul << (id % 32); }

static FORCE_INLINE void gpio_int_enable(enum gpio_id id)
    { bitset32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); }

static FORCE_INLINE void gpio_int_disable(enum gpio_id id)
    { bitclr32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); }

#endif /* GPIO_IMX31_H */
