08.mtk背光等级和背光流程_KERNEL

基于led框架的驱动分析

Led驱动架构理解

史上最详细Linux 虚拟文件系统sysfs之属性文件attribute 整理(一)

史上最详细Linux 虚拟文件系统sysfs之属性文件attribute 整理(二)

一、介绍一下lk和kernel的默认亮度修改位置:

 /vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt8168/include/platform/mt_leds.h

1
2
3
4
5

enum led_brightness {
    LED_OFF     = 0,
    LED_HALF    = 127,
    LED_FULL    = 255,
};

 /vendor/mediatek/proprietary/bootable/bootloader/lk/target/tb8168p1_64_bsp/inc/cust_leds.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#include <platform/mt_typedefs.h>
enum mt65xx_led_type
{
    MT65XX_LED_TYPE_RED = 0,
    MT65XX_LED_TYPE_GREEN,
    MT65XX_LED_TYPE_BLUE,
    MT65XX_LED_TYPE_JOGBALL,
    MT65XX_LED_TYPE_KEYBOARD,
    MT65XX_LED_TYPE_BUTTON,
    MT65XX_LED_TYPE_LCD,
    MT65XX_LED_TYPE_TOTAL,
};

struct cust_mt65xx_led {
    char                 *name;
    enum mt65xx_led_mode  mode;
    int                   data;
    struct PWM_config config_data;
};

 /vendor/mediatek/proprietary/bootable/bootloader/lk/target/tb8168p1_64_bsp/cust_leds.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

extern int disp_bls_set_backlight(unsigned int level);
enum led_brightness backlight_default_level = LED_FULL;  //LK 默认亮度


// Only support 64 levels of backlight (when lcd-backlight = MT65XX_LED_MODE_PWM)
#define BACKLIGHT_LEVEL_PWM_64_FIFO_MODE_SUPPORT 64
// Support 256 levels of backlight (when lcd-backlight = MT65XX_LED_MODE_PWM)
#define BACKLIGHT_LEVEL_PWM_256_SUPPORT 256

// Custom can decide the support type "BACKLIGHT_LEVEL_PWM_256_SUPPORT" or "BACKLIGHT_LEVEL_PWM_64_FIFO_MODE_SUPPORT"
#define BACKLIGHT_LEVEL_PWM_MODE_CONFIG BACKLIGHT_LEVEL_PWM_256_SUPPORT

unsigned int Cust_GetBacklightLevelSupport_byPWM(void)
{
    return BACKLIGHT_LEVEL_PWM_MODE_CONFIG;
}

static struct cust_mt65xx_led cust_led_list[MT65XX_LED_TYPE_TOTAL] = {
    {"red",               MT65XX_LED_MODE_NONE, -1,{0,0,0,0,0}},
    {"green",             MT65XX_LED_MODE_NONE, -1,{0,0,0,0,0}},
    {"blue",              MT65XX_LED_MODE_NONE, -1,{0,0,0,0,0}},
    {"jogball-backlight", MT65XX_LED_MODE_NONE, -1,{0,0,0,0,0}},
    {"keyboard-backlight",MT65XX_LED_MODE_NONE, -1,{0,0,0,0,0}},
    {"button-backlight",  MT65XX_LED_MODE_NONE, -1,{0,0,0,0,0}},
    {"lcd-backlight",     MT65XX_LED_MODE_CUST_BLS_PWM, (int)disp_bls_set_backlight,{0}},
};

enum led_brightness get_cust_led_default_level(void)
{
    return backlight_default_level;
}

struct cust_mt65xx_led *get_cust_led_list(void)
{
    return cust_led_list;
}

 \kernel-4.14\drivers\misc\mediatek\video\common\pwm10\ddp_pwm.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

static int disp_pwm_config_init(enum DISP_MODULE_ENUM module,
    struct disp_ddp_path_config *pConfig, void *cmdq)
{
#ifndef CONFIG_FPGA_EARLY_PORTING
    ... ...
    /* We don't enable PWM until we really need */
    DISP_REG_MASK(cmdq, reg_base + DISP_PWM_CON_0_OFF, pwm_div << 16, (0x3ff << 16));

    /* 1024 levels */
    DISP_REG_MASK(cmdq, reg_base + DISP_PWM_CON_1_OFF, 1023, 0x3ff);  //KERNEL 默认亮度
    /* We don't init the backlight here until AAL/Android give */
#endif
    return 0;
}

 /kernel-4.9-lc/arch/arm/boot/dts/mt6580.dts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

