diff options
Diffstat (limited to 'drivers/pcmcia/ti113x.h')
-rw-r--r-- | drivers/pcmcia/ti113x.h | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index a8a1d104524a..c7ba99871aca 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h | |||
@@ -611,6 +611,170 @@ out: | |||
611 | } | 611 | } |
612 | } | 612 | } |
613 | 613 | ||
614 | |||
615 | /* Returns true value if the second slot of a two-slot controller is empty */ | ||
616 | static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) | ||
617 | { | ||
618 | struct pci_dev *func; | ||
619 | struct yenta_socket *slot2; | ||
620 | int devfn; | ||
621 | unsigned int state; | ||
622 | int ret = 1; | ||
623 | |||
624 | /* catch the two-slot controllers */ | ||
625 | switch (socket->dev->device) { | ||
626 | case PCI_DEVICE_ID_TI_1220: | ||
627 | case PCI_DEVICE_ID_TI_1221: | ||
628 | case PCI_DEVICE_ID_TI_1225: | ||
629 | case PCI_DEVICE_ID_TI_1251A: | ||
630 | case PCI_DEVICE_ID_TI_1251B: | ||
631 | case PCI_DEVICE_ID_TI_1420: | ||
632 | case PCI_DEVICE_ID_TI_1450: | ||
633 | case PCI_DEVICE_ID_TI_1451A: | ||
634 | case PCI_DEVICE_ID_TI_1520: | ||
635 | case PCI_DEVICE_ID_TI_1620: | ||
636 | case PCI_DEVICE_ID_TI_4520: | ||
637 | case PCI_DEVICE_ID_TI_4450: | ||
638 | case PCI_DEVICE_ID_TI_4451: | ||
639 | /* | ||
640 | * there are way more, but they need to be added in yenta_socket.c | ||
641 | * and pci_ids.h first anyway. | ||
642 | */ | ||
643 | break; | ||
644 | |||
645 | /* single-slot controllers have the 2nd slot empty always :) */ | ||
646 | default: | ||
647 | return 1; | ||
648 | } | ||
649 | |||
650 | /* get other slot */ | ||
651 | devfn = socket->dev->devfn & ~0x07; | ||
652 | func = pci_get_slot(socket->dev->bus, | ||
653 | (socket->dev->devfn & 0x07) ? devfn : devfn | 0x01); | ||
654 | if (!func) | ||
655 | return 1; | ||
656 | |||
657 | slot2 = pci_get_drvdata(func); | ||
658 | if (!slot2) | ||
659 | goto out; | ||
660 | |||
661 | /* check state */ | ||
662 | yenta_get_status(&socket->socket, &state); | ||
663 | if (state & SS_DETECT) { | ||
664 | ret = 0; | ||
665 | goto out; | ||
666 | } | ||
667 | |||
668 | out: | ||
669 | pci_dev_put(func); | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | /* | ||
674 | * TI specifiy parts for the power hook. | ||
675 | * | ||
676 | * some TI's with some CB's produces interrupt storm on power on. it has been | ||
677 | * seen with atheros wlan cards on TI1225 and TI1410. solution is simply to | ||
678 | * disable any CB interrupts during this time. | ||
679 | */ | ||
680 | static int ti12xx_power_hook(struct pcmcia_socket *sock, int operation) | ||
681 | { | ||
682 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
683 | u32 mfunc, devctl, sysctl; | ||
684 | u8 gpio3; | ||
685 | |||
686 | /* only POWER_PRE and POWER_POST are interesting */ | ||
687 | if ((operation != HOOK_POWER_PRE) && (operation != HOOK_POWER_POST)) | ||
688 | return 0; | ||
689 | |||
690 | devctl = config_readb(socket, TI113X_DEVICE_CONTROL); | ||
691 | sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); | ||
692 | mfunc = config_readl(socket, TI122X_MFUNC); | ||
693 | |||
694 | /* | ||
695 | * all serial/tied: only disable when modparm set. always doing it | ||
696 | * would mean a regression for working setups 'cos it disables the | ||
697 | * interrupts for both both slots on 2-slot controllers | ||
698 | * (and users of single slot controllers where it's save have to | ||
699 | * live with setting the modparm, most don't have to anyway) | ||
700 | */ | ||
701 | if (((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) && | ||
702 | (pwr_irqs_off || ti12xx_2nd_slot_empty(socket))) { | ||
703 | switch (socket->dev->device) { | ||
704 | case PCI_DEVICE_ID_TI_1250: | ||
705 | case PCI_DEVICE_ID_TI_1251A: | ||
706 | case PCI_DEVICE_ID_TI_1251B: | ||
707 | case PCI_DEVICE_ID_TI_1450: | ||
708 | case PCI_DEVICE_ID_TI_1451A: | ||
709 | case PCI_DEVICE_ID_TI_4450: | ||
710 | case PCI_DEVICE_ID_TI_4451: | ||
711 | /* these chips have no IRQSER setting in MFUNC3 */ | ||
712 | break; | ||
713 | |||
714 | default: | ||
715 | if (operation == HOOK_POWER_PRE) | ||
716 | mfunc = (mfunc & ~TI122X_MFUNC3_MASK); | ||
717 | else | ||
718 | mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER; | ||
719 | } | ||
720 | |||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | /* do the job differently for func0/1 */ | ||
725 | if ((PCI_FUNC(socket->dev->devfn) == 0) || | ||
726 | ((sysctl & TI122X_SCR_INTRTIE) && | ||
727 | (pwr_irqs_off || ti12xx_2nd_slot_empty(socket)))) { | ||
728 | /* some bridges are different */ | ||
729 | switch (socket->dev->device) { | ||
730 | case PCI_DEVICE_ID_TI_1250: | ||
731 | case PCI_DEVICE_ID_TI_1251A: | ||
732 | case PCI_DEVICE_ID_TI_1251B: | ||
733 | case PCI_DEVICE_ID_TI_1450: | ||
734 | /* those oldies use gpio3 for INTA */ | ||
735 | gpio3 = config_readb(socket, TI1250_GPIO3_CONTROL); | ||
736 | if (operation == HOOK_POWER_PRE) | ||
737 | gpio3 = (gpio3 & ~TI1250_GPIO_MODE_MASK) | 0x40; | ||
738 | else | ||
739 | gpio3 &= ~TI1250_GPIO_MODE_MASK; | ||
740 | config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3); | ||
741 | break; | ||
742 | |||
743 | default: | ||
744 | /* all new bridges are the same */ | ||
745 | if (operation == HOOK_POWER_PRE) | ||
746 | mfunc &= ~TI122X_MFUNC0_MASK; | ||
747 | else | ||
748 | mfunc |= TI122X_MFUNC0_INTA; | ||
749 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
750 | } | ||
751 | } else { | ||
752 | switch (socket->dev->device) { | ||
753 | case PCI_DEVICE_ID_TI_1251A: | ||
754 | case PCI_DEVICE_ID_TI_1251B: | ||
755 | case PCI_DEVICE_ID_TI_1450: | ||
756 | /* those have INTA elsewhere and INTB in MFUNC0 */ | ||
757 | if (operation == HOOK_POWER_PRE) | ||
758 | mfunc &= ~TI122X_MFUNC0_MASK; | ||
759 | else | ||
760 | mfunc |= TI125X_MFUNC0_INTB; | ||
761 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
762 | |||
763 | break; | ||
764 | |||
765 | default: | ||
766 | /* all new bridges are the same */ | ||
767 | if (operation == HOOK_POWER_PRE) | ||
768 | mfunc &= ~TI122X_MFUNC1_MASK; | ||
769 | else | ||
770 | mfunc |= TI122X_MFUNC1_INTB; | ||
771 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
614 | static int ti12xx_override(struct yenta_socket *socket) | 778 | static int ti12xx_override(struct yenta_socket *socket) |
615 | { | 779 | { |
616 | u32 val, val_orig; | 780 | u32 val, val_orig; |
@@ -654,6 +818,9 @@ static int ti12xx_override(struct yenta_socket *socket) | |||
654 | else | 818 | else |
655 | ti12xx_irqroute_func1(socket); | 819 | ti12xx_irqroute_func1(socket); |
656 | 820 | ||
821 | /* install power hook */ | ||
822 | socket->socket.power_hook = ti12xx_power_hook; | ||
823 | |||
657 | return ti_override(socket); | 824 | return ti_override(socket); |
658 | } | 825 | } |
659 | 826 | ||