Android Camera序列11(MTK )---Flashlight HAL-Kernel
一、HAL层
1.1、HAL层闪光灯调用具体函数执行流程
1.1.1、Hal3AIf::getInstance的实现
打开相机APK时调用的初始化函数
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/aaa_hal_if.cpp
Hal3AIf::getInstance(MINT32 const i4SensorOpenIndex, E_FlowControl_Type eType, MINT32 i4SubsampleCount)
{
CAM_LOGD("[%s] sensoridx(%d)", __FUNCTION__, i4SensorOpenIndex);
switch (eType)
{
case Hal3AIf::E_FlowControl_Type_SMVR:
return Hal3AFlowCtrl_SMVR::getInstance(i4SensorOpenIndex, i4SubsampleCount);
case Hal3AIf::E_FlowControl_Type_NORMAL:
return Hal3AFlowCtrl::getInstance(i4SensorOpenIndex);
default:
return NULL;
}
}
1.1.2、Hal3AFlowCtrl::getInstance的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp
Hal3AIf*
Hal3AFlowCtrl::
getInstance(MINT32 i4SensorOpenIndex)
{
IHalSensorList* const pHalSensorList = MAKE_HalSensorList();
if (!pHalSensorList) return NULL;
MINT32 i4SensorDev = pHalSensorList->querySensorDevIdx(i4SensorOpenIndex);
switch (i4SensorDev)
{
case SENSOR_DEV_MAIN:
{
static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN);
_singleton.init(i4SensorOpenIndex);
return &_singleton;
}
case SENSOR_DEV_SUB:
{
static Hal3AFlowCtrl _singleton(SENSOR_DEV_SUB);
_singleton.init(i4SensorOpenIndex);
return &_singleton;
}
case SENSOR_DEV_MAIN_2:
{
static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN_2);
_singleton.init(i4SensorOpenIndex);
return &_singleton;
}
case SENSOR_DEV_SUB_2:
{
static Hal3AFlowCtrl _singleton(SENSOR_DEV_SUB_2);
_singleton.init(i4SensorOpenIndex);
return &_singleton;
}
case SENSOR_DEV_MAIN_3:
{
static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN_3);
_singleton.init(i4SensorOpenIndex);
return &_singleton;
}
default:
CAM_LOGE("Unsupport sensor device ID: %d\n", i4SensorDev);
AEE_ASSERT_3A_HAL("Unsupport sensor device.");
return MNULL;
}
}
1.1.3、Hal3AFlowCtrl::init的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp
MRESULT
Hal3AFlowCtrl::
init(MINT32 i4SensorOpenIndex) //can be called only once by RAW or YUV, no user count
{
MY_LOGD("[%s] +", __FUNCTION__);
m_fgLogEn = ::property_get_int32("vendor.debug.camera.log", 0);
if ( m_fgLogEn == 0 ) {
m_fgLogEn = ::property_get_int32("vendor.debug.camera.log.hal3a", 0);
}
m_u4FrmIdFreeze = ::property_get_int32("vendor.debug.3a.freeze", 0);
m_bRRZDump = 0;
m_fgDebugLogWEn = DebugUtil::getDebugLevel(DBG_3A);
IHalSensorList*const pHalSensorList = MAKE_HalSensorList();
if (!pHalSensorList) return 0;
#if (CAM3_3ATESTLVL <= CAM3_3AUT)
I3AWrapper::E_TYPE_T eType = I3AWrapper::E_TYPE_DFT;
#else
MINT32 eSensorType = pHalSensorList->queryType(i4SensorOpenIndex);
I3AWrapper::E_TYPE_T eType = I3AWrapper::E_TYPE_RAW;
switch (eSensorType)
{
case NSSensorType::eRAW:
eType = I3AWrapper::E_TYPE_RAW;
break;
case NSSensorType::eYUV:
eType = I3AWrapper::E_TYPE_YUV;
break;
default:
eType = I3AWrapper::E_TYPE_DFT;
break;
}
#endif
m_i4SensorOpenIdx = i4SensorOpenIndex;
// create 3A wrapper
if (m_p3AWrap == NULL)
{
m_p3AWrap = I3AWrapper::getInstance(eType, i4SensorOpenIndex);
if (m_p3AWrap)
{
MY_LOGD_IF(m_fgLogEn, "[%s] m_p3AWrapper(%p) created OK", __FUNCTION__, m_p3AWrap);
}
else
{
CAM_LOGE("m_p3AWrapper created fail!");
AEE_ASSERT_3A_HAL("m_p3AWrapper created fail!");
}
}
// create Vsync event
//IEventIrq::ConfigParam IrqConfig(i4SensorDev, i4SensorOpenIndex, 5000, IEventIrq::E_Event_Vsync);
//m_pEventIrq = IEventIrq::createInstance(IrqConfig, "VSIrq");
m_SttBufQEnable = property_get_int32("vendor.debug.camera.SttBufQ.enable", 0);
if (m_SttBufQEnable) {
ISttBufQ::createSingleton(m_i4SensorDev, LOG_TAG);
}
// create statistic control
#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
if (m_p3ASttCtrl == NULL && eType == I3AWrapper::E_TYPE_RAW)
{
m_p3ASttCtrl = Hal3ASttCtrl::createInstance(m_i4SensorDev, i4SensorOpenIndex);
if (m_p3ASttCtrl)
{
MY_LOGD_IF(m_fgLogEn, "[%s] m_p3ASttCtrl(%p) created OK", __FUNCTION__, m_p3ASttCtrl);
}
else
{
CAM_LOGE("m_p3ASttCtrl created fail!");
AEE_ASSERT_3A_HAL("m_p3ASttCtrl created fail!");
}
}
#endif
// create AA thread
if (m_pThread == NULL)
{
/* 闪光灯的相关操作在这个线程中实现 */
m_pThread = IThread3A::createInstance(this);
if (m_pThread)
{
MY_LOGD_IF(m_fgLogEn, "[%s] m_pThread(%p) created OK", __FUNCTION__, m_pThread);
}
else
{
CAM_LOGE("m_pThread created fail!");
AEE_ASSERT_3A_HAL("m_pThread created fail!");
}
}
// ResultPool - Get result pool object
if(m_pResultPoolObj == NULL)
m_pResultPoolObj = IResultPool::getInstance(m_i4SensorDev);
if(m_pResultPoolObj == NULL)
CAM_LOGE("ResultPool getInstance fail");
MY_LOGD("[%s] - eType(%d), sensor(%d), sensorIdx(%d)", __FUNCTION__, eType, m_i4SensorDev, i4SensorOpenIndex);
return S_3A_OK;
}
1.1.4、IThread3A::createInstance的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp
IThread3A*
IThread3A::createInstance(Hal3AIf* pHal3A)
{
return Thread3AImp::createInstance(pHal3A);
}
1.1.5、Thread3AImp::createInstance的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp
IThread3A*
Thread3AImp::
createInstance(Hal3AIf* pHal3A)
{
//static Thread3AImp singleton(pHal3A);
//singleton.createThread(); // user count protected
//return &singleton;
Thread3AImp* pThd3A = new Thread3AImp(pHal3A);
//if (pThd3A)
//pThd3A->createThread();
return pThd3A;
}
1.1.6、Thread3AImp::Thread3AImp的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp
Thread3AImp::
Thread3AImp(Hal3AIf* pHal3A)
: mpHal3A(pHal3A)
, mu4LogEn(MFALSE)
, mbListenUpdate(MFALSE)
, mbSetFromP1(MFALSE)
, mLock()
{
MY_LOGD("[%s] Enter (%d)", __FUNCTION__, pHal3A->getSensorDev());
createThread();
}
1.1.7、Thread3AImp::createThread的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp
MVOID
Thread3AImp::createThread()
{
//Mutex::Autolock lock(mLock); // Nelson : mutual exclusive by atomic_flag
GET_PROP("vendor.debug.3a.log", 0, mu4LogEn);
mu4DebugLogWEn = DebugUtil::getDebugLevel(DBG_3A);
if (!thread_alive.test_and_set())
{
MY_LOGD("[%s] +", __FUNCTION__);
sem_init(&mSem, 0, 0);
//pthread_create(&mThread, NULL, onThreadLoop, this);
create3Athread = thread(onThreadLoop, this);
MY_LOGD("[%s] -", __FUNCTION__);
}
}
在打开相机APK后,会通过 Thread3AImp::createThread() 函数创建并执行了线程 create3Athread ,它最终会调用 Thread3AImp::onThreadLoop() 方法
1.1.8、Thread3AImp::onThreadLoop的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp
MVOID*
Thread3AImp::onThreadLoop(MVOID *arg)
{
MY_LOGD("+");
CmdQ_T rCmd(ECmd_Update, ParamIspProfile_T());
Thread3AImp *_this = reinterpret_cast<Thread3AImp*>(arg);
// AaaTimer ccTimer;
MBOOL bGetCmd;
MBOOL fgLogEn = (_this->mu4LogEn & EN_LOG_3A_THREAD) ? MTRUE : MFALSE;
MUINT32 cmdQSize = 0;
// (1) change thread setting
_this->changeThreadSetting();
// (2) thread-in-loop
while (_this->getCommand(rCmd, bGetCmd, MFALSE)) /* 从 getCommand() 中获取rCmd的值 */
{
//MY_LOGD_IF(1, "rCmd(%d)+", rCmd);
//
DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 0);
switch (rCmd.eCmd)
{
case ECmd_Update:
if (!_this->mbListenUpdate)
{
MY_LOGD("[%s] Exit 3A thread", __FUNCTION__);
break;
}
MY_LOGD_IF(fgLogEn, "rCmd(%d)+", rCmd.eCmd);
DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 1);
/* 在这函数里不断通过 post_commnad 发送 ECmd_Update 命令 */
if (!_this->mpHal3A->doUpdateCmd(&rCmd.rParamIspProfile))//on3aprocfinish
{
char strErr[512] = {'\0'};
sprintf(strErr, "ECmd_Update failed #(%d)", rCmd.rParamIspProfile.i4MagicNum);
CAM_LOGE("%s", strErr);
AEE_ASSERT_3A_HAL(strErr);
}
if (!_this->mbSetFromP1) //only check before first set from MW
{
if (rCmd.rParamIspProfile.iValidateOpt != ParamIspProfile_T::EParamValidate_None)
{
MY_LOGD("[%s] First command from P1",__FUNCTION__);
_this->mbSetFromP1 = MTRUE;
}
}
DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 2);
_this->mpHal3A->on3AProcSet(_this->mbSetFromP1);//vsync callback
DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 3);
{
Mutex::Autolock autoLock(_this->mModuleMtx);
cmdQSize = _this->mCmdQ.size();
}
if (cmdQSize)
{
MY_LOGD_IF(fgLogEn, "[%s] Cmd from P1", __FUNCTION__);
}
else
{
if (_this->mbSetFromP1)
{
_this->mpHal3A->doUpdateCmdDummy();
MY_LOGD_IF(fgLogEn, "[%s] Dummy cmd from 3A Thread", __FUNCTION__);
}
}
MY_LOGD_IF(fgLogEn, "rCmd(%d), magic#(%d)-", rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);
break;
default:
AAA_TRACE_HAL(Thread3A_CmdDefault);
MY_LOGD_IF(fgLogEn, "rCmd(%d)+", rCmd.eCmd);
//
DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 4);
if ( ! _this->mpHal3A->postCommand(rCmd.eCmd, &rCmd.rParamIspProfile))
{
CAM_LOGE("Cmd(%d) failed", rCmd.eCmd);
AEE_ASSERT_3A_HAL("onThreadLoop postCommand fail(2).");
}
//
if (rCmd.eCmd != ECmd_PrecaptureStart && rCmd.eCmd != ECmd_PrecaptureEnd)
{
::sem_post(&_this->mSem);
}
MY_LOGD_IF(fgLogEn, "rCmd(%d), magic#(%d)-", rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);
AAA_TRACE_END_HAL;
break;
}
DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", -1);
//
}
MY_LOGD("-");
return NULL;
}
由 onThreadLoop 这个函数名就可以知道,在这个线程内会不断的进行循环操作,直到退出相机APK。具体的循环操作是在 while (_this->getCommand(rCmd, bGetCmd, MFALSE)) 中实现的。由上述代码可知,当从 _this->getCommand() 中获取的 rCmd.eCmd 等于 ECmd_Update 时,会一直处于拍照前的预览状态,并不断的调用 if (!_this->mpHal3A->doUpdateCmd(&rCmd.rParamIspProfile)) 刷新预览界面,而当发生其他操作,比如开始拍照,则会调用 default 下的 if ( ! _this->mpHal3A->postCommand(rCmd.eCmd, &rCmd.rParamIspProfile)) 将 ECmd_Update 切换成其他的状态。
1.1.9、Thread3AImp::getCommand的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp
MBOOL
Thread3AImp::getCommand(IThread3A::CmdQ_T &rCmd, MBOOL &bGetCmd, MBOOL en_timeout)
{
//returning MFALSE means break onThreadLoop
MBOOL fgLogEn = (mu4LogEn & EN_LOG_3A_THREAD) ? MTRUE : MFALSE;
MY_LOGD_IF(fgLogEn, "[%s] +", __FUNCTION__);
Mutex::Autolock autoLock(mModuleMtx);
MY_LOGD_IF(fgLogEn, "[%s] mCmdQ.size()=%d, en_timeout(%d)", __FUNCTION__, (MINT32)mCmdQ.size(), en_timeout);
if (mCmdQ.size() == 0)
{
if (en_timeout)
{
MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.waitRelative +", __FUNCTION__);
mCmdQCond.waitRelative(mModuleMtx, (long long int)27000000);
MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.waitRelative -", __FUNCTION__);
}
else
{
MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.wait +", __FUNCTION__);
mCmdQCond.wait(mModuleMtx);
MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.wait -", __FUNCTION__);
}
}
if (mCmdQ.size() == 0) //this is only for en_timeout == 1 & timeout case
{
MY_LOGD_IF(fgLogEn, "[%s] mCmdQ.size() = %d after mCmdQCond.wait/waitRelative\n", __FUNCTION__, (MINT32)mCmdQ.size());
bGetCmd = MFALSE; // timeout, no command received
return MTRUE;
}
bGetCmd = MTRUE;
// two cases: 1. en_timeout == 1, but get command in time
// 2. en_timeout == 0, finally get command
rCmd = *mCmdQ.begin();
MY_LOGD_IF(fgLogEn, "CmdQ-size(%d), todo(%d, %d)", (MINT32)mCmdQ.size(), rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);
mCmdQ.erase(mCmdQ.begin());
return rCmd.eCmd != ECmd_Uninit;
}
相机APK所处状态的更新最终是由 *rCmd = mCmdQ.begin(); 获取的,然后通过 return rCmd.eCmd != ECmd_Uninit; 输出返回值。当相机APK退出的时候,rCmd.eCmd 的值为10,此时等于 ECmd_Uninit ,所以 rCmd.eCmd != ECmd_Uninit 为 false,此时跳出 while (_this->getCommand(rCmd, bGetCmd, MFALSE)) 循环。
1.1.10、Hal3AFlowCtrl::doUpdateCmd的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp
MBOOL
Hal3AFlowCtrl::
doUpdateCmd(const ParamIspProfile_T* pParam)
{
MINT32 i4MagicNum = pParam->i4MagicNum;
if (m_pThread->isEnd() || m_fgPreStop)
{
MY_LOGD("[%s] Stop updating #(%d)", __FUNCTION__, i4MagicNum);
return MTRUE;
}
//call notifyResult4TG API
if(m_bTgIntAEEn)
{
// ResultPool - Get History
MINT32 rHistoryReqMagic[HistorySize] = {0,0,0};
m_pResultPoolObj->getHistory(rHistoryReqMagic);
MY_LOGD_IF(m_fgLogEn, "[%s] History (Req0, Req1, Req2) = (#%d, #%d, #%d)", __FUNCTION__, rHistoryReqMagic[0], rHistoryReqMagic[1], rHistoryReqMagic[2]);
//call notifyResult4TG API
MY_LOGD_IF(m_fgLogEn, "[%s] notifyResult4TG Previous Req (#%d) New Req (#%d) bTgIntAEEn(%d)",__FUNCTION__, rHistoryReqMagic[1], i4MagicNum, m_bTgIntAEEn);
if(rHistoryReqMagic[1] != 0)
notifyResult4TG(rHistoryReqMagic[1]);
}
AAA_TRACE_D("3A_Update #(%d)", i4MagicNum);
/* 这里发送的命令会更新状态 */
MBOOL fgRet = postCommand(ECmd_Update, pParam);
AAA_TRACE_END_D;
if (!fgRet)
{
CAM_LOGE("ECmd_Update failed");
return MFALSE;
}
if(m_fgPreStop)
{
MY_LOGD("[%s] Stop wait vsirq #(%d)", __FUNCTION__, i4MagicNum);
return MTRUE;
}
IEventIrq::Duration duration;
MY_LOGD_IF(m_fgLogEn, "[%s] start waitVSirq.", __FUNCTION__);
AAA_TRACE_D("3A_WaitVSync #(%d)", i4MagicNum);
AAA_TRACE_DRV(WaitVSync);
m_pEventIrq->wait(duration);
#if (CAM3_3A_ISP_30_EN)
// Apply 3A ISP info at the time after Vsync (isp 3.0 only)
m_p3AWrap->set3AISPInfo();
#endif
//
AAA_TRACE_END_DRV;
AAA_TRACE_END_D;
return MTRUE;
}
当进入相机APK,但还没有开始拍照时,会不断调用 doUpdateCmd() 函数更新相机闪光灯的状态,即不断的执行 MBOOL fgRet = postCommand(ECmd_Update, pParam); 这条代码直到退出相机APK。
打开闪光灯
1.1.11、Hal3AFlowCtrl::postCommand的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp
MBOOL
Hal3AFlowCtrl::
postCommand(ECmd_T const eCmd, const ParamIspProfile_T* pParam)
{
MY_LOGD_IF(m_fgLogEn, "[%s] enter(%d)", __FUNCTION__, eCmd);
MINT32 i4MagicNum = 0;
MINT32 i4MagicNumCur = 0;
MBOOL bMainFlash = MFALSE;
MBOOL bPre = MFALSE;
ParamIspProfile_T rParamIspProf = *pParam;
m_rCapParam.u4CapType = E_CAPTURE_NORMAL;
if (eCmd == ECmd_CameraPreviewStart) /* 刚打开相机APK以及拍完照后条件会成立,但只会调用一次 */
{
MY_LOGD("[%s] Clear ResultPool", __FUNCTION__);
// ResultPool - preview start to clear ResultPool
m_pResultPoolObj->clearAllResultPool();
m_rParam.i8ExposureTime = 0;
if (m_pEventIrq == NULL)
{
IEventIrq::ConfigParam IrqConfig(m_i4SensorDev, m_i4SensorOpenIdx, 5000000, IEventIrq::E_Event_Vsync);
IrqConfig.i4TgInfo = m_i4TgInfo;
m_pEventIrq = IEventIrq::createInstance(IrqConfig, "VSIrq");
}
#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
if(m_p3ASttCtrl)
m_p3ASttCtrl->startStt();
#endif
m_p3AWrap->start();
}
if (eCmd == ECmd_Update)
{
MY_LOGD("[%s] m_rParam.u4AeMode(%d), m_rParam.i8ExposureTime(%lld), iValidateOpt(%d)", __FUNCTION__, (MINT32)m_rParam.u4AeMode, (long long)m_rParam.i8ExposureTime, rParamIspProf.iValidateOpt);
/* rParamIspProf.iValidateOpt 的值默认是1,但需要开启闪光灯时会切换成0 */
if (rParamIspProf.iValidateOpt != ParamIspProfile_T::EParamValidate_None)
{
i4MagicNum = rParamIspProf.i4MagicNum;
i4MagicNumCur = rParamIspProf.i4MagicNumCur;
bMainFlash = m_p3AWrap->chkMainFlashOnCond();
bPre = m_p3AWrap->chkPreFlashOnCond();
rParamIspProf.bMainFlash = bMainFlash;
MY_LOGD_IF(m_fgLogEn, "[%s] (bMainFlash,bPre):(%d,%d)", __FUNCTION__, bMainFlash,bPre);
if ((bMainFlash||bPre) && i4MagicNum != 0)
{
m_u4FlashOnIdx = i4MagicNum;
m_fgFlashOn = 1;
}
if (bMainFlash) /* bMainFlash 需要为 true */
{
/* 这里开启闪光灯 */
m_p3AWrap->setFlashLightOnOff(1, 1);
m_i4MainFlashOnIdx = i4MagicNum;
m_fgInternalFlashOn = MFALSE;
}
if (bPre) {
m_p3AWrap->setFlashLightOnOff(1, 0);
m_fgInternalFlashOn = MFALSE;
}
m_p3AWrap->postCommand(eCmd, &rParamIspProf);
if (m_p3AWrap->chkCapFlash())
{
m_rCapParam.u4CapType = E_CAPTURE_HIGH_QUALITY_CAPTURE;
}
MY_LOGD_IF(m_fgLogEn, "[%s][HQC] inform p1 capture type (%d)", __FUNCTION__, m_rCapParam.u4CapType);
i4MagicNumCur = m_p3AWrap->queryMagicNumber();
MY_LOGD_IF(m_fgLogEn, "[%s] (Req, Stt) = (#%d, #%d)", __FUNCTION__, i4MagicNum, i4MagicNumCur);
// ResultPool - must update u4MagicNumCur to resultPool i4StatiticMagic
MBOOL ret = m_pResultPoolObj->updateResultCFG(i4MagicNum, i4MagicNumCur); //update ReqResult i4StatiticMagic of CFG
if(!ret)
MY_LOGE("[%s] update MagicNumCur to resultPool i4StatiticMagic fail", __FUNCTION__);
// i4StatiticMagic for high quality
AAA_TRACE_HAL(on3AProcFinish);
on3AProcFinish(i4MagicNum, i4MagicNumCur);
AAA_TRACE_END_HAL;
}else {
if (m_rParam.u4AeMode == 0 && m_rParam.i8ExposureTime >= 400000000)
{
m_p3AWrap->postCommand(eCmd, &rParamIspProf);
}
else
{
// dummy frame need to enqueueHwBuf
Hal3ASttCtrl* p3ASttCtrl = Hal3ASttCtrl::getInstance(m_i4SensorDev);
// enque AAO
IBufMgr* pAAOBufMgr = p3ASttCtrl->getBufMgr(BUF_AAO);
if(pAAOBufMgr) pAAOBufMgr->enqueueHwBuf();
}
}
IspTuningBufCtrl::getInstance(m_i4SensorDev)->clearP1Buffer();
}
else
{
m_p3AWrap->postCommand(eCmd, &rParamIspProf);
}
/* 拍照结束或者退出相机APK时,会调用 */
if (eCmd == ECmd_CameraPreviewEnd)
{
MY_LOGD("[%s] reset bMainFlash", __FUNCTION__);
m_u4FlashOnIdx = -1;
#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
if(m_p3ASttCtrl)
m_p3ASttCtrl->stopStt();
#endif
m_p3AWrap->stop();
#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
if(m_p3ASttCtrl)
m_p3ASttCtrl->uninitStt();
#endif
if (m_pEventIrq)
{
m_pEventIrq->destroyInstance("VSIrq");
m_pEventIrq = NULL;
}
m_fgPreStop = MFALSE;
}
return MTRUE;
}
想要调用到 **m_p3AWrap->setFlashLightOnOff(1, 1); ** 开启闪光灯,需要 bMainFlash 变量为 true , 而 bMainFlash 是通过 bMainFlash = m_p3AWrap->chkMainFlashOnCond(); 这条代码进行赋值的。chkMainFlashOnCond() 在文件 Hal3ARawImp.cpp 中定义,具体代码如下:
1.1.12、Hal3ARawImp::chkPreFlashOnCond的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/isp_30/wrapper/Hal3ARawImp.cpp
MBOOL
Hal3ARawImp::
chkPreFlashOnCond() const
{
// Torch
FlashPolicy_T rFlashPolicy;
rFlashPolicy.bIsFlashOnCapture = isFlashOnCapture();
rFlashPolicy.bIsFlashCharging = (FlashMgr::getInstance(m_i4SensorDev)->getFlashState() == MTK_FLASH_STATE_CHARGING);
FlashHal::getInstance(m_i4SensorDev)->hasHw(rFlashPolicy.i4HWSuppportFlash);
CAM_LOGD_IF(m_3ALogEnable, "[%s] bIsFlashOnCapture(%d), bIsFlashCharging(%d), i4HWSuppportFlash(%d)", __FUNCTION__,
rFlashPolicy.bIsFlashOnCapture,
rFlashPolicy.bIsFlashCharging,
rFlashPolicy.i4HWSuppportFlash);
return HAL3A_POLICY_TORCH_ONOFF(m_i4SensorDev, m_rParam, rFlashPolicy);
}
MBOOL
Hal3ARawImp::
chkMainFlashOnCond() const
{
// Main Flash
FlashPolicy_T rFlashPolicy;
rFlashPolicy.bIsFlashOnCapture = isFlashOnCapture();
rFlashPolicy.bIsFlashCharging = (FlashMgr::getInstance(m_i4SensorDev)->getFlashState() == MTK_FLASH_STATE_CHARGING);
FlashHal::getInstance(m_i4SensorDev)->hasHw(rFlashPolicy.i4HWSuppportFlash);
CAM_LOGD_IF(m_3ALogEnable, "[%s] bIsFlashOnCapture(%d), bIsFlashCharging(%d), i4HWSuppportFlash(%d)", __FUNCTION__,
rFlashPolicy.bIsFlashOnCapture,
rFlashPolicy.bIsFlashCharging,
rFlashPolicy.i4HWSuppportFlash);
return HAL3A_POLICY_MAIN_FLASH_ONOFF(m_i4SensorDev, m_rParam, rFlashPolicy);
}
Hal3ARawImp::chkMainFlashOnCond() 和 Hal3ARawImp::chkPreFlashOnCond() 函数会不断的被调用直到退出相机APK。同理,关闭闪光灯实际也会调用到这两个函数,相应的条件成立后才会调用 m_p3AWrap->setFlashLightOnOff(0, 1); 关闭闪光灯。
关闭闪光灯
1.1.13、Hal3AFlowCtrl::notifyP1Done的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp
MVOID
Hal3AFlowCtrl::
notifyP1Done(MINT32 i4MagicNum, MVOID* /*pvArg*/)
{
MBOOL bMainFlash = m_p3AWrap->chkMainFlashOnCond();
MBOOL bPre = m_p3AWrap->chkPreFlashOnCond();
MBOOL bMagicNum = (i4MagicNum >= (MINT32)m_u4FlashOnIdx);
MY_LOGD_IF(m_fgLogEn, "[%s] i4MagicNum(%d), m_u4FlashOnIdx(%d), bMagicNum(%d), bMainFlash(%d), bPre(%d), m_fgFlashOn(%d)", __FUNCTION__, i4MagicNum, m_u4FlashOnIdx, bMagicNum, bMainFlash, bPre, m_fgFlashOn);
if ( bMagicNum && !bMainFlash && !bPre && m_fgFlashOn)
{
/* 这里关闭闪光灯 */
m_p3AWrap->setFlashLightOnOff(0, 1); // don't care main or pre
m_u4FlashOnIdx = -1;
m_fgFlashOn = 0;
}
if (bMagicNum && m_i4MainFlashOnIdx != -1)
{
m_i4MainFlashOnIdx = -1;
}
MBOOL isNeedTurnOnPreFlash = m_p3AWrap->isNeedTurnOnPreFlash();
MY_LOGD_IF(m_fgLogEn,"[%s] isNeedTurnOnPreFlash(%d)", __FUNCTION__, isNeedTurnOnPreFlash);
if(m_fgInternalFlashOn != isNeedTurnOnPreFlash)
{
m_fgInternalFlashOn = isNeedTurnOnPreFlash;
MY_LOG("[%s] setPreFlashOnOff(%d)", __FUNCTION__, m_fgInternalFlashOn);
m_p3AWrap->setPreFlashOnOff(isNeedTurnOnPreFlash);
}
if ((m_u4FrmIdFreeze != 0) && (static_cast<MUINT32>(i4MagicNum) == m_u4FrmIdFreeze))
{
MY_LOGD("[%s]+ one-shot dump @%d", __FUNCTION__, i4MagicNum);
m_p3AWrap->dumpP1Params(i4MagicNum);
::property_set("vendor.debug.rrz.dump", 0);
m_u4FrmIdFreeze = 0;
MY_LOGD("[%s]- one-shot dump @%d", __FUNCTION__, i4MagicNum);
}
}
控制闪光灯开启和关闭的方法
1.1.14、Hal3ARawImp::setFlashLightOnOff的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/isp_30/wrapper/Hal3ARawImp.cpp
MBOOL
Hal3ARawImp::
setFlashLightOnOff(MBOOL bOnOff, MBOOL bMainPre)
{
#if CAM3_FLASH_FEATURE_EN
CAM_LOGD_IF(m_3ALogEnable, "[%s] bOnOff(%d) + ", __FUNCTION__, bOnOff);
if (m_bIsFlashOpened == bOnOff)
{
CAM_LOGD("[%s] flashlight unchanged, bOnOff(%d)", __FUNCTION__, bOnOff);
}
else if (!bOnOff)
{
//modified to update strobe state after capture for ae manager
IAeMgr::getInstance().setStrobeMode(m_i4SensorDev, MFALSE);
IAwbMgr::getInstance().setStrobeMode(m_i4SensorDev, AWB_STROBE_MODE_OFF);
if (bMainPre)
FlashHal::getInstance(m_i4SensorDev)->setOnOff(MFALSE, FLASH_HAL_SCENARIO_MAIN_FLASH);
else
FlashHal::getInstance(m_i4SensorDev)->setOnOff(MFALSE, FLASH_HAL_SCENARIO_VIDEO_TORCH);
}
else //flash on
{
if (bMainPre){
FlashHal::getInstance(m_i4SensorDev)->setOnOff(MTRUE, FLASH_HAL_SCENARIO_MAIN_FLASH);
IAwbMgr::getInstance().SetMainFlashInfo(m_i4SensorDev, MTRUE);
}
else{
FlashHal::getInstance(m_i4SensorDev)->setOnOff(MTRUE, FLASH_HAL_SCENARIO_VIDEO_TORCH);
IAwbMgr::getInstance().setStrobeMode(m_i4SensorDev, AWB_STROBE_MODE_ON);
}
}
if(m_bIsFlashOpened != bOnOff)
{
CAM_LOGD("[%s] flashlight is changed (%d->%d), and assign bOnOff to m_bIsFlashOpened", __FUNCTION__, m_bIsFlashOpened, bOnOff);
m_bIsFlashOpened = bOnOff;
handleBadPicture(m_rParam.i4MagicNum);
}
CAM_LOGD_IF(m_3ALogEnable, "[%s] - ", __FUNCTION__);
#endif
return MTRUE;
}
1.1.15、FlashHal::setOnOff的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/flash_mgr/flash_hal.cpp
int FlashHal::setOnOff(int enable, FLASH_HAL_SCENARIO_ENUM scenario)
{
logI("setOnOff(): type(%d), enable(%d), scenario(%d).", mStrobeTypeId, enable, scenario);
/* verify arguments */
if (verifyScenario(scenario)) {
logE("setOnOff(): invalid arguments.");
return -1;
}
if (!isAvailable()) {
logI("setOnOff(): sensorDev(%d) not available.", mSensorDev);
return -1;
}
if (scenario == FLASH_HAL_SCENARIO_MAIN_FLASH) {
/* get timeout */
int currentTime = getMs();
if (enable) {
mFlashHalTimeInfo.mfStartTime = currentTime;
mFlashHalTimeInfo.mfIsTimeout = 0;
mFlashHalTimeInfo.mfTimeout = mFlashHalInfo[FLASH_HAL_SCENARIO_MAIN_FLASH].timeout;
if (mStrobeCtNum > 1)
mFlashHalTimeInfo.mfTimeoutLt = mFlashHalInfo[FLASH_HAL_SCENARIO_MAIN_FLASH].timeoutLt;
} else {
mFlashHalTimeInfo.mfEndTime = currentTime;
int flashOnPeriod = mFlashHalTimeInfo.mfEndTime - mFlashHalTimeInfo.mfStartTime;
if (flashOnPeriod > mFlashHalTimeInfo.mfTimeout &&
mFlashHalTimeInfo.mfTimeout)
mFlashHalTimeInfo.mfIsTimeout = 1;
if (mStrobeCtNum > 1)
if (flashOnPeriod > mFlashHalTimeInfo.mfTimeoutLt &&
mFlashHalTimeInfo.mfTimeoutLt)
mFlashHalTimeInfo.mfIsTimeout = 1;
}
}
/* set flash info to ISP */ // TODO: moveout
if (scenario != FLASH_HAL_SCENARIO_TORCH) {
FLASH_INFO_T finfo;
finfo.flashMode = FLASHLIGHT_FORCE_OFF; // TODO: not use
finfo.isFlash = enable;
//IspTuningMgr::getInstance().setFlashInfo(mSensorDev, finfo);
}
if (enable)
return setFlashOn(mFlashHalInfo[scenario]);
else
return setFlashOff();
}
开启闪光灯
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/flash_mgr/flash_hal.cpp
int FlashHal::setFlashOn(FlashHalInfo info)
{
Mutex::Autolock lock(mLock);
logI("setFlashOn(): duty(%d), timeout(%d), lt duty(%d), lt timeout(%d).",
info.duty, info.timeout, info.dutyLt, info.timeoutLt);
int isLow = 0;
isLowPower(&isLow);
if (isLow) {
logI("setFlashOn(): is low power.");
return 0;
}
/* set duty */
int dutyCur;
int dutyCurLt;
{
mpStrobe->getDuty(&dutyCur);
if (dutyCur != info.duty)
mpStrobe->setDuty(info.duty);
}
if (mStrobeCtNum > 1) {
mpStrobe2->getDuty(&dutyCurLt);
if (dutyCurLt != info.dutyLt)
mpStrobe2->setDuty(info.dutyLt);
}
/* set on/off */
int bOn;
{
mpStrobe->isOn(&bOn);
if (info.duty < 0) {
/* 实际调用的是 StrobeDrvFlashlight::setOnOff */
mpStrobe->setOnOff(0);
} else {
mpStrobe->setTimeOutTime(info.timeout);
mpStrobe->setOnOff(1);
}
}
if (mStrobeCtNum > 1) {
mpStrobe2->isOn(&bOn);
if (info.dutyLt < 0) {
mpStrobe2->setOnOff(0);
} else {
mpStrobe2->setTimeOutTime(info.timeoutLt);
mpStrobe2->setOnOff(1);
}
}
return 0;
}
关闭闪光灯
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/flash_mgr/flash_hal.cpp
int FlashHal::setFlashOff()
{
Mutex::Autolock lock(mLock);
logI("setFlashOff().");
mpStrobe->setOnOff(0); /* 实际调用的是 StrobeDrvFlashlight::setOnOff */
if (mStrobeCtNum > 1)
mpStrobe2->setOnOff(0);
mpStrobe->getHwFault(&mDriverFault);
return 0;
}
StrobeDrvFlashlight 继承于类 StrobeDrv , StrobeDrvFlashlight::setOnOff 是对 StrobeDrv 中虚函数 setOnOff 的覆写。
1.1.16、StrobeDrvFlashlight::setOnOff 的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/strobe/strobe_drv_flashlight.cpp
int StrobeDrvFlashlight::setOnOff(int enable)
{
int ret = 0;
/* verify arguments */
if (verifyTypeCt(mTypeId, mCtId)) {
logE("setOnOff(): error type/ct(%d,%d).", mTypeId, mCtId);
return -1;
}
if (enable != MTRUE && enable != MFALSE && enable != 2) {
logE("setOnOff(): error enable(%d).", enable);
return -1;
}
logI("setOnOff(): enable(%d).", enable);
/* get strobe fops handler */
StrobeDrvFlashlightFops *pStrobeDrvFlashlightFops = StrobeDrvFlashlightFops::getInstance();
if (enable == MTRUE) {
/* record time at turning on */
if (mIsOn == MFALSE)
mOnTime = getMs();
/* get pre-on time from driver */
int needPreOnTime = 0;
getPreOnTimeMsDuty(mDuty, &needPreOnTime);
needPreOnTime = min(needPreOnTime, MAX_NEED_PRE_ON_TIME);
/* sleep for pre-on */
if (needPreOnTime > 0) {
if (mPreOnTime == -1) {
setPreOn();
logI("setOnOff(): needs pre-on time(%d ms).", needPreOnTime);
sleepMs(needPreOnTime);
} else {
long int curTime = getMs();
int sleepTimeMs = needPreOnTime - (curTime - mPreOnTime);
sleepTimeMs = min(sleepTimeMs, needPreOnTime);
if (sleepTimeMs > 0) {
logI("setOnOff(): still needs pre-on time(%d ms).", sleepTimeMs);
sleepMs(sleepTimeMs);
}
}
}
/* enable strobe */
ret = pStrobeDrvFlashlightFops->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, MTRUE);
logI("setOnOff(): on time(%ld).", mOnTime);
} else if (enable == MFALSE) {
if (mIsOn == MTRUE) {
mOffTime = getMs();
if (mTimeOutTime && (mOffTime - mOnTime > mTimeOutTime))
logI("setOnOff(): timeout.");
}
/* clear set pre-on time */
mPreOnTime = -1;
/* disable strobe */
ret = pStrobeDrvFlashlightFops->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, MFALSE);
logI("setOnOff(): off time(%ld).", mOffTime);
}
else if (enable == 2) {
/* enable strobe */
ret = pStrobeDrvFlashlightFops->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, 2);
logI("setOnOff(): on time(%ld).", mOnTime);
}
if (!ret)
mIsOn = enable;
else
logE("setOnOff(): failed to ioctl.");
return ret;
}
1.1.17、StrobeDrvFlashlightFops::sendCommand的实现
./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/strobe/strobe_drv_flashlight_fops.cpp
int StrobeDrvFlashlightFops::sendCommand(int cmd, int typeId, int ctId, int arg)
{
Mutex::Autolock lock(mLock);
if (mStrobeHandle < 0) {
logD("sendCommandRet(): failed with no strobe handler.");
return -1;
}
/* setup arguments */
struct flashlight_user_arg strobeArg;
strobeArg.type_id = typeId;
strobeArg.ct_id = ctId;
strobeArg.arg = arg;
/* send ioctl */
int ret = ioctl(mStrobeHandle, cmd, &strobeArg); /* 调用kernel中的ioctl */
logD("Send command: type/ct(%d,%d), cmd(%d).", typeId, ctId, cmd);
return ret;
}
二、KERNEL层
2.1、flash驱动加载流程
2.1.1、flashlight_init的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-core.c
module_init(flashlight_init);
static int __init flashlight_init(void)
{
int ret;
pr_debug("Init start\n");
...... /* 省略部分代码 */
ret = platform_driver_register(&flashlight_platform_driver);
if (ret) {
pr_err("Failed to register platform driver\n");
return ret;
}
#ifdef CONFIG_MTK_FLASHLIGHT_PT
register_low_battery_notify(
&pt_low_vol_callback, LOW_BATTERY_PRIO_FLASHLIGHT);
register_battery_percent_notify(
&pt_low_bat_callback, BATTERY_PERCENT_PRIO_FLASHLIGHT);
register_battery_oc_notify(
&pt_oc_callback, BATTERY_OC_PRIO_FLASHLIGHT);
#endif
pr_debug("Init done\n");
return 0;
}
2.1.2、flashlight_platform_driver结构体的实现
#ifdef CONFIG_OF
static const struct of_device_id flashlight_of_match[] = {
{.compatible = "mediatek,flashlight_core"},
{},
};
MODULE_DEVICE_TABLE(of, flashlight_of_match);
#else
..... /* 省略部分代码 */
#endif
static struct platform_driver flashlight_platform_driver = {
.probe = flashlight_probe,
.remove = flashlight_remove,
.shutdown = flashlight_shutdown,
.driver = {
.name = FLASHLIGHT_DEVNAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = flashlight_of_match, /* "mediatek,flashlight_core" */
#endif
},
};
./kernel-4.4/arch/arm/boot/dts/mt6739.dts
flashlight_core: flashlight_core {
compatible = "mediatek,flashlight_core";
};
2.1.3、flashlight_probe的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-core.c
static int flashlight_probe(struct platform_device *dev)
{
pr_debug("Probe start\n");
/* allocate char device number */
alloc_chrdev_region(&flashlight_devno, 0, 1, FLASHLIGHT_DEVNAME);
pr_debug("Allocate major number and minor number: (%d, %d)\n",
MAJOR(flashlight_devno),
MINOR(flashlight_devno));
/* allocate char device */
flashlight_cdev = cdev_alloc();
flashlight_cdev->ops = &flashlight_fops;
flashlight_cdev->owner = THIS_MODULE;
/* add char device to the system */
cdev_add(flashlight_cdev, flashlight_devno, 1);
/* create class */
flashlight_class = class_create(THIS_MODULE, FLASHLIGHT_CORE);
/* create device */
flashlight_device = device_create(flashlight_class, NULL, flashlight_devno,
NULL, FLASHLIGHT_DEVNAME);
/* create device file */
device_create_file(flashlight_device, &dev_attr_flashlight_strobe);
device_create_file(flashlight_device, &dev_attr_flashlight_pt);
device_create_file(flashlight_device, &dev_attr_flashlight_charger);
device_create_file(flashlight_device, &dev_attr_flashlight_capability);
device_create_file(flashlight_device, &dev_attr_flashlight_current);
device_create_file(flashlight_device, &dev_attr_flashlight_fault);
device_create_file(flashlight_device, &dev_attr_flashlight_sw_disable);
/* init flashlight */
fl_init();
pr_debug("Probe done\n");
return 0;
...... /* 省略部分代码 */
}
2.1.4、flashlight_led191_init的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
module_init(flashlight_led191_init);
static int __init flashlight_led191_init(void)
{
int ret;
PK_DBG("Init start.\n");
#ifndef CONFIG_OF
...... /* 省略部分代码 */
#endif
ret = platform_driver_register(&led191_platform_driver);
if (ret) {
PK_ERR("Failed to register platform driver\n");
return ret;
}
PK_DBG("Init done.\n");
return 0;
}
/* define device tree */
#ifndef LED191_DTNAME
#define LED191_DTNAME "mediatek,flashlights_led191"
#endif
#ifdef CONFIG_OF
static const struct of_device_id led191_gpio_of_match[] = {
{.compatible = LED191_DTNAME},
{},
};
MODULE_DEVICE_TABLE(of, led191_gpio_of_match);
#else
...... /* 省略部分代码 */
#endif
static struct platform_driver led191_platform_driver = {
.probe = led191_probe,
.remove = led191_remove,
.driver = {
.name = LED191_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = led191_gpio_of_match, /* "mediatek,flashlights_led191" */
#endif
},
};
./kernel-4.4/arch/arm/boot/dts/x006_k39tv1_bsp_1g.dtsi
flashlights_led191: flashlights_led191 {
compatible = "mediatek,flashlights_led191";
decouple = <0>;
channel@1 {
type = <0>;
ct = <0>;
part = <0>;
};
};
2.1.5、led191_probe的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
static int led191_probe(struct platform_device *pdev)
{
struct led191_platform_data *pdata = dev_get_platdata(&pdev->dev);
int err;
int i;
PK_DBG("Probe start.\n");
/* init pinctrl */
if (led191_pinctrl_init(pdev)) {
PK_DBG("Failed to init pinctrl.\n");
err = -EFAULT;
goto err;
}
/* init platform data */
if (!pdata) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
err = -ENOMEM;
goto err;
}
pdev->dev.platform_data = pdata;
err = led191_parse_dt(&pdev->dev, pdata);
if (err)
goto err;
}
/* init work queue */
INIT_WORK(&led191_work, led191_work_disable);
/* init timer */
hrtimer_init(&led191_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
led191_timer.function = led191_timer_func;
led191_timeout_ms = 100;
/* 为了降低功耗,led191芯片的初始化放到了“set_driver”中实现。这里直接return 0 */
/* init chip hw */
led191_chip_init();
/* clear usage count */
use_count = 0;
/* register flashlight device */
if (pdata->channel_num) {
for (i = 0; i < pdata->channel_num; i++)
if (flashlight_dev_register_by_device_id(&pdata->dev_id[i], &led191_ops)) {
err = -EFAULT;
goto err;
}
} else {
if (flashlight_dev_register(LED191_NAME, &led191_ops)) {
err = -EFAULT;
goto err;
}
}
PK_DBG("Probe done.\n");
return 0;
err:
return err;
}
2.1.6、led191_pinctrl_init的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
static int led191_pinctrl_init(struct platform_device *pdev)
{
int ret = 0;
/* get pinctrl */
led191_pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(led191_pinctrl)) {
PK_ERR("Failed to get flashlight pinctrl.\n");
ret = PTR_ERR(led191_pinctrl);
}
/* Flashlight pin initialization */
led191_hw_ch0_high = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH0_HIGH);
if (IS_ERR(led191_hw_ch0_high)) {
PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH0_HIGH);
ret = PTR_ERR(led191_hw_ch0_high);
}
led191_hw_ch0_low = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH0_LOW);
if (IS_ERR(led191_hw_ch0_low)) {
PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH0_LOW);
ret = PTR_ERR(led191_hw_ch0_low);
}
if (flashlight_device_num == 2) {
led191_hw_ch1_high = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH1_HIGH);
if (IS_ERR(led191_hw_ch1_high)) {
PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH1_HIGH);
ret = PTR_ERR(led191_hw_ch1_high);
}
led191_hw_ch1_low = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH1_LOW);
if (IS_ERR(led191_hw_ch1_low)) {
PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH1_LOW);
ret = PTR_ERR(led191_hw_ch1_low);
}
}
// sgm3785 flash ic,
#if defined(USING_SGM3785_FLASH)
/* sgm3785 flash ENM pin initialization */
led191_hw_ch01_high = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH01_HIGH);
if (IS_ERR(led191_hw_ch01_high)) {
PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH01_HIGH);
ret = PTR_ERR(led191_hw_ch01_high);
}
led191_hw_ch01_low = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH01_LOW);
if (IS_ERR(led191_hw_ch01_low)) {
PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH01_LOW);
ret = PTR_ERR(led191_hw_ch01_low);
}
led191_hw_ch01_pwm = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH01_PWM);
if (IS_ERR(led191_hw_ch01_pwm)) {
PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH01_PWM);
ret = PTR_ERR(led191_hw_ch01_pwm);
}
// init state, ENF = 0 && ENM = 0
if (!IS_ERR(led191_hw_ch0_low)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_ch0_low);// ENF = 0
}
if (!IS_ERR(led191_hw_ch01_low)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_ch01_low);// ENM = 0
}
pwm_setting.pwm_no = 3;
pwm_setting.mode = PWM_MODE_OLD;
pwm_setting.clk_div = CLK_DIV1;
pwm_setting.clk_src = PWM_CLK_OLD_MODE_32K;
pwm_setting.pmic_pad = 0;
pwm_setting.PWM_MODE_OLD_REGS.IDLE_VALUE = 0;
pwm_setting.PWM_MODE_OLD_REGS.GUARD_VALUE = 0;
pwm_setting.PWM_MODE_OLD_REGS.GDURATION = 0;
pwm_setting.PWM_MODE_OLD_REGS.WAVE_NUM = 0;
pwm_setting.PWM_MODE_OLD_REGS.DATA_WIDTH = 7; /* 7 level */
pwm_setting.PWM_MODE_OLD_REGS.THRESH = 0; // level to set.
#endif
// end +++
return ret;
}
2.1.7、led191_parse_dt的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
static int led191_parse_dt(struct device *dev,
struct led191_platform_data *pdata)
{
struct device_node *np, *cnp;
u32 decouple = 0;
int i = 0;
if (!dev || !dev->of_node || !pdata)
return -ENODEV;
np = dev->of_node;
pdata->channel_num = of_get_child_count(np);
if (!pdata->channel_num) {
PK_LOG("Parse no dt, node.\n");
return 0;
}
PK_LOG("Channel number(%d).\n", pdata->channel_num);
if (of_property_read_u32(np, "decouple", &decouple))
PK_LOG("Parse no dt, decouple.\n");
pdata->dev_id = devm_kzalloc(dev,
pdata->channel_num * sizeof(struct flashlight_device_id),
GFP_KERNEL);
if (!pdata->dev_id)
return -ENOMEM;
for_each_child_of_node(np, cnp) {
if (of_property_read_u32(cnp, "type", &pdata->dev_id[i].type))
goto err_node_put;
if (of_property_read_u32(cnp, "ct", &pdata->dev_id[i].ct))
goto err_node_put;
if (of_property_read_u32(cnp, "part", &pdata->dev_id[i].part))
goto err_node_put;
snprintf(pdata->dev_id[i].name, FLASHLIGHT_NAME_SIZE, LED191_NAME);
pdata->dev_id[i].channel = i;
pdata->dev_id[i].decouple = decouple;
PK_LOG("Parse dt (type,ct,part,name,channel,decouple)=(%d,%d,%d,%s,%d,%d).\n",
pdata->dev_id[i].type, pdata->dev_id[i].ct,
pdata->dev_id[i].part, pdata->dev_id[i].name,
pdata->dev_id[i].channel, pdata->dev_id[i].decouple);
i++;
}
return 0;
err_node_put:
of_node_put(cnp);
return -EINVAL;
}
2.1.8、flashlight_dev_register_by_device_id的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-core.c
/*
* Register devices
*
* Please DO NOT register flashlight device driver,
* until success to probe hardware.
*/
int flashlight_dev_register_by_device_id(
struct flashlight_device_id *dev_id,
struct flashlight_operations *dev_ops)
{
struct flashlight_dev *fdev;
if (!dev_id || !dev_ops)
return -EINVAL;
if (flashlight_verify_index(dev_id->type, dev_id->ct, dev_id->part)) {
pr_err("Failed to register device (%d,%d,%d)\n",
dev_id->type, dev_id->ct, dev_id->part);
return -EINVAL;
}
pr_info("Register device (%d,%d,%d)\n",
dev_id->type, dev_id->ct, dev_id->part);
mutex_lock(&fl_mutex);
fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
if (!fdev) {
mutex_unlock(&fl_mutex);
return -ENOMEM;
}
fdev->ops = dev_ops;
fdev->dev_id = *dev_id;
fdev->low_pt_level = -1;
fdev->charger_status = FLASHLIGHT_CHARGER_READY;
list_add_tail(&fdev->node, &flashlight_list);
mutex_unlock(&fl_mutex);
return 0;
}
EXPORT_SYMBOL(flashlight_dev_register_by_device_id);
2.1.9、led191_ops结构体的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
static struct flashlight_operations led191_ops = {
/*************************************************************
* 为了降低功耗,led191芯片的 open 和 release 都放到了“set_driver”
* 中实现。这里直接return 0
*************************************************************/
led191_open,
led191_release,
led191_ioctl,
led191_strobe_store,
led191_set_driver
};
2.1.10、led191_ioctl的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
/*****************************************************************************
* Flashlight operations
*****************************************************************************/
static int led191_ioctl(unsigned int cmd, unsigned long arg)
{
struct flashlight_dev_arg *fl_arg;
int channel;
ktime_t ktime;
fl_arg = (struct flashlight_dev_arg *)arg;
channel = fl_arg->channel;
g_flash_channel_idx = channel;
switch (cmd) {
case FLASH_IOC_SET_TIME_OUT_TIME_MS:
PK_DBG("FLASH_IOC_SET_TIME_OUT_TIME_MS(%d): %d\n",
channel, (int)fl_arg->arg);
led191_timeout_ms = fl_arg->arg;
break;
case FLASH_IOC_SET_DUTY:
PK_DBG("FLASH_IOC_SET_DUTY(%d): %d\n",
channel, (int)fl_arg->arg);
led191_set_level(fl_arg->arg);
break;
case FLASH_IOC_SET_ONOFF:
PK_DBG("FLASH_IOC_SET_ONOFF(%d): %d\n",
channel, (int)fl_arg->arg);
if (fl_arg->arg == 1) {
if (led191_timeout_ms) {
ktime = ktime_set(led191_timeout_ms / 1000,
(led191_timeout_ms % 1000) * 1000000);
hrtimer_start(&led191_timer, ktime, HRTIMER_MODE_REL);
}
led191_enable(channel);
} else {
led191_disable(channel);
hrtimer_cancel(&led191_timer);
}
break;
default:
PK_LOG("No such command and arg(%d): (%d, %d)\n",
channel, _IOC_NR(cmd), (int)fl_arg->arg);
return -ENOTTY;
}
return 0;
}
2.1.11、led191_enable和led191_disable的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
/* flashlight enable function */
static int led191_enable(int channel)
{
int pin = LED191_PINCTRL_PIN_HWEN;
PK_LOG("g_flash_duty = %d, channel:%d\n", g_flash_duty, channel);
led191_pinctrl_set(channel, 1);
return 0;
if (g_flash_duty == 1) {
led191_pinctrl_set(pin, 1);
} else {
led191_pinctrl_set(pin, 1);
led191_pinctrl_set(pin, 0);
}
led191_pinctrl_set(pin, 1);
return 0;
}
/* flashlight disable function */
static int led191_disable(int channel)
{
int pin = 0, state = 0;
PK_LOG("no use pin:%d, channel:%d, state:%d\n", pin, channel, state);
return led191_pinctrl_set(channel, state);
}
2.1.12、led191_pinctrl_set的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
static int led191_pinctrl_set(int pin, int state)
{
int ret = 0;
struct pinctrl_state *led191_hw_chx_low = led191_hw_ch0_low;
struct pinctrl_state *led191_hw_chx_high = led191_hw_ch0_high;
struct pinctrl_state *led191_hw_chx1_low = led191_hw_ch1_low;
struct pinctrl_state *led191_hw_chx1_high = led191_hw_ch1_high;
#if defined(USING_SGM3785_FLASH)
struct pinctrl_state *led191_hw_chx_enm_low = led191_hw_ch01_low;
struct pinctrl_state *led191_hw_chx_enm_high = led191_hw_ch01_high;
struct pinctrl_state *led191_hw_chx_pwm = led191_hw_ch01_pwm;
#endif
if (IS_ERR(led191_pinctrl)) {
PK_ERR("pinctrl is not available\n");
return -1;
}
PK_DBG("g_flash_channel_idx = %d\n", g_flash_channel_idx);
if (pin == 0) {
led191_hw_chx_low = led191_hw_ch0_low;
led191_hw_chx_high = led191_hw_ch0_high;
#if defined(USING_SGM3785_FLASH)
led191_hw_chx_enm_low = led191_hw_ch01_low;
led191_hw_chx_enm_high = led191_hw_ch01_high;
led191_hw_chx_pwm = led191_hw_ch01_pwm;
#endif
} else if (pin == 1 && (flashlight_device_num == 2)) {
led191_hw_chx1_low = led191_hw_ch1_low;
led191_hw_chx1_high = led191_hw_ch1_high;
} else {
PK_DBG("please check g_flash_channel_idx!!!\n");
}
switch (pin) {
case LED191_PINCTRL_PIN_HWEN:
PK_DBG("LED191_PINCTRL_PIN_HWEN\n");
#if defined(USING_SGM3785_FLASH)
if (state == LED191_PINCTRL_PINSTATE_HIGH) { // enable
if (led191_is_flash(g_flash_duty)) { // Flash
PK_LOG("goto flash mode on\n");
// 1. enter Active Mode, ENF = 0 && ENM = PWM && PWM high time <= 2.5ms
if (!IS_ERR(led191_hw_chx_low)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
}
// ENM PWM config
// a. config GPIO28 to PWM mode
if (!IS_ERR(led191_hw_chx_pwm)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_pwm);
}
// b. set PWM
pwm_setting.PWM_MODE_OLD_REGS.THRESH = g_flash_duty;
ret = pwm_set_spec_config(&pwm_setting);
PK_LOG("set PWM return value:%d\n", ret);
udelay(400);// delay 400us
// 2. enter Flash Mode, ENF = 1 && ENM = PWM
if (!IS_ERR(led191_hw_chx_high)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_high);
}
} else { // Torch
PK_LOG("goto torch mode on\n");
// 1. enter Movie/Torch Mode, ENF = 0 && ENM = 1 && time >= 5ms
if (!IS_ERR(led191_hw_chx_low)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
}
if (!IS_ERR(led191_hw_chx_enm_high)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_enm_high);
}
mdelay(5);// delay 5ms
}
} else { // disable
PK_LOG("exit Flash/Torch[Movie] mode, transit to Shutdown Mode\n");
// 1. exit flash Mode or Torch[Movie] mode, ENF = 0 && ENM = 0 && time >= 5ms
if (!IS_ERR(led191_hw_chx_low)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
}
if (!IS_ERR(led191_hw_chx_enm_low)) {
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_enm_low);
}
mdelay(5);// delay 5ms
}
#else
if (state == LED191_PINCTRL_PINSTATE_LOW && !IS_ERR(led191_hw_chx_low))
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
else if (state == LED191_PINCTRL_PINSTATE_HIGH && !IS_ERR(led191_hw_chx_high))
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_high);
else
PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
#endif
break;
case LED191_PINCTRL_PIN_HWEN1:
PK_DBG("LED191_PINCTRL_PIN_HWEN1\n");
if (flashlight_device_num == 2) {
#if defined(CONFIG_P32A_PROJECT) || defined(CONFIG_P33A_PROJECT) || defined(CONFIG_A95C_PROJECT) || defined(CONFIG_H33E_PROJECT)// flash control level is inverse
if (state == LED191_PINCTRL_PINSTATE_LOW && !IS_ERR(led191_hw_chx1_high))
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_high);
else if (state == LED191_PINCTRL_PINSTATE_HIGH && !IS_ERR(led191_hw_chx1_low))
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_low);
else
PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
#else
if (state == LED191_PINCTRL_PINSTATE_LOW && !IS_ERR(led191_hw_chx1_low))
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_low);
else if (state == LED191_PINCTRL_PINSTATE_HIGH && !IS_ERR(led191_hw_chx1_high))
ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_high);
else
PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
#endif
}
break;
// end +++
default:
PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
break;
}
PK_DBG("pin(%d) state(%d), ret:%d\n", pin, state, ret);
return ret;
}
2.1.13、led191_strobe_store的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
static ssize_t led191_strobe_store(struct flashlight_arg arg)
{
led191_set_driver(1);
led191_set_level(arg.level);
led191_timeout_ms = 0;
g_flash_channel_idx = arg.channel;// optimise the channel id
if (arg.level < 0) // optimise
led191_disable(arg.channel);
else
led191_enable(arg.channel);
msleep(arg.dur);
led191_disable(arg.channel);
led191_set_driver(0);
return 0;
}
2.1.14、led191_set_driver的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
static int led191_set_driver(int set)
{
int ret = 0;
/* set chip and usage count */
mutex_lock(&led191_mutex);
if (set) {
if (!use_count)
ret = led191_init();
use_count++;
PK_DBG("Set driver: %d\n", use_count);
} else {
use_count--;
if (!use_count)
ret = led191_uninit();
if (use_count < 0)
use_count = 0;
PK_DBG("Unset driver: %d\n", use_count);
}
mutex_unlock(&led191_mutex);
return ret;
}
2.1.15、led191_init的实现
./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c
/* flashlight init */
static int led191_init(void)
{
int pin = 0, state = 0;
PK_LOG("g_flash_channel_idx:%d\n", g_flash_channel_idx);
g_flash_duty = -1; // init flash duty
if (g_flash_channel_idx == -1) {
led191_pinctrl_set(LED191_PINCTRL_PIN_HWEN, LED191_PINCTRL_PINSTATE_LOW);
led191_pinctrl_set(LED191_PINCTRL_PIN_HWEN1, LED191_PINCTRL_PINSTATE_LOW);
return 0;
}
return led191_pinctrl_set(pin, state);
}