MT6577+Android之PWM背光调节
先来看MTK官方给出的Lights(光)架构图:
图1
这是MTK 2011年的图,下面给出MT6575/6577中此部分的框架图:
图2
再来看更体现一些细节的框架图:
图3
由此可见光系统从上到下依次分为java APP层、java 框架层、本地层和驱动层。下面就来看APP层,先给出调节背光的应用界面:
图4
此功能在settings--->display--->brightness下面,可知有自动调节和手动调节背光亮度的功能,其中手动是通过进度条(slider)来调节的,此应用对应的布局文件为\packages\apps\Settings\res\layout\preference_dialog_brightness.xml
1. Lights应用层
1.1 设置背光亮度调节范围
\packages\apps\Settings\src\com\android\settings\BrightnessPreference.java // Backlight range is from 0 - 255. Need tomake sure that user // doesn't set the backlight to 0 and getstuck private int mScreenBrightnessDim = getContext().getResources().getInteger(com.android.internal.R.integer.config_screenBrightnessDim); private staticfinal int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON; @Override protected void onBindDialogView(View view){ super.onBindDialogView(view); mSeekBar = getSeekBar(view); mSeekBar.setMax(MAXIMUM_BACKLIGHT -mScreenBrightnessDim); mOldBrightness = getBrightness(0); mSeekBar.setProgress(mOldBrightness -mScreenBrightnessDim); mCheckBox =(CheckBox)view.findViewById(R.id.automatic_mode); if (mAutomaticAvailable) { mCheckBox.setOnCheckedChangeListener(this); mOldAutomatic =getBrightnessMode(0); mCheckBox.setChecked(mOldAutomatic!= 0); } else { mCheckBox.setVisibility(View.GONE); } mSeekBar.setOnSeekBarChangeListener(this); }
(1) getContext().getResources().getInteger(com.android.internal.R.integer.config_screenBrightnessDim)的值
在\frameworks\base\core\res\res\values\config.xml下赋值,如下:
<!-- Minimumscreen brightness allowed by the power manager. --> <integername="config_screenBrightnessDim">20</integer>
可见背光亮度最小值是20,不能设置为0,否则会关闭背光的显示。
(2) android.os.Power.BRIGHTNESS_ON的值
在\frameworks\base\core\java\android\os\Power.java中定义:
/** * Brightness value for fully off */ public static final int BRIGHTNESS_OFF = 0; /** * Brightness value for dim backlight */ public static final int BRIGHTNESS_DIM =20; /** * Brightness value for fully on */ public static final int BRIGHTNESS_ON =255; /** * Brightness value to use when battery islow */ public staticfinal int BRIGHTNESS_LOW_BATTERY = 10;
由此可见设置的背光亮度调节范围为20~255。
1.2 设置背光亮度
public voidonProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { setBrightness(progress +mScreenBrightnessDim); } progress表示滑动条的值。 private void setBrightness(int brightness) { try { IPowerManager power =IPowerManager.Stub.asInterface( ServiceManager.getService("power")); //Only set backlight value whenscreen is on if (power != null &&power.isScreenOn()) { power.setBacklightBrightness(brightness); } } catch (RemoteException doe) { } }
通过ServiceManager获得power服务,然后通过power服务设置背光亮度
1.3 背光亮度初始值
frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java
private voidloadSystemSettings(SQLiteDatabase db) { SQLiteStatement stmt = null; try { ………. loadIntegerSetting(stmt,Settings.System.SCREEN_BRIGHTNESS, R.integer.def_screen_brightness); loadBooleanSetting(stmt,Settings.System.SCREEN_BRIGHTNESS_MODE, R.bool.def_screen_brightness_automatic_mode); …………….. } finally { if (stmt != null) stmt.close(); } }
def_screen_brightness的值在下面定义:
\frameworks\base\packages\SettingsProvider\res\values\ defaults.xml
<integername="def_screen_brightness">102</integer> <boolname="def_screen_brightness_automatic_mode">false</bool>
可知默认亮度值为102
2. Lights框架层(java框架层和antive框架层)
接着1.2节,设备背光亮度的power.setBacklightBrightness() 在文件
\frameworks\base\core\java\android\os\IPowerManager.aidl中定义,如下:
interfaceIPowerManager { …… // sets the brightness of thebacklights (screen, keyboard, button) 0-255 void setBacklightBrightness(intbrightness); void setBacklightBrightnessOff(booleanenable); void setMaxBrightness(int brightness); ………. }
IPowerManager.aidl,android系统提供了一种描述语言来定义具有跨进程访问能力的服务接口,这种描述语言称为Android接口描述语言(Android Interface Definition Language, AIDL)。以AIDL定义的服务接口文件以aidl为后缀名,在编译是,编译系统会将它们转换成java文件,这是需要在\frameworks\base\Android.mk
文件中添加对应的aidl文件,才会转换为java文件的,如:
LOCAL_SRC_FILES +=\ …………… core/java/android/os/IPermissionController.aidl\ core/java/android/os/IPowerManager.aidl\ core/java/android/os/IRemoteCallback.aidl\ …………….
然后再对它们进行编译。通常用于访问硬件的服务接口定义在\frameworks\base\core\java\android\os下。
IPowerManager只是提供服务的接口,具体的实在
frameworks\base\core\java\android\os\PowerManager.java中,如下:
/** * sets the brightness of the backlights(screen, keyboard, button). * * @param brightness value from 0 to 255 * * {@hide} */ public void setBacklightBrightness(intbrightness) { try { mService.setBacklightBrightness(brightness); } catch (RemoteException e) { } }
这里调用PowerManagerService的接口,
frameworks\base\services\java\com\android\server\PowerManagerService.java,如下: public void setBacklightBrightness(intbrightness) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,null); // Don't let applications turn thescreen all the way off synchronized (mLocks) { brightness = Math.max(brightness,mScreenBrightnessDim); if (mMaxBrightness > 0) { if (brightness >mMaxBrightness) { brightness =mMaxBrightness; } } mLcdLight.setBrightness(brightness); //We won't adjust Button/KeyboardBKL here for the time being, see CR[ALPS00132847] //mKeyboardLight.setBrightness(mKeyboardVisible? brightness : 0); //mButtonLight.setBrightness(brightness); long identity =Binder.clearCallingIdentity(); try { mBatteryStats.noteScreenBrightness(brightness); } catch (RemoteException e) { Slog.w(TAG,"RemoteException calling noteScreenBrightness onBatteryStatsService", e); } finally { Binder.restoreCallingIdentity(identity); } // update our animation state synchronized (mLocks) { mScreenBrightness.targetValue =brightness; mScreenBrightness.jumpToTargetLocked(); } } }
(1) mLcdLight赋值
………….. static final int LIGHT_ID_BACKLIGHT = 0; static final intLIGHT_ID_KEYBOARD = 1; static final intLIGHT_ID_BUTTONS = 2; static final intLIGHT_ID_BATTERY = 3; mLcdLight = lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);
(2) setBrightness()
此函数位于frameworks\base\services\java\com\android\server\LightsService.java下,调用setBrightness()--->setLightLocked()--->setLight_native()。
LightsService.java声明的本地方法,也就是JNI接口函数有:
private staticnative int init_native(); private static native voidfinalize_native(int ptr); private static native void setLight_native(intptr, int light, int color, int mode, int onMS, int offMS, intbrightnessMode);
这些本地方法在
frameworks\base\services\jni\com_android_server_LightsService.cpp下实现,先来看Andorid Java 和 C 函数的映射表数组:
staticJNINativeMethod method_table[] = { { "init_native", "()I",(void*)init_native }, { "finalize_native","(I)V", (void*)finalize_native }, { "setLight_native","(IIIIIII)V", (void*)setLight_native }, };
JNINativeMethod结构体在dalvik\libnativehelper\include\nativehelper\jni.h
typedef struct { const char* name; const char*signature; void* fnPtr; } JNINativeMethod;
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C/C++函数。
其中比较难以理解的是第二个参数,例如
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"
实际上这些字符是与函数的参数类型一一对应的。
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
详细可参考:http://blog.csdn.net/loongembedded/article/details/41355353
由此可见Java函数对应的CPP函数名字是一样的,在
frameworks\base\services\jni\com_android_server_LightsService.cpp中定义:
(1) init_native()
static jintinit_native(JNIEnv *env, jobject clazz) { int err; hw_module_t* module; Devices* devices; devices =(Devices*)malloc(sizeof(Devices)); err =hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { devices->lights[LIGHT_INDEX_BACKLIGHT] = get_device(module,LIGHT_ID_BACKLIGHT); devices->lights[LIGHT_INDEX_KEYBOARD] = get_device(module,LIGHT_ID_KEYBOARD); devices->lights[LIGHT_INDEX_BUTTONS] = get_device(module,LIGHT_ID_BUTTONS); devices->lights[LIGHT_INDEX_BATTERY] = get_device(module,LIGHT_ID_BATTERY); devices->lights[LIGHT_INDEX_NOTIFICATIONS] = get_device(module,LIGHT_ID_NOTIFICATIONS); devices->lights[LIGHT_INDEX_ATTENTION] = get_device(module,LIGHT_ID_ATTENTION); devices->lights[LIGHT_INDEX_BLUETOOTH] = get_device(module,LIGHT_ID_BLUETOOTH); devices->lights[LIGHT_INDEX_WIFI] = get_device(module,LIGHT_ID_WIFI); } else { memset(devices, 0, sizeof(Devices)); } return (jint)devices; }
这里重点介绍hw_get_module()函数,声明如下:
int hw_get_module(const char *id, const struct hw_module_t **module);
id是输入参数,表示要加载的硬件抽象层模块ID;module是输出参数,如加载成功,它指向一个自定义的硬件抽象层模块结构体。函数返回值为0表示加载成功。
#defineHAL_LIBRARY_PATH1 "/system/lib/hw" #defineHAL_LIBRARY_PATH2 "/vendor/lib/hw" #defineHAL_LIBRARY_PATH3 "/system/lib"
此函数回到这些路径下查找lights硬件抽象层模块lights.default.so并加载。
(2) finalize_native()
static voidfinalize_native(JNIEnv *env, jobject clazz, int ptr) { Devices* devices = (Devices*)ptr; if (devices == NULL) { return; } free(devices); }
(3) setLight_native()
static voidsetLight_native(JNIEnv *env, jobject clazz, int ptr, int light, int colorARGB, intflashMode, int onMS, int offMS, int brightnessMode) { Devices* devices = (Devices*)ptr; light_state_t state; if (light < 0 || light >= LIGHT_COUNT|| devices->lights[light] == NULL) { return ; } memset(&state, 0,sizeof(light_state_t)); state.color = colorARGB; state.flashMode = flashMode; state.flashOnMS = onMS; state.flashOffMS = offMS; state.brightnessMode = brightnessMode; devices->lights[light]->set_light(devices->lights[light],&state); }
devices->lights[light]->set_light(devices->lights[light],&state);这里就是调用HAL层的函数。
3. Lights硬件抽象层(HAL)
先来介绍这部分比较重要的结构体
3.1 light_state_t结构体
在hardware\libhardware\include\hardware\lights.h下定义:
/** * The parameters that can be set for a givenlight. * * Not all lights must support allparameters. If you * can do something backward-compatible, youshould. */ structlight_state_t { /** * The color of the LED in ARGB. * * Do your best here. * - If your light can only do red or green, if they ask for blue, * you should do green. * - If you can only do a brightness ramp, then use this formula: * unsigned char brightness = ((77*((color>>16)&0x00ff)) * +(150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; * - If you can only do on or off, 0 is off, anything else is on. * * The high byte should be ignored. Callers will set it to 0xff (which * would correspond to 255 alpha). */ unsigned int color; /** * See the LIGHT_FLASH_* constants */ int flashMode; int flashOnMS; int flashOffMS; /** * Policy used by the framework to managethe light's brightness. * Currently the values areBRIGHTNESS_MODE_USER and BRIGHTNESS_MODE_SENSOR. */ int brightnessMode; };
这里每个成员都有详细的解释,这里指强调几点:
(1) flashMode成员
/************************************************************************* * Flash modes for the flashMode field oflight_state_t. */ #defineLIGHT_FLASH_NONE 0 /** * To flash the light at a given rate, setflashMode to LIGHT_FLASH_TIMED, * and then flashOnMS should be set to thenumber of milliseconds to turn * the light on, followed by the number ofmilliseconds to turn the light * off. */ #defineLIGHT_FLASH_TIMED 1 /** * To flash the light using hardware assist,set flashMode to * the hardware mode. */ #defineLIGHT_FLASH_HARDWARE 2
表示LED等闪的模式,如果不需要闪烁为LIGHT_FLASH_NONE;如果需要软件来控制闪烁为LIGHT_FLASH_TIMED,这时也需要适当flashOnMS和flashOffMS的值;如果由硬件来控制闪烁的效果则为LIGHT_FLASH_HARDWARE。
(2) brightnessMode成员
/** * Light brightness is managed by a usersetting. */ #defineBRIGHTNESS_MODE_USER 0 /** * Light brightness is managed by a lightsensor. */ #defineBRIGHTNESS_MODE_SENSOR 1
BRIGHTNESS_MODE_USER表示由用户来设置背光,BRIGHTNESS_MODE_SENSOR表示有光传感器来自动调节背光,对应图4的Automatic brightness。
3.2 hw_module_t
在hardware\libhardware\include\hardware\hardware.h下定义:
/* * Value for the hw_module_t.tag field */ #defineMAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C)<< 8) | (D)) #defineHARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T') #defineHARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T') /** * Every hardware module must have a datastructure named HAL_MODULE_INFO_SYM * and the fields of this data structure mustbegin with hw_module_t * followed by module specific information. */ typedef structhw_module_t { /** tag must be initialized toHARDWARE_MODULE_TAG */ uint32_t tag; /** major version number for the module */ uint16_t version_major; /** minor version number of the module */ uint16_t version_minor; /** Identifier of module */ const char *id; /**Name of this module */ const char *name; /** Author/owner/implementor of the module*/ const char *author; /** Modules methods */ struct hw_module_methods_t* methods; /** module's dso */ void* dso; /** padding to 128 bytes, reserved forfuture use */ uint32_t reserved[32-7]; } hw_module_t;
需要重点注意几点:
(1) 每个硬件抽象层都必须有个名为HAL_MODULE_INFO_SYM的结构体,而且它的第1个成员变量类型必须是hw_module_t。
(2) 结构体hw_module_t的成员变量dso用来保存加载硬件抽象层模块后得到的句柄值。前面提到,每一个硬件抽象层模块都对应有一个动态链接库文件。加载硬件抽象层模块的过程实际上就是调用dlopen函数来加载与其对应的动态链接库文件的过程。在调用dlclose函数来卸载这个硬件抽象层模块时,要用到这个句柄值,因此,我们在加载时需要将它保存起来。
(3) methods
typedef structhw_module_methods_t { /** Open a specific device */ int (*open)(const struct hw_module_t*module, const char* id, struct hw_device_t** device); }hw_module_methods_t;
Open函数指针用来打开硬件抽象层模块的设备,参数module表示要打开的设备所在的模块;参数id表示要打开的设备的ID;参数device是一个输出参数,用来描述已经打开的设备。因为一个硬件抽象层模块可能包含多个设备,因为此在调用open的时候需要执行它的ID。
hw_device_t结构体的定义如下:
/** * Every device data structure must begin withhw_device_t * followed by module specific public methodsand attributes. */ typedef structhw_device_t { /** tag must be initialized toHARDWARE_DEVICE_TAG */ uint32_t tag; /** version number for hw_device_t */ uint32_t version; /** reference to the module this devicebelongs to */ struct hw_module_t* module; /** padding reserved for future use */ uint32_t reserved[12]; /** Close this device */ int (*close)(struct hw_device_t* device); } hw_device_t;
需要注意几点:
1) 硬件抽象层模块中的每个设备都必须自定义一个设备结构体,而人气它的第1个成员变量类型必须是hw_device_t。
2) close用来关闭一个设备。
根据上面结构体的定义可知,硬件抽象层中的设备是由其所在的模块提供的接口open来打开的,而关闭是由设备本身结构体提供的close接口来完成的。
3.3 light_device_t
在hardware\libhardware\include\hardware\lights.h下定义:
structlight_device_t { struct hw_device_t common; /** * Set the provided lights to the providedvalues. * * Returns: 0 on succes, error code onfailure. */ int (*set_light)(struct light_device_t*dev, struct light_state_t const* state); };
下面给出mediatek\source\hardware\liblights\lights.c中相关的部分:
/** * module methods */ /** Open a newinstance of a lights device using name */ static intopen_lights(const struct hw_module_t* module, char const* name, struct hw_device_t** device) { int (*set_light)(struct light_device_t*dev, struct light_state_t const* state); if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)){ set_light =set_light_backlight; } elseif (0 == strcmp(LIGHT_ID_KEYBOARD, name)) { set_light = set_light_keyboard; } else if (0 == strcmp(LIGHT_ID_BUTTONS,name)) { set_light = set_light_buttons; } else if (0 == strcmp(LIGHT_ID_BATTERY,name)) { set_light = set_light_battery; } else if (0 ==strcmp(LIGHT_ID_NOTIFICATIONS, name)) { set_light = set_light_notifications; } else if (0 == strcmp(LIGHT_ID_ATTENTION,name)) { set_light = set_light_attention; } else { return -EINVAL; } pthread_once(&g_init, init_globals); struct light_device_t *dev =malloc(sizeof(struct light_device_t)); memset(dev, 0, sizeof(*dev)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (structhw_module_t*)module; dev->common.close = (int (*)(structhw_device_t*))close_lights; dev->set_light = set_light; *device = (struct hw_device_t*)dev; return 0; } static structhw_module_methods_t lights_module_methods = { .open = open_lights, }; /* * The lights Module */ const structhw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = LIGHTS_HARDWARE_MODULE_ID, .name = "MTK lights Module", .author = "MediaTek", .methods = &lights_module_methods, };
结合第2节的setLight_native()--->set_light (),对应调用的是set_light_backlight来设置背光。
3.4 set_light_backlight()
/* LCD BACKLIGHT*/ char const*constLCD_FILE = "/sys/class/leds/lcd-backlight/brightness"; static int set_light_backlight(structlight_device_t* dev, struct light_state_t const* state) { int err = 0; int brightness = rgb_to_brightness(state);// 将rgb亮度转化为亮度 pthread_mutex_lock(&g_lock); g_backlight = brightness; //将数值写入sys文件系统的brightness文件 err = write_int(LCD_FILE, brightness); if (g_haveTrackballLight) { handle_trackball_light_locked(dev); } pthread_mutex_unlock(&g_lock); return err; }
此函数主要是把新的背光亮度值brightness写入到/sys/class/leds/lcd-backlight/brightness文件中,比如103,然后LED驱动再读取此值,然后调节背光。
static int write_int(charconst* path, int value) { int fd; #ifdefLIGHTS_INFO_ON LOGD("write %d to %s",value, path); #endif fd = open(path, O_RDWR); if (fd >= 0) { char buffer[20]; int bytes = sprintf(buffer,"%d\n", value); int amt = write(fd, buffer, bytes); close(fd); return amt == -1 ? -errno : 0; } else { return -errno; } }
我们也可以通过echo(写)和cat(读)来设置背光亮度,如下图:
图5
4. Lights驱动层
mediatek\config\hsimobile77_ics2\ProjectConfig.mkCUSTOM_KERNEL_LEDS=mt65xx
对于MTK平台,
根据上面的介绍,背光驱动提供的用于调节亮度接口是:/sys/class/leds/lcd-backlight/brightness。这个接口有LED驱动注册得来的的,源码位于Kernel/driver/leds/led-class.c中,下面给出其中一部分:
表示leds class的属性文件、权限和支持的操作
static struct device_attributeled_class_attrs[] = { __ATTR(brightness,0644, led_brightness_show, led_brightness_store), __ATTR(max_brightness, 0444,led_max_brightness_show, NULL), #ifdefCONFIG_LEDS_TRIGGERS __ATTR(trigger, 0644,led_trigger_show, led_trigger_store), #endif __ATTR_NULL, }; static int __initleds_init(void) { leds_class =class_create(THIS_MODULE, "leds"); if (IS_ERR(leds_class)) returnPTR_ERR(leds_class); leds_class->suspend =led_suspend; leds_class->resume =led_resume; leds_class->dev_attrs =led_class_attrs; return 0; } static void __exitleds_exit(void) { class_destroy(leds_class); } subsys_initcall(leds_init); module_exit(leds_exit);
这里主要是通过subsys_initcall来进行各种子系统的初始化。
Led-class.c文件只是实现了提供上层的接口,至于真正操作硬件的驱动程序,可以给出其源码路径为:(硬件操作其实就是脉宽调制(PWM)),mediatek\source\kernel\drivers\leds\leds.c
3.4节的set_light_backlight()通过write()把背光值写入到/sys/class/leds/lcd-backlight/brightness文件后,会触发调用led_brightness_store函数,经过led_brightness_store()--->led_set_brightness()--->led_cdev->brightness_set(led_cdev,value)的调用流程,最后调用到mt65xx_led_set(),这是通过mt65xx_leds_probe()的赋值语句知道的:
g_leds_data[i]->cdev.brightness_set= mt65xx_led_set;
这样我们就来看mt65xx_led_set()函数
static voidmt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level) { struct mt65xx_led_data *led_data = container_of(led_cdev,struct mt65xx_led_data, cdev); // do something only when level ischanged if (led_data->level != level) { led_data->level= level; if(strcmp(led_data->cust.name,"lcd-backlight")) { schedule_work(&led_data->work); }else { LEDS_DEBUG("[LED]SetBacklight directly %d at time %lu\n",led_data->level,jiffies); mt65xx_led_set_cust(&led_data->cust,led_data->level); } } }
调用mt65xx_led_set_cust()来实现,此函数的参数led_data->cust
struct PWM_config { int clock_source; int div; int low_duration; int High_duration; }; structcust_mt65xx_led { char *name; enum mt65xx_led_mode mode; int data; struct PWM_config config_data; }; static structcust_mt65xx_led cust_led_list[MT65XX_LED_TYPE_TOTAL] = { {"red", MT65XX_LED_MODE_NONE, -1,{0}}, {"green", MT65XX_LED_MODE_NONE, -1,{0}}, {"blue", MT65XX_LED_MODE_NONE, -1,{0}}, {"jogball-backlight", MT65XX_LED_MODE_NONE,-1,{0}}, {"keyboard-backlight",MT65XX_LED_MODE_NONE,-1,{0}}, {"button-backlight", MT65XX_LED_MODE_PMIC,MT65XX_LED_PMIC_BUTTON,{0}}, // {"lcd-backlight", MT65XX_LED_MODE_CUST,(int)Cust_SetBacklight,{0}}, {"lcd-backlight", MT65XX_LED_MODE_PWM,PWM1,{0}}, }; structcust_mt65xx_led *get_cust_led_list(void) { return cust_led_list; }
参数led_data->level就是当前要设置的背光值。
mt65xx_led_set_cust()--->backlight_set_pwm()--->pwm_set_spec_config()
在调试过程遇到的问题:
(1) cust_mt65xx_ledcust_led_list全局结构体数组的修改
修改之前:{"lcd-backlight", MT65XX_LED_MODE_GPIO,GPIO84,{0}},
因为我们是采用CPU的PWM1来控制背光的的,所以修改为:
{"lcd-backlight", MT65XX_LED_MODE_PWM,PWM1,{0}},
可是进入系统后直接就是黑屏,为什么呢?根据调试信息知道/sys/class/leds/lcd-backlight/brightness文件的值为255,255是最大值,应该是最亮才对啊,但为什么是255就会黑屏呢?
看backlight_set_pwm()函数体下面的部分:
if(level>0&& level <= 32) { pwm_setting.PWM_MODE_FIFO_REGS.SEND_DATA0= (1 << level) - 1 ; pwm_setting.PWM_MODE_FIFO_REGS.SEND_DATA1= 0 ; pwm_set_spec_config(&pwm_setting); }else if(level>32 &&level <=64) { level -= 32; pwm_setting.PWM_MODE_FIFO_REGS.SEND_DATA0= 0xFFFFFFFF ; pwm_setting.PWM_MODE_FIFO_REGS.SEND_DATA1= (1 << level) - 1; pwm_set_spec_config(&pwm_setting); }else { LEDS_DEBUG("[LED]Errorlevel in backlight\n"); mt_set_pwm_disable(pwm_setting.pwm_no); mt_power_off(pwm_setting.pwm_no); }
因为level=255,所以就直接执行了关屏的动作,如果要搞清楚为什么level>64就要关屏,就要详细看MT6577的PWM部分了。
(2) 修改brightness_mapping()
上面出现在leve=255关屏的情况,为解决此问题就需要修改brightness_mapping()函数,看了为了确保上层设置0~255的情况下,是需要brightness_mapping函数的映射的,下面给出其实现部分:
unsigned intbrightness_mapping(unsigned int level) { unsigned int mapped_level; mapped_level = level; return mapped_level; }
很简单吧,为了解决此问题,我们改为:
mapped_level =level/4;
5. Lights硬件层
参考我之前介绍的部分:
http://blog.csdn.net/loongembedded/article/details/38540297
6. 编译
./mk n ub、 ./mk n k和./mk bootimage,然后更新uboot_hsimobile77_ics2.bin和boot.img即可
参考:
mtk led
http://blog.csdn.net/mcgrady_tracy/article/details/41285213
android系统开发(七)-背光模块
http://blog.csdn.net/jiajie961/article/details/6030405
【从应用层到Framework】android LCD、键盘灯的背光亮度设置
http://blog.sina.com.cn/s/blog_40d475e901014wkt.html
Android中背光系统架构
http://blog.csdn.net/yinwei520/article/details/6817528
Android LCD和键盘背光亮度数据流分析
http://blog.csdn.net/wealoong/article/details/7759178
lights从上到下的流程
http://blog.csdn.net/zhangchiytu/article/details/7958513