touchscreen_mmi: usb detection

Added USB detection to the class code to handle charging source
bit setting.

Change-Id: Ic947504509b454150b7067ceb31786c5d29296b2
Signed-off-by: Konstantin Makariev <hcv867@motorola.com>
Reviewed-on: https://gerrit.mot.com/1471999
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Jialei Hao <haojl2@motorola.com>
Reviewed-by: Konstantin Makariev <kmakariev@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
Konstantin Makariev 2019-12-13 15:16:02 -06:00 • committed by Konstantin Makariev
commit 04643c7759
2 changed files with 136 additions and 23 deletions

View file

@ -14,6 +14,8 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/usb.h>
#include <linux/power_supply.h>
#include <linux/touchscreen_mmi.h>
#if defined(CONFIG_PANEL_NOTIFICATIONS)
@ -35,11 +37,19 @@ extern struct blocking_notifier_head dsi_freq_head;
#define unregister_dynamic_refresh_rate_notifier(...)
#endif
enum ts_mmi_work {
TS_MMI_DO_RESUME,
TS_MMI_DO_PS,
TS_MMI_DO_REFRESH_RATE
};
#if defined(CONFIG_PANEL_NOTIFICATIONS)
static int ts_mmi_panel_off(struct ts_mmi_dev *touch_cdev) {
if (atomic_cmpxchg(&touch_cdev->touch_stopped, 0, 1) == 1)
return 0;
atomic_set(&touch_cdev->resume_should_stop, 1);
TRY_TO_CALL(pre_suspend);
if (touch_cdev->pdata.power_off_suspend)
@ -51,7 +61,6 @@ static int ts_mmi_panel_off(struct ts_mmi_dev *touch_cdev) {
else
TRY_TO_CALL(panel_state, touch_cdev->pm_mode, TS_MMI_PM_DEEPSLEEP);
}
cancel_delayed_work_sync(&touch_cdev->resume_work);
TRY_TO_CALL(post_suspend);
@ -61,9 +70,11 @@ static int ts_mmi_panel_off(struct ts_mmi_dev *touch_cdev) {
}
static int inline ts_mmi_panel_on(struct ts_mmi_dev *touch_cdev) {
atomic_set(&touch_cdev->resume_should_stop, 0);
kfifo_put(&touch_cdev->cmd_pipe, TS_MMI_DO_RESUME);
/* schedule_delayed_work returns true if work has been scheduled */
/* and false otherwise, thus return 0 on success to comply POSIX */
return schedule_delayed_work(&touch_cdev->resume_work, 0) == false;
return schedule_delayed_work(&touch_cdev->work, 0) == false;
}
#endif
@ -131,13 +142,8 @@ static int ts_mmi_panel_cb(struct notifier_block *nb,
return 0;
}
static void ts_mmi_queued_resume(struct work_struct *w)
static void ts_mmi_queued_resume(struct ts_mmi_dev *touch_cdev)
{
struct delayed_work *dw =
container_of(w, struct delayed_work, work);
struct ts_mmi_dev *touch_cdev =
container_of(dw, struct ts_mmi_dev, resume_work);
bool wait4_boot_complete = true;
if (atomic_cmpxchg(&touch_cdev->touch_stopped, 1, 0) == 0)
@ -174,6 +180,38 @@ static void ts_mmi_queued_resume(struct work_struct *w)
dev_info(DEV_MMI, "%s: done\n", __func__);
}
static void ts_mmi_worker_func(struct work_struct *w)
{
struct delayed_work *dw =
container_of(w, struct delayed_work, work);
struct ts_mmi_dev *touch_cdev =
container_of(dw, struct ts_mmi_dev, work);
int cmd, rc;
while (kfifo_get(&touch_cdev->cmd_pipe, &cmd)) {
switch (cmd) {
case TS_MMI_DO_RESUME:
rc = atomic_read(&touch_cdev->resume_should_stop);
if (rc) {
dev_info(DEV_MMI, "%s: resume cancelled\n", __func__);
break;
}
ts_mmi_queued_resume(touch_cdev);
break;
case TS_MMI_DO_PS:
TRY_TO_CALL(charger_mode, (int)touch_cdev->ps_is_present);
break;
case TS_MMI_DO_REFRESH_RATE:
TRY_TO_CALL(refresh_rate, (int)touch_cdev->refresh_rate);
break;
default:
dev_dbg(DEV_MMI, "%s: unknown command\n", __func__);
}
}
}
static int ts_mmi_refresh_rate_cb(struct notifier_block *nb,
unsigned long refresh_rate, void *ptr)
{
@ -190,13 +228,61 @@ static int ts_mmi_refresh_rate_cb(struct notifier_block *nb,
do_calibration = true;
}
if (do_calibration)
TRY_TO_CALL(refresh_rate, (int)touch_cdev->refresh_rate);
if (do_calibration) {
kfifo_put(&touch_cdev->cmd_pipe, TS_MMI_DO_REFRESH_RATE);
schedule_delayed_work(&touch_cdev->work, 0);
}
return 0;
}
int ts_mmi_notifiers_register(struct ts_mmi_dev *touch_cdev) {
static int ts_mmi_ps_get_state(struct power_supply *psy, bool *present)
{
union power_supply_propval pval = {0};
int ret;
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, &pval);
if (ret)
return ret;
*present = !pval.intval ? false : true;
return 0;
}
static int ts_mmi_charger_cb(struct notifier_block *self,
unsigned long event, void *ptr)
{
struct ts_mmi_dev *touch_cdev = container_of(
self, struct ts_mmi_dev, ps_notif);
struct power_supply *psy = ptr;
int ret;
bool present;
if (!((event == PSY_EVENT_PROP_CHANGED) && psy &&
psy->desc->get_property && psy->desc->name &&
!strncmp(psy->desc->name, "usb", sizeof("usb"))))
return 0;
ret = ts_mmi_ps_get_state(psy, &present);
if (ret) {
dev_err(DEV_MMI, "%s: failed to get usb status: %d\n",
__func__, ret);
return ret;
}
dev_dbg(DEV_MMI, "%s: event=%lu, usb status: cur=%d, prev=%d\n",
__func__, event, present, touch_cdev->ps_is_present);
if (touch_cdev->ps_is_present != present) {
touch_cdev->ps_is_present = present;
kfifo_put(&touch_cdev->cmd_pipe, TS_MMI_DO_PS);
schedule_delayed_work(&touch_cdev->work, 0);
}
return 0;
}
int ts_mmi_notifiers_register(struct ts_mmi_dev *touch_cdev)
{
int ret = 0;
if (!touch_cdev->class_dev) {
@ -205,11 +291,24 @@ int ts_mmi_notifiers_register(struct ts_mmi_dev *touch_cdev) {
dev_info(DEV_TS, "%s: Start notifiers init.\n", __func__);
INIT_DELAYED_WORK(&touch_cdev->resume_work, ts_mmi_queued_resume);
INIT_DELAYED_WORK(&touch_cdev->work, ts_mmi_worker_func);
ret = kfifo_alloc(&touch_cdev->cmd_pipe,
sizeof(unsigned int)* 10, GFP_KERNEL);
if (ret)
goto FIFO_ALLOC_FAILED;
if (touch_cdev->pdata.usb_detection) {
touch_cdev->ps_notif.notifier_call = ts_mmi_charger_cb;
ret = power_supply_reg_notifier(&touch_cdev->ps_notif);
if (ret)
goto PS_NOTIF_REGISTER_FAILED;
}
touch_cdev->panel_nb.notifier_call = ts_mmi_panel_cb;
ret = register_panel_notifier(&touch_cdev->panel_nb);
if (ret)
goto PANEL_NOTIF_REGISTER_FAILED;
if (touch_cdev->pdata.update_refresh_rate) {
touch_cdev->freq_nb.notifier_call = ts_mmi_refresh_rate_cb;
ret = register_dynamic_refresh_rate_notifier(&touch_cdev->freq_nb);
@ -223,19 +322,28 @@ int ts_mmi_notifiers_register(struct ts_mmi_dev *touch_cdev) {
FREQ_NOTIF_REGISTER_FAILED:
unregister_panel_notifier(&touch_cdev->panel_nb);
PANEL_NOTIF_REGISTER_FAILED:
cancel_delayed_work(&touch_cdev->resume_work);
cancel_delayed_work(&touch_cdev->work);
PS_NOTIF_REGISTER_FAILED:
kfifo_free(&touch_cdev->cmd_pipe);
FIFO_ALLOC_FAILED:
return ret;
}
void ts_mmi_notifiers_unregister(struct ts_mmi_dev *touch_cdev) {
if(touch_cdev->class_dev == NULL) {
void ts_mmi_notifiers_unregister(struct ts_mmi_dev *touch_cdev)
{
if (touch_cdev->class_dev == NULL) {
dev_err(DEV_MMI, "%s:touch_cdev->class_dev == NULL", __func__);
} else {
if (touch_cdev->pdata.update_refresh_rate) {
unregister_dynamic_refresh_rate_notifier(&touch_cdev->freq_nb);
}
unregister_panel_notifier(&touch_cdev->panel_nb);
cancel_delayed_work(&touch_cdev->resume_work);
dev_info(DEV_MMI, "%s:notifiers_unregister finish", __func__);
return;
}
if (touch_cdev->pdata.update_refresh_rate)
unregister_dynamic_refresh_rate_notifier(&touch_cdev->freq_nb);
if (touch_cdev->pdata.usb_detection)
power_supply_unreg_notifier(&touch_cdev->ps_notif);
unregister_panel_notifier(&touch_cdev->panel_nb);
cancel_delayed_work(&touch_cdev->work);
kfifo_free(&touch_cdev->cmd_pipe);
dev_info(DEV_MMI, "%s:notifiers_unregister finish", __func__);
}

View file

@ -16,6 +16,7 @@
#include <linux/list.h>
#include <linux/device.h>
#include <linux/kfifo.h>
#if defined(CONFIG_PANEL_NOTIFICATIONS)
#include <linux/panel_notifier.h>
@ -96,6 +97,7 @@ enum ts_mmi_pm_mode {
int (*power)(struct device *dev, int on);
int (*pinctrl)(struct device *dev, int on);
int (*refresh_rate)(struct device *dev, int freq);
int (*charger_mode)(struct device *dev, int mode);
/* Firmware */
int (*firmware_update)(struct device *dev, char *fwname);
int (*firmware_erase)(struct device *dev);
@ -157,7 +159,10 @@ struct ts_mmi_dev {
struct notifier_block panel_nb;
atomic_t touch_stopped;
enum ts_mmi_pm_mode pm_mode;
struct delayed_work resume_work;
atomic_t resume_should_stop;
struct delayed_work work;
struct kfifo cmd_pipe;
struct notifier_block freq_nb;
unsigned char refresh_rate;