/****************************************************************************** Copyright (c) 2010 Lantiq Deutschland GmbH Am Campeon 3; 85579 Neubiberg, Germany For licensing information, see the file 'LICENSE' in the root folder of this software module. ******************************************************************************/ #define LINUX_2_6 #ifdef LINUX_2_6 #include #ifndef UTS_RELEASE #include #endif /* UTC_RELEASE */ #endif /* LINUX_2_6 */ #ifndef AUTOCONF_INCLUDED #include #endif /* AUTOCONF_INCLUDED */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ifxmips_pmcu.h" /** \defgroup LQ_PMCU_PRG Program Guide \ingroup LQ_PMCU
"Power Management Control Unit ( PMCU )" .
\section Purpose Purpose The PMCU is the central unit of the power management framework. It is responsible for processing requests to change the power states of the hardware modules whose device drivers have registered with it. The PMCU ensures a smooth power state transition by resolving all dependencies before finally changing to the requested power state.\n\n\n Supported Power States:
D0 on State
D1 standby
D2 low power standby
D3 off State
\n \n "High Level PMCU Architecture" . \image html cpe_power_sw_architecture2.jpg \n \n \section Function_Calltree Function Calltree of PMCU \image html pmcucalltree.gif \n */ /* PMCU driver device name used during OS registration */ #define IFX_PMCU_DEVICE_NAME "ifx_pmcu" /* PMCU driver version */ #define IFX_PMCU_DRV_VERSION "2.0.16.0" /* size of request ringbuffer */ #define IFX_REQ_BUFFER_SIZE 5 /* max number of entries in dependency list +1 represents the entry the requested module inside the ifx_pmcu_preCall[][] array */ #define IFX_DEPLIST_SIZE (10 + 1) /* max number of dependency entries inclusive the nested dependencies */ #define IFX_PMCU_ACCU_DEPLIST_MAX 15 /* PMCU printk specific's; colored print_message support */ /******************************************************************************/ #define BLINK "\033[31;1m" #define RED "\033[31;1m" #define YELLOW "\033[33;1m" #define GREEN "\033[32;2m" #define BLUE "\033[34;1m" #define CYAN "\033[36;2m" #define DIM "\033[37;1m" #define NORMAL "\033[0m" #define PMCU_EMERG(module,fmt,arg...)\ if(log_level_g >= 0){\ printk(KERN_EMERG RED #module NORMAL ": " fmt,##arg);\ } #define PMCU_ERR(module,fmt,arg...)\ if(log_level_g >= 0){\ printk(KERN_ERR RED #module NORMAL ": " fmt,##arg);\ } #define PMCU_WARNING(module,fmt,arg...)\ if(log_level_g >= 0){\ printk(KERN_WARNING YELLOW #module NORMAL ": " fmt,##arg);\ } #define PMCU_INFO(module,fmt,arg...)\ if(log_level_g >= 1){\ printk(KERN_INFO GREEN #module NORMAL ": " fmt,##arg);\ } #if 0 #define PMCU_DEBUG(module,fmt,arg...)\ if(log_level_g >= 2){\ printk(KERN_DEBUG CYAN #module NORMAL ": " fmt,##arg);\ } #else /*--- #if 0 ---*/ #define PMCU_DEBUG(module,fmt,arg...) #endif /*--- #else ---*/ /*--- #if 0 ---*/ /******************************************************************************/ #undef PMCU_DEBUG_ENABLE //#define PMCU_DEBUG_ENABLE #ifdef PMCU_DEBUG_ENABLE /* debug macro to print the content of the request ringBuffer */ #define PMCU_DEBUG_PRINT_REQ_BUFFER(max) \ { \ int i; \ for (i=0; i= IFX_REQ_BUFFER_SIZE ){ return IFX_PMCU_RETURN_ERROR; } spin_lock_irqsave(&ifx_pmcu_lock, iflags); req.reqId = IFX_PMCU_PENDING_REQ; memcpy(&ifx_pmcu_reqBuffer[ ifx_pmcu_reqPutIndex ], &req, sizeof(req)); ifx_pmcu_reqPutIndex++; if ( ifx_pmcu_reqPutIndex >= IFX_REQ_BUFFER_SIZE ){ ifx_pmcu_reqPutIndex = 0; } ifx_pmcu_reqBufferSize++; spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); //PMCU_DEBUG_PRINT_REQ_BUFFER(5); return IFX_PMCU_RETURN_SUCCESS; } static IFX_PMCU_REQ_STATE_t ifx_pmcu_get_req( IFX_void_t ) { IFX_PMCU_REQ_STATE_t req; req.reqId = IFX_PMCU_PENDING_REQ_ERROR; if ( !ifx_pmcu_reqBufferSize ){ return req; } ifx_pmcu_reqBufferSize--; memcpy(&req, &ifx_pmcu_reqBuffer[ ifx_pmcu_reqGetIndex ], sizeof(req)); ifx_pmcu_reqBuffer[ ifx_pmcu_reqGetIndex ].reqId = IFX_PMCU_NO_PENDING_REQ; ifx_pmcu_reqGetIndex++; if ( ifx_pmcu_reqGetIndex >= IFX_REQ_BUFFER_SIZE ){ ifx_pmcu_reqGetIndex = 0; } return req; } /* this function runs in interrupt context */ static IFX_void_t ifx_pmcu_process_req_tasklet(unsigned long data) { IFX_PMCU_REQ_STATE_t reqState; IFX_PMCU_RETURN_t ret; IFX_PMCU_MODULE_STATE_t pmcuModuleState; IFX_int8_t pmcuPreCallIndex = -1; PMCU_DEBUG(PMCU, "ifx_pmcu_process_req_tasklet() is called\n"); /* init ifx_pmcu_preCall[][] array */ memset(ifx_pmcu_accuDepList, 0, sizeof(ifx_pmcu_accuDepList)); /* init accumulated dependency list */ memset(ifx_pmcu_preCall, 0, sizeof(ifx_pmcu_preCall)); /* init memory to process modules only once. */ memset(ifx_pmcu_ModMem, 0, sizeof(ifx_pmcu_ModMem)); /* fetch request from ringBuffer */ /* init index of the ifx_pmcu_accuDepList */ ifx_pmcu_indexAccuDepL = 0; reqState = ifx_pmcu_get_req(); if(reqState.reqId == IFX_PMCU_PENDING_REQ_ERROR){ PMCU_ERR(PMCU, "PMCU Request Buffer overflow\n"); return; } if(reqState.reqId == IFX_PMCU_NO_PENDING_REQ){ PMCU_ERR(PMCU, "No valid PMCU Request in buffer, but tasklet is scheduled!!!!!\n"); return; } /* handle PMCU request */ PMCU_DEBUG(PMCU, "REQ: pmcuModule=%s, pmcuModuleNr=%d, pmcuState=%s\n", ifx_pmcu_mod[reqState.moduleState.pmcuModule], reqState.moduleState.pmcuModuleNr, ifx_pmcu_ps[reqState.moduleState.pmcuState]); /* parse the dependency list and all nested dependencies */ memcpy(&pmcuModuleState, &reqState.moduleState, sizeof(pmcuModuleState)); if(ifx_pmcu_parse_deplist(pmcuModuleState) == IFX_PMCU_RETURN_ERROR){ PMCU_ERR(PMCU, "Error occured during dependencyList parsing\n"); return; } //PMCU_DEBUG_PRINT_ACCU_DEPLIST(IFX_PMCU_ACCU_DEPLIST_MAX); /* IFX_PMCU_ACCU_DEPLIST_MAX, ifx_pmcu_indexAccuDepL */ //PMCU_DEBUG_PRINT_MOD_MEM(); /* prepare pmcuModuleState for pre step */ /* --> start pre processing by calling preCallBack functions of all affected modules */ ret = ifx_pmcu_prechange(&pmcuPreCallIndex); //PMCU_DEBUG_PRINT_PRECALL(); /* printout after pre processing */ if (ret == IFX_PMCU_RETURN_SUCCESS) { /* --> start processing state change by calling callBack functions of all affected modules */ ret = ifx_pmcu_statechange(pmcuModuleState, &pmcuPreCallIndex); if (ret != IFX_PMCU_RETURN_SUCCESS) { /* error during ifx_pmcu_state_change() is not allowed! Report FatalError to the application*/ PMCU_ERR(PMCU, "Error was returned from ifx_pmcu_state_change()\n"); } //PMCU_DEBUG_PRINT_PRECALL(); /* printout after statechange */ } /* --> start post processing by calling postCallBack functions of all affected modules */ /* if any error occur during pre or statechange processing set new PowerState to old PowerState, to signalize no change */ if(ret != IFX_PMCU_RETURN_SUCCESS){ pmcuModuleState.pmcuState = ifx_pmcu_map[pmcuModuleState.pmcuModule].pmcuOldState[pmcuModuleState.pmcuModuleNr]; PMCU_DEBUG(PMCU, "Error/Denied was returned from prechange/statechange\n"); } ret = ifx_pmcu_postchange(pmcuModuleState, &pmcuPreCallIndex); if (ret != IFX_PMCU_RETURN_SUCCESS) { /* error during ifx_pmcu_postchange() is not allowed! Report FatalError to the application*/ PMCU_ERR(PMCU, "Error was returned from ifx_pmcu_postchange()\n"); } //PMCU_DEBUG_PRINT_PRECALL(); /* printout after post processing */ } IFX_PMCU_RETURN_t ifx_pmcu_state_req (IFX_PMCU_MODULE_t pmcuModule, IFX_uint8_t pmcuModuleNr, IFX_PMCU_STATE_t newState) { IFX_PMCU_REQ_STATE_t reqState; IFX_int32_t chipId; /* check if the acception of the powerstate request is enabled */ if (request_control_g == 0) { PMCU_INFO(PMCU, "The Powerstate request feature is disabled. All requests are rejected\n"); return IFX_PMCU_RETURN_SUCCESS; } reqState.moduleState.pmcuModule = pmcuModule; reqState.moduleState.pmcuModuleNr = pmcuModuleNr; reqState.moduleState.pmcuState = newState; reqState.reqId = IFX_PMCU_NO_PENDING_REQ; /* check the current hardware to decide if the requested power state is supported. If this isn't the case request the next valid power state for this chip. */ chipId = (IFX_REG_R32(IFX_MPS_CHIPID) & 0x0FFFF000) >> 12; if ((chipId == ARX168) || (chipId == ARX182) || (chipId == ARX182_2) || (chipId == ARX188) || (chipId == GRX188) || (chipId == VRX268)) { if ((reqState.moduleState.pmcuState == IFX_PMCU_STATE_D1) && (reqState.moduleState.pmcuModule == IFX_PMCU_MODULE_CPU)) { reqState.moduleState.pmcuState = IFX_PMCU_STATE_D2; PMCU_INFO(PMCU, "Requested Powerstate D1 is not supported by the current hardware. Changed to D2\n"); } } /* put new powerState request into request buffer */ if(ifx_pmcu_put_req(reqState) == IFX_PMCU_RETURN_ERROR){ PMCU_ERR(PMCU, "PMCU RequestBuffer overflow !!!\n"); } /* fetch powerState request from requestBuffer with the next interrupt in the system */ tasklet_hi_schedule(&ifx_pmcu_tasklet); return IFX_PMCU_RETURN_SUCCESS; } /** Register a device driver to the PMCU \param [in] pmcuRegister Registration Information \return Returns value as follows: - IFX_SUCCESS: if successful - IFX_ERROR: in case of an error \ingroup IFX_PMCU_KERNEL */ IFX_PMCU_RETURN_t ifx_pmcu_register (IFX_PMCU_REGISTER_t* pmcuRegister) { IFX_PMCU_MAP_t *entry = NULL; IFX_PMCU_RETURN_t retVal = IFX_PMCU_RETURN_ERROR; IFX_PMCU_MODULE_DEP_t *pmcuModuleDep; size_t depSize; IFX_uint32_t iflags; down(&ifx_pmcu_map_mutex); spin_lock_irqsave(&ifx_pmcu_lock, iflags); PMCU_DEBUG(PMCU, "pmcu_register is called by module %s\n",ifx_pmcu_mod[pmcuRegister->pmcuModule]); entry = &(ifx_pmcu_map[pmcuRegister->pmcuModule]); /* check registry status */ if ( (entry->registryInfo[pmcuRegister->pmcuModuleNr] == IFX_PMCU_MODULE_NOT_REGISTRED) || (entry->registryInfo[pmcuRegister->pmcuModuleNr] == IFX_PMCU_MODULE_UNREGISTERED)) { /* check if at least pre/post callback function is defined */ if ( (pmcuRegister->pre != NULL) && (pmcuRegister->post != NULL) ) { /* copy module registry struct into PMCU structure */ memcpy(&entry->pmcuRegister[pmcuRegister->pmcuModuleNr], pmcuRegister, sizeof(IFX_PMCU_REGISTER_t)); /* check if dependency list is defined */ if(pmcuRegister->pmcuModuleDep == NULL){ PMCU_DEBUG(PMCU, "PMCU/%s registry message: dependency list not defined\n",ifx_pmcu_mod[pmcuRegister->pmcuModule]); /* set registry flag for this module */ entry->registryInfo[pmcuRegister->pmcuModuleNr] = IFX_PMCU_MODULE_REGISTERED; /* as defined the module must have D0 powerState after startup */ entry->pmcuNewState[pmcuRegister->pmcuModuleNr] = IFX_PMCU_STATE_D0; entry->pmcuOldState[pmcuRegister->pmcuModuleNr] = IFX_PMCU_STATE_D0; spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); up(&ifx_pmcu_map_mutex); return IFX_PMCU_RETURN_SUCCESS; } /* copy dependency list into PMCU structure because only a pointer is provided by the module because I do not know the size of the dependency array, I have to allocate memory during runtime*/ depSize = (sizeof(IFX_PMCU_STATES_DEP_t)) * (pmcuRegister->pmcuModuleDep->nDepth) + (sizeof(pmcuRegister->pmcuModuleDep->nDepth)); pmcuModuleDep = (IFX_PMCU_MODULE_DEP_t*)kmalloc(depSize, GFP_ATOMIC); /* use atomic kmalloc to be on the save side */ if(pmcuModuleDep == NULL){ /* kmalloc failed */ /* set NULL pointer */ entry->pmcuRegister[pmcuRegister->pmcuModuleNr].pmcuModuleDep = NULL; PMCU_ERR(PMCU, "PMCU/%s memory allocation for dependency list failed\n",entry->pmcuModuleName); spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); up(&ifx_pmcu_map_mutex); return IFX_PMCU_RETURN_ERROR; } //PMCU_DEBUG(PMCU, "PMCU/%s kmalloc for dependency list was successful during registration\n",ifx_pmcu_mod[pmcuRegister->pmcuModule]); /* copy dependency content */ memcpy(pmcuModuleDep, pmcuRegister->pmcuModuleDep, depSize); /* overwrite the dependency pointer from the module in the registry struct with the pointer to the local PMCU copy */ entry->pmcuRegister[pmcuRegister->pmcuModuleNr].pmcuModuleDep = pmcuModuleDep; /* set registry flag for this module */ entry->registryInfo[pmcuRegister->pmcuModuleNr] = IFX_PMCU_MODULE_REGISTERED; /* as defined the module must have D0 powerState after startup */ entry->pmcuNewState[pmcuRegister->pmcuModuleNr] = IFX_PMCU_STATE_D0; entry->pmcuOldState[pmcuRegister->pmcuModuleNr] = IFX_PMCU_STATE_D0; retVal = IFX_PMCU_RETURN_SUCCESS; } else { PMCU_ERR(PMCU, "PMCU/%s registry error: pre/post callback not defined\n",entry->pmcuModuleName); spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); up(&ifx_pmcu_map_mutex); return IFX_PMCU_RETURN_ERROR; } } else { /* module already registered */ retVal = IFX_PMCU_RETURN_DENIED; } spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); up(&ifx_pmcu_map_mutex); return retVal; } /** Unregister a device driver to the PMCU \param [in] pmcuUnregister Unregistration Information. Only module name is required. \return Returns value as follows: - IFX_SUCCESS: if successful - IFX_ERROR: in case of an error \ingroup IFX_PMCU_KERNEL */ IFX_PMCU_RETURN_t ifx_pmcu_unregister (IFX_PMCU_REGISTER_t* pmcuUnregister) { IFX_PMCU_MAP_t *entry = NULL; IFX_uint32_t iflags; down(&ifx_pmcu_map_mutex); spin_lock_irqsave(&ifx_pmcu_lock, iflags); PMCU_DEBUG(PMCU, "pmcu_unregister is called by module %s\n",ifx_pmcu_mod[pmcuUnregister->pmcuModule]); entry = &(ifx_pmcu_map[pmcuUnregister->pmcuModule]); if(entry->registryInfo[pmcuUnregister->pmcuModuleNr] == IFX_PMCU_MODULE_REGISTERED ){ /* free dynamic allocated memorey of dependency list */ if(entry->pmcuRegister[pmcuUnregister->pmcuModuleNr].pmcuModuleDep != NULL){ kfree(entry->pmcuRegister[pmcuUnregister->pmcuModuleNr].pmcuModuleDep); //PMCU_DEBUG(PMCU, "PMCU/%s kfree for dependency list was called during unregistration\n",entry->pmcuModuleName); } entry->registryInfo[pmcuUnregister->pmcuModuleNr] = IFX_PMCU_MODULE_UNREGISTERED; entry->pmcuNewState[pmcuUnregister->pmcuModuleNr] = IFX_PMCU_STATE_INVALID; entry->pmcuOldState[pmcuUnregister->pmcuModuleNr] = IFX_PMCU_STATE_INVALID; memset(&entry->pmcuRegister[pmcuUnregister->pmcuModuleNr], 0, sizeof(IFX_PMCU_REGISTER_t)); } spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); up(&ifx_pmcu_map_mutex); return IFX_PMCU_RETURN_SUCCESS; }; /** Recursive function to parse all dependency list's and create a accumulated list of modules and their necessary powerStates, for the requested powerState/module. The accumulated list is a static array called mcAccuDepList[]. \param[in] pmcuModuleState (module, subNr, newState) \return Returns value as follows: - IFX_PMCU_RETURN_SUCCESS: if successful - IFX_PMCU_RETURN_ERROR: in case of an error \ingroup IFX_PMCU_KERNEL */ static IFX_PMCU_RETURN_t ifx_pmcu_parse_deplist (IFX_PMCU_MODULE_STATE_t pmcuModuleState) { IFX_PMCU_MODULE_DEP_t *entryModDep = NULL; /* points to the Dependency struct of the requested subModule */ IFX_uint8_t i = 0; IFX_PMCU_MODULE_STATE_t moduleState; IFX_PMCU_MODULE_t pmcuModule = IFX_PMCU_MODULE_PMCU; IFX_PMCU_STATE_t pmcuState = IFX_PMCU_STATE_INVALID, pmcuOldState = IFX_PMCU_STATE_INVALID; IFX_uint8_t pmcuModuleNr = 0; //PMCU_DEBUG(PMCU, "parse start: pmcuState=%s, pmcuModule=%s\n",ifx_pmcu_ps[pmcuModuleState.pmcuState],ifx_pmcu_mod[pmcuModuleState.pmcuModule]); /* is module already processed? */ if(!ifx_pmcu_ModMem[pmcuModuleState.pmcuModule]){ /* No. Module is not in the list. Create a new entry */ ifx_pmcu_ModMem[pmcuModuleState.pmcuModule] = 1; /* set marker */ memcpy(&ifx_pmcu_accuDepList[ifx_pmcu_indexAccuDepL], &pmcuModuleState, sizeof(pmcuModuleState)); ifx_pmcu_indexAccuDepL++; } /* points to the Dependency struct of the requested subModule */ entryModDep = ifx_pmcu_map[pmcuModuleState.pmcuModule].pmcuRegister[pmcuModuleState.pmcuModuleNr].pmcuModuleDep; /* check if a dependency list exists for the module */ if(entryModDep == NULL){ /* end of processing; no further dependency list available. */ return IFX_PMCU_RETURN_SUCCESS; } /* Dependency list exist. Check if dependency list exceeds maximum number of entries 'IFX_DEPLIST_SIZE' */ if(entryModDep->nDepth >= IFX_DEPLIST_SIZE){ PMCU_ERR(PMCU, "Dependency list of module '%s' is greater than %i\n",ifx_pmcu_mod[pmcuModuleState.pmcuModule],IFX_DEPLIST_SIZE); return IFX_PMCU_RETURN_ERROR; } /* loop over the dependency list */ for (i = 0; i < entryModDep->nDepth; i++) { switch(pmcuModuleState.pmcuState){ /* switch on requested powerState */ case IFX_PMCU_STATE_D0: //PMCU_DEBUG(PMCU, "change to powerState IFX_PMCU_STATE_D0\n"); pmcuState = entryModDep->moduleStates[i].onState; pmcuModule = entryModDep->moduleStates[i].pmcuModule; pmcuModuleNr = 0;/* only sub module 0 is supported */ break; case IFX_PMCU_STATE_D1: //PMCU_DEBUG(PMCU, "change to powerState IFX_PMCU_STATE_D1\n"); pmcuState = entryModDep->moduleStates[i].standBy; pmcuModule = entryModDep->moduleStates[i].pmcuModule; pmcuModuleNr = 0;/* only sub module 0 is supported */ break; case IFX_PMCU_STATE_D2: //PMCU_DEBUG(PMCU, "change to powerState IFX_PMCU_STATE_D2\n"); pmcuState = entryModDep->moduleStates[i].lpStandBy; pmcuModule = entryModDep->moduleStates[i].pmcuModule; pmcuModuleNr = 0;/* only sub module 0 is supported */ break; case IFX_PMCU_STATE_D3: //PMCU_DEBUG(PMCU, "change to powerState IFX_PMCU_STATE_D3\n"); pmcuState = entryModDep->moduleStates[i].offState; pmcuModule = entryModDep->moduleStates[i].pmcuModule; pmcuModuleNr = 0;/* only sub module 0 is supported */ break; default: PMCU_ERR(PMCU, "invalid PowerState was selected\n"); /* error handling invalid state */ return IFX_PMCU_RETURN_ERROR; } /* get current state of the module from the dependency list */ pmcuOldState = ifx_pmcu_map[pmcuModule].pmcuOldState[pmcuModuleNr]; /* check if there is anything todo for this module */ /* compare the CURRENT state with the MASK from the dependency list */ //PMCU_DEBUG(PMCU, "oldState=%s, DepMask=%s, pmcuModule=%s\n",ifx_pmcu_ps[pmcuOldState],ifx_pmcu_ps[pmcuState],ifx_pmcu_mod[pmcuModule]); //PMCU_DEBUG_PRINT_MOD_MEM(); /* is module already processed? if yes skip this module */ if(ifx_pmcu_ModMem[pmcuModule]){ /* yes. Module is already in the list. goto next entry */ continue; } //PMCU_DEBUG(PMCU, "pmcu_stateMap=%d\n",ifx_pmcu_stateMap[pmcuState][pmcuOldState]); if(ifx_pmcu_stateMap[pmcuState][pmcuOldState] == 1){ /* here we have the recursive call of this function */ moduleState.pmcuModule = pmcuModule; moduleState.pmcuState = pmcuState; moduleState.pmcuModuleNr = pmcuModuleNr; ifx_pmcu_parse_deplist(moduleState); }else{ /* fetch next module from depenedency list */ PMCU_DEBUG(PMCU, "no dependency activity necessary for module '%s'\n",ifx_pmcu_mod[pmcuModule]); } } return IFX_PMCU_RETURN_SUCCESS; } /** Apply all callbacks registered to be executed before a state change for pmcuModule. The input for this function is the accumulated dependency list ifx_pmcu_accuDepList[] which is filled by ifx_pmcu_parse_deplist(). \param[out] pmcuPreCallIndex index to the last element inside the ifx_pmcu_preCall[][] array \return Returns value as follows: - IFX_PMCU_RETURN_SUCCESS: if successful - IFX_PMCU_RETURN_ERROR: in case of an error - IFX_PMCU_RETURN_DENIED in case that the powerState change was rejected \ingroup IFX_PMCU_KERNEL */ static IFX_PMCU_RETURN_t ifx_pmcu_prechange (IFX_int8_t* pmcuPreCallIndex) { IFX_PMCU_RETURN_t ret = IFX_PMCU_RETURN_SUCCESS; IFX_int8_t i; IFX_PMCU_MODULE_t pmcuModule; IFX_PMCU_STATE_t pmcuState, pmcuOldState; IFX_uint8_t pmcuModuleNr; PMCU_DEBUG(PMCU, "preCallback processing is called\n"); /* check if we have one or more entries in the table */ if(ifx_pmcu_indexAccuDepL == 0){ PMCU_DEBUG(PMCU, "nothing todo; accumulated depList is empty\n"); } /* loop over the accumulated dependency list in reverse order to follow the processing sequence defined in the dependency lists */ // for (i = 0; i < ifx_pmcu_indexAccuDepL; i++) { for (i = (ifx_pmcu_indexAccuDepL-1); i >= 0; i--) { pmcuModule = ifx_pmcu_accuDepList[i].pmcuModule; pmcuModuleNr = ifx_pmcu_accuDepList[i].pmcuModuleNr; pmcuState = ifx_pmcu_accuDepList[i].pmcuState; pmcuOldState = ifx_pmcu_map[pmcuModule].pmcuOldState[pmcuModuleNr]; /* check if module is registered in PMCU */ if(ifx_pmcu_map[pmcuModule].registryInfo[pmcuModuleNr] != IFX_PMCU_MODULE_REGISTERED){ PMCU_ERR(PMCU, "module '%s' listed in dependency list is not registered in PMCU\n",ifx_pmcu_mod[pmcuModule]); continue; } /* check if preCallback is defined */ if(ifx_pmcu_map[pmcuModule].pmcuRegister[pmcuModuleNr].pre == NULL){ PMCU_DEBUG(PMCU, "no preCallback defined for module '%s'\n",ifx_pmcu_mod[pmcuModule]); continue; } /* mark pre call in list for later use in change/post callbacks */ (*pmcuPreCallIndex)++; /* next free entry */ ifx_pmcu_preCall[*pmcuPreCallIndex][0] = pmcuModule; /* module name */ ifx_pmcu_preCall[*pmcuPreCallIndex][1] = pmcuModuleNr; /* subModule no. */ ifx_pmcu_preCall[*pmcuPreCallIndex][2] = pmcuState; /* powerState */ ifx_pmcu_preCall[*pmcuPreCallIndex][3] = 1; /* preCall was made */ if(ifx_pmcu_map[pmcuModule].pmcuRegister[pmcuModuleNr].pre != NULL){ /* call pre callback of the module */ PMCU_DEBUG(PMCU, "pre Callback of module '%s' is called\n",ifx_pmcu_mod[pmcuModule]); ret = ifx_pmcu_map[pmcuModule].pmcuRegister[pmcuModuleNr].pre(pmcuModule, pmcuState, pmcuOldState); } if(ret != IFX_PMCU_RETURN_SUCCESS){ /* if one denied will be returned, pre-processing can be interrupted */ PMCU_DEBUG(PMCU, "preCallback of module '%s' return DENIED\n",ifx_pmcu_mod[pmcuModule]); return IFX_PMCU_RETURN_DENIED; } PMCU_DEBUG(PMCU, "module '%s' accept preCallback\n",ifx_pmcu_mod[pmcuModule]); } return IFX_PMCU_RETURN_SUCCESS; } /** Apply all callbacks registered to be executed if a state change is requested and accepted. \param[in] pmcuModuleState (module, subNr, newState) \param[out] pmcuPreCallIndex index to the last element inside the ifx_pmcu_preCall[][] array \return Returns value as follows: - IFX_PMCU_RETURN_SUCCESS: if successful - IFX_PMCU_RETURN_ERROR: in case of an error \ingroup IFX_PMCU_KERNEL */ static IFX_PMCU_RETURN_t ifx_pmcu_statechange (IFX_PMCU_MODULE_STATE_t pmcuModuleState, IFX_int8_t* pmcuPreCallIndex) { IFX_PMCU_RETURN_t ret = IFX_PMCU_RETURN_SUCCESS; IFX_uint8_t i; IFX_uint8_t pmcuModuleNr; IFX_PMCU_MODULE_t pmcuModule; IFX_PMCU_STATE_t pmcuState; PMCU_DEBUG(PMCU, "statechangeCallback processing is called\n"); /* check if there is anything todo */ if(*pmcuPreCallIndex == -1){ PMCU_DEBUG(PMCU, "nothing todo for statechange processing\n"); return IFX_PMCU_RETURN_SUCCESS; } /* loop over the ifx_pmcu_preCall[][] list to call the statechange callbacks */ for(i = 0; i <= *pmcuPreCallIndex; i++){ if(ifx_pmcu_preCall[i][3] != 1){ PMCU_ERR(PMCU, "error in ifx_pmcu_preCall[][] list during statechangeCallback processing\n"); return IFX_PMCU_RETURN_ERROR; } pmcuModule = ifx_pmcu_preCall[i][0]; /* fetch module name */ pmcuModuleNr = ifx_pmcu_preCall[i][1]; /* fetch subModule No. */ pmcuState = ifx_pmcu_preCall[i][2]; /* fetch powerState */ ifx_pmcu_preCall[i][4] = 1; /* statechangeCall was made */ if(ifx_pmcu_map[pmcuModule].pmcuRegister[pmcuModuleNr].ifx_pmcu_state_change != NULL){ PMCU_DEBUG(PMCU, "ifx_pmcu_state_change Callback of module '%s' is called\n",ifx_pmcu_mod[pmcuModule]); ret = ifx_pmcu_map[pmcuModule].pmcuRegister[pmcuModuleNr].ifx_pmcu_state_change(pmcuState); } if(ret != IFX_PMCU_RETURN_SUCCESS){ PMCU_ERR(PMCU, "ifx_pmcu_state_change Callback of module '%s' return ERROR\n",ifx_pmcu_mod[pmcuModule]); return IFX_PMCU_RETURN_ERROR; } } return IFX_PMCU_RETURN_SUCCESS; } /** Apply all callbacks registered to be executed after a state change for pmcuModule was done, or a request was denied. \param[in] pmcuModuleState (module, subNr, newState) \param[out] pmcuPreCallIndex index to the last element inside the ifx_pmcu_preCall[][] array \return Returns value as follows: - IFX_PMCU_RETURN_SUCCESS: if successful - IFX_PMCU_RETURN_ERROR: in case of an error \ingroup IFX_PMCU_KERNEL */ static IFX_PMCU_RETURN_t ifx_pmcu_postchange (IFX_PMCU_MODULE_STATE_t pmcuModuleState, IFX_int8_t* pmcuPreCallIndex) { IFX_PMCU_RETURN_t ret = IFX_PMCU_RETURN_SUCCESS; IFX_uint8_t i,denied = 0; IFX_uint8_t pmcuModuleNr; IFX_PMCU_MODULE_t pmcuModule; IFX_PMCU_STATE_t pmcuState, pmcuOldState; PMCU_DEBUG(PMCU, "postCallback processing is called\n"); /* check if there is anything todo */ if(*pmcuPreCallIndex == -1){ PMCU_DEBUG(PMCU, "nothing todo for statechange processing\n"); return IFX_PMCU_RETURN_SUCCESS; } /* check if stateChange was accepted or denied */ if(ifx_pmcu_map[pmcuModuleState.pmcuModule].pmcuOldState[pmcuModuleState.pmcuModuleNr] == pmcuModuleState.pmcuState){ PMCU_DEBUG(PMCU, "requested powerState was denied\n"); denied = 1; /* set denied indicator */ } /* loop over the ifx_pmcu_preCall[][] list to call the post callbacks */ for(i = 0; i <= *pmcuPreCallIndex; i++){ if(ifx_pmcu_preCall[i][3] != 1){ PMCU_ERR(PMCU, "error in ifx_pmcu_preCall[][] list during postCallback processing\n"); return IFX_PMCU_RETURN_ERROR; } pmcuModule = ifx_pmcu_preCall[i][0]; /* fetch module name */ pmcuModuleNr = ifx_pmcu_preCall[i][1]; /* fetch subModule No. */ pmcuState = ifx_pmcu_preCall[i][2]; /* fetch powerState */ ifx_pmcu_preCall[i][5] = 1; /* postCall was made */ pmcuOldState = ifx_pmcu_map[pmcuModule].pmcuOldState[pmcuModuleNr]; if(denied){ pmcuState = pmcuOldState; } if(ifx_pmcu_map[pmcuModule].pmcuRegister[pmcuModuleNr].post != NULL){ PMCU_DEBUG(PMCU, "post Callback of module '%s' is called\n",ifx_pmcu_mod[pmcuModule]); ret = ifx_pmcu_map[pmcuModule].pmcuRegister[pmcuModuleNr].post(pmcuModule, pmcuState, pmcuOldState); } if(ret != IFX_PMCU_RETURN_SUCCESS){ PMCU_ERR(PMCU, "post Callback of module '%s' return ERROR\n",ifx_pmcu_mod[pmcuModule]); return IFX_PMCU_RETURN_ERROR; } /* store new state inside PMCU mapTable */ ifx_pmcu_map[pmcuModule].pmcuOldState[pmcuModuleNr] = pmcuState; ifx_pmcu_map[pmcuModule].pmcuNewState[pmcuModuleNr] = pmcuState; } return IFX_PMCU_RETURN_SUCCESS; } static ssize_t ifx_pmcu_read( struct file *filp, char *buf, size_t count, loff_t *ppos ) { return count; } static ssize_t ifx_pmcu_write( struct file *filp, const char *buf, size_t count, loff_t *ppos ) { return 0; } static int ifx_pmcu_open(struct inode * inode, struct file * file) { return 0; } static int ifx_pmcu_release(struct inode *inode, struct file *file) { return 0; } static unsigned int ifx_pmcu_poll(struct file *filp, poll_table *wait) { poll_wait(filp, &ifx_pmcu_wait_q, wait); return 0; } /** Configuration / Control for the device. \param inode Pointer to the inode. \param file Pointer to the file descriptor. \param cmd IOCTL identifier. \param arg Optional argument. \return - 0 and positive values - success - negative value - ioctl failed */ static int ifx_pmcu_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ret = IFX_ERROR; IFX_PMCU_MODULE_STATE_t usrModuleState; IFX_PMCU_STATE_t moduleState = IFX_PMCU_STATE_INVALID; IFX_int32_t llevel = 0; IFX_int32_t req_ctrl; switch (cmd) { case IFX_PMCU_STATE_GET: { PMCU_DEBUG(PMCU, "ifx_pmcu_ioctl IFX_PMCU_STATE_GET is called\n"); copy_from_user(&usrModuleState, (IFX_PMCU_MODULE_STATE_t *)arg, sizeof(IFX_PMCU_MODULE_STATE_t)); down(&ifx_pmcu_map_mutex); if(ifx_pmcu_map[usrModuleState.pmcuModule].registryInfo[usrModuleState.pmcuModuleNr] == IFX_PMCU_MODULE_REGISTERED){ moduleState = ifx_pmcu_map[usrModuleState.pmcuModule].pmcuOldState[usrModuleState.pmcuModuleNr]; }else{ PMCU_ERR(PMCU,"ifx_pmcu_ioctl IFX_PMCU_STATE_GET -> module not registered\n"); } up(&ifx_pmcu_map_mutex); /* return current module popwer state to userspace */ usrModuleState.pmcuState = moduleState; copy_to_user((IFX_PMCU_MODULE_STATE_t *)arg, &usrModuleState, sizeof(IFX_PMCU_MODULE_STATE_t)); ret = IFX_SUCCESS; break; } case IFX_PMCU_STATE_REQ: { PMCU_DEBUG(PMCU, "ifx_pmcu_ioctl IFX_PMCU_STATE_REQ is called\n"); copy_from_user(&usrModuleState, (IFX_PMCU_MODULE_STATE_t *)arg, sizeof(IFX_PMCU_MODULE_STATE_t)); ret = ifx_pmcu_state_req (usrModuleState.pmcuModule, usrModuleState.pmcuModuleNr, usrModuleState.pmcuState); if(ret == IFX_PMCU_RETURN_ERROR){ ret = IFX_ERROR; } break; } case IFX_PMCU_REQ_CTRL: { PMCU_DEBUG(PMCU, "ifx_pmcu_ioctl IFX_PMCU_REQ_CTRL is called\n"); copy_from_user(&req_ctrl, (IFX_int32_t *)arg, sizeof(IFX_int32_t)); if (req_ctrl == 0) { request_control_g = 0; } else { request_control_g = 1; } ret = IFX_SUCCESS; break; } case IFX_PMCU_LOG_LEVEL: { PMCU_DEBUG(PMCU, "ifx_pmcu_ioctl IFX_PMCU_LOG_LEVEL is called\n"); copy_from_user(&llevel, (IFX_int32_t *)arg, sizeof(IFX_int32_t)); log_level_g = llevel; ret = IFX_SUCCESS; break; } default: ret = IFX_ERROR; } return ret; } static struct file_operations ifx_pmcu_fops = { #ifdef MODULE owner: THIS_MODULE, #endif /* MODULE */ read: ifx_pmcu_read, write: ifx_pmcu_write, ioctl: ifx_pmcu_ioctl, open: ifx_pmcu_open, release: ifx_pmcu_release, poll: ifx_pmcu_poll, }; #ifdef CONFIG_PROC_FS static int ifx_pmcu_proc_device_list(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; int i = 0, j = 0; len += sprintf(buf+len, "PMCU Request Control = %s\n\n",((request_control_g == 1)?"Enabled":"Disabled")); len += sprintf(buf+len, "Legend:\n"); len += sprintf(buf+len, "\tr\t:registered (-=not registered, 1=unregistered, 2=registered)\n"); len += sprintf(buf+len, "\tSub#\t:Submodule or module instance\n"); len += sprintf(buf+len, "\tps\t:power state (-1=invalid state, D0=on, D1=lp1, D2=lp2, D3=off n.d.=no pmcu_state_get() defined)\n\n"); len += sprintf(buf+len, "Modules\t\tSub0\tSub1\tSub2\tSub3\tSub4\tSub5\n"); len += sprintf(buf+len, "\t\tr/ps\tr/ps\tr/ps\tr/ps\tr/ps\tr/ps\n"); down(&ifx_pmcu_map_mutex); for (i = 0; i < IFX_PMCU_MODULE_ID_MAX ; i++) { if(strlen(ifx_pmcu_map[i].pmcuModuleName) < 8 ){ len += sprintf(buf + len, "%s\t\t", ifx_pmcu_map[i].pmcuModuleName); }else{ len += sprintf(buf + len, "%s\t", ifx_pmcu_map[i].pmcuModuleName); } for (j = 0; j < MAX_PMCU_SUB_MODULE; j++) { if( (ifx_pmcu_map[i].registryInfo[j] != IFX_PMCU_MODULE_REGISTERED) || (ifx_pmcu_map[i].pmcuRegister[j].pmcuModule == IFX_PMCU_MODULE_PMCU) ){ len += sprintf(buf+len,"-\t"); }else{ len += sprintf(buf + len, "%d/", ifx_pmcu_map[i].registryInfo[j]); len += sprintf(buf+len,"%s\t",ifx_pmcu_ps[ifx_pmcu_map[i].pmcuOldState[j]]); } } len += sprintf(buf+len,"\n"); } up(&ifx_pmcu_map_mutex); return len; } static int ifx_pmcu_proc_version(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; len += sprintf(buf+len, "IFX_PMCU Version = %s\n",IFX_PMCU_DRV_VERSION); len += sprintf(buf+len, "Compiled on %s, %s for Linux kernel %s\n",__DATE__, __TIME__, UTS_RELEASE); return len; } static int ifx_pmcu_proc_chipid(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; int chipId; chipId = IFX_REG_R32(IFX_MPS_CHIPID); len += sprintf(buf+len, "CHIP_ID_REG = %08x\n",chipId); chipId = (chipId & 0x0FFFF000) >> 12; switch (chipId) { case ARX188: len += sprintf(buf+len, "CHIP_ID = ARX188\n"); break; case ARX168: len += sprintf(buf+len, "CHIP_ID = ARX168\n"); break; case ARX182: case ARX182_2: len += sprintf(buf+len, "CHIP_ID = ARX182\n"); break; case GRX188: len += sprintf(buf+len, "CHIP_ID = GRX188\n"); break; case GRX168: len += sprintf(buf+len, "CHIP_ID = GRX168\n"); break; case VRX288: len += sprintf(buf+len, "CHIP_ID = VRX288\n"); break; case VRX268: len += sprintf(buf+len, "CHIP_ID = VRX268\n"); break; case VRX282: len += sprintf(buf+len, "CHIP_ID = VRX282\n"); break; case GRX288: len += sprintf(buf+len, "CHIP_ID = GRX288\n"); break; default: len += sprintf(buf+len, "CHIP_ID = undefined\n"); break; } return len; } static int ifx_pmcu_proc_get_internal_map(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; int i=0, j = 0; len += sprintf(buf+len, "internal MAP-Table\n"); down(&ifx_pmcu_map_mutex); len += sprintf(buf + len, "pmcu_map[%d]->pmcuModuleName=%s\n", (int)data, ifx_pmcu_map[(int)data].pmcuModuleName); for (j = 0; j < MAX_PMCU_SUB_MODULE; j++) { len += sprintf(buf + len, "registryInfo[%d]=%d\t", j, ifx_pmcu_map[(int)data].registryInfo[j]); } len += sprintf(buf+len,"\n"); for (j = 0; j < MAX_PMCU_SUB_MODULE; j++) { len += sprintf(buf + len, "pmcuOldState[%d]=%d\t", j, ifx_pmcu_map[(int)data].pmcuOldState[j]); } len += sprintf(buf+len,"\n"); for (j = 0; j < MAX_PMCU_SUB_MODULE; j++) { len += sprintf(buf + len, "pmcuNewState[%d]=%d\t", j, ifx_pmcu_map[(int)data].pmcuNewState[j]); } len += sprintf(buf+len,"\n\n"); for (j = 0; j < MAX_PMCU_SUB_MODULE; j++) { len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModule=%d\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModule); len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleNr=%d\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleNr); len += sprintf(buf + len, "pmcuRegister[%d]->ifx_pmcu_state_change=%p\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].ifx_pmcu_state_change); len += sprintf(buf + len, "pmcuRegister[%d]->ifx_pmcu_state_get=%p\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].ifx_pmcu_state_get); len += sprintf(buf + len, "pmcuRegister[%d]->pre=%p\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].pre); len += sprintf(buf + len, "pmcuRegister[%d]->post=%p\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].post); len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleDep=%p\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep); if(ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep != NULL){ len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleDep->nDepth=%d\n", j, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep->nDepth); } len += sprintf(buf+len,"\n"); } for (j = 0; j < MAX_PMCU_SUB_MODULE; j++) { if(ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep != NULL){ for(i=0;inDepth;i++){ len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleDep[%d]->pmcuModule=%s\n", j, i, ifx_pmcu_mod[ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep->moduleStates[i].pmcuModule]); len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleDep[%d]->onState\t=%d\n", j, i, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep->moduleStates[i].onState); len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleDep[%d]->standBy\t=%d\n", j, i, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep->moduleStates[i].standBy); len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleDep[%d]->lpStandBy\t=%d\n", j, i, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep->moduleStates[i].lpStandBy); len += sprintf(buf + len, "pmcuRegister[%d]->pmcuModuleDep[%d]->offState\t=%d\n", j, i, ifx_pmcu_map[(int)data].pmcuRegister[j].pmcuModuleDep->moduleStates[i].offState); len += sprintf(buf+len,"\n"); } } } up(&ifx_pmcu_map_mutex); len += sprintf(buf+len,"\n"); return len; } /** Initialize and install the proc entry \return -1 or 0 on success */ static int ifx_pmcu_proc_EntriesInstall(void) { /*create pmcu proc entry*/ g_ifx_pmcu_dir_pmcu = proc_mkdir("pmcu", NULL); create_proc_read_entry("device_list", 0, g_ifx_pmcu_dir_pmcu, ifx_pmcu_proc_device_list, NULL); create_proc_read_entry("version", 0, g_ifx_pmcu_dir_pmcu, ifx_pmcu_proc_version, NULL); create_proc_read_entry("chipid", 0, g_ifx_pmcu_dir_pmcu, ifx_pmcu_proc_chipid, NULL); g_ifx_pmcu_dir_debug = proc_mkdir("pmcu/debug", NULL); create_proc_read_entry("cpu", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_CPU); create_proc_read_entry("eth", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_ETH); create_proc_read_entry("usb", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_USB); create_proc_read_entry("dsl", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_DSL); create_proc_read_entry("wlan", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_WLAN); create_proc_read_entry("dect", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_DECT); create_proc_read_entry("fxs", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_FXS); create_proc_read_entry("fxo", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_FXO); create_proc_read_entry("ve", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_VE); create_proc_read_entry("ppe", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_PPE); create_proc_read_entry("switch", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_SWITCH); create_proc_read_entry("uart", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_UART); create_proc_read_entry("spi", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_SPI); create_proc_read_entry("sdio", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_SDIO); create_proc_read_entry("pci", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_PCI); create_proc_read_entry("vlynq", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_VLYNQ); create_proc_read_entry("deu", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_DEU); create_proc_read_entry("cpu_ps", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_CPU_PS); create_proc_read_entry("gptu", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_GPTC); create_proc_read_entry("usif_uart", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_USIF_UART); create_proc_read_entry("usif_spi", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_USIF_SPI); create_proc_read_entry("pcie", 0, g_ifx_pmcu_dir_debug, ifx_pmcu_proc_get_internal_map, (void*)IFX_PMCU_MODULE_PCIE); return 0; } /** Initialize and install the proc entry \return -1 or 0 on success */ static int ifx_pmcu_proc_EntriesRemove(void) { remove_proc_entry("pcie", g_ifx_pmcu_dir_debug); remove_proc_entry("usif_spi", g_ifx_pmcu_dir_debug); remove_proc_entry("usif_uart", g_ifx_pmcu_dir_debug); remove_proc_entry("gptu", g_ifx_pmcu_dir_debug); remove_proc_entry("cpu_ps", g_ifx_pmcu_dir_debug); remove_proc_entry("deu", g_ifx_pmcu_dir_debug); remove_proc_entry("vlynq", g_ifx_pmcu_dir_debug); remove_proc_entry("pci", g_ifx_pmcu_dir_debug); remove_proc_entry("sdio", g_ifx_pmcu_dir_debug); remove_proc_entry("spi", g_ifx_pmcu_dir_debug); remove_proc_entry("uart", g_ifx_pmcu_dir_debug); remove_proc_entry("switch", g_ifx_pmcu_dir_debug); remove_proc_entry("ppe", g_ifx_pmcu_dir_debug); remove_proc_entry("ve", g_ifx_pmcu_dir_debug); remove_proc_entry("fxo", g_ifx_pmcu_dir_debug); remove_proc_entry("fxs", g_ifx_pmcu_dir_debug); remove_proc_entry("dect", g_ifx_pmcu_dir_debug); remove_proc_entry("wlan", g_ifx_pmcu_dir_debug); remove_proc_entry("dsl", g_ifx_pmcu_dir_debug); remove_proc_entry("usb", g_ifx_pmcu_dir_debug); remove_proc_entry("eth", g_ifx_pmcu_dir_debug); remove_proc_entry("cpu", g_ifx_pmcu_dir_debug); remove_proc_entry(g_ifx_pmcu_dir_debug->name, NULL); g_ifx_pmcu_dir_debug = NULL; remove_proc_entry("chipid", g_ifx_pmcu_dir_pmcu); remove_proc_entry("version", g_ifx_pmcu_dir_pmcu); remove_proc_entry("device_list", g_ifx_pmcu_dir_pmcu); remove_proc_entry(g_ifx_pmcu_dir_pmcu->name, NULL); g_ifx_pmcu_dir_pmcu = NULL; return 0; } #endif /* CONFIG_PROC_FS */ static int __init ifx_pmcu_init(void) { int err = 0; int i = 0; IFX_uint32_t iflags; PMCU_DEBUG(PMCU, "ifx_pmcu_init is called\n"); /* PMCU device map table is initialized during declaration */ /* init powerState request ringbuffer */ memset(ifx_pmcu_reqBuffer, 0, sizeof(ifx_pmcu_reqBuffer)); /* register port device */ #ifdef PMCU_DYNAMIC_MAJOR_NO ifx_pmcu_major = register_chrdev (0, IFX_PMCU_DEVICE_NAME, &ifx_pmcu_fops); if (ifx_pmcu_major < 0) { PMCU_ERR(PMCU, "ifx-pmcu: Error! Could not register pmcu device. #%d\n", err); return ifx_pmcu_major; } #else err = register_chrdev (ifx_pmcu_major, IFX_PMCU_DEVICE_NAME, &ifx_pmcu_fops); if (err != 0) { PMCU_ERR(PMCU, "ifx-pmcu: Error! Could not register pmcu device. #%d\n", err); return err; } #endif #ifdef CONFIG_PROC_FS ifx_pmcu_proc_EntriesInstall(); #endif down(&ifx_pmcu_map_mutex); spin_lock_irqsave(&ifx_pmcu_lock, iflags); /* Init PMCU device map table: only module name; prerequisite->compiler initialise maptable to NULL!! Sequence of calling module_init by the kernel can not be influenced in a regulare way. Therefore it may happen that a pmcu_register is called by an other module before pmcu_module_init is called. That's why the map table must be initialised before runtime! */ for (i = 0; i < IFX_PMCU_MODULE_ID_MAX; i++) { ifx_pmcu_map[i].pmcuModuleName = ifx_pmcu_mod[i]; } spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); up(&ifx_pmcu_map_mutex); init_waitqueue_head(&ifx_pmcu_wait_q); PMCU_DEBUG(PMCU, "Lantiq PMCU Device Driver Version %s\n", IFX_PMCU_DRV_VERSION); return 0; } static void __exit ifx_pmcu_exit (void) { int i = 0, j = 0; IFX_uint32_t iflags; PMCU_DEBUG(PMCU, "ifx_pmcu_exit is called\n"); down(&ifx_pmcu_map_mutex); spin_lock_irqsave(&ifx_pmcu_lock, iflags); /* clear PMCU device map table: first free allocated memory for dependency list's; than set entire map table to '0'*/ for (i = 0; i < IFX_PMCU_MODULE_ID_MAX; i++) { for (j = 0; j < MAX_PMCU_SUB_MODULE; j++) { if(ifx_pmcu_map[i].pmcuRegister[j].pmcuModuleDep != NULL){ kfree(ifx_pmcu_map[i].pmcuRegister[j].pmcuModuleDep); } } } memset(ifx_pmcu_map, 0, sizeof(IFX_PMCU_MAP_t)); spin_unlock_irqrestore(&ifx_pmcu_lock, iflags); up(&ifx_pmcu_map_mutex); #ifdef CONFIG_PROC_FS ifx_pmcu_proc_EntriesRemove(); #endif unregister_chrdev(ifx_pmcu_major, IFX_PMCU_DEVICE_NAME); return; } module_init (ifx_pmcu_init); module_exit (ifx_pmcu_exit); EXPORT_SYMBOL(ifx_pmcu_state_req); EXPORT_SYMBOL(ifx_pmcu_register); EXPORT_SYMBOL(ifx_pmcu_unregister); MODULE_LICENSE ("GPL"); MODULE_AUTHOR("Lantiq Deutschland GmbH"); MODULE_DESCRIPTION ("LANTIQ PMCU driver"); MODULE_SUPPORTED_DEVICE ("Amazon SE, Danube, XRX100, XRX200");