Path: blob/master/drivers/input/touchscreen/bu21013_ts.c
15111 views
/*1* Copyright (C) ST-Ericsson SA 20102* Author: Naveen Kumar G <[email protected]> for ST-Ericsson3* License terms:GNU General Public License (GPL) version 24*/56#include <linux/kernel.h>7#include <linux/delay.h>8#include <linux/interrupt.h>9#include <linux/i2c.h>10#include <linux/workqueue.h>11#include <linux/input.h>12#include <linux/input/bu21013.h>13#include <linux/slab.h>14#include <linux/regulator/consumer.h>1516#define PEN_DOWN_INTR 017#define MAX_FINGERS 218#define RESET_DELAY 3019#define PENUP_TIMEOUT (10)20#define DELTA_MIN 1621#define MASK_BITS 0x0322#define SHIFT_8 823#define SHIFT_2 224#define LENGTH_OF_BUFFER 1125#define I2C_RETRY_COUNT 52627#define BU21013_SENSORS_BTN_0_7_REG 0x7028#define BU21013_SENSORS_BTN_8_15_REG 0x7129#define BU21013_SENSORS_BTN_16_23_REG 0x7230#define BU21013_X1_POS_MSB_REG 0x7331#define BU21013_X1_POS_LSB_REG 0x7432#define BU21013_Y1_POS_MSB_REG 0x7533#define BU21013_Y1_POS_LSB_REG 0x7634#define BU21013_X2_POS_MSB_REG 0x7735#define BU21013_X2_POS_LSB_REG 0x7836#define BU21013_Y2_POS_MSB_REG 0x7937#define BU21013_Y2_POS_LSB_REG 0x7A38#define BU21013_INT_CLR_REG 0xE839#define BU21013_INT_MODE_REG 0xE940#define BU21013_GAIN_REG 0xEA41#define BU21013_OFFSET_MODE_REG 0xEB42#define BU21013_XY_EDGE_REG 0xEC43#define BU21013_RESET_REG 0xED44#define BU21013_CALIB_REG 0xEE45#define BU21013_DONE_REG 0xEF46#define BU21013_SENSOR_0_7_REG 0xF047#define BU21013_SENSOR_8_15_REG 0xF148#define BU21013_SENSOR_16_23_REG 0xF249#define BU21013_POS_MODE1_REG 0xF350#define BU21013_POS_MODE2_REG 0xF451#define BU21013_CLK_MODE_REG 0xF552#define BU21013_IDLE_REG 0xFA53#define BU21013_FILTER_REG 0xFB54#define BU21013_TH_ON_REG 0xFC55#define BU21013_TH_OFF_REG 0xFD565758#define BU21013_RESET_ENABLE 0x015960#define BU21013_SENSORS_EN_0_7 0x3F61#define BU21013_SENSORS_EN_8_15 0xFC62#define BU21013_SENSORS_EN_16_23 0x1F6364#define BU21013_POS_MODE1_0 0x0265#define BU21013_POS_MODE1_1 0x0466#define BU21013_POS_MODE1_2 0x086768#define BU21013_POS_MODE2_ZERO 0x0169#define BU21013_POS_MODE2_AVG1 0x0270#define BU21013_POS_MODE2_AVG2 0x0471#define BU21013_POS_MODE2_EN_XY 0x0872#define BU21013_POS_MODE2_EN_RAW 0x1073#define BU21013_POS_MODE2_MULTI 0x807475#define BU21013_CLK_MODE_DIV 0x0176#define BU21013_CLK_MODE_EXT 0x0277#define BU21013_CLK_MODE_CALIB 0x807879#define BU21013_IDLET_0 0x0180#define BU21013_IDLET_1 0x0281#define BU21013_IDLET_2 0x0482#define BU21013_IDLET_3 0x0883#define BU21013_IDLE_INTERMIT_EN 0x108485#define BU21013_DELTA_0_6 0x7F86#define BU21013_FILTER_EN 0x808788#define BU21013_INT_MODE_LEVEL 0x0089#define BU21013_INT_MODE_EDGE 0x019091#define BU21013_GAIN_0 0x0192#define BU21013_GAIN_1 0x0293#define BU21013_GAIN_2 0x049495#define BU21013_OFFSET_MODE_DEFAULT 0x0096#define BU21013_OFFSET_MODE_MOVE 0x0197#define BU21013_OFFSET_MODE_DISABLE 0x029899#define BU21013_TH_ON_0 0x01100#define BU21013_TH_ON_1 0x02101#define BU21013_TH_ON_2 0x04102#define BU21013_TH_ON_3 0x08103#define BU21013_TH_ON_4 0x10104#define BU21013_TH_ON_5 0x20105#define BU21013_TH_ON_6 0x40106#define BU21013_TH_ON_7 0x80107#define BU21013_TH_ON_MAX 0xFF108109#define BU21013_TH_OFF_0 0x01110#define BU21013_TH_OFF_1 0x02111#define BU21013_TH_OFF_2 0x04112#define BU21013_TH_OFF_3 0x08113#define BU21013_TH_OFF_4 0x10114#define BU21013_TH_OFF_5 0x20115#define BU21013_TH_OFF_6 0x40116#define BU21013_TH_OFF_7 0x80117#define BU21013_TH_OFF_MAX 0xFF118119#define BU21013_X_EDGE_0 0x01120#define BU21013_X_EDGE_1 0x02121#define BU21013_X_EDGE_2 0x04122#define BU21013_X_EDGE_3 0x08123#define BU21013_Y_EDGE_0 0x10124#define BU21013_Y_EDGE_1 0x20125#define BU21013_Y_EDGE_2 0x40126#define BU21013_Y_EDGE_3 0x80127128#define BU21013_DONE 0x01129#define BU21013_NUMBER_OF_X_SENSORS (6)130#define BU21013_NUMBER_OF_Y_SENSORS (11)131132#define DRIVER_TP "bu21013_tp"133134/**135* struct bu21013_ts_data - touch panel data structure136* @client: pointer to the i2c client137* @wait: variable to wait_queue_head_t structure138* @touch_stopped: touch stop flag139* @chip: pointer to the touch panel controller140* @in_dev: pointer to the input device structure141* @intr_pin: interrupt pin value142* @regulator: pointer to the Regulator used for touch screen143*144* Touch panel device data structure145*/146struct bu21013_ts_data {147struct i2c_client *client;148wait_queue_head_t wait;149bool touch_stopped;150const struct bu21013_platform_device *chip;151struct input_dev *in_dev;152unsigned int intr_pin;153struct regulator *regulator;154};155156/**157* bu21013_read_block_data(): read the touch co-ordinates158* @data: bu21013_ts_data structure pointer159* @buf: byte pointer160*161* Read the touch co-ordinates using i2c read block into buffer162* and returns integer.163*/164static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)165{166int ret, i;167168for (i = 0; i < I2C_RETRY_COUNT; i++) {169ret = i2c_smbus_read_i2c_block_data170(data->client, BU21013_SENSORS_BTN_0_7_REG,171LENGTH_OF_BUFFER, buf);172if (ret == LENGTH_OF_BUFFER)173return 0;174}175return -EINVAL;176}177178/**179* bu21013_do_touch_report(): Get the touch co-ordinates180* @data: bu21013_ts_data structure pointer181*182* Get the touch co-ordinates from touch sensor registers and writes183* into device structure and returns integer.184*/185static int bu21013_do_touch_report(struct bu21013_ts_data *data)186{187u8 buf[LENGTH_OF_BUFFER];188unsigned int pos_x[2], pos_y[2];189bool has_x_sensors, has_y_sensors;190int finger_down_count = 0;191int i;192193if (data == NULL)194return -EINVAL;195196if (bu21013_read_block_data(data, buf) < 0)197return -EINVAL;198199has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);200has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |201((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);202if (!has_x_sensors || !has_y_sensors)203return 0;204205for (i = 0; i < MAX_FINGERS; i++) {206const u8 *p = &buf[4 * i + 3];207unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);208unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);209if (x == 0 || y == 0)210continue;211pos_x[finger_down_count] = x;212pos_y[finger_down_count] = y;213finger_down_count++;214}215216if (finger_down_count) {217if (finger_down_count == 2 &&218(abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||219abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {220return 0;221}222223for (i = 0; i < finger_down_count; i++) {224if (data->chip->x_flip)225pos_x[i] = data->chip->touch_x_max - pos_x[i];226if (data->chip->y_flip)227pos_y[i] = data->chip->touch_y_max - pos_y[i];228229input_report_abs(data->in_dev,230ABS_MT_POSITION_X, pos_x[i]);231input_report_abs(data->in_dev,232ABS_MT_POSITION_Y, pos_y[i]);233input_mt_sync(data->in_dev);234}235} else236input_mt_sync(data->in_dev);237238input_sync(data->in_dev);239240return 0;241}242/**243* bu21013_gpio_irq() - gpio thread function for touch interrupt244* @irq: irq value245* @device_data: void pointer246*247* This gpio thread function for touch interrupt248* and returns irqreturn_t.249*/250static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)251{252struct bu21013_ts_data *data = device_data;253struct i2c_client *i2c = data->client;254int retval;255256do {257retval = bu21013_do_touch_report(data);258if (retval < 0) {259dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");260return IRQ_NONE;261}262263data->intr_pin = data->chip->irq_read_val();264if (data->intr_pin == PEN_DOWN_INTR)265wait_event_timeout(data->wait, data->touch_stopped,266msecs_to_jiffies(2));267} while (!data->intr_pin && !data->touch_stopped);268269return IRQ_HANDLED;270}271272/**273* bu21013_init_chip() - power on sequence for the bu21013 controller274* @data: device structure pointer275*276* This function is used to power on277* the bu21013 controller and returns integer.278*/279static int bu21013_init_chip(struct bu21013_ts_data *data)280{281int retval;282struct i2c_client *i2c = data->client;283284retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,285BU21013_RESET_ENABLE);286if (retval < 0) {287dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");288return retval;289}290msleep(RESET_DELAY);291292retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,293BU21013_SENSORS_EN_0_7);294if (retval < 0) {295dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");296return retval;297}298299retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,300BU21013_SENSORS_EN_8_15);301if (retval < 0) {302dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");303return retval;304}305306retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,307BU21013_SENSORS_EN_16_23);308if (retval < 0) {309dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");310return retval;311}312313retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,314(BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));315if (retval < 0) {316dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");317return retval;318}319320retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,321(BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |322BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |323BU21013_POS_MODE2_MULTI));324if (retval < 0) {325dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");326return retval;327}328329if (data->chip->ext_clk)330retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,331(BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));332else333retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,334(BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));335if (retval < 0) {336dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");337return retval;338}339340retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,341(BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));342if (retval < 0) {343dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");344return retval;345}346347retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,348BU21013_INT_MODE_LEVEL);349if (retval < 0) {350dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");351return retval;352}353354retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,355(BU21013_DELTA_0_6 |356BU21013_FILTER_EN));357if (retval < 0) {358dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");359return retval;360}361362retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,363BU21013_TH_ON_5);364if (retval < 0) {365dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");366return retval;367}368369retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,370BU21013_TH_OFF_4 | BU21013_TH_OFF_3);371if (retval < 0) {372dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");373return retval;374}375376retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,377(BU21013_GAIN_0 | BU21013_GAIN_1));378if (retval < 0) {379dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");380return retval;381}382383retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,384BU21013_OFFSET_MODE_DEFAULT);385if (retval < 0) {386dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");387return retval;388}389390retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,391(BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |392BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));393if (retval < 0) {394dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");395return retval;396}397398retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,399BU21013_DONE);400if (retval < 0) {401dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");402return retval;403}404405return 0;406}407408/**409* bu21013_free_irq() - frees IRQ registered for touchscreen410* @bu21013_data: device structure pointer411*412* This function signals interrupt thread to stop processing and413* frees interrupt.414*/415static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)416{417bu21013_data->touch_stopped = true;418wake_up(&bu21013_data->wait);419free_irq(bu21013_data->chip->irq, bu21013_data);420}421422/**423* bu21013_probe() - initializes the i2c-client touchscreen driver424* @client: i2c client structure pointer425* @id: i2c device id pointer426*427* This function used to initializes the i2c-client touchscreen428* driver and returns integer.429*/430static int __devinit bu21013_probe(struct i2c_client *client,431const struct i2c_device_id *id)432{433struct bu21013_ts_data *bu21013_data;434struct input_dev *in_dev;435const struct bu21013_platform_device *pdata =436client->dev.platform_data;437int error;438439if (!i2c_check_functionality(client->adapter,440I2C_FUNC_SMBUS_BYTE_DATA)) {441dev_err(&client->dev, "i2c smbus byte data not supported\n");442return -EIO;443}444445if (!pdata) {446dev_err(&client->dev, "platform data not defined\n");447return -EINVAL;448}449450bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);451in_dev = input_allocate_device();452if (!bu21013_data || !in_dev) {453dev_err(&client->dev, "device memory alloc failed\n");454error = -ENOMEM;455goto err_free_mem;456}457458bu21013_data->in_dev = in_dev;459bu21013_data->chip = pdata;460bu21013_data->client = client;461462bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH");463if (IS_ERR(bu21013_data->regulator)) {464dev_err(&client->dev, "regulator_get failed\n");465error = PTR_ERR(bu21013_data->regulator);466goto err_free_mem;467}468469error = regulator_enable(bu21013_data->regulator);470if (error < 0) {471dev_err(&client->dev, "regulator enable failed\n");472goto err_put_regulator;473}474475bu21013_data->touch_stopped = false;476init_waitqueue_head(&bu21013_data->wait);477478/* configure the gpio pins */479if (pdata->cs_en) {480error = pdata->cs_en(pdata->cs_pin);481if (error < 0) {482dev_err(&client->dev, "chip init failed\n");483goto err_disable_regulator;484}485}486487/* configure the touch panel controller */488error = bu21013_init_chip(bu21013_data);489if (error) {490dev_err(&client->dev, "error in bu21013 config\n");491goto err_cs_disable;492}493494/* register the device to input subsystem */495in_dev->name = DRIVER_TP;496in_dev->id.bustype = BUS_I2C;497in_dev->dev.parent = &client->dev;498499__set_bit(EV_SYN, in_dev->evbit);500__set_bit(EV_KEY, in_dev->evbit);501__set_bit(EV_ABS, in_dev->evbit);502503input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,504pdata->touch_x_max, 0, 0);505input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,506pdata->touch_y_max, 0, 0);507input_set_drvdata(in_dev, bu21013_data);508509error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,510IRQF_TRIGGER_FALLING | IRQF_SHARED,511DRIVER_TP, bu21013_data);512if (error) {513dev_err(&client->dev, "request irq %d failed\n", pdata->irq);514goto err_cs_disable;515}516517error = input_register_device(in_dev);518if (error) {519dev_err(&client->dev, "failed to register input device\n");520goto err_free_irq;521}522523device_init_wakeup(&client->dev, pdata->wakeup);524i2c_set_clientdata(client, bu21013_data);525526return 0;527528err_free_irq:529bu21013_free_irq(bu21013_data);530err_cs_disable:531pdata->cs_dis(pdata->cs_pin);532err_disable_regulator:533regulator_disable(bu21013_data->regulator);534err_put_regulator:535regulator_put(bu21013_data->regulator);536err_free_mem:537input_free_device(in_dev);538kfree(bu21013_data);539540return error;541}542/**543* bu21013_remove() - removes the i2c-client touchscreen driver544* @client: i2c client structure pointer545*546* This function uses to remove the i2c-client547* touchscreen driver and returns integer.548*/549static int __devexit bu21013_remove(struct i2c_client *client)550{551struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);552553bu21013_free_irq(bu21013_data);554555bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);556557input_unregister_device(bu21013_data->in_dev);558559regulator_disable(bu21013_data->regulator);560regulator_put(bu21013_data->regulator);561562kfree(bu21013_data);563564device_init_wakeup(&client->dev, false);565566return 0;567}568569#ifdef CONFIG_PM570/**571* bu21013_suspend() - suspend the touch screen controller572* @dev: pointer to device structure573*574* This function is used to suspend the575* touch panel controller and returns integer576*/577static int bu21013_suspend(struct device *dev)578{579struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);580struct i2c_client *client = bu21013_data->client;581582bu21013_data->touch_stopped = true;583if (device_may_wakeup(&client->dev))584enable_irq_wake(bu21013_data->chip->irq);585else586disable_irq(bu21013_data->chip->irq);587588regulator_disable(bu21013_data->regulator);589590return 0;591}592593/**594* bu21013_resume() - resume the touch screen controller595* @dev: pointer to device structure596*597* This function is used to resume the touch panel598* controller and returns integer.599*/600static int bu21013_resume(struct device *dev)601{602struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);603struct i2c_client *client = bu21013_data->client;604int retval;605606retval = regulator_enable(bu21013_data->regulator);607if (retval < 0) {608dev_err(&client->dev, "bu21013 regulator enable failed\n");609return retval;610}611612retval = bu21013_init_chip(bu21013_data);613if (retval < 0) {614dev_err(&client->dev, "bu21013 controller config failed\n");615return retval;616}617618bu21013_data->touch_stopped = false;619620if (device_may_wakeup(&client->dev))621disable_irq_wake(bu21013_data->chip->irq);622else623enable_irq(bu21013_data->chip->irq);624625return 0;626}627628static const struct dev_pm_ops bu21013_dev_pm_ops = {629.suspend = bu21013_suspend,630.resume = bu21013_resume,631};632#endif633634static const struct i2c_device_id bu21013_id[] = {635{ DRIVER_TP, 0 },636{ }637};638MODULE_DEVICE_TABLE(i2c, bu21013_id);639640static struct i2c_driver bu21013_driver = {641.driver = {642.name = DRIVER_TP,643.owner = THIS_MODULE,644#ifdef CONFIG_PM645.pm = &bu21013_dev_pm_ops,646#endif647},648.probe = bu21013_probe,649.remove = __devexit_p(bu21013_remove),650.id_table = bu21013_id,651};652653/**654* bu21013_init() - initializes the bu21013 touchscreen driver655*656* This function used to initializes the bu21013657* touchscreen driver and returns integer.658*/659static int __init bu21013_init(void)660{661return i2c_add_driver(&bu21013_driver);662}663664/**665* bu21013_exit() - de-initializes the bu21013 touchscreen driver666*667* This function uses to de-initializes the bu21013668* touchscreen driver and returns none.669*/670static void __exit bu21013_exit(void)671{672i2c_del_driver(&bu21013_driver);673}674675module_init(bu21013_init);676module_exit(bu21013_exit);677678MODULE_LICENSE("GPL v2");679MODULE_AUTHOR("Naveen Kumar G <[email protected]>");680MODULE_DESCRIPTION("bu21013 touch screen controller driver");681682683