/*++

Copyright (c) 1994 Microsoft Corporation

Module Name:

    cl.c

Abstract:

    This module contains the code that contains
    Cirrus Logic controller specific initialization and
    other dispatches

Author:

    Ravisankar Pudipeddi (ravisp) 1-Nov-97


Environment:

    Kernel mode

Revision History :

    Neil Sandlin (neilsa) 3-Mar-99
      new setpower routine interface

--*/

#include "pch.h"


VOID
CLInitialize(IN PFDO_EXTENSION FdoExtension)
/*++

Routine Description:

    Initialize Cirrus Logic cardbus controllers

Arguments:

    FdoExtension - Pointer to the device extension for the controller FDO

Return Value:

    None
--*/
{
    UCHAR                byte, revisionID;
    USHORT               word;


   byte = PcicReadSocket(FdoExtension->SocketList,
                         PCIC_CL_MISC_CTRL3);

   if ((FdoExtension->ControllerType == PcmciaCLPD6832) &&
      ((byte & CL_MC3_INTMODE_MASK) == CL_MC3_INTMODE_EXTHW)) {

      FdoExtension->LegacyIrqMask = 0xd8b8;    //3,4,5,7,11,12,14,15

   }        

    GetPciConfigSpace(FdoExtension, CFGSPACE_REV_ID, &revisionID, 1);
    if (FdoExtension->ControllerType == PcmciaCLPD6832) {
        //disable CSC IRQ routing (use PCI interrupt for CSC)
        GetPciConfigSpace(FdoExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
        word &= ~BCTRL_CL_CSCIRQROUTING_ENABLE;
        SetPciConfigSpace(FdoExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
    }
    else {
        //disable CSC IRQ routing (use PCI interrupt for CSC)
        GetPciConfigSpace(FdoExtension, CFGSPACE_CL_CFGMISC1, &byte, 1);
        byte &= ~CL_CFGMISC1_ISACSC;
        SetPciConfigSpace(FdoExtension, CFGSPACE_CL_CFGMISC1, &byte, 1);
    }

    //enable speaker
    byte = PcicReadSocket(FdoExtension->SocketList, PCIC_CL_MISC_CTRL1);
    byte |= CL_MC1_SPKR_ENABLE;
    PcicWriteSocket(FdoExtension->SocketList, PCIC_CL_MISC_CTRL1, byte);

    byte = PcicReadSocket(FdoExtension->SocketList, PCIC_CL_DEV_IMP_C);
    if (byte & (CL_IMPC_ZVP_A | CL_IMPC_ZVP_B)) {
        //enable multimedia support (i.e. ZV)
        byte = PcicReadSocket(FdoExtension->SocketList,PCIC_CL_MISC_CTRL3);
        byte |= CL_MC3_MM_ARM;
        PcicWriteSocket(FdoExtension->SocketList, PCIC_CL_MISC_CTRL3,byte);
    }
}

NTSTATUS
CLSetPower(
   IN PSOCKET SocketPtr,
   IN BOOLEAN Enable,
   OUT PULONG pDelayTime   
   )
/*++

Routine Description:

    Set power to the specified socket.

Arguments:

    SocketPtr - the socket to set
    Enable - TRUE means to set power - FALSE is to turn it off.
    pDelayTime - specifies delay (msec) to occur after the current phase    

Return Value:

    STATUS_MORE_PROCESSING_REQUIRED - increment phase, perform delay, recall
    other status values terminate sequence

--*/

{
   NTSTATUS status;
   UCHAR             oldPower, newPower, oldMiscCtrl, newMiscCtrl;

   if (IsCardBusCardInSocket(SocketPtr)) {
      //
      // Hand over to generic power setting routine
      //
      return(CBSetPower(SocketPtr, Enable, pDelayTime));

   }

   switch(SocketPtr->PowerPhase) {
   case 1:
      //
      // R2 card - special handling
      //
      oldPower = PcicReadSocket(SocketPtr, PCIC_PWR_RST);
      oldMiscCtrl = PcicReadSocket(SocketPtr, PCIC_CL_MISC_CTRL1);
     
      //
      // Set new vcc
      //
      newPower = (Enable ? PC_CARDPWR_ENABLE: 0);
      //
      // Since we always set 5V for R2 cards, we let MISC control be 0
      // other wise it should be CL_MC1_VCC_3V if the vcc was 3.3V
      //
      newMiscCtrl = 0;
     
      //
      // Set vpp
      //
      if (Enable) {
          //
          // We - as always - set vpp to vcc..
          //
          newPower |= PC_VPP_SETTO_VCC;
      }
      //
      // Don't nuke the non-power related bits in the register..
      //
      newPower |= (oldPower & PC_PWRON_BITS);
      newMiscCtrl |= (oldMiscCtrl & ~CL_MC1_VCC_33V);
      //
      // If Vcc is turned off, reset OUTPUT_ENABLE & AUTOPWR_ENABLE
      //
      if (!(newPower & PC_CARDPWR_ENABLE)) {
         newPower &= ~PC_PWRON_BITS;
      }
      //
      // Only set power if nothing's changed..
      //
      status = STATUS_SUCCESS;
      if ((newPower != oldPower) || (newMiscCtrl != oldMiscCtrl)) {
         PcicWriteSocket(SocketPtr, PCIC_PWR_RST, newPower);
         PcicWriteSocket(SocketPtr, PCIC_CL_MISC_CTRL1, newMiscCtrl);
         //
         // Allow ramp up.. (actually we don't need to this if
         // Enable was FALSE).  Keep it for paranoia's sake
         //         
         *pDelayTime = PcicStallPower;
         SocketPtr->PowerData = (ULONG) newPower;
         status = STATUS_MORE_PROCESSING_REQUIRED;
      }
      break;

   case 2:

      newPower = (UCHAR) SocketPtr->PowerData;         

      if ((newPower & PC_CARDPWR_ENABLE) &&
          ((newPower & PC_PWRON_BITS) != PC_PWRON_BITS)) {
         //
         // More paranoia?
         //
         newPower |= PC_PWRON_BITS;
         PcicWriteSocket(SocketPtr, PCIC_PWR_RST, newPower);
      }
      status = STATUS_SUCCESS;
      break;

   default:
      ASSERT(FALSE);
      status = STATUS_UNSUCCESSFUL;
   }
   return status;      
}


BOOLEAN
CLSetZV(
   IN PSOCKET Socket,
   IN BOOLEAN Enable
   )
{
   UCHAR bData;
   
   if (Enable) {
   
      bData = PcicReadSocket(Socket, PCIC_CL_MISC_CTRL1);
      bData |= CL_MC1_MM_ENABLE;
      bData &= ~CL_MC1_SPKR_ENABLE;
      PcicWriteSocket(Socket, PCIC_CL_MISC_CTRL1, bData);
      
   } else {
   
      bData = PcicReadSocket(Socket, PCIC_CL_MISC_CTRL1);
      bData &= ~CL_MC1_MM_ENABLE;
      bData |= CL_MC1_SPKR_ENABLE;
      PcicWriteSocket(Socket, PCIC_CL_MISC_CTRL1, bData);
      
   }
   return TRUE;
}