/ {
    model = "MT6580";
    compatible = "mediatek,MT6580";
    interrupt-parent = <&gic>;
    #address-cells = <2>;
    #size-cells = <2>;
    
    bus: bus {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <1>;
        ranges = <0 0 0 0xffffffff>;
        
        DISPSYS@0x14007000 {
            compatible = "mediatek,DISPSYS";
            reg = <0x14000000 0x1000>,/*DISP_SYS */
            <0x14007000 0x1000>,    /*DISP_OVL0*/
            <0x14008000 0x1000>,    /*DISP_OVL1*/
            <0x14009000 0x1000>,    /*DISP_RDMA0*/
            <0x1400A000 0x1000>,    /*DISP_RDMA1*/
            <0x1400B000 0x1000>,    /*DISP_WDMA0*/
            <0x1400C000 0x1000>,    /*DISP_COLOR*/
            <0x1400D000 0x1000>,    /*DISP_CCORR*/
            <0x1400E000 0x1000>,    /*DISP_AAL*/
            <0x1400F000 0x1000>,    /*DISP_GAMMA*/
            <0x14010000 0x1000>,    /*DISP_DITHER*/
            <0x14011000 0x1000>,    /*DISP_UFOE*/
            <0x14012000 0x1000>,    /*DISP_DSI0*/
            <0x14013000 0x1000>,    /*DISP_DPI0*/
            <0x1100F000 0x1000>,    /*DISP_PWM*/
            <0x14015000 0x1000>,    /*DISP_MUTEX*/
            <0x14016000 0x1000>,    /*DISP_SMI_LARB0 */
            <0x14017000 0x1000>,    /*DISP_SMI_COMMOM*/
            <0x14018000 0x1000>;    /*MIPITX0,real chip would use this*/

            interrupts = <0 0 8>, /*DISP_SYS */
            <0 119 8>, /*DISP_OVL0 */
            <0 0 8>, /*DISP_OVL1 */
            <0 121 8>, /*DISP_RDMA0 */
            <0 0 8>, /*DISP_RDMA1 */
            <0 123 8>, /*DISP_WDMA0 */
            <0 124 8>, /*DISP_COLOR */
            <0 0 8>, /*DISP_CCORR */
            <0 126 8>, /*DISP_AAL */
            <0 127 8>, /*DISP_GAMMA */
            <0 128 8>, /*DISP_DITHER */
            <0 0 8>, /*DISP_UFOE */
            <0 130 8>, /*DISP_DSI0 */
            <0 0 8>, /*DISP_DPI0 */
            <0 0 8>, /*DISP_PWM */
            <0 112 8>, /*DISP_MUTEX */
            <0 0 8>, /*DISP_SMI_LARB0 */
            <0 0 8>, /*DISP_SMI_COMMOM*/
            <0 0 8>; /*MIPITX0*/
        };
    };
};

 /kernel-4.9-lc/drivers/misc/mediatek/video/mt6580/dispsys/ddp_hal.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

enum DISP_REG_ENUM{
    DISP_REG_CONFIG,
    DISP_REG_OVL0,
    DISP_REG_OVL1,
    DISP_REG_RDMA0,
    DISP_REG_RDMA1,
    DISP_REG_WDMA0,
    DISP_REG_COLOR,
    DISP_REG_CCORR,
    DISP_REG_AAL,
    DISP_REG_GAMMA,
    DISP_REG_DITHER,
    DISP_REG_UFOE,
    DISP_REG_DSI0,
    DISP_REG_DPI0,
    DISP_REG_PWM,
    DISP_REG_MUTEX,
    DISP_REG_SMI_LARB0,
    DISP_REG_SMI_COMMON,
    DISP_REG_MIPI,
    DISP_REG_NUM
};

 /kernel-4.9-lc/drivers/misc/mediatek/video/mt6580/dispsys/ddp_drv.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

volatile unsigned long dispsys_reg[DISP_REG_NUM] = { 0 };
static int disp_probe(struct platform_device *pdev)
{
    ... ...
    /* iomap registers and irq */
    for (i = 0; i < DISP_REG_NUM; i++) {
        dispsys_dev->regs[i] = of_iomap(pdev->dev.of_node, i);
        if (!dispsys_dev->regs[i]) {
            DISPERR("Unable to ioremap registers, of_iomap fail, i=%d\n", i);
            return -ENOMEM;
        }
        dispsys_reg[i] = (unsigned long)dispsys_dev->regs[i];
        ... ...
    }
    ... ...
}

static const struct of_device_id dispsys_of_ids[] = {
    {.compatible = "mediatek,DISPSYS",},
    {}
};

static struct platform_driver dispsys_of_driver = {
    .driver = {
           .name = DISP_DEVNAME,
           .owner = THIS_MODULE,
           .of_match_table = dispsys_of_ids,
           },
    .probe = disp_probe,
    .remove = disp_remove,
    .shutdown = disp_shutdown,
    .suspend = disp_suspend,
    .resume = disp_resume,
};

 /kernel-4.9-lc/drivers/misc/mediatek/video/mt6580/dispsys/ddp_reg.h

1
2
3
4

#define DDP_REG_BASE_DISP_PWM0     dispsys_reg[DISP_REG_PWM]
#define DDP_REG_BASE_DISP_PWM1     0

#define DISPSYS_PWM0_BASE          DDP_REG_BASE_DISP_PWM0

 /kernel-4.9-lc/drivers/misc/mediatek/video/include/ddp_pwm.h

1
2
3
4
5

enum disp_pwm_id_t {
    DISP_PWM0 = 0x1,
    DISP_PWM1 = 0x2,
    DISP_PWM_ALL = (DISP_PWM0 | DISP_PWM1)
};

 /kernel-4.9-lc/drivers/misc/mediatek/video/common/aal20/ddp_pwm.c

1
2
3
4
5
6

#define pwm_get_reg_base(id) (DISPSYS_PWM0_BASE)  //不管传入的id是多少,只返回一个固定的地址DISPSYS_PWM0_BASE
static enum disp_pwm_id_t g_pwm_main_id = DISP_PWM0;
enum disp_pwm_id_t disp_pwm_get_main(void)
{
    return g_pwm_main_id;
}

 /kernel-4.9-lc/arch/arm/boot/dts/tb8321p2_bsp_2g.dts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

