Example #1
0
void imx233_lradc_init(void)
{
    arbiter_init(&channel_arbiter, HW_LRADC_NUM_CHANNELS);
    arbiter_init(&delay_arbiter, HW_LRADC_NUM_DELAYS);
    // enable block
    imx233_reset_block(&HW_LRADC_CTRL0);
    // disable ground ref
    __REG_CLR(HW_LRADC_CTRL0) = HW_LRADC_CTRL0__ONCHIP_GROUNDREF;
    // disable temperature sensors
    __REG_CLR(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE0 |
        HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE1;
    __REG_SET(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMPSENSE_PWD;
    // set frequency
    __REG_CLR(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME_BM;
    __REG_SET(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME__6MHz;
    // setup battery
    battery_chan = 7;
    imx233_lradc_reserve_channel(battery_chan);
    /* setup them for the simplest use: no accumulation, no division*/
    imx233_lradc_setup_channel(battery_chan, false, false, 0, HW_LRADC_CHANNEL_BATTERY);
    /* setup delay channel for battery for automatic reading and scaling */
    battery_delay_chan = 0;
    imx233_lradc_reserve_delay(battery_delay_chan);
    /* setup delay to trigger battery channel and retrigger itself.
     * The counter runs at 2KHz so a delay of 200 will trigger 10
     * conversions per seconds */
    imx233_lradc_setup_delay(battery_delay_chan, 1 << battery_chan,
        1 << battery_delay_chan, 0, 200);
    imx233_lradc_kick_delay(battery_delay_chan);
    /* enable automatic conversion, use Li-Ion type battery */
    imx233_lradc_setup_battery_conversion(true, HW_LRADC_CONVERSION__SCALE_FACTOR__LI_ION);
}
Example #2
0
void imx233_set_clock_divisor(enum imx233_clock_t clk, int div)
{
    switch(clk)
    {
        case CLK_PIX:
            __REG_CLR(HW_CLKCTRL_PIX) = HW_CLKCTRL_PIX__DIV_BM;
            __REG_SET(HW_CLKCTRL_PIX) = div;
            while(HW_CLKCTRL_PIX & __CLK_BUSY);
            break;
        case CLK_SSP:
            __REG_CLR(HW_CLKCTRL_SSP) = HW_CLKCTRL_SSP__DIV_BM;
            __REG_SET(HW_CLKCTRL_SSP) = div;
            while(HW_CLKCTRL_SSP & __CLK_BUSY);
            break;
        case CLK_CPU:
            __REG_CLR(HW_CLKCTRL_CPU) = HW_CLKCTRL_CPU__DIV_CPU_BM;
            __REG_SET(HW_CLKCTRL_CPU) = div;
            while(HW_CLKCTRL_CPU & HW_CLKCTRL_CPU__BUSY_REF_CPU);
            break;
        case CLK_AHB:
            __REG_CLR(HW_CLKCTRL_HBUS) = HW_CLKCTRL_HBUS__DIV_BM;
            __REG_SET(HW_CLKCTRL_HBUS) = div;
            while(HW_CLKCTRL_HBUS & __CLK_BUSY);
            break;
        default: return;
    }
}
Example #3
0
static enum imx233_dcp_error_t imx233_dcp_job(int ch)
{
    /* if IRQs are not enabled, don't enable channel interrupt and do some polling */
    bool irq_enabled = irq_enabled();
    /* enable channel, clear interrupt, enable interrupt */
    imx233_icoll_enable_interrupt(INT_SRC_DCP, true);
    if(irq_enabled)
        __REG_SET(HW_DCP_CTRL) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch);
    __REG_CLR(HW_DCP_STAT) = HW_DCP_STAT__IRQ(ch);
    __REG_SET(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch);

    /* write back packet */
    commit_discard_dcache_range(&channel_packet[ch], sizeof(struct imx233_dcp_packet_t));
    /* write 1 to semaphore to run job */
    HW_DCP_CHxCMDPTR(ch) = (uint32_t)PHYSICAL_ADDR(&channel_packet[ch]);
    HW_DCP_CHxSEMA(ch) = 1;
    /* wait completion */
    if(irq_enabled)
        semaphore_wait(&channel_sema[ch], TIMEOUT_BLOCK);
    else
        while(__XTRACT_EX(HW_DCP_CHxSEMA(ch), HW_DCP_CHxSEMA__VALUE))
            udelay(10);
    /* disable channel and interrupt */
    __REG_CLR(HW_DCP_CTRL) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch);
    __REG_CLR(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch);
    /* read status */
    return get_error_status(ch);
}
Example #4
0
void power_init(void)
{
    /* setup vbusvalid parameters: set threshold to 4v and power up comparators */
    __REG_CLR(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__VBUSVALID_TRSH_BM;
    __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__VBUSVALID_TRSH_4V |
        HW_POWER_5VCTRL__PWRUP_VBUS_CMPS;
    /* enable vbusvalid detection method for the dcdc (improves efficiency) */
    __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__VBUSVALID_5VDETECT;
    /* clear vbusvalid irq and set correct polarity */
    __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__VBUSVALID_IRQ;
    if(HW_POWER_STS & HW_POWER_STS__VBUSVALID)
        __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID;
    else
        __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID;
    __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__ENIRQ_VBUS_VALID;
    imx233_icoll_enable_interrupt(INT_SRC_VDD5V, true);
    /* setup linear regulator offsets to 25 mV below to prevent contention between
     * linear regulators and DCDC */
    __FIELD_SET(HW_POWER_VDDDCTRL, LINREG_OFFSET, 2);
    __FIELD_SET(HW_POWER_VDDACTRL, LINREG_OFFSET, 2);
    __FIELD_SET(HW_POWER_VDDIOCTRL, LINREG_OFFSET, 2);
    /* enable a few bits controlling the DC-DC as recommended by Freescale */
    __REG_SET(HW_POWER_LOOPCTRL) = HW_POWER_LOOPCTRL__TOGGLE_DIF |
        HW_POWER_LOOPCTRL__EN_CM_HYST;
    __FIELD_SET(HW_POWER_LOOPCTRL, EN_RCSCALE, HW_POWER_LOOPCTRL__EN_RCSCALE__2X);
}
Example #5
0
void imx233_lradc_setup_battery_conversion(bool automatic, unsigned long scale_factor)
{
    __REG_CLR(HW_LRADC_CONVERSION) = HW_LRADC_CONVERSION__SCALE_FACTOR_BM;
    __REG_SET(HW_LRADC_CONVERSION) = scale_factor;
    if(automatic)
        __REG_SET(HW_LRADC_CONVERSION) = HW_LRADC_CONVERSION__AUTOMATIC;
    else
        __REG_CLR(HW_LRADC_CONVERSION) = HW_LRADC_CONVERSION__AUTOMATIC;
}
Example #6
0
void imx233_lcdif_dma_send(void *buf, unsigned width, unsigned height)
{
    HW_LCDIF_CUR_BUF = (uint32_t)buf;
    HW_LCDIF_TRANSFER_COUNT = 0;
    HW_LCDIF_TRANSFER_COUNT = (height << 16) | width;
    __REG_CLR(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__RUN;
    __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_SELECT;
    __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__RUN;
}
Example #7
0
void imx233_lradc_setup_channel(int channel, bool div2, bool acc, int nr_samples, int src)
{
    __REG_CLR(HW_LRADC_CHx(channel)) = HW_LRADC_CHx__NUM_SAMPLES_BM | HW_LRADC_CHx__ACCUMULATE;
    __REG_SET(HW_LRADC_CHx(channel)) = nr_samples << HW_LRADC_CHx__NUM_SAMPLES_BP |
        acc << HW_LRADC_CHx__ACCUMULATE;
    if(div2)
        __REG_SET(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__DIVIDE_BY_TWO(channel);
    else
        __REG_CLR(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__DIVIDE_BY_TWO(channel);
    __REG_CLR(HW_LRADC_CTRL4) = HW_LRADC_CTRL4__LRADCxSELECT_BM(channel);
    __REG_SET(HW_LRADC_CTRL4) = src << HW_LRADC_CTRL4__LRADCxSELECT_BP(channel);
}
Example #8
0
void powermgmt_init_target(void)
{
    imx233_power_set_charge_current(IMX233_CHARGE_CURRENT);
    imx233_power_set_stop_current(IMX233_STOP_CURRENT);
    /* assume that adc_init was called and battery monitoring via LRADC setup */
    __REG_SET(HW_POWER_BATTMONITOR) = HW_POWER_BATTMONITOR__ENBATADJ;
    /* make sure we are in a known state: disable charger and 4p2 */
    __REG_SET(HW_POWER_CHARGE) = HW_POWER_CHARGE__PWD_BATTCHRG;
    __REG_CLR(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_DCDC |
                                  HW_POWER_DCDC4P2__ENABLE_4P2;
    __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2;
    charge_state = DISCHARGING;
}
Example #9
0
void imx233_enable_usb_phy(bool enable)
{
    if(enable)
    {
        __REG_CLR(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;
        __REG_CLR(HW_USBPHY_PWD) = HW_USBPHY_PWD__ALL;
    }
    else
    {
        __REG_SET(HW_USBPHY_PWD) = HW_USBPHY_PWD__ALL;
        __REG_SET(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;
    }
}
Example #10
0
void imx233_lcdif_set_data_format(bool data_fmt_16, bool data_fmt_18, bool data_fmt_24)
{
    if(data_fmt_16)
        __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_FORMAT_16_BIT;
    else
        __REG_CLR(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_FORMAT_16_BIT;
    if(data_fmt_18)
        __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_FORMAT_18_BIT;
    else
        __REG_CLR(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_FORMAT_18_BIT;
    if(data_fmt_24)
        __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_FORMAT_24_BIT;
    else
        __REG_CLR(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_FORMAT_24_BIT;
}
Example #11
0
void imx233_enable_usb_controller(bool enable)
{
    if(enable)
        __REG_CLR(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
    else
        __REG_SET(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
}
Example #12
0
void imx233_softirq(int src, bool enable)
{
    if(enable)
        __REG_SET(HW_ICOLL_INTERRUPT(src)) = HW_ICOLL_INTERRUPT__SOFTIRQ;
    else
        __REG_CLR(HW_ICOLL_INTERRUPT(src)) = HW_ICOLL_INTERRUPT__SOFTIRQ;
}
Example #13
0
void imx233_enable_interrupt(int src, bool enable)
{
    if(enable)
        __REG_SET(HW_ICOLL_INTERRUPT(src)) = HW_ICOLL_INTERRUPT__ENABLE;
    else
        __REG_CLR(HW_ICOLL_INTERRUPT(src)) = HW_ICOLL_INTERRUPT__ENABLE;
}
Example #14
0
void imx233_enable_xtal_clock(enum imx233_xtal_clkt_t xtal_clk, bool enable)
{
    if(enable)
        __REG_CLR(HW_CLKCTRL_XTAL) = xtal_clk;
    else
        __REG_SET(HW_CLKCTRL_XTAL) = xtal_clk;
}
Example #15
0
void imx233_enable_timrot_xtal_clk32k(bool enable)
{
    if(enable)
        __REG_CLR(HW_CLKCTRL_XTAL) = HW_CLKCTRL_XTAL__TIMROT_CLK32K_GATE;
    else
        __REG_SET(HW_CLKCTRL_XTAL) = HW_CLKCTRL_XTAL__TIMROT_CLK32K_GATE;
}
Example #16
0
void imx233_lcdif_enable(bool enable)
{
    if(enable)
        __REG_CLR(HW_LCDIF_CTRL) = __BLOCK_CLKGATE;
    else
        __REG_SET(HW_LCDIF_CTRL) = __BLOCK_CLKGATE;
}
Example #17
0
void imx233_lcdif_enable_bus_master(bool enable)
{
    if(enable)
        __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__LCDIF_MASTER;
    else
        __REG_CLR(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__LCDIF_MASTER;
}
Example #18
0
void imx233_enable_usb_pll(bool enable)
{
    if(enable)
        __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS;
    else
        __REG_CLR(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS;
}
Example #19
0
void imx233_lradc_init(void)
{
    mutex_init(&free_bm_mutex);
    semaphore_init(&free_bm_sema, HW_LRADC_NUM_CHANNELS, HW_LRADC_NUM_CHANNELS);
    free_bm = (1 << HW_LRADC_NUM_CHANNELS) - 1;
    // enable block
    imx233_reset_block(&HW_LRADC_CTRL0);
    // disable ground ref
    __REG_CLR(HW_LRADC_CTRL0) = HW_LRADC_CTRL0__ONCHIP_GROUNDREF;
    // disable temperature sensors
    __REG_CLR(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE0 |
        HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE1;
    __REG_SET(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMPSENSE_PWD;
    // set frequency
    __REG_CLR(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME_BM;
    __REG_SET(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME__6MHz;
}
Example #20
0
void imx233_audioin_close(void)
{
    /* TODO mute */
    /* Gate off ADC */
    __REG_SET(HW_AUDIOIN_ANACLKCTRL) = HW_AUDIOIN_ANACLKCTRL__CLKGATE;
    /* will also gate off the module */
    __REG_CLR(HW_AUDIOIN_CTRL) = HW_AUDIOIN_CTRL__RUN;
}
Example #21
0
void imx233_lradc_enable_channel_irq(int channel, bool enable)
{
    if(enable)
        __REG_SET(HW_LRADC_CTRL1) = HW_LRADC_CTRL1__LRADCx_IRQ_EN(channel);
    else
        __REG_CLR(HW_LRADC_CTRL1) = HW_LRADC_CTRL1__LRADCx_IRQ_EN(channel);
    imx233_lradc_clear_channel_irq(channel);
}
Example #22
0
void imx233_lradc_init(void)
{
    if (!g_f_is_initialised) {
        g_f_is_initialised = 1;
        // enable block
        imx233_reset_block(&HW_LRADC_CTRL0);
        // disable ground ref
        __REG_CLR(HW_LRADC_CTRL0) = HW_LRADC_CTRL0__ONCHIP_GROUNDREF;
        // disable temperature sensors
        __REG_CLR(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE0 |
                                    HW_LRADC_CTRL2__TEMP_SENSOR_IENABLE1;
        __REG_SET(HW_LRADC_CTRL2) = HW_LRADC_CTRL2__TEMPSENSE_PWD;
        // set frequency
        __REG_CLR(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME_BM;
        __REG_SET(HW_LRADC_CTRL3) = HW_LRADC_CTRL3__CYCLE_TIME__6MHz;
    }
}
Example #23
0
void imx233_audioin_preinit(void)
{
    /* Enable AUDIOIN block */
    imx233_reset_block(&HW_AUDIOIN_CTRL);
    /* Enable ADC */
    __REG_CLR(HW_AUDIOIN_ANACLKCTRL) = HW_AUDIOIN_ANACLKCTRL__CLKGATE;
    /* Set word-length to 16-bit */
    __REG_SET(HW_AUDIOIN_CTRL) = HW_AUDIOIN_CTRL__WORD_LENGTH;
}
Example #24
0
/* set to 0 to disable current source */
static void imx233_lradc_set_temp_isrc(int sensor, int value)
{
    if(sensor < 0 || sensor > 1)
        panicf("imx233_lradc_set_temp_isrc: invalid sensor");
    unsigned mask = HW_LRADC_CTRL2__TEMP_ISRCx_BM(sensor);
    unsigned bp = HW_LRADC_CTRL2__TEMP_ISRCx_BP(sensor);
    unsigned en = HW_LRADC_CTRL2__TEMP_SENSOR_IENABLEx(sensor);

    __REG_CLR(HW_LRADC_CTRL2) = mask;
    __REG_SET(HW_LRADC_CTRL2) = value << bp;
    if(value != 0)
    {
        __REG_SET(HW_LRADC_CTRL2) = en;
        udelay(100);
    }
    else
        __REG_CLR(HW_LRADC_CTRL2) = en;
}
Example #25
0
void dma_clkgate_channel(unsigned chan, bool enable_clock)
{
    if(APB_IS_APBX_CHANNEL(chan))
        return;
    if(enable_clock)
        __REG_CLR(HW_APBH_CTRL0) =
            HW_APBH_CTRL0__CLKGATE_CHANNEL(APB_GET_DMA_CHANNEL(chan));
    else
        __REG_SET(HW_APBH_CTRL0) =
            HW_APBH_CTRL0__CLKGATE_CHANNEL(APB_GET_DMA_CHANNEL(chan));
}
Example #26
0
void imx233_power_set_charge_current(unsigned current)
{
    __REG_CLR(HW_POWER_CHARGE) = HW_POWER_CHARGE__BATTCHRG_I_BM;
    /* find closest current LOWER THAN OR EQUAL TO the expected current */
    for(unsigned i = 0; i < ARRAYLEN(g_charger_current_bits); i++)
        if(current >= g_charger_current_bits[i].current)
        {
            current -= g_charger_current_bits[i].current;
            __REG_SET(HW_POWER_CHARGE) = g_charger_current_bits[i].bit;
        }
}
Example #27
0
void imx233_lcdif_pio_send(bool data_mode, unsigned len, uint32_t *buf)
{
    unsigned max_xfer_size = 0xffff;
    if(len == 0)
        return;
    if(lcdif_word_length == HW_LCDIF_CTRL__WORD_LENGTH_16_BIT)
        max_xfer_size = 0x1fffe;
    imx233_lcdif_wait_ready();
    unsigned msk = imx233_lcdif_enable_irqs(0);
    imx233_lcdif_enable_bus_master(false);

    do
    {
        unsigned burst = MIN(len, max_xfer_size);
        len -= burst;
        unsigned count = burst;
        if(lcdif_word_length != HW_LCDIF_CTRL__WORD_LENGTH_8_BIT)
        {
            if(burst & 1)
                burst++;
            count = burst / 2;
        }
        else
            count = burst;
        HW_LCDIF_TRANSFER_COUNT = 0;
        HW_LCDIF_TRANSFER_COUNT = 0x10000 | count;
        __REG_CLR(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_SELECT | HW_LCDIF_CTRL__RUN;
        if(data_mode)
            __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__DATA_SELECT;
        __REG_SET(HW_LCDIF_CTRL) = HW_LCDIF_CTRL__RUN;
        burst = (burst + 3) / 4;
        while(burst-- > 0)
        {
            while(HW_LCDIF_STAT & HW_LCDIF_STAT__LFIFO_FULL);
            HW_LCDIF_DATA = *buf++;
        }
        while(HW_LCDIF_CTRL & HW_LCDIF_CTRL__RUN);
    }while(len > 0);
    imx233_lcdif_enable_bus_master(true);
    imx233_lcdif_enable_irqs(msk);
}
Example #28
0
void imx233_dcp_init(void)
{
    /* Reset block */
    imx233_reset_block(&HW_DCP_CTRL);
    /* Setup contexte pointer */
    HW_DCP_CONTEXT = (uint32_t)PHYSICAL_ADDR(&dcp_context);
    /* Enable context switching and caching */
    __REG_SET(HW_DCP_CTRL) = HW_DCP_CTRL__ENABLE_CONTEXT_CACHING |
        HW_DCP_CTRL__ENABLE_CONTEXT_SWITCHING;
    /* Check that there are sufficiently many channels */
    if(__XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS) != HW_DCP_NUM_CHANNELS)
        panicf("DCP has %lu channels but was configured to use %d !",
               __XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS), HW_DCP_NUM_CHANNELS);
    /* Setup channel arbiter to use */
    arbiter_init(&channel_arbiter, HW_DCP_NUM_CHANNELS);
    /* Merge channel0 interrupt */
    __REG_SET(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__CH0_IRQ_MERGED;
    /* setup semaphores */
    for(int i = 0; i< HW_DCP_NUM_CHANNELS; i++)
        semaphore_init(&channel_sema[i], 1, 0);
}
Example #29
0
unsigned imx233_lcdif_enable_irqs(unsigned irq_bm)
{
    unsigned old_msk = __XTRACT(HW_LCDIF_CTRL1, IRQ_EN);
    /* clear irq status */
    __REG_CLR(HW_LCDIF_CTRL1) = irq_bm << HW_LCDIF_CTRL1__IRQ_BP;
    /* disable irqs */
    __REG_CLR(HW_LCDIF_CTRL1) = HW_LCDIF_CTRL1__IRQ_EN_BM;
    /* enable irqs */
    __REG_SET(HW_LCDIF_CTRL1) = irq_bm << HW_LCDIF_CTRL1__IRQ_EN_BP;

    return old_msk;
}
Example #30
0
void imx233_setup_pin_irq(int bank, int pin, bool enable_int,
    bool level, bool polarity, pin_irq_cb_t cb)
{
    __REG_CLR(HW_PINCTRL_PIN2IRQ(bank)) = 1 << pin;
    __REG_CLR(HW_PINCTRL_IRQEN(bank)) = 1 << pin;
    __REG_CLR(HW_PINCTRL_IRQSTAT(bank))= 1 << pin;
    pin_cb[bank][pin] = cb;
    if(enable_int)
    {
        if(level)
            __REG_SET(HW_PINCTRL_IRQLEVEL(bank)) = 1 << pin;
        else
            __REG_CLR(HW_PINCTRL_IRQLEVEL(bank)) = 1 << pin;
        if(polarity)
            __REG_SET(HW_PINCTRL_IRQPOL(bank)) = 1 << pin;
        else
            __REG_CLR(HW_PINCTRL_IRQPOL(bank)) = 1 << pin;
        __REG_SET(HW_PINCTRL_PIN2IRQ(bank)) = 1 << pin;
        __REG_SET(HW_PINCTRL_IRQEN(bank)) = 1 << pin;
        imx233_enable_interrupt(INT_SRC_GPIO(bank), true);
    }
}