summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Garberi <dade.garberi@gmail.com>2018-11-08 21:07:46 +0100
committerDavide Garberi <dade.garberi@gmail.com>2022-07-27 18:59:05 +0200
commit90f7546c2b4ac17a46a24e699877a727d6033757 (patch)
treedb119fb69538171933f9b7f890135e90ffa6dfa1
parentd8a6f82e92cecb1414ac9abafdb53fc4a3b6073d (diff)
cclogic: Add some edits from ZUK
* Reworked from ZUK sources to make it looks a bit better * Also adapted to 4.4 and moved to the new directory Signed-off-by: Davide Garberi <dade.garberi@gmail.com>
-rw-r--r--drivers/misc/cclogic/cclogic-core.c105
-rw-r--r--drivers/misc/cclogic/cclogic-core.h2
-rw-r--r--drivers/misc/cclogic/tusb320hai.c2
-rw-r--r--drivers/power/supply/qcom/qpnp-smbcharger.c87
-rw-r--r--include/linux/cclogic-core.h4
-rw-r--r--include/linux/power_supply.h2
6 files changed, 199 insertions, 3 deletions
diff --git a/drivers/misc/cclogic/cclogic-core.c b/drivers/misc/cclogic/cclogic-core.c
index 55b37125c6ee..e2de82c81532 100644
--- a/drivers/misc/cclogic/cclogic-core.c
+++ b/drivers/misc/cclogic/cclogic-core.c
@@ -23,6 +23,8 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/cclogic-core.h>
+#include <linux/notifier.h>
+#include <linux/export.h>
#include "cclogic-core.h"
#include "cclogic-class.h"
@@ -34,6 +36,39 @@ static struct mutex cclogic_ops_lock;
static int m_plug_state = 0;
#define DRIVER_NAME "cclogic"
+
+static BLOCKING_NOTIFIER_HEAD(cclogic_notifier_list);
+
+/**
+ * cclogic_register_client - register a client notifier
+ * @nb: notifier block to callback on events
+ */
+int cclogic_register_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&cclogic_notifier_list, nb);
+}
+EXPORT_SYMBOL(cclogic_register_client);
+
+/**
+ * cclogic_unregister_client - unregister a client notifier
+ * @nb: notifier block to callback on events
+ */
+int cclogic_unregister_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&cclogic_notifier_list, nb);
+}
+EXPORT_SYMBOL(cclogic_unregister_client);
+
+/**
+ * cclogic_notifier_call_chain - notify clients of fb_events
+ *
+ */
+int cclogic_notifier_call_chain(unsigned long val, void *v)
+{
+ return blocking_notifier_call_chain(&cclogic_notifier_list, val, v);
+}
+EXPORT_SYMBOL_GPL(cclogic_notifier_call_chain);
+
/*
*
*/
@@ -593,6 +628,62 @@ static DEVICE_ATTR(cc,S_IRUGO, cclogic_show_cc, NULL);
/*
*
*/
+static ssize_t cclogic_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cclogic_dev *cclogic_dev = dev_get_drvdata(dev);
+ int size;
+ int reg, value;
+
+ if(cclogic_dev->ops && cclogic_dev->ops->read){
+ reg = 0x08;
+ value = cclogic_dev->ops->read(cclogic_dev->i2c_client,reg);
+ size+=sprintf(&buf[size],"[0x%02x] register = 0x%02x\n",reg,value);
+ pr_debug("[0x%x] = [0x%x]\n", reg, value);
+ reg = 0x09;
+ value = cclogic_dev->ops->read(cclogic_dev->i2c_client,reg);
+ size+=sprintf(&buf[size],"[0x%02x] register = 0x%02x\n",reg,value);
+ pr_debug("[0x%x] = [0x%x]\n", reg, value);
+ reg = 0x0A;
+ value = cclogic_dev->ops->read(cclogic_dev->i2c_client,reg);
+ size+=sprintf(&buf[size],"[0x%02x] register = 0x%02x\n",reg,value);
+ pr_debug("[0x%x] = [0x%x]\n", reg, value);
+ reg = 0x45;
+ value = cclogic_dev->ops->read(cclogic_dev->i2c_client,reg);
+ size+=sprintf(&buf[size],"[0x%02x] register = 0x%02x\n",reg,value);
+ pr_debug("[0x%x] = [0x%x]\n", reg, value);
+ reg = 0xA0;
+ value = cclogic_dev->ops->read(cclogic_dev->i2c_client,reg);
+ size+=sprintf(&buf[size],"[0x%02x] register = 0x%02x\n",reg,value);
+ pr_debug("[0x%x] = [0x%x]\n", reg, value);
+ }
+
+ return size;
+}
+
+ static ssize_t cclogic_reg_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct cclogic_dev *cclogic_dev = dev_get_drvdata(dev);
+// int ret;
+ int reg, value;
+ char rw[10];
+
+ pr_debug("[%s][%d]\n", __func__, __LINE__);
+ gpio_set_value_cansleep(cclogic_dev->platform_data->enb_gpio,1);
+
+ sscanf(buf,"%s %x %x",rw,&reg, &value);
+ if(!strcmp(rw,"write")){
+ if(cclogic_dev->ops && cclogic_dev->ops->read){
+ cclogic_dev->ops->write(cclogic_dev->i2c_client, reg, value);
+ }
+ }
+ return size;
+}
+
+static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, cclogic_reg_show, cclogic_reg_store);
+
+
static void cclogic_func_set(struct cclogic_platform *p,enum cclogic_func_type func)
{
switch(func){
@@ -741,11 +832,13 @@ static int cclogic_do_real_work(struct cclogic_state *state,
{
int ret=0;
struct cclogic_platform *p = pdata->platform_data;
+ static int cclogic_last_status = 0;
pr_debug("[%s][%d]\n", __func__, __LINE__);
cc_otg_state = 0;
switch(state->evt){
case CCLOGIC_EVENT_DETACHED:
+ cclogic_notifier_call_chain(CCLOGIC_EVENT_DETACHED, NULL);
pr_debug("%s-->cable detached\n",__func__);
cclogic_vbus_power_on(pdata,false);
cclogic_func_set(p,CCLOGIC_FUNC_UART);
@@ -755,6 +848,7 @@ static int cclogic_do_real_work(struct cclogic_state *state,
pr_debug("%s-->No event\n",__func__);
break;
case CCLOGIC_EVENT_ATTACHED:
+ cclogic_notifier_call_chain(CCLOGIC_EVENT_ATTACHED, NULL);
pr_debug("%s-->cable attached\n",__func__);
break;
}
@@ -851,6 +945,15 @@ out:
cclogic_class_update_state(&pdata->cdev);
}
+// if(unlikely(!gpio_get_value(pdata->platform_data->irq_plug) &&
+ if(unlikely(state->evt == CCLOGIC_EVENT_DETACHED &&
+ cclogic_last_status == CCLOGIC_EVENT_DETACHED)) {
+ msleep(20);
+ pr_debug("cclogic: reset driver ic, try again\n");
+ ret = pdata->ops->chip_reset(pdata->i2c_client);
+ }
+ cclogic_last_status = state->evt;
+
return ret;
}
@@ -899,7 +1002,6 @@ work_end:
pr_err("[%s][%d] still in error,more than %d retries\n", __func__, __LINE__,CCLOGIC_MAX_RETRIES);
}
-
if(wake_lock_active(&pdata->wakelock)){
wake_unlock(&pdata->wakelock);
}
@@ -1298,6 +1400,7 @@ static struct attribute *cclogic_attrs[] = {
&dev_attr_chip_power.attr,
&dev_attr_status.attr,
&dev_attr_enable.attr,
+ &dev_attr_reg.attr,
#endif
&dev_attr_cc.attr,
NULL,
diff --git a/drivers/misc/cclogic/cclogic-core.h b/drivers/misc/cclogic/cclogic-core.h
index 99443d821d15..49361a73a80a 100644
--- a/drivers/misc/cclogic/cclogic-core.h
+++ b/drivers/misc/cclogic/cclogic-core.h
@@ -145,6 +145,8 @@ struct cclogic_chip {
int (*chip_check)(struct i2c_client *client);
int (*chip_trymode)(struct i2c_client *client, int mode);
struct list_head chip_list;
+ int (*read)(struct i2c_client *client, u8 reg);
+ int (*write)(struct i2c_client *client, u8 reg, u8 data);
};
enum cclogic_func_type {
diff --git a/drivers/misc/cclogic/tusb320hai.c b/drivers/misc/cclogic/tusb320hai.c
index 5089c02b1abf..cefba953a54b 100644
--- a/drivers/misc/cclogic/tusb320hai.c
+++ b/drivers/misc/cclogic/tusb320hai.c
@@ -443,6 +443,8 @@ static struct cclogic_chip tusb320hai_chip = {
.chip_trymode = tusb320hai_trymode,
.typec_version = 11,//spec 1.1
.support = CCLOGIC_SUPPORT_MODE_DUAL,
+ .read = tusb320hai_read_i2c,
+ .write = tusb320hai_write_i2c,
};
/**
diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c
index 819c002ae0fc..54f481b3b266 100644
--- a/drivers/power/supply/qcom/qpnp-smbcharger.c
+++ b/drivers/power/supply/qcom/qpnp-smbcharger.c
@@ -43,6 +43,9 @@
#include <linux/ktime.h>
#include <linux/extcon.h>
#include <linux/pmic-voter.h>
+#include <linux/cclogic-core.h>
+
+#define SUPPORT_CCLOGIC_EVENT_TYPE
/* Mask/Bit helpers */
#define _SMB_MASK(BITS, POS) \
@@ -293,6 +296,12 @@ struct smbchg_chip {
struct votable *hvdcp_enable_votable;
/* extcon for VBUS / ID notification to USB */
struct extcon_dev *extcon;
+
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+ struct notifier_block cclogic_notif;
+ int cclogic_attached;
+ wait_queue_head_t cclogic_wait_queue;
+#endif
};
enum qpnp_schg {
@@ -300,6 +309,14 @@ enum qpnp_schg {
QPNP_SCHG_LITE,
};
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+enum cclogic_event {
+ USB_DETACHED,
+ USB_ATTACHED,
+ USB_REMOVE,
+};
+#endif
+
static char *version_str[] = {
[QPNP_SCHG] = "SCHG",
[QPNP_SCHG_LITE] = "SCHG_LITE",
@@ -680,6 +697,14 @@ static enum pwr_path_type smbchg_get_pwr_path(struct smbchg_chip *chip)
#define USBIN_SRC_DET_BIT BIT(2)
#define FMB_STS_MASK SMB_MASK(3, 0)
#define USBID_GND_THRESHOLD 0x495
+
+static int id_state = 0;
+int get_usb_id_state(void)
+{
+ return id_state;
+}
+EXPORT_SYMBOL(get_usb_id_state);
+
static bool is_otg_present_schg(struct smbchg_chip *chip)
{
int rc;
@@ -761,7 +786,7 @@ static bool is_otg_present(struct smbchg_chip *chip)
if (chip->schg_version == QPNP_SCHG_LITE)
return is_otg_present_schg_lite(chip);
- return is_otg_present_schg(chip);
+ return is_otg_present_schg(chip) || cclogic_get_otg_state();
}
#define USBIN_9V BIT(5)
@@ -6632,6 +6657,14 @@ static irqreturn_t usbin_uv_handler(int irq, void *_chip)
schedule_work(&chip->usb_set_online_work);
}
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+ /* usb pull out, wakeup wq if wq waiting cclogic attached event */
+ if (reg & USBIN_UV_BIT) {
+ chip->cclogic_attached = USB_REMOVE;
+ wake_up_interruptible(&chip->cclogic_wait_queue);
+ }
+#endif
+
smbchg_wipower_check(chip);
out:
return IRQ_HANDLED;
@@ -6651,6 +6684,9 @@ static irqreturn_t src_detect_handler(int irq, void *_chip)
bool usb_present = is_usb_present(chip);
bool src_detect = is_src_detect_high(chip);
int rc;
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+ int ret;
+#endif
pr_smb(PR_STATUS,
"%s chip->usb_present = %d usb_present = %d src_detect = %d hvdcp_3_det_ignore_uv=%d\n",
@@ -6691,6 +6727,15 @@ static irqreturn_t src_detect_handler(int irq, void *_chip)
if (src_detect) {
update_usb_status(chip, usb_present, 0);
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+ ret = wait_event_interruptible_timeout(chip->cclogic_wait_queue,
+ (chip->cclogic_attached == USB_ATTACHED) ||
+ (chip->cclogic_attached == USB_REMOVE),
+ msecs_to_jiffies(2500));
+ pr_info("Waiting cclogic state ret = %d\n", ret);
+ if (ret == 0)
+ pr_err("Waiting cclogic state timeout\n");
+#endif
} else {
update_usb_status(chip, 0, false);
chip->aicl_irq_count = 0;
@@ -8230,6 +8275,25 @@ static void rerun_hvdcp_det_if_necessary(struct smbchg_chip *chip)
}
}
+/*
+ * cclogic callback, notify cclogic event status: detached or attached
+ */
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+static int cclogic_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
+{
+ struct smbchg_chip *chip = container_of(self, struct smbchg_chip, cclogic_notif);
+ if (event == 1) { /* usb detached */
+ chip->cclogic_attached = USB_DETACHED;
+ } else if (event == 2) { /* usb attached */
+ chip->cclogic_attached = USB_ATTACHED;
+ wake_up_interruptible(&chip->cclogic_wait_queue);
+ }
+ pr_smb(PR_MISC, "setting cclogic_attached = %d\n",
+ chip->cclogic_attached);
+ return 0;
+}
+#endif
+
static int smbchg_probe(struct platform_device *pdev)
{
int rc;
@@ -8446,6 +8510,10 @@ static int smbchg_probe(struct platform_device *pdev)
goto votables_cleanup;
}
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+ init_waitqueue_head(&chip->cclogic_wait_queue);
+#endif
+
chip->extcon = devm_extcon_dev_allocate(chip->dev, smbchg_extcon_cable);
if (IS_ERR(chip->extcon)) {
dev_err(chip->dev, "failed to allocate extcon device\n");
@@ -8543,6 +8611,15 @@ static int smbchg_probe(struct platform_device *pdev)
}
chip->allow_hvdcp3_detection = true;
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+ chip->cclogic_notif.notifier_call = cclogic_notifier_callback;
+ rc = cclogic_register_client(&chip->cclogic_notif);
+ if (rc) {
+ pr_err("Unable to register cclogic_notifier : %d\n", rc);
+ goto unregister_dc_psy1;
+ }
+#endif
+
if (chip->cfg_chg_led_support &&
chip->schg_version == QPNP_SCHG_LITE) {
rc = smbchg_register_chg_led(chip);
@@ -8585,6 +8662,10 @@ static int smbchg_probe(struct platform_device *pdev)
unregister_led_class:
if (chip->cfg_chg_led_support && chip->schg_version == QPNP_SCHG_LITE)
led_classdev_unregister(&chip->led_cdev);
+#ifdef SUPPORT_CCLOGIC_EVENT_TYPE
+unregister_dc_psy1:
+ cclogic_unregister_client(&chip->cclogic_notif);
+#endif
out:
handle_usb_removal(chip);
votables_cleanup:
@@ -8617,6 +8698,10 @@ static int smbchg_remove(struct platform_device *pdev)
debugfs_remove_recursive(chip->debug_root);
+#ifdef SUPPORT_SCREEN_ON_FCC_OP
+ fb_unregister_client(&chip->fb_notif);
+#endif
+
destroy_votable(chip->aicl_deglitch_short_votable);
destroy_votable(chip->hw_aicl_rerun_enable_indirect_votable);
destroy_votable(chip->hw_aicl_rerun_disable_votable);
diff --git a/include/linux/cclogic-core.h b/include/linux/cclogic-core.h
index 6ffb9d744abc..181a2c5df4aa 100644
--- a/include/linux/cclogic-core.h
+++ b/include/linux/cclogic-core.h
@@ -1,3 +1,7 @@
+#include <linux/notifier.h>
extern int cclogic_get_otg_state(void);
+extern int cclogic_register_client(struct notifier_block *nb);
+extern int cclogic_unregister_client(struct notifier_block *nb);
+extern int cclogic_notifier_call_chain(unsigned long val, void *v);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 4d2e20415071..d67ff2b9559d 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -480,7 +480,7 @@ devm_power_supply_get_by_phandle(struct device *dev, const char *property)
extern void power_supply_changed(struct power_supply *psy);
extern int power_supply_am_i_supplied(struct power_supply *psy);
extern int power_supply_set_battery_charged(struct power_supply *psy);
-
+extern int get_usb_id_state(void);
#ifdef CONFIG_POWER_SUPPLY
extern int power_supply_is_system_supplied(void);
#else