imx6开关机/亮屏逻辑笔记

点亮屏幕是由mcu控制,但是arm要在开机初始化framebuffer后通过一个lcd_ready脚来通知mcu点亮屏幕

关机/休眠的灭屏与掉电要等mcu发出关机/休眠信号,通知hmi保存重要数据后,消息中心才执行关机命令,关机后通过lcd_ready脚点平通知mcu允许掉电


开机亮屏部分,这部分比较容易定义一个io引脚,放到framebuffer初始化完成的的驱动代码中,代码如下,基于linux3.14.28

引入一个io引脚定义

power-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
mxcfb1: fb@0 {
    compatible = "fsl,mxc_sdc_fb";
    disp_dev = "ldb";
    interface_pix_fmt = "RGB24";
    default_bpp = <24>;
    int_clk = <0>;
    late_init = <0>;
    power-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
    status = "disabled";
};

在显示驱动里调用io引脚函数,开机显示就绪后拉低io,mcu检测到引脚拉低后点亮屏幕背光

struct power_gpios {
    int power_gpios_gpio;
    unsigned long gpio_level;   // 0: on  1: off
    int g_first_ldb;
};

static struct power_gpios g_power_gpios = {0,0,1};

g_power_gpios.power_gpios_gpio = of_get_named_gpio_flags(np, "power-gpios", 0, &flags);
if (gpio_is_valid(g_power_gpios.power_gpios_gpio))
{
	printk("[power_gpios] mxcfb_probe gpio_is_valid, ret = %d \n", gpio_is_valid(g_power_gpios.power_gpios_gpio));

	if(!gpio_request(g_power_gpios.power_gpios_gpio, "power_gpios"))
	{
		printk("[power_gpios] mxcfb_probe gpio_request \n");
		gpio_direction_output(g_power_gpios.power_gpios_gpio, 1);
		gpio_set_value(g_power_gpios.power_gpios_gpio, 0);

		g_power_gpios.gpio_level = 0;
	}
}

通知关机的部分相对坑多,在开部分已经被坑了,只是不影响功能所以看不出来

关机逻辑是为了应对在没有只读文件系统的前提下频繁掉电引起的emmc程序丢失,数据损坏的问题

mcu发出关机命令后,系统进行关机,关机完成后对lcd_ready引脚拉高电平,mcu检测到高电平后方可给arm断电

这里采用了增加属性节点的方式来进行io引脚的控制

加入了class属性的节点,这部分没有保留就拿了一个类似的写在文章里

#include <linux/miscdevice.h>
#include <linux/input.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/of_platform.h>
#include <linux/device.h>

struct shutdown_io {
	int shutdown_io_gpio;
	unsigned long gpio_level;	// 0:PA mute on  1:PA mute off
};

static struct shutdown_io g_shutdown_io;
static struct class *shutdown_io_class;

static ssize_t enable_store(struct class *class, struct class_attribute *attr,
			const char *buf, size_t count)
{
	int rc;
	unsigned long gpio_level = 0;

	rc = kstrtoul(buf, 0, &gpio_level);
	if (rc)
		return rc;

	if (gpio_is_valid(g_shutdown_io.shutdown_io_gpio))
	{
		gpio_direction_output(g_shutdown_io.shutdown_io_gpio, 1);
		gpio_set_value(g_shutdown_io.shutdown_io_gpio, gpio_level);

		g_shutdown_io.gpio_level = gpio_level;

		//printk("[bgk] 43 shutdown_io enable_store, gpio_level = %ld \n", gpio_level);
	}
	else
	{
		printk("[bgk] 46 shutdown_io gpio_is_valid failed \n");
	}

	return count;
}

static ssize_t enable_show(struct class *class, struct class_attribute *attr, char *buf)
{
	if (gpio_is_valid(g_shutdown_io.shutdown_io_gpio))
	{
		//printk("[bgk] 34 shutdown_io enable_show, gpio_level = %ld \n", g_shutdown_io.gpio_level);
	}
	else
	{
		printk("[bgk] 35 shutdown_io gpio_is_valid failed \n");
		return -1;
	}

	return sprintf(buf, "%ld\n", g_shutdown_io.gpio_level);
}

