static void gpio_ack_irq(unsigned int irq) { unsigned int gpio_irq = irq - IRQ_COUNT; unsigned long flags; hw_raw_local_irq_save ( flags ); __raw_writel( ~(1<< gpio_irq), EXTINT_STATUS_REG); hw_raw_local_irq_restore ( flags ); }
int pnx_gpio_clear_irq(unsigned int irq) { unsigned int gpio_irq; unsigned long flags; gpio_irq = irq - IRQ_COUNT; if (!check_gpio_irq(gpio_irq)) return -EINVAL; hw_raw_local_irq_save ( flags ); __raw_writel( ~(1<< gpio_irq), EXTINT_STATUS_REG); hw_raw_local_irq_restore ( flags ); return 0; }
/* * PNX EXTINT : only EXTINT 3 is managed by Linux * We need to unmask the GPIO bank interrupt as soon as possible to * avoid missing GPIO interrupts for other lines in the bank. * Then we need to mask-read-clear-unmask the triggered GPIO lines * in the bank to avoid missing nested interrupts for a GPIO line. * If we wait to unmask individual GPIO lines in the bank after the * line's interrupt handler has been run, we may miss some nested * interrupts. */ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { unsigned long isr; unsigned long flags; unsigned int gpio_irq; /* LPA TBD */ desc->chip->ack(irq); /* read status */ hw_raw_local_irq_save ( flags ); isr = __raw_readl(EXTINT_STATUS_REG) & __raw_readl(EXTINT_ENABLE3_REG); /* clear IRQ source(s)*/ __raw_writel(~isr, EXTINT_STATUS_REG); hw_raw_local_irq_restore ( flags ); gpio_irq = IRQ_COUNT; for (; isr != 0; isr >>= 1, gpio_irq++) { struct irq_desc *d; if (!(isr & 1)) continue; d = irq_desc + gpio_irq; #ifdef CONFIG_DEBUG_EXTINT printk(KERN_ERR "got something from EXTINT#%i line\n", gpio_irq - IRQ_COUNT); #endif desc_handle_irq(gpio_irq, d); } #ifdef CONFIG_NKERNEL /* * interrupt forwarding routine of osware masks INTC_IID_EXT2 * so we have to unmask it after irq handling */ hw_raw_local_irq_save ( flags ); __raw_writel((1<<26 | 1<<16), INTC_REQUESTx(IRQ_EXTINT3)); hw_raw_local_irq_restore ( flags ); #endif }
static void p9_xos_flow(unsigned int event, void *cookie) { struct p9_xos_driver *drv = cookie; struct p9_xos_endpoint *ep; unsigned long flags; long int state = 0; prolog("e=%u c=%p", event, cookie); hw_raw_local_irq_save(flags); BUG_ON(event != 0); /* get empty packets */ ep = &drv->ep[WR_EP]; p9_xos_deque_move(ep->lqueue, &ep->regs[LHEAD], ep); if (ep->regs[STARVATION]) { /* Linux needs empty packets */ ep->regs[STARVATION] = 0; set_bit(MUST_WRITE, &state); } /* get data */ ep = &drv->ep[RD_EP]; p9_xos_deque_move(ep->lqueue, &ep->regs[LHEAD], ep); if (ep->regs[STARVATION]) { /* RTK needs empty packets */ drv->wake_status = 2; set_bit(MUST_SYNC, &state); } if (deque_head(ep->lqueue) != deque_null) { drv->wake_status = 2; set_bit(MUST_READ, &state); } hw_raw_local_irq_restore(flags); if (test_bit(MUST_SYNC, &state)) queue_work(drv->workqueue, &drv->swork); if (test_bit(MUST_WRITE, &state)) queue_work(drv->workqueue, &drv->wwork); if (test_bit(MUST_READ, &state)) queue_work(drv->workqueue, &drv->rwork); if (drv->wake_status == 2) wake_lock(&drv->wake_lock); epilog(); }
static void p9_xos_sync_work(struct work_struct *work) { struct p9_xos_driver *drv; struct p9_xos_endpoint *ep; unsigned long flags; prolog("w=%p", work); drv = container_of(work, struct p9_xos_driver, swork); /* send data */ ep = &drv->ep[WR_EP]; hw_raw_local_irq_save(flags); p9_xos_deque_move(&ep->regs[RHEAD], ep->rqueue, ep); hw_raw_local_irq_restore(flags); /* send empty packets if needed */ ep = &drv->ep[RD_EP]; if (nb_free_packets >= MIN_PACKETS_TO_RELEASE || ep->regs[STARVATION]) { nb_free_packets = 0; hw_raw_local_irq_save(flags); p9_xos_deque_move(&ep->regs[RHEAD], ep->rqueue, ep); hw_raw_local_irq_restore(flags); } xos_ctrl_raise(drv->ctrl, P9_XOS_EVENT); if ((!drv->wake_count) && (drv->wake_status == 1)) { drv->wake_status = 0; wake_unlock(&drv->wake_lock); wmb(); if (drv->wake_status == 2) wake_lock(&drv->wake_lock); } epilog(); }
static void _write_gpio_pin(struct gpio_bank *bank, int gpio, int gpio_value) { void __iomem *reg = bank->gpio_base; unsigned long flags; unsigned long l = 0; reg += PNX_GPIO_OUTPUT_OFFSET; hw_raw_local_irq_save(flags); l = __raw_readl(reg); if (gpio_value) l |= 1 << gpio; else l &= ~(1 << gpio); __raw_writel(l, reg); hw_raw_local_irq_restore(flags); }
static void _set_gpio_mode(struct gpio_bank *bank, int gpio, int mode) { void __iomem *reg = bank->mux_base; unsigned long flags; unsigned long l; /* select direction register */ if(gpio >= 16) { reg += PNX_MUX2_OFFSET; gpio -= 16; } hw_raw_local_irq_save(flags); /* apply mux mode */ /* width 2 bit */ l = __raw_readl(reg); l &= ~(3 << (gpio * 2)); l |= (mode << (gpio * 2)); __raw_writel(l, reg); hw_raw_local_irq_restore(flags); }
static int __init pnx_gpio_probe(struct platform_device *pdev) { int i,j; int gpio = 0; struct gpio_bank *bank; struct gpio_data *data = pdev->dev.platform_data; unsigned long flags; initialized = 1; printk(KERN_INFO "PNX GPIO\n"); gpio_bank_desc = data->gpio_bank_desc; gpio_bank_count = data->nb_banks; for (i = 0; i < gpio_bank_count; i++) { int gpio_count = 32; /* 32 GPIO per bank */ bank = &gpio_bank_desc[i]; bank->reserved_map = 0; /* must always be initialized */ spin_lock_init(&bank->lock); /* check if bank is managed by PNX GPIO driver */ if ((bank->gpio_base != 0) && (bank->mux_base != 0)) { bank->chip.request = pnx_gpio_acquire; bank->chip.free = pnx_gpio_release; bank->chip.direction_input = gpio_input; bank->chip.get = gpio_get; bank->chip.direction_output = gpio_output; bank->chip.set = gpio_set; bank->chip.to_irq = gpio_2irq; bank->chip.label = "gpio"; bank->chip.base = gpio; bank->chip.ngpio = gpio_count; gpiochip_add(&bank->chip); } gpio += gpio_count; } #ifdef CONFIG_MODEM_BLACK_BOX /* set init value */ printk(KERN_INFO "PNX GPIO initialize SCON\n"); /* configure MUX and PAD settings */ for (i = 0; i< SCON_REGISTER_NB; i++) __raw_writel(pnx_scon_init_config[i].scon_reg_value, pnx_scon_init_config[i].scon_reg_addr); /* configure GPIO direction and value */ for (i=0; i < gpio_to_configure; i++) { int index; bank = get_gpio_bank(pnx_gpio_init_config[i].gpio); index = get_gpio_index(pnx_gpio_init_config[i].gpio); _set_gpio_direction(bank, index, pnx_gpio_init_config[i].dir); _write_gpio_pin(bank, index, pnx_gpio_init_config[i].value); } /* reserve GPIO used by Modem */ for (i = 0; i < pnx_modem_gpio_reserved_nb; i++) { int index; bank = get_gpio_bank(pnx_modem_gpio_reserved[i]); index = get_gpio_index(pnx_modem_gpio_reserved[i]); bank->reserved_map |= (1 << index); } /* configure EXTINT used by modem */ for (i = 0; i< pnx_modem_extint_nb; i++) __raw_writel(pnx_extint_init_config[i].reg_value, pnx_extint_init_config[i].reg_addr); printk(KERN_INFO "PNX GPIO Driver\n"); #endif /* for extint */ for (j = IRQ_COUNT; j < IRQ_COUNT + NR_EXTINT; j++) { set_irq_chip(j, &gpio_irq_chip); set_irq_handler(j, handle_simple_irq); set_irq_flags(j, IRQF_VALID); } hw_raw_local_irq_save ( flags ); /* mask all EXT IRQ sources before registring handler */ /* read status */ j = __raw_readl(EXTINT_STATUS_REG) & __raw_readl(EXTINT_ENABLE3_REG); /* clear IRQ source(s)*/ __raw_writel(j, EXTINT_STATUS_REG); __raw_writel(0, EXTINT_ENABLE3_REG); /* set irq in low level */ set_irq_type(IRQ_EXTINT3, IRQF_TRIGGER_LOW); /* chained GPIO-IRQ on EXTINT3 */ set_irq_chained_handler(IRQ_EXTINT3, gpio_irq_handler); hw_raw_local_irq_restore ( flags ); return 0; }