Path: blob/master/drivers/input/touchscreen/migor_ts.c
15111 views
/*1* Touch Screen driver for Renesas MIGO-R Platform2*3* Copyright (c) 2008 Magnus Damm4* Copyright (c) 2007 Ujjwal Pande <[email protected]>,5* Kenati Technologies Pvt Ltd.6*7* This file is free software; you can redistribute it and/or8* modify it under the terms of the GNU General Public9* License as published by the Free Software Foundation; either10* version 2 of the License, or (at your option) any later version.11*12* This file is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU15* General Public License for more details.16*17* You should have received a copy of the GNU General Public18* License along with this library; if not, write to the Free Software19* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA20*/21#include <linux/module.h>22#include <linux/kernel.h>23#include <linux/input.h>24#include <linux/interrupt.h>25#include <linux/pm.h>26#include <linux/slab.h>27#include <asm/io.h>28#include <linux/i2c.h>29#include <linux/timer.h>3031#define EVENT_PENDOWN 132#define EVENT_REPEAT 233#define EVENT_PENUP 33435struct migor_ts_priv {36struct i2c_client *client;37struct input_dev *input;38struct delayed_work work;39int irq;40};4142static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11,430x01, 0x06, 0x07, };44static const u_int8_t migor_ts_dis_seq[17] = { };4546static void migor_ts_poscheck(struct work_struct *work)47{48struct migor_ts_priv *priv = container_of(work,49struct migor_ts_priv,50work.work);51unsigned short xpos, ypos;52unsigned char event;53u_int8_t buf[16];5455memset(buf, 0, sizeof(buf));5657/* Set Index 0 */58buf[0] = 0;59if (i2c_master_send(priv->client, buf, 1) != 1) {60dev_err(&priv->client->dev, "Unable to write i2c index\n");61goto out;62}6364/* Now do Page Read */65if (i2c_master_recv(priv->client, buf, sizeof(buf)) != sizeof(buf)) {66dev_err(&priv->client->dev, "Unable to read i2c page\n");67goto out;68}6970ypos = ((buf[9] & 0x03) << 8 | buf[8]);71xpos = ((buf[11] & 0x03) << 8 | buf[10]);72event = buf[12];7374if (event == EVENT_PENDOWN || event == EVENT_REPEAT) {75input_report_key(priv->input, BTN_TOUCH, 1);76input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/77input_report_abs(priv->input, ABS_Y, xpos);78input_sync(priv->input);79} else if (event == EVENT_PENUP) {80input_report_key(priv->input, BTN_TOUCH, 0);81input_sync(priv->input);82}83out:84enable_irq(priv->irq);85}8687static irqreturn_t migor_ts_isr(int irq, void *dev_id)88{89struct migor_ts_priv *priv = dev_id;9091/* the touch screen controller chip is hooked up to the cpu92* using i2c and a single interrupt line. the interrupt line93* is pulled low whenever someone taps the screen. to deassert94* the interrupt line we need to acknowledge the interrupt by95* communicating with the controller over the slow i2c bus.96*97* we can't acknowledge from interrupt context since the i2c98* bus controller may sleep, so we just disable the interrupt99* here and handle the acknowledge using delayed work.100*/101102disable_irq_nosync(irq);103schedule_delayed_work(&priv->work, HZ / 20);104105return IRQ_HANDLED;106}107108109static int migor_ts_open(struct input_dev *dev)110{111struct migor_ts_priv *priv = input_get_drvdata(dev);112struct i2c_client *client = priv->client;113int count;114115/* enable controller */116count = i2c_master_send(client, migor_ts_ena_seq,117sizeof(migor_ts_ena_seq));118if (count != sizeof(migor_ts_ena_seq)) {119dev_err(&client->dev, "Unable to enable touchscreen.\n");120return -ENXIO;121}122123return 0;124}125126static void migor_ts_close(struct input_dev *dev)127{128struct migor_ts_priv *priv = input_get_drvdata(dev);129struct i2c_client *client = priv->client;130131disable_irq(priv->irq);132133/* cancel pending work and wait for migor_ts_poscheck() to finish */134if (cancel_delayed_work_sync(&priv->work)) {135/*136* if migor_ts_poscheck was canceled we need to enable IRQ137* here to balance disable done in migor_ts_isr.138*/139enable_irq(priv->irq);140}141142/* disable controller */143i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq));144145enable_irq(priv->irq);146}147148static int migor_ts_probe(struct i2c_client *client,149const struct i2c_device_id *idp)150{151struct migor_ts_priv *priv;152struct input_dev *input;153int error;154155priv = kzalloc(sizeof(*priv), GFP_KERNEL);156if (!priv) {157dev_err(&client->dev, "failed to allocate driver data\n");158error = -ENOMEM;159goto err0;160}161162dev_set_drvdata(&client->dev, priv);163164input = input_allocate_device();165if (!input) {166dev_err(&client->dev, "Failed to allocate input device.\n");167error = -ENOMEM;168goto err1;169}170171input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);172input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);173174input_set_abs_params(input, ABS_X, 95, 955, 0, 0);175input_set_abs_params(input, ABS_Y, 85, 935, 0, 0);176177input->name = client->name;178input->id.bustype = BUS_I2C;179input->dev.parent = &client->dev;180181input->open = migor_ts_open;182input->close = migor_ts_close;183184input_set_drvdata(input, priv);185186priv->client = client;187priv->input = input;188INIT_DELAYED_WORK(&priv->work, migor_ts_poscheck);189priv->irq = client->irq;190191error = input_register_device(input);192if (error)193goto err1;194195error = request_irq(priv->irq, migor_ts_isr, IRQF_TRIGGER_LOW,196client->name, priv);197if (error) {198dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");199goto err2;200}201202device_init_wakeup(&client->dev, 1);203return 0;204205err2:206input_unregister_device(input);207input = NULL; /* so we dont try to free it below */208err1:209input_free_device(input);210kfree(priv);211err0:212dev_set_drvdata(&client->dev, NULL);213return error;214}215216static int migor_ts_remove(struct i2c_client *client)217{218struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);219220free_irq(priv->irq, priv);221input_unregister_device(priv->input);222kfree(priv);223224dev_set_drvdata(&client->dev, NULL);225226return 0;227}228229static int migor_ts_suspend(struct device *dev)230{231struct i2c_client *client = to_i2c_client(dev);232struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);233234if (device_may_wakeup(&client->dev))235enable_irq_wake(priv->irq);236237return 0;238}239240static int migor_ts_resume(struct device *dev)241{242struct i2c_client *client = to_i2c_client(dev);243struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);244245if (device_may_wakeup(&client->dev))246disable_irq_wake(priv->irq);247248return 0;249}250251static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);252253static const struct i2c_device_id migor_ts_id[] = {254{ "migor_ts", 0 },255{ }256};257MODULE_DEVICE_TABLE(i2c, migor_ts);258259static struct i2c_driver migor_ts_driver = {260.driver = {261.name = "migor_ts",262.pm = &migor_ts_pm,263},264.probe = migor_ts_probe,265.remove = migor_ts_remove,266.id_table = migor_ts_id,267};268269static int __init migor_ts_init(void)270{271return i2c_add_driver(&migor_ts_driver);272}273274static void __exit migor_ts_exit(void)275{276i2c_del_driver(&migor_ts_driver);277}278279MODULE_DESCRIPTION("MigoR Touchscreen driver");280MODULE_AUTHOR("Magnus Damm <[email protected]>");281MODULE_LICENSE("GPL");282283module_init(migor_ts_init);284module_exit(migor_ts_exit);285286287