static CLASS_ATTR(enable, 0755, enable_show, enable_store);


static int shutdown_io_probe(struct platform_device *pdev)
{
	int ret = -1;
	enum of_gpio_flags flag;
	struct device_node *shutdown_io_node = pdev->dev.of_node;
	g_shutdown_io.shutdown_io_gpio = of_get_named_gpio_flags(shutdown_io_node, "enable-gpios", 0, &flag);
	//printk("[bgk] 8001 shutdown_io_probe, get gpio id successful \n");

	if(!gpio_is_valid(g_shutdown_io.shutdown_io_gpio))
	{
		printk("[bgk] 8002 invalid shutdown_io-gpios: %d\n", g_shutdown_io.shutdown_io_gpio);
		return -1;
	}

	if(gpio_request(g_shutdown_io.shutdown_io_gpio, "shutdown_io_gpio"))
	{
		printk("[bgk] 8003 shutdown_io gpio request failed! \n");
		return ret; 
	}

	gpio_direction_output(g_shutdown_io.shutdown_io_gpio, 1);
	gpio_set_value(g_shutdown_io.shutdown_io_gpio, 1);

	g_shutdown_io.gpio_level = 1;

	shutdown_io_class = class_create(THIS_MODULE, "shutdown_io");
	if (IS_ERR(shutdown_io_class)) {
		pr_warn("Unable to create backlight class; errno = %ld\n",
			PTR_ERR(shutdown_io_class));
		return PTR_ERR(shutdown_io_class);
	}


	ret = class_create_file(shutdown_io_class, &class_attr_enable);
	if(ret < 0)
	{
		printk("[bgk] 8004 shutdown_io class_create_file failed! \n");
		return -ENOMEM;
	}

	return 0;
}

static int shutdown_io_remove(struct platform_device *pdev)
{
	if(!gpio_is_valid(g_shutdown_io.shutdown_io_gpio))
	{
		printk("[bgk] 8005 invalid shutdown_io-gpios: %d\n", g_shutdown_io.shutdown_io_gpio); 
		return -1;
	}
	gpio_set_value(g_shutdown_io.shutdown_io_gpio, 0);
	gpio_free(g_shutdown_io.shutdown_io_gpio);

	class_remove_file(shutdown_io_class, &class_attr_enable);
	class_destroy(shutdown_io_class);

	return 0;
}

static struct of_device_id shutdown_io_of_match[] = {
		{ .compatible = "shutdown_io" },
		{ }
};
MODULE_DEVICE_TABLE(of, shutdown_io_of_match);


static struct platform_driver shutdown_io_driver = {
		.driver	= {
			.name		= "shutdown_io",
			.owner		= THIS_MODULE,
			.of_match_table = of_match_ptr(shutdown_io_of_match),
		},
		.probe			= shutdown_io_probe,
		.remove			= shutdown_io_remove,
};

module_platform_driver(shutdown_io_driver);

MODULE_DESCRIPTION("shutdown_io Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:shutdown_io");

这部分代码加在了drivers/video/mxc/mxc_ipuv3_fb.c的mxcfb_probe函数中最末尾

信心满满去验证属性节点,结果当头一棒,运行提示权限不足运行失败

怀疑是属性节点的使用条件问题,多次检测属性节点的使用条件,在平台驱动里调用,打印返回值也都是正确的,就是在应用层访问属性节点的时候提示权限问题,但这个提示显然不是因为创建属性节点时指定的权限问题

static CLASS_ATTR(enable, 0755, enable_show, enable_store);
很是迷茫,百度这个函数,竟然没有任何收获,倒是看源码得出正确时返回0,这是也确实返回0
class_create_file

在mxc_ipuv3_fb.c里看到有引用了device_create_file,设备属性节点的创建,而且能正确运转,于是将class属性节点更换为device属性节点

struct power_gpios {
    int power_gpios_gpio;
    unsigned long gpio_level;   // 0: on  1: off
    int g_first_ldb;
};

static struct power_gpios g_power_gpios = {0,0,1};
static struct class *power_gpios_class;

