mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
power: supply: bq25700: register otg vbus regulator
For Type-C PD driver using the tcpm framework and charger ic
(bq25700) output otg vbus solution. Because the dwc3 driver
cannot know whether the Type-C PD device sends DR_swap and
PR_swap messages, there are some problems with the charger ic
vbus control:
(1) rk3588s as sink, Type-C device sends DR_swap Message, u2phy driver
will send enable otg vbus notification to charger ic driver;
(2) After the Type-C device sends PR_swap Message to realize the
Sink->Source or Source->Sink switch, the charge ic driver cannot
dynamically enable or disable the otg vbus;
Based on the above problems, an otg vbus regulator is registered in
the charge ic driver for use by the fusb302 (Type-C PD controller chip)
driver, the otg vbus control is transferred to the tcpm framework.
In some cases (for example, the hardware does not have a PD chip),
in order to be compatible with switching from a lower version kernel
(kenrel-4.4/4.19) to a higher version kernel(kernel-5.10), dts will not
be modified. the software registration of the otg vbus regulator fails,
the vbus extcon mechanism will be registered.
Signed-off-by: Wang Jie <dave.wang@rock-chips.com>
Change-Id: I721abcb214795c0024e200b10ec3ab1d4a9b790a
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/usb/phy.h>
|
||||
@@ -194,6 +195,7 @@ struct bq25700_device {
|
||||
struct gpio_desc *typec1_discharge_io;
|
||||
struct gpio_desc *otg_mode_en_io;
|
||||
|
||||
struct regulator_dev *otg_vbus_reg;
|
||||
struct regmap *regmap;
|
||||
struct regmap_field *rmap_fields[F_MAX_FIELDS];
|
||||
int chip_id;
|
||||
@@ -1583,24 +1585,25 @@ static int bq25700_charger_evt_notifier1(struct notifier_block *nb,
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void bq25700_set_otg_vbus(struct bq25700_device *charger, bool enable)
|
||||
{
|
||||
DBG("OTG %s\n", enable ? "enable" : "disable");
|
||||
|
||||
if (!IS_ERR_OR_NULL(charger->otg_mode_en_io))
|
||||
gpiod_direction_output(charger->otg_mode_en_io, enable);
|
||||
bq25700_field_write(charger, EN_OTG, enable);
|
||||
}
|
||||
|
||||
static void bq25700_host_evt_worker(struct work_struct *work)
|
||||
{
|
||||
struct bq25700_device *charger =
|
||||
container_of(work, struct bq25700_device, host_work.work);
|
||||
struct extcon_dev *edev = charger->cable_edev;
|
||||
|
||||
/* Determine charger type */
|
||||
if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) {
|
||||
if (!IS_ERR_OR_NULL(charger->otg_mode_en_io))
|
||||
gpiod_direction_output(charger->otg_mode_en_io, 1);
|
||||
bq25700_field_write(charger, EN_OTG, 1);
|
||||
DBG("OTG enable\n");
|
||||
} else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) {
|
||||
if (!IS_ERR_OR_NULL(charger->otg_mode_en_io))
|
||||
gpiod_direction_output(charger->otg_mode_en_io, 0);
|
||||
bq25700_field_write(charger, EN_OTG, 0);
|
||||
DBG("OTG disable\n");
|
||||
}
|
||||
if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0)
|
||||
bq25700_set_otg_vbus(charger, true);
|
||||
else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0)
|
||||
bq25700_set_otg_vbus(charger, false);
|
||||
}
|
||||
|
||||
static void bq25700_host_evt_worker1(struct work_struct *work)
|
||||
@@ -1609,18 +1612,10 @@ static void bq25700_host_evt_worker1(struct work_struct *work)
|
||||
container_of(work, struct bq25700_device, host_work1.work);
|
||||
struct extcon_dev *edev = charger->cable_edev_1;
|
||||
|
||||
/* Determine charger type */
|
||||
if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) {
|
||||
if (!IS_ERR_OR_NULL(charger->otg_mode_en_io))
|
||||
gpiod_direction_output(charger->otg_mode_en_io, 1);
|
||||
bq25700_field_write(charger, EN_OTG, 1);
|
||||
DBG("OTG enable\n");
|
||||
} else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) {
|
||||
if (!IS_ERR_OR_NULL(charger->otg_mode_en_io))
|
||||
gpiod_direction_output(charger->otg_mode_en_io, 0);
|
||||
bq25700_field_write(charger, EN_OTG, 0);
|
||||
DBG("OTG disable\n");
|
||||
}
|
||||
if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0)
|
||||
bq25700_set_otg_vbus(charger, true);
|
||||
else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0)
|
||||
bq25700_set_otg_vbus(charger, false);
|
||||
}
|
||||
|
||||
static int bq25700_host_evt_notifier(struct notifier_block *nb,
|
||||
@@ -1943,6 +1938,77 @@ static int bq25700_register_host_nb(struct bq25700_device *charger)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq25700_otg_vbus_enable(struct regulator_dev *dev)
|
||||
{
|
||||
struct bq25700_device *charger = rdev_get_drvdata(dev);
|
||||
|
||||
bq25700_set_otg_vbus(charger, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq25700_otg_vbus_disable(struct regulator_dev *dev)
|
||||
{
|
||||
struct bq25700_device *charger = rdev_get_drvdata(dev);
|
||||
|
||||
bq25700_set_otg_vbus(charger, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq25700_otg_vbus_is_enabled(struct regulator_dev *dev)
|
||||
{
|
||||
struct bq25700_device *charger = rdev_get_drvdata(dev);
|
||||
u8 val;
|
||||
int gpio_status = 1;
|
||||
|
||||
val = bq25700_field_read(charger, EN_OTG);
|
||||
if (!IS_ERR_OR_NULL(charger->otg_mode_en_io))
|
||||
gpio_status = gpiod_get_value(charger->otg_mode_en_io);
|
||||
|
||||
return val && gpio_status ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct regulator_ops bq25700_otg_vbus_ops = {
|
||||
.enable = bq25700_otg_vbus_enable,
|
||||
.disable = bq25700_otg_vbus_disable,
|
||||
.is_enabled = bq25700_otg_vbus_is_enabled,
|
||||
};
|
||||
|
||||
static const struct regulator_desc bq25700_otg_vbus_desc = {
|
||||
.name = "otg-vbus",
|
||||
.of_match = "otg-vbus",
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.owner = THIS_MODULE,
|
||||
.ops = &bq25700_otg_vbus_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.fixed_uV = 5000000,
|
||||
.n_voltages = 1,
|
||||
};
|
||||
|
||||
static int bq25700_register_otg_vbus_regulator(struct bq25700_device *charger)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct regulator_config config = { };
|
||||
|
||||
np = of_get_child_by_name(charger->dev->of_node, "regulators");
|
||||
if (!np) {
|
||||
dev_warn(charger->dev, "cannot find regulators node\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
config.dev = charger->dev;
|
||||
config.driver_data = charger;
|
||||
|
||||
charger->otg_vbus_reg = devm_regulator_register(charger->dev,
|
||||
&bq25700_otg_vbus_desc,
|
||||
&config);
|
||||
if (IS_ERR(charger->otg_vbus_reg))
|
||||
return PTR_ERR(charger->otg_vbus_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long bq25700_init_usb(struct bq25700_device *charger)
|
||||
{
|
||||
struct extcon_dev *edev, *edev1;
|
||||
@@ -1976,18 +2042,27 @@ static long bq25700_init_usb(struct bq25700_device *charger)
|
||||
|
||||
if (!charger->pd_charge_only)
|
||||
bq25700_register_cg_nb(charger);
|
||||
bq25700_register_host_nb(charger);
|
||||
|
||||
if (bq25700_register_otg_vbus_regulator(charger) < 0) {
|
||||
dev_warn(charger->dev,
|
||||
"Cannot register otg vbus regulator\n");
|
||||
charger->otg_vbus_reg = NULL;
|
||||
bq25700_register_host_nb(charger);
|
||||
}
|
||||
|
||||
bq25700_register_discnt_nb(charger);
|
||||
bq25700_register_pd_nb(charger);
|
||||
|
||||
if (charger->cable_edev) {
|
||||
schedule_delayed_work(&charger->host_work, 0);
|
||||
if (!charger->otg_vbus_reg)
|
||||
schedule_delayed_work(&charger->host_work, 0);
|
||||
schedule_delayed_work(&charger->pd_work, 0);
|
||||
if (!charger->pd_charge_only)
|
||||
schedule_delayed_work(&charger->usb_work, 0);
|
||||
}
|
||||
if (charger->cable_edev_1) {
|
||||
schedule_delayed_work(&charger->host_work1, 0);
|
||||
if (!charger->otg_vbus_reg)
|
||||
schedule_delayed_work(&charger->host_work1, 0);
|
||||
schedule_delayed_work(&charger->pd_work1, 0);
|
||||
if (!charger->pd_charge_only)
|
||||
schedule_delayed_work(&charger->usb_work1, 0);
|
||||
|
||||
Reference in New Issue
Block a user