&odm {
    led@0 {
        compatible = "mediatek,red";
        led_mode = <0>;
        data = <1>;
        pwm_config = <0 0 0 0 0>;
    };
    led@1 {
        compatible = "mediatek,green";
        led_mode = <0>;
        data = <1>;
        pwm_config = <0 0 0 0 0>;
    };
    led@2 {
        compatible = "mediatek,blue";
        led_mode = <0>;
        data = <1>;
        pwm_config = <0 0 0 0 0>;
    };
    led@3 {
        compatible = "mediatek,jogball-backlight";
        led_mode = <0>;
        data = <1>;
        pwm_config = <0 0 0 0 0>;
    };
    led@4 {
        compatible = "mediatek,keyboard-backlight";
        led_mode = <0>;
        data = <1>;
        pwm_config = <0 0 0 0 0>;
    };
    led@5 {
        compatible = "mediatek,button-backlight";
        led_mode = <0>;
        data = <1>;
        pwm_config = <0 0 0 0 0>;
    };
    led@6 {
        compatible = "mediatek,lcd-backlight";
        led_mode = <5>;  //对应着 MT65XX_LED_MODE_CUST_BLS_PWM
        data = <1>;
        pwm_config = <0 0 0 0 0>;
    };
    vibrator0:vibrator@0 {
        compatible = "mediatek,vibrator";
        vib_timer = <25>;
        vib_limit = <9>;
        vib_vol= <6>;
    };
};

 /kernel-4.9-lc/drivers/misc/mediatek/leds/mt6580/mtk_leds_sw.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

/******************************************************************************
 *  LED & Backlight type defination
 *****************************************************************************/

enum mt65xx_led_type {  //根据不同type,获得不同name,根据name遍历dts节点led@0、led@1、led@2 ...
    MT65XX_LED_TYPE_RED = 0,
    MT65XX_LED_TYPE_GREEN,
    MT65XX_LED_TYPE_BLUE,
    MT65XX_LED_TYPE_JOGBALL,
    MT65XX_LED_TYPE_KEYBOARD,
    MT65XX_LED_TYPE_BUTTON,
    MT65XX_LED_TYPE_LCD,
    MT65XX_LED_TYPE_TOTAL,
};

enum mt65xx_led_mode {  //根据不同mode绑定不同背光指针函数
    MT65XX_LED_MODE_NONE,
    MT65XX_LED_MODE_PWM,
    MT65XX_LED_MODE_GPIO,
    MT65XX_LED_MODE_PMIC,
    MT65XX_LED_MODE_CUST_LCM,
    MT65XX_LED_MODE_CUST_BLS_PWM
};

/**
 * led customization data structure
 * name : must the same as lights HAL
 * mode : control mode
 * data :
 *    PWM:  pwm number
 *    GPIO: gpio id
 *    PMIC: enum mt65xx_led_pmic
 *    CUST: custom set brightness function pointer
 * config_data: pwm config data
 */
struct cust_mt65xx_led {  //用来保存dts的数据
    char *name;
    enum mt65xx_led_mode mode;
    long data;
    struct PWM_config config_data;
};

/**
 * led device node structure with mtk extentions
 * cdev: common led device structure
 * cust: customization data from device tree
 * work: workqueue for specialfied led device
 * level: brightness level
 * delay_on: on time if led is blinking
 * delay_off: off time if led is blinking
 */
struct mt65xx_led_data {
    struct led_classdev cdev;
    struct cust_mt65xx_led cust;
    struct work_struct work;
    int level;
    int delay_on;
    int delay_off;
};

 /kernel-4.9-lc/drivers/misc/mediatek/leds/mtk_leds_drv.c

1

struct mt65xx_led_data *g_leds_data[MT65XX_LED_TYPE_TOTAL];

 /kernel-4.14/drivers/misc/mediatek/leds/mt8168/mtk_leds_sw.h

1
2
3
4
5

/* 10bit backlight level */
#define LED_INCREASE_LED_LEVEL_MTKPATCH
#ifdef LED_INCREASE_LED_LEVEL_MTKPATCH
#define MT_LED_INTERNAL_LEVEL_BIT_CNT 10
#endif

 /kernel-4.14/drivers/misc/mediatek/leds/mt8168/mtk_leds.c

1
2
3
4
5
6
7
8
9

char *leds_name[TYPE_TOTAL] = {  //leds_name数组必须和mt65xx_led_type排列一 一对应
    "red",
    "green",
    "blue",
    "jogball-backlight",
    "keyboard-backlight",
    "button-backlight",
    "lcd-backlight",
};

C 库函数 char *strncat(char *dest, const char *src, size_t n) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。

以下for循环遍历MT65XX_LED_TYPE_TOTAL/leds_name 共7种类型,下面只以背光"lcd-backlight"为例分析:

struct cust_mt65xx_led *pled_dtsi = NULL;  //mtk_leds.c 全局变量

mt65xx_leds_probe        //kernel-4.9-lc/drivers/misc/mediatek/leds/mtk_leds_drv.c

 ->mt_get_cust_led_list    //kernel-4.9-lc/drivers/misc/mediatek/leds/mt6580/mtk_leds.c

  ->struct cust_mt65xx_led *cust_led_list = get_cust_led_dtsi();   //从dts获取各种类型led的数据,并且设置背光函数指针,全部保存在pled_dtsi

   ->pled_dtsi = kmalloc(TYPE_TOTAL * sizeof(struct cust_mt65xx_led),

   ->for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {

 ->char node_name[32] = "mediatek,";

    ->pled_dtsi[i].name = leds_name[i];  //"lcd-backlight"

    ->if (strlen(node_name) + strlen(leds_name[i]) + 1 > sizeof(node_name)) //先判断组合后的名字长度是否超过node_name的buf大小

     ->LEDS_DEBUG("buffer for %s%s not enough\n", node_name, leds_name[i]);

    ->led_node = of_find_compatible_node(NULL, NULL, strncat(node_name, leds_name[i], sizeof(node_name) - strlen(node_name) - 1)); //strncat追加字符串,组合后节点名为"mediatek,lcd-backlight",刚好和dts匹配

    ->of_property_read_u32(led_node, "led_mode", &mode);  //根据dts,读出来的是5,对应MT65XX_LED_MODE_CUST_BLS_PWM

    ->pled_dtsi[i].mode = mode;

    ->of_property_read_u32(led_node, "data",  &data);

    ->pled_dtsi[i].data = data;

    ->of_property_read_u32_array(led_node, "pwm_config", pwm_config, ARRAY_SIZE(pwm_config));

    ->pled_dtsi[i].config_data.clock_source = pwm_config[0];

    ->pled_dtsi[i].config_data.div = pwm_config[1];

    ->pled_dtsi[i].config_data.low_duration = pwm_config[2];

    ->pled_dtsi[i].config_data.High_duration = pwm_config[3];

    ->pled_dtsi[i].config_data.pmic_pad = pwm_config[4];  

    ->switch (pled_dtsi[i].mode) {

     ->MT65XX_LED_MODE_CUST_LCM

      ->pled_dtsi[i].data = (long)mtkfb_set_backlight_level

     ->MT65XX_LED_MODE_CUST_BLS_PWM

      ->pled_dtsi[i].data = (long)disp_bls_set_backlight

   ->return pled_dtsi;

  ->return cust_led_list;

 ->for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {  //struct cust_mt65xx_led cust;

  ->g_leds_data[i]->cust.mode = cust_led_list[i].mode;

  ->g_leds_data[i]->cust.data = cust_led_list[i].data;

  ->g_leds_data[i]->cust.name = cust_led_list[i].name;  //"lcd-backlight"

  ->g_leds_data[i]->cdev.name = cust_led_list[i].name;  //"lcd-backlight"

  ->g_leds_data[i]->cust.config_data = cust_led_list[i].config_data;        /* bei add */

  ->g_leds_data[i]->cdev.brightness_set = mt65xx_led_set;

  ->g_leds_data[i]->cdev.blink_set = mt65xx_blink_set;

  ->INIT_WORK(&g_leds_data[i]->work, mt_mt65xx_led_work);

  ->led_classdev_register(&pdev->dev, &g_leds_data[i]->cdev);

#define led_classdev_register(parent, led_cdev)                                \    //kernel4.14/include/linux/leds.h

        of_led_classdev_register(parent, NULL, led_cdev)

 /kernel-4.14/include/uapi/linux/uleds.h

1

#define LED_MAX_NAME_SIZE   64

 

of_led_classdev_register(struct device *parent, struct device_node *np, struct led_classdev *led_cdev)

 ->char name[LED_MAX_NAME_SIZE];

 ->led_classdev_next_name(led_cdev->name, name, sizeof(name));  //"lcd-backlight",如果没有重名,那么这里的name也是"lcd-backlight"

  ->class_find_device(leds_class, NULL, name, match_name)  //while查找是否有重名设备

 ->led_cdev->dev = device_create_with_groups(leds_class, parent, 0, led_cdev, led_cdev->groups, "%s", name);  //device_create_with_groups->device_create_groups_vargs

以下为开机log,可以看到led_cdev->groups是空的,所以注册的attr是使用的class->dev_groups,也就是leds_class->dev_groups = led_groups;:

static int match_name(struct device *dev, const void *data){

 if (!dev_name(dev))

  return 0;

 return !strcmp(dev_name(dev), (char *)data); 

}

static int led_classdev_next_name(const char *init_name, char *name,

                                  size_t len)

{

        unsigned int i = 0;

        int ret = 0;

        struct device *dev;

        strlcpy(name, init_name, len);

        while ((ret < len) &&

               (dev = class_find_device(leds_class, NULL, name, match_name))) {  //这里应该是判断是否有重名设备,如果有,那就添加下标

                put_device(dev);                        

                ret = snprintf(name, len, "%s_%u", init_name, ++i);      //比如lcd-backlight就变成lcd-backlight_1、lcd-backlight_2、lcd-backlight_3等等

                printk("Isaac [led_classdev_next_name] name=%s, i=%u\n", name, i);

        }

        printk("Isaac [led_classdev_next_name] init_name=%s, name=%s\n", init_name, name);

        if (ret >= len)

                return -ENOMEM;

        return i;

}

(210624_14:05:22.449)[    0.320966] <2>.(2)[1:swapper/0]Isaac [leds_init] enter

(210624_14:05:23.070)[    0.906847] <1>.(1)[1:swapper/0]Isaac [led_classdev_next_name] init_name=vibrator, name=vibrator

(210624_14:05:23.070)[    0.907944] <1>.(1)[1:swapper/0]Isaac [of_led_classdev_register] led_cdev->groups=0x98f2408

(210624_14:05:23.070)[    0.908986] <1>.(1)[1:swapper/0]Isaac [of_led_classdev_register] led_cdev->name=vibrator, name=vibrator

(210624_14:05:23.071)[    0.925813] <1>.(1)[1:swapper/0]Isaac [led_update_brightness] enter

(210624_14:05:24.414)[    2.237634] <1>.(1)[1:swapper/0]Isaac [mt65xx_leds_probe] enter

(210624_14:05:24.414)[    2.238375] <1>.(1)[1:swapper/0]Isaac [mt65xx_leds_probe] (&g_leds_data[i]->cdev)->groups=0x0

(210624_14:05:24.414)[    2.239467] <1>.(1)[1:swapper/0]Isaac [led_classdev_next_name] init_name=lcd-backlight, name=lcd-backlight

(210624_14:05:24.414)[    2.240671] <1>.(1)[1:swapper/0]Isaac [of_led_classdev_register] led_cdev->groups=0x0

(210624_14:05:24.414)[    2.241647] <1>.(1)[1:swapper/0]Isaac [of_led_classdev_register] led_cdev->name=lcd-backlight, name=lcd-backlight

(210624_14:05:24.414)[    2.257893] <1>.(1)[1:swapper/0]Isaac [led_update_brightness] enter

(210624_14:05:38.866)[   16.649092] <0>.(0)[449:android.hardwar]Isaac [brightness_store] buf=103

vib_probe

 ->devm_led_classdev_register

  ->devm_of_led_classdev_register

   ->of_led_classdev_register

mt65xx_leds_probe

 ->led_classdev_register

  ->of_led_classdev_register  

device_create_with_groups、device_create这两个函数最终都是调用了device_create_groups_vargs

创建设备节点,并创建of_led_classdev_register:

struct device *device_create_with_groups(struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, ...)

 ->device_create_groups_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, va_list args)

  ->dev = kzalloc(sizeof(*dev), GFP_KERNEL);

  ->device_initialize(dev);

  ->dev->class = class;

  ->dev->parent = parent;

  ->dev->groups = groups;

  ->dev_set_drvdata(dev, drvdata);  //dev->driver_data = data;  //到时可以通过dev_get_drvdata(dev);获得该私有指针

  -> kobject_set_name_vargs(&dev->kobj, fmt, args);  //设置kobj名字,/sys/class/leds/lcd-backlight

  ->device_add(dev)

   ->device_create_file(dev, &dev_attr_uevent);

   ->device_add_class_symlinks(dev);

   ->device_add_attrs(dev);

    ->if (class) {

     ->device_add_groups(dev, class->dev_groups);

      ->sysfs_create_groups(&dev->kobj, groups);  ///sys/class/leds/lcd-backlight/brightness

    ->if (type) {

     ->device_add_groups(dev, type->group);  //if (dev->type) 这个应该不存在

    ->device_add_groups(dev, dev->groups);  //这个也不存在

创建设备节点:

struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) ->device_create_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, va_list args)

  ->device_create_groups_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, va_list args)

 /kernel-4.14/include/linux/pm.h

1
2
3
4
5
6
7
8

/*
 * Use this if you want to use the same suspend and resume callbacks for suspend
 * to RAM and hibernation.
 */
#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
const struct dev_pm_ops name = { \
    SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}

 /kernel-4.14/include/linux/device.h

1
2
3
4
5
6
7
8
9

struct class {
        const char                *name;
        struct module                *owner;

        const struct attribute_group        **class_groups;     //Default attributes of this class.
        const struct attribute_group        **dev_groups;    //Default attributes of the devices that belong to the class. 
        struct kobject                        *dev_kobj;
        ... ...
}

brightness_show

 ->led_update_brightness(led_cdev)

  ->ret = led_cdev->brightness_get(led_cdev)  //if (led_cdev->brightness_get)

  ->led_cdev->brightness = ret

 /kernel-4.9-lc/drivers/leds/led-class.c 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

static struct class *leds_class;
static ssize_t brightness_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    struct led_classdev *led_cdev = dev_get_drvdata(dev);

    /* no lock needed for this */
    led_update_brightness(led_cdev);

    return sprintf(buf, "%u\n", led_cdev->brightness);
}

static ssize_t brightness_store(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t size)
{
    struct led_classdev *led_cdev = dev_get_drvdata(dev);
    unsigned long state;
    ssize_t ret;

    mutex_lock(&led_cdev->led_access);

    if (led_sysfs_is_disabled(led_cdev)) {
        ret = -EBUSY;
        goto unlock;
    }

    ret = kstrtoul(buf, 10, &state);
    if (ret)
        goto unlock;

    if (state == LED_OFF)
        led_trigger_remove(led_cdev);
    led_set_brightness(led_cdev, state);

    ret = size;
unlock:
    mutex_unlock(&led_cdev->led_access);
    return ret;
}
static DEVICE_ATTR_RW(brightness);

static ssize_t max_brightness_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    struct led_classdev *led_cdev = dev_get_drvdata(dev);

    return sprintf(buf, "%u\n", led_cdev->max_brightness);
}
static DEVICE_ATTR_RO(max_brightness);

#ifdef CONFIG_LEDS_TRIGGERS
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
static struct attribute *led_trigger_attrs[] = {
    &dev_attr_trigger.attr,
    NULL,
};

static const struct attribute_group led_trigger_group = {
    .attrs = led_trigger_attrs,
};
#endif

static struct attribute *led_class_attrs[] = {
    &dev_attr_brightness.attr,
    &dev_attr_max_brightness.attr,
    NULL,
};

static const struct attribute_group led_group = {
    .attrs = led_class_attrs,
};

static const struct attribute_group *led_groups[] = {
    &led_group,
#ifdef CONFIG_LEDS_TRIGGERS
    &led_trigger_group,
#endif
    NULL,
};

#ifdef CONFIG_PM_SLEEP
static int led_suspend(struct device *dev)
{
    struct led_classdev *led_cdev = dev_get_drvdata(dev);

    if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
        led_classdev_suspend(led_cdev);

    return 0;
}

static int led_resume(struct device *dev)
{
    struct led_classdev *led_cdev = dev_get_drvdata(dev);

    if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
        led_classdev_resume(led_cdev);

    return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);

static int __init leds_init(void)
{
    leds_class = class_create(THIS_MODULE, "leds");
    if (IS_ERR(leds_class))
        return PTR_ERR(leds_class);
    leds_class->pm = &leds_class_dev_pm_ops;
    leds_class->dev_groups = led_groups;
    return 0;
}
subsys_initcall(leds_init);

static unsigned int bl_div_hal = CLK_DIV1;