static ssize_t enable_show(struct device *dev,
                struct device_attribute *attr, char *buf)
{
    printk("[power_gpios] enable_show, power_gpios_gpio = %d \n", g_power_gpios.power_gpios_gpio);
    if (gpio_is_valid(g_power_gpios.power_gpios_gpio))
    {
        printk("[bgk] 34 power_gpios enable_show, gpio_level = %ld \n", g_power_gpios.gpio_level);
    }
    else
    {
        printk("[bgk] 35 power_gpios gpio_is_valid failed, ret = %d \n", gpio_is_valid(g_power_gpios.power_gpios_gpio));
        return -1;
    }

    return sprintf(buf, "%ld\n", g_power_gpios.gpio_level);
}

static ssize_t enable_store(struct device *dev,
                    struct device_attribute *attr,
                    const char *buf, size_t count)
{

    int rc;
    unsigned long gpio_level = 0;
    printk("[power_gpios] enable_store, power_gpios_gpio = %d \n", g_power_gpios.power_gpios_gpio);

    rc = kstrtoul(buf, 0, &gpio_level);
    if (rc)
        return rc;

    if (gpio_is_valid(g_power_gpios.power_gpios_gpio))
    {
        gpio_direction_output(g_power_gpios.power_gpios_gpio, 1);
        gpio_set_value(g_power_gpios.power_gpios_gpio, gpio_level);

        g_power_gpios.gpio_level = gpio_level;

        printk("[bgk] 43 power_gpios enable_store, gpio_level = %ld \n", gpio_level);
    }
    else
    {
        printk("[bgk] 35 power_gpios gpio_is_valid failed, ret = %d \n", gpio_is_valid(g_power_gpios.power_gpios_gpio));
    }

    return count;
}

static DEVICE_ATTR(lcd_power, S_IWUSR | S_IRUGO, enable_show, enable_store);

ret = device_create_file(fbi->dev, &dev_attr_lcd_power);
			printk("[bgk] device_create_file ret = %d \n", ret);
			if (ret)
			dev_err(&pdev->dev, "Error %d on creating fdev_attr_enable "
					" device propety\n", ret);

更换完之后出了属性节点的路径不同,无法读取节点的现象是一样的,故排除了class属性节点或者device属性节点的原因,问题定位到enbale_show和enable_store这两个函数

static DEVICE_ATTR(lcd_power, S_IWUSR | S_IRUGO, enable_show, enable_store);

将这两个函数留空后,正确运行,定位到操作io的函数,通过打印发现drivers/video/mxc/mxc_ipuv3_fb.c的mxcfb_probe函数被执行了3次,说明有3个设备被找到并进行了注册,这个是导致IO引脚运行一场的根本原因

mxcfb1: fb@0 {
    compatible = "fsl,mxc_sdc_fb";
    disp_dev = "ldb";
    interface_pix_fmt = "RGB24";
    default_bpp = <24>;
    int_clk = <0>;
    late_init = <0>;
    power-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
    status = "disabled";
};
// modified-end by xiongqin.bi for 720p

mxcfb2: fb@1 {
    compatible = "fsl,mxc_sdc_fb";
    disp_dev = "hdmi";
    interface_pix_fmt = "RGB24";
    mode_str ="1920x1080M@60";
    default_bpp = <24>;
    int_clk = <0>;
    late_init = <0>;
    status = "disabled";
};

mxcfb3: fb@2 {
    compatible = "fsl,mxc_sdc_fb";
    disp_dev = "lcd";
    interface_pix_fmt = "RGB565";
    mode_str ="CLAA-WVGA";
    default_bpp = <16>;
    int_clk = <0>;
    late_init = <0>;
    status = "disabled";
};

mxcfb4: fb@3 {
    compatible = "fsl,mxc_sdc_fb";
    disp_dev = "ldb";
    interface_pix_fmt = "RGB666";
    default_bpp = <16>;
    int_clk = <0>;
    late_init = <0>;
    status = "disabled";
};
将dts中的显示设备遍历到驱动里在mxcfb_dispdrv_init函数进行,disp_dev数组则是存放着每次注册的显示设备
static int mxcfb_dispdrv_init(struct platform_device *pdev,
		struct fb_info *fbi)
{
	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
	struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
	struct mxc_dispdrv_setting setting;
	char disp_dev[32], *default_dev = "lcd";
	int ret = 0;

