unplugged-kernel/drivers/input/touchscreen/mediatek/hxchipset_hx83102p/himax_platform.c

769 lines
17 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include "himax_platform.h"
#include "himax_common.h"
int i2c_error_count;
bool ic_boot_done;
const struct of_device_id himax_match_table[] = {
//{.compatible = "mediatek,cap_touch" },
//{.compatible = "mediatek,touch" },
{.compatible = "himax,hxcommon" },
{},
};
MODULE_DEVICE_TABLE(of, himax_match_table);
static int himax_tpd_int_gpio = 5;
unsigned int himax_tpd_rst_gpio_number = -1;
unsigned int himax_tpd_int_gpio_number = -1;
static uint8_t *gBuffer;
/* Custom set some config */
/* [1]=X resolution, [3]=Y resolution */
static int hx_panel_coords[4] = {0, 1200, 0, 2000};
static int hx_display_coords[4] = {0, 1200, 0, 2000};
static int report_type = PROTOCOL_TYPE_B;
struct device *g_device;
/******* SPI-start *******/
static struct spi_device *hx_spi;
/******* SPI-end *******/
void (*kp_tpd_gpio_as_int)(int gpio);
int (*kp_tpd_driver_add)(struct tpd_driver_t *drv);
void (*kp_tpd_get_dts_info)(void);
void (*kp_tpd_gpio_output)(int pinnum, int value);
int (*kp_tpd_driver_remove)(struct tpd_driver_t *drv);
const struct of_device_id *kp_touch_of_match;
struct tpd_device **kp_tpd;
#if !defined(HX_USE_KSYM)
#define setup_symbol(sym) ({kp_##sym = &(sym); kp_##sym; })
#define setup_symbol_func(sym) ({kp_##sym = (sym); kp_##sym; })
#else
#define setup_symbol(sym) ({kp_##sym = \
(void *)kallsyms_lookup_name(#sym); kp_##sym; })
#define setup_symbol_func(sym) setup_symbol(sym)
#endif
#define assert_on_symbol(sym) \
do { \
if (!setup_symbol(sym)) { \
E("%s: setup %s failed!\n", __func__, #sym); \
ret = -1; \
} \
} while (0)
#define assert_on_symbol_func(sym) \
do { \
if (!setup_symbol_func(sym)) { \
E("%s: setup %s failed!\n", __func__, #sym); \
ret = -1; \
} \
} while (0)
int32_t setup_tpd_vars(void)
{
int32_t ret = 0;
assert_on_symbol_func(tpd_gpio_as_int);
assert_on_symbol_func(tpd_driver_add);
assert_on_symbol_func(tpd_get_dts_info);
assert_on_symbol_func(tpd_gpio_output);
assert_on_symbol_func(tpd_driver_remove);
kp_touch_of_match = (const struct of_device_id *)(&(touch_of_match[0]));
assert_on_symbol(tpd);
return ret;
}
int himax_dev_set(struct himax_ts_data *ts)
{
int ret = 0;
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
ret = -ENOMEM;
E("%s: Failed to allocate input device-input_dev\n", __func__);
return ret;
}
ts->input_dev->name = "mtk-tpd";
if (!ic_data->HX_PEN_FUNC)
goto skip_pen_operation;
ts->hx_pen_dev = input_allocate_device();
if (ts->hx_pen_dev == NULL) {
ret = -ENOMEM;
E("%s: Failed to allocate input device-hx_pen_dev\n", __func__);
input_free_device(ts->input_dev);
return ret;
}
ts->hx_pen_dev->name = "himax-pen";
skip_pen_operation:
return ret;
}
int himax_input_register_device(struct input_dev *input_dev)
{
return input_register_device(input_dev);
}
void himax_vk_parser(struct device_node *dt,
struct himax_i2c_platform_data *pdata)
{
u32 data = 0;
uint8_t cnt = 0, i = 0;
uint32_t coords[4] = {0};
struct device_node *node, *pp = NULL;
struct himax_virtual_key *vk;
node = of_parse_phandle(dt, "virtualkey", 0);
if (node == NULL) {
I(" DT-No vk info in DT\n");
goto END;
} else {
while ((pp = of_get_next_child(node, pp)))
cnt++;
if (!cnt)
goto END;
vk = kcalloc(cnt, sizeof(*vk), GFP_KERNEL);
if (vk == NULL) {
E("%s, Failed to allocate memory\n", __func__);
return;
}
pp = NULL;
while ((pp = of_get_next_child(node, pp))) {
if (of_property_read_u32(pp, "idx", &data) == 0)
vk[i].index = data;
if (of_property_read_u32_array(pp, "range", coords, 4)
== 0) {
vk[i].x_range_min = coords[0];
vk[i].x_range_max = coords[1];
vk[i].y_range_min = coords[2];
vk[i].y_range_max = coords[3];
} else
I(" range faile\n");
i++;
}
pdata->virtual_key = vk;
for (i = 0; i < cnt; i++)
I(" vk[%d] idx:%d x_min:%d, y_max:%d\n", i,
pdata->virtual_key[i].index,
pdata->virtual_key[i].x_range_min,
pdata->virtual_key[i].y_range_max);
}
END:
return;
}
int himax_parse_dt(struct himax_ts_data *ts,
struct himax_i2c_platform_data *pdata)
{
struct device_node *dt = NULL;
dt = ts->dev->of_node;
I("%s: Entering!\n", __func__);
himax_tpd_rst_gpio_number = GTP_RST_PORT;
himax_tpd_int_gpio_number = GTP_INT_PORT;
pdata->gpio_reset = himax_tpd_rst_gpio_number;
pdata->gpio_irq = himax_tpd_int_gpio_number;
I("%s: int : %2.2x\n", __func__, pdata->gpio_irq);
I("%s: rst : %2.2x\n", __func__, pdata->gpio_reset);
himax_vk_parser(dt, pdata);
/* Set device tree data */
/* Set panel coordinates */
pdata->abs_x_min = hx_panel_coords[0];
pdata->abs_x_max = hx_panel_coords[1];
pdata->abs_y_min = hx_panel_coords[2];
pdata->abs_y_max = hx_panel_coords[3];
I(" %s:panel-coords = %d, %d, %d, %d\n", __func__,
pdata->abs_x_min,
pdata->abs_x_max,
pdata->abs_y_min,
pdata->abs_y_max);
/* Set display coordinates */
pdata->screenWidth = hx_display_coords[1];
pdata->screenHeight = hx_display_coords[3];
I(" %s:display-coords = (%d, %d)\n", __func__,
pdata->screenWidth,
pdata->screenHeight);
/* report type */
pdata->protocol_type = report_type;
return 0;
}
static ssize_t himax_spi_sync(struct spi_message *message)
{
int status;
status = spi_sync(hx_spi, message);
if (status == 0) {
status = message->status;
if (status == 0)
status = message->actual_length;
}
return status;
}
static int himax_spi_read(uint8_t *command, uint8_t command_len,
uint8_t *data, uint32_t length, uint8_t toRetry)
{
struct spi_message message;
struct spi_transfer xfer[2];
int retry = 0;
int error = -1;
spi_message_init(&message);
memset(xfer, 0, sizeof(xfer));
xfer[0].tx_buf = command;
xfer[0].len = command_len;
spi_message_add_tail(&xfer[0], &message);
xfer[1].tx_buf = data;
xfer[1].rx_buf = data;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &message);
for (retry = 0; retry < toRetry; retry++) {
error = spi_sync(hx_spi, &message);
if (error)
E("SPI read error: %d\n", error);
else
break;
}
if (retry == toRetry) {
E("%s: SPI read error retry over %d\n",
__func__, toRetry);
return -EIO;
}
return 0;
}
static int himax_spi_write(uint8_t *buf, uint32_t length)
{
struct spi_transfer t = {
.tx_buf = buf,
.len = length,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return himax_spi_sync(&m);
}
int himax_bus_read(uint8_t command, uint8_t *data,
uint32_t length, uint8_t toRetry)
{
int result = 0;
uint8_t spi_format_buf[3];
mutex_lock(&private_ts->rw_lock);
spi_format_buf[0] = 0xF3;
spi_format_buf[1] = command;
spi_format_buf[2] = 0x00;
result = himax_spi_read(&spi_format_buf[0], 3, data, length, 10);
mutex_unlock(&private_ts->rw_lock);
return result;
}
int himax_bus_write(uint8_t command, uint8_t *data,
uint32_t length, uint8_t toRetry)
{
int i = 0;
int result = 0;
uint8_t *spi_format_buf = gBuffer;
mutex_lock(&private_ts->rw_lock);
spi_format_buf[0] = 0xF2;
spi_format_buf[1] = command;
for (i = 0; i < length; i++)
spi_format_buf[i + 2] = data[i];
result = himax_spi_write(spi_format_buf, length + 2);
mutex_unlock(&private_ts->rw_lock);
return result;
}
int himax_bus_write_command(uint8_t command, uint8_t toRetry)
{
return himax_bus_write(command, NULL, 0, toRetry);
}
uint8_t himax_int_gpio_read(int pinnum)
{
return gpio_get_value(himax_tpd_int_gpio);
}
void himax_int_enable(int enable)
{
struct himax_ts_data *ts = private_ts;
unsigned long irqflags = 0;
int irqnum = ts->hx_irq;
spin_lock_irqsave(&ts->irq_lock, irqflags);
I("%s: Entering! irqnum = %d\n", __func__, irqnum);
if (enable == 1 && atomic_read(&ts->irq_state) == 0) {
atomic_set(&ts->irq_state, 1);
enable_irq(irqnum);
private_ts->irq_enabled = 1;
} else if (enable == 0 && atomic_read(&ts->irq_state) == 1) {
atomic_set(&ts->irq_state, 0);
disable_irq_nosync(irqnum);
private_ts->irq_enabled = 0;
}
I("enable = %d\n", enable);
spin_unlock_irqrestore(&ts->irq_lock, irqflags);
}
#if defined(HX_RST_PIN_FUNC)
void himax_rst_gpio_set(int pinnum, uint8_t value)
{
if (value)
kp_tpd_gpio_output(himax_tpd_rst_gpio_number, 1);
else
kp_tpd_gpio_output(himax_tpd_rst_gpio_number, 0);
}
#endif
int himax_gpio_power_config(struct himax_i2c_platform_data *pdata)
{
int error = 0;
error = regulator_enable((*kp_tpd)->reg);
if (error != 0)
I("Failed to enable reg-vgp6: %d\n", error);
msleep(100);
#if defined(HX_RST_PIN_FUNC)
kp_tpd_gpio_output(himax_tpd_rst_gpio_number, 1);
msleep(20);
kp_tpd_gpio_output(himax_tpd_rst_gpio_number, 0);
msleep(20);
kp_tpd_gpio_output(himax_tpd_rst_gpio_number, 1);
#endif
I("mtk_tpd: himax reset over\n");
/* set INT mode */
kp_tpd_gpio_as_int(himax_tpd_int_gpio_number);
return 0;
}
void himax_gpio_power_deconfig(struct himax_i2c_platform_data *pdata)
{
int error = 0;
error = regulator_disable(tpd->reg);
if (error != 0)
I("Failed to disable reg-vgp6: %d\n", error);
regulator_put(tpd->reg);
I("%s: regulator put, completed.\n", __func__);
}
static void himax_ts_isr_func(struct himax_ts_data *ts)
{
himax_ts_work(ts);
}
irqreturn_t himax_ts_thread(int irq, void *ptr)
{
himax_ts_isr_func((struct himax_ts_data *)ptr);
return IRQ_HANDLED;
}
static void himax_ts_work_func(struct work_struct *work)
{
struct himax_ts_data *ts = container_of(work,
struct himax_ts_data, work);
himax_ts_work(ts);
}
int himax_int_register_trigger(void)
{
int ret = NO_ERR;
struct himax_ts_data *ts = private_ts;
if (ic_data->HX_INT_IS_EDGE) {
ret = request_threaded_irq(ts->hx_irq, NULL, himax_ts_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
HIMAX_common_NAME, ts);
} else {
ret = request_threaded_irq(ts->hx_irq, NULL, himax_ts_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, HIMAX_common_NAME, ts);
}
return ret;
}
int himax_int_en_set(void)
{
int ret = NO_ERR;
ret = himax_int_register_trigger();
return ret;
}
int himax_ts_register_interrupt(void)
{
struct himax_ts_data *ts = private_ts;
struct device_node *node = NULL;
u32 ints[2] = {0, 0};
int ret = 0;
node = of_find_matching_node(node, (kp_touch_of_match));
if (node) {
if (of_property_read_u32_array(node, "debounce",
ints, ARRAY_SIZE(ints)) == 0) {
I("%s: Now it has set debounce\n", __func__);
gpio_set_debounce(ints[0], ints[1]);
I("%s: Now debounce are ints[0] = %d, ints[1] = %d\n",
__func__, ints[0], ints[1]);
} else {
I("%s: DOES NOT set debounce!\n", __func__);
}
ts->hx_irq = irq_of_parse_and_map(node, 0);
I("himax_touch_irq=%d\n", ts->hx_irq);
} else {
I("[%s] tpd request_irq can not find touch eint device node!\n",
__func__);
ts->hx_irq = 0;
}
ts->irq_enabled = 0;
ts->use_irq = 0;
/* Work functon */
if (ts->hx_irq) {/*INT mode*/
ts->use_irq = 1;
ret = himax_int_register_trigger();
if (ret == 0) {
ts->irq_enabled = 1;
atomic_set(&ts->irq_state, 1);
I("%s: irq enabled at gpio: %d\n",
__func__, ts->hx_irq);
#if defined(HX_SMART_WAKEUP)
irq_set_irq_wake(ts->hx_irq, 1);
#endif
} else {
ts->use_irq = 0;
E("%s: request_irq failed\n", __func__);
}
} else {
I("%s: ts->hx_irq is empty, use polling mode.\n", __func__);
}
/*if use polling mode need to disable HX_ESD_RECOVERY function*/
if (!ts->use_irq) {
ts->himax_wq = create_singlethread_workqueue("himax_touch");
INIT_WORK(&ts->work, himax_ts_work_func);
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = himax_ts_timer_func;
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
I("%s: polling mode enabled\n", __func__);
}
tpd_load_status = 1;
return ret;
}
int himax_ts_unregister_interrupt(void)
{
struct himax_ts_data *ts = private_ts;
int ret = 0;
I("%s: entered.\n", __func__);
/* Work functon */
if (ts->hx_irq && ts->use_irq) {/*INT mode*/
#if defined(HX_SMART_WAKEUP)
irq_set_irq_wake(ts->hx_irq, 0);
#endif
free_irq(ts->hx_irq, ts);
I("%s: irq disabled at qpio: %d\n", __func__, ts->hx_irq);
}
/*if use polling mode need to disable HX_ESD_RECOVERY function*/
if (!ts->use_irq) {
hrtimer_cancel(&ts->timer);
cancel_work_sync(&ts->work);
if (ts->himax_wq != NULL)
destroy_workqueue(ts->himax_wq);
I("%s: polling mode destroyed", __func__);
}
return ret;
}
struct pinctrl *himax_spi_pinctrl;
struct pinctrl_state *spi_all;
static int himax_common_probe_spi(struct spi_device *spi)
{
struct himax_ts_data *ts = NULL;
int ret = 0;
/* Allocate driver data */
I("%s:IN!\n", __func__);
gBuffer = kzalloc(sizeof(uint8_t) * (HX_MAX_WRITE_SZ + 2), GFP_KERNEL);
if (gBuffer == NULL) {
E("%s: allocate gBuffer failed\n", __func__);
ret = -ENOMEM;
goto err_alloc_gbuffer_failed;
}
ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL);
if (ts == NULL) {
E("%s: allocate himax_ts_data failed\n", __func__);
ret = -ENOMEM;
goto err_alloc_data_failed;
}
/* Initialize the driver data */
hx_spi = spi;
/* setup SPI parameters */
/* CPOL=CPHA=0, speed 1MHz */
if (hx_spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
I("Full duplex not supported by master\n");
ret = -EIO;
goto err_spi_setup;
}
hx_spi->mode = SPI_MODE_3;
hx_spi->bits_per_word = 8;
ts->hx_irq = 0;
spi_set_drvdata(spi, ts);
ts->dev = &spi->dev;
g_device = &spi->dev;
private_ts = ts;
mutex_init(&ts->rw_lock);
ret = himax_chip_common_init();
if (ret < 0)
goto err_common_init_failed;
return ret;
err_common_init_failed:
err_spi_setup:
kfree(ts);
err_alloc_data_failed:
kfree(gBuffer);
gBuffer = NULL;
err_alloc_gbuffer_failed:
return ret;
}
int himax_common_remove_spi(struct spi_device *spi)
{
int ret = 0;
if (g_hx_chip_inited)
himax_chip_common_deinit();
spi_set_drvdata(spi, NULL);
kfree(gBuffer);
return ret;
}
static void himax_common_suspend(struct device *dev)
{
struct himax_ts_data *ts = private_ts;
I("%s: enter\n", __func__);
himax_chip_common_suspend(ts);
I("%s: END\n", __func__);
}
static void himax_common_resume(struct device *dev)
{
struct himax_ts_data *ts = private_ts;
I("%s: enter\n", __func__);
himax_chip_common_resume(ts);
I("%s: END\n", __func__);
}
#if defined(HX_CONFIG_FB)
int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
struct fb_event *evdata = data;
int *blank;
struct himax_ts_data *ts =
container_of(self, struct himax_ts_data, fb_notif);
I(" %s\n", __func__);
if (ic_boot_done != 1) {
E("%s: IC is booting\n", __func__);
return -ECANCELED;
}
if (evdata && evdata->data &&
#if defined(HX_CONTAINER_SPEED_UP)
event == FB_EARLY_EVENT_BLANK
#else
event == FB_EVENT_BLANK
#endif
&& ts && (hx_spi)) {
blank = evdata->data;
switch (*blank) {
case FB_BLANK_UNBLANK:
#if defined(HX_CONTAINER_SPEED_UP)
queue_delayed_work(ts->ts_int_workqueue,
&ts->ts_int_work,
msecs_to_jiffies(DELAY_TIME));
#else
himax_common_resume(ts->dev);
#endif
break;
case FB_BLANK_POWERDOWN:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_NORMAL:
himax_common_suspend(ts->dev);
break;
}
}
return 0;
}
#endif
static const struct i2c_device_id himax_common_ts_id[] = {
{HIMAX_common_NAME, 0 },
{}
};
struct spi_device_id hx_spi_id_table = {"himax-spi", 1};
struct spi_driver himax_common_driver = {
.driver = {
.name = HIMAX_common_NAME,
.bus = &spi_bus_type,
.owner = THIS_MODULE,
#if defined(CONFIG_OF)
.of_match_table = himax_match_table,
#endif
},
.probe = himax_common_probe_spi,
.remove = himax_common_remove_spi,
.id_table = &hx_spi_id_table,
};
static int himax_common_local_init(void)
{
int retval;
I("[Himax] Himax_ts SPI Touchscreen Driver local init\n");
(*kp_tpd)->reg = regulator_get((*kp_tpd)->tpd_dev, "vtouch");
retval = regulator_set_voltage((*kp_tpd)->reg, 2800000, 2800000);
if (retval != 0)
E("Failed to set voltage 2V8: %d\n", retval);
retval = spi_register_driver(&himax_common_driver);
if (retval < 0) {
E("unable to add SPI driver.\n");
return -EFAULT;
}
I("[Himax] Himax_ts SPI Touchscreen Driver local init end!\n");
I("%s end.\n", __func__);
tpd_type_cap = 1;
tpd->dev->name = "no-use_tpd";
return 0;
}
static struct tpd_driver_t tpd_device_driver = {
.tpd_device_name = HIMAX_common_NAME,
.tpd_local_init = himax_common_local_init,
.suspend = himax_common_suspend,
.resume = himax_common_resume,
#if defined(TPD_HAVE_BUTTON)
.tpd_have_button = 1,
#else
.tpd_have_button = 0,
#endif
};
static int __init himax_common_init(void)
{
I("Himax_common touch panel driver init\n");
D("Himax check double loading\n");
if (g_mmi_refcnt++ > 0) {
I("Himax driver has been loaded! ignoring....\n");
goto END;
}
if (setup_tpd_vars() != 0) {
E("Failed to get tpd variables!\n");
goto ERR;
}
kp_tpd_get_dts_info();
if (kp_tpd_driver_add(&tpd_device_driver) < 0) {
I("Failed to add Driver!\n");
goto ERR;
}
END:
return 0;
ERR:
return HX_INIT_FAIL;
}
static void __exit himax_common_exit(void)
{
spi_unregister_driver(&himax_common_driver);
kp_tpd_driver_remove(&tpd_device_driver);
}
module_init(himax_common_init);
module_exit(himax_common_exit);
MODULE_DESCRIPTION("Himax_common driver");
MODULE_LICENSE("GPL");