768 lines
18 KiB
C
768 lines
18 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include "himax_ic.h"
|
|
|
|
int i2c_error_count;
|
|
int irq_enable_count;
|
|
|
|
DEFINE_MUTEX(hx_wr_access);
|
|
|
|
MODULE_DEVICE_TABLE(of, himax_match_table);
|
|
const struct of_device_id himax_match_table[] = {
|
|
{.compatible = "mediatek,cap_touch"}, {},
|
|
};
|
|
|
|
static int himax_tpd_int_gpio = 5;
|
|
unsigned int himax_touch_irq;
|
|
unsigned int himax_tpd_rst_gpio_number = -1;
|
|
unsigned int himax_tpd_int_gpio_number = -1;
|
|
|
|
u8 *gpDMABuf_va;
|
|
u8 *gpDMABuf_pa;
|
|
|
|
/* Custom set some config */
|
|
static int hx_panel_coords[4] = {0, 1080, 0,
|
|
1920}; /* [1]=X resolution, [3]=Y resolution */
|
|
static int hx_display_coords[4] = {0, 1080, 0, 1920};
|
|
static int report_type = PROTOCOL_TYPE_B;
|
|
|
|
struct i2c_client *i2c_client_point;
|
|
|
|
#if defined(HX_PLATFOME_DEFINE_KEY)
|
|
/*In MT6797 need to set 1 into use-tpd-button in dts */
|
|
/* kernel-3.18\arch\arm64\boot\dts\amt6797_evb_m.dts*/
|
|
/*key_range : [keyindex][key_data] {..{x,y}..}*/
|
|
static int key_range[3][2] = {{180, 2400}, {360, 2400}, {540, 2400} };
|
|
#endif
|
|
|
|
int himax_dev_set(struct himax_ts_data *ts)
|
|
{
|
|
ts->input_dev = tpd->dev;
|
|
|
|
return NO_ERR;
|
|
}
|
|
int himax_input_register_device(struct input_dev *input_dev)
|
|
{
|
|
return NO_ERR;
|
|
}
|
|
|
|
#if defined(HX_PLATFOME_DEFINE_KEY)
|
|
void himax_platform_key(void)
|
|
{
|
|
int idx = 0;
|
|
|
|
if (tpd_dts_data.use_tpd_button) {
|
|
for (idx = 0; idx < tpd_dts_data.tpd_key_num; idx++) {
|
|
input_set_capability(tpd->dev, EV_KEY,
|
|
tpd_dts_data.tpd_key_local[idx]);
|
|
I("[%d]key:%d\n", idx, tpd_dts_data.tpd_key_local[idx]);
|
|
}
|
|
}
|
|
}
|
|
/* report coordinates to system and system will transfer it into Key */
|
|
static void himax_vk_parser(struct himax_i2c_platform_data *pdata, int key_num)
|
|
{
|
|
int i = 0;
|
|
struct himax_virtual_key *vk;
|
|
uint8_t key_index = 0;
|
|
|
|
vk = kzalloc(key_num * (sizeof(*vk)), GFP_KERNEL);
|
|
for (key_index = 0; key_index < key_num; key_index++) {
|
|
/* index: def in our driver */
|
|
vk[key_index].index = key_index + 1;
|
|
/* key size */
|
|
vk[key_index].x_range_min = key_range[key_index][0],
|
|
vk[key_index].x_range_max = key_range[key_index][0];
|
|
vk[key_index].y_range_min = key_range[key_index][1],
|
|
vk[key_index].y_range_max = key_range[key_index][1];
|
|
}
|
|
pdata->virtual_key = vk;
|
|
|
|
for (i = 0; i < key_num; i++) {
|
|
I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,
|
|
pdata->virtual_key[i].index,
|
|
pdata->virtual_key[i].x_range_min,
|
|
pdata->virtual_key[i].y_range_max);
|
|
}
|
|
}
|
|
#else
|
|
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");
|
|
return;
|
|
}
|
|
while ((pp = of_get_next_child(node, pp)))
|
|
cnt++;
|
|
if (!cnt)
|
|
return;
|
|
|
|
vk = kzalloc(cnt * (sizeof(*vk)), GFP_KERNEL);
|
|
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");
|
|
i++;
|
|
}
|
|
pdata->virtual_key = vk;
|
|
for (i = 0; i < cnt; i++)
|
|
I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,
|
|
pdata->virtual_key[i].index,
|
|
pdata->virtual_key[i].x_range_min,
|
|
pdata->virtual_key[i].y_range_max);
|
|
}
|
|
#endif
|
|
int himax_parse_dt(struct himax_ts_data *ts,
|
|
struct himax_i2c_platform_data *pdata)
|
|
{
|
|
struct device_node *dt = ts->client->dev.of_node;
|
|
struct i2c_client *client = ts->client;
|
|
|
|
if (dt) {
|
|
const struct of_device_id *match;
|
|
|
|
match = of_match_device(of_match_ptr(himax_match_table),
|
|
&client->dev);
|
|
if (!match) {
|
|
TPD_DMESG("[Himax]Error: No device match found\n");
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
#if defined(HX_PLATFOME_DEFINE_KEY)
|
|
|
|
/* now 3 keys */
|
|
himax_vk_parser(pdata, 3);
|
|
#else
|
|
himax_vk_parser(dt, pdata);
|
|
|
|
#endif
|
|
|
|
/* 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)", __func__, pdata->screenWidth,
|
|
pdata->screenHeight);
|
|
/* report type */
|
|
pdata->protocol_type = report_type;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef MTK_I2C_DMA
|
|
int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data,
|
|
uint8_t length, uint8_t toRetry)
|
|
{
|
|
int ret = 0;
|
|
s32 retry = 0;
|
|
u8 buffer[1];
|
|
|
|
struct i2c_msg msg[] = {
|
|
{.addr = (client->addr & I2C_MASK_FLAG),
|
|
.flags = 0,
|
|
.buf = buffer,
|
|
.len = 1,
|
|
.timing = 400},
|
|
{.addr = (client->addr & I2C_MASK_FLAG),
|
|
.ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
|
|
.flags = I2C_M_RD,
|
|
.buf = gpDMABuf_pa,
|
|
.len = length,
|
|
.timing = 400},
|
|
};
|
|
mutex_lock(&hx_wr_access);
|
|
buffer[0] = command;
|
|
|
|
if (data == NULL) {
|
|
mutex_unlock(&hx_wr_access);
|
|
return -1;
|
|
}
|
|
for (retry = 0; retry < toRetry; ++retry) {
|
|
ret = i2c_transfer(client->adapter, &msg[0], 2);
|
|
if (ret < 0)
|
|
continue;
|
|
|
|
memcpy(data, gpDMABuf_va, length);
|
|
mutex_unlock(&hx_wr_access);
|
|
return 0;
|
|
}
|
|
E("Dma I2C Read Error: %d byte(s), err-code: %d", length, ret);
|
|
i2c_error_count = toRetry;
|
|
mutex_unlock(&hx_wr_access);
|
|
return ret;
|
|
}
|
|
|
|
int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *buf,
|
|
uint8_t len, uint8_t toRetry)
|
|
{
|
|
int rc = 0, retry = 0;
|
|
u8 *pWriteData = gpDMABuf_va;
|
|
|
|
struct i2c_msg msg[] = {
|
|
{.addr = (client->addr & I2C_MASK_FLAG),
|
|
.ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
|
|
.flags = 0,
|
|
.buf = gpDMABuf_pa,
|
|
.len = len + 1,
|
|
.timing = 400},
|
|
};
|
|
|
|
mutex_lock(&hx_wr_access);
|
|
if (!pWriteData) {
|
|
E("dma_alloc_coherent failed!\n");
|
|
mutex_unlock(&hx_wr_access);
|
|
return -1;
|
|
}
|
|
|
|
gpDMABuf_va[0] = command;
|
|
|
|
memcpy(gpDMABuf_va + 1, buf, len);
|
|
|
|
for (retry = 0; retry < toRetry; ++retry) {
|
|
rc = i2c_transfer(client->adapter, &msg[0], 1);
|
|
if (rc < 0)
|
|
continue;
|
|
|
|
mutex_unlock(&hx_wr_access);
|
|
return 0;
|
|
}
|
|
|
|
E("Dma I2C master write Error: %d byte(s), err-code: %d", len, rc);
|
|
i2c_error_count = toRetry;
|
|
mutex_unlock(&hx_wr_access);
|
|
return rc;
|
|
}
|
|
|
|
int i2c_himax_write_command(struct i2c_client *client, uint8_t command,
|
|
uint8_t toRetry)
|
|
{
|
|
return i2c_himax_write(client, command, NULL, 0, toRetry);
|
|
}
|
|
|
|
int i2c_himax_master_write(struct i2c_client *client, uint8_t *buf, uint8_t len,
|
|
uint8_t toRetry)
|
|
{
|
|
int rc = 0, retry = 0;
|
|
u8 *pWriteData = gpDMABuf_va;
|
|
|
|
struct i2c_msg msg[] = {
|
|
{.addr = (client->addr & I2C_MASK_FLAG),
|
|
.ext_flag = (client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
|
|
.flags = 0,
|
|
.buf = gpDMABuf_pa,
|
|
.len = len,
|
|
.timing = 400},
|
|
};
|
|
|
|
mutex_lock(&hx_wr_access);
|
|
if (!pWriteData) {
|
|
E("dma_alloc_coherent failed!\n");
|
|
mutex_unlock(&hx_wr_access);
|
|
return -1;
|
|
}
|
|
|
|
memcpy(gpDMABuf_va, buf, len);
|
|
for (retry = 0; retry < toRetry; ++retry) {
|
|
rc = i2c_transfer(client->adapter, &msg[0], 1);
|
|
if (rc < 0)
|
|
continue;
|
|
|
|
mutex_unlock(&hx_wr_access);
|
|
return 0;
|
|
}
|
|
E("Dma I2C master write Error: %d byte(s), err-code: %d", len, rc);
|
|
i2c_error_count = toRetry;
|
|
mutex_unlock(&hx_wr_access);
|
|
return rc;
|
|
}
|
|
|
|
#else
|
|
int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data,
|
|
uint8_t length, uint8_t toRetry)
|
|
{
|
|
int retry;
|
|
struct i2c_msg msg[] = {{
|
|
.addr = client->addr,
|
|
.flags = 0,
|
|
.len = 1,
|
|
.buf = &command,
|
|
},
|
|
{
|
|
.addr = client->addr,
|
|
.flags = I2C_M_RD,
|
|
.len = length,
|
|
.buf = data,
|
|
} };
|
|
|
|
for (retry = 0; retry < toRetry; retry++) {
|
|
if (i2c_transfer(client->adapter, msg, 2) == 2)
|
|
break;
|
|
msleep(20);
|
|
}
|
|
if (retry == toRetry) {
|
|
E("%s: i2c_read_block retry over %d\n", __func__, toRetry);
|
|
i2c_error_count = toRetry;
|
|
return -EIO;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data,
|
|
uint8_t length, uint8_t toRetry)
|
|
{
|
|
int retry /*, loop_i*/;
|
|
uint8_t buf[length + 1];
|
|
|
|
struct i2c_msg msg[] = {{
|
|
.addr = client->addr, .flags = 0, .len = length + 1, .buf = buf,
|
|
} };
|
|
|
|
buf[0] = command;
|
|
memcpy(buf + 1, data, length);
|
|
|
|
for (retry = 0; retry < toRetry; retry++) {
|
|
if (i2c_transfer(client->adapter, msg, 1) == 1)
|
|
break;
|
|
msleep(20);
|
|
}
|
|
|
|
if (retry == toRetry) {
|
|
E("%s: i2c_write_block retry over %d\n", __func__, toRetry);
|
|
i2c_error_count = toRetry;
|
|
return -EIO;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int i2c_himax_write_command(struct i2c_client *client, uint8_t command,
|
|
uint8_t toRetry)
|
|
{
|
|
return i2c_himax_write(client, command, NULL, 0, toRetry);
|
|
}
|
|
|
|
int i2c_himax_master_write(struct i2c_client *client, uint8_t *data,
|
|
uint8_t length, uint8_t toRetry)
|
|
{
|
|
int retry /*, loop_i*/;
|
|
uint8_t buf[length];
|
|
|
|
struct i2c_msg msg[] = {{
|
|
.addr = client->addr, .flags = 0, .len = length, .buf = buf,
|
|
} };
|
|
|
|
memcpy(buf, data, length);
|
|
|
|
for (retry = 0; retry < toRetry; retry++) {
|
|
if (i2c_transfer(client->adapter, msg, 1) == 1)
|
|
break;
|
|
msleep(20);
|
|
}
|
|
|
|
if (retry == toRetry) {
|
|
E("%s: i2c_write_block retry over %d\n", __func__, toRetry);
|
|
i2c_error_count = toRetry;
|
|
return -EIO;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
uint8_t himax_int_gpio_read(int pinnum)
|
|
{
|
|
return gpio_get_value(himax_tpd_int_gpio);
|
|
}
|
|
|
|
void himax_int_enable(int irqnum, int enable)
|
|
{
|
|
I("%s: Entering!\n", __func__);
|
|
if (enable == 1 && irq_enable_count == 0) {
|
|
enable_irq(irqnum);
|
|
irq_enable_count++;
|
|
private_ts->irq_enabled = 1;
|
|
} else if (enable == 0 && irq_enable_count == 1) {
|
|
disable_irq_nosync(irqnum);
|
|
irq_enable_count--;
|
|
private_ts->irq_enabled = 0;
|
|
}
|
|
I("irq_enable_count = %d\n", irq_enable_count);
|
|
}
|
|
|
|
#ifdef HX_RST_PIN_FUNC
|
|
void himax_rst_gpio_set(int pinnum, uint8_t value)
|
|
{
|
|
if (value)
|
|
tpd_gpio_output(himax_tpd_rst_gpio_number, 1);
|
|
else
|
|
tpd_gpio_output(himax_tpd_rst_gpio_number, 0);
|
|
}
|
|
#endif
|
|
|
|
int himax_gpio_power_config(struct i2c_client *client,
|
|
struct himax_i2c_platform_data *pdata)
|
|
{
|
|
int error = 0;
|
|
|
|
error = regulator_enable(tpd->reg);
|
|
if (error != 0)
|
|
TPD_DMESG("Failed to enable reg-vgp6: %d\n", error);
|
|
msleep(100);
|
|
|
|
#ifdef HX_RST_PIN_FUNC
|
|
tpd_gpio_output(himax_tpd_rst_gpio_number, 1);
|
|
msleep(20);
|
|
tpd_gpio_output(himax_tpd_rst_gpio_number, 0);
|
|
msleep(20);
|
|
tpd_gpio_output(himax_tpd_rst_gpio_number, 1);
|
|
#endif
|
|
|
|
TPD_DMESG("mtk_tpd: himax reset over\n");
|
|
|
|
/* set INT mode */
|
|
|
|
tpd_gpio_as_int(himax_tpd_int_gpio_number);
|
|
return 0;
|
|
}
|
|
|
|
static void himax_ts_isr_func(struct himax_ts_data *ts)
|
|
{
|
|
himax_ts_work(ts);
|
|
}
|
|
|
|
irqreturn_t himax_ts_thread(int irq, void *ptr)
|
|
{
|
|
struct himax_ts_data *ts = ptr;
|
|
|
|
if (ts->debug_log_level & BIT(2))
|
|
himax_log_touch_int_devation(HX_FINGER_ON);
|
|
|
|
himax_ts_isr_func((struct himax_ts_data *)ptr);
|
|
|
|
if (ts->debug_log_level & BIT(2))
|
|
himax_log_touch_int_devation(HX_FINGER_LEAVE);
|
|
|
|
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(struct i2c_client *client)
|
|
{
|
|
int ret = NO_ERR;
|
|
struct himax_ts_data *ts = i2c_get_clientdata(client);
|
|
|
|
if (ic_data->HX_INT_IS_EDGE) {
|
|
ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,
|
|
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
|
client->name, ts);
|
|
} else {
|
|
ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,
|
|
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
|
client->name, ts);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int himax_int_en_set(struct i2c_client *client)
|
|
{
|
|
int ret = NO_ERR;
|
|
|
|
ret = himax_int_register_trigger(client);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int himax_ts_register_interrupt(struct i2c_client *client)
|
|
{
|
|
struct himax_ts_data *ts = i2c_get_clientdata(client);
|
|
struct device_node *node = NULL;
|
|
u32 ints[2] = {0, 0};
|
|
int ret = 0;
|
|
|
|
node = of_find_matching_node(node, touch_of_match);
|
|
if (node) {
|
|
of_property_read_u32_array(node, "debounce", ints,
|
|
ARRAY_SIZE(ints));
|
|
gpio_set_debounce(ints[0], ints[1]);
|
|
himax_touch_irq = irq_of_parse_and_map(node, 0);
|
|
I("himax_touch_irq=%ud\n", himax_touch_irq);
|
|
client->irq = himax_touch_irq;
|
|
ts->client->irq = himax_touch_irq;
|
|
} else {
|
|
I("[%s] tpd request_irq can not find touch eint device node!.",
|
|
__func__);
|
|
}
|
|
|
|
ts->irq_enabled = 0;
|
|
ts->use_irq = 0;
|
|
|
|
/* Work functon */
|
|
if (client->irq) { /*INT mode*/
|
|
|
|
ts->use_irq = 1;
|
|
ret = himax_int_register_trigger(client);
|
|
if (ret == 0) {
|
|
ts->irq_enabled = 1;
|
|
irq_enable_count = 1;
|
|
I("%s: irq enabled at qpio: %d\n", __func__,
|
|
client->irq);
|
|
#ifdef HX_SMART_WAKEUP
|
|
irq_set_irq_wake(client->irq, 1);
|
|
#endif
|
|
} else {
|
|
ts->use_irq = 0;
|
|
E("%s: request_irq failed\n", __func__);
|
|
}
|
|
} else {
|
|
I("%s: client->irq is empty, use polling mode.\n", __func__);
|
|
}
|
|
|
|
if (!ts->use_irq) /*if use polling mode need to disable */
|
|
/* HX_ESD_RECOVERY function*/
|
|
{
|
|
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__);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int himax_common_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
int ret = 0;
|
|
#if defined(MTK_I2C_DMA)
|
|
client->dev.coherent_dma_mask = DMA_BIT_MASK(32);
|
|
gpDMABuf_va = (u8 *)dma_alloc_coherent(
|
|
&client->dev, 4096, (dma_addr_t *)&gpDMABuf_pa, GFP_KERNEL);
|
|
if (!gpDMABuf_va) {
|
|
E("Allocate DMA I2C Buffer failed\n");
|
|
ret = -ENODEV;
|
|
goto err_alloc_MTK_DMA_failed;
|
|
}
|
|
memset(gpDMABuf_va, 0, 4096);
|
|
#endif
|
|
|
|
i2c_client_point = client;
|
|
client->addr = 0x48;
|
|
ret = himax_chip_common_probe(client, id);
|
|
|
|
#if defined(MTK_I2C_DMA)
|
|
if (ret) {
|
|
if (gpDMABuf_va) {
|
|
dma_free_coherent(&client->dev, 4096, gpDMABuf_va,
|
|
(dma_addr_t)gpDMABuf_pa);
|
|
gpDMABuf_va = NULL;
|
|
gpDMABuf_pa = NULL;
|
|
}
|
|
}
|
|
err_alloc_MTK_DMA_failed:
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
int himax_common_remove(struct i2c_client *client)
|
|
{
|
|
int ret = 0;
|
|
|
|
himax_chip_common_remove(client);
|
|
|
|
if (gpDMABuf_va) {
|
|
dma_free_coherent(&client->dev, 4096, gpDMABuf_va,
|
|
(dma_addr_t)gpDMABuf_pa);
|
|
gpDMABuf_va = NULL;
|
|
gpDMABuf_pa = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void himax_common_suspend(struct device *dev)
|
|
{
|
|
struct himax_ts_data *ts = dev_get_drvdata(&i2c_client_point->dev);
|
|
|
|
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 = dev_get_drvdata(&i2c_client_point->dev);
|
|
|
|
I("%s: enter\n", __func__);
|
|
|
|
himax_chip_common_resume(ts);
|
|
|
|
I("%s: END\n", __func__);
|
|
}
|
|
|
|
#if defined(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 (evdata && evdata->data && event == FB_EVENT_BLANK && ts &&
|
|
ts->client) {
|
|
blank = evdata->data;
|
|
switch (*blank) {
|
|
case FB_BLANK_UNBLANK:
|
|
himax_common_resume(&ts->client->dev);
|
|
break;
|
|
|
|
case FB_BLANK_POWERDOWN:
|
|
case FB_BLANK_HSYNC_SUSPEND:
|
|
case FB_BLANK_VSYNC_SUSPEND:
|
|
case FB_BLANK_NORMAL:
|
|
himax_common_suspend(&ts->client->dev);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int himax_common_detect(struct i2c_client *client,
|
|
struct i2c_board_info *info)
|
|
{
|
|
strcpy(info->type, TPD_DEVICE);
|
|
return 0;
|
|
}
|
|
|
|
static const struct i2c_device_id himax_common_ts_id[] = {
|
|
{HIMAX_common_NAME, 0}, {} };
|
|
|
|
static struct i2c_driver tpd_i2c_driver = {
|
|
.probe = himax_common_probe,
|
|
.remove = himax_common_remove,
|
|
.detect = himax_common_detect,
|
|
.driver = {
|
|
|
|
|
|
.name = HIMAX_common_NAME,
|
|
.of_match_table = of_match_ptr(himax_match_table),
|
|
},
|
|
.id_table = himax_common_ts_id,
|
|
.address_list = (const unsigned short *)forces,
|
|
};
|
|
|
|
static int himax_common_local_init(void)
|
|
{
|
|
int retval;
|
|
|
|
I("[Himax] Himax_ts I2C Touchscreen Driver local init\n");
|
|
|
|
tpd->reg = regulator_get(tpd->tpd_dev, "vtouch");
|
|
retval = regulator_set_voltage(tpd->reg, 2800000, 2800000);
|
|
if (retval != 0)
|
|
E("Failed to set voltage 2V8: %d\n", retval);
|
|
|
|
if (i2c_add_driver(&tpd_i2c_driver) != 0) {
|
|
I("unable to add i2c driver.\n");
|
|
return -1;
|
|
}
|
|
|
|
/* input_set_abs_params(tpd->input_dev, ABS_MT_TRACKING_ID, 0, */
|
|
/* (HIMAX_MAX_TOUCH-1), 0, 0); */
|
|
|
|
/* set vendor string */
|
|
/* client->input_devid.vendor = 0x00; */
|
|
/* client->input_dev->id.product = tpd_info.pid; */
|
|
/* client-->input_dev->id.version = tpd_info.vid; */
|
|
#if defined(HX_PLATFOME_DEFINE_KEY)
|
|
if (tpd_dts_data.use_tpd_button) {
|
|
I("tpd_dts_data.use_tpd_button %d\n",
|
|
tpd_dts_data.use_tpd_button);
|
|
tpd_button_setting(tpd_dts_data.tpd_key_num,
|
|
tpd_dts_data.tpd_key_local,
|
|
tpd_dts_data.tpd_key_dim_local);
|
|
}
|
|
#endif
|
|
|
|
I("end %s, %d\n", __func__, __LINE__);
|
|
tpd_type_cap = 1;
|
|
|
|
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,
|
|
#ifdef 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");
|
|
tpd_get_dts_info();
|
|
if (tpd_driver_add(&tpd_device_driver) < 0)
|
|
E("Failed to add Driver!\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit himax_common_exit(void)
|
|
{
|
|
tpd_driver_remove(&tpd_device_driver);
|
|
}
|
|
module_init(himax_common_init);
|
|
module_exit(himax_common_exit);
|
|
|
|
MODULE_DESCRIPTION("Himax_common driver");
|
|
MODULE_LICENSE("GPL");
|