static ssize_t brightness_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)  //kernel-4.9-lc/drivers/leds/led-class.c

 ->struct led_classdev *led_cdev = dev_get_drvdata(dev)

 ->->kstrtoul(buf, 10, &state)  //从buf提取亮度级数,转换为长整数

 ->struct led_classdev *led_cdev = dev_get_drvdata(dev);  //return dev->driver_data;

 ->led_set_brightness(led_cdev, state)    //最终调用了__led_set_brightness(led_cdev, value)  //kernel-4.9-lc/drivers/leds/led-core.c

  ->led_cdev->brightness_set(led_cdev, value)  //kernel-4.14/drivers/leds/led-core.c

   ->mt65xx_led_set            //kernel-4.14/drivers/misc/mediatek/leds/mtk_leds_drv.c

    ->mt_mt65xx_led_set(led_cdev, level)  //kernel-4.14/drivers/misc/mediatek/leds/mt8168/mtk_leds.c

     ->struct mt65xx_led_data *led_data = container_of(led_cdev, struct mt65xx_led_data, cdev);

     //#ifdef CONFIG_MTK_AAL_SUPPORT

     ->disp_aal_notify_backlight_changed((((1 <<MT_LED_INTERNAL_LEVEL_BIT_CNT) - 1) * level + 127) / 255)  //将255等级转换成1023等级

      ->backlight_brightness_set(bl_1024)

       ->struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list()

        ->get_cust_led_dtsi()

         ->if (pled_dtsi)

          ->return pled_dtsi  //如果pled_dtsi存在,证明已经在mt65xx_leds_probe初始化成功,直接返回pled_dtsi

       ->if (MT65XX_LED_MODE_CUST_BLS_PWM == cust_led_list[MT65XX_LED_TYPE_LCD].mode)

       ->MT65XX_LED_MODE_CUST_BLS_PWM  //背光

        ->mt_mt65xx_led_set_cust(&cust_led_list[MT65XX_LED_TYPE_LCD],  level)  //mt_mt65xx_led_set_cust(struct cust_mt65xx_led *cust, int level)

         ->struct nled_setting led_tmp_setting = { 0, 0, 0 };

         ->case MT65XX_LED_MODE_PWM

          ->mt_led_set_pwm(cust->data, &led_tmp_setting);

         ->case MT65XX_LED_MODE_GPIO

          ->return ((cust_set_brightness) (cust->data)) (level);

         ->case MT65XX_LED_MODE_PMIC  //指示灯

          ->mt_brightness_set_pmic(cust->data, level, bl_div_hal);

         ->case MT65XX_LED_MODE_CUST_LCM

          ->return ((cust_brightness_set) (cust->data)) (level, bl_div_hal);

         ->case MT65XX_LED_MODE_CUST_BLS_PWM  //背光

          ->return ((cust_set_brightness) (cust->data)) (level)

           ->disp_bls_set_backlight(level) /kernel-4.19-lc/drivers/misc/mediatek/video/common/aal20/ddp_pwm.c  /kernel-4.14/drivers/misc/mediatek/leds/mt8168/mtk_leds.c

            ->ret = disp_pwm_set_backlight(disp_pwm_get_main(), level_1024);  //int disp_pwm_set_backlight(enumdisp_pwm_id_t id, int level_1024)

             ->disp_pwm_set_backlight_cmdq(id, level_1024NULL)  /* Always write registers by CPU */

              ->reg_base = pwm_get_reg_base(id);                            //kernel-4.19-lc/drivers/misc/mediatek/video/mt6580/dispsys/ddp_reg.h

               ->DISPSYS_PWM0_BASE

                ->dispsys_reg[DISP_REG_PWM]

                 -><0x1100F000 0x1000>,    /*DISP_PWM*/

              ->DISP_REG_MASK(cmdqreg_base + DISP_PWM_CON_1_OFFlevel_1024 << 16, 0x1fff << 16) //将level_1024写进寄存器

               ->mt_reg_sync_writel((unsigned int)(INREG32(reg32)&~(mask))|(val), (volatile unsigned long *)(reg32));

                ->__raw_writel((v), (void __force __iomem *)((a))); //#define mt_reg_sync_writel(v, a)

               ->mb();

                ->__asm__ __volatile__ ("dsb" : : : "memory");

              ->disp_pwm_set_enabled(cmdq, id, 1);

               ->DISP_REG_MASK(NULLreg_base + DISP_PWM_EN_OFF, 0x1, 0x1);  //PWM使能

               ->disp_pwm_set_drverIC_en(id, enabled);  //#ifdef GPIO_LCM_LED_EN 没用

             ->if (ret >= 0) {

              disp_pwm_trigger_refresh(id, (level_1024 == 0));  /* For backlight turn-off, we have to trigger right away*/

       ->else

       ->mt65xx_led_set_cust(&cust_led_list[MT65XX_LED_TYPE_LCD], (level >>(MT_LED_INTERNAL_LEVEL_BIT_CNT - 8)));

        ->MT65XX_LED_MODE_CUST_BLS_PWM

         ->mt_mt65xx_led_set_cust(cust, ((((1 << LED_INTERNAL_LEVEL_BIT_CNT) - 1) * level + 127) / 255));

        ->mt_mt65xx_led_set_cust(cust, level);

     //#else

         if (led_data->cust.mode == MT65XX_LED_MODE_CUST_BLS_PWM)

             mt_mt65xx_led_set_cust(&led_data->cust, ((((1 << MT_LED_INTERNAL_LEVEL_BIT_CNT)- 1) * level + 127) / 255));

         else

             mt_mt65xx_led_set_cust(&led_data->cust, level);

无论什么条件,最终都是调用了mt_mt65xx_led_set_cust(), 然后通过DISP_REG_MASK()将背光亮度写进寄存器

PS: led_set_brightness的详细调用过程:

led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness)

 ->if (led_cdev->flags & LED_SUSPENDED) return;

 ->led_set_brightness_nosleep(led_cdev, brightness)

  ->led_cdev->brightness = min(value, led_cdev->max_brightness);  //取最小值,保存到led_cdev->brightness,以备show

   ->led_set_brightness_nopm(led_cdev, led_cdev->brightness)

    /* Use brightness_set op if available, it is guaranteed not to sleep */

    ->if (!__led_set_brightness(led_cdev, value))

       ->led_cdev->brightness_set(led_cdev, value)

     ->return;

    /* If brightness setting can sleep, delegate it to a work queue task */

    ->led_cdev->delayed_set_value = value;

    ->schedule_work(&led_cdev->set_brightness_work);

================================================================================

thermal设置最大亮度流程:

/kernel-4.14/drivers/misc/mediatek/thermal/mtk_cooler_backlight.c

/* bind fan callbacks to fan device */

static struct thermal_cooling_device_ops mtk_cl_backlight_ops = {

        .get_max_state = mtk_cl_backlight_get_max_state,

        .get_cur_state = mtk_cl_backlight_get_cur_state,

        .set_cur_state = mtk_cl_backlight_set_cur_state,

};

mtk_cl_backlight_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)

 ->mtk_cl_backlight_set_max_brightness_limit(void)

  ->setMaxbrightness(int max_level, int enable)

   ->disp_bls_set_max_backlight(((((1 << LED_INTERNAL_LEVEL_BIT_CNT) - 1) * max_level + 127) / 255));

    ->disp_pwm_set_max_backlight(disp_pwm_get_main(), level_1024);

     ->disp_pwm_set_backlight(id, atomic_read(&g_pwm_backlight[index]));

      ->disp_pwm_set_backlight_cmdq(id, level_1024, NULL);  /* Always write registers by CPU */

      ->disp_pwm_trigger_refresh(id, (level_1024 == 0));  /* For backlight turn-off, we have to trigger right away*/

adb cat 

<4>[  541.496468]  (0)[6335:cat]Isaac [led_update_brightness] enter

<4>[  541.496499]  (0)[6335:cat]Isaac [brightness_show] led_cdev->brightness=155

adb echo

<4>[  751.958250]  (1)[7320:sh]Isaac [brightness_store] buf=166

<4>[  751.962956]  (0)[927:mnld]Isaac [led_update_brightness] enter

<4>[  751.962987]  (0)[927:mnld]Isaac [brightness_show] led_cdev->brightness=166

///kernel-4.9-lc/drivers/misc/mediatek/leds/mt6580/mtk_led.c

struct cust_mt65xx_led *mt_get_cust_led_list(void)

{

        struct cust_mt65xx_led *cust_led_list = get_cust_led_dtsi();

        return cust_led_list;

}

void mt_led_pwm_disable(int pwm_num)

{

        struct cust_mt65xx_led *cust_led_list = get_cust_led_dtsi();

        mt_pwm_disable(pwm_num, cust_led_list->config_data.pmic_pad);

}

struct cust_mt65xx_led *get_cust_led_dtsi(void)

{

case MT65XX_LED_MODE_CUST_BLS_PWM:

                                        pled_dtsi[i].data =

                                            (long)disp_bls_set_backlight;

                                        LEDS_DEBUG

                                            ("kernel:the backlight hw mode is BLS.\n");

                                        break;

}

///kernel-4.9-lc/drivers/misc/mediatek/leds/mtk_leds_drv.c

static int mt65xx_leds_probe(struct platform_device *pdev)

{

        struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();
       g_leds_data[i]->cdev.brightness_set = mt65xx_led_set;

}

--------------------------------------------------------------------------------------------------------  

(220416_09:51:53.150)[   25.853800] <3>.(3)[1062:android.hardwar]mtk_leds backlight_debug_log(119) :[BL] Set Backlight directly T:25.853,L:103 map:103   

(220416_09:51:53.150)[   25.853808] <3>.(3)[1062:android.hardwar]Isaac [disp_bls_set_backlight] level_1024=413

(220416_09:51:53.150)[   25.856428] <3>-(3)[1062:android.hardwar]CPU: 3 PID: 1062 Comm: android.hardwar Tainted: P        W  O      4.19.191 #14

(220416_09:51:53.150)[   25.857804] <3>-(3)[1062:android.hardwar]Hardware name: Generic DT based system

(220416_09:51:53.150)[   25.858724] <3>-(3)[1062:android.hardwar]Backtrace:

(220416_09:51:53.150)[   25.859364] <3>-(3)[1062:android.hardwar][<c0111688>] (dump_backtrace) from [<c0111684>] (show_stack+0x20/0x24)

(220416_09:51:53.150)[   25.860636] <3>-(3)[1062:android.hardwar] r10:00000067 r6:ffffffff r5:c1a24ae4 r4:00000000

(220416_09:51:53.150)[   25.861684] <3>-(3)[1062:android.hardwar][<c0111664>] (show_stack) from [<c1276a44>] (dump_stack+0x8c/0xb8)

(220416_09:51:53.151)[   25.862910] <3>-(3)[1062:android.hardwar] r10:00000067 r4:600f0013

(220416_09:51:53.151)[   25.863711] <3>-(3)[1062:android.hardwar][<c12769b8>] (dump_stack) from [<c0a290fc>] (disp_bls_set_backlight+0x28/0x98)

(220416_09:51:53.151)[   25.865069] <3>-(3)[1062:android.hardwar] r5:e42608e0 r4:0000019d

(220416_09:51:53.151)[   25.865845] <3>-(3)[1062:android.hardwar][<c0a290fc>] (disp_bls_set_backlight) from [<c0af0fe8>] (mt_mt65xx_led_set_cust+0x158/0x268)

(220416_09:51:53.151)[   25.867370] <3>-(3)[1062:android.hardwar][<c0af0e90>] (mt_mt65xx_led_set_cust) from [<c0af13c8>] (mt_mt65xx_led_set+0x248/0x2d8)

(220416_09:51:53.151)[   25.868836] <3>-(3)[1062:android.hardwar] r7:0000019d r6:c19cd01c r5:e4260800 r4:00000067

(220416_09:51:53.151)[   25.869876] <3>-(3)[1062:android.hardwar][<c0af1180>] (mt_mt65xx_led_set) from [<c0af02f8>] (mt65xx_led_set+0xb4/0xe4)

(220416_09:51:53.151)[   25.871224] <3>-(3)[1062:android.hardwar] r10:00000004 r9:c190a208 r8:00000004 r7:00000000 r6:e4260800 r5:00000067

(220416_09:51:53.151)[   25.872524] <3>-(3)[1062:android.hardwar] r4:e4260800

(220416_09:51:53.152)[   25.873168] <3>-(3)[1062:android.hardwar][<c0af02f8>] (mt65xx_led_set) from [<c0dd43c4>] (led_set_brightness+0x58/0xa0)

(220416_09:51:53.152)[   25.874528] <3>-(3)[1062:android.hardwar][<c0dd436c>] (led_set_brightness) from [<c0dd4c5c>] (brightness_store+0x8c/0xb4)

(220416_09:51:53.152)[   25.875906] <3>-(3)[1062:android.hardwar] r5:e42608cc r4:ddb68a80

(220416_09:51:53.152)[   25.876682] <3>-(3)[1062:android.hardwar][<c0dd4c5c>] (brightness_store) from [<c07f9b3c>] (dev_attr_store+0x40/0x4c)

(220416_09:51:53.152)[   25.878022] <3>-(3)[1062:android.hardwar][<c07f9b3c>] (dev_attr_store) from [<c03e1530>] (sysfs_kf_write+0x58/0x64)

(220416_09:51:53.152)[   25.879340] <3>-(3)[1062:android.hardwar][<c03e1530>] (sysfs_kf_write) from [<c03dfb64>] (kernfs_fop_write+0x148/0x1d8)

(220416_09:51:53.152)[   25.880700] <3>-(3)[1062:android.hardwar][<c03dfb64>] (kernfs_fop_write) from [<c0336268>] (__vfs_write+0x58/0x178)

(220416_09:51:53.152)[   25.882017] <3>-(3)[1062:android.hardwar][<c0336210>] (__vfs_write) from [<c03365f4>] (vfs_write+0xd0/0x198)

(220416_09:51:53.152)[   25.883265] <3>-(3)[1062:android.hardwar] r9:deb86000 r8:deb87f60 r7:bedeaf38 r6:00000004 r5:00000004 r4:de982300

(220416_09:51:53.153)[   25.884574] <3>-(3)[1062:android.hardwar][<c0336524>] (vfs_write) from [<c0336834>] (ksys_write+0x74/0xd4)

(220416_09:51:53.153)[   25.885801] <3>-(3)[1062:android.hardwar] r9:deb86000 r8:c190a208 r7:bedeaf38 r6:00000004 r5:de982303 r4:de982300

(220416_09:51:53.153)[   25.886828] <1>.(1)[1163:android.hardwar]binder: 1163:1163 ioctl 40046210 bec600d8 returned -22

(220416_09:51:53.153)[   25.887108] <3>-(3)[1062:android.hardwar][<c03367c0>] (ksys_write) from [<c03368c0>] (sys_write+0x2c/0x30)

(220416_09:51:53.153)[   25.889420] <3>-(3)[1062:android.hardwar] r10:00000004 r8:c0101204 r7:00000004 r6:00000005 r5:bedeaf38 r4:00000004

(220416_09:51:53.153)[   25.890730] <3>-(3)[1062:android.hardwar][<c03368c0>] (sys_write) from [<c0101000>] (ret_fast_syscall+0x0/0x54)

(220416_09:51:53.153)[   25.891999] <3>-(3)[1062:android.hardwar]Exception stack(0xdeb87f8c to 0xdeb87fd4)

(220416_09:51:53.153)[   25.892955] <3>-(3)[1062:android.hardwar]7f80:                            c03368c0 00000067 09cbbd8e 00000005 00000004

(220416_09:51:53.154)[   25.894300] <3>-(3)[1062:android.hardwar]7fa0: 00000000 c0101000 00000067 09cbbd8e 00000005 bedeaf38 00000004 00000014

(220416_09:51:53.154)[   25.895645] <3>-(3)[1062:android.hardwar]7fc0: 00000067 09cbbd8e 00000005 00000004 b0f0f2cc

(220416_09:51:53.154)[   25.897790] <3>.(3)[1062:android.hardwar]Isaac [disp_pwm_set_backlight] level_1024

(220416_09:51:53.154)[   25.898756] <3>.(3)[1062:android.hardwar]Isaac [disp_pwm_set_backlight_cmdq] level_1024

(220416_09:51:53.154)[   25.899768] <3>.(3)[1062:android.hardwar][PWM] disp_pwm_set_backlight_cmdq: (id = 0x1, level_1024 = 413), old = -1

(220416_09:51:53.154)[   25.901162] <3>.(3)[1062:android.hardwar][PWM] disp_pwm_backlight_status: backlight is on (413), power:(1), pwm id: (0)

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值