123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- /*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (C) 2012 Alexandra Chin <[email protected]>
- * Copyright (C) 2012 Scott Lin <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/input.h>
- #include <linux/platform_device.h>
- #include <linux/input/synaptics_dsx.h>
- #include "synaptics_dsx_core.h"
- #define SYSFS_FOLDER_NAME "video"
- static ssize_t video_sysfs_dcs_write_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
- static ssize_t video_sysfs_param_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
- static int video_send_dcs_command(unsigned char command_opcode);
- struct f38_command {
- union {
- struct {
- unsigned char command_opcode;
- unsigned char register_access:1;
- unsigned char gamma_page:1;
- unsigned char f38_control1_b2__7:6;
- unsigned char parameter_field_1;
- unsigned char parameter_field_2;
- unsigned char parameter_field_3;
- unsigned char parameter_field_4;
- unsigned char send_to_dcs:1;
- unsigned char f38_command6_b1__7:7;
- } __packed;
- unsigned char data[7];
- };
- };
- struct synaptics_rmi4_video_handle {
- unsigned char param;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- struct synaptics_rmi4_data *rmi4_data;
- struct kobject *sysfs_dir;
- };
- #ifdef RMI_DCS_SUSPEND_RESUME
- struct dcs_command {
- unsigned char command;
- unsigned int wait_time;
- };
- static struct dcs_command suspend_sequence[] = {
- {
- .command = 0x28,
- .wait_time = 200,
- },
- {
- .command = 0x10,
- .wait_time = 200,
- },
- };
- static struct dcs_command resume_sequence[] = {
- {
- .command = 0x11,
- .wait_time = 200,
- },
- {
- .command = 0x29,
- .wait_time = 200,
- },
- };
- #endif
- static struct device_attribute attrs[] = {
- __ATTR(dcs_write, 0220,
- synaptics_rmi4_show_error,
- video_sysfs_dcs_write_store),
- __ATTR(param, 0220,
- synaptics_rmi4_show_error,
- video_sysfs_param_store),
- };
- static struct synaptics_rmi4_video_handle *video;
- DECLARE_COMPLETION(video_remove_complete);
- static ssize_t video_sysfs_dcs_write_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- int retval;
- unsigned int input;
- if (kstrtouint(buf, 16, &input) != 1)
- return -EINVAL;
- retval = video_send_dcs_command((unsigned char)input);
- if (retval < 0)
- return retval;
- return count;
- }
- static ssize_t video_sysfs_param_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- unsigned int input;
- if (kstrtouint(buf, 16, &input) != 1)
- return -EINVAL;
- video->param = (unsigned char)input;
- return count;
- }
- static int video_send_dcs_command(unsigned char command_opcode)
- {
- int retval;
- struct f38_command command;
- struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
- memset(&command, 0x00, sizeof(command));
- command.command_opcode = command_opcode;
- command.parameter_field_1 = video->param;
- command.send_to_dcs = 1;
- video->param = 0;
- retval = synaptics_rmi4_reg_write(rmi4_data,
- video->command_base_addr,
- command.data,
- sizeof(command.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to send DCS command\n",
- __func__);
- return retval;
- }
- return 0;
- }
- static int video_scan_pdt(void)
- {
- int retval;
- unsigned char page;
- unsigned short addr;
- bool f38_found = false;
- struct synaptics_rmi4_fn_desc rmi_fd;
- struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
- for (page = 0; page < PAGES_TO_SERVICE; page++) {
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- addr |= (page << 8);
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&rmi_fd,
- sizeof(rmi_fd));
- if (retval < 0)
- return retval;
- addr &= ~(MASK_8BIT << 8);
- if (!rmi_fd.fn_number)
- break;
- if (rmi_fd.fn_number == SYNAPTICS_RMI4_F38) {
- f38_found = true;
- goto f38_found;
- }
- }
- }
- if (!f38_found) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F38\n",
- __func__);
- return -EINVAL;
- }
- f38_found:
- video->query_base_addr = rmi_fd.query_base_addr | (page << 8);
- video->control_base_addr = rmi_fd.ctrl_base_addr | (page << 8);
- video->data_base_addr = rmi_fd.data_base_addr | (page << 8);
- video->command_base_addr = rmi_fd.cmd_base_addr | (page << 8);
- return 0;
- }
- static int synaptics_rmi4_video_init(struct synaptics_rmi4_data *rmi4_data)
- {
- int retval;
- unsigned char attr_count;
- if (video) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
- video = kzalloc(sizeof(*video), GFP_KERNEL);
- if (!video) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for video\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
- video->rmi4_data = rmi4_data;
- retval = video_scan_pdt();
- if (retval < 0) {
- retval = 0;
- goto exit_scan_pdt;
- }
- video->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME,
- &rmi4_data->input_dev->dev.kobj);
- if (!video->sysfs_dir) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs directory\n",
- __func__);
- retval = -ENODEV;
- goto exit_sysfs_dir;
- }
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(video->sysfs_dir,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- retval = -ENODEV;
- goto exit_sysfs_attrs;
- }
- }
- return 0;
- exit_sysfs_attrs:
- for (attr_count--; attr_count >= 0; attr_count--)
- sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
- kobject_put(video->sysfs_dir);
- exit_sysfs_dir:
- exit_scan_pdt:
- kfree(video);
- video = NULL;
- exit:
- return retval;
- }
- static void synaptics_rmi4_video_remove(struct synaptics_rmi4_data *rmi4_data)
- {
- unsigned char attr_count;
- if (!video)
- goto exit;
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
- sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
- kobject_put(video->sysfs_dir);
- kfree(video);
- video = NULL;
- exit:
- complete(&video_remove_complete);
- }
- static void synaptics_rmi4_video_reset(struct synaptics_rmi4_data *rmi4_data)
- {
- if (!video)
- synaptics_rmi4_video_init(rmi4_data);
- }
- #ifdef RMI_DCS_SUSPEND_RESUME
- static void synaptics_rmi4_video_suspend(struct synaptics_rmi4_data *rmi4_data)
- {
- int retval;
- unsigned char ii;
- unsigned char command;
- unsigned char num_of_cmds;
- if (!video)
- return;
- num_of_cmds = ARRAY_SIZE(suspend_sequence);
- for (ii = 0; ii < num_of_cmds; ii++) {
- command = suspend_sequence[ii].command;
- retval = video_send_dcs_command(command);
- if (retval < 0)
- return;
- msleep(suspend_sequence[ii].wait_time);
- }
- }
- static void synaptics_rmi4_video_resume(struct synaptics_rmi4_data *rmi4_data)
- {
- int retval;
- unsigned char ii;
- unsigned char command;
- unsigned char num_of_cmds;
- if (!video)
- return;
- num_of_cmds = ARRAY_SIZE(resume_sequence);
- for (ii = 0; ii < num_of_cmds; ii++) {
- command = resume_sequence[ii].command;
- retval = video_send_dcs_command(command);
- if (retval < 0)
- return;
- msleep(resume_sequence[ii].wait_time);
- }
- }
- #endif
- static struct synaptics_rmi4_exp_fn video_module = {
- .fn_type = RMI_VIDEO,
- .init = synaptics_rmi4_video_init,
- .remove = synaptics_rmi4_video_remove,
- .reset = synaptics_rmi4_video_reset,
- .reinit = NULL,
- .early_suspend = NULL,
- #ifdef RMI_DCS_SUSPEND_RESUME
- .suspend = synaptics_rmi4_video_suspend,
- .resume = synaptics_rmi4_video_resume,
- #else
- .suspend = NULL,
- .resume = NULL,
- #endif
- .late_resume = NULL,
- .attn = NULL,
- };
- static int __init rmi4_video_module_init(void)
- {
- synaptics_rmi4_new_function(&video_module, true);
- return 0;
- }
- static void __exit rmi4_video_module_exit(void)
- {
- synaptics_rmi4_new_function(&video_module, false);
- wait_for_completion(&video_remove_complete);
- }
- module_init(rmi4_video_module_init);
- module_exit(rmi4_video_module_exit);
- MODULE_AUTHOR("Synaptics, Inc.");
- MODULE_DESCRIPTION("Synaptics DSX Video Module");
- MODULE_LICENSE("GPL v2");
|