static inline void hci_h4p_recv_frame(struct hci_h4p_info *info, struct sk_buff *skb) { if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) { NBT_DBG("fw_event\n"); hci_h4p_parse_fw_event(info, skb); } else { hci_recv_frame(skb); NBT_DBG("Frame sent to upper layer\n"); } }
static int hci_h4p_send_negotiation(struct hci_h4p_info *info, struct sk_buff *skb) { unsigned long flags; int err; NBT_DBG("Sending negotiation..\n"); hci_h4p_change_speed(info, INIT_SPEED); hci_h4p_set_rts(info, 1); info->init_error = 0; init_completion(&info->init_completion); skb_queue_tail(&info->txq, skb); spin_lock_irqsave(&info->lock, flags); hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_THRI); spin_unlock_irqrestore(&info->lock, flags); if (!wait_for_completion_interruptible_timeout(&info->init_completion, msecs_to_jiffies(1000))) return -ETIMEDOUT; if (info->init_error < 0) return info->init_error; /* Change to operational settings */ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS); hci_h4p_set_rts(info, 0); hci_h4p_change_speed(info, MAX_BAUD_RATE); err = hci_h4p_wait_for_cts(info, 1, 100); if (err < 0) return err; hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS); init_completion(&info->init_completion); err = hci_h4p_send_alive_packet(info); if (err < 0) return err; if (!wait_for_completion_interruptible_timeout(&info->init_completion, msecs_to_jiffies(1000))) return -ETIMEDOUT; if (info->init_error < 0) return info->init_error; NBT_DBG("Negotiation succesful\n"); return 0; }
static inline void brf6150_recv_frame(struct brf6150_info *info, struct sk_buff *skb) { if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) { NBT_DBG("fw_event\n"); brf6150_parse_fw_event(info); kfree_skb(skb); } else { hci_recv_frame(skb); if (!(brf6150_inb(info, UART_LSR) & UART_LSR_DR)) brf6150_enable_pm_rx(info); NBT_DBG("Frame sent to upper layer\n"); } }
static int brf6150_change_speed(struct brf6150_info *info, unsigned long speed) { unsigned int divisor; u8 lcr, mdr1; NBT_DBG("Setting speed %lu\n", speed); if (speed >= 460800) { divisor = UART_CLOCK / 13 / speed; mdr1 = 3; } else { divisor = UART_CLOCK / 16 / speed; mdr1 = 0; } brf6150_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */ lcr = brf6150_inb(info, UART_LCR); brf6150_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */ brf6150_outb(info, UART_DLL, divisor & 0xff); /* Set speed */ brf6150_outb(info, UART_DLM, divisor >> 8); brf6150_outb(info, UART_LCR, lcr); brf6150_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */ return 0; }
static void hci_h4p_rx_tasklet(unsigned long data) { u8 byte; struct hci_h4p_info *info = (struct hci_h4p_info *)data; NBT_DBG("tasklet woke up\n"); NBT_DBG_TRANSFER("rx_tasklet woke up\ndata "); while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) { byte = hci_h4p_inb(info, UART_RX); if (info->garbage_bytes) { info->garbage_bytes--; continue; } if (info->rx_skb == NULL) { info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC | GFP_DMA); if (!info->rx_skb) { dev_err(info->dev, "No memory for new packet\n"); goto finish_rx; } info->rx_state = WAIT_FOR_PKT_TYPE; info->rx_skb->dev = (void *)info->hdev; } info->hdev->stat.byte_rx++; NBT_DBG_TRANSFER_NF("0x%.2x ", byte); hci_h4p_handle_byte(info, byte); } if (!info->rx_enabled) { if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT && info->autorts) { __hci_h4p_set_auto_ctsrts(info, 0 , UART_EFR_RTS); info->autorts = 0; } /* Flush posted write to avoid spurious interrupts */ hci_h4p_inb(info, UART_OMAP_SCR); hci_h4p_set_clk(info, &info->rx_clocks_en, 0); } finish_rx: NBT_DBG_TRANSFER_NF("\n"); NBT_DBG("rx_ended\n"); }
static void brf6150_alive_packet(struct brf6150_info *info, struct sk_buff *skb) { NBT_DBG("Received alive packet\n"); if (skb->data[1] == 0xCC) { complete(&info->init_completion); } kfree_skb(skb); }
static int brf6150_send_alive_packet(struct brf6150_info *info) { struct sk_buff *skb; NBT_DBG("Sending alive packet\n"); skb = brf6150_read_fw_cmd(info, GFP_ATOMIC); if (!skb) { printk(KERN_WARNING "Cannot read alive command"); return -1; } clk_enable(info->uart_ck); skb_queue_tail(&info->txq, skb); tasklet_schedule(&info->tx_task); NBT_DBG("Alive packet sent\n"); return 0; }
static void hci_h4p_alive_packet(struct hci_h4p_info *info, struct sk_buff *skb) { NBT_DBG("Received alive packet\n"); if (skb->data[1] != 0xCC) { dev_err(info->dev, "Could not negotiate hci_h4p settings\n"); info->init_error = -EINVAL; } complete(&info->init_completion); kfree_skb(skb); }
static int brf6150_send_negotiation(struct brf6150_info *info) { struct sk_buff *skb; NBT_DBG("Sending negotiation..\n"); brf6150_change_speed(info, INIT_SPEED); skb = brf6150_read_fw_cmd(info, GFP_KERNEL); if (!skb) { printk(KERN_WARNING "Cannot read negoatiation message"); return -1; } clk_enable(info->uart_ck); skb_queue_tail(&info->txq, skb); tasklet_schedule(&info->tx_task); NBT_DBG("Negotiation sent\n"); return 0; }
/* Negotiation functions */ int hci_h4p_send_alive_packet(struct hci_h4p_info *info) { unsigned long flags; NBT_DBG("Sending alive packet\n"); if (!info->alive_cmd_skb) return -EINVAL; /* Keep reference to buffer so we can reuse it */ info->alive_cmd_skb = skb_get(info->alive_cmd_skb); skb_queue_tail(&info->txq, info->alive_cmd_skb); spin_lock_irqsave(&info->lock, flags); hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_THRI); spin_unlock_irqrestore(&info->lock, flags); NBT_DBG("Alive packet sent\n"); return 0; }
static int hci_h4p_hci_send_frame(struct sk_buff *skb) { struct hci_h4p_info *info; struct hci_dev *hdev = (struct hci_dev *)skb->dev; int err = 0; if (!hdev) { printk(KERN_WARNING "hci_h4p: Frame for unknown device\n"); return -ENODEV; } NBT_DBG("dev %p, skb %p\n", hdev, skb); info = hdev->driver_data; if (!test_bit(HCI_RUNNING, &hdev->flags)) { dev_warn(info->dev, "Frame for non-running device\n"); return -EIO; } switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: hdev->stat.acl_tx++; break; case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; } /* Push frame type to skb */ *skb_push(skb, 1) = (bt_cb(skb)->pkt_type); /* We should allways send word aligned data to h4+ devices */ if (skb->len % 2) { err = skb_pad(skb, 1); if (!err) *skb_put(skb, 1) = 0x00; } if (err) return err; skb_queue_tail(&info->txq, skb); hci_h4p_enable_tx(info); return 0; }
static irqreturn_t brf6150_interrupt(int irq, void *data) { struct brf6150_info *info = (struct brf6150_info *)data; u8 iir, msr; int ret; unsigned long flags; ret = IRQ_NONE; clk_enable(info->uart_ck); iir = brf6150_inb(info, UART_IIR); if (iir & UART_IIR_NO_INT) { printk("Interrupt but no reason irq 0x%.2x\n", iir); clk_disable(info->uart_ck); return IRQ_HANDLED; } NBT_DBG("In interrupt handler iir 0x%.2x\n", iir); iir &= UART_IIR_ID; if (iir == UART_IIR_MSI) { msr = brf6150_inb(info, UART_MSR); ret = IRQ_HANDLED; } if (iir == UART_IIR_RLSI) { brf6150_inb(info, UART_RX); brf6150_inb(info, UART_LSR); ret = IRQ_HANDLED; } if (iir == UART_IIR_RDI) { brf6150_rx(info); ret = IRQ_HANDLED; } if (iir == UART_IIR_THRI) { spin_lock_irqsave(&info->lock, flags); brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) & ~UART_IER_THRI); spin_unlock_irqrestore(&info->lock, flags); tasklet_schedule(&info->tx_task); ret = IRQ_HANDLED; } clk_disable(info->uart_ck); return ret; }
static irqreturn_t hci_h4p_interrupt(int irq, void *data) { struct hci_h4p_info *info = (struct hci_h4p_info *)data; u8 iir, msr; int ret; ret = IRQ_NONE; iir = hci_h4p_inb(info, UART_IIR); if (iir & UART_IIR_NO_INT) { return IRQ_HANDLED; } NBT_DBG("In interrupt handler iir 0x%.2x\n", iir); iir &= UART_IIR_ID; if (iir == UART_IIR_MSI) { msr = hci_h4p_inb(info, UART_MSR); ret = IRQ_HANDLED; } if (iir == UART_IIR_RLSI) { hci_h4p_inb(info, UART_RX); hci_h4p_inb(info, UART_LSR); ret = IRQ_HANDLED; } if (iir == UART_IIR_RDI) { hci_h4p_rx_tasklet((unsigned long)data); ret = IRQ_HANDLED; } if (iir == UART_IIR_THRI) { hci_h4p_tx_tasklet((unsigned long)data); ret = IRQ_HANDLED; } return ret; }
static int hci_h4p_probe(struct platform_device *pdev) { struct omap_bluetooth_config *bt_config; struct hci_h4p_info *info; int irq, err; dev_info(&pdev->dev, "Registering HCI H4P device\n"); info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL); if (!info) return -ENOMEM; info->dev = &pdev->dev; info->pm_enabled = 0; info->tx_enabled = 1; info->rx_enabled = 1; info->garbage_bytes = 0; info->tx_clocks_en = 0; info->rx_clocks_en = 0; irq = 0; spin_lock_init(&info->lock); spin_lock_init(&info->clocks_lock); skb_queue_head_init(&info->txq); if (pdev->dev.platform_data == NULL) { dev_err(&pdev->dev, "Could not get Bluetooth config data\n"); kfree(info); return -ENODATA; } bt_config = pdev->dev.platform_data; info->chip_type = bt_config->chip_type; info->bt_wakeup_gpio = bt_config->bt_wakeup_gpio; info->host_wakeup_gpio = bt_config->host_wakeup_gpio; info->reset_gpio = bt_config->reset_gpio; info->bt_sysclk = bt_config->bt_sysclk; NBT_DBG("RESET gpio: %d\n", info->reset_gpio); NBT_DBG("BTWU gpio: %d\n", info->bt_wakeup_gpio); NBT_DBG("HOSTWU gpio: %d\n", info->host_wakeup_gpio); NBT_DBG("Uart: %d\n", bt_config->bt_uart); NBT_DBG("sysclk: %d\n", info->bt_sysclk); err = gpio_request(info->reset_gpio, "bt_reset"); if (err < 0) { dev_err(&pdev->dev, "Cannot get GPIO line %d\n", info->reset_gpio); goto cleanup_setup; } err = gpio_request(info->bt_wakeup_gpio, "bt_wakeup"); if (err < 0) { dev_err(info->dev, "Cannot get GPIO line 0x%d", info->bt_wakeup_gpio); gpio_free(info->reset_gpio); goto cleanup_setup; } err = gpio_request(info->host_wakeup_gpio, "host_wakeup"); if (err < 0) { dev_err(info->dev, "Cannot get GPIO line %d", info->host_wakeup_gpio); gpio_free(info->reset_gpio); gpio_free(info->bt_wakeup_gpio); goto cleanup_setup; } gpio_direction_output(info->reset_gpio, 0); gpio_direction_output(info->bt_wakeup_gpio, 0); gpio_direction_input(info->host_wakeup_gpio); switch (bt_config->bt_uart) { case 1: if (cpu_is_omap16xx()) { irq = INT_UART1; info->uart_fclk = clk_get(NULL, "uart1_ck"); } else if (cpu_is_omap24xx()) { irq = INT_24XX_UART1_IRQ; info->uart_iclk = clk_get(NULL, "uart1_ick"); info->uart_fclk = clk_get(NULL, "uart1_fck"); } info->uart_base = OMAP2_IO_ADDRESS(OMAP_UART1_BASE); break; case 2: if (cpu_is_omap16xx()) { irq = INT_UART2; info->uart_fclk = clk_get(NULL, "uart2_ck"); } else { irq = INT_24XX_UART2_IRQ; info->uart_iclk = clk_get(NULL, "uart2_ick"); info->uart_fclk = clk_get(NULL, "uart2_fck"); } info->uart_base = OMAP2_IO_ADDRESS(OMAP_UART2_BASE); break; case 3: if (cpu_is_omap16xx()) { irq = INT_UART3; info->uart_fclk = clk_get(NULL, "uart3_ck"); } else { irq = INT_24XX_UART3_IRQ; info->uart_iclk = clk_get(NULL, "uart3_ick"); info->uart_fclk = clk_get(NULL, "uart3_fck"); } info->uart_base = OMAP2_IO_ADDRESS(OMAP_UART3_BASE); break; default: dev_err(info->dev, "No uart defined\n"); goto cleanup; } info->irq = irq; err = request_irq(irq, hci_h4p_interrupt, IRQF_DISABLED, "hci_h4p", info); if (err < 0) { dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", irq); goto cleanup; } err = request_irq(gpio_to_irq(info->host_wakeup_gpio), hci_h4p_wakeup_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_DISABLED, "hci_h4p_wkup", info); if (err < 0) { dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n", gpio_to_irq(info->host_wakeup_gpio)); free_irq(irq, info); goto cleanup; } err = set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1); if (err < 0) { dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n", gpio_to_irq(info->host_wakeup_gpio)); free_irq(irq, info); free_irq(gpio_to_irq(info->host_wakeup_gpio), info); goto cleanup; } init_timer_deferrable(&info->lazy_release); info->lazy_release.function = hci_h4p_lazy_clock_release; info->lazy_release.data = (unsigned long)info; hci_h4p_set_clk(info, &info->tx_clocks_en, 1); err = hci_h4p_reset_uart(info); if (err < 0) goto cleanup_irq; hci_h4p_init_uart(info); hci_h4p_set_rts(info, 0); err = hci_h4p_reset(info); hci_h4p_reset_uart(info); if (err < 0) goto cleanup_irq; gpio_set_value(info->reset_gpio, 0); hci_h4p_set_clk(info, &info->tx_clocks_en, 0); platform_set_drvdata(pdev, info); if (hci_h4p_register_hdev(info) < 0) { dev_err(info->dev, "failed to register hci_h4p hci device\n"); goto cleanup_irq; } return 0; cleanup_irq: free_irq(irq, (void *)info); free_irq(gpio_to_irq(info->host_wakeup_gpio), info); cleanup: gpio_set_value(info->reset_gpio, 0); gpio_free(info->reset_gpio); gpio_free(info->bt_wakeup_gpio); gpio_free(info->host_wakeup_gpio); cleanup_setup: kfree(info); return err; }
static int hci_h4p_hci_open(struct hci_dev *hdev) { struct hci_h4p_info *info; int err; struct sk_buff *neg_cmd_skb; struct sk_buff_head fw_queue; unsigned long flags; info = hdev->driver_data; if (test_bit(HCI_RUNNING, &hdev->flags)) return 0; skb_queue_head_init(&fw_queue); err = hci_h4p_read_fw(info, &fw_queue); if (err < 0) { dev_err(info->dev, "Cannot read firmware\n"); return err; } neg_cmd_skb = skb_dequeue(&fw_queue); if (!neg_cmd_skb) { err = -EPROTO; goto err_clean; } info->alive_cmd_skb = skb_dequeue(&fw_queue); if (!info->alive_cmd_skb) { err = -EPROTO; goto err_clean; } info->rx_enabled = 1; info->rx_state = WAIT_FOR_PKT_TYPE; info->rx_count = 0; info->garbage_bytes = 0; info->rx_skb = NULL; info->pm_enabled = 0; init_completion(&info->fw_completion); hci_h4p_set_clk(info, &info->tx_clocks_en, 1); hci_h4p_set_clk(info, &info->rx_clocks_en, 1); err = hci_h4p_reset(info); if (err < 0) goto err_clean; hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS); info->autorts = 1; err = hci_h4p_send_negotiation(info, neg_cmd_skb); neg_cmd_skb = NULL; if (err < 0) goto err_clean; err = hci_h4p_send_fw(info, &fw_queue); if (err < 0) { dev_err(info->dev, "Sending firmware failed.\n"); goto err_clean; } info->pm_enabled = 1; spin_lock_irqsave(&info->lock, flags); info->rx_enabled = gpio_get_value(info->host_wakeup_gpio); hci_h4p_set_clk(info, &info->rx_clocks_en, info->rx_enabled); spin_unlock_irqrestore(&info->lock, flags); hci_h4p_set_clk(info, &info->tx_clocks_en, 0); kfree_skb(info->alive_cmd_skb); info->alive_cmd_skb = NULL; set_bit(HCI_RUNNING, &hdev->flags); NBT_DBG("hci up and running\n"); return 0; err_clean: hci_h4p_hci_flush(hdev); hci_h4p_reset_uart(info); del_timer_sync(&info->lazy_release); hci_h4p_set_clk(info, &info->tx_clocks_en, 0); hci_h4p_set_clk(info, &info->rx_clocks_en, 0); gpio_set_value(info->reset_gpio, 0); gpio_set_value(info->bt_wakeup_gpio, 0); skb_queue_purge(&fw_queue); kfree_skb(neg_cmd_skb); neg_cmd_skb = NULL; kfree_skb(info->alive_cmd_skb); info->alive_cmd_skb = NULL; kfree_skb(info->rx_skb); return err; }
static void hci_h4p_tx_tasklet(unsigned long data) { unsigned int sent = 0; struct sk_buff *skb; struct hci_h4p_info *info = (struct hci_h4p_info *)data; NBT_DBG("tasklet woke up\n"); NBT_DBG_TRANSFER("tx_tasklet woke up\n data "); if (info->autorts != info->rx_enabled) { if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) { if (info->autorts && !info->rx_enabled) { __hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS); info->autorts = 0; } if (!info->autorts && info->rx_enabled) { __hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS); info->autorts = 1; } } else { hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) | UART_OMAP_SCR_EMPTY_THR); goto finish_tx; } } skb = skb_dequeue(&info->txq); if (!skb) { /* No data in buffer */ NBT_DBG("skb ready\n"); if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) { hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_THRI); hci_h4p_inb(info, UART_OMAP_SCR); hci_h4p_disable_tx(info); return; } else hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) | UART_OMAP_SCR_EMPTY_THR); goto finish_tx; } /* Copy data to tx fifo */ while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) && (sent < skb->len)) { NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]); hci_h4p_outb(info, UART_TX, skb->data[sent]); sent++; } info->hdev->stat.byte_tx += sent; NBT_DBG_TRANSFER_NF("\n"); if (skb->len == sent) { kfree_skb(skb); } else { skb_pull(skb, sent); skb_queue_head(&info->txq, skb); } hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) & ~UART_OMAP_SCR_EMPTY_THR); hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_THRI); finish_tx: /* Flush posted write to avoid spurious interrupts */ hci_h4p_inb(info, UART_OMAP_SCR); }
static int __init brf6150_init(void) { struct brf6150_info *info; int irq, err; info = kmalloc(sizeof(struct brf6150_info), GFP_KERNEL); if (!info) return -ENOMEM; memset(info, 0, sizeof(struct brf6150_info)); brf6150_device.dev.driver_data = info; init_completion(&info->init_completion); init_completion(&info->fw_completion); info->pm_enabled = 0; info->rx_pm_enabled = 0; info->tx_pm_enabled = 0; info->garbage_bytes = 0; tasklet_init(&info->tx_task, brf6150_tx_tasklet, (unsigned long)info); spin_lock_init(&info->lock); skb_queue_head_init(&info->txq); init_timer(&info->pm_timer); info->pm_timer.function = brf6150_pm_timer; info->pm_timer.data = (unsigned long)info; exit_info = NULL; info->btinfo = omap_get_config(OMAP_TAG_NOKIA_BT, struct omap_bluetooth_config); if (info->btinfo == NULL) return -1; NBT_DBG("RESET gpio: %d\n", info->btinfo->reset_gpio); NBT_DBG("BTWU gpio: %d\n", info->btinfo->bt_wakeup_gpio); NBT_DBG("HOSTWU gpio: %d\n", info->btinfo->host_wakeup_gpio); NBT_DBG("Uart: %d\n", info->btinfo->bt_uart); NBT_DBG("sysclk: %d\n", info->btinfo->bt_sysclk); err = omap_request_gpio(info->btinfo->reset_gpio); if (err < 0) { printk(KERN_WARNING "Cannot get GPIO line %d", info->btinfo->reset_gpio); kfree(info); return err; } err = omap_request_gpio(info->btinfo->bt_wakeup_gpio); if (err < 0) { printk(KERN_WARNING "Cannot get GPIO line 0x%d", info->btinfo->bt_wakeup_gpio); omap_free_gpio(info->btinfo->reset_gpio); kfree(info); return err; } err = omap_request_gpio(info->btinfo->host_wakeup_gpio); if (err < 0) { printk(KERN_WARNING "Cannot get GPIO line %d", info->btinfo->host_wakeup_gpio); omap_free_gpio(info->btinfo->reset_gpio); omap_free_gpio(info->btinfo->bt_wakeup_gpio); kfree(info); return err; } omap_set_gpio_direction(info->btinfo->reset_gpio, 0); omap_set_gpio_direction(info->btinfo->bt_wakeup_gpio, 0); omap_set_gpio_direction(info->btinfo->host_wakeup_gpio, 1); set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE); switch (info->btinfo->bt_uart) { case 1: irq = INT_UART1; info->uart_ck = clk_get(NULL, "uart1_ck"); /* FIXME: Use platform_get_resource for the port */ info->uart_base = ioremap(OMAP_UART1_BASE, 0x16); if (!info->uart_base) goto cleanup; break; case 2: irq = INT_UART2; info->uart_ck = clk_get(NULL, "uart2_ck"); /* FIXME: Use platform_get_resource for the port */ info->uart_base = ioremap(OMAP_UART2_BASE, 0x16); if (!info->uart_base) goto cleanup; break; case 3: irq = INT_UART3; info->uart_ck = clk_get(NULL, "uart3_ck"); /* FIXME: Use platform_get_resource for the port */ info->uart_base = ioremap(OMAP_UART3_BASE, 0x16); if (!info->uart_base) goto cleanup; break; default: printk(KERN_ERR "No uart defined\n"); goto cleanup; } info->irq = irq; err = request_irq(irq, brf6150_interrupt, 0, "brf6150", (void *)info); if (err < 0) { printk(KERN_ERR "brf6150: unable to get IRQ %d\n", irq); goto cleanup; } err = request_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), brf6150_wakeup_interrupt, 0, "brf6150_wkup", (void *)info); if (err < 0) { printk(KERN_ERR "brf6150: unable to get wakeup IRQ %d\n", OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio)); free_irq(irq, (void *)info); goto cleanup; } /* Register with LDM */ if (platform_device_register(&brf6150_device)) { printk(KERN_ERR "failed to register brf6150 device\n"); err = -ENODEV; goto cleanup_irq; } /* Register the driver with LDM */ if (driver_register(&brf6150_driver)) { printk(KERN_WARNING "failed to register brf6150 driver\n"); platform_device_unregister(&brf6150_device); err = -ENODEV; goto cleanup_irq; } if (brf6150_register_hdev(info) < 0) { printk(KERN_WARNING "failed to register brf6150 hci device\n"); platform_device_unregister(&brf6150_device); driver_unregister(&brf6150_driver); goto cleanup_irq; } exit_info = info; return 0; cleanup_irq: free_irq(irq, (void *)info); free_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), (void *)info); cleanup: omap_free_gpio(info->btinfo->reset_gpio); omap_free_gpio(info->btinfo->bt_wakeup_gpio); omap_free_gpio(info->btinfo->host_wakeup_gpio); kfree(info); return err; }