diff options
| author | Davide Garberi <dade.garberi@gmail.com> | 2018-11-08 21:07:46 +0100 |
|---|---|---|
| committer | Davide Garberi <dade.garberi@gmail.com> | 2022-07-27 18:59:05 +0200 |
| commit | 90f7546c2b4ac17a46a24e699877a727d6033757 (patch) | |
| tree | db119fb69538171933f9b7f890135e90ffa6dfa1 | |
| parent | d8a6f82e92cecb1414ac9abafdb53fc4a3b6073d (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.c | 105 | ||||
| -rw-r--r-- | drivers/misc/cclogic/cclogic-core.h | 2 | ||||
| -rw-r--r-- | drivers/misc/cclogic/tusb320hai.c | 2 | ||||
| -rw-r--r-- | drivers/power/supply/qcom/qpnp-smbcharger.c | 87 | ||||
| -rw-r--r-- | include/linux/cclogic-core.h | 4 | ||||
| -rw-r--r-- | include/linux/power_supply.h | 2 |
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,®, &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 |
