Linux的I2C 设备驱动 -- mini2440 上i2c接口触摸屏驱动

发布者:zonheny最新更新时间:2021-11-22 来源: eefocus关键字:Linux  I2C  设备驱动  mini2440  i2c接口  触摸屏驱动 手机看文章 扫描二维码
随时随地手机看文章

本篇记录在友善之臂 mini2440 平台上挂载I2C接口触摸屏的驱动开发过程。

内核版本linux-2.6.32.2,
平台是ARM9 S3C2440+I2C接口的触摸屏

如上篇 Linux的I2C驱动体系结构讲述
http://www.lupaworld.com/273398/viewspace-204237.html

要挂载新的I2C设备,需要实现3部分:

1) 适配器的硬件驱动:
内核中已经实现mini2440,i2c适配器驱动,可以在如下目录i2c-s3c2410.c中看到相关代码
linux-2.6.32.2/drivers/i2c/busses/i2c-s3c2410.c

2) I2C 设配器的algorithm
同样在inux-2.6.32.2/drivers/i2c/busses/i2c-s3c2410.c文件中实现。

以上两部分无须做任何更改

3) I2C设备驱动,可以以linux-2.6.32.2/drivers/input/touchscreen/migor_ts.c为例,分析如下:
//-------------------------------------------------------------------//
#include
#include
#include
#include
#include
#include
#include
#include

/*resolution definion according to touch screen */
#define MIN_X_COORDINATE    0
#define MAX_X_COORDINATE    1024   
#define MIN_Y_COORDINATE    0
#define MAX_Y_COORDINATE    768

/* touch screen data structure */
struct i2c_ts_priv {
    struct i2c_client *client;
    struct input_dev *input;
    struct delayed_work work;
    int irq;
};

static void i2c_ts_poscheck(struct work_struct *work)
{
    struct i2c_ts_priv *priv = container_of(work, struct i2c_ts_priv, work.work);
    /* buffer for storing data */
    char buf[6];
    int number;
    int xpos, ypos;

    memset(buf, 0, sizeof(buf));

    /* Now do Page Read */
    if (i2c_master_recv(priv->client, buf,6) != 6) {
        dev_err(&priv->client->dev, "Unable to read i2c pagen");
        goto out;
    }
       
    /* convert coordinate */
    number = buf[0]&0x07;
    xpos = ((buf[3] << 8) | buf[2]);
    ypos = ((buf[5] << 8) | buf[4]);
   
     /* report input event */
    if ((number != 0) && (xpos != 0) && (ypos != 0)) {
        input_report_key(priv->input, BTN_TOUCH, 1);
        input_report_abs(priv->input, ABS_X, xpos);
        input_report_abs(priv->input, ABS_Y, ypos);
        input_sync(priv->input);
    } else if (number == 0) {
        input_report_key(priv->input, BTN_TOUCH, 0);
        input_sync(priv->input);
    }

 out:
    enable_irq(priv->irq);
}

/* read finger numbers and coordinate and report input event */
static irqreturn_t i2c_ts_isr(int irq, void *dev_id)
{
    struct i2c_ts_priv *priv = dev_id;
      
    /* disable irq */
    disable_irq_nosync(irq);
    schedule_delayed_work(&priv->work, HZ/100);   
    return IRQ_HANDLED;
}


static int i2c_ts_open(struct input_dev *dev)
{
    return 0;
}

static void i2c_ts_close(struct input_dev *dev)
{

}

static int i2c_ts_probe(struct i2c_client *client,
              const struct i2c_device_id *idp)
{
    struct i2c_ts_priv *priv;
    struct input_dev *input;
    int error;
    char buf[2];   

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    if (!priv) {
        dev_err(&client->dev, "failed to allocate driver datan");
        error = -ENOMEM;
        goto err0;
    }

    dev_set_drvdata(&client->dev, priv);

    input = input_allocate_device();
    if (!input) {
        dev_err(&client->dev, "Failed to allocate input device.n");
        error = -ENOMEM;
        goto err1;
    }

    input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);

    input_set_abs_params(input, ABS_X, MIN_X_COORDINATE, MAX_X_COORDINATE, 0, 0);
    input_set_abs_params(input, ABS_Y, MIN_Y_COORDINATE, MAX_Y_COORDINATE, 0, 0);

    input->name = client->name;
    input->id.bustype = BUS_I2C;
    input->dev.parent = &client->dev;

    input->open = i2c_ts_open;
    input->close = i2c_ts_close;

    input_set_drvdata(input, priv);

    priv->client = client;
    priv->input = input;
    INIT_DELAYED_WORK(&priv->work, i2c_ts_poscheck);
    priv->irq = client->irq;

    error = input_register_device(input);
    if (error)
        goto err1;

    error = request_irq(priv->irq, i2c_ts_isr, IRQF_TRIGGER_FALLING,
                client->name, priv);
    if (error) {
        dev_err(&client->dev, "Unable to request touchscreen IRQ.n");
        goto err2;
    }

    device_init_wakeup(&client->dev,1);
   
    return 0;

 err2:
    input_unregister_device(input);
    input = NULL; /* so we dont try to free it below */
 err1:
    input_free_device(input);
    kfree(priv);
 err0:
    dev_set_drvdata(&client->dev, NULL);
    return error;
}

