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

来源:互联网 发布:手机百度网盘网络出错 编辑:程序博客网 时间:2024/05/23 16:54

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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/i2c.h>
#include <linux/timer.h>
#include <linux/delay.h>

/*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 page\n");
        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 data\n");
        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 <allen.p.wang@gmail.com>");
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设备驱动成功加载。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一加3t屏幕开了怎么办? 孕妇吃了8个杏怎么办啊 洗碗盆落水器垫子密封不好怎么办? 手剥橙子剥的特别疼怎么办? 经常带对讲机的耳麦耳朵痛怎么办 公安检查遇到穿便装的军人怎么办 cf幽灵鬼呼吸辅军训刘海怎么办助 眼睛被等离子切割器的光烤了怎么办 玩王者的时候屏幕竖着了该怎么办 铝合金门双包门套比墙的厚了怎么办 磁共振检查后发现带金属了怎么办 贴了乳贴过免痒怎么办 yy别人听见我打游戏的声音怎么办 微信的聊天记录发错邮箱怎么办 百度云盘文件有违规内容怎么办 天籁一键启动钥匙没电怎么办 中兴手机系统界面已停止运行怎么办 怎么办可以复制成不关联的文档 希捷400g硬盘电机不转怎么办 金立手机微信语音播放失败怎么办 手机4g网络变2g怎么办 生存战争2吃了腐烂的食物后怎么办 古筝调音 d的显示为b怎么办 消防建审没有原有的结构图纸怎么办 生石灰弄到脸上用水洗后发热怎么办 吃了没熟的鹅肝怎么办 蹲式厕所被袜子堵了怎么办 自热包的水喝了怎么办 火锅发热包不小心吃了怎么办 塑料螺旋饭盒盖子被吸住了怎么办 昨晚喝太多酒今天排尿拍不出怎么办 开光过的貔貅摔坏一点嘴巴怎么办 诺基亚6第二代忘记解屏密码怎么办 工厂搬迁已经般空了工人怎么办 被上司强行换了一个岗位该怎么办 上司要调整我岗位我该怎么办 我被别人打伤了警察不管怎么办 郑州共享汽车小黄车路上坏了怎么办 爱跟别人聊朋友的事怎么办 任职履历上学历写错了怎么办 六个月的宝宝老长婴儿湿疹怎么办