290 lines
7.6 KiB
C
Executable file
290 lines
7.6 KiB
C
Executable file
#include <linux/device.h>
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/notifier.h>
|
|
#include <linux/ifconn/ifconn_notifier.h>
|
|
#include <linux/ifconn/ifconn_manager.h>
|
|
#if defined(CONFIG_PDIC_SUPPORT_DP)
|
|
#include <linux/power_supply.h>
|
|
#include <linux/power/s2m_chg_manager.h>
|
|
#endif
|
|
|
|
#define DEBUG
|
|
#define SET_IFCONN_NOTIFIER_BLOCK(nb, fn, dev) do { \
|
|
(nb)->notifier_call = (fn); \
|
|
(nb)->priority = (dev); \
|
|
} while (0)
|
|
|
|
#define DESTROY_IFCONN_NOTIFIER_BLOCK(nb) \
|
|
SET_IFCONN_NOTIFIER_BLOCK(nb, NULL, -1)
|
|
|
|
static char IFCONN_NOTI_DEV_Print[IFCONN_NOTIFY_MAX][15] = {
|
|
{"MANAGER"},
|
|
{"USB"},
|
|
{"BATTERY"},
|
|
{"PDIC"},
|
|
{"MUIC"},
|
|
{"VBUS"},
|
|
{"CCIC"},
|
|
{"DP"},
|
|
{"DPUSB"},
|
|
{"MODEM"},
|
|
{"FLED"},
|
|
{"MANAGER_MUIC"},
|
|
{"MANAGER_PDIC"},
|
|
{"ALL"},
|
|
};
|
|
|
|
void (*fp_select_pdo)(int num);
|
|
int (*fp_select_pps)(int num, int ppsVol, int ppsCur);
|
|
int (*fp_pd_get_apdo_max_power)(unsigned int *pdo_pos, unsigned int *taMaxVol,
|
|
unsigned int *taMaxCur, unsigned int *taMaxPwr);
|
|
int (*fp_pd_pps_enable)(int num, int ppsVol, int ppsCur, int enable);
|
|
int (*fp_pd_get_pps_voltage)(void);
|
|
EXPORT_SYMBOL_GPL(fp_select_pdo);
|
|
EXPORT_SYMBOL_GPL(fp_select_pps);
|
|
EXPORT_SYMBOL_GPL(fp_pd_get_apdo_max_power);
|
|
EXPORT_SYMBOL_GPL(fp_pd_pps_enable);
|
|
EXPORT_SYMBOL_GPL(fp_pd_get_pps_voltage);
|
|
|
|
void select_pdo(int num)
|
|
{
|
|
if (fp_select_pdo)
|
|
fp_select_pdo(num);
|
|
}
|
|
|
|
int select_pps(int num, int ppsVol, int ppsCur)
|
|
{
|
|
if (fp_select_pps)
|
|
fp_select_pps(num, ppsVol, ppsCur);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pd_get_apdo_max_power(unsigned int *pdo_pos, unsigned int *taMaxVol,
|
|
unsigned int *taMaxCur, unsigned int *taMaxPwr)
|
|
{
|
|
if (fp_pd_get_apdo_max_power)
|
|
fp_pd_get_apdo_max_power(pdo_pos, taMaxVol, taMaxCur, taMaxPwr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pd_pps_enable(int num, int ppsVol, int ppsCur, int enable)
|
|
{
|
|
if (fp_pd_pps_enable)
|
|
fp_pd_pps_enable(num, ppsVol, ppsCur, enable);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pd_get_pps_voltage(void)
|
|
{
|
|
if (fp_pd_get_pps_voltage)
|
|
return fp_pd_get_pps_voltage();
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(select_pdo);
|
|
EXPORT_SYMBOL_GPL(select_pps);
|
|
EXPORT_SYMBOL_GPL(pd_get_apdo_max_power);
|
|
EXPORT_SYMBOL_GPL(pd_pps_enable);
|
|
EXPORT_SYMBOL_GPL(pd_get_pps_voltage);
|
|
|
|
|
|
|
|
static struct ifconn_notifier pnoti[IFCONN_NOTIFY_MAX];
|
|
|
|
void _ifconn_show_attr(struct ifconn_notifier_template *t)
|
|
{
|
|
if (t == NULL)
|
|
return;
|
|
|
|
pr_info("%s, src:%s, dest:%s, id:%d, event:%d, data:0x%p\n",
|
|
__func__, IFCONN_NOTI_DEV_Print[t->src], IFCONN_NOTI_DEV_Print[t->dest], t->id, t->event, t->data);
|
|
}
|
|
|
|
int ifconn_notifier_register(struct notifier_block *nb, notifier_fn_t notifier,
|
|
ifconn_notifier_t listener, ifconn_notifier_t src)
|
|
{
|
|
int ret = 0;
|
|
struct ifconn_notifier_template *template = NULL;
|
|
#if defined(CONFIG_PDIC_SUPPORT_DP)
|
|
union power_supply_propval value;
|
|
struct power_supply *psy;
|
|
#endif
|
|
|
|
pr_info("%s: src : %d =? listner : %d, nb : %p register\n", __func__,
|
|
src, listener, nb);
|
|
|
|
if (src >= IFCONN_NOTIFY_ALL || src < 0
|
|
|| listener >= IFCONN_NOTIFY_ALL || listener < 0) {
|
|
pr_err("%s: dev index err\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
SET_IFCONN_NOTIFIER_BLOCK(nb, notifier, listener);
|
|
ret = blocking_notifier_chain_register(&(pnoti[src].notifier_call_chain), nb);
|
|
if (ret < 0)
|
|
pr_err("%s: blocking_notifier_chain_register error(%d)\n",
|
|
__func__, ret);
|
|
|
|
pnoti[src].nb[listener] = nb;
|
|
if (pnoti[src].sent[listener] || pnoti[src].sent[IFCONN_NOTIFY_ALL]) {
|
|
pr_info("%s: src : %d, listner : %d, sent : %d, sent all : %d\n", __func__,
|
|
src, listener, pnoti[src].sent[listener], pnoti[src].sent[IFCONN_NOTIFY_ALL]);
|
|
|
|
if (!pnoti[src].sent[listener] && pnoti[src].sent[IFCONN_NOTIFY_ALL]) {
|
|
template = &pnoti[src].ifconn_template[IFCONN_NOTIFY_ALL];
|
|
_ifconn_show_attr(template);
|
|
template->src = src;
|
|
template->dest = listener;
|
|
} else {
|
|
template = &(pnoti[src].ifconn_template[listener]);
|
|
}
|
|
if (listener == IFCONN_NOTIFY_BATTERY) {
|
|
if (ifconn_manager_get_pd_con_state()) {
|
|
pr_info("%s, PD connected\n", __func__);
|
|
} else {
|
|
pr_info("%s, PD not connected, muic notify\n", __func__);
|
|
template->id = IFCONN_NOTIFY_ID_ATTACH;
|
|
template->attach = IFCONN_NOTIFY_ATTACH;
|
|
template->cable_type = ifconn_manager_get_muic_cable_type();
|
|
template->event = ifconn_manager_get_muic_cable_type();
|
|
}
|
|
|
|
}
|
|
_ifconn_show_attr(template);
|
|
ret = nb->notifier_call(nb, template->id, template);
|
|
}
|
|
|
|
#if defined(CONFIG_PDIC_SUPPORT_DP)
|
|
if (listener == IFCONN_NOTIFY_DP) {
|
|
pr_info("%s, DP registered, set to pdic start VDM\n", __func__);
|
|
psy = power_supply_get_by_name("s2mu106-usbpd");
|
|
if (!psy) {
|
|
pr_info("%s, fail to get psy\n", __func__);
|
|
psy = power_supply_get_by_name("usbpd-manager");
|
|
if (!psy) {
|
|
pr_info("%s, fail to get psy\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
value.intval = 1;
|
|
power_supply_set_property(psy, (enum power_supply_property)POWER_SUPPLY_S2M_PROP_DP_ENABLED, &value);
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ifconn_notifier_register);
|
|
|
|
int ifconn_notifier_unregister(ifconn_notifier_t src,
|
|
ifconn_notifier_t listener)
|
|
{
|
|
int ret = 0;
|
|
struct notifier_block *nb = NULL;
|
|
|
|
if (src >= IFCONN_NOTIFY_ALL || src < 0
|
|
|| listener >= IFCONN_NOTIFY_ALL || listener < 0) {
|
|
pr_err("%s: dev index err\n", __func__);
|
|
return -1;
|
|
}
|
|
nb = pnoti[src].nb[listener];
|
|
|
|
pr_info("%s: listener=%d unregister\n", __func__, nb->priority);
|
|
|
|
ret = blocking_notifier_chain_unregister(&(pnoti[src].notifier_call_chain), nb);
|
|
if (ret < 0)
|
|
pr_err("%s: blocking_notifier_chain_unregister error(%d)\n",
|
|
__func__, ret);
|
|
DESTROY_IFCONN_NOTIFIER_BLOCK(nb);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ifconn_notifier_unregister);
|
|
|
|
int ifconn_notifier_notify(ifconn_notifier_t src,
|
|
ifconn_notifier_t listener,
|
|
int noti_id,
|
|
int event,
|
|
ifconn_notifier_data_param_t param_type, void *data)
|
|
{
|
|
int ret = 0;
|
|
struct ifconn_notifier_template *template = NULL;
|
|
struct notifier_block *nb = NULL;
|
|
|
|
pr_info("%s: enter\n", __func__);
|
|
|
|
if (src > IFCONN_NOTIFY_ALL || src < 0
|
|
|| listener > IFCONN_NOTIFY_ALL || listener < 0) {
|
|
pr_err("%s: dev index err\n", __func__);
|
|
return -1;
|
|
}
|
|
pr_info("%s: src = %s, listener = %s, nb = 0x%p notify\n", __func__,
|
|
IFCONN_NOTI_DEV_Print[src], IFCONN_NOTI_DEV_Print[listener],
|
|
pnoti[src].nb[listener]);
|
|
|
|
if (param_type == IFCONN_NOTIFY_PARAM_TEMPLATE) {
|
|
template = (struct ifconn_notifier_template *)data;
|
|
} else {
|
|
template = &(pnoti[src].ifconn_template[listener]);
|
|
template->id = (uint64_t) noti_id;
|
|
template->up_src = template->src = (uint64_t) src;
|
|
template->dest = (uint64_t) listener;
|
|
template->cable_type = template->event = event;
|
|
template->data = data;
|
|
}
|
|
|
|
pr_info("[DEBUG] %s, sub1(%d), sub2(%d)\n", __func__, template->sub1, template->sub2);
|
|
|
|
_ifconn_show_attr(template);
|
|
|
|
if (pnoti[src].nb[listener] == NULL)
|
|
pnoti[src].sent[listener] = true;
|
|
|
|
if (listener == IFCONN_NOTIFY_ALL) {
|
|
ret = blocking_notifier_call_chain(&(pnoti[src].notifier_call_chain),
|
|
(unsigned long)noti_id, template);
|
|
} else {
|
|
if (pnoti[src].nb[listener] == NULL) {
|
|
if (param_type == IFCONN_NOTIFY_PARAM_TEMPLATE) {
|
|
memcpy(&(pnoti[src].ifconn_template[listener]), template,
|
|
sizeof(struct ifconn_notifier_template));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
nb = pnoti[src].nb[listener];
|
|
ret = nb->notifier_call(nb, (unsigned long)noti_id, template);
|
|
}
|
|
|
|
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;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ifconn_notifier_notify);
|
|
|
|
#if 0
|
|
static int __init ifconn_notifier_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
pr_info("%s\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
device_initcall(ifconn_notifier_init);
|
|
#endif
|