MT6577+Android之PWM背光调节

MT6577+Android之PWM背光调节

 

先来看MTK官方给出的Lights(光)架构图:

MT6577+Android之PWM背光调节_第1张图片

图1

这是MTK 2011年的图,下面给出MT6575/6577中此部分的框架图:

MT6577+Android之PWM背光调节_第2张图片

图2

再来看更体现一些细节的框架图:

MT6577+Android之PWM背光调节_第3张图片

图3

由此可见光系统从上到下依次分为java APP层、java 框架层、本地层和驱动层。下面就来看APP层,先给出调节背光的应用界面:

MT6577+Android之PWM背光调节_第4张图片

图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(读)来设置背光亮度,如下图:

MT6577+Android之PWM背光调节_第5张图片

图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

 

你可能感兴趣的:(MT6577+Android之PWM背光调节)