软件框架:

lcd框架其实与i2c/spi及其他驱动框架大同小异,都是由一个底层的platform驱动和一个较上层的抽象驱动组成。前者一般由厂商编写,而后者是内核框架提供的。


核心层 \linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek\drivers\video\fbdev\core\fbmem.c

主要做的事情:

注册字符设备(只创建class),提供上层接口,但是还得需要调用底层的platform驱动提供的api。

static int __init
fbmem_init(void)
{proc_create("fb", 0, NULL, &fb_proc_fops);if (register_chrdev(FB_MAJOR,"fb",&fb_fops))printk("unable to get major %d for fb devs\n", FB_MAJOR);fb_class = class_create(THIS_MODULE, "graphics");if (IS_ERR(fb_class)) {printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));fb_class = NULL;}return 0;
}

这里实现的fb_fops大部分还是需要调用platform的api。

static const struct file_operations fb_fops = {.owner =    THIS_MODULE,.read =        fb_read,.write =   fb_write,.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl = fb_compat_ioctl,
#endif.mmap =      fb_mmap,.open =        fb_open,.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO.fsync =   fb_deferred_io_fsync,
#endif.llseek =    default_llseek,
};

如:

static int
fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{int fbidx = iminor(inode);struct fb_info *info;int res = 0;info = get_fb_info(fbidx);if (!info) {request_module("fb%d", fbidx);info = get_fb_info(fbidx);if (!info)return -ENODEV;}if (IS_ERR(info))return PTR_ERR(info);mutex_lock(&info->lock);if (!try_module_get(info->fbops->owner)) {res = -ENODEV;goto out;}file->private_data = info;if (info->fbops->fb_open) {res = info->fbops->fb_open(info,1);//调用info中的fopsif (res)module_put(info->fbops->owner);}
#ifdef CONFIG_FB_DEFERRED_IOif (info->fbdefio)fb_deferred_io_open(info, inode, file);
#endif
out:mutex_unlock(&info->lock);if (res)put_fb_info(info);return res;
}

*我们发现这两层是通过struct fb_info info;这个变量连接起来的!!

看一些这个结构体:

struct fb_info {atomic_t count;int node;int flags;struct mutex lock;     /* Lock for open/release/ioctl funcs */struct mutex mm_lock;        /* Lock for fb_mmap and smem_* fields */struct fb_var_screeninfo var;   /* Current var */struct fb_fix_screeninfo fix;  /* Current fix */struct fb_monspecs monspecs;   /* Current Monitor specs */struct work_struct queue;    /* Framebuffer event queue */struct fb_pixmap pixmap;   /* Image hardware mapper */struct fb_pixmap sprite; /* Cursor hardware mapper */struct fb_cmap cmap;        /* Current cmap */struct list_head modelist;      /* mode list */struct fb_videomode *mode; /* current mode */#ifdef CONFIG_FB_BACKLIGHT/* assigned backlight device *//* set before framebuffer registration, remove after unregister */struct backlight_device *bl_dev;/* Backlight level curve */struct mutex bl_curve_mutex;    u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IOstruct delayed_work deferred_work;struct fb_deferred_io *fbdefio;
#endifstruct fb_ops *fbops;struct device *device;       /* This is the parent */struct device *dev;     /* This is this fb device */int class_flag;                    /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTINGstruct fb_tile_ops *tileops;    /* Tile Blitting */
#endifchar __iomem *screen_base;    /* Virtual address */unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ void *pseudo_palette;      /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING    0
#define FBINFO_STATE_SUSPENDED  1u32 state;         /* Hardware state i.e suspend */void *fbcon_par;                /* fbcon use-only private area *//* From here on everything is device dependent */void *par;/* we need the PCI or similar aperture base/size notsmem_start/size as smem_start may just be an objectallocated inside the aperture so may not actually overlap */struct apertures_struct {unsigned int count;struct aperture {resource_size_t base;resource_size_t size;} ranges[0];} *apertures;bool skip_vt_switch; /* no VT switch on suspend/resume required */
};

里面存放的是lcd有关的硬件信息。

那么这个fb_info又是在哪里初始化的呢?

答案是:platform

platform驱动层linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek\drivers\video\fbdev\xx.c

当platform的probe执行时:

static int mxsfb_probe(struct platform_device *pdev)
{const struct of_device_id *of_id =of_match_device(mxsfb_dt_ids, &pdev->dev);struct resource *res;struct mxsfb_info *host;struct fb_info *fb_info;struct pinctrl *pinctrl;int irq = platform_get_irq(pdev, 0);int gpio, ret;if (of_id)pdev->id_entry = of_id->data;gpio = of_get_named_gpio(pdev->dev.of_node, "enable-gpio", 0);if (gpio == -EPROBE_DEFER)return -EPROBE_DEFER;if (gpio_is_valid(gpio)) {ret = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_OUT_INIT_LOW, "lcd_pwr_en");if (ret) {dev_err(&pdev->dev, "faild to request gpio %d, ret = %d\n", gpio, ret);return ret;}}res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) {dev_err(&pdev->dev, "Cannot get memory IO resource\n");return -ENODEV;}host = devm_kzalloc(&pdev->dev, sizeof(struct mxsfb_info), GFP_KERNEL);if (!host) {dev_err(&pdev->dev, "Failed to allocate IO resource\n");return -ENOMEM;}fb_info = framebuffer_alloc(sizeof(struct fb_info), &pdev->dev);//分配fb_info空间if (!fb_info) {dev_err(&pdev->dev, "Failed to allocate fbdev\n");devm_kfree(&pdev->dev, host);return -ENOMEM;}host->fb_info = fb_info;fb_info->par = host;//以下为从设备树中获取硬件信息到info中ret = devm_request_irq(&pdev->dev, irq, mxsfb_irq_handler, 0,dev_name(&pdev->dev), host);if (ret) {dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",irq, ret);ret = -ENODEV;goto fb_release;}host->base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(host->base)) {dev_err(&pdev->dev, "ioremap failed\n");ret = PTR_ERR(host->base);goto fb_release;}host->pdev = pdev;platform_set_drvdata(pdev, host);host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];host->clk_pix = devm_clk_get(&host->pdev->dev, "pix");if (IS_ERR(host->clk_pix)) {host->clk_pix = NULL;ret = PTR_ERR(host->clk_pix);goto fb_release;}host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");if (IS_ERR(host->clk_axi)) {host->clk_axi = NULL;ret = PTR_ERR(host->clk_axi);goto fb_release;}host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");if (IS_ERR(host->clk_disp_axi)) {host->clk_disp_axi = NULL;ret = PTR_ERR(host->clk_disp_axi);goto fb_release;}host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");if (IS_ERR(host->reg_lcd))host->reg_lcd = NULL;fb_info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16,GFP_KERNEL);if (!fb_info->pseudo_palette) {ret = -ENOMEM;goto fb_release;}INIT_LIST_HEAD(&fb_info->modelist);pm_runtime_enable(&host->pdev->dev);//将fbinfo进一步初始化(包含了info中fobs的初始化)ret = mxsfb_init_fbinfo(host);//重要if (ret != 0)goto fb_pm_runtime_disable;mxsfb_dispdrv_init(pdev, fb_info);if (!host->dispdrv) {pinctrl = devm_pinctrl_get_select_default(&pdev->dev);if (IS_ERR(pinctrl)) {ret = PTR_ERR(pinctrl);goto fb_pm_runtime_disable;}}if (!host->enabled) {writel(0, host->base + LCDC_CTRL);mxsfb_set_par(fb_info);mxsfb_enable_controller(fb_info);pm_runtime_get_sync(&host->pdev->dev);}//注册deviceret = register_framebuffer(fb_info);//重要if (ret != 0) {dev_err(&pdev->dev, "Failed to register framebuffer\n");goto fb_destroy;}console_lock();ret = fb_blank(fb_info, FB_BLANK_UNBLANK);console_unlock();if (ret < 0) {dev_err(&pdev->dev, "Failed to unblank framebuffer\n");goto fb_unregister;}dev_info(&pdev->dev, "initialized\n");return 0;................
}

进一步初始化info

mxsfb_init_fbinfo:

static int mxsfb_init_fbinfo(struct mxsfb_info *host)
{struct fb_info *fb_info = host->fb_info;struct fb_var_screeninfo *var = &fb_info->var;struct fb_modelist *modelist;int ret;fb_info->fbops = &mxsfb_ops;fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;fb_info->fix.type = FB_TYPE_PACKED_PIXELS;fb_info->fix.ypanstep = 1;fb_info->fix.ywrapstep = 1;fb_info->fix.visual = FB_VISUAL_TRUECOLOR,fb_info->fix.accel = FB_ACCEL_NONE;ret = mxsfb_init_fbinfo_dt(host);..........
}

mxsfb_ops:是在platform中实现的

static struct fb_ops mxsfb_ops = {.owner = THIS_MODULE,.fb_check_var = mxsfb_check_var,.fb_set_par = mxsfb_set_par,.fb_setcolreg = mxsfb_setcolreg,.fb_ioctl = mxsfb_ioctl,.fb_blank = mxsfb_blank,.fb_pan_display = mxsfb_pan_display,.fb_mmap = mxsfb_mmap,.fb_fillrect = cfb_fillrect,.fb_copyarea = cfb_copyarea,.fb_imageblit = cfb_imageblit,
};

register_framebuffer在核心层定义:注册device

int
register_framebuffer(struct fb_info *fb_info)
{int ret;mutex_lock(&registration_lock);ret = do_register_framebuffer(fb_info);mutex_unlock(&registration_lock);return ret;
}

注册device

do_register_framebuffer:

static int do_register_framebuffer(struct fb_info *fb_info)
{int i, ret;struct fb_event event;struct fb_videomode mode;if (fb_check_foreignness(fb_info))return -ENOSYS;ret = do_remove_conflicting_framebuffers(fb_info->apertures,fb_info->fix.id,fb_is_primary_device(fb_info));if (ret)return ret;if (num_registered_fb == FB_MAX)return -ENXIO;num_registered_fb++;for (i = 0 ; i < FB_MAX; i++)if (!registered_fb[i])break;fb_info->node = i;atomic_set(&fb_info->count, 1);mutex_init(&fb_info->lock);mutex_init(&fb_info->mm_lock);fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), NULL, "fb%d", i);//注册了device,名字为fbx............
}

硬件部分:

先看一下原理图:

主要看24个data接口(RGB888)和4个ctrl接口。

数据接口为R0-7 G0-7 B0-7

控制接口为:

​ LCD_DE 使能

​ LCD_PCLK 像素时钟

​ LCD_HSYNC 行同步信号,当此信号有效的话就表示开始显示新的一行数据

​ LCD_VSYNC 帧同步信号,当此信号有效的话就表示开始显示新的一帧数据

而这些接口将通过elcdif接口与IC进行通信。所以我们必须配置板子上的elcdif接口。

查看设备树

先看imx6ull.dtsi

1010             lcdif: lcdif@021c8000 {
1011                 compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";
1012                 reg = <0x021c8000 0x4000>;
1013                 interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
1014                 clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
1015                      <&clks IMX6UL_CLK_LCDIF_APB>,
1016                      <&clks IMX6UL_CLK_DUMMY>;
1017                 clock-names = "pix", "axi", "disp_axi";
1018                 status = "disabled";
1019             };

存在lcdif,但是由于没有display节点很明显需要在自己的dts下添加。(不会?查看Document)

\linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek\Documentation\devicetree\bindings\video\fsl,imx-fd.txt

Freescale imx21 Framebuffer
This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
Required properties:
- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
- reg : Should contain 1 register ranges(address and length)
- interrupts : One interrupt of the fb dev
Required nodes:
- display: Phandle to a display node as described in Documentation/devicetree/bindings/video/display-timing.txtAdditional, the display node has to define properties:- bits-per-pixel: Bits per pixel- fsl,pcr: LCDC PCR value
Optional properties:
- lcd-supply: Regulator for LCD supply voltage.
- fsl,dmacr: DMA Control Register value. This is optional. By default, the register is not modified as recommended by the datasheet.
- fsl,lpccr: Contrast Control Register value. This property provides the default value for the contrast control register.If that property is omitted, the register is zeroed.
- fsl,lscr1: LCDC Sharp Configuration Register value.
Example:imxfb: fb@10021000 { compatible = "fsl,imx21-fb";interrupts = <61>;reg = <0x10021000 0x1000>;display = <&display0>; };...display0: display0 { model = "Primeview-PD050VL1";native-mode = <&timing_disp0>;bits-per-pixel = <16>;fsl,pcr = <0xf0c88080>; /* non-standard but required */display-timings { timing_disp0: 640x480 { hactive = <640>;vactive = <480>;hback-porch = <112>;hfront-porch = <36>;hsync-len = <32>;vback-porch = <33>;vfront-porch = <33>;vsync-len = <2>;clock-frequency = <25000000>; }; }; };

\linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek\Documentation\devicetree\bindings\video\display-timing.txt

display-timing bindings =======================
display-timings node
--------------------
required properties:- none
optional properties:- native-mode: The native mode for the display, in case multiple modes are provided. When omitted, assume the first node is the native.
timing subnode
--------------
required properties:- hactive, vactive: display resolution- hfront-porch, hback-porch, hsync-len: horizontal display timing parameters in pixelsvfront-porch, vback-porch, vsync-len: vertical display timing parameters in lines- clock-frequency: display clock in Hz
optional properties:- hsync-active: hsync pulse is active low/high/ignored- vsync-active: vsync pulse is active low/high/ignored- de-active: data-enable pulse is active low/high/ignored- pixelclk-active: with- active high = drive pixel data on rising edge/ sample data on falling edge- active low  = drive pixel data on falling edge/ sample data on rising edge- ignored     = ignored- interlaced (bool): boolean to enable interlaced mode- doublescan (bool): boolean to enable doublescan mode- doubleclk (bool): boolean to enable doubleclock mode
All the optional properties that are not bool follow the following logic: <1>: high active<0>: low activeomitted: not used on hardware
There are different ways of describing the capabilities of a display. The devicetree representation corresponds to the one commonly found in datasheets for displays. If a display supports multiple signal timings, the native-mode can be specified.
The parameters are defined as:+----------+-------------------------------------+----------+-------+ |          |        ↑                            |          |       | |          |        |vback_porch                 |          |       ||          |        ↓                            |          |       | +----------#######################################----------+-------+|          #        ↑                            #          |       | |          #        |                            #          |       ||  hback   #        |                            #  hfront  | hsync | |   porch  #        |       hactive              #  porch   |  len  | |<-------->#<-------+--------------------------->#<-------->|<----->||          #        |                            #          |       | |          #        |vactive                     #          |       ||          #        |                            #          |       | |          #        ↓                            #          |       | +----------#######################################----------+-------+|          |        ↑                            |          |       | |          |        |vfront_porch                |          |       ||          |        ↓                            |          |       | +----------+-------------------------------------+----------+-------+|          |        ↑                            |          |       | |          |        |vsync_len                   |          |       ||          |        ↓                            |          |       | +----------+-------------------------------------+----------+-------+
Example:display-timings { native-mode = <&timing0>;timing0: 1080p24 { /* 1920x1080p24 */clock-frequency = <52000000>;hactive = <1920>;vactive = <1080>;hfront-porch = <25>;hback-porch = <25>;hsync-len = <25>;vback-porch = <2>;vfront-porch = <2>;vsync-len = <2>;hsync-active = <1>; }; };
Every required property also supports the use of ranges, so the commonly used datasheet description with minimum, typical and maximum values can be used.
Example:timing1: timing { /* 1920x1080p24 */clock-frequency = <148500000>;hactive = <1920>;vactive = <1080>;hsync-len = <0 44 60>;hfront-porch = <80 88 95>;hback-porch = <100 148 160>;vfront-porch = <0 4 6>;vback-porch = <0 36 50>;vsync-len = <0 5 6>; };

所以我们在自己设备树下要添加的节点:

1 &lcdif {2   pinctrl-names = "default";
3   pinctrl-0 = <&pinctrl_lcdif_dat /* 使用到的 IO */
4               &pinctrl_lcdif_ctrl>;
6   display = <&display0>;
7   status = "okay";
8
9   display0: display { /* LCD 属性信息 */
10      bits-per-pixel = <24>; /* 一个像素占用几个 bit */
11      bus-width = <24>; /* 总线宽度 */
12
13      display-timings {14          native-mode = <&timing0>; /* 时序信息 */
15          timing0: timing0 {
16              clock-frequency = <9200000>; /* LCD 像素时钟,单位 Hz */
17              hactive = <480>; /* LCD X 轴像素个数 */
18              vactive = <272>; /* LCD Y 轴像素个数 */
19              hfront-porch = <8>; /* LCD hfp 参数 */
20              hback-porch = <4>; /* LCD hbp 参数 */
21              hsync-len = <41>; /* LCD hspw 参数 */
22              vback-porch = <2>; /* LCD vbp 参数 */
23              vfront-porch = <4>; /* LCD vfp 参数 */
24              vsync-len = <10>; /* LCD vspw 参数 */
25
26              hsync-active = <0>; /* hsync 数据线极性 */
27              vsync-active = <0>; /* vsync 数据线极性 */
28              de-active = <1>; /* de 数据线极性 */
29              pixelclk-active = <0>; /* clk 数据线先极性 */
30          };
31      };
32  };
33 };

其中pinctrl节点:

        pinctrl_lcdif_dat: lcdifdatgrp {fsl,pins = <MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x79MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x79MX6UL_PAD_LCD_DATA18__LCDIF_DATA18  0x79MX6UL_PAD_LCD_DATA19__LCDIF_DATA19  0x79MX6UL_PAD_LCD_DATA20__LCDIF_DATA20  0x79MX6UL_PAD_LCD_DATA21__LCDIF_DATA21  0x79MX6UL_PAD_LCD_DATA22__LCDIF_DATA22  0x79MX6UL_PAD_LCD_DATA23__LCDIF_DATA23  0x79>;};pinctrl_lcdif_ctrl: lcdifctrlgrp {fsl,pins = <MX6UL_PAD_LCD_CLK__LCDIF_CLK        0x79MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79>;};

接下来我们主要分析硬件部分(也就是platform的probe到底获取哪些硬件信息,我们好编写设备树文件)

再次贴上probe

static int mxsfb_probe(struct platform_device *pdev)
{const struct of_device_id *of_id =of_match_device(mxsfb_dt_ids, &pdev->dev);struct resource *res;struct mxsfb_info *host;struct fb_info *fb_info;struct pinctrl *pinctrl;int irq = platform_get_irq(pdev, 0);//1.获取了中断号int gpio, ret;if (of_id)pdev->id_entry = of_id->data;gpio = of_get_named_gpio(pdev->dev.of_node, "enable-gpio", 0);//2.获取了gpio节点if (gpio == -EPROBE_DEFER)return -EPROBE_DEFER;if (gpio_is_valid(gpio)) {ret = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_OUT_INIT_LOW, "lcd_pwr_en");if (ret) {dev_err(&pdev->dev, "faild to request gpio %d, ret = %d\n", gpio, ret);return ret;}}res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) {dev_err(&pdev->dev, "Cannot get memory IO resource\n");return -ENODEV;}host = devm_kzalloc(&pdev->dev, sizeof(struct mxsfb_info), GFP_KERNEL);if (!host) {dev_err(&pdev->dev, "Failed to allocate IO resource\n");return -ENOMEM;}fb_info = framebuffer_alloc(sizeof(struct fb_info), &pdev->dev);if (!fb_info) {dev_err(&pdev->dev, "Failed to allocate fbdev\n");devm_kfree(&pdev->dev, host);return -ENOMEM;}host->fb_info = fb_info;fb_info->par = host;ret = devm_request_irq(&pdev->dev, irq, mxsfb_irq_handler, 0,dev_name(&pdev->dev), host);if (ret) {dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",irq, ret);ret = -ENODEV;goto fb_release;}host->base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(host->base)) {dev_err(&pdev->dev, "ioremap failed\n");ret = PTR_ERR(host->base);goto fb_release;}host->pdev = pdev;platform_set_drvdata(pdev, host);host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];host->clk_pix = devm_clk_get(&host->pdev->dev, "pix");if (IS_ERR(host->clk_pix)) {host->clk_pix = NULL;ret = PTR_ERR(host->clk_pix);goto fb_release;}host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");if (IS_ERR(host->clk_axi)) {host->clk_axi = NULL;ret = PTR_ERR(host->clk_axi);goto fb_release;}host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");if (IS_ERR(host->clk_disp_axi)) {host->clk_disp_axi = NULL;ret = PTR_ERR(host->clk_disp_axi);goto fb_release;}host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");if (IS_ERR(host->reg_lcd))host->reg_lcd = NULL;fb_info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16,GFP_KERNEL);if (!fb_info->pseudo_palette) {ret = -ENOMEM;goto fb_release;}INIT_LIST_HEAD(&fb_info->modelist);pm_runtime_enable(&host->pdev->dev);ret = mxsfb_init_fbinfo(host);if (ret != 0)goto fb_pm_runtime_disable;mxsfb_dispdrv_init(pdev, fb_info);if (!host->dispdrv) {pinctrl = devm_pinctrl_get_select_default(&pdev->dev);if (IS_ERR(pinctrl)) {ret = PTR_ERR(pinctrl);goto fb_pm_runtime_disable;}}if (!host->enabled) {writel(0, host->base + LCDC_CTRL);mxsfb_set_par(fb_info);mxsfb_enable_controller(fb_info);pm_runtime_get_sync(&host->pdev->dev);}ret = register_framebuffer(fb_info);if (ret != 0) {dev_err(&pdev->dev, "Failed to register framebuffer\n");goto fb_destroy;}console_lock();ret = fb_blank(fb_info, FB_BLANK_UNBLANK);console_unlock();if (ret < 0) {dev_err(&pdev->dev, "Failed to unblank framebuffer\n");goto fb_unregister;}dev_info(&pdev->dev, "initialized\n");return 0;.....
}

此外我们通过原理图可以看到elcdif还有一个pwm接口,这是用于配置背光的,我们也要添加设备树节点。由于这涉及pwm驱动,我们不展开讲。


补充:关于pwm背光

linux中有单纯的pwm驱动的框架,它主要是用于一个端口输出pwm波形,并在sysfs上利用属性文件提供接口供用户修改pwm属性。

而有关一些外设上的pwm驱动,则是完全不同的驱动框架。比如我们的lcd背光pwm。

由于这个驱动也是厂商写好的,我们看如何配置设备树即可。

参考:Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt

 backlight { compatible = "pwm-backlight";pwms = <&pwm1 0 5000000>;brightness-levels = <0 4 8 16 32 64 128 255>;default-brightness-level = <7>;status = "okay"};
解释:
pwms:pwms 属性指定背光所使用的 pwm 通道,第一个参数指定使用 pwm1,由于I.MX6ULL 的 PWM 只有一个通道,因此这里为 0。最后一个参数是 PWM 周期,单位为 ns,这里 PWM 周期为 5000000ns,频率为 200Hz。
brightness-levels:背光等级数组,一共 8 个等级,索引编号从 0 到 7。
default-brightness-level:背光默认处于第 7 等级,也就是 255,为 100%占空比。

o(&pdev->dev, “initialized\n”);

return 0;
.....

}


此外我们通过原理图可以看到elcdif还有一个pwm接口,这是用于配置背光的,我们也要添加设备树节点。由于这涉及pwm驱动,我们不展开讲。-----#### 补充:关于pwm背光linux中有单纯的pwm驱动的框架,它主要是用于一个端口输出pwm波形,并在sysfs上利用属性文件提供接口供用户修改pwm属性。而有关一些外设上的pwm驱动,则是完全不同的驱动框架。比如我们的lcd背光pwm。由于这个驱动也是厂商写好的,我们看如何配置设备树即可。参考:Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
backlight { compatible = "pwm-backlight";pwms = <&pwm1 0 5000000>;brightness-levels = <0 4 8 16 32 64 128 255>;default-brightness-level = <7>;status = "okay"};

```
解释:
pwms:pwms 属性指定背光所使用的 pwm 通道,第一个参数指定使用 pwm1,由于I.MX6ULL 的 PWM 只有一个通道,因此这里为 0。最后一个参数是 PWM 周期,单位为 ns,这里 PWM 周期为 5000000ns,频率为 200Hz。
brightness-levels:背光等级数组,一共 8 个等级,索引编号从 0 到 7。
default-brightness-level:背光默认处于第 7 等级,也就是 255,为 100%占空比。
```

linux驱动之LCD驱动框架相关推荐

  1. 嵌入式Linux下彩色LCD驱动的设计与实现

    嵌入式Linux下彩色LCD驱动的设计与实现 转载 摘要:本文介绍了如何在嵌入在开发彩色LCD显示驱动的方法,并对Linux中的显示驱动程序结构和框架作一介绍. 长期以来,在常见的掌上电脑(PDA)等 ...

  2. Linux驱动之LCD驱动编写

    在Linux驱动之内核自带的S3C2440的LCD驱动分析这篇博客中已经分析了编写LCD驱动的步骤,接下来就按照这个步骤来字尝试字节编写LCD驱动.用的LCD屏幕为tft屏,每个像素点为16bit.对 ...

  3. Linux驱动之LCD驱动

    显示设备例如LCD,在Linux中用Framebuffer来表征,在/dev目录下显示设备一般表示成这样:/dev/fbX,应用程序通过访问这个设备来访问LCD,实际上应用程序通过操作显存来操作显示设 ...

  4. STM32MP157 Linux系统移植开发篇14:Linux内核RGB LCD驱动移植

    本文章为<STM32MP157 Linux系统移植开发篇>系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板).stm32mp157是ARM双核,2 ...

  5. linux驱动篇-LCD

    前言 在嵌入式行业,有很多从业者.我们工作的主旋律是拿开源代码,拿厂家代码,完成产品的功能,提升产品的性能,进而解决各种各样的问题.或者是维护一个模块或方向,一搞就是好几年. 时间长了,中年润发现我们 ...

  6. Linux下LCD驱动的详解

    看了不少人写的LCD驱动解释,看之前很懵逼,看之后还是很懵逼.都是放一大堆内核代码,我当时就想吐槽,能写就写,写不明白放一大堆代码是啥意思.后来,实在没办法,只能去看内核代码,结果,真香,原来别人放一 ...

  7. 【实战篇】模块化编程之LCD驱动框架详解

    ID:嵌入式云IOT技术圈 作者:杨源鑫 传送门:[架构篇]嵌入式编程中如何给代码的结构分层 废话不多说,理论讲太多没啥感觉,这些条条框框本质就是基于面对对象的设计模式相关的一些理论,设计模式就是前人 ...

  8. Linux下的FrameBuffer驱动框架

    一.RGB LCD经典显示器件介绍: 1.LCD屏幕的重要属性参数: ① 分辨率:也就是屏幕上的像素点的个数: ② 像素格式:即单个像素点RGB三种颜色的表达方式,包括RGB888.ARGB8888和 ...

  9. Linux LCD 驱动实验

    目录 Linux 下LCD 驱动简析 1 Framebuffer 设备 LCD 驱动简析 硬件原理图分析 LCD 驱动程序编写 运行测试 LCD 屏幕基本测试 设置LCD 作为终端控制台 LCD 背光 ...

最新文章

  1. 关于BIO | NIO | AIO的讨论
  2. 博士补贴125万,硕士70万本科21万,浙江某地人才(简直是抢人)新政!
  3. ORACLE 中dbms_stats的使用
  4. 网页加载出现没有合适的负载均衡器_终于讲清楚了,什么是负载均衡(Load balancing)...
  5. cdoj 秋实大哥搞算数
  6. iOS9 白名单问题 -canOpenURL: failed for URL: xx - error:This app is not allowed to query for scheme x...
  7. 教你玩转CSS 媒体类型
  8. 【vue2.0进阶】用axios来实现数据请求,简单易用
  9. DeepSDF : Learning Continuous Signed Distance Functions for Shape Representation
  10. android下拉分页加载,Android LoadMoreListView+SwipeRefreshLayout(分页下拉)基本结构
  11. 118页/8万字重磅(附下载)| 全球智能网联汽车产业深度报告:未来已来 掘金智能网联汽车时代【华西汽车 崔琰团队】
  12. cad里面f命令用不了_cad命令_CAD命令中 F 命令是什么作用?
  13. F(x) - NU ABO 韩中(繁)ass字幕
  14. PyG搭建GCN实现链接预测
  15. 《Python语言程序设计基础》嵩天著-第3章程序部分练习题答案
  16. 埃尔米特多项式 (Hermite Polynomials)简介(2)
  17. CSS基础(新手入门教程)
  18. 【电气安全】关于医疗专用隔离电源系统在医院配电系统中的应用
  19. Python用pyexiv2读写图片元数据(EXIF、IPTC、XMP)
  20. Linux操作系统PS命令详细 解析

热门文章

  1. 华为为什么认可这四所大学?(附微电子高校排行榜)
  2. python如何解决爬虫ip被封- - -“您操作太频繁,请稍后再访问“
  3. php 实现雪碧图制作,如何在小程序中使用雪碧图
  4. uni-app中兴趣标签选择
  5. 开发信三要素,看看你的开发信有吗?
  6. 水表自动抄表系统有什么功能
  7. [词性] 十二、介词 3 [ about ] [ after ] [ as ]
  8. “高精尖”智慧钢厂轻松打造!图扑软件数字孪生yyds
  9. hutool 解读(三)—— IO流
  10. 基于STM32设计的小说阅读器(翻页、字体切换、颜色切换、语音播报)