diff options
Diffstat (limited to 'drivers/bluetooth/btmrvl_sdio.c')
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 103 |
1 files changed, 82 insertions, 21 deletions
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 1b52c9f5230d..9dedca516ff5 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c | |||
@@ -64,6 +64,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = { | |||
64 | .io_port_0 = 0x00, | 64 | .io_port_0 = 0x00, |
65 | .io_port_1 = 0x01, | 65 | .io_port_1 = 0x01, |
66 | .io_port_2 = 0x02, | 66 | .io_port_2 = 0x02, |
67 | .int_read_to_clear = false, | ||
67 | }; | 68 | }; |
68 | static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { | 69 | static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { |
69 | .cfg = 0x00, | 70 | .cfg = 0x00, |
@@ -80,6 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { | |||
80 | .io_port_0 = 0x78, | 81 | .io_port_0 = 0x78, |
81 | .io_port_1 = 0x79, | 82 | .io_port_1 = 0x79, |
82 | .io_port_2 = 0x7a, | 83 | .io_port_2 = 0x7a, |
84 | .int_read_to_clear = false, | ||
83 | }; | 85 | }; |
84 | 86 | ||
85 | static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { | 87 | static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { |
@@ -97,6 +99,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { | |||
97 | .io_port_0 = 0xd8, | 99 | .io_port_0 = 0xd8, |
98 | .io_port_1 = 0xd9, | 100 | .io_port_1 = 0xd9, |
99 | .io_port_2 = 0xda, | 101 | .io_port_2 = 0xda, |
102 | .int_read_to_clear = true, | ||
103 | .host_int_rsr = 0x01, | ||
104 | .card_misc_cfg = 0xcc, | ||
100 | }; | 105 | }; |
101 | 106 | ||
102 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { | 107 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { |
@@ -667,46 +672,78 @@ static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv) | |||
667 | return 0; | 672 | return 0; |
668 | } | 673 | } |
669 | 674 | ||
670 | static void btmrvl_sdio_interrupt(struct sdio_func *func) | 675 | static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg) |
671 | { | 676 | { |
672 | struct btmrvl_private *priv; | 677 | struct btmrvl_adapter *adapter = card->priv->adapter; |
673 | struct btmrvl_sdio_card *card; | ||
674 | ulong flags; | ||
675 | u8 ireg = 0; | ||
676 | int ret; | 678 | int ret; |
677 | 679 | ||
678 | card = sdio_get_drvdata(func); | 680 | ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE); |
679 | if (!card || !card->priv) { | 681 | if (ret) { |
680 | BT_ERR("sbi_interrupt(%p) card or priv is " | 682 | BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret); |
681 | "NULL, card=%p\n", func, card); | 683 | return ret; |
682 | return; | ||
683 | } | 684 | } |
684 | 685 | ||
685 | priv = card->priv; | 686 | *ireg = adapter->hw_regs[card->reg->host_intstatus]; |
687 | BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg); | ||
688 | |||
689 | return 0; | ||
690 | } | ||
686 | 691 | ||
687 | ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); | 692 | static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg) |
693 | { | ||
694 | int ret; | ||
695 | |||
696 | *ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); | ||
688 | if (ret) { | 697 | if (ret) { |
689 | BT_ERR("sdio_readb: read int status register failed"); | 698 | BT_ERR("sdio_readb: read int status failed: %d", ret); |
690 | return; | 699 | return ret; |
691 | } | 700 | } |
692 | 701 | ||
693 | if (ireg != 0) { | 702 | if (*ireg) { |
694 | /* | 703 | /* |
695 | * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS | 704 | * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS |
696 | * Clear the interrupt status register and re-enable the | 705 | * Clear the interrupt status register and re-enable the |
697 | * interrupt. | 706 | * interrupt. |
698 | */ | 707 | */ |
699 | BT_DBG("ireg = 0x%x", ireg); | 708 | BT_DBG("int_status = 0x%x", *ireg); |
700 | 709 | ||
701 | sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | | 710 | sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS | |
702 | UP_LD_HOST_INT_STATUS), | 711 | UP_LD_HOST_INT_STATUS), |
703 | card->reg->host_intstatus, &ret); | 712 | card->reg->host_intstatus, &ret); |
704 | if (ret) { | 713 | if (ret) { |
705 | BT_ERR("sdio_writeb: clear int status register failed"); | 714 | BT_ERR("sdio_writeb: clear int status failed: %d", ret); |
706 | return; | 715 | return ret; |
707 | } | 716 | } |
708 | } | 717 | } |
709 | 718 | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static void btmrvl_sdio_interrupt(struct sdio_func *func) | ||
723 | { | ||
724 | struct btmrvl_private *priv; | ||
725 | struct btmrvl_sdio_card *card; | ||
726 | ulong flags; | ||
727 | u8 ireg = 0; | ||
728 | int ret; | ||
729 | |||
730 | card = sdio_get_drvdata(func); | ||
731 | if (!card || !card->priv) { | ||
732 | BT_ERR("sbi_interrupt(%p) card or priv is " | ||
733 | "NULL, card=%p\n", func, card); | ||
734 | return; | ||
735 | } | ||
736 | |||
737 | priv = card->priv; | ||
738 | |||
739 | if (card->reg->int_read_to_clear) | ||
740 | ret = btmrvl_sdio_read_to_clear(card, &ireg); | ||
741 | else | ||
742 | ret = btmrvl_sdio_write_to_clear(card, &ireg); | ||
743 | |||
744 | if (ret) | ||
745 | return; | ||
746 | |||
710 | spin_lock_irqsave(&priv->driver_lock, flags); | 747 | spin_lock_irqsave(&priv->driver_lock, flags); |
711 | sdio_ireg |= ireg; | 748 | sdio_ireg |= ireg; |
712 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 749 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
@@ -777,6 +814,30 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) | |||
777 | 814 | ||
778 | BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport); | 815 | BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport); |
779 | 816 | ||
817 | if (card->reg->int_read_to_clear) { | ||
818 | reg = sdio_readb(func, card->reg->host_int_rsr, &ret); | ||
819 | if (ret < 0) { | ||
820 | ret = -EIO; | ||
821 | goto release_irq; | ||
822 | } | ||
823 | sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret); | ||
824 | if (ret < 0) { | ||
825 | ret = -EIO; | ||
826 | goto release_irq; | ||
827 | } | ||
828 | |||
829 | reg = sdio_readb(func, card->reg->card_misc_cfg, &ret); | ||
830 | if (ret < 0) { | ||
831 | ret = -EIO; | ||
832 | goto release_irq; | ||
833 | } | ||
834 | sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret); | ||
835 | if (ret < 0) { | ||
836 | ret = -EIO; | ||
837 | goto release_irq; | ||
838 | } | ||
839 | } | ||
840 | |||
780 | sdio_set_drvdata(func, card); | 841 | sdio_set_drvdata(func, card); |
781 | 842 | ||
782 | sdio_release_host(func); | 843 | sdio_release_host(func); |