static int i2c_ts_remove(struct i2c_client *client)
{
    struct i2c_ts_priv *priv = dev_get_drvdata(&client->dev);

    free_irq(priv->irq, priv);
    input_unregister_device(priv->input);
    kfree(priv);

    dev_set_drvdata(&client->dev, NULL);

    return 0;
}

static int i2c_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
    struct i2c_ts_priv *priv = dev_get_drvdata(&client->dev);
    if(device_may_wakeup(&client->dev))
    enable_irq_wake(priv->irq);
    return 0;
}

static int i2c_ts_resume(struct i2c_client *client)
{
    struct i2c_ts_priv *priv = dev_get_drvdata(&client->dev);
    if(device_may_wakeup(&client->dev))
    disable_irq_wake(priv->irq);
    return 0;
}

static const struct i2c_device_id i2c_ts_id[] = {
    { "i2c-ts", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, i2c_ts_id);

static struct i2c_driver i2c_ts_driver = {
    .driver = {
        .name = "i2c-ts",
    },
    .probe = i2c_ts_probe,
    .remove = i2c_ts_remove,
    .suspend = i2c_ts_suspend,
    .resume = i2c_ts_resume,
    .id_table = i2c_ts_id,
};

static int __init i2c_ts_init(void)
{
    return i2c_add_driver(&i2c_ts_driver);
}

static void __exit i2c_ts_exit(void)
{
    i2c_del_driver(&i2c_ts_driver);
}

MODULE_DESCRIPTION("i2c Touchscreen driver");
MODULE_AUTHOR("ALlen ");
MODULE_LICENSE("GPL");

module_init(i2c_ts_init);
module_exit(i2c_ts_exit);

4).实现如上步骤后,还需要创建和配置I2C 设备,设置文件位于
linux-2.6.32.2/arch/arm/mach-s3c2440/mach-mini2440.c中,
添加如下代码:
..................................................
+/* I2C touch screen devices. */
+/* bus configuration */
+static struct s3c2410_platform_i2c i2c_touchscreen_cfg __initdata = {
+   .flags        = 0,
+    .slave_addr    = 0x5c,
+   .frequency    = 100*1000,
+    .sda_delay    = 2,
+};

+/* i2c device name is "i2c_ts", address is 0x5c, interrupt is eint20 */
+static struct i2c_board_info touchscreen_i2c_devs[] __initdata = {
+    {
+        I2C_BOARD_INFO("i2c-ts", 0x5c),
+        .irq    = IRQ_EINT20,
+    },
+};
...................................................

static void __init mini2440_machine_init(void)
{
..................................................
 +   /* i2c touch screen devices */
 +   s3c_i2c0_set_platdata(&i2c_touchscreen_cfg);
 +  i2c_register_board_info(0, touchscreen_i2c_devs,  +ARRAY_SIZE(touchscreen_i2c_devs));
...................................................
}

此处I2C_BOARD_INFO("i2c-ts",0x5c), “i2c-ts” 要和i2c设备驱动中i2c_ts_id一致。
才能保证i2c设备驱动成功加载。

关键字:Linux  I2C  设备驱动  mini2440  i2c接口  触摸屏驱动 引用地址:Linux的I2C 设备驱动 -- mini2440 上i2c接口触摸屏驱动

上一篇:MINI2440平台移植的uboot
下一篇:mini2440-i2c驱动分析

推荐阅读最新更新时间:2024-11-06 11:06

