1213 lines
31 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef CONFIG_CTS_I2C_HOST
#define LOG_TAG "I2CDrv"
#else
#define LOG_TAG "SPIDrv"
#endif
#include "cts_config.h"
#include "cts_platform.h"
#include "cts_core.h"
#include "cts_sysfs.h"
#include "cts_charger_detect.h"
#include "cts_earjack_detect.h"
#include "cts_oem.h"
#include "cts_strerror.h"
#include "cts_firmware.h"
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#include "tpd.h"
#include "cts_config.h"
#include "cts_platform.h"
#include "cts_core.h"
#else /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */
#ifdef CFG_CTS_DRM_NOTIFIER
#include <drm/drm_panel.h>
static struct drm_panel *active_panel;
static int check_dt(struct device_node *np);
#endif /* CFG_CTS_DRM_NOTIFIER */
#endif /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */
static void cts_resume_work_func(struct work_struct *work);
bool cts_show_debug_log;
#ifdef CTS_MTK_GET_PANEL
static char *active_panel_name;
#endif
module_param_named(debug_log, cts_show_debug_log, bool, 0660);
MODULE_PARM_DESC(debug_log, "Show debug log control");
struct chipone_ts_data *g_cts_data = NULL;
int cts_suspend(struct chipone_ts_data *cts_data)
{
int ret;
cts_info("Suspend");
cts_lock_device(&cts_data->cts_dev);
ret = cts_suspend_device(&cts_data->cts_dev);
cts_unlock_device(&cts_data->cts_dev);
if (ret)
cts_err("Suspend device failed %d", ret);
ret = cts_stop_device(&cts_data->cts_dev);
if (ret) {
cts_err("Stop device failed %d", ret);
return ret;
}
#ifdef CFG_CTS_GESTURE
/* Enable IRQ wake if gesture wakeup enabled */
if (cts_is_gesture_wakeup_enabled(&cts_data->cts_dev)) {
ret = cts_plat_enable_irq_wake(cts_data->pdata);
if (ret) {
cts_err("Enable IRQ wake failed %d", ret);
return ret;
}
ret = cts_plat_enable_irq(cts_data->pdata);
if (ret) {
cts_err("Enable IRQ failed %d", ret);
return ret;
}
}
#endif /* CFG_CTS_GESTURE */
/** - To avoid waking up while not sleeping,
*delay 20ms to ensure reliability
*/
msleep(20);
return 0;
}
int cts_resume(struct chipone_ts_data *cts_data)
{
int ret;
cts_info("Resume");
#ifdef CFG_CTS_GESTURE
if (cts_is_gesture_wakeup_enabled(&cts_data->cts_dev)) {
ret = cts_plat_disable_irq_wake(cts_data->pdata);
if (ret)
cts_warn("Disable IRQ wake failed %d", ret);
ret = cts_plat_disable_irq(cts_data->pdata);
if (ret < 0)
cts_err("Disable IRQ failed %d", ret);
}
#endif /* CFG_CTS_GESTURE */
cts_lock_device(&cts_data->cts_dev);
ret = cts_resume_device(&cts_data->cts_dev);
cts_unlock_device(&cts_data->cts_dev);
if (ret) {
cts_warn("Resume device failed %d", ret);
return ret;
}
ret = cts_start_device(&cts_data->cts_dev);
if (ret) {
cts_err("Start device failed %d", ret);
return ret;
}
return 0;
}
static void cts_resume_work_func(struct work_struct *work)
{
struct chipone_ts_data *cts_data =
container_of(work, struct chipone_ts_data, ts_resume_work);
cts_info("%s", __func__);
cts_resume(cts_data);
}
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#ifdef CONFIG_CTS_PM_FB_NOTIFIER
#ifdef CFG_CTS_DRM_NOTIFIER
static int fb_notifier_callback(struct notifier_block *nb,
unsigned long action, void *data)
{
volatile int blank;
const struct cts_platform_data *pdata =
container_of(nb, struct cts_platform_data, fb_notifier);
struct chipone_ts_data *cts_data =
container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
struct drm_panel_notifier *evdata = data;
cts_info("FB notifier callback");
if (!evdata || !evdata->data || !cts_data)
return 0;
blank = *(int *)evdata->data;
cts_info("action=%lu, blank=%d", action, blank);
if (action == DRM_PANEL_EARLY_EVENT_BLANK) {
if (blank == DRM_PANEL_BLANK_POWERDOWN)
cts_suspend(cts_data);
} else {
blank = *(int *)evdata->data;
if (action == DRM_PANEL_EVENT_BLANK) {
if (blank == DRM_PANEL_BLANK_UNBLANK)
/* cts_resume(cts_data); */
queue_work(cts_data->workqueue,
&cts_data->ts_resume_work);
}
}
return 0;
}
#else
static int fb_notifier_callback(struct notifier_block *nb,
unsigned long action, void *data)
{
volatile int blank;
const struct cts_platform_data *pdata =
container_of(nb, struct cts_platform_data, fb_notifier);
struct chipone_ts_data *cts_data =
container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
struct fb_event *evdata = data;
cts_info("FB notifier callback");
if (evdata && evdata->data) {
if (action == FB_EVENT_BLANK) {
blank = *(int *)evdata->data;
if (blank == FB_BLANK_UNBLANK) {
/* cts_resume(cts_data); */
queue_work(cts_data->workqueue,
&cts_data->ts_resume_work);
return NOTIFY_OK;
}
} else if (action == FB_EARLY_EVENT_BLANK) {
blank = *(int *)evdata->data;
if (blank == FB_BLANK_POWERDOWN) {
cts_suspend(cts_data);
return NOTIFY_OK;
}
}
}
return NOTIFY_DONE;
}
#endif
static int cts_init_pm_fb_notifier(struct chipone_ts_data *cts_data)
{
cts_info("Init FB notifier");
cts_data->pdata->fb_notifier.notifier_call = fb_notifier_callback;
#ifdef CFG_CTS_DRM_NOTIFIER
{
int ret = -ENODEV;
if (active_panel) {
ret =drm_panel_notifier_register(active_panel,
&cts_data->pdata->fb_notifier);
if (ret)
cts_err("register drm_notifier failed. ret=%d\n", ret);
}
return ret;
}
#else
return fb_register_client(&cts_data->pdata->fb_notifier);
#endif
}
static int cts_deinit_pm_fb_notifier(struct chipone_ts_data *cts_data)
{
cts_info("Deinit FB notifier");
#ifdef CFG_CTS_DRM_NOTIFIER
{
int ret = 0;
if (active_panel) {
ret = drm_panel_notifier_unregister(active_panel,
&cts_data->pdata->fb_notifier);
if (ret)
cts_err("Error occurred while unregistering drm_notifier.\n");
}
return ret;
}
#else
return fb_unregister_client(&cts_data->pdata->fb_notifier);
#endif
}
#endif /* CONFIG_CTS_PM_FB_NOTIFIER */
#ifdef CFG_CTS_DRM_NOTIFIER
static int check_dt(struct device_node *np)
{
int i;
int count;
struct device_node *node;
struct drm_panel *panel;
count = of_count_phandle_with_args(np, "panel", NULL);
if (count <= 0)
return 0;
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "panel", i);
panel = of_drm_find_panel(node);
of_node_put(node);
if (!IS_ERR(panel)) {
cts_info("check active_panel");
active_panel = panel;
return 0;
}
}
if (node)
cts_err("%s: %s not actived", __func__, node->name);
return -ENODEV;
}
static int check_default_tp(struct device_node *dt, const char *prop)
{
const char *active_tp;
const char *compatible;
char *start;
int ret;
ret = of_property_read_string(dt->parent, prop, &active_tp);
if (ret) {
cts_err("%s:fail to read %s %d", __func__, prop, ret);
return -ENODEV;
}
ret = of_property_read_string(dt, "compatible", &compatible);
if (ret < 0) {
cts_err("%s:fail to read %s %d", __func__, "compatible", ret);
return -ENODEV;
}
start = strnstr(active_tp, compatible, strlen(active_tp));
if (start == NULL) {
cts_err("no match compatible, %s, %s", compatible, active_tp);
ret = -ENODEV;
}
return ret;
}
#endif
#endif
#ifdef CTS_MTK_GET_PANEL
char panel_name[50] = { 0 };
static int cts_get_panel(void)
{
int ret = -1;
cts_info("Enter cts_get_panel");
if (saved_command_line) {
char *sub;
char key_prefix[] = "mipi_mot_vid_";
char ic_prefix[] = "icnl";
cts_info("saved_command_line is %s", saved_command_line);
sub = strstr(saved_command_line, key_prefix);
if (sub) {
char *d;
int n, len, len_max = 50;
d = strstr(sub, " ");
if (d)
n = strlen(sub) - strlen(d);
else
n = strlen(sub);
if (n > len_max)
len = len_max;
else
len = n;
strncpy(panel_name, sub, len);
active_panel_name = panel_name;
if (strstr(active_panel_name, ic_prefix))
cts_info("active_panel_name=%s", active_panel_name);
else {
cts_info("Not chipone panel!");
return ret;
}
} else {
cts_info("chipone active panel not found!");
return ret;
}
} else {
cts_info("saved_command_line null!");
return ret;
}
return 0;
}
#endif
static int rockchip_panel_notifier_call(struct notifier_block *self,
unsigned long val, void *v)
{
enum rockchip_panel_event event = (enum rockchip_panel_event)val;
struct chipone_ts_data *cts_data =
container_of(self, struct chipone_ts_data, panel_nb);
if (event == PANEL_ENABLED) {
cts_info("notify to resume");
cts_resume(cts_data);
} else if (event == PANEL_PRE_DISABLE) {
cts_info("notify to suspend");
cts_suspend(cts_data);
}
return NOTIFY_OK;
}
#ifdef CONFIG_CTS_I2C_HOST
static int cts_driver_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#else
static int cts_driver_probe(struct spi_device *client)
#endif
{
struct chipone_ts_data *cts_data = NULL;
struct cts_device *cts_dev = NULL;
struct cts_firmware *firmware = NULL;
int ret = 0;
#ifdef CTS_MTK_GET_PANEL
ret = cts_get_panel();
if (ret) {
cts_info("MTK get chipone panel error");
return ret;
}
#endif
#ifdef CFG_CTS_DRM_NOTIFIER
{
struct device_node *dp = client->dev.of_node;
if (check_dt(dp)) {
if (!check_default_tp(dp, "qcom,i2c-touch-active"))
ret = -EPROBE_DEFER;
else
ret = -ENODEV;
cts_err("%s: %s not actived\n", __func__, dp->name);
return ret;
}
}
#endif
#ifdef CONFIG_CTS_I2C_HOST
if (client == NULL) {
cts_err("Probe i2c client = NULL");
return -EINVAL;
}
cts_info("Probe i2c client: name='%s' addr=0x%02x flags=0x%02x irq=%d",
client->name, client->addr, client->flags, client->irq);
#if !defined(CONFIG_MTK_PLATFORM)
if (client->addr != CTS_DEV_NORMAL_MODE_I2CADDR) {
cts_err("Probe i2c addr 0x%02x != driver config addr 0x%02x",
client->addr, CTS_DEV_NORMAL_MODE_I2CADDR);
return -ENODEV;
};
#endif
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
cts_err("Check functionality failed");
return -ENODEV;
}
#else
if (client == NULL) {
cts_info("Probe spi client = NULL");
return -EINVAL;
}
cts_info("Probe spi device '%s': "
"mode='%u' speed=%u bits_per_word=%u "
"chip_select=%u, cs_gpio=%d irq=%d",
client->modalias, client->mode, client->max_speed_hz, client->bits_per_word,
client->chip_select, client->cs_gpio, client->irq);
#endif
cts_data = kzalloc(sizeof(struct chipone_ts_data), GFP_KERNEL);
if (cts_data == NULL) {
cts_err("Allocate chipone_ts_data failed");
return -ENOMEM;
}
cts_data->pdata = kzalloc(sizeof(struct cts_platform_data), GFP_KERNEL);
if (cts_data->pdata == NULL) {
cts_err("Allocate cts_platform_data failed");
ret = -ENOMEM;
goto err_free_cts_data;
}
#ifdef CONFIG_CTS_I2C_HOST
i2c_set_clientdata(client, cts_data);
cts_data->i2c_client = client;
cts_data->device = &client->dev;
#else
spi_set_drvdata(client, cts_data);
cts_data->spi_client = client;
cts_data->device = &client->dev;
#endif
ret = cts_init_platform_data(cts_data->pdata, client);
if (ret) {
cts_err("Init platform data failed %d", ret);
goto err_free_pdata;
}
cts_data->cts_dev.pdata = cts_data->pdata;
cts_data->pdata->cts_dev = &cts_data->cts_dev;
cts_dev = cts_data->pdata->cts_dev;
g_cts_data = cts_data;
firmware = kzalloc(sizeof(struct cts_firmware), GFP_KERNEL);
if (firmware == NULL) {
cts_err("Create firmware buffer failed");
goto err_free_firmware_buffer;
}
firmware->data = kzalloc(CFG_CTS_FIRMWARE_SIZE, GFP_KERNEL);
if (firmware->data == NULL) {
cts_err("Create firmware data buffer failed");
goto err_free_firmware_data_buffer;
}
cts_dev->firmware = firmware;
cts_data->workqueue =
create_singlethread_workqueue(CFG_CTS_DEVICE_NAME "-workqueue");
if (cts_data->workqueue == NULL) {
cts_err("Create workqueue failed");
ret = -ENOMEM;
goto err_deinit_platform_data;
}
#ifdef CONFIG_CTS_ESD_PROTECTION
cts_data->esd_workqueue =
create_singlethread_workqueue(CFG_CTS_DEVICE_NAME "-esd_workqueue");
if (cts_data->esd_workqueue == NULL) {
cts_err("Create esd workqueue failed");
ret = -ENOMEM;
goto err_destroy_workqueue;
}
#endif
#ifdef CFG_CTS_HEARTBEAT_MECHANISM
cts_data->heart_workqueue =
create_singlethread_workqueue(CFG_CTS_DEVICE_NAME "-heart_workqueue");
if (cts_data->heart_workqueue == NULL) {
cts_err("Create heart workqueue failed");
ret = -ENOMEM;
goto err_destroy_esd_workqueue;
}
#endif
ret = cts_plat_request_resource(cts_data->pdata);
if (ret < 0) {
cts_err("Request resource failed %d", ret);
goto err_destroy_heart_workqueue;
}
ret = cts_reset_device(cts_dev);
if (ret < 0) {
cts_err("Reset device failed %d", ret);
goto err_free_resource;
}
ret = cts_probe_device(cts_dev);
if (ret) {
cts_err("Probe device failed %d", ret);
goto err_free_resource;
}
ret = cts_plat_init_touch_device(cts_data->pdata);
if (ret < 0) {
cts_err("Init touch device failed %d", ret);
goto err_free_resource;
}
ret = cts_plat_init_vkey_device(cts_data->pdata);
if (ret < 0) {
cts_err("Init vkey device failed %d", ret);
goto err_deinit_touch_device;
}
ret = cts_plat_init_gesture(cts_data->pdata);
if (ret < 0) {
cts_err("Init gesture failed %d", ret);
goto err_deinit_vkey_device;
}
cts_init_esd_protection(cts_data);
ret = cts_tool_init(cts_data);
if (ret < 0)
cts_warn("Init tool node failed %d", ret);
ret = cts_sysfs_add_device(&client->dev);
if (ret < 0)
cts_warn("Add sysfs entry for device failed %d", ret);
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#ifdef CONFIG_CTS_PM_FB_NOTIFIER
ret = cts_init_pm_fb_notifier(cts_data);
if (ret) {
cts_err("Init FB notifier failed %d", ret);
goto err_deinit_sysfs;
}
#endif
#endif
ret = cts_plat_request_irq(cts_data->pdata);
if (ret < 0) {
cts_err("Request IRQ failed %d", ret);
goto err_register_fb;
}
#ifdef CONFIG_CTS_CHARGER_DETECT
ret = cts_charger_detect_init(cts_data);
if (ret)
cts_err("Init charger detect failed %d", ret);
/* Ignore this error */
#endif
#ifdef CONFIG_CTS_EARJACK_DETECT
ret = cts_earjack_detect_init(cts_data);
if (ret) {
cts_err("Init earjack detect failed %d", ret);
// Ignore this error
}
#endif
ret = cts_oem_init(cts_data);
if (ret < 0) {
cts_warn("Init oem specific faild %d", ret);
goto err_deinit_oem;
}
#ifdef CFG_CTS_HEARTBEAT_MECHANISM
INIT_DELAYED_WORK(&cts_data->heart_work, cts_heartbeat_mechanism_work);
#endif
INIT_WORK(&cts_data->ts_resume_work, cts_resume_work_func);
/* Init firmware upgrade work and schedule */
INIT_DELAYED_WORK(&cts_data->fw_upgrade_work, cts_firmware_upgrade_work);
queue_delayed_work(cts_data->workqueue, &cts_data->fw_upgrade_work,
msecs_to_jiffies(5 * 1000));
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#ifdef CONFIG_MTK_PLATFORM
tpd_load_status = 1;
#endif /* CONFIG_MTK_PLATFORM */
#endif
cts_data->panel_nb.notifier_call = rockchip_panel_notifier_call;
ret = devm_rockchip_panel_notifier_register_client(&client->dev,
&cts_data->panel_nb);
if (ret) {
cts_err("failed to register notifier client for TP: %d\n", ret);
goto err_deinit_oem;
}
return 0;
err_deinit_oem:
cts_oem_deinit(cts_data);
#ifdef CONFIG_CTS_CHARGER_DETECT
cts_charger_detect_deinit(cts_data);
#endif
#ifdef CONFIG_CTS_EARJACK_DETECT
cts_earjack_detect_deinit(cts_data);
#endif
cts_plat_free_irq(cts_data->pdata);
err_register_fb:
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#ifdef CONFIG_CTS_PM_FB_NOTIFIER
cts_deinit_pm_fb_notifier(cts_data);
err_deinit_sysfs:
#endif
#endif
cts_sysfs_remove_device(&client->dev);
#ifdef CONFIG_CTS_LEGACY_TOOL
cts_tool_deinit(cts_data);
#endif
#ifdef CONFIG_CTS_ESD_PROTECTION
cts_deinit_esd_protection(cts_data);
#endif
#ifdef CFG_CTS_GESTURE
cts_plat_deinit_gesture(cts_data->pdata);
#endif
err_deinit_vkey_device:
#ifdef CONFIG_CTS_VIRTUALKEY
cts_plat_deinit_vkey_device(cts_data->pdata);
#endif
err_deinit_touch_device:
cts_plat_deinit_touch_device(cts_data->pdata);
err_free_resource:
cts_plat_free_resource(cts_data->pdata);
err_destroy_heart_workqueue:
#ifdef CFG_CTS_HEARTBEAT_MECHANISM
destroy_workqueue(cts_data->heart_workqueue);
err_destroy_esd_workqueue:
#endif
#ifdef CONFIG_CTS_ESD_PROTECTION
destroy_workqueue(cts_data->esd_workqueue);
err_destroy_workqueue:
#endif
destroy_workqueue(cts_data->workqueue);
err_deinit_platform_data:
if (firmware->data) {
kfree(firmware->data);
firmware->data = NULL;
}
err_free_firmware_data_buffer:
if (firmware) {
kfree(firmware);
firmware = NULL;
}
err_free_firmware_buffer:
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
cts_deinit_platform_data(cts_data->pdata);
#endif
err_free_pdata:
kfree(cts_data->pdata);
err_free_cts_data:
kfree(cts_data);
cts_err("Probe failed %d", ret);
return ret;
}
#ifdef CONFIG_CTS_I2C_HOST
static void cts_driver_remove(struct i2c_client *client)
#else
static void cts_driver_remove(struct spi_device *client)
#endif
{
struct chipone_ts_data *cts_data;
int ret = 0;
cts_info("Remove");
#ifdef CONFIG_CTS_I2C_HOST
cts_data = (struct chipone_ts_data *)i2c_get_clientdata(client);
#else
cts_data = (struct chipone_ts_data *)spi_get_drvdata(client);
#endif
if (cts_data) {
ret = cts_stop_device(&cts_data->cts_dev);
if (ret)
cts_warn("Stop device failed %d", ret);
#ifdef CONFIG_CTS_CHARGER_DETECT
cts_charger_detect_deinit(cts_data);
#endif
#ifdef CONFIG_CTS_EARJACK_DETECT
cts_earjack_detect_deinit(cts_data);
#endif
cts_plat_free_irq(cts_data->pdata);
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#ifdef CONFIG_CTS_PM_FB_NOTIFIER
cts_deinit_pm_fb_notifier(cts_data);
#endif
#endif
cts_tool_deinit(cts_data);
cts_sysfs_remove_device(&client->dev);
cts_deinit_esd_protection(cts_data);
cts_plat_deinit_touch_device(cts_data->pdata);
cts_plat_deinit_vkey_device(cts_data->pdata);
cts_plat_deinit_gesture(cts_data->pdata);
cts_plat_free_resource(cts_data->pdata);
cts_oem_deinit(cts_data);
#ifdef CFG_CTS_HEARTBEAT_MECHANISM
if (cts_data->heart_workqueue)
destroy_workqueue(cts_data->heart_workqueue);
#endif
#ifdef CONFIG_CTS_ESD_PROTECTION
if (cts_data->esd_workqueue)
destroy_workqueue(cts_data->esd_workqueue);
#endif
if (cts_data->workqueue)
destroy_workqueue(cts_data->workqueue);
if (cts_data->cts_dev.firmware->data) {
kfree(cts_data->cts_dev.firmware->data);
cts_data->cts_dev.firmware->data = NULL;
}
if (cts_data->cts_dev.firmware) {
kfree(cts_data->cts_dev.firmware);
cts_data->cts_dev.firmware = NULL;
}
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
cts_deinit_platform_data(cts_data->pdata);
#endif
if (cts_data->pdata)
kfree(cts_data->pdata);
kfree(cts_data);
} else {
cts_warn("Chipone i2c driver remove while NULL chipone_ts_data");
}
}
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#ifdef CONFIG_CTS_PM_LEGACY
static int cts_i2c_driver_suspend(struct device *dev, pm_message_t state)
{
cts_info("Suspend by legacy power management");
return cts_suspend(dev_get_drvdata(dev));
}
static int cts_i2c_driver_resume(struct device *dev)
{
cts_info("Resume by legacy power management");
return cts_resume(dev_get_drvdata(dev));
}
#endif /* CONFIG_CTS_PM_LEGACY */
#ifdef CONFIG_CTS_PM_GENERIC
static int cts_i2c_driver_pm_suspend(struct device *dev)
{
cts_info("Suspend by bus power management");
return cts_suspend(dev_get_drvdata(dev));
}
static int cts_i2c_driver_pm_resume(struct device *dev)
{
cts_info("Resume by bus power management");
return cts_resume(dev_get_drvdata(dev));
}
/* bus control the suspend/resume procedure */
static const struct dev_pm_ops cts_i2c_driver_pm_ops = {
.suspend = cts_i2c_driver_pm_suspend,
.resume = cts_i2c_driver_pm_resume,
};
#endif /* CONFIG_CTS_PM_GENERIC */
#endif
#ifdef CONFIG_CTS_SYSFS
static ssize_t reset_pin_show(struct device_driver *driver, char *buf)
{
return snprintf(buf, PAGE_SIZE, "CFG_CTS_HAS_RESET_PIN: %c\n",
#ifdef CFG_CTS_HAS_RESET_PIN
'Y'
#else
'N'
#endif
);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(reset_pin, S_IRUGO, reset_pin_show, NULL);
#else
static DRIVER_ATTR_RO(reset_pin);
#endif
static ssize_t force_update_show(struct device_driver *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "CFG_CTS_HAS_RESET_PIN: %c\n",
#ifdef CFG_CTS_FIRMWARE_FORCE_UPDATE
'Y'
#else
'N'
#endif
);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(force_update, S_IRUGO, force_update_show, NULL);
#else
static DRIVER_ATTR_RO(force_update);
#endif
static ssize_t max_touch_num_show(struct device_driver *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "CFG_CTS_MAX_TOUCH_NUM: %d\n",
CFG_CTS_MAX_TOUCH_NUM);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(max_touch_num, S_IRUGO, max_touch_num_show, NULL);
#else
static DRIVER_ATTR_RO(max_touch_num);
#endif
static ssize_t vkey_show(struct device_driver *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "CONFIG_CTS_VIRTUALKEY: %c\n",
#ifdef CONFIG_CTS_VIRTUALKEY
'Y'
#else
'N'
#endif
);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(vkey, S_IRUGO, vkey_show, NULL);
#else
static DRIVER_ATTR_RO(vkey);
#endif
static ssize_t gesture_show(struct device_driver *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "CFG_CTS_GESTURE: %c\n",
#ifdef CFG_CTS_GESTURE
'Y'
#else
'N'
#endif
);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(gesture, S_IRUGO, gesture_show, NULL);
#else
static DRIVER_ATTR_RO(gesture);
#endif
static ssize_t esd_protection_show(struct device_driver *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "CONFIG_CTS_ESD_PROTECTION: %c\n",
#ifdef CONFIG_CTS_ESD_PROTECTION
'Y'
#else
'N'
#endif
);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(esd_protection, S_IRUGO, esd_protection_show, NULL);
#else
static DRIVER_ATTR_RO(esd_protection);
#endif
static ssize_t slot_protocol_show(struct device_driver *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "CONFIG_CTS_SLOTPROTOCOL: %c\n",
#ifdef CONFIG_CTS_SLOTPROTOCOL
'Y'
#else
'N'
#endif
);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(slot_protocol, S_IRUGO, slot_protocol_show, NULL);
#else
static DRIVER_ATTR_RO(slot_protocol);
#endif
static ssize_t max_xfer_size_show(struct device_driver *dev, char *buf)
{
#ifdef CONFIG_CTS_I2C_HOST
return snprintf(buf, PAGE_SIZE, "CFG_CTS_MAX_I2C_XFER_SIZE: %d\n",
CFG_CTS_MAX_I2C_XFER_SIZE);
#else
return snprintf(buf, PAGE_SIZE, "CFG_CTS_MAX_SPI_XFER_SIZE: %d\n",
CFG_CTS_MAX_SPI_XFER_SIZE);
#endif
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(max_xfer_size, S_IRUGO, max_xfer_size_show, NULL);
#else
static DRIVER_ATTR_RO(max_xfer_size);
#endif
static ssize_t driver_info_show(struct device_driver *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "Driver version: %s\n",
CFG_CTS_DRIVER_VERSION);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
static DRIVER_ATTR(driver_info, S_IRUGO, driver_info_show, NULL);
#else
static DRIVER_ATTR_RO(driver_info);
#endif
static struct attribute *cts_driver_config_attrs[] = {
&driver_attr_reset_pin.attr,
&driver_attr_force_update.attr,
&driver_attr_max_touch_num.attr,
&driver_attr_vkey.attr,
&driver_attr_gesture.attr,
&driver_attr_esd_protection.attr,
&driver_attr_slot_protocol.attr,
&driver_attr_max_xfer_size.attr,
&driver_attr_driver_info.attr,
NULL
};
static const struct attribute_group cts_driver_config_group = {
.name = "config",
.attrs = cts_driver_config_attrs,
};
static const struct attribute_group *cts_driver_config_groups[] = {
&cts_driver_config_group,
NULL,
};
#endif /* CONFIG_CTS_SYSFS */
#ifdef CONFIG_CTS_OF
static const struct of_device_id cts_driver_of_match_table[] = {
{.compatible = CFG_CTS_OF_DEVICE_ID_NAME, },
{ },
};
MODULE_DEVICE_TABLE(of, cts_driver_of_match_table);
#endif /* CONFIG_CTS_OF */
#ifdef CONFIG_CTS_I2C_HOST
static const struct i2c_device_id cts_device_id_table[] = {
{ CFG_CTS_DEVICE_NAME, 0 },
{ }
};
#else
static const struct spi_device_id cts_device_id_table[] = {
{ CFG_CTS_DEVICE_NAME, 0 },
{ }
};
#endif
#ifdef CONFIG_CTS_I2C_HOST
static struct i2c_driver cts_i2c_driver = {
#else
static struct spi_driver cts_spi_driver = {
#endif
.probe = cts_driver_probe,
.remove = cts_driver_remove,
.driver = {
.name = CFG_CTS_DRIVER_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_CTS_OF
.of_match_table = of_match_ptr(cts_driver_of_match_table),
#endif /* CONFIG_CTS_OF */
#ifdef CONFIG_CTS_SYSFS
.groups = cts_driver_config_groups,
#endif /* CONFIG_CTS_SYSFS */
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#ifdef CONFIG_CTS_PM_LEGACY
.suspend = cts_i2c_driver_suspend,
.resume = cts_i2c_driver_resume,
#endif /* CONFIG_CTS_PM_LEGACY */
#ifdef CONFIG_CTS_PM_GENERIC
.pm = &cts_i2c_driver_pm_ops,
#endif /* CONFIG_CTS_PM_GENERIC */
#endif
},
.id_table = cts_device_id_table,
};
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
static int cts_driver_init(void)
#else
static int __init cts_driver_init(void)
#endif
{
int ret = 0;
cts_info("Chipone touch driver init, version: "CFG_CTS_DRIVER_VERSION);
#ifdef CONFIG_CTS_I2C_HOST
cts_info(" - Register i2c driver");
ret = i2c_add_driver(&cts_i2c_driver);
if (ret) {
cts_info("Register i2c driver failed %d(%s)", ret, cts_strerror(ret));
return ret;
}
#else
cts_info(" - Register spi driver");
ret = spi_register_driver(&cts_spi_driver);
if (ret) {
cts_info("Register spi driver failed %d(%s)", ret, cts_strerror(ret));
return ret;
}
#endif
cts_info(" - Register touch driver successfully");
return 0;
}
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
static void cts_driver_exit(void)
#else
static void __exit cts_driver_exit(void)
#endif
{
cts_info("Exit");
#ifdef CONFIG_CTS_I2C_HOST
cts_info(" - Delete i2c driver");
i2c_del_driver(&cts_i2c_driver);
#else
cts_info(" - Delete spi driver");
spi_unregister_driver(&cts_spi_driver);
#endif
}
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
module_init(cts_driver_init);
module_exit(cts_driver_exit);
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
#endif
MODULE_DESCRIPTION("Chipone TDDI touchscreen Driver for QualComm platform");
MODULE_VERSION(CFG_CTS_DRIVER_VERSION);
MODULE_AUTHOR("Miao Defang <dfmiao@chiponeic.com>");
MODULE_LICENSE("GPL");
#else /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */
static int chipone_tpd_local_init(void)
{
#if (defined(TPD_WARP_START) && defined(TPD_WARP_END))
static int tpd_wb_start_local[TPD_WARP_CNT] = TPD_WARP_START;
static int tpd_wb_end_local[TPD_WARP_CNT] = TPD_WARP_END;
#endif
#if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION))
static int tpd_def_calmat_local[8] = TPD_CALIBRATION_MATRIX;
#endif
int ret;
if ((ret = cts_driver_init()) != 0) {
cts_err("Init driver failed %d", ret);
return ret;
}
if (tpd_load_status == 0) {
cts_err("Driver not load successfully, exit.");
cts_driver_exit();
return -1;
}
#if (defined(TPD_WARP_START) && defined(TPD_WARP_END))
TPD_DO_WARP = 1;
memcpy(tpd_wb_start, tpd_wb_start_local, TPD_WARP_CNT * 4);
memcpy(tpd_wb_end, tpd_wb_start_local, TPD_WARP_CNT * 4);
#endif
#if (defined(CONFIG_TPD_HAVE_CALIBRATION) && !defined(CONFIG_TPD_CUSTOM_CALIBRATION))
memcpy(tpd_calmat, tpd_def_calmat_local, 8 * 4);
memcpy(tpd_def_calmat, tpd_def_calmat_local, 8 * 4);
#endif
tpd_type_cap = 1;
return 0;
}
/* TPD pass dev = NULL */
static void chipone_tpd_suspend(struct device *dev)
{
cts_suspend(g_cts_data);
}
/* TPD pass dev = NULL */
static void chipone_tpd_resume(struct device *dev)
{
cts_resume(g_cts_data);
}
static struct tpd_driver_t chipone_tpd_driver = {
.tpd_device_name = CFG_CTS_DRIVER_NAME,
.tpd_local_init = chipone_tpd_local_init,
.suspend = chipone_tpd_suspend,
.resume = chipone_tpd_resume,
.tpd_have_button = 0,
.attrs = {
.attr = NULL,
.num = 0,
}
};
static int __init chipone_tpd_driver_init(void)
{
int ret;
cts_info("Chipone TDDI TPD driver %s", CFG_CTS_DRIVER_VERSION);
tpd_get_dts_info();
if (tpd_dts_data.touch_max_num < 2) {
tpd_dts_data.touch_max_num = 2;
} else if (tpd_dts_data.touch_max_num > CFG_CTS_MAX_TOUCH_NUM) {
tpd_dts_data.touch_max_num = CFG_CTS_MAX_TOUCH_NUM;
}
if((ret = tpd_driver_add(&chipone_tpd_driver)) < 0) {
cts_err("Add TPD driver failed %d", ret);
return ret;
}
return 0;
}
static void __exit chipone_tpd_driver_exit(void)
{
cts_info("Chipone TPD driver exit");
tpd_driver_remove(&chipone_tpd_driver);
}
module_init(chipone_tpd_driver_init);
module_exit(chipone_tpd_driver_exit);
#ifdef CFG_CTS_KERNEL_BUILTIN_FIRMWARE
MODULE_FIRMWARE(CFG_CTS_FIRMWARE_FILENAME_9916);
#endif /* CFG_CTS_KERNEL_BUILTIN_FIRMWARE */
MODULE_DESCRIPTION("Chipone TDDI TPD Driver for MTK platform");
MODULE_VERSION(CFG_CTS_DRIVER_VERSION);
MODULE_AUTHOR("Miao Defang <dfmiao@chiponeic.com>");
MODULE_LICENSE("GPL");
#endif /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */