aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth/btmrvl_sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/btmrvl_sdio.c')
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c103
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};
68static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { 69static 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
85static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { 87static 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
102static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { 107static 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
670static void btmrvl_sdio_interrupt(struct sdio_func *func) 675static 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); 692static 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
722static 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);