This document describes how to develop an I2C interface touch screen driver mounted on the friendly mini-2440 platform.
Kernel edition linux-2.6.32.2,
The platform is a touch screen with the arm9-s3c2440 + I2C interface.
For exampleLinux I2C driver architectureDescription
Http://www.lupaworld.com/273398/viewspace-204237.html
To mount a new I2C device, you need to implement three parts:
1) adapter hardware driver:
The kernel has implemented the mini2440, I2C Adapter Driver, you can see the relevant in the following directory i2c-s3c2410.cCode
Linux-2.6.32.2/Drivers/I2C/busses/i2c-s3c2410.c
2) algorithm with memory configured for I2C
Also implemented in inux-2.6.32.2/Drivers/I2C/busses/i2c-s3c2410.c files.
No changes are required for the above two parts.
3) I2C Device Driver, can take linux-2.6.32.2/Drivers/input/touchscreen/migor_ts.c as an example, the analysis is as follows:
//-------------------------------------------------------------------//
# 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 = kzarloc (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, ir1__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 ). after completing this step, you also need to create and configure the I2C device where the setup file is located in
linux-2.6.32.2/ARCH/ARM/mach-s3c2440/mach-mini2440.c,
Add the following code:
................................. .................
+/* I2C touch screen devices. */
+/* bus configuration */
+ static struct s3c2410_platform_i2c i2c_touchscreen_cfg _ initdata ={< br> +. 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 */
+ Maid (& i2c_touchscreen_cfg );
+ I2c_register_board_info (0, touchscreen_i2c_devs, + array_size (touchscreen_i2c_devs ));
........................................ ...........
}
Here i2c_board_info ("i2c-ts", 0x5c), "i2c-ts" should be consistent with i2c_ts_id In the I2C device driver.
In order to ensure that the I2C device driver is loaded successfully.