linux设备树

您所在的位置:网站首页 linux触摸屏滑动代码 linux设备树

linux设备树

2024-07-13 02:06| 来源: 网络整理| 查看: 265

----------------------------------------------------------------------------------------------------------------------------内核版本:linux 5.2.8根文件系统:busybox 1.25.0u-boot:2016.05----------------------------------------------------------------------------------------------------------------------------

在上一节我们已经移植了LCD驱动,那么本节将会移植LCD触摸屏驱动。有关触摸屏的原理,以及硬件接线,我们在linux驱动移植-LCD触摸屏设备驱动章节已经介绍的非常清楚了。同时在这一篇博客,我们也详细介绍了触摸屏驱动的实现,并进行了代码演示。

linux 5.2.8内核已经自带了s3c2440触摸屏驱动,该驱动还依赖于ADC驱动,相当于把我们在linux驱动移植-LCD触摸屏设备驱动中写的驱动程序拆成了两个部分,但是代码整体逻辑大致是一样的。

这一节,我们将尝试引入设备树,通过设备树来实现触摸屏驱动程序。

一、触摸屏驱动

linux 5.2.8自带的s3c2440触摸屏驱动,其采用platform设备驱动模型。

1.1 platform device

名字为"s3c2410-ts"的platform device定义在arch/arm/plat-samsung/devs.c文件:

static struct resource s3c_ts_resource[] = { [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC), // 0x58000000 SZ_1M [1] = DEFINE_RES_IRQ(IRQ_TC), // IRQ_TC为子中断 子中断控制器硬件中断号9,对应的主中断控制器硬件中断号31 }; struct platform_device s3c_device_ts = { .name = "s3c2410-ts", .id = -1, .dev.parent = &s3c_device_adc.dev, .num_resources = ARRAY_SIZE(s3c_ts_resource), .resource = s3c_ts_resource, }; void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *hard_s3c2410ts_info) { s3c_set_platdata(hard_s3c2410ts_info, sizeof(struct s3c2410_ts_mach_info), &s3c_device_ts); }

其中函数s3c24xx_ts_set_platdata用于设置platform设备的私有数据,数据类型为struct s3c2410_ts_mach_info,s3c_device_ts.dev.platform_data会被设置为&default_ts_data :

static struct s3c2410_ts_mach_info default_ts_data __initdata = { .delay = 10000, .presc = 49, .oversampling_shift = 2, }; default_ts_data定义在arch/arm/plat-samsung/devs.c文件中的,我们需要把s3c_device_ts成员里初始化的这些常量数据抽离到设备树中。 1.2 platform driver

名字为"s3c2410-ts"的platform driver定义在drivers/input/touchscreen/s3c2410_ts.c文件:

static const struct dev_pm_ops s3c_ts_pmops = { .suspend = s3c2410ts_suspend, .resume = s3c2410ts_resume, }; #endif static const struct platform_device_id s3cts_driver_ids[] = { { "s3c2410-ts", 0 }, { "s3c2440-ts", 0 }, { "s3c64xx-ts", FEAT_PEN_IRQ }, { } }; MODULE_DEVICE_TABLE(platform, s3cts_driver_ids); static struct platform_driver s3c_ts_driver = { .driver = { .name = "samsung-ts", #ifdef CONFIG_PM .pm = &s3c_ts_pmops, #endif }, .id_table = s3cts_driver_ids, .probe = s3c2410ts_probe, .remove = s3c2410ts_remove, }; module_platform_driver(s3c_ts_driver); 1.3 s3c2410ts_probe

当platform设备和驱动匹配后,将会调用s3c2410ts_probe进行input设备的注册。函数定义在drivers/input/touchscreen/s3c2410_ts.c:

/** * s3c2410ts_probe - device core probe entry point * @pdev: The device we are being bound to. * * Initialise, find and allocate any resources we need to run and then * register with the ADC and input systems. */ static int s3c2410ts_probe(struct platform_device *pdev) { struct s3c2410_ts_mach_info *info; struct device *dev = &pdev->dev; struct input_dev *input_dev; struct resource *res; int ret = -EINVAL; /* Initialise input stuff */ memset(&ts, 0, sizeof(struct s3c2410ts)); ts.dev = dev; info = dev_get_platdata(dev); if (!info) { dev_err(dev, "no platform data, cannot attach\n"); return -EINVAL; } dev_dbg(dev, "initialising touchscreen\n"); ts.clock = clk_get(dev, "adc"); if (IS_ERR(ts.clock)) { dev_err(dev, "cannot get adc clock source\n"); return -ENOENT; } ret = clk_prepare_enable(ts.clock); if (ret) { dev_err(dev, "Failed! to enabled clocks\n"); goto err_clk_get; } dev_dbg(dev, "got and enabled clocks\n"); ts.irq_tc = ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "no resource for interrupt\n"); goto err_clk; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "no resource for registers\n"); ret = -ENOENT; goto err_clk; } ts.io = ioremap(res->start, resource_size(res)); if (ts.io == NULL) { dev_err(dev, "cannot map registers\n"); ret = -ENOMEM; goto err_clk; } /* inititalise the gpio */ if (info->cfg_gpio) info->cfg_gpio(to_platform_device(ts.dev)); ts.client = s3c_adc_register(pdev, s3c24xx_ts_select, s3c24xx_ts_conversion, 1); if (IS_ERR(ts.client)) { dev_err(dev, "failed to register adc client\n"); ret = PTR_ERR(ts.client); goto err_iomap; } /* Initialise registers */ if ((info->delay & 0xffff) > 0) writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); input_dev = input_allocate_device(); if (!input_dev) { dev_err(dev, "Unable to allocate the input device !!\n"); ret = -ENOMEM; goto err_iomap; } ts.input = input_dev; ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); ts.input->name = "S3C24XX TouchScreen"; ts.input->id.bustype = BUS_HOST; ts.input->id.vendor = 0xDEAD; ts.input->id.product = 0xBEEF; ts.input->id.version = 0x0102; ts.shift = info->oversampling_shift; ts.features = platform_get_device_id(pdev)->driver_data; ret = request_irq(ts.irq_tc, stylus_irq, 0, "s3c2410_ts_pen", ts.input); if (ret) { dev_err(dev, "cannot get TC interrupt\n"); goto err_inputdev; } dev_info(dev, "driver attached, registering input device\n"); /* All went ok, so register to the input system */ ret = input_register_device(ts.input); if (ret < 0) { dev_err(dev, "failed to register input device\n"); ret = -EIO; goto err_tcirq; } return 0; err_tcirq: free_irq(ts.irq_tc, ts.input); err_inputdev: input_free_device(ts.input); err_iomap: iounmap(ts.io); err_clk: clk_disable_unprepare(ts.clock); del_timer_sync(&touch_timer); err_clk_get: clk_put(ts.clock); return ret; } View Code

