diff --git a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix.c b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix.c index 85ad0aad6dd8..790b09811d91 100644 --- a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix.c +++ b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix.c @@ -233,6 +233,9 @@ struct reg_ioctl { #define ZINITIX_I2C_CHECKSUM_WCNT 0x016a #define ZINITIX_I2C_CHECKSUM_RESULT 0x016c +#define BT541_GESTURE_CONTROL_REG 0x011D +#define BT541_CLEAR_GESTURE_CMD 0x0088 + /* Interrupt & status register flag bit ------------------------------------------------- */ @@ -1139,6 +1142,7 @@ static int zinitix_power_control(struct bt541_ts_info *data, int on) } dev_info(&data->client->dev, "Enable data->vcc_i2c regualtor\n"); } + data->ic_power_state = TS_MMI_POWER_ON; return 0; @@ -1175,6 +1179,7 @@ power_off: gpio_direction_output(data->pdata->gpio_reset, 0); pr_info("%s: set gpio_reset to 0 success\n", __func__); } + data->ic_power_state = TS_MMI_POWER_OFF; return 0; } @@ -2710,6 +2715,38 @@ static int bt541_pinctrl_configure(struct bt541_ts_info *info, bool active) } #endif +int zinitix_ts_mmi_disable_gesture(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bt541_ts_info *info = i2c_get_clientdata(client); + + down(&info->work_lock); + if (write_reg(client, BT541_GESTURE_CONTROL_REG, BT541_CLEAR_GESTURE_CMD) != I2C_SUCCESS) { + zinitix_printk("Disable gestures failed\n"); + up(&info->work_lock); + return -1; + } + up(&info->work_lock); + + return 0; +} + +int zinitix_ts_mmi_restore_gesture(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bt541_ts_info *info = i2c_get_clientdata(client); + + down(&info->work_lock); + if (write_reg(client, BT541_GESTURE_CONTROL_REG, info->gesture_command) != I2C_SUCCESS) { + zinitix_printk("Restore gestures failed\n"); + up(&info->work_lock); + return -1; + } + up(&info->work_lock); + + return 0; +} + int zinitix_ts_mmi_gesture_suspend(struct device *dev) { int i = 0; @@ -5934,6 +5971,10 @@ static int bt541_ts_probe_dt(struct device_node *np, return ret; } + pdata->stow_mode_ctrl = of_property_read_bool(np, "zinitix,stow-mode-ctrl"); + if (pdata->stow_mode_ctrl) + pr_info("%s: Support zinitix touch stow mode", __func__); + if (pdata->tsp_supply_type == TSP_LDO_SUPPLY) { pdata->tsp_en_gpio = of_get_named_gpio(np, "zinitix,vdd_en-gpio", 0); if (pdata->tsp_en_gpio < 0) { diff --git a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_touch.h b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_touch.h index 4a17176d031e..2c29bac02b7b 100644 --- a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_touch.h +++ b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_touch.h @@ -187,6 +187,7 @@ struct bt541_ts_platform_data { int avdd_gpio; int iovdd_gpio; char ic_name[ZINITIX_MAX_STR_LABLE_LEN]; + bool stow_mode_ctrl; }; struct coord { @@ -325,6 +326,10 @@ struct bt541_ts_info { int ts_mmi_power_state; struct completion pm_completion; bool pm_suspend; + atomic_t set_stowed_state; + atomic_t get_stowed_state; + int ic_power_state; + struct mutex mode_lock; }; extern int zinitix_hw_reset( struct bt541_ts_info* data,bool on ); @@ -335,6 +340,8 @@ extern void clear_report_data(struct bt541_ts_info *info); extern int zinitix_ts_mmi_gesture_suspend(struct device *dev); extern int zinitix_ts_mmi_gesture_resume(struct device *dev); extern bool mini_init_touch(struct bt541_ts_info *info); +extern int zinitix_ts_mmi_disable_gesture(struct device *dev); +extern int zinitix_ts_mmi_restore_gesture(struct device *dev); #endif /* LINUX_BT541_TS_H */ diff --git a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.c b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.c index abcf15f85f11..a232b1ab5112 100644 --- a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.c +++ b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.c @@ -21,6 +21,30 @@ return -ENODEV; \ } +#define ADD_ATTR(name) { \ + if (idx < MAX_ATTRS_ENTRIES) { \ + dev_info(dev, "%s: [%d] adding %p\n", __func__, idx, &dev_attr_##name.attr); \ + ext_attributes[idx] = &dev_attr_##name.attr; \ + idx++; \ + } else { \ + dev_err(dev, "%s: cannot add attribute '%s'\n", __func__, #name); \ + } \ +} + +#define GET_TS_DATA(dev) { \ + ts_info = dev_get_drvdata(dev); \ + if (!ts_info) { \ + dev_err(dev, "Failed to get driver data"); \ + return -ENODEV; \ + } \ +} + + +static struct attribute *ext_attributes[MAX_ATTRS_ENTRIES]; +static struct attribute_group ext_attr_group = { + .attrs = ext_attributes, +}; + volatile int tpd_halt = 0; static int zinitix_ts_mmi_methods_get_vendor(struct device *dev, void *cdata) @@ -309,6 +333,17 @@ static int zinitix_ts_mmi_post_suspend(struct device *dev) info->work_state = SUSPEND; up(&info->work_lock); + //set stow mode + mutex_lock(&info->mode_lock); + if ((info->pdata->stow_mode_ctrl) && (info->ic_power_state == TS_MMI_POWER_ON) && + atomic_read(&info->get_stowed_state)) { + dev_info(dev, "%s: stowed, disable all gestures after suspend 0x%04x\n", __func__, + info->gesture_command); + zinitix_ts_mmi_disable_gesture(dev); + atomic_set(&info->set_stowed_state, 1); + } + mutex_unlock(&info->mode_lock); + dev_info(dev, "%s: Suspend end \n", __func__); return 0; @@ -338,11 +373,93 @@ static int zinitix_ts_mmi_post_resume(struct device *dev) #endif tpd_halt = 0; info->work_state = NOTHING; + //Clear stowed state + atomic_set(&info->get_stowed_state, 0); + atomic_set(&info->set_stowed_state, 0); up(&info->work_lock); dev_info(dev, "%s: Resume end\n", __func__); return 0; } +static ssize_t zinitix_ts_stowed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bt541_ts_info *ts_info; + + dev = MMI_DEV_TO_TS_DEV(dev); + GET_TS_DATA(dev); + + ASSERT_PTR(ts_info); + + return scnprintf(buf, PAGE_SIZE, "stowed state:%d\n", atomic_read(&ts_info->set_stowed_state)); +} + +static ssize_t zinitix_ts_stowed_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int mode = 0; + int err = 0; + struct bt541_ts_info *ts_info; + + dev = MMI_DEV_TO_TS_DEV(dev); + GET_TS_DATA(dev); + + err = sscanf(buf, "%d", &mode); + if (err < 0) { + dev_err(dev, "stowed: Failed to convert value\n"); + return -EINVAL; + } + + mutex_lock(&ts_info->mode_lock); + + atomic_set(&ts_info->get_stowed_state, !!mode); + + if (atomic_read(&ts_info->set_stowed_state) == atomic_read(&ts_info->get_stowed_state)) { + dev_info(dev, "%s: Stowed mode is same, not to set \n", __func__); + mutex_unlock(&ts_info->mode_lock); + return size; + } + + if ((ts_info->ic_power_state == TS_MMI_POWER_ON) && (ts_info->work_state == SUSPEND)) { + if (mode) { + dev_info(dev, "%s: stowed, disable all gestures 0x%04x\n", __func__, ts_info->gesture_command); + zinitix_ts_mmi_disable_gesture(dev); + } else { + dev_info(dev, "%s: unstowed, restore gestures 0x%04x\n", __func__, ts_info->gesture_command); + zinitix_ts_mmi_restore_gesture(dev); + } + atomic_set(&ts_info->set_stowed_state, !!mode); + } else { + dev_info(dev, "%s: touch state is not proper to enter stow mode, work state:%d, \ + ic power state: %d\n", __func__, ts_info->work_state, ts_info->ic_power_state); + } + mutex_unlock(&ts_info->mode_lock); + + return size; +} +static DEVICE_ATTR(stowed, (S_IWUSR | S_IWGRP | S_IRUGO), zinitix_ts_stowed_show, + zinitix_ts_stowed_store); + +static int zinitix_mmi_extend_attribute_group(struct device *dev, + struct attribute_group **group) +{ + int idx = 0; + struct bt541_ts_info *info = dev_get_drvdata(dev); + struct bt541_ts_platform_data *pdata = info->pdata; + ASSERT_PTR(pdata); + + if (pdata->stow_mode_ctrl) + ADD_ATTR(stowed); + + if (idx) { + ext_attributes[idx] = NULL; + *group = &ext_attr_group; + } else + *group = NULL; + + return 0; +} + static struct ts_mmi_methods zinitix_ts_mmi_methods = { .get_vendor = zinitix_ts_mmi_methods_get_vendor, .get_productinfo = zinitix_ts_mmi_methods_get_productinfo, @@ -359,6 +476,8 @@ static struct ts_mmi_methods zinitix_ts_mmi_methods = { .drv_irq = zinitix_ts_mmi_methods_drv_irq, /* Firmware */ .firmware_update = zinitix_ts_firmware_update, + /* vendor specific attribute group */ + .extend_attribute_group = zinitix_mmi_extend_attribute_group, /* PM callback */ .panel_state = zinitix_ts_mmi_panel_state, .pre_suspend = zinitix_ts_mmi_pre_suspend, @@ -399,9 +518,11 @@ int zinitix_ts_mmi_dev_register(struct device *dev) { INIT_DELAYED_WORK(&info->work, ts_mmi_worker_func); + mutex_init(&info->mode_lock); ret = ts_mmi_dev_register(dev, &zinitix_ts_mmi_methods); if (ret) { dev_err(dev, "%s, Failed to register ts mmi\n", __func__); + mutex_destroy(&info->mode_lock); return ret; } dev_info(dev, "%s, Register ts mmi success\n", __func__); @@ -422,6 +543,7 @@ void zinitix_ts_mmi_dev_unregister(struct device *dev) { if (!info) dev_err(dev ,"Failed to get driver data"); + mutex_destroy(&info->mode_lock); ts_mmi_dev_unregister(dev); } diff --git a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.h b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.h index e2bea7996568..010ebb946800 100644 --- a/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.h +++ b/drivers/input/touchscreen/zinitix_ztw62x_mmi/zinitix_ts_mmi.h @@ -17,6 +17,8 @@ #include #include "zinitix_touch.h" +#define MAX_ATTRS_ENTRIES 10 + #ifdef CONFIG_INPUT_TOUCHSCREEN_MMI int zinitix_ts_mmi_dev_register(struct device *dev); void zinitix_ts_mmi_dev_unregister(struct device *dev);