6

Linux内核LCD驱动分析与换屏方法(Tiny4412)

 2 years ago
source link: https://blog.51cto.com/u_11822586/5557908
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

​Linux内核中换屏技术​

21.5.1 u-boot中的参数bootargs实现换屏​

在uboot中有一个 bootargs环境变量,这个参数就是传递数据给内核的。​

对tiny4412提供的内核,可以通过修改 bootargs 实现驱动不同的LCD屏。​

21.5.2 分析bootargs中的lcd参数

再启动uboot的时候会有如下的环境参数:​

bootargs=noinitrd root=/dev/nfs nfsroot=192.168.10.106:/home/xyd/rootfs/​

ip=192.168.10.123:192.168.10.106:192.168.10.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0 coherent_pool=2M lcd=S702​

每个参数之间都是空格分开。​

可以看到上面传递了2,启动内核之后就可以驱动S702屏。​

在内核启动阶段,内核会根据lcd=S720这个信息,在注册平台设备/驱动前把LCD平台数据修改了。​

21.5.3 分析在注册平台设备/驱动前修改lcd平台数据过程

首先从板级文件Mach-tiny4412.c中开始看。在这个文件中我们会看到一个机器初始化函数。​

(1) 机器初始化函数中多平台设备注册代码段

代码段如下,在02299行可以看到:​

static void __init smdk4x12_machine_init(void)​

//注册多平台设备

platform_add_devices(smdk4x12_devices, //包含LCD平台设备结构指针​

ARRAY_SIZE(smdk4x12_devices));//数组元素个数,即平台设备个数​

注册平台设备函数原型:​

int platform_add_devices(struct platform_device **devs, int num)

LCD平台设备层结构指针就是存放在 smdk4x12_devices的,以上函数注册包含LCD平台设备。所以,我们可以推出修改平台数据的地方应该在 platform_add_devices 函数前。​

问题:在哪里修改lcd平台数据?

在platform_add_devices之前,有和lcd相关代码,下面的调用是在有触摸屏的时候才调用。我们只是把它作为例子来找到能识别s702屏的地方。​

后边会讲到真正调用识别S702屏的地方。​

代码如下:​

static void __init smdk4x12_machine_init(void)​

#ifdef CONFIG_TOUCHSCREEN_FT5X0X//配置FT5X0X触摸屏的宏​

struct s3cfb_lcd *lcd = tiny4412_get_lcd();​

ft5x0x_pdata.screen_max_x = lcd->width;​

ft5x0x_pdata.screen_max_y = lcd->height;​

#endif​

platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices));​

其实真正的获得lcd参数结构是在tiny4412_fb_init_pdata函数里边调用,后面会有分析。

问题:现在我们分析如何通过bootargc传参获得lcd平台数据?

(2)机器初始化函数中调用一个和lcd相关的tiny4412_get_lcd函数

SI里边调转,此函数在Tiny4412-lcds.c (linux-3.5\arch\arm\mach-exynos)文件下。​

代码如下:​

struct s3cfb_lcd *tiny4412_get_lcd(void)​

return tiny4412_lcd_config[lcd_idx].lcd;​

这个函数只返回一个数组元素,此数组定义和初始化如下:​

在文件Tiny4412-lcds.c (linux-3.5\arch\arm\mach-exynos) 中。​

代码如下:是一个结构体数组。​