全局变量ts定义如下:

#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0)) #define INT_DOWN (0) #define INT_UP (1 dev; struct adc_device *adc; struct resource *regs; enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data; int ret; unsigned tmp; adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL); if (!adc) return -ENOMEM; spin_lock_init(&adc->lock); adc->pdev = pdev; adc->prescale = S3C2410_ADCCON_PRSCVL(49); adc->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(adc->vdd)) { dev_err(dev, "operating without regulator \"vdd\" .\n"); return PTR_ERR(adc->vdd); } adc->irq = platform_get_irq(pdev, 1); if (adc->irq irq, s3c_adc_irq, 0, dev_name(dev), adc); if (ret < 0) { dev_err(dev, "failed to attach adc irq\n"); return ret; } adc->clk = devm_clk_get(dev, "adc"); if (IS_ERR(adc->clk)) { dev_err(dev, "failed to get adc clock\n"); return PTR_ERR(adc->clk); } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); adc->regs = devm_ioremap_resource(dev, regs); if (IS_ERR(adc->regs)) return PTR_ERR(adc->regs); ret = regulator_enable(adc->vdd); if (ret) return ret; clk_prepare_enable(adc->clk); tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; /* Enable 12-bit ADC resolution */ if (cpu == TYPE_ADCV12) tmp |= S3C2416_ADCCON_RESSEL; if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) tmp |= S3C64XX_ADCCON_RESSEL; writel(tmp, adc->regs + S3C2410_ADCCON); dev_info(dev, "attached adc driver\n"); platform_set_drvdata(pdev, adc); adc_dev = adc; return 0; } View Code 三、修改驱动程序

由于linux 5.2.8已经自带了s3c2440触摸屏、以及ADC驱动,因此我们直接在内核源码上改造,使其支持设备树即可。

3.1 修改设备树 3.1.1 新增myts设备节点

在内核arch/arm/boot/dts/s3c2440-smdk2440.dts文件中添加myts设备节点,用于触摸屏驱动:

myts: myts@5800000 { compatible = "myts"; reg = ; reg-names = "adc_ts_physical"; interrupts = ; interrupt-names = "int_tc"; clocks = ; clock-names = "adc"; delay = ; presc = ; oversampling_shift = ; }; 3.1.2 新增myadc设备节点

在内核arch/arm/boot/dts/s3c2440-smdk2440.dts文件中添加myadc设备节点,用于ADC驱动:

myadc: myadc@5800000 { compatible = "myadc"; reg = ; reg-names = "adc_physical"; interrupts = ,; interrupt-names = "int_tc","int_adc_s"; clocks = ; clock-names = "adc"; }; 3.2 修改触摸屏驱动 3.2.1 修改s3c_ts_driver

为了支持设备树,所以我们需要修改s3c_ts_driver变量添加设备树匹配项,变量定义在arch/arm/plat-samsung/devs.c文件。修改完成后代码如下:

static const struct dev_pm_ops s3c_ts_pmops = { .suspend = s3c2410ts_suspend, .resume = s3c2410ts_resume, }; #endif static const struct of_device_id s3cts_dt_match[] = { // 用于设备树匹配 { .compatible = "myts", .data = (void *)0 }, {}, }; static const struct platform_device_id s3cts_driver_ids[] = { { "s3c2410-ts", 0 }, { "s3c2440-ts", 0 }, { "s3c64xx-ts", FEAT_PEN_IRQ }, { } }; MODULE_DEVICE_TABLE(platform, s3cts_driver_ids); static struct platform_driver s3c_ts_driver = { .driver = { .name = "samsung-ts", .of_match_table = of_match_ptr(s3cts_dt_match), #ifdef CONFIG_PM .pm = &s3c_ts_pmops, #endif }, .id_table = s3cts_driver_ids, .probe = s3c2410ts_probe, .remove = s3c2410ts_remove, }; 3.2.2  修改s3c2410ts_probe

当platform设备和驱动匹配后,将会调用s3c2410ts_probe进行input设备的注册,函数位于drivers/input/touchscreen/s3c2410_ts.c文件,修改完之后代码如下:

