Linux的I2C 设备驱动 -- mini2440 上i2c接口触摸屏驱动
生活随笔
收集整理的這篇文章主要介紹了
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設備驅動成功加載。
內核版本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設備驅動成功加載。
總結
以上是生活随笔為你收集整理的Linux的I2C 设备驱动 -- mini2440 上i2c接口触摸屏驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 比亚迪彻底无敌!今年累计销量已超50万辆
- 下一篇: 8千多LV拖鞋穿一个星期掉色:官方回应