1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > linux驱动之LCD驱动框架

linux驱动之LCD驱动框架

时间:2019-12-17 23:50:39

相关推荐

linux驱动之LCD驱动框架

软件框架:

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 __initfbmem_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 pat_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 intfb_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);#endifout:mutex_unlock(&info->lock);if (res)put_fb_info(info);return res;}

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

看一些这个结构体:

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_RUNNING0#define FBINFO_STATE_SUSPENDED1u32 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

intregister_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 FramebufferThis 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 devRequired 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 valueOptional 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:- noneoptional 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 Hzoptional 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 modeAll the optional properties that are not bool follow the following logic: <1>: high active<0>: low activeomitted: not used on hardwareThere 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>; /* 总线宽度 */1213 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 参数 */2526 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%占空比。```

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。