/** * s3c2410ts_probe - device core probe entry point * @pdev: The device we are being bound to. * * Initialise, find and allocate any resources we need to run and then * register with the ADC and input systems. */ static int s3c2410ts_probe(struct platform_device *pdev) { struct s3c2410_ts_mach_info *info; struct device *dev = &pdev->dev; struct input_dev *input_dev; struct resource *res; int ret = -EINVAL; struct device_node *np; np = dev->of_node; // 获取myts设备节点 if (!np) { dev_err(dev, "could not find device info\n"); return -EINVAL; } /* Initialise input stuff */ memset(&ts, 0, sizeof(struct s3c2410ts)); ts.dev = dev; info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); // 动态分配struct s3c2410_ts_mach_info if (!info) { dev_err(dev, "no mem for info\n"); return -ENOMEM; } // 获取设备节点中的各个属性值,用来设置驱动参数 of_property_read_u32(np, "delay", &info->delay); of_property_read_u32(np, "presc", &info->presc); of_property_read_u32(np, "oversampling_shift", &info->oversampling_shift); dev_dbg(dev, "%s: delay: 0x%lx\n", __func__, info->delay); dev_dbg(dev, "%s: presc: 0x%1x\n", __func__, info->presc); dev_dbg(dev, "%s: oversampling_shift: 0x%1x\n", __func__, info->oversampling_shift); dev_dbg(dev, "initialising touchscreen\n"); ts.clock = clk_get(dev, "adc"); // 获取adc时钟 if (IS_ERR(ts.clock)) { dev_err(dev, "cannot get adc clock source\n"); return -ENOENT; } ret = clk_prepare_enable(ts.clock); // 使能时钟 if (ret) { dev_err(dev, "Failed! to enabled clocks\n"); goto err_clk_get; } dev_dbg(dev, "got and enabled clocks\n"); ts.irq_tc = ret = platform_get_irq(pdev, 0); // 获取第一个IRQ编号 if (ret < 0) { dev_err(dev, "no resource for interrupt\n"); goto err_clk; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 获取第一个内存资源 if (!res) { dev_err(dev, "no resource for registers\n"); ret = -ENOENT; goto err_clk; } ts.io = ioremap(res->start, resource_size(res)); // 将ADC相关寄存器起始物理地址映射到虚拟地址,并返回虚拟地址 if (ts.io == NULL) { dev_err(dev, "cannot map registers\n"); ret = -ENOMEM; goto err_clk; } /* inititalise the gpio */ if (info->cfg_gpio) info->cfg_gpio(to_platform_device(ts.dev)); ts.client = s3c_adc_register(pdev, s3c24xx_ts_select, s3c24xx_ts_conversion, 1); if (IS_ERR(ts.client)) { dev_err(dev, "failed to register adc client\n"); ret = PTR_ERR(ts.client); goto err_iomap; } /* Initialise registers */ if ((info->delay & 0xffff) > 0) writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); // 设置ADC启动延时时间 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); // 设置ADCTSC 1 evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); // 支持按键事件 支持绝对位移事件 ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); // 触摸屏笔尖按下 input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); // s3c2440手册ADC是10位,所以第四个参数设置为0x3FF input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); // s3c2440手册ADC是10位,所以第四个参数设置为0x3FF ts.input->name = "S3C24XX TouchScreen"; ts.input->id.bustype = BUS_HOST; ts.input->id.vendor = 0xDEAD; ts.input->id.product = 0xBEEF; ts.input->id.version = 0x0102; ts.shift = info->oversampling_shift; //ts.features = platform_get_device_id(pdev)->driver_data; ts.features = of_device_get_match_data(&pdev->dev); // 获取私有数据 ret = request_irq(ts.irq_tc, stylus_irq, 0, // 申请中断 "s3c2410_ts_pen", ts.input); if (ret) { dev_err(dev, "cannot get TC interrupt\n"); goto err_inputdev; } dev_info(dev, "driver attached, registering input device\n"); /* All went ok, so register to the input system */ ret = input_register_device(ts.input); // 注册input_dev if (ret < 0) { dev_err(dev, "failed to register input device\n"); ret = -EIO; goto err_tcirq; } return 0; err_tcirq: free_irq(ts.irq_tc, ts.input); err_inputdev: input_free_device(ts.input); err_iomap: iounmap(ts.io); err_clk: clk_disable_unprepare(ts.clock); del_timer_sync(&touch_timer); err_clk_get: clk_put(ts.clock); return ret; }

同时需要引入头文件:

#include 3.3 修改ADC驱动 3.3.1 修改s3c_adc_driver

为了支持设备树,所以我们需要修改s3c_adc_driver变量添加设备树匹配项,变量定义在arch/arm/plat-samsung/adc.c文件。修改完成后代码如下:

static const struct of_device_id s3c_adc_dt_match[] = { // 用于设备树匹配 { .compatible = "myadc", .data = (void *)TYPE_ADCV1 }, {}, }; static const struct platform_device_id s3c_adc_driver_ids[] = { { .name = "s3c24xx-adc", .driver_data = TYPE_ADCV1, }, { .name = "s3c2443-adc", .driver_data = TYPE_ADCV11, }, { .name = "s3c2416-adc", .driver_data = TYPE_ADCV12, }, { .name = "s3c64xx-adc", .driver_data = TYPE_ADCV2, }, { .name = "samsung-adc-v3", .driver_data = TYPE_ADCV3, }, { } }; MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids); static const struct dev_pm_ops adc_pm_ops = { .suspend = s3c_adc_suspend, .resume = s3c_adc_resume, }; static struct platform_driver s3c_adc_driver = { .id_table = s3c_adc_driver_ids, .driver = { .name = "s3c-adc", .of_match_table = of_match_ptr(s3c_adc_dt_match), .pm = &adc_pm_ops, }, .probe = s3c_adc_probe, .remove = s3c_adc_remove, }; 3.3.2  修改s3c_adc_probe

当platform设备和驱动匹配后,将会调用s3c_adc_probe进行ADD相关的初始化工作。函数位于arch/arm/plat-samsung/adc.c文件,修改完之后代码如下:

static int s3c_adc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct adc_device *adc; struct resource *regs; //enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data; enum s3c_cpu_type cpu = (int)of_device_get_match_data(&pdev->dev); // 获取私有数据 int ret; unsigned tmp; adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL); if (!adc) return -ENOMEM; spin_lock_init(&adc->lock); adc->pdev = pdev; adc->prescale = S3C2410_ADCCON_PRSCVL(49); // 设置预分频器的值 (49&0xff) vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(adc->vdd)) { dev_err(dev, "operating without regulator \"vdd\" .\n"); return PTR_ERR(adc->vdd); } adc->irq = platform_get_irq(pdev, 1); // 获取第2个IRQ编号 IRQ_ADC ADC转换成功后,会进入IRQ_ADC中断函数 if (adc->irq irq, s3c_adc_irq, 0, dev_name(dev), // 申请中断 adc); if (ret < 0) { dev_err(dev, "failed to attach adc irq\n"); return ret; } adc->clk = devm_clk_get(dev, "adc"); // 获取adc时钟 if (IS_ERR(adc->clk)) { dev_err(dev, "failed to get adc clock\n"); return PTR_ERR(adc->clk); } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 获取第一个内存资源 ADC相关寄存器基地址 adc->regs = devm_ioremap_resource(dev, regs); // 将ADC相关寄存器起始物理地址映射到虚拟地址,并返回虚拟地址 if (IS_ERR(adc->regs)) return PTR_ERR(adc->regs); ret = regulator_enable(adc->vdd); if (ret) return ret; clk_prepare_enable(adc->clk); // 使能时钟 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; // 49 pdev)->driver_data;

全部修改为:

enum s3c_cpu_type cpu = (int)of_device_get_match_data(&pdev->dev); // 获取私有数据 四、烧录开发板测试 4.1 配置内核

执行如下命令:

root@zhengyang:/work/sambashare/linux-5.2.8-dt# make menuconfig

配置内核,将内核自带的触摸屏驱动编译进内核:

Device Drivers ---> Input device support --> [*] Touchscreens --> Samsung S3C2410/generic touchscreen input driver Graphics support ---> [ ] Bootup logo --->

保存文件,输入文件名s3c2440_defconfig,在当前路径下生成s3c2440_defconfig:存档:

root@zhengyang:/work/sambashare/linux-5.2.8-dt# mv s3c2440_defconfig ./arch/arm/configs/ 4.2 编译内核

此时重新执行:

root@zhengyang:/work/sambashare/linux-5.2.8-dt# make distclean root@zhengyang:/work/sambashare/linux-5.2.8-dt# make s3c2440_defconfig root@zhengyang:/work/sambashare/linux-5.2.8-dt# make uImage V=1

将uImage复制到tftp服务器路径下:、

root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/uImage /work/tftpboot/ 4.3  编译dts

在linux内核根目录执行如下命令:

root@zhengyang:/work/sambashare/linux-5.2.8-dt# make dtbs DTC arch/arm/boot/dts/s3c2416-smdk2416.dtb DTC arch/arm/boot/dts/s3c2440-smdk2440.dtb

编译设备树文件,把前面配置过的arch/arm/boot/dts里的dts文件编译成dtb文件。

将s3c2440-smdk2440.dtb复制到tftp服务器路径下:

root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts/s3c2440-smdk2440.dtb /work/tftpboot/ 4.4 启动内核

uboot启动后,将dtb下载到内存地址0x30001000中:

SMDK2440 # tftp 0x30001000 s3c2440-smdk2440.dtb

注意:我们可以修改uboot源码,扩展一个device_tree分区,然后将dtb文件存储在该分区中。

然后将内核镜像加载到内存0x30008000地址,并烧录内核到Nand Flash:

SMDK2440 # tftp 30008000 uImage SMDK2440 # nand erase.part kernel SMDK2440 # nand write 30008000 kernel

然后可以使用如下命令启动内核:

SMDK2440 # bootm 0x30008000 - 0x30001000 // 无设备树时,直接bootm 0x30008000 //bootm uImage地址 ramdisk地址 设备树镜像地址

内核启动打印有关LCD触摸屏信息如下:

.... samsung-ts 58000000.myts: no pinctrl handle OF: no dma-ranges found for node(/myts@5800000) samsung-ts 58000000.myts: device is not dma coherent samsung-ts 58000000.myts: device is not behind an iommu samsung-ts 58000000.myts: s3c2410ts_probe: delay: 0xffff samsung-ts 58000000.myts: s3c2410ts_probe: presc: 0x31 samsung-ts 58000000.myts: s3c2410ts_probe: oversampling_shift: 0x2 samsung-ts 58000000.myts: initialising touchscreen clock-names adc in index 0 samsung-ts 58000000.myts: got and enabled clocks OF: of_irq_parse_one: dev=/myts@5800000, index=0 OF: parent=/interrupt-controller@4a000000, intsize=4 OF: intspec=1 of_irq_parse_raw: /interrupt-controller@4a000000:00000001,0000001f,00000009,00000003 OF: of_irq_parse_raw: ipar=/interrupt-controller@4a000000, size=4 OF: -> addrsize=1 OF: -> got it ! samsung-ts 58000000.myts: driver attached, registering input device PM: Adding info for No Bus:input0 input: S3C24XX TouchScreen as /devices/virtual/input/input0 ....

内核启动打印有关ADC信息如下:

.... s3c-adc 58000000.myadc: no pinctrl handle OF: no dma-ranges found for node(/myadc@5800000) s3c-adc 58000000.myadc: device is not dma coherent s3c-adc 58000000.myadc: device is not behind an iommu OF: of_irq_parse_one: dev=/myadc@5800000, index=1 OF: parent=/interrupt-controller@4a000000, intsize=4 OF: intspec=1 of_irq_parse_raw: /interrupt-controller@4a000000:00000001,0000001f,0000000a,00000003 OF: of_irq_parse_raw: ipar=/interrupt-controller@4a000000, size=4 OF: -> addrsize=1 OF: -> got it ! clock-names adc in index 0 s3c-adc 58000000.myadc: attached adc driver ....

运行命令cat /proc/interrupts可以查看当前系统有哪些中断服务:

[root@zy:/]# cat /proc/interrupts CPU0 7: 1304 s3c-eint 7 Edge eth0 8: 0 s3c 8 Edge s3c2410-rtc tick 13: 10445 s3c 13 Edge samsung_time_irq 22: 0 s3c 16 Edge 4d000000.fb 27: 0 s3c 27 Edge 54000000.i2c 30: 0 s3c 30 Edge s3c2410-rtc alarm 35: 8 s3c-level 35 Level 50004000.serial 36: 56 s3c-level 36 Level 50004000.serial 41: 0 s3c-level 41 Edge s3c2410_ts_pen // IRQ_TC 42: 0 s3c-level 42 Edge 58000000.myadc // IRQ_ADC 59: 0 s3c-level 59 Edge 53000000.watchdog

查看设备节点文件:

[root@zy:/]# ls /dev/input -l total 0 crw-rw---- 1 0 0 13, 64 Jan 1 00:00 event0 五、使用tslib进行测试 5.1 下载tslib

直接到github上下载:

root@zhengyang:/work/sambashare/drivers/#git clone https://github.com/kergoth/tslib

下载完成后,我直接上传到ubuntu服务器如下路径:/work/sambashare/drivers。

跳转到tslib文件夹:

root@zhengyang:/work/sambashare/drivers# cd tslib/ 5.2 编译

首先运行:

root@zhengyang:/work/sambashare/drivers/tslib# ./autogen.sh root@zhengyang:/work/sambashare/drivers/tslib# mkdir tmp

然后配置:

root@zhengyang:/work/sambashare/drivers/tslib# CC=arm-linux-gcc ./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp CFLAGS="-march=armv4t -O2 -Wall -W"

编译安装:

root@zhengyang:/work/sambashare/drivers/tslib# make //编译 root@zhengyang:/work/sambashare/drivers/tslib# make install //安装到tmp目录下

需要注意的是编译所使用的的版本要和内核编译的版本保持一致,我用的是arm-linux-gcc4.8.3版本。

可以通过如下命令查看可执行文件的平台属性信息:

root@zhengyang:/work/sambashare/drivers/tslib# cd tmp root@zhengyang:/work/sambashare/drivers/tslib/tmp# arm-linux-readelf -A bin/ts_test Attribute Section: aeabi File Attributes Tag_CPU_name: "4T" Tag_CPU_arch: v4T Tag_ARM_ISA_use: Yes Tag_THUMB_ISA_use: Thumb-1 Tag_ABI_PCS_wchar_t: 4 Tag_ABI_FP_rounding: Needed Tag_ABI_FP_denormal: Needed Tag_ABI_FP_exceptions: Needed Tag_ABI_FP_number_model: IEEE 754 Tag_ABI_align_needed: 8-byte Tag_ABI_align_preserved: 8-byte, except leaf SP Tag_ABI_enum_size: int 5.3 配置nfs文件系统

将tmp里面的bin ,etc,include,lib4个目录下的文件拷贝到文件系统的bin ,etc,include,lib4个目录下 :

root@zhengyang:/work/sambashare/drivers/tslib/tmp# cp * /work/nfs_root/rootfs/ -rfd

进入nfs文件系统,修改etc/inittab文件:

root@zhengyang:/work/sambashare/drivers/tslib/tmp# cd /work/nfs_root/rootfs/ root@zhengyang:/work/sambashare/drivers/tslib/tmp# vim etc/inittab

检查是否会启动:

tty1: tty1::askfirst:-/bin/sh #在虚拟终端tty1启动askfirst动作的shell,也就是在LCD上会出现Please press Enter to active this console.

若有,前面加#,屏蔽掉,这条命令。

5.4  安配置LCD和触摸屏环境 [root@zy:/]# export TSLIB_TSDEVICE=/dev/input/event0  #ts设备文件(触摸屏):event0 [root@zy:/]# export TSLIB_CALIBFILE=/etc/pointercal #校验文件(calibrate file),存放校验值 [root@zy:/]# export TSLIB_CONFFILE=/etc/ts.conf  #配置文件 [root@zy:/]# export TSLIB_PLUGINDIR=/lib/ts #插件文件 [root@zy:/]# export TSLIB_CONSOLEDEVICE=none  #终端控制台设为NULL [root@zy:/]# export TSLIB_FBDEVICE=/dev/fb0 #fb设备文件(LCD):fb0

或者直接写入nfs根文件系统路径下etc/profile文件中。

5.5 测试

运行校准程序,触摸屏依次出现5个点,依次点击之:

[root@zy:/]# ts_calibrate xres = 240, yres = 320 Took 5 samples... Top left : X = 267 Y = 783 Took 5 samples... Top right : X = 782 Y = 774 Took 3 samples... Bot right : X = 769 Y = 185 Took 2 samples... Bot left : X = 289 Y = 212 Took 19 samples... Center : X = 532 Y = 497 -29.351410 0.281104 0.002008 352.980225 -0.013406 -0.379243 Calibration constants: -1923574 18422 131 23132912 -878 -24854 65536

生成的校准文件名为pointercal,位于/etc目录下。

在开发板上执行如下名,就可以在lcd上绘图了:

[root@zy:/]# ts_test

屏幕最上方会出现三个按钮,分别为“Drag”、“Draw”和“Quit”,默认是第一个,因此,用触摸笔点击任何一处,十字光标便会到那里。

下面是点击Draw按钮并用触摸笔写字的效果图:

同时控制台输出大量信息,其中一小部分:

194.859177: 125 192 255 194.889177: 131 196 255 194.919155: 135 199 255 194.949226: 138 196 255 194.979155: 141 189 255 195.009152: 143 183 255 195.039166: 144 178 255 195.069162: 146 175 255 195.099161: 150 176 255 195.129166: 154 175 255 195.159257: 157 175 255 195.189178: 158 179 255 195.219176: 155 187 255 195.249176: 152 197 255 195.279150: 150 206 255 195.309160: 151 209 255 195.339161: 154 212 255 195.369205: 160 213 0

第一列为timeval结构体的两个成员:tv_sec和tv_usec,中间两列分别是X和Y的坐标,最后为pressure,这里可以理解成“触摸事件”,为255表示触摸笔点击了(接触)屏幕,为0表示触摸笔离开了屏幕(这里出现很多的255是正常的,因为写字过程中笔没有离开触摸屏)。点击屏幕上“Quit”或按Ctrl+C可退出该程序。

参考文章

[1]linux驱动移植-LCD驱动基础

[2]linux驱动移植-LCD设备驱动

[3]linux驱动移植-LCD触摸屏设备驱动

[4]基于设备树的TQ2440触摸屏驱动移植



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3