#define pr_fmt(fmt) "[MUIC] " fmt #include #include #include #include #include #if defined(CONFIG_SWITCH) #include #endif /* CONFIG_SWITCH */ /* * The src & dest addresses of the noti. * keep the same value defined in ccic_notifier.h * b'0001 : CCIC * b'0010 : MUIC * b'1111 : Broadcasting */ #define NOTI_ADDR_SRC CCIC_NOTIFY_DEV_MUIC #define NOTI_ADDR_DST (0xf) /* ATTACH Noti. ID */ #define NOTI_ID_ATTACH (1) #define SET_MUIC_NOTIFIER_BLOCK(nb, fn, dev) do { \ (nb)->notifier_call = (fn); \ (nb)->priority = (dev); \ } while (0) #define DESTROY_MUIC_NOTIFIER_BLOCK(nb) \ SET_MUIC_NOTIFIER_BLOCK(nb, NULL, -1) static struct muic_notifier_struct muic_notifier; #if defined(CONFIG_MUIC_S2MU106) static struct muic_notifier_struct muic_ccic_notifier; #endif struct device *switch_device; static int muic_uses_new_noti; #if defined(CONFIG_MUIC_S2MU106) static int muic_ccic_uses_new_noti; #endif void muic_notifier_set_new_noti(bool flag) { muic_uses_new_noti = flag ? 1: 0; } static void __set_noti_cxt(int attach, int type) { if (type < 0) { muic_notifier.cmd = attach; muic_notifier.cxt.attach = attach; return; } /* Old Interface */ muic_notifier.cmd = attach; muic_notifier.attached_dev = type; /* New Interface */ muic_notifier.cxt.src = NOTI_ADDR_SRC; muic_notifier.cxt.dest = NOTI_ADDR_DST; muic_notifier.cxt.id = NOTI_ID_ATTACH; muic_notifier.cxt.attach = attach; muic_notifier.cxt.cable_type = type; muic_notifier.cxt.rprd = 0; } #if defined(CONFIG_MUIC_S2MU106) static void __set_ccic_noti_cxt(int attach, int type) { if (type < 0) { muic_ccic_notifier.cmd = attach; muic_ccic_notifier.cxt.attach = attach; return; } /* Old Interface */ muic_ccic_notifier.cmd = attach; muic_ccic_notifier.attached_dev = type; /* New Interface */ muic_ccic_notifier.cxt.src = NOTI_ADDR_SRC; muic_ccic_notifier.cxt.dest = NOTI_ADDR_DST; muic_ccic_notifier.cxt.id = NOTI_ID_ATTACH; muic_ccic_notifier.cxt.attach = attach; muic_ccic_notifier.cxt.cable_type = type; muic_ccic_notifier.cxt.rprd = 0; } #endif int muic_notifier_register(struct notifier_block *nb, notifier_fn_t notifier, muic_notifier_device_t listener) { int ret = 0; void *pcxt; pr_info("%s: listener=%d register\n", __func__, listener); SET_MUIC_NOTIFIER_BLOCK(nb, notifier, listener); ret = blocking_notifier_chain_register(&(muic_notifier.notifier_call_chain), nb); if (ret < 0) pr_err("%s: blocking_notifier_chain_register error(%d)\n", __func__, ret); pcxt = muic_uses_new_noti ? &(muic_notifier.cxt) : \ (void *)&(muic_notifier.attached_dev); /* current muic's attached_device status notify */ nb->notifier_call(nb, muic_notifier.cxt.attach, pcxt); return ret; } int muic_notifier_unregister(struct notifier_block *nb) { int ret = 0; pr_info("%s: listener=%d unregister\n", __func__, nb->priority); ret = blocking_notifier_chain_unregister(&(muic_notifier.notifier_call_chain), nb); if (ret < 0) pr_err("%s: blocking_notifier_chain_unregister error(%d)\n", __func__, ret); DESTROY_MUIC_NOTIFIER_BLOCK(nb); return ret; } static int muic_notifier_notify(void) { int ret = 0; void *pcxt; pr_info("%s: CMD=%d, DATA=%d\n", __func__, muic_notifier.cxt.attach, muic_notifier.cxt.cable_type); #ifdef CONFIG_SEC_FACTORY if (muic_notifier.cxt.attach != 0) muic_send_attached_muic_cable_intent(muic_notifier.cxt.cable_type); else muic_send_attached_muic_cable_intent(0); #endif pcxt = muic_uses_new_noti ? &(muic_notifier.cxt) : \ (void *)&(muic_notifier.attached_dev); ret = blocking_notifier_call_chain(&(muic_notifier.notifier_call_chain), muic_notifier.cxt.attach, pcxt); switch (ret) { case NOTIFY_STOP_MASK: case NOTIFY_BAD: pr_err("%s: notify error occur(0x%x)\n", __func__, ret); break; case NOTIFY_DONE: case NOTIFY_OK: pr_info("%s: notify done(0x%x)\n", __func__, ret); break; default: pr_info("%s: notify status unknown(0x%x)\n", __func__, ret); break; } return ret; } #if defined(CONFIG_MUIC_S2MU106) int muic_ccic_notifier_register(struct notifier_block *nb, notifier_fn_t notifier, muic_notifier_device_t listener) { int ret = 0; #if defined(CONFIG_MUIC_MANAGER) && defined(CONFIG_CCIC_NOTIFIER) void *pcxt; #endif pr_info("%s: listener=%d register\n", __func__, listener); SET_MUIC_NOTIFIER_BLOCK(nb, notifier, listener); ret = blocking_notifier_chain_register(&(muic_ccic_notifier.notifier_call_chain), nb); if (ret < 0) pr_err("%s: blocking_notifier_chain_register error(%d)\n", __func__, ret); #if defined(CONFIG_MUIC_MANAGER) && defined(CONFIG_CCIC_NOTIFIER) pcxt = muic_ccic_uses_new_noti ? &(muic_ccic_notifier.cxt) : (void *)&(muic_ccic_notifier.attached_dev); /* current muic's attached_device status notify */ nb->notifier_call(nb, muic_ccic_notifier.cxt.attach, pcxt); #else nb->notifier_call(nb, muic_ccic_notifier.cmd, &(muic_ccic_notifier.attached_dev)); #endif return ret; } int muic_ccic_notifier_unregister(struct notifier_block *nb) { int ret = 0; pr_info("%s: listener=%d unregister\n", __func__, nb->priority); ret = blocking_notifier_chain_unregister(&(muic_ccic_notifier.notifier_call_chain), nb); if (ret < 0) pr_err("%s: blocking_notifier_chain_unregister error(%d)\n", __func__, ret); DESTROY_MUIC_NOTIFIER_BLOCK(nb); return ret; } static int muic_ccic_notifier_notify(void) { int ret = 0; #if defined(CONFIG_MUIC_MANAGER) && defined(CONFIG_CCIC_NOTIFIER) void *pcxt; pr_info("%s: CMD=%d, DATA=%d\n", __func__, muic_ccic_notifier.cxt.attach, muic_ccic_notifier.cxt.cable_type); pcxt = muic_ccic_uses_new_noti ? &(muic_ccic_notifier.cxt) : (void *)&(muic_ccic_notifier.attached_dev); ret = blocking_notifier_call_chain(&(muic_ccic_notifier.notifier_call_chain), muic_ccic_notifier.cxt.attach, pcxt); #else pr_info("%s: CMD=%d, DATA=%d\n", __func__, muic_ccic_notifier.cmd, muic_ccic_notifier.attached_dev); ret = blocking_notifier_call_chain(&(muic_ccic_notifier.notifier_call_chain), muic_ccic_notifier.cmd, &(muic_ccic_notifier.attached_dev)); #endif switch (ret) { case NOTIFY_STOP_MASK: case NOTIFY_BAD: pr_err("%s: notify error occur(0x%x)\n", __func__, ret); break; case NOTIFY_DONE: case NOTIFY_OK: pr_info("%s: notify done(0x%x)\n", __func__, ret); break; default: pr_info("%s: notify status unknown(0x%x)\n", __func__, ret); break; } return ret; } #endif void muic_notifier_attach_attached_dev(muic_attached_dev_t new_dev) { pr_info("%s: (%d)\n", __func__, new_dev); __set_noti_cxt(MUIC_NOTIFY_CMD_ATTACH, new_dev); /* muic's attached_device attach broadcast */ muic_notifier_notify(); } void muic_pdic_notifier_attach_attached_dev(muic_attached_dev_t new_dev) { pr_info("%s: (%d)\n", __func__, new_dev); #if defined(CONFIG_CCIC_S2MU004) || defined(CONFIG_MUIC_S2MU107) || defined(CONFIG_MUIC_S2MU106) __set_ccic_noti_cxt(MUIC_PDIC_NOTIFY_CMD_ATTACH, new_dev); /* muic's attached_device attach broadcast */ muic_ccic_notifier_notify(); #else __set_noti_cxt(MUIC_PDIC_NOTIFY_CMD_ATTACH, new_dev); /* muic's attached_device attach broadcast */ muic_notifier_notify(); #endif } void muic_pdic_notifier_detach_attached_dev(muic_attached_dev_t new_dev) { pr_info("%s: (%d)\n", __func__, new_dev); #if defined(CONFIG_CCIC_S2MU004) || defined(CONFIG_MUIC_S2MU107) || defined(CONFIG_MUIC_S2MU106) __set_ccic_noti_cxt(MUIC_PDIC_NOTIFY_CMD_DETACH, new_dev); /* muic's attached_device attach broadcast */ muic_ccic_notifier_notify(); #else __set_noti_cxt(MUIC_PDIC_NOTIFY_CMD_DETACH, muic_notifier.attached_dev); /* muic's attached_device attach broadcast */ muic_notifier_notify(); #endif } void muic_notifier_detach_attached_dev(muic_attached_dev_t cur_dev) { pr_info("%s: (%d)\n", __func__, cur_dev); __set_noti_cxt(MUIC_NOTIFY_CMD_DETACH, -1); if (muic_notifier.cxt.cable_type != cur_dev) pr_warn("%s: attached_dev of muic_notifier(%d) != muic_data(%d)\n", __func__, muic_notifier.cxt.cable_type, cur_dev); if (muic_notifier.cxt.cable_type != ATTACHED_DEV_NONE_MUIC) { /* muic's attached_device detach broadcast */ muic_notifier_notify(); } __set_noti_cxt(0, ATTACHED_DEV_NONE_MUIC); } void muic_notifier_logically_attach_attached_dev(muic_attached_dev_t new_dev) { pr_info("%s: (%d)\n", __func__, new_dev); __set_noti_cxt(MUIC_NOTIFY_CMD_ATTACH, new_dev); /* muic's attached_device attach broadcast */ muic_notifier_notify(); } void muic_notifier_logically_detach_attached_dev(muic_attached_dev_t cur_dev) { pr_info("%s: (%d)\n", __func__, cur_dev); __set_noti_cxt(MUIC_NOTIFY_CMD_DETACH, cur_dev); /* muic's attached_device detach broadcast */ muic_notifier_notify(); __set_noti_cxt(0, ATTACHED_DEV_NONE_MUIC); } #if IS_ENABLED(CONFIG_HICCUP_CHARGER) void muic_notifier_hiccup_mode(int enable) { int attach = muic_notifier.cxt.attach; int type = muic_notifier.cxt.cable_type; pr_info("%s: hiccup mode (%d)\n", __func__, enable); #if 0 __set_noti_cxt(MUIC_NOTIFY_CMD_HICCUP, enable); #endif /* muic's hiccup mode broadcast */ muic_notifier_notify(); __set_noti_cxt(attach, type); } #endif #ifdef CONFIG_CCIC_NOTIFIER extern int ccic_notifier_init(void); #endif #ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER extern int manager_notifier_init(void); #endif static int __init muic_notifier_init(void) { int ret = 0; pr_info("%s\n", __func__); #if defined(CONFIG_MUIC_SUPPORT_CCIC) && defined(CONFIG_CCIC_NOTIFIER) || defined(CONFIG_MUIC_S2MU106) muic_uses_new_noti = 1; #endif #if defined(CONFIG_SWITCH) switch_device = sec_device_create(NULL, "switch"); if (IS_ERR(switch_device)) { pr_err("(%s): failed to created device (switch_device)!\n", __func__); return -ENODEV; } #endif BLOCKING_INIT_NOTIFIER_HEAD(&(muic_notifier.notifier_call_chain)); __set_noti_cxt(0, ATTACHED_DEV_UNKNOWN_MUIC); #if defined(CONFIG_MUIC_S2MU106) BLOCKING_INIT_NOTIFIER_HEAD(&(muic_ccic_notifier.notifier_call_chain)); __set_ccic_noti_cxt(0, ATTACHED_DEV_UNKNOWN_MUIC); muic_ccic_uses_new_noti = 1; #endif return ret; } device_initcall(muic_notifier_init);