160347c19SSamuli Konttila /* 260347c19SSamuli Konttila * Driver for cypress touch screen controller 360347c19SSamuli Konttila * 460347c19SSamuli Konttila * Copyright (c) 2009 Aava Mobile 560347c19SSamuli Konttila * 660347c19SSamuli Konttila * Some cleanups by Alan Cox <alan@linux.intel.com> 760347c19SSamuli Konttila * 860347c19SSamuli Konttila * This program is free software; you can redistribute it and/or modify 960347c19SSamuli Konttila * it under the terms of the GNU General Public License version 2 as 1060347c19SSamuli Konttila * published by the Free Software Foundation. 1160347c19SSamuli Konttila * 1260347c19SSamuli Konttila * This program is distributed in the hope that it will be useful, 1360347c19SSamuli Konttila * but WITHOUT ANY WARRANTY; without even the implied warranty of 1460347c19SSamuli Konttila * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1560347c19SSamuli Konttila * GNU General Public License for more details. 1660347c19SSamuli Konttila * 1760347c19SSamuli Konttila * You should have received a copy of the GNU General Public License 1860347c19SSamuli Konttila * along with this program; if not, write to the Free Software 1960347c19SSamuli Konttila * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2060347c19SSamuli Konttila */ 2160347c19SSamuli Konttila 2260347c19SSamuli Konttila #include <linux/module.h> 2360347c19SSamuli Konttila #include <linux/kernel.h> 2460347c19SSamuli Konttila #include <linux/input.h> 2560347c19SSamuli Konttila #include <linux/slab.h> 2660347c19SSamuli Konttila #include <linux/interrupt.h> 2760347c19SSamuli Konttila #include <linux/io.h> 2860347c19SSamuli Konttila #include <linux/i2c.h> 2960347c19SSamuli Konttila #include <linux/gpio.h> 3060347c19SSamuli Konttila #include <linux/input/cy8ctmg110_pdata.h> 3160347c19SSamuli Konttila 3260347c19SSamuli Konttila #define CY8CTMG110_DRIVER_NAME "cy8ctmg110" 3360347c19SSamuli Konttila 3460347c19SSamuli Konttila /* Touch coordinates */ 3560347c19SSamuli Konttila #define CY8CTMG110_X_MIN 0 3660347c19SSamuli Konttila #define CY8CTMG110_Y_MIN 0 3760347c19SSamuli Konttila #define CY8CTMG110_X_MAX 759 3860347c19SSamuli Konttila #define CY8CTMG110_Y_MAX 465 3960347c19SSamuli Konttila 4060347c19SSamuli Konttila 4160347c19SSamuli Konttila /* cy8ctmg110 register definitions */ 4260347c19SSamuli Konttila #define CY8CTMG110_TOUCH_WAKEUP_TIME 0 4360347c19SSamuli Konttila #define CY8CTMG110_TOUCH_SLEEP_TIME 2 4460347c19SSamuli Konttila #define CY8CTMG110_TOUCH_X1 3 4560347c19SSamuli Konttila #define CY8CTMG110_TOUCH_Y1 5 4660347c19SSamuli Konttila #define CY8CTMG110_TOUCH_X2 7 4760347c19SSamuli Konttila #define CY8CTMG110_TOUCH_Y2 9 4860347c19SSamuli Konttila #define CY8CTMG110_FINGERS 11 4960347c19SSamuli Konttila #define CY8CTMG110_GESTURE 12 5060347c19SSamuli Konttila #define CY8CTMG110_REG_MAX 13 5160347c19SSamuli Konttila 5260347c19SSamuli Konttila 5360347c19SSamuli Konttila /* 5460347c19SSamuli Konttila * The touch driver structure. 5560347c19SSamuli Konttila */ 5660347c19SSamuli Konttila struct cy8ctmg110 { 5760347c19SSamuli Konttila struct input_dev *input; 5860347c19SSamuli Konttila char phys[32]; 5960347c19SSamuli Konttila struct i2c_client *client; 6060347c19SSamuli Konttila int reset_pin; 6160347c19SSamuli Konttila int irq_pin; 6260347c19SSamuli Konttila }; 6360347c19SSamuli Konttila 6460347c19SSamuli Konttila /* 6560347c19SSamuli Konttila * cy8ctmg110_power is the routine that is called when touch hardware 6660347c19SSamuli Konttila * will powered off or on. 6760347c19SSamuli Konttila */ 6860347c19SSamuli Konttila static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron) 6960347c19SSamuli Konttila { 7060347c19SSamuli Konttila if (ts->reset_pin) 7160347c19SSamuli Konttila gpio_direction_output(ts->reset_pin, 1 - poweron); 7260347c19SSamuli Konttila } 7360347c19SSamuli Konttila 7460347c19SSamuli Konttila static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg, 7560347c19SSamuli Konttila unsigned char len, unsigned char *value) 7660347c19SSamuli Konttila { 7760347c19SSamuli Konttila struct i2c_client *client = tsc->client; 78f1b50760SDan Carpenter int ret; 7960347c19SSamuli Konttila unsigned char i2c_data[6]; 8060347c19SSamuli Konttila 8160347c19SSamuli Konttila BUG_ON(len > 5); 8260347c19SSamuli Konttila 8360347c19SSamuli Konttila i2c_data[0] = reg; 8460347c19SSamuli Konttila memcpy(i2c_data + 1, value, len); 8560347c19SSamuli Konttila 8660347c19SSamuli Konttila ret = i2c_master_send(client, i2c_data, len + 1); 8721184c4eSAxel Lin if (ret != len + 1) { 8860347c19SSamuli Konttila dev_err(&client->dev, "i2c write data cmd failed\n"); 8921184c4eSAxel Lin return ret < 0 ? ret : -EIO; 9060347c19SSamuli Konttila } 9160347c19SSamuli Konttila 9260347c19SSamuli Konttila return 0; 9360347c19SSamuli Konttila } 9460347c19SSamuli Konttila 9560347c19SSamuli Konttila static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc, 9660347c19SSamuli Konttila unsigned char *data, unsigned char len, unsigned char cmd) 9760347c19SSamuli Konttila { 9860347c19SSamuli Konttila struct i2c_client *client = tsc->client; 99f1b50760SDan Carpenter int ret; 10060347c19SSamuli Konttila struct i2c_msg msg[2] = { 10160347c19SSamuli Konttila /* first write slave position to i2c devices */ 1029493d974SShubhrajyoti Datta { 1039493d974SShubhrajyoti Datta .addr = client->addr, 1049493d974SShubhrajyoti Datta .len = 1, 1059493d974SShubhrajyoti Datta .buf = &cmd 1069493d974SShubhrajyoti Datta }, 10760347c19SSamuli Konttila /* Second read data from position */ 1089493d974SShubhrajyoti Datta { 1099493d974SShubhrajyoti Datta .addr = client->addr, 1109493d974SShubhrajyoti Datta .flags = I2C_M_RD, 1119493d974SShubhrajyoti Datta .len = len, 1129493d974SShubhrajyoti Datta .buf = data 1139493d974SShubhrajyoti Datta } 11460347c19SSamuli Konttila }; 11560347c19SSamuli Konttila 11660347c19SSamuli Konttila ret = i2c_transfer(client->adapter, msg, 2); 11760347c19SSamuli Konttila if (ret < 0) 11860347c19SSamuli Konttila return ret; 11960347c19SSamuli Konttila 12060347c19SSamuli Konttila return 0; 12160347c19SSamuli Konttila } 12260347c19SSamuli Konttila 12360347c19SSamuli Konttila static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc) 12460347c19SSamuli Konttila { 12560347c19SSamuli Konttila struct input_dev *input = tsc->input; 12660347c19SSamuli Konttila unsigned char reg_p[CY8CTMG110_REG_MAX]; 12760347c19SSamuli Konttila int x, y; 12860347c19SSamuli Konttila 12960347c19SSamuli Konttila memset(reg_p, 0, CY8CTMG110_REG_MAX); 13060347c19SSamuli Konttila 13160347c19SSamuli Konttila /* Reading coordinates */ 13260347c19SSamuli Konttila if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0) 13360347c19SSamuli Konttila return -EIO; 13460347c19SSamuli Konttila 13560347c19SSamuli Konttila y = reg_p[2] << 8 | reg_p[3]; 13660347c19SSamuli Konttila x = reg_p[0] << 8 | reg_p[1]; 13760347c19SSamuli Konttila 13860347c19SSamuli Konttila /* Number of touch */ 13960347c19SSamuli Konttila if (reg_p[8] == 0) { 14060347c19SSamuli Konttila input_report_key(input, BTN_TOUCH, 0); 14160347c19SSamuli Konttila } else { 14260347c19SSamuli Konttila input_report_key(input, BTN_TOUCH, 1); 14360347c19SSamuli Konttila input_report_abs(input, ABS_X, x); 14460347c19SSamuli Konttila input_report_abs(input, ABS_Y, y); 14560347c19SSamuli Konttila } 14660347c19SSamuli Konttila 14760347c19SSamuli Konttila input_sync(input); 14860347c19SSamuli Konttila 14960347c19SSamuli Konttila return 0; 15060347c19SSamuli Konttila } 15160347c19SSamuli Konttila 15260347c19SSamuli Konttila static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep) 15360347c19SSamuli Konttila { 15460347c19SSamuli Konttila unsigned char reg_p[3]; 15560347c19SSamuli Konttila 15660347c19SSamuli Konttila if (sleep) { 15760347c19SSamuli Konttila reg_p[0] = 0x00; 15860347c19SSamuli Konttila reg_p[1] = 0xff; 15960347c19SSamuli Konttila reg_p[2] = 5; 16060347c19SSamuli Konttila } else { 16160347c19SSamuli Konttila reg_p[0] = 0x10; 16260347c19SSamuli Konttila reg_p[1] = 0xff; 16360347c19SSamuli Konttila reg_p[2] = 0; 16460347c19SSamuli Konttila } 16560347c19SSamuli Konttila 16660347c19SSamuli Konttila return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p); 16760347c19SSamuli Konttila } 16860347c19SSamuli Konttila 16960347c19SSamuli Konttila static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id) 17060347c19SSamuli Konttila { 17160347c19SSamuli Konttila struct cy8ctmg110 *tsc = dev_id; 17260347c19SSamuli Konttila 17360347c19SSamuli Konttila cy8ctmg110_touch_pos(tsc); 17460347c19SSamuli Konttila 17560347c19SSamuli Konttila return IRQ_HANDLED; 17660347c19SSamuli Konttila } 17760347c19SSamuli Konttila 17860347c19SSamuli Konttila static int __devinit cy8ctmg110_probe(struct i2c_client *client, 17960347c19SSamuli Konttila const struct i2c_device_id *id) 18060347c19SSamuli Konttila { 18160347c19SSamuli Konttila const struct cy8ctmg110_pdata *pdata = client->dev.platform_data; 18260347c19SSamuli Konttila struct cy8ctmg110 *ts; 18360347c19SSamuli Konttila struct input_dev *input_dev; 18460347c19SSamuli Konttila int err; 18560347c19SSamuli Konttila 18660347c19SSamuli Konttila /* No pdata no way forward */ 18760347c19SSamuli Konttila if (pdata == NULL) { 18860347c19SSamuli Konttila dev_err(&client->dev, "no pdata\n"); 18960347c19SSamuli Konttila return -ENODEV; 19060347c19SSamuli Konttila } 19160347c19SSamuli Konttila 19260347c19SSamuli Konttila if (!i2c_check_functionality(client->adapter, 19360347c19SSamuli Konttila I2C_FUNC_SMBUS_READ_WORD_DATA)) 19460347c19SSamuli Konttila return -EIO; 19560347c19SSamuli Konttila 19660347c19SSamuli Konttila ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL); 19760347c19SSamuli Konttila input_dev = input_allocate_device(); 19860347c19SSamuli Konttila if (!ts || !input_dev) { 19960347c19SSamuli Konttila err = -ENOMEM; 20060347c19SSamuli Konttila goto err_free_mem; 20160347c19SSamuli Konttila } 20260347c19SSamuli Konttila 20360347c19SSamuli Konttila ts->client = client; 20460347c19SSamuli Konttila ts->input = input_dev; 2052c204109SAxel Lin ts->reset_pin = pdata->reset_pin; 2062c204109SAxel Lin ts->irq_pin = pdata->irq_pin; 20760347c19SSamuli Konttila 20860347c19SSamuli Konttila snprintf(ts->phys, sizeof(ts->phys), 20960347c19SSamuli Konttila "%s/input0", dev_name(&client->dev)); 21060347c19SSamuli Konttila 21160347c19SSamuli Konttila input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen"; 21260347c19SSamuli Konttila input_dev->phys = ts->phys; 21360347c19SSamuli Konttila input_dev->id.bustype = BUS_I2C; 21460347c19SSamuli Konttila input_dev->dev.parent = &client->dev; 21560347c19SSamuli Konttila 21660347c19SSamuli Konttila input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 21760347c19SSamuli Konttila input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 21860347c19SSamuli Konttila 21960347c19SSamuli Konttila input_set_abs_params(input_dev, ABS_X, 220a4e6aad6SJames Ketrenos CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0); 22160347c19SSamuli Konttila input_set_abs_params(input_dev, ABS_Y, 222a4e6aad6SJames Ketrenos CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0); 22360347c19SSamuli Konttila 22460347c19SSamuli Konttila if (ts->reset_pin) { 22560347c19SSamuli Konttila err = gpio_request(ts->reset_pin, NULL); 22660347c19SSamuli Konttila if (err) { 22760347c19SSamuli Konttila dev_err(&client->dev, 22860347c19SSamuli Konttila "Unable to request GPIO pin %d.\n", 22960347c19SSamuli Konttila ts->reset_pin); 23060347c19SSamuli Konttila goto err_free_mem; 23160347c19SSamuli Konttila } 23260347c19SSamuli Konttila } 23360347c19SSamuli Konttila 23460347c19SSamuli Konttila cy8ctmg110_power(ts, true); 23560347c19SSamuli Konttila cy8ctmg110_set_sleepmode(ts, false); 23660347c19SSamuli Konttila 23760347c19SSamuli Konttila err = gpio_request(ts->irq_pin, "touch_irq_key"); 23860347c19SSamuli Konttila if (err < 0) { 23960347c19SSamuli Konttila dev_err(&client->dev, 24060347c19SSamuli Konttila "Failed to request GPIO %d, error %d\n", 24160347c19SSamuli Konttila ts->irq_pin, err); 24260347c19SSamuli Konttila goto err_shutoff_device; 24360347c19SSamuli Konttila } 24460347c19SSamuli Konttila 24560347c19SSamuli Konttila err = gpio_direction_input(ts->irq_pin); 24660347c19SSamuli Konttila if (err < 0) { 24760347c19SSamuli Konttila dev_err(&client->dev, 24860347c19SSamuli Konttila "Failed to configure input direction for GPIO %d, error %d\n", 24960347c19SSamuli Konttila ts->irq_pin, err); 25060347c19SSamuli Konttila goto err_free_irq_gpio; 25160347c19SSamuli Konttila } 25260347c19SSamuli Konttila 25360347c19SSamuli Konttila client->irq = gpio_to_irq(ts->irq_pin); 25460347c19SSamuli Konttila if (client->irq < 0) { 25560347c19SSamuli Konttila err = client->irq; 25660347c19SSamuli Konttila dev_err(&client->dev, 25760347c19SSamuli Konttila "Unable to get irq number for GPIO %d, error %d\n", 25860347c19SSamuli Konttila ts->irq_pin, err); 25960347c19SSamuli Konttila goto err_free_irq_gpio; 26060347c19SSamuli Konttila } 26160347c19SSamuli Konttila 26260347c19SSamuli Konttila err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread, 2639b7e31bbSLars-Peter Clausen IRQF_TRIGGER_RISING | IRQF_ONESHOT, 2649b7e31bbSLars-Peter Clausen "touch_reset_key", ts); 26560347c19SSamuli Konttila if (err < 0) { 26660347c19SSamuli Konttila dev_err(&client->dev, 26760347c19SSamuli Konttila "irq %d busy? error %d\n", client->irq, err); 26860347c19SSamuli Konttila goto err_free_irq_gpio; 26960347c19SSamuli Konttila } 27060347c19SSamuli Konttila 27160347c19SSamuli Konttila err = input_register_device(input_dev); 27260347c19SSamuli Konttila if (err) 27360347c19SSamuli Konttila goto err_free_irq; 27460347c19SSamuli Konttila 27560347c19SSamuli Konttila i2c_set_clientdata(client, ts); 27660347c19SSamuli Konttila device_init_wakeup(&client->dev, 1); 27760347c19SSamuli Konttila return 0; 27860347c19SSamuli Konttila 27960347c19SSamuli Konttila err_free_irq: 28060347c19SSamuli Konttila free_irq(client->irq, ts); 28160347c19SSamuli Konttila err_free_irq_gpio: 28260347c19SSamuli Konttila gpio_free(ts->irq_pin); 28360347c19SSamuli Konttila err_shutoff_device: 28460347c19SSamuli Konttila cy8ctmg110_set_sleepmode(ts, true); 28560347c19SSamuli Konttila cy8ctmg110_power(ts, false); 28660347c19SSamuli Konttila if (ts->reset_pin) 28760347c19SSamuli Konttila gpio_free(ts->reset_pin); 28860347c19SSamuli Konttila err_free_mem: 28960347c19SSamuli Konttila input_free_device(input_dev); 29060347c19SSamuli Konttila kfree(ts); 29160347c19SSamuli Konttila return err; 29260347c19SSamuli Konttila } 29360347c19SSamuli Konttila 29460347c19SSamuli Konttila #ifdef CONFIG_PM 29593f38e91SMark Brown static int cy8ctmg110_suspend(struct device *dev) 29660347c19SSamuli Konttila { 29793f38e91SMark Brown struct i2c_client *client = to_i2c_client(dev); 29860347c19SSamuli Konttila struct cy8ctmg110 *ts = i2c_get_clientdata(client); 29960347c19SSamuli Konttila 30060347c19SSamuli Konttila if (device_may_wakeup(&client->dev)) 30160347c19SSamuli Konttila enable_irq_wake(client->irq); 30260347c19SSamuli Konttila else { 30360347c19SSamuli Konttila cy8ctmg110_set_sleepmode(ts, true); 30460347c19SSamuli Konttila cy8ctmg110_power(ts, false); 30560347c19SSamuli Konttila } 30660347c19SSamuli Konttila return 0; 30760347c19SSamuli Konttila } 30860347c19SSamuli Konttila 30993f38e91SMark Brown static int cy8ctmg110_resume(struct device *dev) 31060347c19SSamuli Konttila { 31193f38e91SMark Brown struct i2c_client *client = to_i2c_client(dev); 31260347c19SSamuli Konttila struct cy8ctmg110 *ts = i2c_get_clientdata(client); 31360347c19SSamuli Konttila 31460347c19SSamuli Konttila if (device_may_wakeup(&client->dev)) 31560347c19SSamuli Konttila disable_irq_wake(client->irq); 31660347c19SSamuli Konttila else { 31760347c19SSamuli Konttila cy8ctmg110_power(ts, true); 31860347c19SSamuli Konttila cy8ctmg110_set_sleepmode(ts, false); 31960347c19SSamuli Konttila } 32060347c19SSamuli Konttila return 0; 32160347c19SSamuli Konttila } 32293f38e91SMark Brown 32393f38e91SMark Brown static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); 32460347c19SSamuli Konttila #endif 32560347c19SSamuli Konttila 32660347c19SSamuli Konttila static int __devexit cy8ctmg110_remove(struct i2c_client *client) 32760347c19SSamuli Konttila { 32860347c19SSamuli Konttila struct cy8ctmg110 *ts = i2c_get_clientdata(client); 32960347c19SSamuli Konttila 33060347c19SSamuli Konttila cy8ctmg110_set_sleepmode(ts, true); 33160347c19SSamuli Konttila cy8ctmg110_power(ts, false); 33260347c19SSamuli Konttila 33360347c19SSamuli Konttila free_irq(client->irq, ts); 33460347c19SSamuli Konttila input_unregister_device(ts->input); 33560347c19SSamuli Konttila gpio_free(ts->irq_pin); 33660347c19SSamuli Konttila if (ts->reset_pin) 33760347c19SSamuli Konttila gpio_free(ts->reset_pin); 33860347c19SSamuli Konttila kfree(ts); 33960347c19SSamuli Konttila 34060347c19SSamuli Konttila return 0; 34160347c19SSamuli Konttila } 34260347c19SSamuli Konttila 343d448303aSAxel Lin static const struct i2c_device_id cy8ctmg110_idtable[] = { 34460347c19SSamuli Konttila { CY8CTMG110_DRIVER_NAME, 1 }, 34560347c19SSamuli Konttila { } 34660347c19SSamuli Konttila }; 34760347c19SSamuli Konttila 34860347c19SSamuli Konttila MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable); 34960347c19SSamuli Konttila 35060347c19SSamuli Konttila static struct i2c_driver cy8ctmg110_driver = { 35160347c19SSamuli Konttila .driver = { 35260347c19SSamuli Konttila .owner = THIS_MODULE, 35360347c19SSamuli Konttila .name = CY8CTMG110_DRIVER_NAME, 35493f38e91SMark Brown #ifdef CONFIG_PM 35593f38e91SMark Brown .pm = &cy8ctmg110_pm, 35693f38e91SMark Brown #endif 35760347c19SSamuli Konttila }, 35860347c19SSamuli Konttila .id_table = cy8ctmg110_idtable, 35960347c19SSamuli Konttila .probe = cy8ctmg110_probe, 3601cb0aa88SBill Pemberton .remove = cy8ctmg110_remove, 36160347c19SSamuli Konttila }; 36260347c19SSamuli Konttila 3631b92c1cfSAxel Lin module_i2c_driver(cy8ctmg110_driver); 36460347c19SSamuli Konttila 36560347c19SSamuli Konttila MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>"); 36660347c19SSamuli Konttila MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver"); 36760347c19SSamuli Konttila MODULE_LICENSE("GPL v2"); 368