diff options
Diffstat (limited to 'drivers/input/touchscreen/synaptics_s7301.c')
-rw-r--r-- | drivers/input/touchscreen/synaptics_s7301.c | 740 |
1 files changed, 0 insertions, 740 deletions
diff --git a/drivers/input/touchscreen/synaptics_s7301.c b/drivers/input/touchscreen/synaptics_s7301.c deleted file mode 100644 index 2a0c756..0000000 --- a/drivers/input/touchscreen/synaptics_s7301.c +++ /dev/null @@ -1,740 +0,0 @@ -/* drivers/input/touchscreen/synaptics_s7301.c - * - * Copyright (C) 2012 Samsung Electronics, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/synaptics_s7301.h> - -#define REPORT_MT(x, y, z, w_max, w_min) \ -do { \ - input_report_abs(data->input, ABS_MT_POSITION_X, x); \ - input_report_abs(data->input, ABS_MT_POSITION_Y, y); \ - input_report_abs(data->input, ABS_MT_PRESSURE, z); \ - input_report_abs(data->input, ABS_MT_TOUCH_MAJOR, w_max); \ - input_report_abs(data->input, ABS_MT_TOUCH_MINOR, w_min); \ -} while (0) - -#define SET_FUNC_ADDR(num, page) \ -do { \ - data->f##num.query_base_addr = buffer[0] + page; \ - data->f##num.command_base_addr = buffer[1] + page; \ - data->f##num.control_base_addr = buffer[2] + page; \ - data->f##num.data_base_addr = buffer[3] + page; \ - if (!test_bit(buffer[5], data->func_bit)) { \ - __set_bit(buffer[5], data->func_bit); \ - cnt++; \ - } \ -} while (0) - -#define CHECK_PAGE(addr) ((addr >> 8) & 0xff) - -static void synaptics_ts_set_page(struct synaptics_drv_data *data, - u16 addr) -{ - u8 page = CHECK_PAGE(addr); - if (page != data->page) { - u8 buf[2] = {0xff, page}; - i2c_master_send(data->client, buf, sizeof(buf)); - data->page = page; - } -} - -int synaptics_ts_write_data(struct synaptics_drv_data *data, - u16 addr, u8 cmd) -{ - struct i2c_msg msg; - u8 buf[2]; - - synaptics_ts_set_page(data, addr); - - buf[0] = addr & 0xff; - buf[1] = cmd; - - msg.addr = data->client->addr; - msg.flags = data->client->flags & I2C_M_TEN; - msg.len = 2; - msg.buf = buf; - - return i2c_transfer(data->client->adapter, &msg, 1); -} - -int synaptics_ts_read_data(struct synaptics_drv_data *data, - u16 addr, u8 *buf) -{ - struct i2c_msg msg[2]; - - synaptics_ts_set_page(data, addr); - - msg[0].addr = data->client->addr; - msg[0].flags = 0x00; - msg[0].len = 1; - msg[0].buf = (u8 *) &addr; - - msg[1].addr = data->client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 1; - msg[1].buf = buf; - - return i2c_transfer(data->client->adapter, msg, 2); -} - -int synaptics_ts_write_block(struct synaptics_drv_data *data, - u16 addr, u8 *cmd, u16 count) -{ - struct i2c_msg msg; - int ret = 0, i = 0; - u8 buf[256]; - - synaptics_ts_set_page(data, addr); - - buf[0] = addr & 0xff; - - for (i = 1; i <= count; i++) - buf[i] = *cmd++; - - msg.addr = data->client->addr; - msg.flags = data->client->flags & I2C_M_TEN; - msg.len = count + 1; - msg.buf = buf; - - ret = i2c_transfer(data->client->adapter, &msg, 1); - - return (ret == 1) ? count : ret; -} - -int synaptics_ts_read_block(struct synaptics_drv_data *data, - u16 addr, u8 *buf, u16 count) -{ - struct i2c_msg msg[2]; - int ret = 0; - - synaptics_ts_set_page(data, addr); - - msg[0].addr = data->client->addr; - msg[0].flags = 0x00; - msg[0].len = 1; - msg[0].buf = (u8 *) &addr; - - msg[1].addr = data->client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = count; - msg[1].buf = buf; - - ret = i2c_transfer(data->client->adapter, msg, 2); - - return (ret == 1) ? count : ret; -} - -#if defined(CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK) -static void free_dvfs_lock(struct work_struct *work) -{ - struct synaptics_drv_data *data = - container_of(work, struct synaptics_drv_data, - dvfs_dwork.work); - - dev_unlock(data->bus_dev, data->dev); - exynos_cpufreq_lock_free(DVFS_LOCK_ID_TSP); - data->dvfs_lock_status = false; -} -void set_dvfs_lock(struct synaptics_drv_data *data, bool en) -{ - if (0 == data->cpufreq_level) - exynos_cpufreq_get_level(SEC_DVFS_LOCK_FREQ, - &data->cpufreq_level); - - if (en) { - cancel_delayed_work(&data->dvfs_dwork); - if (!data->dvfs_lock_status) { - dev_lock(data->bus_dev, - data->dev, SEC_BUS_LOCK_FREQ); - exynos_cpufreq_lock(DVFS_LOCK_ID_TSP, - data->cpufreq_level); - data->dvfs_lock_status = true; - } - } else { - if (data->dvfs_lock_status) - schedule_delayed_work(&data->dvfs_dwork, - (SEC_DVFS_LOCK_TIMEOUT * HZ) / 1000); - } -} -#endif /* CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK */ - -static void forced_release_fingers(struct synaptics_drv_data *data) -{ - int i; -#if 0 - printk(KERN_DEBUG "[TSP] %s\n", __func__); -#endif - for (i = 0; i < MAX_TOUCH_NUM; ++i) { - input_mt_slot(data->input, i); - input_mt_report_slot_state(data->input, - MT_TOOL_FINGER, 0); - - data->finger[i].status = MT_STATUS_INACTIVE; - data->finger[i].z = 0; - } - input_sync(data->input); - set_dvfs_lock(data, false); - return ; -} - -static int synaptics_ts_set_func_info(struct synaptics_drv_data *data) -{ - int i = 0, cnt = 0; - u8 buffer[6]; - u16 addr = 0; - u16 base_addr = FUNC_ADDR_FIRST; - u16 last_addr = FUNC_ADDR_LAST; - - for (i = 0; i <= PAGE_MAX; i += PAGE_MAX) { - base_addr += i; - last_addr += i; - for (addr = base_addr; addr >= last_addr; - addr -= FUNC_ADDR_SIZE) { - synaptics_ts_read_block(data, - addr, buffer, 6); - if (data->debug) { - printk(KERN_DEBUG - "[TSP] function : 0x%x\n", - buffer[5]); - printk(KERN_DEBUG - "[TSP] query_base_addr : 0x%x\n", - buffer[0]); - printk(KERN_DEBUG - "[TSP] command_base_addr : 0x%x\n", - buffer[1]); - printk(KERN_DEBUG - "[TSP] control_base_addr : 0x%x\n", - buffer[2]); - printk(KERN_DEBUG - "[TSP] data_base_addr : 0x%x\n", - buffer[3]); - } - switch (buffer[5]) { - case 0x01: - SET_FUNC_ADDR(01, i); - break; - - case 0x11: - SET_FUNC_ADDR(11, i); - break; - - case 0x34: - SET_FUNC_ADDR(34, i); - break; - - case 0x54: - SET_FUNC_ADDR(54, i); - break; - - default: - break; - } - } - } - return cnt; -} - -static int synaptics_ts_read_dummy(struct synaptics_drv_data *data) -{ - u8 buf; - int ret = 0, cnt = 0; - while (cnt < 5) { - ret = synaptics_ts_read_data(data, - data->f01.data_base_addr, &buf); - if (ret < 0) { - pr_err("[TSP] read reg_data failed(%d) ret : %d\n", - cnt++, ret); - msleep(20); - } else - return 0; - } - return -EIO; -} - -static void set_charger_connection_bit(struct synaptics_drv_data *data) -{ - u8 buf = 0; - - if (data->suspend) { - schedule_delayed_work(&data->noti_dwork, HZ / 2); - return ; - } - - synaptics_ts_read_data(data, - data->f01.control_base_addr, &buf); - - if (data->charger_connection) - buf |= CHARGER_CONNECT_BIT; - else - buf &= ~(CHARGER_CONNECT_BIT); - - synaptics_ts_write_data(data, - data->f01.control_base_addr, buf); -} - -static void inform_charger_connection(struct charger_callbacks *cb, int mode) -{ - struct synaptics_drv_data *data = container_of(cb, - struct synaptics_drv_data, callbacks); - - if (!data->ready) { - printk(KERN_DEBUG - "[TSP] %s - driver is not ready\n", - __func__); - return ; - } - - data->charger_connection = !!mode; - set_charger_connection_bit(data); -} - -static int synaptics_ts_set_func(struct synaptics_drv_data *data) -{ - int i = 0; - - printk(KERN_DEBUG "[TSP] %s\n", __func__); - - if (synaptics_ts_set_func_info(data) != 4) { - pr_err("[TSP] failed to get function info.\n"); - forced_fw_update(data); - synaptics_ts_set_func_info(data); - } else - synaptics_fw_updater(data, NULL); - - for (i = 0; i < MAX_TOUCH_NUM; ++i) - data->finger[i].status = MT_STATUS_INACTIVE; - - return synaptics_ts_read_dummy(data); -} - -static int check_interrupt_status(struct synaptics_drv_data *data, - u32 *finger_status) -{ - int ret = 0; - u8 buf[3]; - u16 addr = 0; - - /* read the interrupt status */ - addr = data->f01.data_base_addr + 1; - ret = synaptics_ts_read_data(data, - addr, buf); - if (ret < 0) { - pr_err("[TSP] failed to read i2c data(%d)\n", __LINE__); - return -EIO; - } - - /* read the finger states */ - addr = data->f11.data_base_addr; - ret = synaptics_ts_read_block(data, - addr, buf, 3); - if (ret < 0) { - pr_err("[TSP] failed to read i2c data(%d)\n", __LINE__); - return -EIO; - } - - *finger_status = (u32) (buf[0] | (buf[1] << 8) | - ((buf[2] & 0xf) << 16)); - - if (data->debug) - printk(KERN_DEBUG - "[TSP] finger_status : 0x%x\n", - *finger_status); - - return 0; -} - -static void synaptics_ts_read_points(struct synaptics_drv_data *data, - u32 finger_status) -{ - struct finger_data buf; - bool finger_pressed = false; - int ret = 0; - int id = 0; - u16 addr = data->f11.data_base_addr + 3; - - for (id = 0; id < MAX_TOUCH_NUM; id++, - addr += sizeof(struct finger_data)) { - if (finger_status & (0x3 << (id * 2))) { - ret = synaptics_ts_read_block(data, - addr, (u8 *) &buf, 5); - if (ret < 0) { - pr_err("[TSP] failed to read finger[%u]\n", id); - return ; - } - - if (data->debug) - printk(KERN_DEBUG - "[TSP] ID: %d, x_msb: %d, y_msb: %d, z: %d\n", - id, - buf.x_msb, - buf.y_msb, - buf.z); - - data->finger[id].x = - (buf.x_msb << 4) + - (buf.xy_lsb & 0x0F); - data->finger[id].y = - (buf.y_msb << 4) + - (buf.xy_lsb >> 4); - - if ((buf.w >> 4) > - (buf.w & 0x0F)) { - data->finger[id].w_max = - ((buf.w & 0xF0) >> 4); - data->finger[id].w_min = - (buf.w & 0x0F); - } else { - data->finger[id].w_min = - ((buf.w & 0xF0) >> 4); - data->finger[id].w_max = - (buf.w & 0x0F); - } - - data->finger[id].z = buf.z; - if (data->finger[id].z) { - if (MT_STATUS_INACTIVE == - data->finger[id].status) { - data->finger[id].status = - MT_STATUS_PRESS; - if (data->debug) - printk(KERN_DEBUG - "[TSP] ID: %d, x: %d, y: %d, z: %d\n", - id, - data->finger[id].x, - data->finger[id].y, - data->finger[id].z); - else - printk(KERN_DEBUG - "s7301 %d P\n", id); - } else if (data->debug) - printk(KERN_DEBUG - "[TSP] ID: %d, x: %d, y: %d, z: %d\n", - id, - data->finger[id].x, - data->finger[id].y, - data->finger[id].z); - } - } else if (MT_STATUS_PRESS == data->finger[id].status) { - data->finger[id].status = MT_STATUS_RELEASE; - data->finger[id].z = 0; - if (data->debug) - printk(KERN_DEBUG "[TSP] ID: %d\n", id); - else - printk(KERN_DEBUG "s7301 %d R\n", id); - } - } - - for (id = 0; id < MAX_TOUCH_NUM; ++id) { - if (MT_STATUS_INACTIVE == data->finger[id].status) - continue; - - input_mt_slot(data->input, id); - input_mt_report_slot_state(data->input, - MT_TOOL_FINGER, - !!data->finger[id].z); - - switch (data->finger[id].status) { - case MT_STATUS_PRESS: - case MT_STATUS_MOVE: - finger_pressed = true; - REPORT_MT( - data->finger[id].x, - data->finger[id].y, - data->finger[id].z, - data->finger[id].w_max, - data->finger[id].w_min); - break; - - case MT_STATUS_RELEASE: - data->finger[id].status = MT_STATUS_INACTIVE; - break; - default: - break; - } - } - input_sync(data->input); - set_dvfs_lock(data, finger_pressed); -} - -static irqreturn_t synaptics_ts_irq_handler(int irq, void *_data) -{ - struct synaptics_drv_data *data = (struct synaptics_drv_data *)_data; - u32 finger_status = 0; - if (!check_interrupt_status(data, &finger_status)) - synaptics_ts_read_points(data, finger_status); - return IRQ_HANDLED; -} - -#if defined(CONFIG_HAS_EARLYSUSPEND) -static void synaptics_ts_early_suspend(struct early_suspend *h) -{ - struct synaptics_drv_data *data = - container_of(h, struct synaptics_drv_data, early_suspend); - printk(KERN_DEBUG "[TSP] %s\n", __func__); - cancel_delayed_work_sync(&data->resume_dwork); - mutex_lock(&data->mutex); - if (!data->suspend) { - disable_irq(data->client->irq); - forced_release_fingers(data); - if (!wake_lock_active(&data->wakelock)) { - data->ready = false; - data->pdata->set_power(0); - data->suspend = true; - } - } - mutex_unlock(&data->mutex); -} - -static void synaptics_ts_late_resume(struct early_suspend *h) -{ - struct synaptics_drv_data *data = - container_of(h, struct synaptics_drv_data, early_suspend); - - printk(KERN_DEBUG "[TSP] %s\n", __func__); - - if (data->suspend) { - if (data->pdata->set_power(1)) - data->pdata->hw_reset(); - } - schedule_delayed_work(&data->resume_dwork, HZ / 10); -} -#endif - -static void init_function_data_dwork(struct work_struct *work) -{ - struct synaptics_drv_data *data = - container_of(work, struct synaptics_drv_data, init_dwork.work); - int ret = 0; - - printk(KERN_DEBUG "[TSP] %s\n", __func__); - - ret = synaptics_ts_set_func(data); - if (ret) { - pr_err("[TSP] failed to initialize\n"); - return ; - } - -#if defined(CONFIG_HAS_EARLYSUSPEND) - data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; - data->early_suspend.suspend = synaptics_ts_early_suspend; - data->early_suspend.resume = synaptics_ts_late_resume; - register_early_suspend(&data->early_suspend); -#endif - -#if defined(CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK) - INIT_DELAYED_WORK(&data->dvfs_dwork, - free_dvfs_lock); - data->bus_dev = dev_get("exynos-busfreq"); - data->dvfs_lock_status = false; - ret = exynos_cpufreq_get_level(SEC_DVFS_LOCK_FREQ, - &data->cpufreq_level); - if (ret < 0) - data->cpufreq_level = 0; -#endif - - data->ready = true; - set_charger_connection_bit(data); - - if (data->client->irq) { - ret = request_threaded_irq(data->client->irq, NULL, - synaptics_ts_irq_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - data->client->name, data); - if (ret < 0) { - pr_err("[TSP] failed to request threaded irq %d, ret %d\n", - data->client->irq, ret); - return ; - } - } -} - -static void synaptics_ts_resume_dwork(struct work_struct *work) -{ - struct synaptics_drv_data *data = - container_of(work, struct synaptics_drv_data, - resume_dwork.work); - - mutex_lock(&data->mutex); - if (data->suspend) { - data->ready = true; - set_charger_connection_bit(data); - synaptics_ts_drawing_mode(data); - synaptics_ts_read_dummy(data); - enable_irq(data->client->irq); - data->suspend = false; - } - mutex_unlock(&data->mutex); -} - -static void synaptics_ts_noti_dwork(struct work_struct *work) -{ - struct synaptics_drv_data *data = - container_of(work, struct synaptics_drv_data, - noti_dwork.work); - - set_charger_connection_bit(data); -} - -static int __init synaptics_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct synaptics_drv_data *ddata; - struct synaptics_platform_data *pdata; - struct input_dev *input; - int ret = 0; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("[TSP] failed to check i2c functionality!\n"); - ret = -ENODEV; - goto err_check_functionality_failed; - } - - ddata = kzalloc(sizeof(struct synaptics_drv_data), GFP_KERNEL); - if (unlikely(ddata == NULL)) { - pr_err("[TSP] failed to allocate the synaptics_drv_data.\n"); - ret = -ENOMEM; - goto err_alloc_data_failed; - } - - pdata = client->dev.platform_data; - if (pdata == NULL) { - pr_err("[TSP] failed to get platform data\n"); - goto err_pdata; - } - - ddata->client = client; - ddata->pdata = pdata; - ddata->gpio = pdata->gpio_attn; - ddata->x_line = pdata->x_line; - ddata->y_line = pdata->y_line; - - /* Register callbacks */ - /* To inform tsp , charger connection status*/ - ddata->callbacks.inform_charger = inform_charger_connection; - if (pdata->register_cb) - pdata->register_cb(&ddata->callbacks); - - i2c_set_clientdata(client, ddata); - - input = input_allocate_device(); - if (!input) { - pr_err("[TSP] failed to allocate input device\n"); - ret = -ENOMEM; - goto err_input_dev_alloc_failed; - } - - ddata->input = input; - input_set_drvdata(input, ddata); - -#if 0 - input->name = client->driver->driver.name; -#else - input->name = "sec_touchscreen"; -#endif - - __set_bit(EV_ABS, input->evbit); - __set_bit(EV_KEY, input->evbit); - __set_bit(MT_TOOL_FINGER, input->keybit); - __set_bit(INPUT_PROP_DIRECT, input->propbit); - - input_mt_init_slots(input, MAX_TOUCH_NUM); - input_set_abs_params(input, ABS_MT_POSITION_X, 0, - pdata->max_x, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, - pdata->max_y, 0, 0); - input_set_abs_params(input, ABS_MT_PRESSURE, 0, - pdata->max_pressure, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, - pdata->max_width, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, - pdata->max_width, 0, 0); - - ret = input_register_device(input); - if (ret) { - pr_err("[TSP] failed to register input device\n"); - ret = -ENOMEM; - goto err_input_register_device_failed; - } - - mutex_init(&ddata->mutex); - wake_lock_init(&ddata->wakelock, WAKE_LOCK_SUSPEND, "touch"); - - INIT_DELAYED_WORK(&ddata->init_dwork, init_function_data_dwork); - INIT_DELAYED_WORK(&ddata->resume_dwork, synaptics_ts_resume_dwork); - INIT_DELAYED_WORK(&ddata->noti_dwork, synaptics_ts_noti_dwork); - schedule_delayed_work(&ddata->init_dwork, HZ); - - ret = set_tsp_sysfs(ddata); - if (ret) { - pr_err("[TSP] failed to register input device\n"); - ret = -ENODEV; - goto err_make_sysfs_failed; - } - - return 0; - -err_make_sysfs_failed: - input_unregister_device(input); -err_input_register_device_failed: - input_free_device(input); -err_input_dev_alloc_failed: -err_pdata: - kfree(ddata); -err_alloc_data_failed: -err_check_functionality_failed: - return ret; -} - -static int synaptics_ts_remove(struct i2c_client *client) -{ - struct synaptics_drv_data *data = i2c_get_clientdata(client); - - unregister_early_suspend(&data->early_suspend); - free_irq(client->irq, data); - input_unregister_device(data->input); - kfree(data); - return 0; -} - -static const struct i2c_device_id synaptics_ts_id[] = { - {SYNAPTICS_TS_NAME, 0}, - {} -}; - -static struct i2c_driver synaptics_ts_driver = { - .driver = { - .name = SYNAPTICS_TS_NAME, - }, - .id_table = synaptics_ts_id, - .probe = synaptics_ts_probe, - .remove = __devexit_p(synaptics_ts_remove), -}; - -static int __devinit synaptics_ts_init(void) -{ - return i2c_add_driver(&synaptics_ts_driver); -} - -static void __exit synaptics_ts_exit(void) -{ - i2c_del_driver(&synaptics_ts_driver); -} - -module_init(synaptics_ts_init); -module_exit(synaptics_ts_exit); - -MODULE_AUTHOR("junki671.min@samsung.com"); -MODULE_DESCRIPTION("Driver for Synaptics S7301 Touchscreen Controller"); -MODULE_LICENSE("GPL"); - |