mini2440驱动分析之PWM
1. pwm驱动也是作为杂项设备注册的,同样为了防止并发造成的竞态,有个信号量保护。模块的初始化函数 static int __init dev_init(void) { int ret; init_MUTEX(&lock); ret = misc_register(&misc); printk (DEVICE_NAME tinitializedn ); return ret; } 这个函数就是初始化了一个信号量,然后调用misc_register注册到杂项设备 2. 这个pwm驱动的基本功能体现在ioctl方法上 static int s3c24xx_pwm_ioctl(struct i
[单片机]
LINUX 5.5加入对SR-IOV式 X3100系列产品的支持
Exar公司(纳斯达克:EXAR)近日宣布Red Hat企业版 Linux 5.5可支持其第三代Neterion X3100 10千兆以太网服务器适配器,包括与单根I/O虚拟化技术(SR-IOV)的全兼容性。SR-IOV是对PCI Express标准的一种延伸,它可以使一个单个PCI Express 适配器通过一个共享的PCI Express 物理接口同时起到多个独立器件的作用。 对于使用Red Hat企业版Linux 5.5自带的内核虚拟机(KVM)管理程序的IT组织来说,Exar公司的 Neterion X3100 服务器适配器利用SR-IOV让其能够充分利用Exar公司针对虚拟化顶尖水平的硬件加速技术。X310
[网络通信]
Linux开发环境的建立步骤
传统的嵌入式开发环境需要单片机的仿真器,包括C语言、汇编语言、调试工具等的集成开发环境IDE、实时操作系统等。 由于Flash技术的发展,仿真器已可以省去。随着BDM调试工具的标准化,BDM调试工具会变得越来越简单、越来越通用。 软件方面,Linux下的自由软件GNU gcc可以完成几乎所有知名CPU以及DSP的交叉C编译和调试,故IDE可以省去。 操作系统方面,uClinux、RTLinux、μC/OS等源码开放的、免费的嵌入式操作系统也都性能稳定可靠。 因此,全部使用自由软件开发嵌入式应用无疑是一种不错的选择。我们在32位MCU ColdFire上实现了上述全部开发过程。这一过程原则上也适合其它几乎所有的32位
[工业控制]
mini2440烧写裸机程序(linux+supervivi+dnw)
一、编写源程序(init.S、testledC.lds、testledC.c、Makefile) @****************************************************************************** @ File:init.S @ 功能:通过它转入C程序 @****************************************************************************** .text .global _start _start: ldr r0, =0x53000000 @ WATCHDOG寄存器地址
[单片机]
用户态应用程序直接访问I2C驱动
#include stdio.h #include stdlib.h #include string.h #include sys/types.h #include sys/stat.h #include fcntl.h #include i2c-dev.h //调用来自 i2c-tools-3.1.0.tar.bz2 ,包含操作I2C函数的声明 // i2c_usr_test r addr * i2c_usr_test w addr val // void print_usage(char *file) { printf( %s r addr\n , file); prin
[单片机]
Linux向目标系统AT91RM9200的移植方法与应用优势分析
1.引言 目前,在嵌入式系统里基于ARM微核的嵌入式处理器以其功耗低,功能强大的优点已经成为市场的主流。与此同时,在网络上发展起来的Linux操作系统,以其功能强大,开放源代码,支持硬件种类众多的特点,越来越受到人们的青睐。然而如何把Linux操作系统移植到ARM平台上却成了一个重点,也是一个难点问题。 嵌入式Linux系统包括引导程序(Bootloader),内核(kernel)和根文件系统三个部分,其开发流程如图1所示:嵌入式Linux 移植到特定的硬件平台上,一般需要以下五个步骤: (1)前期准备包括从网站上下载嵌入式Linux的源码包, 搭建交叉编译开发环境,配置主机的开发环境等 (2)配置Bootloader,并将
[单片机]
<font color='red'>Linux</font>向目标系统AT91RM9200的移植方法与应用优势分析
OK6410A 开发板 (八) 122 linux-5.11 OK6410A 以linux用户角度去应用用户空间内存
以linux用户角度去应用用户空间内存 // 在 用户空间是以 段的形式管理的 在内核空间是通过 VMA 来管理这些段的 // https://blog.csdn.net/u011011827/article/details/117335579 中的 VMA 代码段内存 通过增加代码长度 通过汇编指定一个段为代码段(虽然里面可能是数据) 数据段内存 全局变量 // __attribute__((section( .ARM.__at_address ))) , 这个东西要该默认的连接脚本?//TODO 栈内存 局部变量 堆内存 level1 api: syscall
[单片机]
LINUX下ARM汇编的常用指令解析
1.ldr 和 str : (1) ldr 作为指令,叫做寄存器加载指令。将内存中的值加载到寄存器中。 (2) ldr 作为伪指令,实现一个32位常数或地址值加载到寄存器中。后面加载的常量或地址值标号前面必须有一个 “=” ,编译器会将伪指令替换成指令实现。 (3) str 将寄存器中的值保存到内存单元中。 2..long 伪操作,给数值分配内存单元。 start: virable: .long start 如上,表示将start表示的值存到virable所代表的内存中。 virable: .long 0x66666666 如上,表示将0x66666666存入virable所在的内存单元中。 3.adr
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved