migor_ts.c (5578B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Touch Screen driver for Renesas MIGO-R Platform 4 * 5 * Copyright (c) 2008 Magnus Damm 6 * Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>, 7 * Kenati Technologies Pvt Ltd. 8 */ 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/input.h> 12#include <linux/interrupt.h> 13#include <linux/pm.h> 14#include <linux/slab.h> 15#include <asm/io.h> 16#include <linux/i2c.h> 17#include <linux/timer.h> 18 19#define EVENT_PENDOWN 1 20#define EVENT_REPEAT 2 21#define EVENT_PENUP 3 22 23struct migor_ts_priv { 24 struct i2c_client *client; 25 struct input_dev *input; 26 int irq; 27}; 28 29static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11, 30 0x01, 0x06, 0x07, }; 31static const u_int8_t migor_ts_dis_seq[17] = { }; 32 33static irqreturn_t migor_ts_isr(int irq, void *dev_id) 34{ 35 struct migor_ts_priv *priv = dev_id; 36 unsigned short xpos, ypos; 37 unsigned char event; 38 u_int8_t buf[16]; 39 40 /* 41 * The touch screen controller chip is hooked up to the CPU 42 * using I2C and a single interrupt line. The interrupt line 43 * is pulled low whenever someone taps the screen. To deassert 44 * the interrupt line we need to acknowledge the interrupt by 45 * communicating with the controller over the slow i2c bus. 46 * 47 * Since I2C bus controller may sleep we are using threaded 48 * IRQ here. 49 */ 50 51 memset(buf, 0, sizeof(buf)); 52 53 /* Set Index 0 */ 54 buf[0] = 0; 55 if (i2c_master_send(priv->client, buf, 1) != 1) { 56 dev_err(&priv->client->dev, "Unable to write i2c index\n"); 57 goto out; 58 } 59 60 /* Now do Page Read */ 61 if (i2c_master_recv(priv->client, buf, sizeof(buf)) != sizeof(buf)) { 62 dev_err(&priv->client->dev, "Unable to read i2c page\n"); 63 goto out; 64 } 65 66 ypos = ((buf[9] & 0x03) << 8 | buf[8]); 67 xpos = ((buf[11] & 0x03) << 8 | buf[10]); 68 event = buf[12]; 69 70 switch (event) { 71 case EVENT_PENDOWN: 72 case EVENT_REPEAT: 73 input_report_key(priv->input, BTN_TOUCH, 1); 74 input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/ 75 input_report_abs(priv->input, ABS_Y, xpos); 76 input_sync(priv->input); 77 break; 78 79 case EVENT_PENUP: 80 input_report_key(priv->input, BTN_TOUCH, 0); 81 input_sync(priv->input); 82 break; 83 } 84 85 out: 86 return IRQ_HANDLED; 87} 88 89static int migor_ts_open(struct input_dev *dev) 90{ 91 struct migor_ts_priv *priv = input_get_drvdata(dev); 92 struct i2c_client *client = priv->client; 93 int count; 94 95 /* enable controller */ 96 count = i2c_master_send(client, migor_ts_ena_seq, 97 sizeof(migor_ts_ena_seq)); 98 if (count != sizeof(migor_ts_ena_seq)) { 99 dev_err(&client->dev, "Unable to enable touchscreen.\n"); 100 return -ENXIO; 101 } 102 103 return 0; 104} 105 106static void migor_ts_close(struct input_dev *dev) 107{ 108 struct migor_ts_priv *priv = input_get_drvdata(dev); 109 struct i2c_client *client = priv->client; 110 111 disable_irq(priv->irq); 112 113 /* disable controller */ 114 i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq)); 115 116 enable_irq(priv->irq); 117} 118 119static int migor_ts_probe(struct i2c_client *client, 120 const struct i2c_device_id *idp) 121{ 122 struct migor_ts_priv *priv; 123 struct input_dev *input; 124 int error; 125 126 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 127 input = input_allocate_device(); 128 if (!priv || !input) { 129 dev_err(&client->dev, "failed to allocate memory\n"); 130 error = -ENOMEM; 131 goto err_free_mem; 132 } 133 134 priv->client = client; 135 priv->input = input; 136 priv->irq = client->irq; 137 138 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 139 140 __set_bit(BTN_TOUCH, input->keybit); 141 142 input_set_abs_params(input, ABS_X, 95, 955, 0, 0); 143 input_set_abs_params(input, ABS_Y, 85, 935, 0, 0); 144 145 input->name = client->name; 146 input->id.bustype = BUS_I2C; 147 input->dev.parent = &client->dev; 148 149 input->open = migor_ts_open; 150 input->close = migor_ts_close; 151 152 input_set_drvdata(input, priv); 153 154 error = request_threaded_irq(priv->irq, NULL, migor_ts_isr, 155 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 156 client->name, priv); 157 if (error) { 158 dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); 159 goto err_free_mem; 160 } 161 162 error = input_register_device(input); 163 if (error) 164 goto err_free_irq; 165 166 i2c_set_clientdata(client, priv); 167 device_init_wakeup(&client->dev, 1); 168 169 return 0; 170 171 err_free_irq: 172 free_irq(priv->irq, priv); 173 err_free_mem: 174 input_free_device(input); 175 kfree(priv); 176 return error; 177} 178 179static int migor_ts_remove(struct i2c_client *client) 180{ 181 struct migor_ts_priv *priv = i2c_get_clientdata(client); 182 183 free_irq(priv->irq, priv); 184 input_unregister_device(priv->input); 185 kfree(priv); 186 187 dev_set_drvdata(&client->dev, NULL); 188 189 return 0; 190} 191 192static int __maybe_unused migor_ts_suspend(struct device *dev) 193{ 194 struct i2c_client *client = to_i2c_client(dev); 195 struct migor_ts_priv *priv = i2c_get_clientdata(client); 196 197 if (device_may_wakeup(&client->dev)) 198 enable_irq_wake(priv->irq); 199 200 return 0; 201} 202 203static int __maybe_unused migor_ts_resume(struct device *dev) 204{ 205 struct i2c_client *client = to_i2c_client(dev); 206 struct migor_ts_priv *priv = i2c_get_clientdata(client); 207 208 if (device_may_wakeup(&client->dev)) 209 disable_irq_wake(priv->irq); 210 211 return 0; 212} 213 214static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume); 215 216static const struct i2c_device_id migor_ts_id[] = { 217 { "migor_ts", 0 }, 218 { } 219}; 220MODULE_DEVICE_TABLE(i2c, migor_ts_id); 221 222static struct i2c_driver migor_ts_driver = { 223 .driver = { 224 .name = "migor_ts", 225 .pm = &migor_ts_pm, 226 }, 227 .probe = migor_ts_probe, 228 .remove = migor_ts_remove, 229 .id_table = migor_ts_id, 230}; 231 232module_i2c_driver(migor_ts_driver); 233 234MODULE_DESCRIPTION("MigoR Touchscreen driver"); 235MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); 236MODULE_LICENSE("GPL");