	setting.if_fmt = plat_data->interface_pix_fmt;
	setting.dft_mode_str = plat_data->mode_str;
	setting.default_bpp = plat_data->default_bpp;
	if (!setting.default_bpp)
		setting.default_bpp = 16;
	setting.fbi = fbi;
	if (!strlen(plat_data->disp_dev)) {
		memcpy(disp_dev, default_dev, strlen(default_dev));
		disp_dev[strlen(default_dev)] = '\0';
	} else {
		memcpy(disp_dev, plat_data->disp_dev,
				strlen(plat_data->disp_dev));
		disp_dev[strlen(plat_data->disp_dev)] = '\0';
	}

	mxcfbi->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);
	if (IS_ERR(mxcfbi->dispdrv)) {
		ret = PTR_ERR(mxcfbi->dispdrv);
		dev_err(&pdev->dev, "NO mxc display driver found!\n");
		return ret;
	} else {
		/* fix-up  */
		mxcfbi->ipu_di_pix_fmt = setting.if_fmt;
		mxcfbi->default_bpp = setting.default_bpp;

		ret = mxcfb_get_crtc(&pdev->dev, mxcfbi, setting.crtc);
		if (ret)
			return ret;

		dev_dbg(&pdev->dev, "di_pixfmt:0x%x, bpp:0x%x, di:%d, ipu:%d\n",
				setting.if_fmt, setting.default_bpp,
				mxcfbi->ipu_di, mxcfbi->ipu_id);
	}

	dev_info(&pdev->dev, "registered mxc display driver %s\n", disp_dev);

	return ret;
}

定位到原因之后就做过滤,只在注册ldb驱动的时候创建和调用属性节点

struct power_gpios {
    int power_gpios_gpio;
    unsigned long gpio_level;   // 0: on  1: off
    int g_first_ldb;
};

static struct power_gpios g_power_gpios = {0,0,1};
static struct class *power_gpios_class;

static ssize_t enable_show(struct device *dev,
                struct device_attribute *attr, char *buf)
{
    printk("[power_gpios] enable_show, power_gpios_gpio = %d \n", g_power_gpios.power_gpios_gpio);
    if (gpio_is_valid(g_power_gpios.power_gpios_gpio))
    {
        printk("[bgk] 34 power_gpios enable_show, gpio_level = %ld \n", g_power_gpios.gpio_level);
    }
    else
    {
        printk("[bgk] 35 power_gpios gpio_is_valid failed, ret = %d \n", gpio_is_valid(g_power_gpios.power_gpios_gpio));
        return -1;
    }

    return sprintf(buf, "%ld\n", g_power_gpios.gpio_level);
}

static ssize_t enable_store(struct device *dev,
                    struct device_attribute *attr,
                    const char *buf, size_t count)
{

    int rc;
    unsigned long gpio_level = 0;
    printk("[power_gpios] enable_store, power_gpios_gpio = %d \n", g_power_gpios.power_gpios_gpio);

    rc = kstrtoul(buf, 0, &gpio_level);
    if (rc)
        return rc;

    if (gpio_is_valid(g_power_gpios.power_gpios_gpio))
    {
        gpio_direction_output(g_power_gpios.power_gpios_gpio, 1);
        gpio_set_value(g_power_gpios.power_gpios_gpio, gpio_level);

        g_power_gpios.gpio_level = gpio_level;

        printk("[bgk] 43 power_gpios enable_store, gpio_level = %ld \n", gpio_level);
    }
    else
    {
        printk("[bgk] 35 power_gpios gpio_is_valid failed, ret = %d \n", gpio_is_valid(g_power_gpios.power_gpios_gpio));
    }

    return count;
}

static DEVICE_ATTR(lcd_power, S_IWUSR | S_IRUGO, enable_show, enable_store);

