MT8163平台led驱动代码分析

代码路径

mt8163-kernel-3.18\drivers\misc\mediatek\leds\leds_drv.c
mt8163-kernel-3.18\drivers\misc\mediatek\leds\leds_drv.h

\mt8163-kernel-3.18\drivers\misc\mediatek\leds\mt8163\leds.c
\mt8163-kernel-3.18\drivers\misc\mediatek\leds\mt8163\leds_hal.h
\mt8163-kernel-3.18\drivers\misc\mediatek\leds\mt8163\leds_sw.h
mt8163-kernel-3.18\drivers\misc\mediatek\leds\leds_drv.c

注册led平台驱动

static struct platform_driver mt65xx_leds_driver = {
    .driver = {
           .name = "leds-mt65xx",
           .owner = THIS_MODULE,
           },
    .probe = mt65xx_leds_probe,
    .remove = mt65xx_leds_remove,
    /* .suspend      = mt65xx_leds_suspend, */
    .shutdown = mt65xx_leds_shutdown,
};

mt65xx_leds_probe函数

struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();//获取客制化的led配置信息,该函数的具体实现后面再来看
for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {
        if (cust_led_list[i].mode == MT65XX_LED_MODE_NONE) {
            g_leds_data[i] = NULL;
            continue;
        }

        g_leds_data[i] =
            kzalloc(sizeof(struct mt65xx_led_data), GFP_KERNEL);
        if (!g_leds_data[i]) {
            ret = -ENOMEM;
            goto err;
        }
//将客制化的led配置信息赋值给全局变量g_leds_data
        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;

        g_leds_data[i]->cdev.name = cust_led_list[i].name;
        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);

        ret = led_classdev_register(&pdev->dev, &g_leds_data[i]->cdev);//向内核注册led驱动,会在/sys/class/leds下产生相应的节点,当操作节点下的brghtness属性时就会调用到上面的brightness_set对应的函数mt65xx_led_set,后面分析mt65xx_led_set和mt65xx_blink_set具体实现

回过头来看客制化的led配置是如何解析的?

struct cust_mt65xx_led *mt_get_cust_led_list(void)
{
    struct cust_mt65xx_led *cust_led_list =       get_cust_led_dtsi();//直接从dtsi文件中读取led的配置信息,用户需要什么样的led效果只需要在dtsi中配置就可以了
    return cust_led_list;
}
struct cust_mt65xx_led *get_cust_led_dtsi(void)

{
for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++){
            char node_name[32] = "mediatek,";

            pled_dtsi[i].name = leds_name[i];//指示灯的名字

            led_node =
                of_find_compatible_node(NULL, NULL,
                            strcat(node_name,
                               leds_name[i]));
            if (!led_node) {
                LEDS_DEBUG("Cannot find LED node from dts\n");
                pled_dtsi[i].mode = 0;
                pled_dtsi[i].data = -1;
            } else {
                isSupportDTS = true;
                ret =
                    of_property_read_u32(led_node, "led_mode",
                             &mode);
                if (!ret) {
                    pled_dtsi[i].mode = mode;//指示灯模式
                    LEDS_DEBUG
                        ("The %s's led mode is : %d\n",
                         pled_dtsi[i].name,
                         pled_dtsi[i].mode);
                } else {
                    LEDS_DEBUG
                        ("led dts can not get led mode");
                    pled_dtsi[i].mode = 0;
                }

                ret =
                    of_property_read_u32(led_node, "data",
                             &data);
                if (!ret) {
                    pled_dtsi[i].data = data;//指示灯的data字段
                    LEDS_DEBUG
                        ("The %s's led data is : %ld\n",
                         pled_dtsi[i].name,
                         pled_dtsi[i].data);
                } else {
                    LEDS_DEBUG
                        ("led dts can not get led data");
                    pled_dtsi[i].data = -1;
                }

                ret =
                    of_property_read_u32_array(led_node,
                                   "pwm_config",
                                   pwm_config,
                                   ARRAY_SIZE
                                   (pwm_config));
                if (!ret) {
                    LEDS_DEBUG
                        ("The %s's pwm config data is %d %d %d %d %d\n",
                         pled_dtsi[i].name, pwm_config[0],
                         pwm_config[1], pwm_config[2],
                         pwm_config[3], pwm_config[4]);
                    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];//pwm配置信息

                } else
                    LEDS_DEBUG
                        ("led dts can not get pwm config data.\n");

                switch (pled_dtsi[i].mode) {
                case MT65XX_LED_MODE_CUST_LCM://如果是CUST_LCM模式设置data字段
                    pled_dtsi[i].data =
                        (long)mtkfb_set_backlight_level;
                    LEDS_DEBUG
                        ("kernel:the backlight hw mode is LCM.\n");
                    break;
                case MT65XX_LED_MODE_CUST_BLS_PWM: //如果是CUST_BLS_PWM模式设置data字段
                    pled_dtsi[i].data =
                        (long)disp_bls_set_backlight;
                    LEDS_DEBUG
                        ("kernel:the backlight hw mode is BLS.\n");
                    break;
                default:
                    break;
                }
            }
        }
}

}

那么dtsi中又是如何定义这些客制化的led配置信息呢?

/* led part */
        led0:led@0 {
            compatible = "mediatek,red";//红灯配置信息
            led_mode = <0>;
            data = < >;
            pwm_config = <0 0 0 0 0>;
        };

        led1:led@1 {
            compatible = "mediatek,green";//绿灯配置信息
            led_mode = <0>;
            data = < >;
            pwm_config = <0 0 0 0 0>;
        };

        led2:led@2 {
            compatible = "mediatek,blue";//蓝灯配置信息
            led_mode = <0>;
            data = < >;
            pwm_config = <0 0 0 0 0>;
        };

        led3:led@3 {
            compatible = "mediatek,jogball-backlight"; 
            led_mode = <0>;
            data = < >;
            pwm_config = <0 0 0 0 0>;
        };

        led4:led@4 {
            compatible = "mediatek,keyboard-backlight";//键盘灯
            led_mode = <0>;
            data = < >;
            pwm_config = <0 0 0 0 0>;
        };

        led5:led@5 {
            compatible = "mediatek,button-backlight";//按键灯
            led_mode = <0>;
            data = < >;
            pwm_config = <0 0 0 0 0>;
        };

        led6:led@6 {
            compatible = "mediatek,lcd-backlight";//lcd背光
            led_mode = <5>;
            data = < >;
            pwm_config = <0 0 0 0 0>;
            gpios = <&pio 43 0>;
        };

上面的led_mode和data具体含义是什么?下面来看mt65xx_led_set的具体实现

static void mt65xx_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);
#ifdef CONFIG_BACKLIGHT_SUPPORT_LP8557
    bool flag = FALSE;
    int value = 0;
    int retval;
    struct device_node *node = NULL;
    struct i2c_client *client = g_client;
    value = i2c_smbus_read_byte_data(g_client, 0x10);
    LEDS_DRV_DEBUG("LEDS:mt65xx_led_set:0x10 = %d\n", value);

    node = of_find_compatible_node(NULL, NULL,
                            "mediatek,lcd-backlight");
    if (node) {
        I2C_SET_FOR_BACKLIGHT = of_get_named_gpio(node, "gpios", 0);
        LEDS_DRV_DEBUG("Led_i2c gpio num for power:%d\n", I2C_SET_FOR_BACKLIGHT);
    }
#endif
    if (strcmp(led_data->cust.name, "lcd-backlight") == 0) {
#ifdef CONTROL_BL_TEMPERATURE
        mutex_lock(&bl_level_limit_mutex);
        current_level = level;
        /* LEDS_DRV_DEBUG("brightness_set_cust:current_level=%d\n", current_level); */
        if (0 == limit_flag) {
            last_level = level;
            /* LEDS_DRV_DEBUG("brightness_set_cust:last_level=%d\n", last_level); */
        } else {
            if (limit < current_level) {
                level = limit;
                LEDS_DRV_DEBUG
                    ("backlight_set_cust: control level=%d\n",
                     level);
            }
        }
        mutex_unlock(&bl_level_limit_mutex);
#endif
    }
#ifdef CONFIG_BACKLIGHT_SUPPORT_LP8557
    retval = gpio_request(I2C_SET_FOR_BACKLIGHT, "i2c_set_for_backlight");
    if (retval)
        LEDS_DRV_DEBUG("LEDS: request I2C gpio149 failed\n");

    if (strcmp(led_data->cust.name, "lcd-backlight") == 0) {
        if (level == 0) {
            LEDS_DRV_DEBUG("LEDS:mt65xx_led_set:close the power\n");
            i2c_smbus_write_byte_data(client, 0x00, 0);
            gpio_direction_output(I2C_SET_FOR_BACKLIGHT, 0);
        }
        if (!last_level1 && level) {
            LEDS_DRV_DEBUG("LEDS:mt65xx_led_set:open the power\n");
            gpio_direction_output(I2C_SET_FOR_BACKLIGHT, 1);
            mdelay(100);
            i2c_smbus_write_byte_data(client, 0x10, 4);
            flag = TRUE;
        }
        last_level1 = level;
    }
    gpio_free(I2C_SET_FOR_BACKLIGHT);
#endif
    mt_mt65xx_led_set(led_cdev, level);//最终是调用mt_mt65xx_led_set函数
#ifdef CONFIG_BACKLIGHT_SUPPORT_LP8557
    if (strcmp(led_data->cust.name, "lcd-backlight") == 0) {
        if (flag) {
            i2c_smbus_write_byte_data(client, 0x14, 0xdf);
            i2c_smbus_write_byte_data(client, 0x04, 0xff);
            i2c_smbus_write_byte_data(client, 0x00, 1);
        }
    }
#endif
}
void mt_mt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level)
{
switch (cust->mode) {
    case MT65XX_LED_MODE_PWM:
    if (strcmp(cust->name, "lcd-backlight") == 0) {
            bl_brightness_hal = level;
            if (level == 0) {
                mt_pwm_disable(cust->data,
                           cust->config_data.pmic_pad);

            } else {

                if (BacklightLevelSupport ==
                    BACKLIGHT_LEVEL_PWM_256_SUPPORT)
                    level = brightness_mapping(tmp_level);
                else
                    level = brightness_mapto64(tmp_level);
                mt_backlight_set_pwm(cust->data, level,
                             bl_div_hal,
                             &cust->config_data);
            }
            bl_duty_hal = level;

        } else {
            if (level == 0) {
                led_tmp_setting.nled_mode = NLED_OFF;
                mt_led_set_pwm(cust->data, &led_tmp_setting);
                mt_pwm_disable(cust->data,
                           cust->config_data.pmic_pad);
            } else {
                led_tmp_setting.nled_mode = NLED_ON;
                mt_led_set_pwm(cust->data, &led_tmp_setting);
            }
        }
        return 1;
    case MT65XX_LED_MODE_GPIO:
        return ((cust_set_brightness) (cust->data)) (level);
    case MT65XX_LED_MODE_PMIC:
return 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);

}
int mt_brightness_set_pmic(enum mt65xx_led_pmic pmic_type, u32 level, u32 div)
{
if (pmic_type == MT65XX_LED_PMIC_BUTTON) {

        if (level) {
#ifdef PMIC_MT6325
            upmu_set_kpled_dim_duty(0x9);
            upmu_set_kpled_en(0x1);
#endif
        } else {
#ifdef PMIC_MT6325
            upmu_set_kpled_en(0x0);
#endif
        }
        return 0;

    }else if (pmic_type == MT65XX_LED_PMIC_NLED_ISINK0) {
        if (first_time == true) {
#ifdef PMIC_MT6325
            upmu_set_isinks_ch1_en(0x0);    /* sw workround for sync leds status */
            upmu_set_isink_rsv2_isink1(0x00);
            upmu_set_isinks_ch2_en(0x0);
            upmu_set_isink_rsv2_isink2(0x00);
#endif
            first_time = false;
        }
#ifdef PMIC_MT6325
        upmu_set_isinks_ch0_mode(ISINK_PWM_MODE);
        upmu_set_isinks_ch0_step(0x0);  /* 4mA */

        upmu_set_isink_dim0_duty(15);
        upmu_set_isink_dim0_fsel(11);   /* 6320 0.25KHz */
#endif
        led_init_flag[0] = true;

        if (level) {

#ifdef PMIC_MT6325
            upmu_set_rg_bst_drv_1m_ck_pdn(0x0);

            upmu_set_isink_rsv2_isink0(0x1);
            upmu_set_isinks_ch0_en(0x01);
#endif
        } else {
#ifdef PMIC_MT6325
            upmu_set_isinks_ch0_en(0x00);
            upmu_set_isink_rsv2_isink0(0x00);
#endif
        }
        return 0;
    }else if (pmic_type == MT65XX_LED_PMIC_NLED_ISINK1) {
        if (first_time == true) {
#ifdef PMIC_MT6325
            upmu_set_isinks_ch0_en(0);  /* sw workround for sync leds status */
            upmu_set_isink_rsv2_isink0(0x00);
            upmu_set_isinks_ch2_en(0);
            upmu_set_isink_rsv2_isink2(0x00);
#endif
            first_time = false;
        }
#ifdef PMIC_MT6325
        upmu_set_isinks_ch1_mode(ISINK_PWM_MODE);
        upmu_set_isinks_ch1_step(0x3);  /* 4mA */

        upmu_set_isink_dim1_duty(15);
        upmu_set_isink_dim1_fsel(11);   /* 6320 0.25KHz */
#endif
        led_init_flag[1] = true;

        if (level) {
#ifdef PMIC_MT6325
            upmu_set_rg_bst_drv_1m_ck_pdn(0x0);

            upmu_set_isink_rsv2_isink1(0x1);
            upmu_set_isinks_ch1_en(0x01);
#endif
        } else {
#ifdef PMIC_MT6325
            upmu_set_isinks_ch1_en(0x00);
            upmu_set_isink_rsv2_isink1(0x00);
#endif
        }
        return 0;
    }else if (pmic_type == MT65XX_LED_PMIC_NLED_ISINK2) {

        if (first_time == true) {
#ifdef PMIC_MT6325
            upmu_set_isinks_ch0_en(0);  /* sw workround for sync leds status */
            upmu_set_isink_rsv2_isink0(0x00);
            upmu_set_isinks_ch1_en(0);
            upmu_set_isink_rsv2_isink1(0x00);
#endif
            first_time = false;
        }
#ifdef PMIC_MT6325
        upmu_set_isinks_ch2_mode(ISINK_PWM_MODE);
        upmu_set_isinks_ch2_step(0x3);  /* 16mA */

        upmu_set_isink_dim2_duty(15);
        upmu_set_isink_dim2_fsel(11);   /* 6320 0.25KHz */
#endif
        led_init_flag[2] = true;

        if (level) {
#ifdef PMIC_MT6325
            upmu_set_rg_bst_drv_1m_ck_pdn(0x0);

            upmu_set_isink_rsv2_isink2(0x1);
            upmu_set_isinks_ch2_en(0x01);
#endif
        } else {
#ifdef PMIC_MT6325
            upmu_set_isinks_ch2_en(0x00);
            upmu_set_isink_rsv2_isink2(0x00);
#endif
        }
        return 0;
    }else if (pmic_type == MT65XX_LED_PMIC_NLED_ISINK01) {
#ifdef PMIC_MT6325
        upmu_set_isinks_ch0_mode(ISINK_PWM_MODE);
        upmu_set_isinks_ch0_step(0x0);  /* 4mA */
        upmu_set_isink_dim0_duty(1);
        upmu_set_isink_dim0_fsel(1);    /* 6320 1.5KHz */

        upmu_set_isinks_ch1_mode(ISINK_PWM_MODE);
        upmu_set_isinks_ch1_step(0x3);  /* 4mA */

        upmu_set_isink_dim1_duty(15);
        upmu_set_isink_dim1_fsel(11);   /* 6320 0.25KHz */
#endif
        led_init_flag[0] = true;
        led_init_flag[1] = true;

        if (level) {
#ifdef PMIC_MT6325
            upmu_set_rg_bst_drv_1m_ck_pdn(0x0);

            upmu_set_isinks_ch0_en(0x01);
            upmu_set_isinks_ch1_en(0x01);
#endif
        } else {
#ifdef PMIC_MT6325
            upmu_set_isinks_ch0_en(0x00);
            upmu_set_isinks_ch1_en(0x00);
#endif
        }
        return 0;
    }
}

猜你喜欢

转载自blog.csdn.net/yuewen2008/article/details/78380825