Hi! > > Do you have a link? (I replaced it with disable_irq_nosync, if that is > > enough...) > > > > link: http://patchwork.kernel.org/patch/35515/ Thanks! Here's my attempt at that conversion; unfortunately I'm stuck in 2.6.29 for msm stuff, so I was not even able to compile-test it :-(. Pavel diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi.c b/drivers/input/touchscreen/synaptics_i2c_rmi.c index 771b710..4816262 100644 --- a/drivers/input/touchscreen/synaptics_i2c_rmi.c +++ b/drivers/input/touchscreen/synaptics_i2c_rmi.c @@ -13,6 +13,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * + * http://www.synaptics.com/sites/default/files/511_000099_01F.pdf */ #include <linux/module.h> @@ -34,7 +35,6 @@ struct synaptics_ts_data { u16 addr; struct i2c_client *client; struct input_dev *input_dev; - int use_irq; struct hrtimer timer; struct work_struct work; u16 max[2]; @@ -87,6 +87,22 @@ static int synaptics_init_panel(struct synaptics_ts_data *ts) static void decode_report(struct synaptics_ts_data *ts, u8 *buf) { +/* + * This sensor sends two 6-byte absolute finger reports, an optional + * 2-byte relative report followed by a status byte. This function + * reads the two finger reports and transforms the coordinates + * according the platform data so they can be aligned with the lcd + * behind the touchscreen. Typically we flip the y-axis since the + * sensor uses the bottom left corner as the origin, but if the sensor + * is mounted upside down the platform data will request that the + * x-axis should be flipped instead. The snap to inactive edge border + * are used to allow tapping the edges of the screen on the G1. The + * active area of the touchscreen is smaller than the lcd. When the + * finger gets close the edge of the screen we snap it to the + * edge. This allows ui elements at the edge of the screen to be hit, + * and it prevents hitting ui elements that are not at the edge of the + * screen when the finger is touching the edge. + */ int pos[2][2]; int f, a; int base = 2; @@ -144,7 +160,7 @@ static void decode_report(struct synaptics_ts_data *ts, u8 *buf) input_sync(ts->input_dev); } -static void synaptics_ts_work_func(struct work_struct *work) +static void synaptics_ts_work(struct synaptics_ts_data *ts) { int i; int ret; @@ -152,8 +168,6 @@ static void synaptics_ts_work_func(struct work_struct *work) struct i2c_msg msg[2]; u8 start_reg = 0; u8 buf[15]; - struct synaptics_ts_data *ts = - container_of(work, struct synaptics_ts_data, work); msg[0].addr = ts->client->addr; msg[0].flags = 0; @@ -164,7 +178,7 @@ static void synaptics_ts_work_func(struct work_struct *work) msg[1].len = sizeof(buf); msg[1].buf = buf; - for (i = 0; i < ((ts->use_irq && !bad_data) ? 1 : 10); i++) { + for (i = 0; i < (!bad_data ? 1 : 10); i++) { ret = i2c_transfer(ts->client->adapter, msg, 2); if (ret < 0) { pr_err("ts_work: i2c_transfer failed\n"); @@ -190,27 +204,20 @@ static void synaptics_ts_work_func(struct work_struct *work) decode_report(ts, buf); } - if (ts->use_irq) - enable_irq(ts->client->irq); + enable_irq(ts->client->irq); } -static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer) -{ - struct synaptics_ts_data *ts = - container_of(timer, struct synaptics_ts_data, timer); - - queue_work(synaptics_wq, &ts->work); - hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); - return HRTIMER_NORESTART; +static irqreturn_t synaptics_ts_hardirq(int irq, void *dev_id) +{ + disable_irq_nosync(irq); + return IRQ_WAKE_THREAD; } static irqreturn_t synaptics_ts_irq_handler(int irq, void *dev_id) { struct synaptics_ts_data *ts = dev_id; - - disable_irq_nosync(ts->client->irq); - queue_work(synaptics_wq, &ts->work); + synaptics_ts_work(ts); return IRQ_HANDLED; } @@ -469,24 +476,21 @@ static int __devinit synaptics_ts_probe( ts->input_dev->name); goto err_input_register_device_failed; } - if (client->irq) { - ret = request_irq(client->irq, synaptics_ts_irq_handler, - 0, client->name, ts); - if (ret == 0) { - ret = i2c_set(ts, 0xf1, 0x01, "enable abs int"); - if (ret) - free_irq(client->irq, ts); - } - if (ret == 0) - ts->use_irq = 1; - else - dev_err(&client->dev, "request_irq failed\n"); - } - if (!ts->use_irq) { - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ts->timer.function = synaptics_ts_timer_func; - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + + ret = request_threaded_irq(client->irq, + synatptics_ts_hardirq, synaptics_ts_irq_handler, + 0, client->name, ts); + + if (ret) + pr_err("synaptics: could not register irq\n"); + + + ret = i2c_set(ts, 0xf1, 0x01, "enable abs int"); + if (ret) { + pr_err("synaptics: could not enable irq\n"); + free_irq(client->irq, ts); } + #ifdef CONFIG_HAS_EARLYSUSPEND ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ts->early_suspend.suspend = synaptics_ts_early_suspend; @@ -495,7 +499,7 @@ static int __devinit synaptics_ts_probe( #endif pr_info("synaptics: Start touchscreen %s in %s mode\n", - ts->input_dev->name, ts->use_irq ? "interrupt" : "polling"); + ts->input_dev->name, "interrupt"); return 0; @@ -517,10 +521,7 @@ static int synaptics_ts_remove(struct i2c_client *client) #ifdef CONFIG_HAS_EARLYSUSPEND unregister_early_suspend(&ts->early_suspend); #endif - if (ts->use_irq) - free_irq(client->irq, ts); - else - hrtimer_cancel(&ts->timer); + free_irq(client->irq, ts); input_unregister_device(ts->input_dev); kfree(ts); return 0; @@ -532,12 +533,9 @@ static int synaptics_ts_suspend(struct i2c_client *client, pm_message_t mesg) int ret; struct synaptics_ts_data *ts = i2c_get_clientdata(client); - if (ts->use_irq) - disable_irq(client->irq); - else - hrtimer_cancel(&ts->timer); + disable_irq(client->irq); ret = cancel_work_sync(&ts->work); - if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */ + if (ret) /* if work was pending disable-count is now 2 */ enable_irq(client->irq); i2c_set(ts, 0xf1, 0, "disable interrupt"); i2c_set(ts, 0xf0, 0x86, "deep sleep"); @@ -563,11 +561,8 @@ static int synaptics_ts_resume(struct i2c_client *client) synaptics_init_panel(ts); - if (ts->use_irq) { - enable_irq(client->irq); - i2c_set(ts, 0xf1, 0x01, "enable abs int"); - } else - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + enable_irq(client->irq); + i2c_set(ts, 0xf1, 0x01, "enable abs int"); return 0; } -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html