static int mxcfb_probe(struct platform_device *pdev)
{
    // int lcd_ready;
    enum of_gpio_flags flags;
    struct device_node *np = pdev->dev.of_node;

    struct ipuv3_fb_platform_data *plat_data;
    struct fb_info *fbi;
    struct mxcfb_info *mxcfbi;
    struct resource *res;
    int ret = 0;

    dev_dbg(&pdev->dev, "%s enter\n", __func__);
    pdev->id = of_alias_get_id(pdev->dev.of_node, "mxcfb");
    if (pdev->id < 0) {
        dev_err(&pdev->dev, "can not get alias id\n");
        return pdev->id;
    }

    plat_data = devm_kzalloc(&pdev->dev, sizeof(struct
                    ipuv3_fb_platform_data), GFP_KERNEL);
    if (!plat_data)
        return -ENOMEM;
    pdev->dev.platform_data = plat_data;

    ret = mxcfb_get_of_property(pdev, plat_data);
    if (ret < 0) {
        dev_err(&pdev->dev, "get mxcfb of property fail\n");
        return ret;
    }

    /* Initialize FB structures */
    fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
    if (!fbi) {
        ret = -ENOMEM;
        goto init_fbinfo_failed;
    }

    ret = mxcfb_option_setup(pdev, fbi);
    if (ret)
        goto get_fb_option_failed;

    mxcfbi = (struct mxcfb_info *)fbi->par;
    mxcfbi->ipu_int_clk = plat_data->int_clk;
    mxcfbi->late_init = plat_data->late_init;
    mxcfbi->first_set_par = true;
    ret = mxcfb_dispdrv_init(pdev, fbi);
    if (ret < 0)
        goto init_dispdrv_failed;

    ret = ipu_test_set_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
    if (ret < 0) {
        dev_err(&pdev->dev, "ipu%d-di%d already in use\n",
                mxcfbi->ipu_id, mxcfbi->ipu_di);
        goto ipu_in_busy;
    }

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res && res->start && res->end) {
        fbi->fix.smem_len = res->end - res->start + 1;
        fbi->fix.smem_start = res->start;
        fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
        /* Do not clear the fb content drawn in bootloader. */
        if (!mxcfbi->late_init)
            memset(fbi->screen_base, 0, fbi->fix.smem_len);
    }

    mxcfbi->ipu = ipu_get_soc(mxcfbi->ipu_id);
    if (IS_ERR(mxcfbi->ipu)) {
        ret = -ENODEV;
        goto get_ipu_failed;
    }

    /* first user uses DP with alpha feature */
    if (!g_dp_in_use[mxcfbi->ipu_id]) {
        mxcfbi->ipu_ch_irq = IPU_IRQ_BG_SYNC_EOF;
        mxcfbi->ipu_ch_nf_irq = IPU_IRQ_BG_SYNC_NFACK;
        mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
        mxcfbi->ipu_ch = MEM_BG_SYNC;
        /* Unblank the primary fb only by default */
        if (pdev->id == 0)
            mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_UNBLANK;
        else
            mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;

        ret = mxcfb_register(fbi);
        if (ret < 0)
            goto mxcfb_register_failed;

        ipu_disp_set_global_alpha(mxcfbi->ipu, mxcfbi->ipu_ch,
                      true, 0x80);
        ipu_disp_set_color_key(mxcfbi->ipu, mxcfbi->ipu_ch, false, 0);

        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        ret = mxcfb_setup_overlay(pdev, fbi, res);

        if (ret < 0) {
            mxcfb_unregister(fbi);
            goto mxcfb_setupoverlay_failed;
        }

        g_dp_in_use[mxcfbi->ipu_id] = true;

        ret = device_create_file(mxcfbi->ovfbi->dev,
                     &dev_attr_fsl_disp_property);
        if (ret)
            dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
                            "file for disp property\n",
                            ret);

        ret = device_create_file(mxcfbi->ovfbi->dev,
                     &dev_attr_fsl_disp_dev_property);
        if (ret)
            dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
                            "file for disp device "
                            "propety\n", ret);
    } else {
        mxcfbi->ipu_ch_irq = IPU_IRQ_DC_SYNC_EOF;
        mxcfbi->ipu_ch_nf_irq = IPU_IRQ_DC_SYNC_NFACK;
        mxcfbi->ipu_alp_ch_irq = -1;
        mxcfbi->ipu_ch = MEM_DC_SYNC;
        mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;

        ret = mxcfb_register(fbi);
        if (ret < 0)
            goto mxcfb_register_failed;
    }

    platform_set_drvdata(pdev, fbi);

    ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_property);
    if (ret)
        dev_err(&pdev->dev, "Error %d on creating file for disp "
                    "property\n", ret);

    ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
    if (ret)
        dev_err(&pdev->dev, "Error %d on creating file for disp "
                    " device propety\n", ret);

    // add bi.xiongqin
    printk("[bgk] pdev->dev.platform_data->disp_dev = %s \n ", plat_data->disp_dev);
    if (!strcmp(plat_data->disp_dev, "ldb"))
    {
        printk("[bgk] g_first_ldb = %d \n ", g_power_gpios.g_first_ldb);
        if (g_power_gpios.g_first_ldb == true)
        {
            g_power_gpios.g_first_ldb = false;

            ret = device_create_file(fbi->dev, &dev_attr_lcd_power);
            printk("[bgk] device_create_file ret = %d \n", ret);
            if (ret)
            dev_err(&pdev->dev, "Error %d on creating fdev_attr_enable "
                    " device propety\n", ret);

            g_power_gpios.power_gpios_gpio = of_get_named_gpio_flags(np, "power-gpios", 0, &flags);
            printk("[power_gpios] gpio_is_valid, power_gpios_gpio = %d \n", g_power_gpios.power_gpios_gpio);
            if (gpio_is_valid(g_power_gpios.power_gpios_gpio))
            {
                printk("[power_gpios] mxcfb_probe gpio_is_valid, ret = %d \n", gpio_is_valid(g_power_gpios.power_gpios_gpio));

                if(!gpio_request(g_power_gpios.power_gpios_gpio, "power_gpios"))
                {
                    printk("[power_gpios] mxcfb_probe gpio_request \n");
                    gpio_direction_output(g_power_gpios.power_gpios_gpio, 1);
                    gpio_set_value(g_power_gpios.power_gpios_gpio, 0);

                    g_power_gpios.gpio_level = 0;
                }
            }
        }
    }
    // end bi.xiongqin

    return 0;

