#include <linux/power_supply.h>
#include <linux/power/rk_usbbc.h>
#include <linux/regmap.h>
+#include <linux/rk_keys.h>
#include <linux/rtc.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#define DRIVER_VERSION "1.0"
-extern void rk_send_wakeup_key(void);
-
static const u16 chrg_vol_sel_array[] = {
4050, 4100, 4150, 4200, 4250, 4300, 4350
};
bool support_dc_det;
int virtual_power;
int sample_res;
+ int otg5v_suspend_enable;
bool extcon;
};
u8 chrg_input;
u8 chrg_current;
u8 res_div;
- u8 int_msk_reg2;
- u8 plug_in_irq;
- u8 plug_out_irq;
+ u8 sleep_set_off_reg1;
+ u8 plugin_trigger;
+ u8 plugout_trigger;
+ int plugin_irq;
+ int plugout_irq;
};
static int rk818_reg_read(struct rk818_charger *cg, u8 reg)
{
switch (state) {
case USB_OTG_POWER_ON:
- rk818_reg_set_bits(cg, RK818_INT_STS_MSK_REG2,
- PLUG_IN_MSK, PLUG_IN_MSK);
- rk818_reg_set_bits(cg, RK818_INT_STS_MSK_REG2,
- PLUG_OUT_MSK, PLUG_OUT_MSK);
- rk818_reg_set_bits(cg, RK818_DCDC_EN_REG,
- OTG_EN_MASK, OTG_EN_MASK);
+ if (cg->otg_in) {
+ CG_INFO("otg5v is on yet, ignore..\n");
+ } else {
+ cg->otg_in = 1;
+ disable_irq(cg->plugin_irq);
+ disable_irq(cg->plugout_irq);
+ rk818_reg_set_bits(cg, RK818_DCDC_EN_REG,
+ OTG_EN_MASK, OTG_EN_MASK);
+ CG_INFO("enable otg5v\n");
+ }
break;
case USB_OTG_POWER_OFF:
- rk818_reg_clear_bits(cg, RK818_INT_STS_MSK_REG2, PLUG_IN_MSK);
- rk818_reg_clear_bits(cg, RK818_INT_STS_MSK_REG2, PLUG_OUT_MSK);
- rk818_reg_clear_bits(cg, RK818_DCDC_EN_REG, OTG_EN_MASK);
+ if (!cg->otg_in) {
+ CG_INFO("otg5v is off yet, ignore..\n");
+ } else {
+ cg->otg_in = 0;
+ enable_irq(cg->plugin_irq);
+ enable_irq(cg->plugout_irq);
+ rk818_reg_clear_bits(cg, RK818_DCDC_EN_REG,
+ OTG_EN_MASK);
+ CG_INFO("disable otg5v\n");
+ }
break;
default:
dev_err(cg->dev, "error otg type\n");
CG_INFO("detect dc charger out..\n");
rk818_cg_set_chrg_param(cg, DC_TYPE_NONE_CHARGER);
/* check otg supply, power on anyway */
- if (cg->otg_in) {
- CG_INFO("disable charge, enable otg\n");
+ if (cg->otg_in)
rk818_cg_set_otg_state(cg, USB_OTG_POWER_ON);
- }
}
rk_send_wakeup_key();
rk818_cg_set_chrg_param(cg, USB_TYPE_CDP_CHARGER);
break;
case USB_OTG_POWER_ON:
- cg->otg_in = 1;
- if (cg->pdata->power_dc2otg && cg->dc_in) {
+ if (cg->pdata->power_dc2otg && cg->dc_in)
CG_INFO("otg power from dc adapter\n");
- } else {
+ else
rk818_cg_set_otg_state(cg, USB_OTG_POWER_ON);
- CG_INFO("disable charge, enable otg\n");
- }
break;
case USB_OTG_POWER_OFF:
- cg->otg_in = 0;
rk818_cg_set_otg_state(cg, USB_OTG_POWER_OFF);
- CG_INFO("enable charge, disable otg\n");
break;
default:
break;
struct rk818_charger *cg = container_of(work,
struct rk818_charger, irq_work.work);
- if (cg->plug_in_irq) {
+ if (cg->plugin_trigger) {
CG_INFO("pmic: plug in\n");
- cg->plug_in_irq = 0;
+ cg->plugin_trigger = 0;
rk_send_wakeup_key();
- } else if (cg->plug_out_irq) {
+ } else if (cg->plugout_trigger) {
CG_INFO("pmic: plug out\n");
- cg->plug_out_irq = 0;
+ cg->plugout_trigger = 0;
rk818_cg_set_chrg_param(cg, USB_TYPE_NONE_CHARGER);
rk818_cg_set_chrg_param(cg, DC_TYPE_NONE_CHARGER);
rk_send_wakeup_key();
struct rk818_charger *icg;
icg = (struct rk818_charger *)cg;
- icg->plug_in_irq = 1;
+ icg->plugin_trigger = 1;
queue_delayed_work(icg->usb_charger_wq, &icg->irq_work,
msecs_to_jiffies(10));
struct rk818_charger *icg;
icg = (struct rk818_charger *)cg;
- icg->plug_out_irq = 1;
+ icg->plugout_trigger = 1;
queue_delayed_work(icg->usb_charger_wq, &icg->irq_work,
msecs_to_jiffies(10));
return ret;
}
+ cg->plugin_irq = plug_in_irq;
+ cg->plugout_irq = plug_out_irq;
+
INIT_DELAYED_WORK(&cg->irq_work, rk818_cg_irq_delay_work);
return 0;
struct extcon_dev *edev = cg->cable_edev;
/* Determine cable/charger type */
- if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) > 0) {
+ if (extcon_get_cable_state_(edev, EXTCON_USB_VBUS_EN) > 0) {
CG_INFO("receive type-c notifier event: OTG ON...\n");
- cg->otg_in = 1;
- if (cg->dc_in && cg->pdata->power_dc2otg) {
+ if (cg->dc_in && cg->pdata->power_dc2otg)
CG_INFO("otg power from dc adapter\n");
- } else {
+ else
rk818_cg_set_otg_state(cg, USB_OTG_POWER_ON);
- CG_INFO("disable charge, enable otg\n");
- }
- } else if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == 0) {
+ } else if (extcon_get_cable_state_(edev, EXTCON_USB_VBUS_EN) == 0) {
CG_INFO("receive type-c notifier event: OTG OFF...\n");
- cg->otg_in = 0;
rk818_cg_set_otg_state(cg, USB_OTG_POWER_OFF);
- CG_INFO("enble charge, disable otg\n");
}
rk818_cg_pr_info(cg);
if (charger != USB_TYPE_UNKNOWN_CHARGER) {
CG_INFO("receive type-c notifier event: %s...\n",
event[charger]);
+ cg->usb_charger = charger;
rk818_cg_set_chrg_param(cg, charger);
rk818_cg_pr_info(cg);
}
/* Register host */
INIT_DELAYED_WORK(&cg->host_work, rk818_cg_host_evt_worker);
cg->cable_host_nb.notifier_call = rk818_cg_host_evt_notifier;
- ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
+ ret = extcon_register_notifier(edev, EXTCON_USB_VBUS_EN,
&cg->cable_host_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for HOST\n");
&cg->cable_cg_nb);
extcon_unregister_notifier(edev, EXTCON_CHG_USB_CDP,
&cg->cable_cg_nb);
- extcon_unregister_notifier(edev, EXTCON_USB_HOST,
+ extcon_unregister_notifier(edev, EXTCON_USB_VBUS_EN,
&cg->cable_host_nb);
return ret;
}
cg->cable_edev = edev;
+ schedule_delayed_work(&cg->host_work, 0);
+ schedule_delayed_work(&cg->usb_work, 0);
+
CG_INFO("register typec extcon evt notifier\n");
} else {
INIT_DELAYED_WORK(&cg->usb_work, rk818_cg_bc_evt_worker);
dev_err(dev, "sample_res missing!\n");
}
+ ret = of_property_read_u32(np, "otg5v_suspend_enable",
+ &pdata->otg5v_suspend_enable);
+ if (ret < 0) {
+ pdata->otg5v_suspend_enable = 1;
+ dev_err(dev, "otg5v_suspend_enable missing!\n");
+ }
+
if (!is_battery_exist(cg))
pdata->virtual_power = 1;
return ret;
}
-static int rk818_charger_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- struct rk818_charger *cg = platform_get_drvdata(pdev);
-
- if (cg->otg_in && cg->dc_in) {
- cg->int_msk_reg2 = rk818_reg_read(cg, RK818_INT_STS_MSK_REG2);
- rk818_reg_set_bits(cg, RK818_INT_STS_MSK_REG2,
- CHRG_CVTLMT_INT_MSK, CHRG_CVTLMT_INT_MSK);
- }
-
- return 0;
-}
-
-static int rk818_charger_resume(struct platform_device *pdev)
-{
- struct rk818_charger *cg = platform_get_drvdata(pdev);
-
- if (cg->otg_in && cg->dc_in)
- rk818_reg_write(cg, RK818_INT_STS_MSK_REG2, cg->int_msk_reg2);
-
- return 0;
-}
-
static void rk818_charger_shutdown(struct platform_device *pdev)
{
struct rk818_charger *cg = platform_get_drvdata(pdev);
&cg->cable_cg_nb);
extcon_unregister_notifier(cg->cable_edev, EXTCON_CHG_USB_CDP,
&cg->cable_cg_nb);
- extcon_unregister_notifier(cg->cable_edev, EXTCON_USB_HOST,
+ extcon_unregister_notifier(cg->cable_edev, EXTCON_USB_VBUS_EN,
&cg->cable_host_nb);
extcon_unregister_notifier(cg->cable_edev, EXTCON_USB,
&cg->cable_discnt_nb);
cg->ac_in, cg->usb_in, cg->dc_in, cg->otg_in);
}
+static int rk818_charger_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct rk818_charger *cg = platform_get_drvdata(pdev);
+
+ cg->sleep_set_off_reg1 = rk818_reg_read(cg, RK818_SLEEP_SET_OFF_REG1);
+
+ /* enable sleep boost5v and otg5v */
+ if (cg->pdata->otg5v_suspend_enable) {
+ if ((cg->otg_in && !cg->dc_in) ||
+ (cg->otg_in && cg->dc_in && !cg->pdata->power_dc2otg)) {
+ rk818_reg_clear_bits(cg, RK818_SLEEP_SET_OFF_REG1,
+ OTG_BOOST_SLP_OFF);
+ CG_INFO("suspend: otg 5v on\n");
+ return 0;
+ }
+ }
+
+ /* disable sleep otg5v */
+ rk818_reg_set_bits(cg, RK818_SLEEP_SET_OFF_REG1,
+ OTG_SLP_SET_OFF, OTG_SLP_SET_OFF);
+ CG_INFO("suspend: otg 5v off\n");
+
+ return 0;
+}
+
+static int rk818_charger_resume(struct platform_device *pdev)
+{
+ struct rk818_charger *cg = platform_get_drvdata(pdev);
+
+ /* resume sleep boost5v and otg5v */
+ rk818_reg_set_bits(cg, RK818_SLEEP_SET_OFF_REG1,
+ OTG_BOOST_SLP_OFF, cg->sleep_set_off_reg1);
+
+ return 0;
+}
+
static struct platform_driver rk818_charger_driver = {
.probe = rk818_charger_probe,
.suspend = rk818_charger_suspend,