soc: qcom: fsa4480: Add Xiaomi power supply integration
Taken and modified from garnet-t-oss' fsa4480-msm54 driver. Change-Id: Ia5056525cd7f2e9f5e203399f39836218511f14b Signed-off-by: Jens Reidel <adrian@travitia.xyz>
This commit is contained in:
parent
bc43b97718
commit
be89c2c54e
@ -12,6 +12,15 @@
|
||||
#include <linux/soc/qcom/fsa4480-i2c.h>
|
||||
#include <linux/qti-regmap-debugfs.h>
|
||||
#include <linux/mmhardware_sysfs.h>
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
#include <linux/battmngr/xm_battmngr_iio.h>
|
||||
#include <linux/battmngr/battmngr_notifier.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/err.h>
|
||||
#endif
|
||||
|
||||
#define FSA4480_I2C_NAME "fsa4480-driver"
|
||||
|
||||
@ -28,15 +37,27 @@
|
||||
#define FSA4480_DELAY_L_SENSE 0x0F
|
||||
#define FSA4480_DELAY_L_AGND 0x10
|
||||
#define FSA4480_RESET 0x1E
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
#define ET7480_ID 0x00
|
||||
#define ET7480_ID_VALUE 0x88
|
||||
#define DIO4480_ID_VALUE 0xF1
|
||||
#endif
|
||||
|
||||
struct fsa4480_priv {
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct notifier_block ucsi_nb;
|
||||
struct notifier_block nb;
|
||||
atomic_t usbc_mode;
|
||||
struct work_struct usbc_analog_work;
|
||||
struct blocking_notifier_head fsa4480_notifier;
|
||||
struct mutex notification_lock;
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
struct power_supply *usb_psy;
|
||||
u32 use_powersupply;
|
||||
int switch_control;
|
||||
bool dio4480;
|
||||
struct gpio_desc *typec_gpio;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct fsa4480_reg_val {
|
||||
@ -63,6 +84,21 @@ static const struct fsa4480_reg_val fsa_reg_i2c_defaults[] = {
|
||||
{FSA4480_SWITCH_SETTINGS, 0x98},
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
static int fsa4480_check_usb_psy(struct fsa4480_priv *fsa_priv)
|
||||
{
|
||||
if (!fsa_priv->usb_psy) {
|
||||
fsa_priv->usb_psy = power_supply_get_by_name("usb");
|
||||
if (!fsa_priv->usb_psy) {
|
||||
pr_err("usb psy not found!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fsa4480_usbc_update_settings(struct fsa4480_priv *fsa_priv,
|
||||
u32 switch_control, u32 switch_enable)
|
||||
{
|
||||
@ -87,11 +123,166 @@ static void fsa4480_usbc_update_settings(struct fsa4480_priv *fsa_priv,
|
||||
regmap_write(fsa_priv->regmap, FSA4480_SWITCH_SETTINGS, switch_enable);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
static int fsa4480_usbc_event_changed_battmngr(struct fsa4480_priv *fsa_priv,
|
||||
struct battmngr_notify *data)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
|
||||
dev = fsa_priv->dev;
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(dev, "%s: USB change event received, audio switch %d, supply mode %d, usbc mode %ld, expected %d\n",
|
||||
__func__, fsa_priv->dio4480, data->pd_msg.accessory_mode, fsa_priv->usbc_mode.counter,
|
||||
TYPEC_ACCESSORY_AUDIO);
|
||||
|
||||
switch (data->pd_msg.accessory_mode) {
|
||||
case TYPEC_ACCESSORY_AUDIO:
|
||||
case TYPEC_ACCESSORY_NONE:
|
||||
if (atomic_read(&(fsa_priv->usbc_mode)) == data->pd_msg.accessory_mode)
|
||||
break; /* filter notifications received before */
|
||||
atomic_set(&(fsa_priv->usbc_mode), data->pd_msg.accessory_mode);
|
||||
|
||||
dev_dbg(dev, "%s: queueing usbc_analog_work\n",
|
||||
__func__);
|
||||
pm_stay_awake(fsa_priv->dev);
|
||||
queue_work(system_freezable_wq, &fsa_priv->usbc_analog_work);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsa4480_usbc_event_changed_psupply(struct fsa4480_priv *fsa_priv,
|
||||
unsigned long evt, void *ptr)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
struct power_supply *psy = ptr;
|
||||
union power_supply_propval mode;
|
||||
int rc = 0;
|
||||
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
|
||||
dev = fsa_priv->dev;
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (fsa4480_check_usb_psy(fsa_priv)) {
|
||||
if (psy != fsa_priv->usb_psy) {
|
||||
dev_dbg(dev, "%s: this event is not usb psy\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rc = xm_battmngr_read_iio_prop(g_battmngr_iio, PD_PHY,
|
||||
PD_TYPEC_ACCESSORY_MODE, &mode.intval);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "%s: Unable to read USB TYPEC_MODE: %d\n",
|
||||
__func__, rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s: USB change event received, audio switch %d, supply mode %d, usbc mode %ld, expected %d\n",
|
||||
__func__, fsa_priv->dio4480, mode.intval, fsa_priv->usbc_mode.counter,
|
||||
TYPEC_ACCESSORY_AUDIO);
|
||||
|
||||
switch (mode.intval) {
|
||||
case TYPEC_ACCESSORY_AUDIO:
|
||||
case TYPEC_ACCESSORY_NONE:
|
||||
if (atomic_read(&(fsa_priv->usbc_mode)) == mode.intval)
|
||||
break; /* filter notifications received before */
|
||||
atomic_set(&(fsa_priv->usbc_mode), mode.intval);
|
||||
|
||||
dev_dbg(dev, "%s: queueing usbc_analog_work\n",
|
||||
__func__);
|
||||
pm_stay_awake(fsa_priv->dev);
|
||||
queue_work(system_freezable_wq, &fsa_priv->usbc_analog_work);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsa4480_usbc_event_changed_ucsi(struct fsa4480_priv *fsa_priv,
|
||||
unsigned long evt, void *ptr)
|
||||
{
|
||||
struct device *dev;
|
||||
enum typec_accessory acc = ((struct ucsi_glink_constat_info *)ptr)->acc;
|
||||
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
|
||||
dev = fsa_priv->dev;
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(dev, "%s: USB change event received, audio switch %d, supply mode %d, usbc mode %ld, expected %d\n",
|
||||
__func__, fsa_priv->dio4480, acc, fsa_priv->usbc_mode.counter,
|
||||
TYPEC_ACCESSORY_AUDIO);
|
||||
|
||||
switch (acc) {
|
||||
case TYPEC_ACCESSORY_AUDIO:
|
||||
case TYPEC_ACCESSORY_NONE:
|
||||
if (atomic_read(&(fsa_priv->usbc_mode)) == acc)
|
||||
break; /* filter notifications received before */
|
||||
atomic_set(&(fsa_priv->usbc_mode), acc);
|
||||
|
||||
dev_dbg(dev, "%s: queueing usbc_analog_work\n",
|
||||
__func__);
|
||||
pm_stay_awake(fsa_priv->dev);
|
||||
queue_work(system_freezable_wq, &fsa_priv->usbc_analog_work);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsa4480_usbc_event_changed(struct notifier_block *nb_ptr,
|
||||
unsigned long evt, void *ptr)
|
||||
{
|
||||
struct fsa4480_priv *fsa_priv =
|
||||
container_of(nb_ptr, struct fsa4480_priv, nb);
|
||||
struct device *dev;
|
||||
struct battmngr_notify *data = ptr;
|
||||
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
|
||||
dev = fsa_priv->dev;
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
if (fsa_priv->use_powersupply == 2) {
|
||||
if ((evt == BATTMNGR_EVENT_PD) && (data->pd_msg.msg_type == BATTMNGR_MSG_PD_AUDIO))
|
||||
return fsa4480_usbc_event_changed_battmngr(fsa_priv, data);
|
||||
} else if (fsa_priv->use_powersupply == 1) {
|
||||
return fsa4480_usbc_event_changed_psupply(fsa_priv, evt, ptr);
|
||||
} else {
|
||||
return fsa4480_usbc_event_changed_ucsi(fsa_priv, evt, ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int fsa4480_usbc_event_changed(struct notifier_block *nb,
|
||||
unsigned long evt, void *ptr)
|
||||
{
|
||||
struct fsa4480_priv *fsa_priv =
|
||||
container_of(nb, struct fsa4480_priv, ucsi_nb);
|
||||
container_of(nb, struct fsa4480_priv, nb);
|
||||
struct device *dev;
|
||||
enum typec_accessory acc = ((struct ucsi_glink_constat_info *)ptr)->acc;
|
||||
|
||||
@ -124,6 +315,173 @@ static int fsa4480_usbc_event_changed(struct notifier_block *nb,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
static int fsa4480_usbc_analog_setup_switches_battmngr(
|
||||
struct fsa4480_priv *fsa_priv)
|
||||
{
|
||||
int rc = 0;
|
||||
int mode;
|
||||
struct device *dev;
|
||||
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
dev = fsa_priv->dev;
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&fsa_priv->notification_lock);
|
||||
/* get latest mode again within locked context */
|
||||
mode = atomic_read(&(fsa_priv->usbc_mode));
|
||||
|
||||
dev_dbg(dev, "%s: setting GPIOs active = %d rcvd supply mode = %d\n",
|
||||
__func__, mode != TYPEC_ACCESSORY_NONE, mode);
|
||||
|
||||
switch (mode) {
|
||||
/* add all modes FSA should notify for in here */
|
||||
case TYPEC_ACCESSORY_AUDIO:
|
||||
if (fsa_priv->typec_gpio)
|
||||
gpiod_set_value_cansleep(fsa_priv->typec_gpio, 1);
|
||||
|
||||
/* activate switches */
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F);
|
||||
|
||||
/* notify call chain on event */
|
||||
blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier,
|
||||
mode, NULL);
|
||||
break;
|
||||
case TYPEC_ACCESSORY_NONE:
|
||||
if (fsa_priv->typec_gpio)
|
||||
gpiod_set_value_cansleep(fsa_priv->typec_gpio, 0);
|
||||
|
||||
/* notify call chain on event */
|
||||
blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier,
|
||||
TYPEC_ACCESSORY_NONE, NULL);
|
||||
|
||||
/* deactivate switches */
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
|
||||
break;
|
||||
default:
|
||||
/* ignore other usb connection modes */
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&fsa_priv->notification_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fsa4480_usbc_analog_setup_switches_psupply(
|
||||
struct fsa4480_priv *fsa_priv)
|
||||
{
|
||||
int rc = 0;
|
||||
int mode;
|
||||
struct device *dev;
|
||||
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
dev = fsa_priv->dev;
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&fsa_priv->notification_lock);
|
||||
/* get latest mode again within locked context */
|
||||
mode = atomic_read(&(fsa_priv->usbc_mode));
|
||||
|
||||
dev_dbg(dev, "%s: setting GPIOs active = %d rcvd supply mode = %d\n",
|
||||
__func__, mode != TYPEC_ACCESSORY_NONE, mode);
|
||||
|
||||
switch (mode) {
|
||||
/* add all modes FSA should notify for in here */
|
||||
case TYPEC_ACCESSORY_AUDIO:
|
||||
if (fsa_priv->typec_gpio)
|
||||
gpiod_set_value_cansleep(fsa_priv->typec_gpio, 1);
|
||||
|
||||
/* activate switches */
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F);
|
||||
|
||||
/* notify call chain on event */
|
||||
blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier,
|
||||
mode, NULL);
|
||||
break;
|
||||
case TYPEC_ACCESSORY_NONE:
|
||||
if (fsa_priv->typec_gpio)
|
||||
gpiod_set_value_cansleep(fsa_priv->typec_gpio, 0);
|
||||
|
||||
/* notify call chain on event */
|
||||
blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier,
|
||||
TYPEC_ACCESSORY_NONE, NULL);
|
||||
|
||||
/* deactivate switches */
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
|
||||
break;
|
||||
default:
|
||||
/* ignore other usb connection modes */
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&fsa_priv->notification_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fsa4480_usbc_analog_setup_switches_ucsi(
|
||||
struct fsa4480_priv *fsa_priv)
|
||||
{
|
||||
int rc = 0;
|
||||
int mode;
|
||||
struct device *dev;
|
||||
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
dev = fsa_priv->dev;
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&fsa_priv->notification_lock);
|
||||
/* get latest mode again within locked context */
|
||||
mode = atomic_read(&(fsa_priv->usbc_mode));
|
||||
|
||||
dev_dbg(dev, "%s: setting GPIOs active = %d\n",
|
||||
__func__, mode != TYPEC_ACCESSORY_NONE);
|
||||
|
||||
switch (mode) {
|
||||
/* add all modes FSA should notify for in here */
|
||||
case TYPEC_ACCESSORY_AUDIO:
|
||||
/* activate switches */
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F);
|
||||
|
||||
/* notify call chain on event */
|
||||
blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier,
|
||||
mode, NULL);
|
||||
break;
|
||||
case TYPEC_ACCESSORY_NONE:
|
||||
/* notify call chain on event */
|
||||
blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier,
|
||||
TYPEC_ACCESSORY_NONE, NULL);
|
||||
|
||||
/* deactivate switches */
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
|
||||
break;
|
||||
default:
|
||||
/* ignore other usb connection modes */
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&fsa_priv->notification_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv)
|
||||
{
|
||||
if (fsa_priv->use_powersupply == 2)
|
||||
return fsa4480_usbc_analog_setup_switches_battmngr(fsa_priv);
|
||||
else if (fsa_priv->use_powersupply == 1)
|
||||
return fsa4480_usbc_analog_setup_switches_psupply(fsa_priv);
|
||||
else
|
||||
return fsa4480_usbc_analog_setup_switches_ucsi(fsa_priv);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv)
|
||||
{
|
||||
@ -170,6 +528,7 @@ static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv)
|
||||
mutex_unlock(&fsa_priv->notification_lock);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fsa4480_reg_notifier - register notifier block with fsa driver
|
||||
@ -205,11 +564,17 @@ int fsa4480_reg_notifier(struct notifier_block *nb,
|
||||
* as part of the init sequence check if there is a connected
|
||||
* USB C analog adapter
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
rc = fsa4480_usbc_analog_setup_switches(fsa_priv);
|
||||
regmap_update_bits(fsa_priv->regmap, FSA4480_SWITCH_CONTROL, 0x07,
|
||||
fsa_priv->switch_control);
|
||||
#else
|
||||
if (atomic_read(&(fsa_priv->usbc_mode)) == TYPEC_ACCESSORY_AUDIO) {
|
||||
dev_dbg(fsa_priv->dev, "%s: analog adapter already inserted\n",
|
||||
__func__);
|
||||
rc = fsa4480_usbc_analog_setup_switches(fsa_priv);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -226,6 +591,7 @@ EXPORT_SYMBOL(fsa4480_reg_notifier);
|
||||
int fsa4480_unreg_notifier(struct notifier_block *nb,
|
||||
struct device_node *node)
|
||||
{
|
||||
int rc = 0;
|
||||
struct i2c_client *client = of_find_i2c_device_by_node(node);
|
||||
struct fsa4480_priv *fsa_priv;
|
||||
|
||||
@ -236,9 +602,19 @@ int fsa4480_unreg_notifier(struct notifier_block *nb,
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
mutex_lock(&fsa_priv->notification_lock);
|
||||
#endif
|
||||
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
|
||||
return blocking_notifier_chain_unregister
|
||||
rc = blocking_notifier_chain_unregister
|
||||
(&fsa_priv->fsa4480_notifier, nb);
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
mutex_unlock(&fsa_priv->notification_lock);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(fsa4480_unreg_notifier);
|
||||
|
||||
@ -267,7 +643,13 @@ static int fsa4480_validate_display_port_settings(struct fsa4480_priv *fsa_priv)
|
||||
int fsa4480_switch_event(struct device_node *node,
|
||||
enum fsa_function event)
|
||||
{
|
||||
int switch_control = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
int *switch_control;
|
||||
#else
|
||||
int switch_control_real = 0;
|
||||
int *switch_control = &switch_control_real;
|
||||
#endif
|
||||
struct i2c_client *client = of_find_i2c_device_by_node(node);
|
||||
struct fsa4480_priv *fsa_priv;
|
||||
|
||||
@ -280,15 +662,19 @@ int fsa4480_switch_event(struct device_node *node,
|
||||
if (!fsa_priv->regmap)
|
||||
return -EINVAL;
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
switch_control = &fsa_priv->switch_control;
|
||||
#endif
|
||||
|
||||
switch (event) {
|
||||
case FSA_MIC_GND_SWAP:
|
||||
regmap_read(fsa_priv->regmap, FSA4480_SWITCH_CONTROL,
|
||||
&switch_control);
|
||||
if ((switch_control & 0x07) == 0x07)
|
||||
switch_control = 0x0;
|
||||
switch_control);
|
||||
if ((*switch_control & 0x07) == 0x07)
|
||||
*switch_control = 0x0;
|
||||
else
|
||||
switch_control = 0x7;
|
||||
fsa4480_usbc_update_settings(fsa_priv, switch_control, 0x9F);
|
||||
*switch_control = 0x7;
|
||||
fsa4480_usbc_update_settings(fsa_priv, *switch_control, 0x9F);
|
||||
break;
|
||||
case FSA_USBC_ORIENTATION_CC1:
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x18, 0xF8);
|
||||
@ -334,6 +720,11 @@ static int fsa4480_probe(struct i2c_client *i2c,
|
||||
{
|
||||
struct fsa4480_priv *fsa_priv;
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
u32 use_powersupply = 0;
|
||||
int reg_val = 0;
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
fsa_priv = devm_kzalloc(&i2c->dev, sizeof(*fsa_priv),
|
||||
GFP_KERNEL);
|
||||
@ -355,16 +746,61 @@ static int fsa4480_probe(struct i2c_client *i2c,
|
||||
}
|
||||
|
||||
fsa4480_update_reg_defaults(fsa_priv->regmap);
|
||||
devm_regmap_qti_debugfs_register(fsa_priv->dev, fsa_priv->regmap);
|
||||
|
||||
fsa_priv->ucsi_nb.notifier_call = fsa4480_usbc_event_changed;
|
||||
fsa_priv->ucsi_nb.priority = 0;
|
||||
rc = register_ucsi_glink_notifier(&fsa_priv->ucsi_nb);
|
||||
devm_regmap_qti_debugfs_register(fsa_priv->dev, fsa_priv->regmap);
|
||||
fsa_priv->nb.notifier_call = fsa4480_usbc_event_changed;
|
||||
fsa_priv->nb.priority = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
rc = of_property_read_u32(fsa_priv->dev->of_node,
|
||||
"qcom,use-power-supply", &use_powersupply);
|
||||
if (rc || use_powersupply == 2) {
|
||||
fsa_priv->use_powersupply = 2;
|
||||
rc = battmngr_notifier_register(&fsa_priv->nb);
|
||||
if (rc) {
|
||||
dev_err(fsa_priv->dev,
|
||||
"%s: battmngr notifier registration failed: %d\n",
|
||||
__func__, rc);
|
||||
goto err_data;
|
||||
}
|
||||
} else if (rc || use_powersupply == 1) {
|
||||
fsa_priv->use_powersupply = 1;
|
||||
fsa_priv->usb_psy = power_supply_get_by_name("usb");
|
||||
if (!fsa_priv->usb_psy) {
|
||||
dev_dbg(fsa_priv->dev,
|
||||
"%s: could not get USB psy info: %d\n",
|
||||
__func__, rc);
|
||||
}
|
||||
|
||||
rc = power_supply_reg_notifier(&fsa_priv->nb);
|
||||
if (rc) {
|
||||
dev_err(fsa_priv->dev,
|
||||
"%s: power supply reg failed: %d\n",
|
||||
__func__, rc);
|
||||
goto err_supply;
|
||||
}
|
||||
} else {
|
||||
dev_dbg(fsa_priv->dev,
|
||||
"%s: Looking up %s property failed or disabled\n",
|
||||
__func__, "qcom,use-power-supply");
|
||||
|
||||
fsa_priv->use_powersupply = 0;
|
||||
rc = register_ucsi_glink_notifier(&fsa_priv->nb);
|
||||
if (rc) {
|
||||
dev_err(fsa_priv->dev,
|
||||
"%s: ucsi glink notifier registration failed: %d\n",
|
||||
__func__, rc);
|
||||
goto err_data;
|
||||
}
|
||||
}
|
||||
#else
|
||||
rc = register_ucsi_glink_notifier(&fsa_priv->nb);
|
||||
if (rc) {
|
||||
dev_err(fsa_priv->dev, "%s: ucsi glink notifier registration failed: %d\n",
|
||||
__func__, rc);
|
||||
goto err_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
mutex_init(&fsa_priv->notification_lock);
|
||||
i2c_set_clientdata(i2c, fsa_priv);
|
||||
@ -378,8 +814,40 @@ static int fsa4480_probe(struct i2c_client *i2c,
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&fsa_priv->fsa4480_notifier);
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
regmap_read(fsa_priv->regmap, ET7480_ID, ®_val);
|
||||
if (reg_val == DIO4480_ID_VALUE) {
|
||||
fsa_priv->dio4480 = true;
|
||||
pr_debug("%s audio switch use dio4480 reg_val is %x", __func__, reg_val);
|
||||
} else {
|
||||
fsa_priv->dio4480 = false;
|
||||
pr_debug("%s audio switch use et7480 reg_val is %x", __func__, reg_val);
|
||||
}
|
||||
|
||||
fsa_priv->typec_gpio = devm_gpiod_get_optional(fsa_priv->dev, "fsatypec",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(fsa_priv->typec_gpio)) {
|
||||
ret = PTR_ERR(fsa_priv->typec_gpio);
|
||||
fsa_priv->typec_gpio = NULL;
|
||||
if (ret == -EBUSY) {
|
||||
dev_info(fsa_priv->dev,
|
||||
"line busy\n");
|
||||
} else {
|
||||
dev_err(fsa_priv->dev,
|
||||
"Failed to get GPIO: %d\n", ret);
|
||||
goto err_data;
|
||||
}
|
||||
}
|
||||
if (fsa_priv->typec_gpio)
|
||||
gpiod_set_value_cansleep(fsa_priv->typec_gpio, 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
err_supply:
|
||||
power_supply_put(fsa_priv->usb_psy);
|
||||
#endif
|
||||
err_data:
|
||||
devm_kfree(&i2c->dev, fsa_priv);
|
||||
return rc;
|
||||
@ -393,7 +861,19 @@ static int fsa4480_remove(struct i2c_client *i2c)
|
||||
if (!fsa_priv)
|
||||
return -EINVAL;
|
||||
|
||||
unregister_ucsi_glink_notifier(&fsa_priv->ucsi_nb);
|
||||
#if IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
if (fsa_priv->use_powersupply == 2) {
|
||||
battmngr_notifier_unregister(&fsa_priv->nb);
|
||||
} else if (fsa_priv->use_powersupply == 1) {
|
||||
/* deregister from PMI */
|
||||
power_supply_unreg_notifier(&fsa_priv->nb);
|
||||
power_supply_put(fsa_priv->usb_psy);
|
||||
} else {
|
||||
unregister_ucsi_glink_notifier(&fsa_priv->nb);
|
||||
}
|
||||
#else
|
||||
unregister_ucsi_glink_notifier(&fsa_priv->nb);
|
||||
#endif
|
||||
fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
|
||||
cancel_work_sync(&fsa_priv->usbc_analog_work);
|
||||
pm_relax(fsa_priv->dev);
|
||||
@ -414,7 +894,9 @@ static struct i2c_driver fsa4480_i2c_driver = {
|
||||
.driver = {
|
||||
.name = FSA4480_I2C_NAME,
|
||||
.of_match_table = fsa4480_i2c_dt_match,
|
||||
#if !IS_ENABLED(CONFIG_XM_POWER_SUPPLY)
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
#endif
|
||||
},
|
||||
.probe = fsa4480_probe,
|
||||
.remove = fsa4480_remove,
|
||||
|
Loading…
Reference in New Issue
Block a user