mxcfb_setupoverlay_failed:
mxcfb_register_failed:
get_ipu_failed:
    ipu_clear_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
ipu_in_busy:
init_dispdrv_failed:
    fb_dealloc_cmap(&fbi->cmap);
    framebuffer_release(fbi);
get_fb_option_failed:
init_fbinfo_failed:
    return ret;
}

static int mxcfb_remove(struct platform_device *pdev)
{
    struct fb_info *fbi = platform_get_drvdata(pdev);
    struct mxcfb_info *mxc_fbi = fbi->par;

    if (!fbi)
        return 0;

    device_remove_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
    device_remove_file(fbi->dev, &dev_attr_fsl_disp_property);
    mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
    mxcfb_unregister(fbi);
    mxcfb_unmap_video_memory(fbi);

    if (mxc_fbi->ovfbi) {
        device_remove_file(mxc_fbi->ovfbi->dev,
                   &dev_attr_fsl_disp_dev_property);
        device_remove_file(mxc_fbi->ovfbi->dev,
                   &dev_attr_fsl_disp_property);
        mxcfb_blank(FB_BLANK_POWERDOWN, mxc_fbi->ovfbi);
        mxcfb_unsetup_overlay(fbi);
        mxcfb_unmap_video_memory(mxc_fbi->ovfbi);
    }

    ipu_clear_usage(mxc_fbi->ipu_id, mxc_fbi->ipu_di);
    if (&fbi->cmap)
        fb_dealloc_cmap(&fbi->cmap);
    framebuffer_release(fbi);

    // add bi.xiongqin
    if(!gpio_is_valid(g_power_gpios.power_gpios_gpio))
    { 
        printk("[bgk] 8005 invalid power_gpios-gpios: %d\n", g_power_gpios.power_gpios_gpio); 
        return -1; 
    }
    gpio_set_value(g_power_gpios.power_gpios_gpio, 0);
    gpio_free(g_power_gpios.power_gpios_gpio);

    device_remove_file(fbi->dev, &dev_attr_lcd_power);
    // add bi.xiongqin

    return 0;
}

最后还要在关机的时候调用该属性节点,增加/etc/rc0.d下在S40umountfs之前脚本S34power_gpios.sh

#!/bin/bash
echo 1 > /sys/class/graphics/fb0/lcd_power







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值