static struct {​

char *name;​

struct s3cfb_lcd *lcd;​

int ctp;​

} tiny4412_lcd_config[] = {​

{ "HD700",&wxga_hd700, 1 },​

{ "S70",&wvga_s70, 1 },​

{ "S702",&wvga_s70, 3 },​

{ "W50",&wvga_w50, 0 },​

{ "W101",&wsvga_w101, 1 },​

{ "A97",&xga_a97, 0 },​

{ "LQ150",&xga_lq150, 1 },​

{ "L80",&vga_l80, 1 },​

{ "HD101",&wxga_hd101, 1 },​

{ "BP101",&wxga_bp101, 1 },​

{ "HDM",&hdmi_def, 0 },/* Pls keep it at last */​

所以我们就要关注lcd_idx值,在哪里设置这个值。​

SI跳转得到如下:​

static int lcd_idx = 0; //在本文件中定义为静态变量​

(3) 在哪里得到lcd_idx的值

我们采用搜索的方式查找lcd_idx,可以找到以下:​

Tiny4412-lcds.c (arch\arm\mach-exynos):lcd_idx = i;​

进入查看搜索语句所在代码:​

static int __inittiny4412_setup_lcd(char *str)​

int i;​

/* 这里想通过名字查找对应的lcd配置参数,返回下标号lcd_idx */​

for (i = 0; i < ARRAY_SIZE(tiny4412_lcd_config); i++) {​

if (!strcascmp(tiny4412_lcd_config[i].name, str)) {​

lcd_idx = i; ​

break;​

__ret:​

printk("TINY4412: %s selected\n", tiny4412_lcd_config[lcd_idx].name);​

return 0;​

这个是static静态函数,在本文件中有效。​

这里我们可以知道tiny4412_lcd_config是一个数组,它就是存放所有支持的LCD屏信息。 通过比较数组成员nametiny4412_setup_lcd参数str决定lcd_idx的值。​

到这里就有疑问了:tiny4412_setup_lcd在哪里被调用?​

(4)补充知识:字符串比较函数。

int strcasecmp(const char *s1, const char *s2)​

int c1, c2;​

c1 = tolower(*s1++); //转换小写​

c2 = tolower(*s2++); //转换小写​

} while (c1 == c2 && c1 != 0);​

return c1 - c2;​

这个函数是不区分大小写比较​

21.5.4 几个重要结构

(1)结构定义即初始化

这个结构体是当前板子所支持的lcd屏列表。​

/* 定义lcd屏支持列表 */​

static struct {​

char *name;​

struct s3cfb_lcd *lcd;​

int ctp;​

} tiny4412_lcd_config[] = {​

{ "HD700",&wxga_hd700, 1 },​

{ "S70",&wvga_s70, 1 },//我们当前板子上所使用的屏​

{ "W50",&wvga_w50, 0 },​

{ "W101",&wsvga_w101, 1 },​

{ "A97",&xga_a97, 0 },​

{ "HDM",&hdmi_def, 0 },/* Pls keep it at last */​

里边struct s3cfb_lcd *lcd;结构成员是存放lcd屏的工作时序参数。​

(2)结构体定义

如下:这个结构已经包含LCD驱动所需要的平台数据信息。​

* @width:horizontal resolution---水平分辨率​

* @height:vertical resolution---垂直分辨率​

* @p_width:width of lcd in mm---屏物理尺寸(宽,mm单位)​

* @p_height:height of lcd in mm---屏物理尺寸(高,mm单位)​

* @bpp:bits per pixel​

* @freq:vframe frequency---刷屏频率​

* @timing:timing values--时序参数​

* @polarity:polarity settings---极性参数​

struct s3cfb_lcd {​

intwidth;​

intheight;​

intp_width; ​

intp_height;​

intbpp;​

intfreq;​

structs3cfb_lcd_timing timing;​

structs3cfb_lcd_polarity polarity;​

(3) s3cfb_lcd_timing屏的时序参数结构

* @h_fp:horizontal front porch​

* @h_bp:horizontal back porch​

* @h_sw:horizontal sync width​

* @v_fp:vertical front porch​

* @v_fpe:vertical front porch for even field​

* @v_bp:vertical back porch​

* @v_bpe:vertical back porch for even field​

struct s3cfb_lcd_timing {​

inth_fp;​

inth_bp;​

inth_sw;​

intv_fp;​

intv_fpe;​

intv_bp;​

intv_bpe;​

intv_sw;​

(4)屏的时序极性配置

* @rise_vclk:if 1, video data is fetched at rising edge​

* @inv_hsync:if HSYNC polarity is inversed​

* @inv_vsync:if VSYNC polarity is inversed​

* @inv_vden:if VDEN polarity is inversed​

struct s3cfb_lcd_polarity {​

intrise_vclk;​

intinv_hsync;​

intinv_vsync;​

intinv_vden;​

21.5.5 以bootargc传入lcd=S70为例子填充s3cfb_lcd结构

定义struct s3cfb_lcd结构变量wvga_s70 ,并初始化屏参数;​

在文件Tiny4412-lcds.c (arch\arm\Mach-exynos)下实现。​

//以下信息是根据LCD屏的手册得到的​

static struct s3cfb_lcdwvga_s70= {​

.width = 800,​

.height = 480,​

.p_width = 155,​

.p_height = 93,​

.bpp = 24,​

.freq = 63,​

.timing = {//屏的时序参数结构​

.h_fp = 80,​

.h_bp = 36,​

.h_sw = 10,​

.v_fp = 22,​

.v_fpe = 1,​

.v_bp = 15, ​

.v_bpe = 1,​

.v_sw = 8,​

.polarity = {//屏的时序极性结构​

.rise_vclk = 1,​

.inv_hsync = 1,​

.inv_vsync = 1,​

.inv_vden = 0,​

21.5.6 确定是谁使用 tiny4412_setup_lcd(char *str),str是否是"s70"

通过搜索tiny4412_setup_lcd的方式,在本文件中可以找到使用处:​

Linux内核LCD驱动分析与换屏方法(Tiny4412)_初始化

我们可以知道是被early_param调用:​

early_param("lcd", tiny4412_setup_lcd);​

early_param这个宏是内核用来在系统启动初期需要解析的参数。​

上面的语句,系统启动初期会判断在bootargc环境变量中有”lcd”这个字符串;​

如果有则把lcd =的值作为 tiny4412_setup_lcd函数的参数;​

然后调用执行tiny4412_setup_lcd函数。​

补充知识:early_param宏​

/* early_param用于注册内核选项解析的处理函数 */

#define early_param(str, fn) \​

__setup_param(str, fn, fn, 1)​

str:参数名,就是bootargs 参数传递进来的参数对左边的字符串。​

fn:处理函数,原型是 int XXX(char *s); 这个函数的参数是就 str=后面的字符串​

示例:​

…… lcd=s70​

就是作为传递给处理函数fn。​

经过上面的分析已经知道 struct s3cfb_lcd *tiny4412_get_lcd(void) 返回屏的时序参数结构。​

之前说真正调用tiny4412_get_lcd是:

smdk4x12_machine_init调用tiny4412_fb_init_pdata;

tiny4412_fb_init_pdata里边调用了tiny4412_get_lcd。

所以,就要知道哪里使用了tiny4412_get_lcd(void)返回的s3cfb_lcd *结构指针

21.5.7 真正调用了tiny4412_get_lcd(void),并使用返回Lcd结构指针修改屏的参数结构

在机器初始化函数中往下看,调用了一个tiny4412_fb_init_pdata函数,该函数参数就是LCD驱动数据结构指针。​

真正的用意是修改函数参数,就是修改LCD驱动数据结构指针(smdk4x12_lcd0_pdata)里边的数据,实现这个LCD驱动数据结构(smdk4x12_lcd0_pdata)填充的是s70的参数数据。

代码如下:​

static void __init smdk4x12_machine_init(void)​

samsung_bl_set(&smdk4x12_bl_gpio_info, &smdk4x12_bl_data);​

//调用下面函数,其中有部分代码修改了smdk4x12_lcd0_pdata结构的数据。

tiny4412_fb_init_pdata(&smdk4x12_lcd0_pdata);​

s5p_fimd0_set_platdata(&smdk4x12_lcd0_pdata);​

platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices));​

先分析tiny4412_fb_init_pdata送进来的参数smdk4x12_lcd0_pdata是什么?

static struct s3c_fb_platdata smdk4x12_lcd0_pdata __initdata = {​

.win[0]= &smdk4x12_fb_win0,​

.win[1]= &smdk4x12_fb_win1,​

.win[2]= &smdk4x12_fb_win2,​

.win[3]= &smdk4x12_fb_win3,​

.win[4]= &smdk4x12_fb_win4,​

.vtiming= &smdk4x12_lcd_timing,​

.vidcon0= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,​

.vidcon1= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,​

.setup_gpio= exynos4_fimd0_gpio_setup_24bpp,​

struct s3c_fb_platdata结构原型:

struct s3c_fb_platdata {​

void(*setup_gpio)(void);​

struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN];​

struct fb_videomode *vtiming;​

u32 vidcon0;​

u32 vidcon1;​

};

以上结构填充的一些默认数据在调用tiny4412_fb_init_pdata函数之后会被改掉,修改成s70屏的参数数据。

再分析tiny4412_fb_init_pdata函数的实现:​

这个函数实现在Mach-tiny4412.c (linux-3.5\arch\arm\mach-exynos)中。​

该函数中把struct s3c_fb_platdata * smdk4x12_lcd0_pdata结构中的的数据设置到s3c_fb_pd_win窗口结构fb_videomode结构里边去

代码如下:​

static void __init tiny4412_fb_init_pdata(struct s3c_fb_platdata *pd)​

struct s3cfb_lcd *lcd;​

struct s3c_fb_pd_win *win;​

//把送进来的结构vtiming赋值

struct fb_videomode *mode = pd->vtiming;

unsigned long val = 0;​

u64 pixclk = 1000000000000ULL;​

u32 div;​

int i;​

/* 真的调用tiny4412_get_lcd,获取s70 lcd屏参数,​

这个lcd屏参数是通过命令行传递lcd屏型号来找到具体是哪一个参数的 */​

lcd = tiny4412_get_lcd();

/* 设置(修改)smdk4x12_lcd0_pdata结构中每个lcd窗口的参数 */

for (i = 0; i < S3C_FB_MAX_WIN; i++) {​

/* 过滤空的lcd窗口结构 */​

if (pd->win[i] == NULL)​

continue;​

/* 把lcd参数设置到s3c_fb_pd_win窗口结构中 */

//送进来的结构窗口赋值,修改其中的参数

win = pd->win[i]; ​

win->xres = lcd->width;​

win->yres = lcd->height;​

win->default_bpp = lcd->bpp ? : 24;​

win->virtual_x = win->xres;​

win->virtual_y = win->yres * CONFIG_FB_S3C_NR_BUFFERS;​

win->width = lcd->p_width;​

win->height = lcd->p_height;​

/* 把屏的时序设置到fb_videomode结构中,lcd注册需要使用到 */

mode->left_margin = lcd->timing.h_bp;​

mode->right_margin = lcd->timing.h_fp;​

mode->upper_margin = lcd->timing.v_bp;​

mode->lower_margin = lcd->timing.v_fp;​

mode->hsync_len = lcd->timing.h_sw;​

mode->vsync_len = lcd->timing.v_sw;​

mode->xres = lcd->width;​

mode->yres = lcd->height;​

/* calculates pixel clock */​

div = mode->left_margin + mode->hsync_len + mode->right_margin +​

mode->xres;​

div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +​

mode->yres;​

/*如果没有自定义频率,则设置为60Hz*/​

div *= lcd->freq ? : 60; ​

do_div(pixclk, div); ​

mode->pixclock = pixclk + 386;//386​

/* initialize signal polarity of RGB interface */​

if (lcd->polarity.rise_vclk)​

val |= VIDCON1_INV_VCLK;​

if (lcd->polarity.inv_hsync)​

val |= VIDCON1_INV_HSYNC;​

if (lcd->polarity.inv_vsync)​

val |= VIDCON1_INV_VSYNC;​

if (lcd->polarity.inv_vden)​

val |= VIDCON1_INV_VDEN;​

//修改vidcon1的值

pd->vidcon1 = val;​

到这里我们需要知道:在平台设备和驱动注册前修改lcd平台数据设置完成。​

21.5.8 补充知识:tiny4412_fb_init_pdata涉及到几个结构。

1、屏窗口结构

struct s3c_fb_pd_win {​

unsigned shortdefault_bpp;​

unsigned shortmax_bpp;​

unsigned shortxres;​

unsigned shortyres;​

unsigned shortvirtual_x;​

unsigned shortvirtual_y;​

unsigned shortwidth;​

unsigned shortheight;​

2、屏的工作时序模式结构

struct fb_videomode {​

const char *name;/* optional */​

u32 refresh;/* optional */​

u32 xres;​

u32 yres;​

u32 pixclock;​

u32 left_margin;​

u32 right_margin;​

u32 upper_margin;​

u32 lower_margin;​

u32 hsync_len;​

u32 vsync_len;​

u32 sync;​

u32 vmode;​

u32 flag;​

到此,S70屏的数据应经存放在smdk4x12_lcd0_pdata结构中,但是谁来用这个已经修改好的smdk4x12_lcd0_pdata屏数据结构呢?

按正常来讲应该是平台设备结构的dev结构成员里边私有数据成员。

接下来我们来找这个私有数据成员。

21.5.9 内核带的平台结构变量s5p_device_fimd0没有初始化平台数据成员

到这里我们还有还有一个问题:内核带的平台数据结构变量没有初始化平台数据成员。​

在devs.c中定义如下:​

static struct platform_device s5p_device_fimd0 = {​

.name= "s5p-fb",​

.id= 0,​

.num_resources= ARRAY_SIZE(s5p_fimd0_resource),​

.resource= s5p_fimd0_resource,​

.dev = {​

.dma_mask= &samsung_device_dma_mask,​

.coherent_dma_mask= DMA_BIT_MASK(32),​

// 此处应该初始化平台数据,但是没有。???

以上结构根据没有初始化已经修改好的平台数据。​

平台设备结构原型:​

struct platform_device {​

const char *name;​

int id;​

//这个结构里边有一个void *platform_data成员

struct device dev;​

u32 num_resources;​

struct resource*resource;​

const struct platform_device_id*id_entry;​

struct mfd_cell *mfd_cell;​

struct pdev_archdata archdata;​

在平台设备结构中成员struct device dev结构原型:​

struct device {​

struct device *parent;​

struct device_private*p;​

struct kobject kobj;​

const char *init_name; /* initial name of the device */​

const struct device_type *type;​

struct mutexmutex;/* mutex to synchronize calls toits driver*/​

struct bus_type*bus; /* type of bus device is on */​

struct device_driver *driver;/* which driver has allocated this device */​

Void *platform_data;/* Platform specific data, device​

core doesn't touch it */​

struct dev_pm_infopower;​

struct dev_pm_domain *pm_domain;​

#ifdef CONFIG_NUMA​

int numa_node;​

#endif​

u64 *dma_mask;​

u64 coherent_dma_mask;​

struct device_dma_parameters *dma_parms;​

struct list_headdma_pools;​

struct dma_coherent_mem*dma_mem; ​

#ifdef CONFIG_CMA​

struct cma *cma_area;​

#endif​

struct dev_archdataarchdata;​

struct device_node*of_node;​

dev_tdevt;​

u32 id;​

spinlock_t devres_lock;​

struct list_head devres_head;​

struct klist_node knode_class;​

struct class*class;​

const struct attribute_group **groups;​

void(*release)(struct device *dev);​

没有看到有填充私有数据,那么一定在注册s5p_device_fimd0前使用其他方法把私有数据设置进来,比如调用函数设置了平台数据。​

因除了这个结构初始化平台设备数据,没有其他的会做这个事情了。​

21.5.10 在lcd数据初始化之后,又对lcd数据进行了设置

搜索 smdk4x12_lcd0_pdata 平台数据结构变量。​

查看其他地方私有了这个数据结构。​

static void __init smdk4x12_machine_init(void)​

tiny4412_fb_init_pdata(&smdk4x12_lcd0_pdata);​

//在lcd数据初始化之后,又对lcd数据进行了设置

s5p_fimd0_set_platdata(&smdk4x12_lcd0_pdata);

platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices));​

在lcd数据初始化之后,又调用函数s5p_fimd0_set_platdata对lcd数据进行了设置(修改)。​

s5p_fimd0_set_platdata函数原型:​

void __init s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd)​

s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),&s5p_device_fimd0);​

以上的参数s5p_device_fimd0 就是lcd平台设备结构变量。​

pd :返推回去就是 smdk4x12_lcd0_pdata。​

s3c_set_platdata函数原型:​

可以知道pdev 就是 &s5p_device_fimd0。​

void __init *s3c_set_platdata(void *pd, //把平台数据结构传进来​

size_t pdsize,//平台数据结构的长度​

struct platform_device *pdev)//平台设备结构​

void *npd;​

if (!pd) {​

printk(KERN_ERR "%s: no platform data supplied\n", pdev->name);​

return NULL;​

npd = kmemdup(pd, pdsize, GFP_KERNEL);​

if (!npd) {​

printk(KERN_ERR "%s: cannot clone platform data\n", pdev->name);​

return NULL;​

pdev->dev.platform_data = npd;​

return npd;​

该函数先开辟平台数据结构(pdsize)空间,然后把 pd 数据复制到新开辟的空间,返回新的空间地址。​

kmemdup函数会开辟一个空间,然后把 pd 指向内存空间中的 pdsize 字节数量复制到新开辟的空间中,返回新开辟空间首地址。​

所以,在我们知道该函数先给smdk4x12_lcd0_pdata结构开辟空间;​

然后把smdk4x12_lcd0_pdata结构中的数据复制到这个新开辟的空间中;​

得到这个存有smdk4x12_lcd0_pdata结构数据的新空间首地址赋值给:​

s5p_device_fimd0->dev.platform_data。​

此处我们知道s5p_device_fimd0结构的dev结构私有数据就是smdk4x12_lcd0_pdata结构的首地址。​

到此,平台设备的数据都已经准备好,只等拿去注册了。

  • 小知识:​

那有时候会有同学问为什么要这样做?为什么不直接填充到平台结构的私有数据?​

出于内存使用合理性考虑。​

  1. 定义在静态存储区,则这个结构的生命周期和系统同在。​

只要系统运行着始终会存在,就算驱动模块卸载了,还存在。​

2)如果把定义堆空间中,在驱动卸载时候可以把它占用的空间释放。​

所以内核中就这样的调用kmemdup函数,在堆空间中开辟一块区域,便于释放。​

注意:平台数结构变量加了 __initdata 修饰,这块内存在启动完成后,挂接文件系统后会释放。所以,所在传递给驱动的信息,如果定义时候添加 __initdata 修饰,则需要重新开辟一个空间,把它的值复制到里面去。​

下面我通过注册时使用的smdk4x12_devices平台数据结构指针变量反推来查找注册关联。​

21.5.11 smdk4x12_devices平台数据结构指针变量定义及填充

就在Mach-tiny4412.c (linux-3.5\arch\arm\mach-exynos)文件中;​

定义了注册多平台设备用到的smdk4x12_devices平台数据结构指针变量;​

代码如下:​

static struct platform_device *smdk4x12_devices[] __initdata = {​

#ifdef CONFIG_EXYNOS4_DEV_DWMCI​

&exynos_device_dwmci,​

#endif​

&s3c_device_hsmmc2,​

&s3c_device_hsmmc3,​

&wm8994_fixed_voltage0,​

&wm8994_fixed_voltage1,​

&wm8994_fixed_voltage2,​

&s3c_device_i2c0,​

&s3c_device_i2c1,​

&s3c_device_i2c2,​

&s3c_device_i2c3,​

#ifdef CONFIG_VIDEO_M5MOLS​

&s3c_device_i2c4,​

#endif​

&s3c_device_i2c7,​

&s3c_device_adc,​

&s3c_device_rtc,​

&s3c_device_wdt,​

#ifdef CONFIG_TINY4412_BUZZER​

&s3c_device_timer[0],​

#endif​

#ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE​

&exynos_device_flite0,​

&exynos_device_flite1,​

#endif​

&s5p_device_mipi_csis0,​

&s5p_device_mipi_csis1,​

&s5p_device_fimc0,​

&s5p_device_fimc1,​

&s5p_device_fimc2,​

&s5p_device_fimc3,​

&s5p_device_fimc_md,​

&s5p_device_fimd0,//在这里把屏的平台设备结构填充进来

&mali_gpu_device,​

&s5p_device_mfc,​

&s5p_device_mfc_l,​

&s5p_device_mfc_r,​

&s5p_device_jpeg,​

#ifdef CONFIG_SAMSUNG_DEV_KEYPAD​

&samsung_device_keypad,​

#endif​

&tiny4412_device_1wire,​

&tiny4412_device_adc,​

#ifdef CONFIG_INPUT_GPIO​

&tiny4412_input_device,​

#endif​

#ifdef CONFIG_IR_GPIO_CIR​

&tiny4412_device_gpiorc,​

#endif​

#ifdef CONFIG_VIDEO_EXYNOS_FIMC_IS​

&exynos4_device_fimc_is,​

#endif​

#ifdef CONFIG_LCD_LMS501KF03​

&s3c_device_spi_gpio,​

#endif​

#ifdef CONFIG_S3C64XX_DEV_SPI0​

&s3c64xx_device_spi0,​

#endif​

#ifdef CONFIG_S3C64XX_DEV_SPI1​

&s3c64xx_device_spi1,​

#endif​

#ifdef CONFIG_S3C64XX_DEV_SPI2​

&s3c64xx_device_spi2,​

#endif​

#ifdef CONFIG_ION_EXYNOS​

&exynos_device_ion,​

#endif​

&s5p_device_i2c_hdmiphy,​

&s5p_device_hdmi,​

&s5p_device_mixer,​

&exynos4_bus_devfreq,​

&samsung_asoc_dma,​

&samsung_asoc_idma,​

#ifdef CONFIG_SND_SAMSUNG_I2S​

&exynos4_device_i2s0,​

#endif​

#ifdef CONFIG_SND_SAMSUNG_PCM​

&exynos4_device_pcm0,​

#endif​

#ifdef CONFIG_SND_SAMSUNG_SPDIF​

&exynos4_device_spdif,​

#endif​

&tiny4412_audio,​

#ifdef CONFIG_VIDEO_EXYNOS_FIMG2D​

&s5p_device_fimg2d,​

#endif​

#ifdef CONFIG_EXYNOS_THERMAL​

&exynos_device_tmu,​

#endif​

&s5p_device_ehci,​

&exynos4_device_ohci,​

&s5p_device_usbswitch,​

#if defined CONFIG_SND_SAMSUNG_ALP​

&exynos_device_srp,​

#endif​

#ifdef CONFIG_BUSFREQ_OPP​

&exynos4_busfreq,​

#endif​

#ifdef CONFIG_BATTERY_SAMSUNG​

&samsung_device_battery,​

#endif​

到此,调用注册函数就可以把屏注册进内核了。​


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK