13d0407baSopenharmony_ci/*
23d0407baSopenharmony_ci * rk817 charger driver
33d0407baSopenharmony_ci *
43d0407baSopenharmony_ci * Copyright (C) 2018 Rockchip Electronics Co., Ltd
53d0407baSopenharmony_ci * xsf <xsf@rock-chips.com>
63d0407baSopenharmony_ci *
73d0407baSopenharmony_ci * This program is free software; you can redistribute it and/or modify it
83d0407baSopenharmony_ci * under the terms and conditions of the GNU General Public License,
93d0407baSopenharmony_ci * version 2, as published by the Free Software Foundation.
103d0407baSopenharmony_ci *
113d0407baSopenharmony_ci * This program is distributed in the hope it will be useful, but WITHOUT
123d0407baSopenharmony_ci * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
133d0407baSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
143d0407baSopenharmony_ci * more details.
153d0407baSopenharmony_ci *
163d0407baSopenharmony_ci */
173d0407baSopenharmony_ci
183d0407baSopenharmony_ci#include <linux/delay.h>
193d0407baSopenharmony_ci#include <linux/extcon.h>
203d0407baSopenharmony_ci#include <linux/gpio.h>
213d0407baSopenharmony_ci#include <linux/iio/consumer.h>
223d0407baSopenharmony_ci#include <linux/iio/iio.h>
233d0407baSopenharmony_ci#include <linux/irq.h>
243d0407baSopenharmony_ci#include <linux/jiffies.h>
253d0407baSopenharmony_ci#include <linux/mfd/rk808.h>
263d0407baSopenharmony_ci#include <linux/module.h>
273d0407baSopenharmony_ci#include <linux/of_device.h>
283d0407baSopenharmony_ci#include <linux/of_gpio.h>
293d0407baSopenharmony_ci#include <linux/platform_device.h>
303d0407baSopenharmony_ci#include <linux/power_supply.h>
313d0407baSopenharmony_ci#include <linux/power/rk_usbbc.h>
323d0407baSopenharmony_ci#include <linux/regmap.h>
333d0407baSopenharmony_ci#include <linux/rtc.h>
343d0407baSopenharmony_ci#include <linux/timer.h>
353d0407baSopenharmony_ci#include <linux/workqueue.h>
363d0407baSopenharmony_ci
373d0407baSopenharmony_cistatic int dbg_enable;
383d0407baSopenharmony_cimodule_param_named(dbg_level, dbg_enable, int, 0644);
393d0407baSopenharmony_ci
403d0407baSopenharmony_ci#define DBG(args...) \
413d0407baSopenharmony_ci	do { \
423d0407baSopenharmony_ci		if (dbg_enable) { \
433d0407baSopenharmony_ci			pr_info(args); \
443d0407baSopenharmony_ci		} \
453d0407baSopenharmony_ci	} while (0)
463d0407baSopenharmony_ci
473d0407baSopenharmony_ci#define CHARGE_DRIVER_VERSION		"1.0"
483d0407baSopenharmony_ci
493d0407baSopenharmony_ci#define DISABLE	0x00
503d0407baSopenharmony_ci#define ENABLE	0x01
513d0407baSopenharmony_ci#define OTG_SLP_ENABLE	0x01
523d0407baSopenharmony_ci#define OTG_SLP_DISABLE	0x00
533d0407baSopenharmony_ci#define OTG_ENABLE		0x11
543d0407baSopenharmony_ci#define OTG_DISABLE		0x10
553d0407baSopenharmony_ci#define RK817_BOOST_ENABLE	0x11
563d0407baSopenharmony_ci#define RK817_BOOST_DISABLE	0x10
573d0407baSopenharmony_ci#define OTG_MODE		0x01
583d0407baSopenharmony_ci#define OTG_MODE_ON		0x01
593d0407baSopenharmony_ci#define DEFAULT_INPUT_VOLTAGE	4500
603d0407baSopenharmony_ci#define DEFAULT_INPUT_CURRENT	2000
613d0407baSopenharmony_ci#define DEFAULT_CHRG_VOLTAGE	4200
623d0407baSopenharmony_ci#define DEFAULT_CHRG_CURRENT	1400
633d0407baSopenharmony_ci#define DEFAULT_CHRG_TERM_MODE	1
643d0407baSopenharmony_ci#define DEFAULT_CHRG_TERM_CUR		150
653d0407baSopenharmony_ci#define SAMPLE_RES_10MR		10
663d0407baSopenharmony_ci#define SAMPLE_RES_20MR		20
673d0407baSopenharmony_ci#define SAMPLE_RES_DIV1		1
683d0407baSopenharmony_ci#define SAMPLE_RES_DIV2		2
693d0407baSopenharmony_ci
703d0407baSopenharmony_ci#define INPUT_450MA		450
713d0407baSopenharmony_ci#define INPUT_1500MA	1500
723d0407baSopenharmony_ci
733d0407baSopenharmony_ci#define CURRENT_TO_ADC(current, samp_res)	\
743d0407baSopenharmony_ci	(current * 1000 * samp_res / 172)
753d0407baSopenharmony_ci
763d0407baSopenharmony_cienum charge_current {
773d0407baSopenharmony_ci	CHRG_CUR_1000MA,
783d0407baSopenharmony_ci	CHRG_CUR_1500MA,
793d0407baSopenharmony_ci	CHRG_CUR_2000MA,
803d0407baSopenharmony_ci	CHRG_CUR_2500MA,
813d0407baSopenharmony_ci	CHRG_CUR_2750MA,
823d0407baSopenharmony_ci	CHRG_CUR_3000MA,
833d0407baSopenharmony_ci	CHRG_CUR_3500MA,
843d0407baSopenharmony_ci	CHRG_CUR_500MA,
853d0407baSopenharmony_ci};
863d0407baSopenharmony_ci
873d0407baSopenharmony_cienum charge_voltage {
883d0407baSopenharmony_ci	CHRG_VOL_4100MV,
893d0407baSopenharmony_ci	CHRG_VOL_4150MV,
903d0407baSopenharmony_ci	CHRG_VOL_4200MV,
913d0407baSopenharmony_ci	CHRG_VOL_4250MV,
923d0407baSopenharmony_ci	CHRG_VOL_4300MV,
933d0407baSopenharmony_ci	CHRG_VOL_4350MV,
943d0407baSopenharmony_ci	CHRG_VOL_4400MV,
953d0407baSopenharmony_ci	CHRG_VOL_4450MV,
963d0407baSopenharmony_ci};
973d0407baSopenharmony_ci
983d0407baSopenharmony_cienum input_voltage {
993d0407baSopenharmony_ci	INPUT_VOL_4000MV,
1003d0407baSopenharmony_ci	INPUT_VOL_4100MV,
1013d0407baSopenharmony_ci	INPUT_VOL_4200MV,
1023d0407baSopenharmony_ci	INPUT_VOL_4300MV,
1033d0407baSopenharmony_ci	INPUT_VOL_4400MV,
1043d0407baSopenharmony_ci	INPUT_VOL_4500MV,
1053d0407baSopenharmony_ci	INPUT_VOL_4600MV,
1063d0407baSopenharmony_ci	INPUT_VOL_4700MV,
1073d0407baSopenharmony_ci};
1083d0407baSopenharmony_ci
1093d0407baSopenharmony_cienum input_current {
1103d0407baSopenharmony_ci	INPUT_CUR_450MA,
1113d0407baSopenharmony_ci	INPUT_CUR_80MA,
1123d0407baSopenharmony_ci	INPUT_CUR_850MA,
1133d0407baSopenharmony_ci	INPUT_CUR_1500MA,
1143d0407baSopenharmony_ci	INPUT_CUR_1750MA,
1153d0407baSopenharmony_ci	INPUT_CUR_2000MA,
1163d0407baSopenharmony_ci	INPUT_CUR_2500MA,
1173d0407baSopenharmony_ci	INPUT_CUR_3000MA,
1183d0407baSopenharmony_ci};
1193d0407baSopenharmony_ci
1203d0407baSopenharmony_cienum charge_clk {
1213d0407baSopenharmony_ci	CHRG_CLK_1M,
1223d0407baSopenharmony_ci	CHRG_CLK_2M,
1233d0407baSopenharmony_ci};
1243d0407baSopenharmony_ci
1253d0407baSopenharmony_cienum charge_term_sel {
1263d0407baSopenharmony_ci	CHRG_TERM_150MA,
1273d0407baSopenharmony_ci	CHRG_TERM_200MA,
1283d0407baSopenharmony_ci	CHRG_TERM_300MA,
1293d0407baSopenharmony_ci	CHRG_TERM_400MA,
1303d0407baSopenharmony_ci};
1313d0407baSopenharmony_ci
1323d0407baSopenharmony_cienum charge_timer_trickle {
1333d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_30MIN,
1343d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_45MIN,
1353d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_60MIN,
1363d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_90MIN,
1373d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_120MIN,
1383d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_150MIN,
1393d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_180MIN,
1403d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_210MIN,
1413d0407baSopenharmony_ci};
1423d0407baSopenharmony_ci
1433d0407baSopenharmony_cienum charge_timer_cccv {
1443d0407baSopenharmony_ci	CHRG_TIMER_CCCV_4H,
1453d0407baSopenharmony_ci	CHRG_TIMER_CCCV_5H,
1463d0407baSopenharmony_ci	CHRG_TIMER_CCCV_6H,
1473d0407baSopenharmony_ci	CHRG_TIMER_CCCV_8H,
1483d0407baSopenharmony_ci	CHRG_TIMER_CCCV_10H,
1493d0407baSopenharmony_ci	CHRG_TIMER_CCCV_12H,
1503d0407baSopenharmony_ci	CHRG_TIMER_CCCV_14H,
1513d0407baSopenharmony_ci	CHRG_TIMER_CCCV_16H,
1523d0407baSopenharmony_ci};
1533d0407baSopenharmony_ci
1543d0407baSopenharmony_cienum charge_status {
1553d0407baSopenharmony_ci	CHRG_OFF,
1563d0407baSopenharmony_ci	DEAD_CHRG,
1573d0407baSopenharmony_ci	TRICKLE_CHRG,
1583d0407baSopenharmony_ci	CC_OR_CV_CHRG,
1593d0407baSopenharmony_ci	CHRG_TERM,
1603d0407baSopenharmony_ci	USB_OVER_VOL,
1613d0407baSopenharmony_ci	BAT_TMP_ERR,
1623d0407baSopenharmony_ci	BAT_TIM_ERR,
1633d0407baSopenharmony_ci};
1643d0407baSopenharmony_ci
1653d0407baSopenharmony_cienum discharge_ilimit {
1663d0407baSopenharmony_ci	DISCHRG_2000MA,
1673d0407baSopenharmony_ci	DISCHRG_2500MA,
1683d0407baSopenharmony_ci	DISCHRG_3000MA,
1693d0407baSopenharmony_ci	DISCHRG_3500MA,
1703d0407baSopenharmony_ci	DISCHRG_4000MA,
1713d0407baSopenharmony_ci};
1723d0407baSopenharmony_ci
1733d0407baSopenharmony_cienum bat_system_comp_time {
1743d0407baSopenharmony_ci	DLY_20US,
1753d0407baSopenharmony_ci	DLY_10US,
1763d0407baSopenharmony_ci	DLY_40US,
1773d0407baSopenharmony_ci	DLY_20US_AGAIN,
1783d0407baSopenharmony_ci};
1793d0407baSopenharmony_ci
1803d0407baSopenharmony_cienum charge_term_mode {
1813d0407baSopenharmony_ci	CHRG_ANALOG,
1823d0407baSopenharmony_ci	CHRG_DIGITAL,
1833d0407baSopenharmony_ci};
1843d0407baSopenharmony_ci
1853d0407baSopenharmony_cienum charger_t {
1863d0407baSopenharmony_ci	USB_TYPE_UNKNOWN_CHARGER,
1873d0407baSopenharmony_ci	USB_TYPE_NONE_CHARGER,
1883d0407baSopenharmony_ci	USB_TYPE_USB_CHARGER,
1893d0407baSopenharmony_ci	USB_TYPE_AC_CHARGER,
1903d0407baSopenharmony_ci	USB_TYPE_CDP_CHARGER,
1913d0407baSopenharmony_ci	DC_TYPE_DC_CHARGER,
1923d0407baSopenharmony_ci	DC_TYPE_NONE_CHARGER,
1933d0407baSopenharmony_ci};
1943d0407baSopenharmony_ci
1953d0407baSopenharmony_cienum charger_state {
1963d0407baSopenharmony_ci	OFFLINE = 0,
1973d0407baSopenharmony_ci	ONLINE
1983d0407baSopenharmony_ci};
1993d0407baSopenharmony_ci
2003d0407baSopenharmony_cienum rk817_charge_fields {
2013d0407baSopenharmony_ci	BOOST_EN, OTG_EN, OTG_SLP_EN, CHRG_CLK_SEL,
2023d0407baSopenharmony_ci	CHRG_EN, CHRG_VOL_SEL, CHRG_CT_EN, CHRG_CUR_SEL,
2033d0407baSopenharmony_ci	USB_VLIM_EN, USB_VLIM_SEL, USB_ILIM_EN, USB_ILIM_SEL,
2043d0407baSopenharmony_ci	SYS_CAN_SD,  USB_SYS_EN, BAT_OVP_EN, CHRG_TERM_ANA_DIG,
2053d0407baSopenharmony_ci	CHRG_TERM_ANA_SEL,
2063d0407baSopenharmony_ci	CHRG_TERM_DIG,
2073d0407baSopenharmony_ci	BAT_HTS_TS, BAT_LTS_TS,
2083d0407baSopenharmony_ci	CHRG_TIMER_TRIKL_EN, CHRG_TIMER_TRIKL,
2093d0407baSopenharmony_ci	CHRG_TIMER_CCCV_EN, CHRG_TIMER_CCCV,
2103d0407baSopenharmony_ci	BAT_EXS, CHG_STS, BAT_OVP_STS, CHRG_IN_CLAMP,
2113d0407baSopenharmony_ci	USB_EXS, USB_EFF,
2123d0407baSopenharmony_ci	BAT_DIS_ILIM_STS, BAT_SYS_CMP_DLY, BAT_DIS_ILIM_EN,
2133d0407baSopenharmony_ci	BAT_DISCHRG_ILIM,
2143d0407baSopenharmony_ci	PLUG_IN_STS, SOC_REG0, SOC_REG1, SOC_REG2,
2153d0407baSopenharmony_ci	F_MAX_FIELDS
2163d0407baSopenharmony_ci};
2173d0407baSopenharmony_ci
2183d0407baSopenharmony_cistatic const struct reg_field rk817_charge_reg_fields[] = {
2193d0407baSopenharmony_ci	[SOC_REG0] = REG_FIELD(0x9A, 0, 7),
2203d0407baSopenharmony_ci	[SOC_REG1] = REG_FIELD(0x9B, 0, 7),
2213d0407baSopenharmony_ci	[SOC_REG2] = REG_FIELD(0x9C, 0, 7),
2223d0407baSopenharmony_ci	[BOOST_EN] = REG_FIELD(0xB4, 1, 5),
2233d0407baSopenharmony_ci	[OTG_EN] = REG_FIELD(0xB4, 2, 6),
2243d0407baSopenharmony_ci	[OTG_SLP_EN] = REG_FIELD(0xB5, 6, 6),
2253d0407baSopenharmony_ci	[CHRG_EN] = REG_FIELD(0xE4, 7, 7),
2263d0407baSopenharmony_ci	[CHRG_VOL_SEL] = REG_FIELD(0xE4, 4, 6),
2273d0407baSopenharmony_ci	[CHRG_CT_EN] = REG_FIELD(0xE4, 3, 3),
2283d0407baSopenharmony_ci	[CHRG_CUR_SEL] = REG_FIELD(0xE4, 0, 2),
2293d0407baSopenharmony_ci
2303d0407baSopenharmony_ci	[USB_VLIM_EN] = REG_FIELD(0xE5, 7, 7),
2313d0407baSopenharmony_ci	[USB_VLIM_SEL] = REG_FIELD(0xE5, 4, 6),
2323d0407baSopenharmony_ci	[USB_ILIM_EN] = REG_FIELD(0xE5, 3, 3),
2333d0407baSopenharmony_ci	[USB_ILIM_SEL] = REG_FIELD(0xE5, 0, 2),
2343d0407baSopenharmony_ci
2353d0407baSopenharmony_ci	[SYS_CAN_SD] = REG_FIELD(0xE6, 7, 7),
2363d0407baSopenharmony_ci	[USB_SYS_EN] = REG_FIELD(0xE6, 6, 6),
2373d0407baSopenharmony_ci	[BAT_OVP_EN] = REG_FIELD(0xE6, 3, 3),
2383d0407baSopenharmony_ci	[CHRG_TERM_ANA_DIG] = REG_FIELD(0xE6, 2, 2),
2393d0407baSopenharmony_ci	[CHRG_TERM_ANA_SEL] = REG_FIELD(0xE6, 0, 1),
2403d0407baSopenharmony_ci
2413d0407baSopenharmony_ci	[CHRG_TERM_DIG] = REG_FIELD(0xE7, 0, 7),
2423d0407baSopenharmony_ci
2433d0407baSopenharmony_ci	[BAT_HTS_TS] = REG_FIELD(0xE8, 0, 7),
2443d0407baSopenharmony_ci
2453d0407baSopenharmony_ci	[BAT_LTS_TS] = REG_FIELD(0xE9, 0, 7),
2463d0407baSopenharmony_ci
2473d0407baSopenharmony_ci	[CHRG_TIMER_TRIKL_EN] = REG_FIELD(0xEA, 7, 7),
2483d0407baSopenharmony_ci	[CHRG_TIMER_TRIKL] = REG_FIELD(0xEA, 4, 6),
2493d0407baSopenharmony_ci	[CHRG_TIMER_CCCV_EN] = REG_FIELD(0xEA, 3, 3),
2503d0407baSopenharmony_ci	[CHRG_TIMER_CCCV] = REG_FIELD(0xEA, 0, 2),
2513d0407baSopenharmony_ci
2523d0407baSopenharmony_ci	[BAT_EXS] = REG_FIELD(0xEB, 7, 7),
2533d0407baSopenharmony_ci	[CHG_STS] = REG_FIELD(0xEB, 4, 6),
2543d0407baSopenharmony_ci	[BAT_OVP_STS] = REG_FIELD(0xEB, 3, 3),
2553d0407baSopenharmony_ci	[CHRG_IN_CLAMP] = REG_FIELD(0xEB, 2, 2),
2563d0407baSopenharmony_ci	[USB_EXS] = REG_FIELD(0xEB, 1, 1),
2573d0407baSopenharmony_ci	[USB_EFF] = REG_FIELD(0xEB, 0, 0),
2583d0407baSopenharmony_ci
2593d0407baSopenharmony_ci	[BAT_DIS_ILIM_STS] = REG_FIELD(0xEC, 6, 6),
2603d0407baSopenharmony_ci	[BAT_SYS_CMP_DLY] = REG_FIELD(0xEC, 4, 5),
2613d0407baSopenharmony_ci	[BAT_DIS_ILIM_EN] = REG_FIELD(0xEC, 3, 3),
2623d0407baSopenharmony_ci	[BAT_DISCHRG_ILIM] = REG_FIELD(0xEC, 0, 2),
2633d0407baSopenharmony_ci	[PLUG_IN_STS] = REG_FIELD(0xf0, 6, 6),
2643d0407baSopenharmony_ci	[CHRG_CLK_SEL] = REG_FIELD(0xF3, 6, 6),
2653d0407baSopenharmony_ci};
2663d0407baSopenharmony_ci
2673d0407baSopenharmony_cistruct charger_platform_data {
2683d0407baSopenharmony_ci	u32 max_input_current;
2693d0407baSopenharmony_ci	u32 min_input_voltage;
2703d0407baSopenharmony_ci
2713d0407baSopenharmony_ci	u32 max_chrg_current;
2723d0407baSopenharmony_ci	u32 max_chrg_voltage;
2733d0407baSopenharmony_ci
2743d0407baSopenharmony_ci	u32 chrg_finish_cur;
2753d0407baSopenharmony_ci	u32 chrg_term_mode;
2763d0407baSopenharmony_ci
2773d0407baSopenharmony_ci	u32 power_dc2otg;
2783d0407baSopenharmony_ci	u32 dc_det_level;
2793d0407baSopenharmony_ci	int dc_det_pin;
2803d0407baSopenharmony_ci	bool support_dc_det;
2813d0407baSopenharmony_ci	int virtual_power;
2823d0407baSopenharmony_ci	int sample_res;
2833d0407baSopenharmony_ci	int otg5v_suspend_enable;
2843d0407baSopenharmony_ci	bool extcon;
2853d0407baSopenharmony_ci	int gate_function_disable;
2863d0407baSopenharmony_ci};
2873d0407baSopenharmony_ci
2883d0407baSopenharmony_cistruct rk817_charger {
2893d0407baSopenharmony_ci	struct i2c_client *client;
2903d0407baSopenharmony_ci	struct platform_device *pdev;
2913d0407baSopenharmony_ci	struct device *dev;
2923d0407baSopenharmony_ci	struct rk808 *rk817;
2933d0407baSopenharmony_ci	struct regmap *regmap;
2943d0407baSopenharmony_ci	struct regmap_field *rmap_fields[F_MAX_FIELDS];
2953d0407baSopenharmony_ci
2963d0407baSopenharmony_ci	struct power_supply *ac_psy;
2973d0407baSopenharmony_ci	struct power_supply *usb_psy;
2983d0407baSopenharmony_ci	struct extcon_dev *cable_edev;
2993d0407baSopenharmony_ci	struct charger_platform_data *pdata;
3003d0407baSopenharmony_ci	struct workqueue_struct *usb_charger_wq;
3013d0407baSopenharmony_ci	struct workqueue_struct *dc_charger_wq;
3023d0407baSopenharmony_ci	struct delayed_work dc_work;
3033d0407baSopenharmony_ci	struct delayed_work usb_work;
3043d0407baSopenharmony_ci	struct delayed_work host_work;
3053d0407baSopenharmony_ci	struct delayed_work discnt_work;
3063d0407baSopenharmony_ci	struct delayed_work irq_work;
3073d0407baSopenharmony_ci	struct notifier_block bc_nb;
3083d0407baSopenharmony_ci	struct notifier_block cable_cg_nb;
3093d0407baSopenharmony_ci	struct notifier_block cable_host_nb;
3103d0407baSopenharmony_ci	struct notifier_block cable_discnt_nb;
3113d0407baSopenharmony_ci	unsigned int bc_event;
3123d0407baSopenharmony_ci	enum charger_t usb_charger;
3133d0407baSopenharmony_ci	enum charger_t dc_charger;
3143d0407baSopenharmony_ci	struct regulator *otg5v_rdev;
3153d0407baSopenharmony_ci	u8 ac_in;
3163d0407baSopenharmony_ci	u8 usb_in;
3173d0407baSopenharmony_ci	u8 otg_in;
3183d0407baSopenharmony_ci	u8 dc_in;
3193d0407baSopenharmony_ci	u8 prop_status;
3203d0407baSopenharmony_ci
3213d0407baSopenharmony_ci	u32 max_input_current;
3223d0407baSopenharmony_ci	u32 min_input_voltage;
3233d0407baSopenharmony_ci
3243d0407baSopenharmony_ci	u32 max_chrg_current;
3253d0407baSopenharmony_ci	u32 max_chrg_voltage;
3263d0407baSopenharmony_ci
3273d0407baSopenharmony_ci	u32 chrg_finish_cur;
3283d0407baSopenharmony_ci	u32 chrg_term_mode;
3293d0407baSopenharmony_ci
3303d0407baSopenharmony_ci	u8 res_div;
3313d0407baSopenharmony_ci	u8 otg_slp_state;
3323d0407baSopenharmony_ci	u8 plugin_trigger;
3333d0407baSopenharmony_ci	u8 plugout_trigger;
3343d0407baSopenharmony_ci	int plugin_irq;
3353d0407baSopenharmony_ci	int plugout_irq;
3363d0407baSopenharmony_ci};
3373d0407baSopenharmony_ci
3383d0407baSopenharmony_cistatic enum power_supply_property rk817_ac_props[] = {
3393d0407baSopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
3403d0407baSopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
3413d0407baSopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MAX,
3423d0407baSopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_MAX,
3433d0407baSopenharmony_ci};
3443d0407baSopenharmony_ci
3453d0407baSopenharmony_cistatic enum power_supply_property rk817_usb_props[] = {
3463d0407baSopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
3473d0407baSopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
3483d0407baSopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MAX,
3493d0407baSopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_MAX,
3503d0407baSopenharmony_ci};
3513d0407baSopenharmony_ci
3523d0407baSopenharmony_cistatic int rk817_charge_ac_get_property(struct power_supply *psy,
3533d0407baSopenharmony_ci					enum power_supply_property psp,
3543d0407baSopenharmony_ci					union power_supply_propval *val)
3553d0407baSopenharmony_ci{
3563d0407baSopenharmony_ci	struct rk817_charger *charge = power_supply_get_drvdata(psy);
3573d0407baSopenharmony_ci	int ret = 0;
3583d0407baSopenharmony_ci
3593d0407baSopenharmony_ci	switch (psp) {
3603d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
3613d0407baSopenharmony_ci		if (charge->pdata->virtual_power)
3623d0407baSopenharmony_ci			val->intval = 1;
3633d0407baSopenharmony_ci		else
3643d0407baSopenharmony_ci			val->intval = (charge->ac_in | charge->dc_in);
3653d0407baSopenharmony_ci
3663d0407baSopenharmony_ci		DBG("ac report online: %d\n", val->intval);
3673d0407baSopenharmony_ci		break;
3683d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_STATUS:
3693d0407baSopenharmony_ci		if (charge->pdata->virtual_power)
3703d0407baSopenharmony_ci			val->intval = POWER_SUPPLY_STATUS_CHARGING;
3713d0407baSopenharmony_ci		else
3723d0407baSopenharmony_ci			val->intval = charge->prop_status;
3733d0407baSopenharmony_ci
3743d0407baSopenharmony_ci		DBG("report prop: %d\n", val->intval);
3753d0407baSopenharmony_ci		break;
3763d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
3773d0407baSopenharmony_ci		val->intval = charge->max_chrg_voltage * 1000;	/* uV */
3783d0407baSopenharmony_ci		break;
3793d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_MAX:
3803d0407baSopenharmony_ci		val->intval = charge->max_chrg_current * 1000;	/* uA */
3813d0407baSopenharmony_ci		break;
3823d0407baSopenharmony_ci	default:
3833d0407baSopenharmony_ci		ret = -EINVAL;
3843d0407baSopenharmony_ci		break;
3853d0407baSopenharmony_ci	}
3863d0407baSopenharmony_ci
3873d0407baSopenharmony_ci	return ret;
3883d0407baSopenharmony_ci}
3893d0407baSopenharmony_ci
3903d0407baSopenharmony_cistatic int rk817_charge_usb_get_property(struct power_supply *psy,
3913d0407baSopenharmony_ci					 enum power_supply_property psp,
3923d0407baSopenharmony_ci					 union power_supply_propval *val)
3933d0407baSopenharmony_ci{
3943d0407baSopenharmony_ci	struct rk817_charger *charge = power_supply_get_drvdata(psy);
3953d0407baSopenharmony_ci	int ret = 0;
3963d0407baSopenharmony_ci
3973d0407baSopenharmony_ci	switch (psp) {
3983d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
3993d0407baSopenharmony_ci		if (charge->pdata->virtual_power)
4003d0407baSopenharmony_ci			val->intval = 1;
4013d0407baSopenharmony_ci		else
4023d0407baSopenharmony_ci			val->intval = charge->usb_in;
4033d0407baSopenharmony_ci
4043d0407baSopenharmony_ci		DBG("usb report online: %d\n", val->intval);
4053d0407baSopenharmony_ci		break;
4063d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_STATUS:
4073d0407baSopenharmony_ci		if (charge->pdata->virtual_power)
4083d0407baSopenharmony_ci			val->intval = POWER_SUPPLY_STATUS_CHARGING;
4093d0407baSopenharmony_ci		else
4103d0407baSopenharmony_ci			val->intval = charge->prop_status;
4113d0407baSopenharmony_ci
4123d0407baSopenharmony_ci		DBG("report prop: %d\n", val->intval);
4133d0407baSopenharmony_ci		break;
4143d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
4153d0407baSopenharmony_ci		val->intval = charge->max_chrg_voltage;
4163d0407baSopenharmony_ci		break;
4173d0407baSopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_MAX:
4183d0407baSopenharmony_ci		val->intval = charge->max_chrg_current;
4193d0407baSopenharmony_ci		break;
4203d0407baSopenharmony_ci	default:
4213d0407baSopenharmony_ci		ret = -EINVAL;
4223d0407baSopenharmony_ci		break;
4233d0407baSopenharmony_ci	}
4243d0407baSopenharmony_ci
4253d0407baSopenharmony_ci	return ret;
4263d0407baSopenharmony_ci}
4273d0407baSopenharmony_ci
4283d0407baSopenharmony_cistatic const struct power_supply_desc rk817_ac_desc = {
4293d0407baSopenharmony_ci	.name		= "ac",
4303d0407baSopenharmony_ci	.type		= POWER_SUPPLY_TYPE_MAINS,
4313d0407baSopenharmony_ci	.properties	= rk817_ac_props,
4323d0407baSopenharmony_ci	.num_properties	= ARRAY_SIZE(rk817_ac_props),
4333d0407baSopenharmony_ci	.get_property	= rk817_charge_ac_get_property,
4343d0407baSopenharmony_ci};
4353d0407baSopenharmony_ci
4363d0407baSopenharmony_cistatic const struct power_supply_desc rk817_usb_desc = {
4373d0407baSopenharmony_ci	.name		= "usb",
4383d0407baSopenharmony_ci	.type		= POWER_SUPPLY_TYPE_USB,
4393d0407baSopenharmony_ci	.properties	= rk817_usb_props,
4403d0407baSopenharmony_ci	.num_properties	= ARRAY_SIZE(rk817_usb_props),
4413d0407baSopenharmony_ci	.get_property	= rk817_charge_usb_get_property,
4423d0407baSopenharmony_ci};
4433d0407baSopenharmony_ci
4443d0407baSopenharmony_cistatic int rk817_charge_init_power_supply(struct rk817_charger *charge)
4453d0407baSopenharmony_ci{
4463d0407baSopenharmony_ci	struct power_supply_config psy_cfg = { .drv_data = charge, };
4473d0407baSopenharmony_ci
4483d0407baSopenharmony_ci	charge->usb_psy = devm_power_supply_register(charge->dev,
4493d0407baSopenharmony_ci						     &rk817_usb_desc,
4503d0407baSopenharmony_ci						     &psy_cfg);
4513d0407baSopenharmony_ci	if (IS_ERR(charge->usb_psy)) {
4523d0407baSopenharmony_ci		dev_err(charge->dev, "register usb power supply fail\n");
4533d0407baSopenharmony_ci		return PTR_ERR(charge->usb_psy);
4543d0407baSopenharmony_ci	}
4553d0407baSopenharmony_ci
4563d0407baSopenharmony_ci	charge->ac_psy = devm_power_supply_register(charge->dev, &rk817_ac_desc,
4573d0407baSopenharmony_ci						&psy_cfg);
4583d0407baSopenharmony_ci	if (IS_ERR(charge->ac_psy)) {
4593d0407baSopenharmony_ci		dev_err(charge->dev, "register ac power supply fail\n");
4603d0407baSopenharmony_ci		return PTR_ERR(charge->ac_psy);
4613d0407baSopenharmony_ci	}
4623d0407baSopenharmony_ci
4633d0407baSopenharmony_ci	return 0;
4643d0407baSopenharmony_ci}
4653d0407baSopenharmony_ci
4663d0407baSopenharmony_cistatic int rk817_charge_field_read(struct rk817_charger *charge,
4673d0407baSopenharmony_ci				   enum rk817_charge_fields field_id)
4683d0407baSopenharmony_ci{
4693d0407baSopenharmony_ci	int ret;
4703d0407baSopenharmony_ci	int val;
4713d0407baSopenharmony_ci
4723d0407baSopenharmony_ci	ret = regmap_field_read(charge->rmap_fields[field_id], &val);
4733d0407baSopenharmony_ci	if (ret < 0)
4743d0407baSopenharmony_ci		return ret;
4753d0407baSopenharmony_ci
4763d0407baSopenharmony_ci	return val;
4773d0407baSopenharmony_ci}
4783d0407baSopenharmony_ci
4793d0407baSopenharmony_cistatic int rk817_charge_field_write(struct rk817_charger *charge,
4803d0407baSopenharmony_ci				    enum rk817_charge_fields field_id,
4813d0407baSopenharmony_ci				    unsigned int val)
4823d0407baSopenharmony_ci{
4833d0407baSopenharmony_ci	return regmap_field_write(charge->rmap_fields[field_id], val);
4843d0407baSopenharmony_ci}
4853d0407baSopenharmony_ci
4863d0407baSopenharmony_cistatic int rk817_charge_get_otg_state(struct rk817_charger *charge)
4873d0407baSopenharmony_ci{
4883d0407baSopenharmony_ci	return regulator_is_enabled(charge->otg5v_rdev);
4893d0407baSopenharmony_ci}
4903d0407baSopenharmony_ci
4913d0407baSopenharmony_cistatic void rk817_charge_boost_disable(struct rk817_charger *charge)
4923d0407baSopenharmony_ci{
4933d0407baSopenharmony_ci	rk817_charge_field_write(charge, BOOST_EN, RK817_BOOST_DISABLE);
4943d0407baSopenharmony_ci}
4953d0407baSopenharmony_ci
4963d0407baSopenharmony_cistatic void rk817_charge_boost_enable(struct rk817_charger *charge)
4973d0407baSopenharmony_ci{
4983d0407baSopenharmony_ci	rk817_charge_field_write(charge, BOOST_EN, RK817_BOOST_ENABLE);
4993d0407baSopenharmony_ci}
5003d0407baSopenharmony_ci
5013d0407baSopenharmony_cistatic void rk817_charge_otg_disable(struct rk817_charger *charge)
5023d0407baSopenharmony_ci{
5033d0407baSopenharmony_ci	int ret;
5043d0407baSopenharmony_ci
5053d0407baSopenharmony_ci	ret = regulator_disable(charge->otg5v_rdev);
5063d0407baSopenharmony_ci
5073d0407baSopenharmony_ci	if (ret) {
5083d0407baSopenharmony_ci		DBG("disable otg5v failed:%d\n", ret);
5093d0407baSopenharmony_ci		return;
5103d0407baSopenharmony_ci	}
5113d0407baSopenharmony_ci
5123d0407baSopenharmony_ci	return;
5133d0407baSopenharmony_ci}
5143d0407baSopenharmony_ci
5153d0407baSopenharmony_cistatic void rk817_charge_otg_enable(struct rk817_charger *charge)
5163d0407baSopenharmony_ci{
5173d0407baSopenharmony_ci	int ret;
5183d0407baSopenharmony_ci
5193d0407baSopenharmony_ci	ret = regulator_enable(charge->otg5v_rdev);
5203d0407baSopenharmony_ci
5213d0407baSopenharmony_ci	if (ret) {
5223d0407baSopenharmony_ci		DBG("enable otg5v failed:%d\n", ret);
5233d0407baSopenharmony_ci		return;
5243d0407baSopenharmony_ci	}
5253d0407baSopenharmony_ci
5263d0407baSopenharmony_ci	return;
5273d0407baSopenharmony_ci}
5283d0407baSopenharmony_ci
5293d0407baSopenharmony_ci#ifdef CONFIG_PM_SLEEP
5303d0407baSopenharmony_cistatic int rk817_charge_get_otg_slp_state(struct rk817_charger *charge)
5313d0407baSopenharmony_ci{
5323d0407baSopenharmony_ci	return (rk817_charge_field_read(charge, OTG_SLP_EN) & OTG_SLP_ENABLE);
5333d0407baSopenharmony_ci}
5343d0407baSopenharmony_ci
5353d0407baSopenharmony_cistatic void rk817_charge_otg_slp_disable(struct rk817_charger *charge)
5363d0407baSopenharmony_ci{
5373d0407baSopenharmony_ci	rk817_charge_field_write(charge, OTG_SLP_EN, OTG_SLP_DISABLE);
5383d0407baSopenharmony_ci}
5393d0407baSopenharmony_ci
5403d0407baSopenharmony_cistatic void rk817_charge_otg_slp_enable(struct rk817_charger *charge)
5413d0407baSopenharmony_ci{
5423d0407baSopenharmony_ci	rk817_charge_field_write(charge, OTG_SLP_EN, OTG_SLP_ENABLE);
5433d0407baSopenharmony_ci}
5443d0407baSopenharmony_ci#endif
5453d0407baSopenharmony_ci
5463d0407baSopenharmony_cistatic int rk817_charge_get_charge_state(struct rk817_charger *charge)
5473d0407baSopenharmony_ci{
5483d0407baSopenharmony_ci	return rk817_charge_field_read(charge, CHRG_EN);
5493d0407baSopenharmony_ci}
5503d0407baSopenharmony_ci
5513d0407baSopenharmony_cistatic void rk817_charge_enable_charge(struct rk817_charger *charge)
5523d0407baSopenharmony_ci{
5533d0407baSopenharmony_ci	rk817_charge_field_write(charge, CHRG_EN, ENABLE);
5543d0407baSopenharmony_ci}
5553d0407baSopenharmony_ci
5563d0407baSopenharmony_cistatic void rk817_charge_usb_to_sys_enable(struct rk817_charger *charge)
5573d0407baSopenharmony_ci{
5583d0407baSopenharmony_ci	rk817_charge_field_write(charge, USB_SYS_EN, ENABLE);
5593d0407baSopenharmony_ci}
5603d0407baSopenharmony_ci
5613d0407baSopenharmony_cistatic void rk817_charge_sys_can_sd_disable(struct rk817_charger *charge)
5623d0407baSopenharmony_ci{
5633d0407baSopenharmony_ci	rk817_charge_field_write(charge, SYS_CAN_SD, DISABLE);
5643d0407baSopenharmony_ci}
5653d0407baSopenharmony_ci
5663d0407baSopenharmony_cistatic int rk817_charge_get_charge_status(struct rk817_charger *charge)
5673d0407baSopenharmony_ci{
5683d0407baSopenharmony_ci	int status;
5693d0407baSopenharmony_ci
5703d0407baSopenharmony_ci	status = rk817_charge_field_read(charge, CHG_STS);
5713d0407baSopenharmony_ci
5723d0407baSopenharmony_ci	switch (status) {
5733d0407baSopenharmony_ci	case CHRG_OFF:
5743d0407baSopenharmony_ci		DBG("charge off...\n");
5753d0407baSopenharmony_ci		break;
5763d0407baSopenharmony_ci	case DEAD_CHRG:
5773d0407baSopenharmony_ci		DBG("dead charge...\n");
5783d0407baSopenharmony_ci		break;
5793d0407baSopenharmony_ci	case TRICKLE_CHRG:
5803d0407baSopenharmony_ci		DBG("trickle charge...\n");
5813d0407baSopenharmony_ci		break;
5823d0407baSopenharmony_ci	case CC_OR_CV_CHRG:
5833d0407baSopenharmony_ci		DBG("CC or CV charge...\n");
5843d0407baSopenharmony_ci		break;
5853d0407baSopenharmony_ci	case CHRG_TERM:
5863d0407baSopenharmony_ci		DBG("charge TERM...\n");
5873d0407baSopenharmony_ci		break;
5883d0407baSopenharmony_ci	case USB_OVER_VOL:
5893d0407baSopenharmony_ci		DBG("USB over voltage...\n");
5903d0407baSopenharmony_ci		break;
5913d0407baSopenharmony_ci	case BAT_TMP_ERR:
5923d0407baSopenharmony_ci		DBG("battery temperature error...\n");
5933d0407baSopenharmony_ci		break;
5943d0407baSopenharmony_ci	case BAT_TIM_ERR:
5953d0407baSopenharmony_ci		DBG("battery timer error..\n");
5963d0407baSopenharmony_ci		break;
5973d0407baSopenharmony_ci	default:
5983d0407baSopenharmony_ci		break;
5993d0407baSopenharmony_ci	}
6003d0407baSopenharmony_ci
6013d0407baSopenharmony_ci	return status;
6023d0407baSopenharmony_ci}
6033d0407baSopenharmony_ci
6043d0407baSopenharmony_cistatic int rk817_charge_get_plug_in_status(struct rk817_charger *charge)
6053d0407baSopenharmony_ci{
6063d0407baSopenharmony_ci	return rk817_charge_field_read(charge, PLUG_IN_STS);
6073d0407baSopenharmony_ci}
6083d0407baSopenharmony_ci
6093d0407baSopenharmony_cistatic void rk817_charge_set_charge_clock(struct rk817_charger *charge,
6103d0407baSopenharmony_ci					  enum charge_clk clock)
6113d0407baSopenharmony_ci{
6123d0407baSopenharmony_ci	rk817_charge_field_write(charge, CHRG_CLK_SEL, clock);
6133d0407baSopenharmony_ci}
6143d0407baSopenharmony_ci
6153d0407baSopenharmony_cistatic int is_battery_exist(struct rk817_charger *charge)
6163d0407baSopenharmony_ci{
6173d0407baSopenharmony_ci	return rk817_charge_field_read(charge, BAT_EXS);
6183d0407baSopenharmony_ci}
6193d0407baSopenharmony_ci
6203d0407baSopenharmony_cistatic void rk817_charge_set_chrg_voltage(struct rk817_charger *charge,
6213d0407baSopenharmony_ci					  int chrg_vol)
6223d0407baSopenharmony_ci{
6233d0407baSopenharmony_ci	int voltage;
6243d0407baSopenharmony_ci
6253d0407baSopenharmony_ci	if (chrg_vol < 4100 || chrg_vol > 4500) {
6263d0407baSopenharmony_ci		dev_err(charge->dev, "the charge voltage is error!\n");
6273d0407baSopenharmony_ci	} else {
6283d0407baSopenharmony_ci		voltage = (chrg_vol - 4100) / 50;
6293d0407baSopenharmony_ci		rk817_charge_field_write(charge,
6303d0407baSopenharmony_ci					 CHRG_VOL_SEL,
6313d0407baSopenharmony_ci					 CHRG_VOL_4100MV + voltage);
6323d0407baSopenharmony_ci	}
6333d0407baSopenharmony_ci}
6343d0407baSopenharmony_ci
6353d0407baSopenharmony_cistatic void rk817_charge_set_chrg_current(struct rk817_charger *charge,
6363d0407baSopenharmony_ci					  int chrg_current)
6373d0407baSopenharmony_ci{
6383d0407baSopenharmony_ci	if (chrg_current < 500 || chrg_current > 3500)
6393d0407baSopenharmony_ci		dev_err(charge->dev, "the charge current is error!\n");
6403d0407baSopenharmony_ci
6413d0407baSopenharmony_ci	if (chrg_current < 1000)
6423d0407baSopenharmony_ci		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_500MA);
6433d0407baSopenharmony_ci	else if (chrg_current < 1500)
6443d0407baSopenharmony_ci		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_1000MA);
6453d0407baSopenharmony_ci	else if (chrg_current < 2000)
6463d0407baSopenharmony_ci		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_1500MA);
6473d0407baSopenharmony_ci	else if (chrg_current < 2500)
6483d0407baSopenharmony_ci		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_2000MA);
6493d0407baSopenharmony_ci	else if (chrg_current < 3000)
6503d0407baSopenharmony_ci		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_2500MA);
6513d0407baSopenharmony_ci	else if (chrg_current < 3500)
6523d0407baSopenharmony_ci		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_3000MA);
6533d0407baSopenharmony_ci	else
6543d0407baSopenharmony_ci		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_3500MA);
6553d0407baSopenharmony_ci}
6563d0407baSopenharmony_ci
6573d0407baSopenharmony_cistatic void rk817_charge_vlimit_enable(struct rk817_charger *charge)
6583d0407baSopenharmony_ci{
6593d0407baSopenharmony_ci	rk817_charge_field_write(charge, USB_VLIM_EN, ENABLE);
6603d0407baSopenharmony_ci}
6613d0407baSopenharmony_ci
6623d0407baSopenharmony_cistatic void rk817_charge_set_input_voltage(struct rk817_charger *charge,
6633d0407baSopenharmony_ci					   int input_voltage)
6643d0407baSopenharmony_ci{
6653d0407baSopenharmony_ci	int voltage;
6663d0407baSopenharmony_ci
6673d0407baSopenharmony_ci	if (input_voltage < 4000)
6683d0407baSopenharmony_ci		dev_err(charge->dev, "the input voltage is error.\n");
6693d0407baSopenharmony_ci
6703d0407baSopenharmony_ci	voltage = INPUT_VOL_4000MV + (input_voltage - 4000) / 100;
6713d0407baSopenharmony_ci
6723d0407baSopenharmony_ci	rk817_charge_field_write(charge, USB_VLIM_SEL, voltage);
6733d0407baSopenharmony_ci	rk817_charge_vlimit_enable(charge);
6743d0407baSopenharmony_ci}
6753d0407baSopenharmony_ci
6763d0407baSopenharmony_cistatic void rk817_charge_ilimit_enable(struct rk817_charger *charge)
6773d0407baSopenharmony_ci{
6783d0407baSopenharmony_ci	rk817_charge_field_write(charge, USB_ILIM_EN, ENABLE);
6793d0407baSopenharmony_ci}
6803d0407baSopenharmony_ci
6813d0407baSopenharmony_cistatic void rk817_charge_set_input_current(struct rk817_charger *charge,
6823d0407baSopenharmony_ci					   int input_current)
6833d0407baSopenharmony_ci{
6843d0407baSopenharmony_ci	if (input_current < 80 || input_current > 3000)
6853d0407baSopenharmony_ci		dev_err(charge->dev, "the input current is error.\n");
6863d0407baSopenharmony_ci
6873d0407baSopenharmony_ci	if (input_current < 450)
6883d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
6893d0407baSopenharmony_ci					 INPUT_CUR_80MA);
6903d0407baSopenharmony_ci	else if (input_current < 850)
6913d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
6923d0407baSopenharmony_ci					 INPUT_CUR_450MA);
6933d0407baSopenharmony_ci	else if (input_current < 1500)
6943d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
6953d0407baSopenharmony_ci					 INPUT_CUR_850MA);
6963d0407baSopenharmony_ci	else if (input_current < 1750)
6973d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
6983d0407baSopenharmony_ci					 INPUT_CUR_1500MA);
6993d0407baSopenharmony_ci	else if (input_current < 2000)
7003d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
7013d0407baSopenharmony_ci					 INPUT_CUR_1750MA);
7023d0407baSopenharmony_ci	else if (input_current < 2500)
7033d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
7043d0407baSopenharmony_ci					 INPUT_CUR_2000MA);
7053d0407baSopenharmony_ci	else if (input_current < 3000)
7063d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
7073d0407baSopenharmony_ci					 INPUT_CUR_2500MA);
7083d0407baSopenharmony_ci	else
7093d0407baSopenharmony_ci		rk817_charge_field_write(charge, USB_ILIM_SEL,
7103d0407baSopenharmony_ci					 INPUT_CUR_3000MA);
7113d0407baSopenharmony_ci
7123d0407baSopenharmony_ci	rk817_charge_ilimit_enable(charge);
7133d0407baSopenharmony_ci}
7143d0407baSopenharmony_ci
7153d0407baSopenharmony_cistatic void rk817_charge_set_chrg_term_mod(struct rk817_charger *charge,
7163d0407baSopenharmony_ci					   int mode)
7173d0407baSopenharmony_ci{
7183d0407baSopenharmony_ci	rk817_charge_field_write(charge, CHRG_TERM_ANA_DIG, mode);
7193d0407baSopenharmony_ci}
7203d0407baSopenharmony_ci
7213d0407baSopenharmony_cistatic void rk817_charge_set_term_current_analog(struct rk817_charger *charge,
7223d0407baSopenharmony_ci						 int chrg_current)
7233d0407baSopenharmony_ci{
7243d0407baSopenharmony_ci	int value;
7253d0407baSopenharmony_ci
7263d0407baSopenharmony_ci	if (chrg_current < 200)
7273d0407baSopenharmony_ci		value = CHRG_TERM_150MA;
7283d0407baSopenharmony_ci	else if (chrg_current < 300)
7293d0407baSopenharmony_ci		value = CHRG_TERM_200MA;
7303d0407baSopenharmony_ci	else if (chrg_current < 400)
7313d0407baSopenharmony_ci		value = CHRG_TERM_300MA;
7323d0407baSopenharmony_ci	else
7333d0407baSopenharmony_ci		value = CHRG_TERM_400MA;
7343d0407baSopenharmony_ci
7353d0407baSopenharmony_ci	rk817_charge_field_write(charge,
7363d0407baSopenharmony_ci				 CHRG_TERM_ANA_SEL,
7373d0407baSopenharmony_ci				 value);
7383d0407baSopenharmony_ci}
7393d0407baSopenharmony_ci
7403d0407baSopenharmony_cistatic void rk817_charge_set_term_current_digital(struct rk817_charger *charge,
7413d0407baSopenharmony_ci						  int chrg_current)
7423d0407baSopenharmony_ci{
7433d0407baSopenharmony_ci	int value;
7443d0407baSopenharmony_ci	u8 current_adc;
7453d0407baSopenharmony_ci
7463d0407baSopenharmony_ci	value = CURRENT_TO_ADC(chrg_current, charge->res_div);
7473d0407baSopenharmony_ci
7483d0407baSopenharmony_ci	value &= (0xff << 5);
7493d0407baSopenharmony_ci	current_adc = value >> 5;
7503d0407baSopenharmony_ci	rk817_charge_field_write(charge, CHRG_TERM_DIG, current_adc);
7513d0407baSopenharmony_ci}
7523d0407baSopenharmony_ci
7533d0407baSopenharmony_cistatic void rk817_charge_set_chrg_finish_condition(struct rk817_charger *charge)
7543d0407baSopenharmony_ci{
7553d0407baSopenharmony_ci	if (charge->chrg_term_mode == CHRG_ANALOG)
7563d0407baSopenharmony_ci		rk817_charge_set_term_current_analog(charge,
7573d0407baSopenharmony_ci						     charge->chrg_finish_cur);
7583d0407baSopenharmony_ci	else
7593d0407baSopenharmony_ci		rk817_charge_set_term_current_digital(charge,
7603d0407baSopenharmony_ci						      charge->chrg_finish_cur);
7613d0407baSopenharmony_ci
7623d0407baSopenharmony_ci	rk817_charge_set_chrg_term_mod(charge, charge->chrg_term_mode);
7633d0407baSopenharmony_ci}
7643d0407baSopenharmony_ci
7653d0407baSopenharmony_cistatic int rk817_charge_online(struct rk817_charger *charge)
7663d0407baSopenharmony_ci{
7673d0407baSopenharmony_ci	return (charge->ac_in | charge->usb_in | charge->dc_in);
7683d0407baSopenharmony_ci}
7693d0407baSopenharmony_ci
7703d0407baSopenharmony_cistatic int rk817_charge_get_dsoc(struct rk817_charger *charge)
7713d0407baSopenharmony_ci{
7723d0407baSopenharmony_ci	int soc_save;
7733d0407baSopenharmony_ci
7743d0407baSopenharmony_ci	soc_save = rk817_charge_field_read(charge, SOC_REG0);
7753d0407baSopenharmony_ci	soc_save |= (rk817_charge_field_read(charge, SOC_REG1) << 8);
7763d0407baSopenharmony_ci	soc_save |= (rk817_charge_field_read(charge, SOC_REG2) << 16);
7773d0407baSopenharmony_ci
7783d0407baSopenharmony_ci	return soc_save / 1000;
7793d0407baSopenharmony_ci}
7803d0407baSopenharmony_ci
7813d0407baSopenharmony_cistatic void rk817_charge_set_otg_in(struct rk817_charger *charge, int online)
7823d0407baSopenharmony_ci{
7833d0407baSopenharmony_ci	charge->otg_in = online;
7843d0407baSopenharmony_ci}
7853d0407baSopenharmony_ci
7863d0407baSopenharmony_cistatic void rk817_charge_set_chrg_param(struct rk817_charger *charge,
7873d0407baSopenharmony_ci					enum charger_t charger)
7883d0407baSopenharmony_ci{
7893d0407baSopenharmony_ci	switch (charger) {
7903d0407baSopenharmony_ci	case USB_TYPE_NONE_CHARGER:
7913d0407baSopenharmony_ci		charge->usb_in = 0;
7923d0407baSopenharmony_ci		charge->ac_in = 0;
7933d0407baSopenharmony_ci		if (charge->dc_in == 0) {
7943d0407baSopenharmony_ci			charge->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
7953d0407baSopenharmony_ci			rk817_charge_set_input_current(charge, INPUT_450MA);
7963d0407baSopenharmony_ci		}
7973d0407baSopenharmony_ci		power_supply_changed(charge->usb_psy);
7983d0407baSopenharmony_ci		power_supply_changed(charge->ac_psy);
7993d0407baSopenharmony_ci		break;
8003d0407baSopenharmony_ci	case USB_TYPE_USB_CHARGER:
8013d0407baSopenharmony_ci		charge->usb_in = 1;
8023d0407baSopenharmony_ci		charge->ac_in = 0;
8033d0407baSopenharmony_ci		charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
8043d0407baSopenharmony_ci		if (charge->dc_in == 0)
8053d0407baSopenharmony_ci			rk817_charge_set_input_current(charge, INPUT_450MA);
8063d0407baSopenharmony_ci		power_supply_changed(charge->usb_psy);
8073d0407baSopenharmony_ci		power_supply_changed(charge->ac_psy);
8083d0407baSopenharmony_ci		break;
8093d0407baSopenharmony_ci	case USB_TYPE_AC_CHARGER:
8103d0407baSopenharmony_ci	case USB_TYPE_CDP_CHARGER:
8113d0407baSopenharmony_ci		charge->ac_in = 1;
8123d0407baSopenharmony_ci		charge->usb_in = 0;
8133d0407baSopenharmony_ci		charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
8143d0407baSopenharmony_ci		if (charger == USB_TYPE_AC_CHARGER)
8153d0407baSopenharmony_ci			rk817_charge_set_input_current(charge,
8163d0407baSopenharmony_ci						       charge->max_input_current);
8173d0407baSopenharmony_ci		else
8183d0407baSopenharmony_ci			rk817_charge_set_input_current(charge,
8193d0407baSopenharmony_ci						       INPUT_1500MA);
8203d0407baSopenharmony_ci		power_supply_changed(charge->usb_psy);
8213d0407baSopenharmony_ci		power_supply_changed(charge->ac_psy);
8223d0407baSopenharmony_ci		break;
8233d0407baSopenharmony_ci	case DC_TYPE_DC_CHARGER:
8243d0407baSopenharmony_ci		charge->dc_in = 1;
8253d0407baSopenharmony_ci		charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
8263d0407baSopenharmony_ci		rk817_charge_set_input_current(charge,
8273d0407baSopenharmony_ci					       charge->max_input_current);
8283d0407baSopenharmony_ci		power_supply_changed(charge->usb_psy);
8293d0407baSopenharmony_ci		power_supply_changed(charge->ac_psy);
8303d0407baSopenharmony_ci		break;
8313d0407baSopenharmony_ci	case DC_TYPE_NONE_CHARGER:
8323d0407baSopenharmony_ci		charge->dc_in = 0;
8333d0407baSopenharmony_ci		if (!rk817_charge_get_plug_in_status(charge)) {
8343d0407baSopenharmony_ci			charge->ac_in = 0;
8353d0407baSopenharmony_ci			charge->usb_in = 0;
8363d0407baSopenharmony_ci			charge->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
8373d0407baSopenharmony_ci			rk817_charge_set_input_current(charge, INPUT_450MA);
8383d0407baSopenharmony_ci		} else if (charge->usb_in) {
8393d0407baSopenharmony_ci			rk817_charge_set_input_current(charge, INPUT_450MA);
8403d0407baSopenharmony_ci			charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
8413d0407baSopenharmony_ci		}
8423d0407baSopenharmony_ci		power_supply_changed(charge->usb_psy);
8433d0407baSopenharmony_ci		power_supply_changed(charge->ac_psy);
8443d0407baSopenharmony_ci		break;
8453d0407baSopenharmony_ci	default:
8463d0407baSopenharmony_ci		charge->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
8473d0407baSopenharmony_ci		rk817_charge_set_input_current(charge, INPUT_450MA);
8483d0407baSopenharmony_ci		break;
8493d0407baSopenharmony_ci	}
8503d0407baSopenharmony_ci
8513d0407baSopenharmony_ci	if (rk817_charge_online(charge) && rk817_charge_get_dsoc(charge) == 100)
8523d0407baSopenharmony_ci		charge->prop_status = POWER_SUPPLY_STATUS_FULL;
8533d0407baSopenharmony_ci}
8543d0407baSopenharmony_ci
8553d0407baSopenharmony_cistatic void rk817_charge_set_otg_state(struct rk817_charger *charge, int state)
8563d0407baSopenharmony_ci{
8573d0407baSopenharmony_ci	switch (state) {
8583d0407baSopenharmony_ci	case USB_OTG_POWER_ON:
8593d0407baSopenharmony_ci		if (charge->otg_in) {
8603d0407baSopenharmony_ci			DBG("otg5v is on yet, ignore..\n");
8613d0407baSopenharmony_ci		} else {
8623d0407baSopenharmony_ci
8633d0407baSopenharmony_ci			if (!rk817_charge_get_otg_state(charge)) {
8643d0407baSopenharmony_ci				rk817_charge_otg_enable(charge);
8653d0407baSopenharmony_ci				if (!rk817_charge_get_otg_state(charge)) {
8663d0407baSopenharmony_ci					DBG("enable otg5v failed\n");
8673d0407baSopenharmony_ci					return;
8683d0407baSopenharmony_ci				}
8693d0407baSopenharmony_ci			}
8703d0407baSopenharmony_ci			disable_irq(charge->plugin_irq);
8713d0407baSopenharmony_ci			disable_irq(charge->plugout_irq);
8723d0407baSopenharmony_ci			DBG("enable otg5v\n");
8733d0407baSopenharmony_ci		}
8743d0407baSopenharmony_ci		break;
8753d0407baSopenharmony_ci
8763d0407baSopenharmony_ci	case USB_OTG_POWER_OFF:
8773d0407baSopenharmony_ci		if (!charge->otg_in) {
8783d0407baSopenharmony_ci			DBG("otg5v is off yet, ignore..\n");
8793d0407baSopenharmony_ci		} else {
8803d0407baSopenharmony_ci
8813d0407baSopenharmony_ci			if (rk817_charge_get_otg_state(charge)) {
8823d0407baSopenharmony_ci				rk817_charge_otg_disable(charge);
8833d0407baSopenharmony_ci				if (rk817_charge_get_otg_state(charge)) {
8843d0407baSopenharmony_ci					DBG("disable otg5v failed\n");
8853d0407baSopenharmony_ci					return;
8863d0407baSopenharmony_ci				}
8873d0407baSopenharmony_ci			}
8883d0407baSopenharmony_ci			enable_irq(charge->plugin_irq);
8893d0407baSopenharmony_ci			enable_irq(charge->plugout_irq);
8903d0407baSopenharmony_ci			DBG("disable otg5v\n");
8913d0407baSopenharmony_ci		}
8923d0407baSopenharmony_ci		break;
8933d0407baSopenharmony_ci	default:
8943d0407baSopenharmony_ci		dev_err(charge->dev, "error otg type\n");
8953d0407baSopenharmony_ci		break;
8963d0407baSopenharmony_ci	}
8973d0407baSopenharmony_ci}
8983d0407baSopenharmony_ci
8993d0407baSopenharmony_cistatic irqreturn_t rk817_charge_dc_det_isr(int irq, void *charger)
9003d0407baSopenharmony_ci{
9013d0407baSopenharmony_ci	struct rk817_charger *charge = (struct rk817_charger *)charger;
9023d0407baSopenharmony_ci
9033d0407baSopenharmony_ci	if (gpio_get_value(charge->pdata->dc_det_pin))
9043d0407baSopenharmony_ci		irq_set_irq_type(irq, IRQF_TRIGGER_LOW);
9053d0407baSopenharmony_ci	else
9063d0407baSopenharmony_ci		irq_set_irq_type(irq, IRQF_TRIGGER_HIGH);
9073d0407baSopenharmony_ci
9083d0407baSopenharmony_ci	queue_delayed_work(charge->dc_charger_wq, &charge->dc_work,
9093d0407baSopenharmony_ci			   msecs_to_jiffies(10));
9103d0407baSopenharmony_ci
9113d0407baSopenharmony_ci	return IRQ_HANDLED;
9123d0407baSopenharmony_ci}
9133d0407baSopenharmony_ci
9143d0407baSopenharmony_cistatic enum charger_t rk817_charge_get_dc_state(struct rk817_charger *charge)
9153d0407baSopenharmony_ci{
9163d0407baSopenharmony_ci	int level;
9173d0407baSopenharmony_ci
9183d0407baSopenharmony_ci	if (!gpio_is_valid(charge->pdata->dc_det_pin))
9193d0407baSopenharmony_ci		return DC_TYPE_NONE_CHARGER;
9203d0407baSopenharmony_ci
9213d0407baSopenharmony_ci	level = gpio_get_value(charge->pdata->dc_det_pin);
9223d0407baSopenharmony_ci
9233d0407baSopenharmony_ci	return (level == charge->pdata->dc_det_level) ?
9243d0407baSopenharmony_ci		DC_TYPE_DC_CHARGER : DC_TYPE_NONE_CHARGER;
9253d0407baSopenharmony_ci}
9263d0407baSopenharmony_ci
9273d0407baSopenharmony_cistatic void rk817_charge_dc_det_worker(struct work_struct *work)
9283d0407baSopenharmony_ci{
9293d0407baSopenharmony_ci	enum charger_t charger;
9303d0407baSopenharmony_ci	struct rk817_charger *charge = container_of(work,
9313d0407baSopenharmony_ci			struct rk817_charger, dc_work.work);
9323d0407baSopenharmony_ci
9333d0407baSopenharmony_ci	charger = rk817_charge_get_dc_state(charge);
9343d0407baSopenharmony_ci	if (charger == DC_TYPE_DC_CHARGER) {
9353d0407baSopenharmony_ci		DBG("detect dc charger in..\n");
9363d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, DC_TYPE_DC_CHARGER);
9373d0407baSopenharmony_ci		/* check otg supply */
9383d0407baSopenharmony_ci		if (charge->otg_in && charge->pdata->power_dc2otg) {
9393d0407baSopenharmony_ci			DBG("otg power from dc adapter\n");
9403d0407baSopenharmony_ci			rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
9413d0407baSopenharmony_ci		}
9423d0407baSopenharmony_ci
9433d0407baSopenharmony_ci		rk817_charge_boost_disable(charge);
9443d0407baSopenharmony_ci	} else {
9453d0407baSopenharmony_ci		DBG("detect dc charger out..\n");
9463d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, DC_TYPE_NONE_CHARGER);
9473d0407baSopenharmony_ci		rk817_charge_boost_enable(charge);
9483d0407baSopenharmony_ci		/* check otg supply, power on anyway */
9493d0407baSopenharmony_ci		if (charge->otg_in)
9503d0407baSopenharmony_ci			rk817_charge_set_otg_state(charge, USB_OTG_POWER_ON);
9513d0407baSopenharmony_ci	}
9523d0407baSopenharmony_ci}
9533d0407baSopenharmony_ci
9543d0407baSopenharmony_cistatic int rk817_charge_init_dc(struct rk817_charger *charge)
9553d0407baSopenharmony_ci{
9563d0407baSopenharmony_ci	int ret, level;
9573d0407baSopenharmony_ci	unsigned long irq_flags;
9583d0407baSopenharmony_ci	unsigned int dc_det_irq;
9593d0407baSopenharmony_ci
9603d0407baSopenharmony_ci	charge->dc_charger_wq = alloc_ordered_workqueue("%s",
9613d0407baSopenharmony_ci				WQ_MEM_RECLAIM | WQ_FREEZABLE,
9623d0407baSopenharmony_ci				"rk817-dc-wq");
9633d0407baSopenharmony_ci	INIT_DELAYED_WORK(&charge->dc_work, rk817_charge_dc_det_worker);
9643d0407baSopenharmony_ci	charge->dc_charger = DC_TYPE_NONE_CHARGER;
9653d0407baSopenharmony_ci
9663d0407baSopenharmony_ci	if (!charge->pdata->support_dc_det)
9673d0407baSopenharmony_ci		return 0;
9683d0407baSopenharmony_ci
9693d0407baSopenharmony_ci	ret = devm_gpio_request(charge->dev,
9703d0407baSopenharmony_ci				charge->pdata->dc_det_pin,
9713d0407baSopenharmony_ci				"rk817_dc_det");
9723d0407baSopenharmony_ci	if (ret < 0) {
9733d0407baSopenharmony_ci		dev_err(charge->dev, "failed to request gpio %d\n",
9743d0407baSopenharmony_ci			charge->pdata->dc_det_pin);
9753d0407baSopenharmony_ci		return ret;
9763d0407baSopenharmony_ci	}
9773d0407baSopenharmony_ci
9783d0407baSopenharmony_ci	ret = gpio_direction_input(charge->pdata->dc_det_pin);
9793d0407baSopenharmony_ci	if (ret) {
9803d0407baSopenharmony_ci		dev_err(charge->dev, "failed to set gpio input\n");
9813d0407baSopenharmony_ci		return ret;
9823d0407baSopenharmony_ci	}
9833d0407baSopenharmony_ci
9843d0407baSopenharmony_ci	level = gpio_get_value(charge->pdata->dc_det_pin);
9853d0407baSopenharmony_ci	if (level == charge->pdata->dc_det_level)
9863d0407baSopenharmony_ci		charge->dc_charger = DC_TYPE_DC_CHARGER;
9873d0407baSopenharmony_ci	else
9883d0407baSopenharmony_ci		charge->dc_charger = DC_TYPE_NONE_CHARGER;
9893d0407baSopenharmony_ci
9903d0407baSopenharmony_ci	if (level)
9913d0407baSopenharmony_ci		irq_flags = IRQF_TRIGGER_LOW;
9923d0407baSopenharmony_ci	else
9933d0407baSopenharmony_ci		irq_flags = IRQF_TRIGGER_HIGH;
9943d0407baSopenharmony_ci
9953d0407baSopenharmony_ci	dc_det_irq = gpio_to_irq(charge->pdata->dc_det_pin);
9963d0407baSopenharmony_ci	ret = devm_request_irq(charge->dev, dc_det_irq, rk817_charge_dc_det_isr,
9973d0407baSopenharmony_ci			       irq_flags, "rk817_dc_det", charge);
9983d0407baSopenharmony_ci	if (ret != 0) {
9993d0407baSopenharmony_ci		dev_err(charge->dev, "rk817_dc_det_irq request failed!\n");
10003d0407baSopenharmony_ci		return ret;
10013d0407baSopenharmony_ci	}
10023d0407baSopenharmony_ci
10033d0407baSopenharmony_ci	enable_irq_wake(dc_det_irq);
10043d0407baSopenharmony_ci
10053d0407baSopenharmony_ci	if (charge->dc_charger != DC_TYPE_NONE_CHARGER)
10063d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, charge->dc_charger);
10073d0407baSopenharmony_ci
10083d0407baSopenharmony_ci	return 0;
10093d0407baSopenharmony_ci}
10103d0407baSopenharmony_ci
10113d0407baSopenharmony_cistatic void rk817_charge_host_evt_worker(struct work_struct *work)
10123d0407baSopenharmony_ci{
10133d0407baSopenharmony_ci	struct rk817_charger *charge = container_of(work,
10143d0407baSopenharmony_ci			struct rk817_charger, host_work.work);
10153d0407baSopenharmony_ci	struct extcon_dev *edev = charge->cable_edev;
10163d0407baSopenharmony_ci
10173d0407baSopenharmony_ci	/* Determine cable/charger type */
10183d0407baSopenharmony_ci	if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) {
10193d0407baSopenharmony_ci		DBG("receive type-c notifier event: OTG ON...\n");
10203d0407baSopenharmony_ci		if (charge->dc_in && charge->pdata->power_dc2otg) {
10213d0407baSopenharmony_ci			if (charge->otg_in)
10223d0407baSopenharmony_ci				rk817_charge_set_otg_state(charge,
10233d0407baSopenharmony_ci							   USB_OTG_POWER_OFF);
10243d0407baSopenharmony_ci			DBG("otg power from dc adapter\n");
10253d0407baSopenharmony_ci		} else {
10263d0407baSopenharmony_ci			rk817_charge_set_otg_state(charge, USB_OTG_POWER_ON);
10273d0407baSopenharmony_ci		}
10283d0407baSopenharmony_ci		rk817_charge_set_otg_in(charge, ONLINE);
10293d0407baSopenharmony_ci	} else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) {
10303d0407baSopenharmony_ci		DBG("receive type-c notifier event: OTG OFF...\n");
10313d0407baSopenharmony_ci		rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
10323d0407baSopenharmony_ci		rk817_charge_set_otg_in(charge, OFFLINE);
10333d0407baSopenharmony_ci	}
10343d0407baSopenharmony_ci}
10353d0407baSopenharmony_ci
10363d0407baSopenharmony_cistatic void rk817_charger_evt_worker(struct work_struct *work)
10373d0407baSopenharmony_ci{
10383d0407baSopenharmony_ci	struct rk817_charger *charge = container_of(work,
10393d0407baSopenharmony_ci				struct rk817_charger, usb_work.work);
10403d0407baSopenharmony_ci	struct extcon_dev *edev = charge->cable_edev;
10413d0407baSopenharmony_ci	enum charger_t charger = USB_TYPE_UNKNOWN_CHARGER;
10423d0407baSopenharmony_ci	static const char * const event[] = {"UN", "NONE", "USB",
10433d0407baSopenharmony_ci					     "AC", "CDP1.5A"};
10443d0407baSopenharmony_ci
10453d0407baSopenharmony_ci	/* Determine cable/charger type */
10463d0407baSopenharmony_ci	if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0)
10473d0407baSopenharmony_ci		charger = USB_TYPE_USB_CHARGER;
10483d0407baSopenharmony_ci	else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0)
10493d0407baSopenharmony_ci		charger = USB_TYPE_AC_CHARGER;
10503d0407baSopenharmony_ci	else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0)
10513d0407baSopenharmony_ci		charger = USB_TYPE_CDP_CHARGER;
10523d0407baSopenharmony_ci
10533d0407baSopenharmony_ci	if (charger != USB_TYPE_UNKNOWN_CHARGER) {
10543d0407baSopenharmony_ci		DBG("receive type-c notifier event: %s...\n",
10553d0407baSopenharmony_ci		    event[charger]);
10563d0407baSopenharmony_ci		charge->usb_charger = charger;
10573d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, charger);
10583d0407baSopenharmony_ci	}
10593d0407baSopenharmony_ci}
10603d0407baSopenharmony_ci
10613d0407baSopenharmony_cistatic void rk817_charge_discnt_evt_worker(struct work_struct *work)
10623d0407baSopenharmony_ci{
10633d0407baSopenharmony_ci	struct rk817_charger *charge = container_of(work,
10643d0407baSopenharmony_ci			struct rk817_charger, discnt_work.work);
10653d0407baSopenharmony_ci
10663d0407baSopenharmony_ci	if (extcon_get_state(charge->cable_edev, EXTCON_USB) == 0) {
10673d0407baSopenharmony_ci		DBG("receive type-c notifier event: DISCNT...\n");
10683d0407baSopenharmony_ci
10693d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, USB_TYPE_NONE_CHARGER);
10703d0407baSopenharmony_ci	}
10713d0407baSopenharmony_ci}
10723d0407baSopenharmony_ci
10733d0407baSopenharmony_cistatic void rk817_charge_bc_evt_worker(struct work_struct *work)
10743d0407baSopenharmony_ci{
10753d0407baSopenharmony_ci	struct rk817_charger *charge = container_of(work,
10763d0407baSopenharmony_ci						    struct rk817_charger,
10773d0407baSopenharmony_ci						    usb_work.work);
10783d0407baSopenharmony_ci	static const char * const event_name[] = {"DISCNT", "USB", "AC",
10793d0407baSopenharmony_ci						  "CDP1.5A", "UNKNOWN",
10803d0407baSopenharmony_ci						  "OTG ON", "OTG OFF"};
10813d0407baSopenharmony_ci
10823d0407baSopenharmony_ci	switch (charge->bc_event) {
10833d0407baSopenharmony_ci	case USB_BC_TYPE_DISCNT:
10843d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, USB_TYPE_NONE_CHARGER);
10853d0407baSopenharmony_ci		break;
10863d0407baSopenharmony_ci	case USB_BC_TYPE_SDP:
10873d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, USB_TYPE_USB_CHARGER);
10883d0407baSopenharmony_ci		break;
10893d0407baSopenharmony_ci	case USB_BC_TYPE_DCP:
10903d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, USB_TYPE_AC_CHARGER);
10913d0407baSopenharmony_ci		break;
10923d0407baSopenharmony_ci	case USB_BC_TYPE_CDP:
10933d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, USB_TYPE_CDP_CHARGER);
10943d0407baSopenharmony_ci		break;
10953d0407baSopenharmony_ci	case USB_OTG_POWER_ON:
10963d0407baSopenharmony_ci		if (charge->pdata->power_dc2otg && charge->dc_in)
10973d0407baSopenharmony_ci			DBG("otg power from dc adapter\n");
10983d0407baSopenharmony_ci		else
10993d0407baSopenharmony_ci			rk817_charge_set_otg_state(charge, USB_OTG_POWER_ON);
11003d0407baSopenharmony_ci		break;
11013d0407baSopenharmony_ci	case USB_OTG_POWER_OFF:
11023d0407baSopenharmony_ci		rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
11033d0407baSopenharmony_ci		break;
11043d0407baSopenharmony_ci	default:
11053d0407baSopenharmony_ci		break;
11063d0407baSopenharmony_ci	}
11073d0407baSopenharmony_ci
11083d0407baSopenharmony_ci	DBG("receive bc notifier event: %s..\n", event_name[charge->bc_event]);
11093d0407baSopenharmony_ci}
11103d0407baSopenharmony_ci
11113d0407baSopenharmony_cistatic int rk817_charger_evt_notifier(struct notifier_block *nb,
11123d0407baSopenharmony_ci				      unsigned long event, void *ptr)
11133d0407baSopenharmony_ci{
11143d0407baSopenharmony_ci	struct rk817_charger *charge =
11153d0407baSopenharmony_ci		container_of(nb, struct rk817_charger, cable_cg_nb);
11163d0407baSopenharmony_ci
11173d0407baSopenharmony_ci	queue_delayed_work(charge->usb_charger_wq, &charge->usb_work,
11183d0407baSopenharmony_ci			   msecs_to_jiffies(10));
11193d0407baSopenharmony_ci
11203d0407baSopenharmony_ci	return NOTIFY_DONE;
11213d0407baSopenharmony_ci}
11223d0407baSopenharmony_ci
11233d0407baSopenharmony_cistatic int rk817_charge_host_evt_notifier(struct notifier_block *nb,
11243d0407baSopenharmony_ci					  unsigned long event, void *ptr)
11253d0407baSopenharmony_ci{
11263d0407baSopenharmony_ci	struct rk817_charger *charge =
11273d0407baSopenharmony_ci		container_of(nb, struct rk817_charger, cable_host_nb);
11283d0407baSopenharmony_ci
11293d0407baSopenharmony_ci	queue_delayed_work(charge->usb_charger_wq, &charge->host_work,
11303d0407baSopenharmony_ci			   msecs_to_jiffies(10));
11313d0407baSopenharmony_ci
11323d0407baSopenharmony_ci	return NOTIFY_DONE;
11333d0407baSopenharmony_ci}
11343d0407baSopenharmony_ci
11353d0407baSopenharmony_cistatic int rk817_charge_discnt_evt_notfier(struct notifier_block *nb,
11363d0407baSopenharmony_ci					   unsigned long event, void *ptr)
11373d0407baSopenharmony_ci{
11383d0407baSopenharmony_ci	struct rk817_charger *charge =
11393d0407baSopenharmony_ci		container_of(nb, struct rk817_charger, cable_discnt_nb);
11403d0407baSopenharmony_ci
11413d0407baSopenharmony_ci	queue_delayed_work(charge->usb_charger_wq, &charge->discnt_work,
11423d0407baSopenharmony_ci			   msecs_to_jiffies(10));
11433d0407baSopenharmony_ci
11443d0407baSopenharmony_ci	return NOTIFY_DONE;
11453d0407baSopenharmony_ci}
11463d0407baSopenharmony_ci
11473d0407baSopenharmony_cistatic int rk817_charge_bc_evt_notifier(struct notifier_block *nb,
11483d0407baSopenharmony_ci					unsigned long event, void *ptr)
11493d0407baSopenharmony_ci{
11503d0407baSopenharmony_ci	struct rk817_charger *charge =
11513d0407baSopenharmony_ci		container_of(nb, struct rk817_charger, bc_nb);
11523d0407baSopenharmony_ci
11533d0407baSopenharmony_ci	charge->bc_event = event;
11543d0407baSopenharmony_ci	queue_delayed_work(charge->usb_charger_wq, &charge->usb_work,
11553d0407baSopenharmony_ci			   msecs_to_jiffies(10));
11563d0407baSopenharmony_ci
11573d0407baSopenharmony_ci	return NOTIFY_DONE;
11583d0407baSopenharmony_ci}
11593d0407baSopenharmony_ci
11603d0407baSopenharmony_cistatic int rk817_charge_usb_init(struct rk817_charger *charge)
11613d0407baSopenharmony_ci{
11623d0407baSopenharmony_ci	enum charger_t charger;
11633d0407baSopenharmony_ci	enum bc_port_type bc_type;
11643d0407baSopenharmony_ci	struct extcon_dev *edev;
11653d0407baSopenharmony_ci	struct device *dev = charge->dev;
11663d0407baSopenharmony_ci	int ret;
11673d0407baSopenharmony_ci
11683d0407baSopenharmony_ci	charge->usb_charger_wq = alloc_ordered_workqueue("%s",
11693d0407baSopenharmony_ci				WQ_MEM_RECLAIM | WQ_FREEZABLE,
11703d0407baSopenharmony_ci				"rk817-usb-wq");
11713d0407baSopenharmony_ci
11723d0407baSopenharmony_ci	/* type-C */
11733d0407baSopenharmony_ci	if (charge->pdata->extcon) {
11743d0407baSopenharmony_ci		edev = extcon_get_edev_by_phandle(dev, 0);
11753d0407baSopenharmony_ci		if (IS_ERR(edev)) {
11763d0407baSopenharmony_ci			if (PTR_ERR(edev) != -EPROBE_DEFER)
11773d0407baSopenharmony_ci				dev_err(dev, "Invalid or missing extcon\n");
11783d0407baSopenharmony_ci			return PTR_ERR(edev);
11793d0407baSopenharmony_ci		}
11803d0407baSopenharmony_ci
11813d0407baSopenharmony_ci		/* Register chargers  */
11823d0407baSopenharmony_ci		INIT_DELAYED_WORK(&charge->usb_work, rk817_charger_evt_worker);
11833d0407baSopenharmony_ci		charge->cable_cg_nb.notifier_call = rk817_charger_evt_notifier;
11843d0407baSopenharmony_ci		ret = extcon_register_notifier(edev, EXTCON_CHG_USB_SDP,
11853d0407baSopenharmony_ci					       &charge->cable_cg_nb);
11863d0407baSopenharmony_ci		if (ret < 0) {
11873d0407baSopenharmony_ci			dev_err(dev, "failed to register notifier for SDP\n");
11883d0407baSopenharmony_ci			return ret;
11893d0407baSopenharmony_ci		}
11903d0407baSopenharmony_ci
11913d0407baSopenharmony_ci		ret = extcon_register_notifier(edev, EXTCON_CHG_USB_DCP,
11923d0407baSopenharmony_ci					       &charge->cable_cg_nb);
11933d0407baSopenharmony_ci		if (ret < 0) {
11943d0407baSopenharmony_ci			dev_err(dev, "failed to register notifier for DCP\n");
11953d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
11963d0407baSopenharmony_ci						   &charge->cable_cg_nb);
11973d0407baSopenharmony_ci			return ret;
11983d0407baSopenharmony_ci		}
11993d0407baSopenharmony_ci
12003d0407baSopenharmony_ci		ret = extcon_register_notifier(edev, EXTCON_CHG_USB_CDP,
12013d0407baSopenharmony_ci					       &charge->cable_cg_nb);
12023d0407baSopenharmony_ci		if (ret < 0) {
12033d0407baSopenharmony_ci			dev_err(dev, "failed to register notifier for CDP\n");
12043d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
12053d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12063d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_DCP,
12073d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12083d0407baSopenharmony_ci			return ret;
12093d0407baSopenharmony_ci		}
12103d0407baSopenharmony_ci
12113d0407baSopenharmony_ci		/* Register host */
12123d0407baSopenharmony_ci		INIT_DELAYED_WORK(&charge->host_work,
12133d0407baSopenharmony_ci				  rk817_charge_host_evt_worker);
12143d0407baSopenharmony_ci		charge->cable_host_nb.notifier_call =
12153d0407baSopenharmony_ci			rk817_charge_host_evt_notifier;
12163d0407baSopenharmony_ci		ret = extcon_register_notifier(edev, EXTCON_USB_VBUS_EN,
12173d0407baSopenharmony_ci					       &charge->cable_host_nb);
12183d0407baSopenharmony_ci		if (ret < 0) {
12193d0407baSopenharmony_ci			dev_err(dev, "failed to register notifier for HOST\n");
12203d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
12213d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12223d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_DCP,
12233d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12243d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_CDP,
12253d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12263d0407baSopenharmony_ci
12273d0407baSopenharmony_ci			return ret;
12283d0407baSopenharmony_ci		}
12293d0407baSopenharmony_ci
12303d0407baSopenharmony_ci		/* Register discnt usb */
12313d0407baSopenharmony_ci		INIT_DELAYED_WORK(&charge->discnt_work,
12323d0407baSopenharmony_ci				  rk817_charge_discnt_evt_worker);
12333d0407baSopenharmony_ci		charge->cable_discnt_nb.notifier_call =
12343d0407baSopenharmony_ci			rk817_charge_discnt_evt_notfier;
12353d0407baSopenharmony_ci		ret = extcon_register_notifier(edev, EXTCON_USB,
12363d0407baSopenharmony_ci					       &charge->cable_discnt_nb);
12373d0407baSopenharmony_ci		if (ret < 0) {
12383d0407baSopenharmony_ci			dev_err(dev, "failed to register notifier for HOST\n");
12393d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
12403d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12413d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_DCP,
12423d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12433d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_CHG_USB_CDP,
12443d0407baSopenharmony_ci						   &charge->cable_cg_nb);
12453d0407baSopenharmony_ci			extcon_unregister_notifier(edev, EXTCON_USB_VBUS_EN,
12463d0407baSopenharmony_ci						   &charge->cable_host_nb);
12473d0407baSopenharmony_ci			return ret;
12483d0407baSopenharmony_ci		}
12493d0407baSopenharmony_ci
12503d0407baSopenharmony_ci		charge->cable_edev = edev;
12513d0407baSopenharmony_ci
12523d0407baSopenharmony_ci		DBG("register typec extcon evt notifier\n");
12533d0407baSopenharmony_ci	} else {
12543d0407baSopenharmony_ci		INIT_DELAYED_WORK(&charge->usb_work,
12553d0407baSopenharmony_ci				  rk817_charge_bc_evt_worker);
12563d0407baSopenharmony_ci		charge->bc_nb.notifier_call = rk817_charge_bc_evt_notifier;
12573d0407baSopenharmony_ci		ret = rk_bc_detect_notifier_register(&charge->bc_nb, &bc_type);
12583d0407baSopenharmony_ci		if (ret) {
12593d0407baSopenharmony_ci			dev_err(dev, "failed to register notifier for bc\n");
12603d0407baSopenharmony_ci			return -EINVAL;
12613d0407baSopenharmony_ci	}
12623d0407baSopenharmony_ci
12633d0407baSopenharmony_ci		switch (bc_type) {
12643d0407baSopenharmony_ci		case USB_BC_TYPE_DISCNT:
12653d0407baSopenharmony_ci			charger = USB_TYPE_NONE_CHARGER;
12663d0407baSopenharmony_ci			break;
12673d0407baSopenharmony_ci		case USB_BC_TYPE_SDP:
12683d0407baSopenharmony_ci		case USB_BC_TYPE_CDP:
12693d0407baSopenharmony_ci			charger = USB_TYPE_USB_CHARGER;
12703d0407baSopenharmony_ci			break;
12713d0407baSopenharmony_ci		case USB_BC_TYPE_DCP:
12723d0407baSopenharmony_ci			charger = USB_TYPE_AC_CHARGER;
12733d0407baSopenharmony_ci			break;
12743d0407baSopenharmony_ci		default:
12753d0407baSopenharmony_ci			charger = USB_TYPE_NONE_CHARGER;
12763d0407baSopenharmony_ci			break;
12773d0407baSopenharmony_ci		}
12783d0407baSopenharmony_ci
12793d0407baSopenharmony_ci		charge->usb_charger = charger;
12803d0407baSopenharmony_ci		if (charge->dc_charger != DC_TYPE_NONE_CHARGER)
12813d0407baSopenharmony_ci			rk817_charge_set_chrg_param(charge,
12823d0407baSopenharmony_ci						    charge->usb_charger);
12833d0407baSopenharmony_ci
12843d0407baSopenharmony_ci		DBG("register bc evt notifier\n");
12853d0407baSopenharmony_ci	}
12863d0407baSopenharmony_ci
12873d0407baSopenharmony_ci	return 0;
12883d0407baSopenharmony_ci}
12893d0407baSopenharmony_ci
12903d0407baSopenharmony_cistatic void rk817_charge_pre_init(struct rk817_charger *charge)
12913d0407baSopenharmony_ci{
12923d0407baSopenharmony_ci	charge->max_chrg_current = charge->pdata->max_chrg_current;
12933d0407baSopenharmony_ci	charge->max_input_current = charge->pdata->max_input_current;
12943d0407baSopenharmony_ci	charge->max_chrg_voltage = charge->pdata->max_chrg_voltage;
12953d0407baSopenharmony_ci	charge->min_input_voltage = charge->pdata->min_input_voltage;
12963d0407baSopenharmony_ci	charge->chrg_finish_cur = charge->pdata->chrg_finish_cur;
12973d0407baSopenharmony_ci	charge->chrg_term_mode = charge->pdata->chrg_term_mode;
12983d0407baSopenharmony_ci
12993d0407baSopenharmony_ci	rk817_charge_set_input_voltage(charge, charge->min_input_voltage);
13003d0407baSopenharmony_ci
13013d0407baSopenharmony_ci	rk817_charge_set_chrg_voltage(charge, charge->max_chrg_voltage);
13023d0407baSopenharmony_ci	rk817_charge_set_chrg_current(charge, charge->max_chrg_current);
13033d0407baSopenharmony_ci
13043d0407baSopenharmony_ci	rk817_charge_set_chrg_finish_condition(charge);
13053d0407baSopenharmony_ci
13063d0407baSopenharmony_ci	if (rk817_charge_get_otg_state(charge))
13073d0407baSopenharmony_ci		rk817_charge_otg_disable(charge);
13083d0407baSopenharmony_ci	rk817_charge_field_write(charge, OTG_EN, OTG_DISABLE);
13093d0407baSopenharmony_ci	rk817_charge_set_otg_in(charge, OFFLINE);
13103d0407baSopenharmony_ci
13113d0407baSopenharmony_ci	if (!charge->pdata->gate_function_disable)
13123d0407baSopenharmony_ci		rk817_charge_sys_can_sd_disable(charge);
13133d0407baSopenharmony_ci	rk817_charge_usb_to_sys_enable(charge);
13143d0407baSopenharmony_ci	rk817_charge_enable_charge(charge);
13153d0407baSopenharmony_ci
13163d0407baSopenharmony_ci	rk817_charge_set_charge_clock(charge, CHRG_CLK_2M);
13173d0407baSopenharmony_ci}
13183d0407baSopenharmony_ci
13193d0407baSopenharmony_cistatic void rk817_chage_debug(struct rk817_charger *charge)
13203d0407baSopenharmony_ci{
13213d0407baSopenharmony_ci	rk817_charge_get_charge_status(charge);
13223d0407baSopenharmony_ci	DBG("OTG state : %d\n", rk817_charge_get_otg_state(charge));
13233d0407baSopenharmony_ci	DBG("charge state: %d\n", rk817_charge_get_charge_state(charge));
13243d0407baSopenharmony_ci	DBG("max_chrg_current: %d\n"
13253d0407baSopenharmony_ci	    "max_input_current: %d\n"
13263d0407baSopenharmony_ci	    "min_input_voltage: %d\n"
13273d0407baSopenharmony_ci	    "max_chrg_voltage: %d\n"
13283d0407baSopenharmony_ci	    "max_chrg_finish_cur: %d\n"
13293d0407baSopenharmony_ci	    "chrg_term_mode: %d\n",
13303d0407baSopenharmony_ci	    charge->max_chrg_current,
13313d0407baSopenharmony_ci	    charge->max_input_current,
13323d0407baSopenharmony_ci	    charge->min_input_voltage,
13333d0407baSopenharmony_ci	    charge->max_chrg_voltage,
13343d0407baSopenharmony_ci	    charge->chrg_finish_cur,
13353d0407baSopenharmony_ci	    charge->chrg_term_mode);
13363d0407baSopenharmony_ci}
13373d0407baSopenharmony_ci
13383d0407baSopenharmony_cistatic int rk817_charge_get_otg5v_regulator(struct rk817_charger *charge)
13393d0407baSopenharmony_ci{
13403d0407baSopenharmony_ci	int ret;
13413d0407baSopenharmony_ci
13423d0407baSopenharmony_ci	charge->otg5v_rdev = devm_regulator_get(charge->dev, "otg_switch");
13433d0407baSopenharmony_ci	if (IS_ERR(charge->otg5v_rdev)) {
13443d0407baSopenharmony_ci		ret = PTR_ERR(charge->otg5v_rdev);
13453d0407baSopenharmony_ci		dev_warn(charge->dev, "failed to get otg regulator: %d\n", ret);
13463d0407baSopenharmony_ci	}
13473d0407baSopenharmony_ci
13483d0407baSopenharmony_ci	return 0;
13493d0407baSopenharmony_ci}
13503d0407baSopenharmony_ci
13513d0407baSopenharmony_ci#ifdef CONFIG_OF
13523d0407baSopenharmony_cistatic int rk817_charge_parse_dt(struct rk817_charger *charge)
13533d0407baSopenharmony_ci{
13543d0407baSopenharmony_ci	struct charger_platform_data *pdata;
13553d0407baSopenharmony_ci	enum of_gpio_flags flags;
13563d0407baSopenharmony_ci	struct device *dev = charge->dev;
13573d0407baSopenharmony_ci	struct device_node *np = charge->dev->of_node;
13583d0407baSopenharmony_ci	int ret;
13593d0407baSopenharmony_ci
13603d0407baSopenharmony_ci	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
13613d0407baSopenharmony_ci	if (!pdata)
13623d0407baSopenharmony_ci		return -ENOMEM;
13633d0407baSopenharmony_ci
13643d0407baSopenharmony_ci	charge->pdata = pdata;
13653d0407baSopenharmony_ci	pdata->max_chrg_current = DEFAULT_CHRG_CURRENT;
13663d0407baSopenharmony_ci	pdata->max_input_current = DEFAULT_INPUT_CURRENT;
13673d0407baSopenharmony_ci	pdata->max_chrg_voltage = DEFAULT_CHRG_VOLTAGE;
13683d0407baSopenharmony_ci	pdata->min_input_voltage = DEFAULT_INPUT_VOLTAGE;
13693d0407baSopenharmony_ci	pdata->chrg_finish_cur = DEFAULT_CHRG_TERM_CUR;
13703d0407baSopenharmony_ci	pdata->chrg_term_mode = DEFAULT_CHRG_TERM_MODE;
13713d0407baSopenharmony_ci
13723d0407baSopenharmony_ci	pdata->extcon = of_property_read_bool(np, "extcon");
13733d0407baSopenharmony_ci
13743d0407baSopenharmony_ci	ret = of_property_read_u32(np, "max_chrg_current",
13753d0407baSopenharmony_ci				   &pdata->max_chrg_current);
13763d0407baSopenharmony_ci	if (ret < 0)
13773d0407baSopenharmony_ci		dev_err(dev, "max_chrg_current missing!\n");
13783d0407baSopenharmony_ci
13793d0407baSopenharmony_ci	ret = of_property_read_u32(np, "max_input_current",
13803d0407baSopenharmony_ci				   &pdata->max_input_current);
13813d0407baSopenharmony_ci	if (ret < 0)
13823d0407baSopenharmony_ci		dev_err(dev, "max_input_current missing!\n");
13833d0407baSopenharmony_ci
13843d0407baSopenharmony_ci	ret = of_property_read_u32(np, "max_chrg_voltage",
13853d0407baSopenharmony_ci				   &pdata->max_chrg_voltage);
13863d0407baSopenharmony_ci	if (ret < 0)
13873d0407baSopenharmony_ci		dev_err(dev, "max_chrg_voltage missing!\n");
13883d0407baSopenharmony_ci
13893d0407baSopenharmony_ci	ret = of_property_read_u32(np, "min_input_voltage",
13903d0407baSopenharmony_ci				   &pdata->min_input_voltage);
13913d0407baSopenharmony_ci	if (ret < 0)
13923d0407baSopenharmony_ci		dev_WARN(dev, "min_input_voltage missing!\n");
13933d0407baSopenharmony_ci
13943d0407baSopenharmony_ci	ret = of_property_read_u32(np, "chrg_finish_cur",
13953d0407baSopenharmony_ci				   &pdata->chrg_finish_cur);
13963d0407baSopenharmony_ci
13973d0407baSopenharmony_ci	if (ret < 0)
13983d0407baSopenharmony_ci		dev_WARN(dev, "chrg_term_mode missing!\n");
13993d0407baSopenharmony_ci
14003d0407baSopenharmony_ci	ret = of_property_read_u32(np, "chrg_term_mode",
14013d0407baSopenharmony_ci				   &pdata->chrg_term_mode);
14023d0407baSopenharmony_ci	if (ret < 0)
14033d0407baSopenharmony_ci		dev_WARN(dev, "chrg_term_mode missing!\n");
14043d0407baSopenharmony_ci
14053d0407baSopenharmony_ci	ret = of_property_read_u32(np, "virtual_power", &pdata->virtual_power);
14063d0407baSopenharmony_ci	if (ret < 0)
14073d0407baSopenharmony_ci		dev_err(dev, "virtual_power missing!\n");
14083d0407baSopenharmony_ci
14093d0407baSopenharmony_ci	ret = of_property_read_u32(np, "power_dc2otg", &pdata->power_dc2otg);
14103d0407baSopenharmony_ci	if (ret < 0)
14113d0407baSopenharmony_ci		dev_err(dev, "power_dc2otg missing!\n");
14123d0407baSopenharmony_ci
14133d0407baSopenharmony_ci	ret = of_property_read_u32(np, "sample_res", &pdata->sample_res);
14143d0407baSopenharmony_ci	if (ret < 0) {
14153d0407baSopenharmony_ci		pdata->sample_res = SAMPLE_RES_10MR;
14163d0407baSopenharmony_ci		dev_err(dev, "sample_res missing!\n");
14173d0407baSopenharmony_ci	}
14183d0407baSopenharmony_ci
14193d0407baSopenharmony_ci	ret = of_property_read_u32(np, "otg5v_suspend_enable",
14203d0407baSopenharmony_ci				   &pdata->otg5v_suspend_enable);
14213d0407baSopenharmony_ci	if (ret < 0) {
14223d0407baSopenharmony_ci		pdata->otg5v_suspend_enable = 1;
14233d0407baSopenharmony_ci		dev_err(dev, "otg5v_suspend_enable missing!\n");
14243d0407baSopenharmony_ci	}
14253d0407baSopenharmony_ci
14263d0407baSopenharmony_ci	ret = of_property_read_u32(np, "gate_function_disable",
14273d0407baSopenharmony_ci				   &pdata->gate_function_disable);
14283d0407baSopenharmony_ci	if (ret < 0)
14293d0407baSopenharmony_ci		dev_err(dev, "gate_function_disable missing!\n");
14303d0407baSopenharmony_ci
14313d0407baSopenharmony_ci	if (!is_battery_exist(charge))
14323d0407baSopenharmony_ci		pdata->virtual_power = 1;
14333d0407baSopenharmony_ci
14343d0407baSopenharmony_ci	charge->res_div = (charge->pdata->sample_res == SAMPLE_RES_10MR) ?
14353d0407baSopenharmony_ci		       SAMPLE_RES_DIV1 : SAMPLE_RES_DIV2;
14363d0407baSopenharmony_ci
14373d0407baSopenharmony_ci	if (!of_find_property(np, "dc_det_gpio", &ret)) {
14383d0407baSopenharmony_ci		pdata->support_dc_det = false;
14393d0407baSopenharmony_ci		DBG("not support dc\n");
14403d0407baSopenharmony_ci	} else {
14413d0407baSopenharmony_ci		pdata->support_dc_det = true;
14423d0407baSopenharmony_ci		pdata->dc_det_pin = of_get_named_gpio_flags(np, "dc_det_gpio",
14433d0407baSopenharmony_ci							    0, &flags);
14443d0407baSopenharmony_ci		if (gpio_is_valid(pdata->dc_det_pin)) {
14453d0407baSopenharmony_ci			DBG("support dc\n");
14463d0407baSopenharmony_ci			pdata->dc_det_level = (flags & OF_GPIO_ACTIVE_LOW) ?
14473d0407baSopenharmony_ci					       0 : 1;
14483d0407baSopenharmony_ci		} else {
14493d0407baSopenharmony_ci			dev_err(dev, "invalid dc det gpio!\n");
14503d0407baSopenharmony_ci			return -EINVAL;
14513d0407baSopenharmony_ci		}
14523d0407baSopenharmony_ci	}
14533d0407baSopenharmony_ci
14543d0407baSopenharmony_ci	DBG("input_current:%d\n"
14553d0407baSopenharmony_ci		"input_min_voltage: %d\n"
14563d0407baSopenharmony_ci	    "chrg_current:%d\n"
14573d0407baSopenharmony_ci	    "chrg_voltage:%d\n"
14583d0407baSopenharmony_ci	    "sample_res:%d\n"
14593d0407baSopenharmony_ci	    "extcon:%d\n"
14603d0407baSopenharmony_ci	    "virtual_power:%d\n"
14613d0407baSopenharmony_ci	    "power_dc2otg:%d\n",
14623d0407baSopenharmony_ci	    pdata->max_input_current, pdata->min_input_voltage,
14633d0407baSopenharmony_ci	    pdata->max_chrg_current,  pdata->max_chrg_voltage,
14643d0407baSopenharmony_ci	    pdata->sample_res, pdata->extcon,
14653d0407baSopenharmony_ci	    pdata->virtual_power, pdata->power_dc2otg);
14663d0407baSopenharmony_ci
14673d0407baSopenharmony_ci	return 0;
14683d0407baSopenharmony_ci}
14693d0407baSopenharmony_ci#else
14703d0407baSopenharmony_cistatic int rk817_charge_parse_dt(struct rk817_charger *charge)
14713d0407baSopenharmony_ci{
14723d0407baSopenharmony_ci	return -ENODEV;
14733d0407baSopenharmony_ci}
14743d0407baSopenharmony_ci#endif
14753d0407baSopenharmony_ci
14763d0407baSopenharmony_cistatic void rk817_charge_irq_delay_work(struct work_struct *work)
14773d0407baSopenharmony_ci{
14783d0407baSopenharmony_ci	struct rk817_charger *charge = container_of(work,
14793d0407baSopenharmony_ci			struct rk817_charger, irq_work.work);
14803d0407baSopenharmony_ci
14813d0407baSopenharmony_ci	if (charge->plugin_trigger) {
14823d0407baSopenharmony_ci		DBG("pmic: plug in\n");
14833d0407baSopenharmony_ci		charge->plugin_trigger = 0;
14843d0407baSopenharmony_ci		if (charge->pdata->extcon)
14853d0407baSopenharmony_ci			queue_delayed_work(charge->usb_charger_wq, &charge->usb_work,
14863d0407baSopenharmony_ci					   msecs_to_jiffies(10));
14873d0407baSopenharmony_ci	} else if (charge->plugout_trigger) {
14883d0407baSopenharmony_ci		DBG("pmic: plug out\n");
14893d0407baSopenharmony_ci		charge->plugout_trigger = 0;
14903d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, USB_TYPE_NONE_CHARGER);
14913d0407baSopenharmony_ci		rk817_charge_set_chrg_param(charge, DC_TYPE_NONE_CHARGER);
14923d0407baSopenharmony_ci	} else {
14933d0407baSopenharmony_ci		DBG("pmic: unknown irq\n");
14943d0407baSopenharmony_ci	}
14953d0407baSopenharmony_ci}
14963d0407baSopenharmony_ci
14973d0407baSopenharmony_cistatic irqreturn_t rk817_plug_in_isr(int irq, void *cg)
14983d0407baSopenharmony_ci{
14993d0407baSopenharmony_ci	struct rk817_charger *charge;
15003d0407baSopenharmony_ci
15013d0407baSopenharmony_ci	charge = (struct rk817_charger *)cg;
15023d0407baSopenharmony_ci	charge->plugin_trigger = 1;
15033d0407baSopenharmony_ci	queue_delayed_work(charge->usb_charger_wq, &charge->irq_work,
15043d0407baSopenharmony_ci			   msecs_to_jiffies(10));
15053d0407baSopenharmony_ci
15063d0407baSopenharmony_ci	return IRQ_HANDLED;
15073d0407baSopenharmony_ci}
15083d0407baSopenharmony_ci
15093d0407baSopenharmony_cistatic irqreturn_t rk817_plug_out_isr(int irq, void *cg)
15103d0407baSopenharmony_ci{
15113d0407baSopenharmony_ci	struct rk817_charger *charge;
15123d0407baSopenharmony_ci
15133d0407baSopenharmony_ci	charge = (struct rk817_charger *)cg;
15143d0407baSopenharmony_ci	charge->plugout_trigger = 1;
15153d0407baSopenharmony_ci	queue_delayed_work(charge->usb_charger_wq, &charge->irq_work,
15163d0407baSopenharmony_ci			   msecs_to_jiffies(10));
15173d0407baSopenharmony_ci
15183d0407baSopenharmony_ci	return IRQ_HANDLED;
15193d0407baSopenharmony_ci}
15203d0407baSopenharmony_ci
15213d0407baSopenharmony_cistatic int rk817_charge_init_irqs(struct rk817_charger *charge)
15223d0407baSopenharmony_ci{
15233d0407baSopenharmony_ci	struct rk808 *rk817 = charge->rk817;
15243d0407baSopenharmony_ci	struct platform_device *pdev = charge->pdev;
15253d0407baSopenharmony_ci	int ret, plug_in_irq, plug_out_irq;
15263d0407baSopenharmony_ci
15273d0407baSopenharmony_ci	plug_in_irq = regmap_irq_get_virq(rk817->irq_data, RK817_IRQ_PLUG_IN);
15283d0407baSopenharmony_ci	if (plug_in_irq < 0) {
15293d0407baSopenharmony_ci		dev_err(charge->dev, "plug_in_irq request failed!\n");
15303d0407baSopenharmony_ci		return plug_in_irq;
15313d0407baSopenharmony_ci	}
15323d0407baSopenharmony_ci
15333d0407baSopenharmony_ci	plug_out_irq = regmap_irq_get_virq(rk817->irq_data, RK817_IRQ_PLUG_OUT);
15343d0407baSopenharmony_ci	if (plug_out_irq < 0) {
15353d0407baSopenharmony_ci		dev_err(charge->dev, "plug_out_irq request failed!\n");
15363d0407baSopenharmony_ci		return plug_out_irq;
15373d0407baSopenharmony_ci	}
15383d0407baSopenharmony_ci
15393d0407baSopenharmony_ci	ret = devm_request_threaded_irq(charge->dev, plug_in_irq, NULL,
15403d0407baSopenharmony_ci					rk817_plug_in_isr,
15413d0407baSopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
15423d0407baSopenharmony_ci					"rk817_plug_in", charge);
15433d0407baSopenharmony_ci	if (ret) {
15443d0407baSopenharmony_ci		dev_err(&pdev->dev, "plug_in_irq request failed!\n");
15453d0407baSopenharmony_ci		return ret;
15463d0407baSopenharmony_ci	}
15473d0407baSopenharmony_ci
15483d0407baSopenharmony_ci	ret = devm_request_threaded_irq(charge->dev, plug_out_irq, NULL,
15493d0407baSopenharmony_ci					rk817_plug_out_isr,
15503d0407baSopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
15513d0407baSopenharmony_ci					"rk817_plug_out", charge);
15523d0407baSopenharmony_ci	if (ret) {
15533d0407baSopenharmony_ci		dev_err(&pdev->dev, "plug_out_irq request failed!\n");
15543d0407baSopenharmony_ci		return ret;
15553d0407baSopenharmony_ci	}
15563d0407baSopenharmony_ci
15573d0407baSopenharmony_ci	charge->plugin_irq = plug_in_irq;
15583d0407baSopenharmony_ci	charge->plugout_irq = plug_out_irq;
15593d0407baSopenharmony_ci
15603d0407baSopenharmony_ci	INIT_DELAYED_WORK(&charge->irq_work, rk817_charge_irq_delay_work);
15613d0407baSopenharmony_ci
15623d0407baSopenharmony_ci	return 0;
15633d0407baSopenharmony_ci}
15643d0407baSopenharmony_ci
15653d0407baSopenharmony_cistatic const struct of_device_id rk817_charge_of_match[] = {
15663d0407baSopenharmony_ci	{ .compatible = "rk817,charger", },
15673d0407baSopenharmony_ci	{ },
15683d0407baSopenharmony_ci};
15693d0407baSopenharmony_ci
15703d0407baSopenharmony_cistatic int rk817_charge_probe(struct platform_device *pdev)
15713d0407baSopenharmony_ci{
15723d0407baSopenharmony_ci	struct rk808 *rk817 = dev_get_drvdata(pdev->dev.parent);
15733d0407baSopenharmony_ci	const struct of_device_id *of_id =
15743d0407baSopenharmony_ci			of_match_device(rk817_charge_of_match, &pdev->dev);
15753d0407baSopenharmony_ci	struct i2c_client *client = rk817->i2c;
15763d0407baSopenharmony_ci	struct rk817_charger *charge;
15773d0407baSopenharmony_ci	int i;
15783d0407baSopenharmony_ci	int ret;
15793d0407baSopenharmony_ci
15803d0407baSopenharmony_ci	if (!of_id) {
15813d0407baSopenharmony_ci		dev_err(&pdev->dev, "Failed to find matching dt id\n");
15823d0407baSopenharmony_ci		return -ENODEV;
15833d0407baSopenharmony_ci	}
15843d0407baSopenharmony_ci
15853d0407baSopenharmony_ci	charge = devm_kzalloc(&pdev->dev, sizeof(*charge), GFP_KERNEL);
15863d0407baSopenharmony_ci	if (!charge)
15873d0407baSopenharmony_ci		return -EINVAL;
15883d0407baSopenharmony_ci
15893d0407baSopenharmony_ci	charge->rk817 = rk817;
15903d0407baSopenharmony_ci	charge->pdev = pdev;
15913d0407baSopenharmony_ci	charge->dev = &pdev->dev;
15923d0407baSopenharmony_ci	charge->client = client;
15933d0407baSopenharmony_ci	platform_set_drvdata(pdev, charge);
15943d0407baSopenharmony_ci
15953d0407baSopenharmony_ci	charge->regmap = rk817->regmap;
15963d0407baSopenharmony_ci	if (IS_ERR(charge->regmap)) {
15973d0407baSopenharmony_ci		dev_err(charge->dev, "Failed to initialize regmap\n");
15983d0407baSopenharmony_ci		return -EINVAL;
15993d0407baSopenharmony_ci	}
16003d0407baSopenharmony_ci
16013d0407baSopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rk817_charge_reg_fields); i++) {
16023d0407baSopenharmony_ci		const struct reg_field *reg_fields = rk817_charge_reg_fields;
16033d0407baSopenharmony_ci
16043d0407baSopenharmony_ci		charge->rmap_fields[i] =
16053d0407baSopenharmony_ci			devm_regmap_field_alloc(charge->dev,
16063d0407baSopenharmony_ci						charge->regmap,
16073d0407baSopenharmony_ci						reg_fields[i]);
16083d0407baSopenharmony_ci		if (IS_ERR(charge->rmap_fields[i])) {
16093d0407baSopenharmony_ci			dev_err(charge->dev, "cannot allocate regmap field\n");
16103d0407baSopenharmony_ci			return PTR_ERR(charge->rmap_fields[i]);
16113d0407baSopenharmony_ci		}
16123d0407baSopenharmony_ci	}
16133d0407baSopenharmony_ci
16143d0407baSopenharmony_ci	ret = rk817_charge_parse_dt(charge);
16153d0407baSopenharmony_ci	if (ret < 0) {
16163d0407baSopenharmony_ci		dev_err(charge->dev, "charge parse dt failed!\n");
16173d0407baSopenharmony_ci		return ret;
16183d0407baSopenharmony_ci	}
16193d0407baSopenharmony_ci	rk817_charge_get_otg5v_regulator(charge);
16203d0407baSopenharmony_ci
16213d0407baSopenharmony_ci	rk817_charge_pre_init(charge);
16223d0407baSopenharmony_ci
16233d0407baSopenharmony_ci	ret = rk817_charge_init_power_supply(charge);
16243d0407baSopenharmony_ci	if (ret) {
16253d0407baSopenharmony_ci		dev_err(charge->dev, "init power supply fail!\n");
16263d0407baSopenharmony_ci		return ret;
16273d0407baSopenharmony_ci	}
16283d0407baSopenharmony_ci
16293d0407baSopenharmony_ci	ret = rk817_charge_init_dc(charge);
16303d0407baSopenharmony_ci	if (ret) {
16313d0407baSopenharmony_ci		dev_err(charge->dev, "init dc failed!\n");
16323d0407baSopenharmony_ci		return ret;
16333d0407baSopenharmony_ci	}
16343d0407baSopenharmony_ci
16353d0407baSopenharmony_ci	ret = rk817_charge_usb_init(charge);
16363d0407baSopenharmony_ci	if (ret) {
16373d0407baSopenharmony_ci		dev_err(charge->dev, "init usb failed!\n");
16383d0407baSopenharmony_ci		return ret;
16393d0407baSopenharmony_ci	}
16403d0407baSopenharmony_ci
16413d0407baSopenharmony_ci	ret = rk817_charge_init_irqs(charge);
16423d0407baSopenharmony_ci	if (ret) {
16433d0407baSopenharmony_ci		dev_err(charge->dev, "init irqs failed!\n");
16443d0407baSopenharmony_ci		goto irq_fail;
16453d0407baSopenharmony_ci	}
16463d0407baSopenharmony_ci
16473d0407baSopenharmony_ci	if (charge->pdata->extcon) {
16483d0407baSopenharmony_ci		schedule_delayed_work(&charge->host_work, 0);
16493d0407baSopenharmony_ci		schedule_delayed_work(&charge->usb_work, 0);
16503d0407baSopenharmony_ci	}
16513d0407baSopenharmony_ci
16523d0407baSopenharmony_ci	rk817_chage_debug(charge);
16533d0407baSopenharmony_ci	DBG("driver version: %s\n", CHARGE_DRIVER_VERSION);
16543d0407baSopenharmony_ci
16553d0407baSopenharmony_ci	return 0;
16563d0407baSopenharmony_ciirq_fail:
16573d0407baSopenharmony_ci	if (charge->pdata->extcon) {
16583d0407baSopenharmony_ci		cancel_delayed_work_sync(&charge->host_work);
16593d0407baSopenharmony_ci		cancel_delayed_work_sync(&charge->discnt_work);
16603d0407baSopenharmony_ci	}
16613d0407baSopenharmony_ci
16623d0407baSopenharmony_ci	cancel_delayed_work_sync(&charge->usb_work);
16633d0407baSopenharmony_ci	cancel_delayed_work_sync(&charge->dc_work);
16643d0407baSopenharmony_ci	cancel_delayed_work_sync(&charge->irq_work);
16653d0407baSopenharmony_ci	destroy_workqueue(charge->usb_charger_wq);
16663d0407baSopenharmony_ci	destroy_workqueue(charge->dc_charger_wq);
16673d0407baSopenharmony_ci
16683d0407baSopenharmony_ci	if (charge->pdata->extcon) {
16693d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
16703d0407baSopenharmony_ci					   EXTCON_CHG_USB_SDP,
16713d0407baSopenharmony_ci					   &charge->cable_cg_nb);
16723d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
16733d0407baSopenharmony_ci					   EXTCON_CHG_USB_DCP,
16743d0407baSopenharmony_ci					   &charge->cable_cg_nb);
16753d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
16763d0407baSopenharmony_ci					   EXTCON_CHG_USB_CDP,
16773d0407baSopenharmony_ci					   &charge->cable_cg_nb);
16783d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
16793d0407baSopenharmony_ci					   EXTCON_USB_VBUS_EN,
16803d0407baSopenharmony_ci					   &charge->cable_host_nb);
16813d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
16823d0407baSopenharmony_ci					   EXTCON_USB,
16833d0407baSopenharmony_ci					   &charge->cable_discnt_nb);
16843d0407baSopenharmony_ci	} else {
16853d0407baSopenharmony_ci		rk_bc_detect_notifier_unregister(&charge->bc_nb);
16863d0407baSopenharmony_ci	}
16873d0407baSopenharmony_ci
16883d0407baSopenharmony_ci	return ret;
16893d0407baSopenharmony_ci}
16903d0407baSopenharmony_ci
16913d0407baSopenharmony_ci#ifdef CONFIG_PM_SLEEP
16923d0407baSopenharmony_cistatic int  rk817_charge_pm_suspend(struct device *dev)
16933d0407baSopenharmony_ci{
16943d0407baSopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
16953d0407baSopenharmony_ci	struct rk817_charger *charge = dev_get_drvdata(&pdev->dev);
16963d0407baSopenharmony_ci
16973d0407baSopenharmony_ci	charge->otg_slp_state = rk817_charge_get_otg_slp_state(charge);
16983d0407baSopenharmony_ci
16993d0407baSopenharmony_ci	/* enable sleep boost5v and otg5v */
17003d0407baSopenharmony_ci	if (charge->pdata->otg5v_suspend_enable) {
17013d0407baSopenharmony_ci		if ((charge->otg_in && !charge->dc_in) ||
17023d0407baSopenharmony_ci		    (charge->otg_in && charge->dc_in &&
17033d0407baSopenharmony_ci		    !charge->pdata->power_dc2otg)) {
17043d0407baSopenharmony_ci			rk817_charge_otg_slp_enable(charge);
17053d0407baSopenharmony_ci			DBG("suspend: otg 5v on\n");
17063d0407baSopenharmony_ci			return 0;
17073d0407baSopenharmony_ci		}
17083d0407baSopenharmony_ci	}
17093d0407baSopenharmony_ci
17103d0407baSopenharmony_ci	/* disable sleep otg5v */
17113d0407baSopenharmony_ci	rk817_charge_otg_slp_disable(charge);
17123d0407baSopenharmony_ci	DBG("suspend: otg 5v off\n");
17133d0407baSopenharmony_ci	return 0;
17143d0407baSopenharmony_ci}
17153d0407baSopenharmony_ci
17163d0407baSopenharmony_cistatic int rk817_charge_pm_resume(struct device *dev)
17173d0407baSopenharmony_ci{
17183d0407baSopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
17193d0407baSopenharmony_ci	struct rk817_charger *charge = dev_get_drvdata(&pdev->dev);
17203d0407baSopenharmony_ci
17213d0407baSopenharmony_ci	/* resume sleep boost5v and otg5v */
17223d0407baSopenharmony_ci	if (charge->otg_slp_state)
17233d0407baSopenharmony_ci		rk817_charge_otg_slp_enable(charge);
17243d0407baSopenharmony_ci
17253d0407baSopenharmony_ci	return 0;
17263d0407baSopenharmony_ci}
17273d0407baSopenharmony_ci#endif
17283d0407baSopenharmony_cistatic SIMPLE_DEV_PM_OPS(rk817_charge_pm_ops,
17293d0407baSopenharmony_ci	rk817_charge_pm_suspend, rk817_charge_pm_resume);
17303d0407baSopenharmony_ci
17313d0407baSopenharmony_cistatic void rk817_charger_shutdown(struct platform_device *dev)
17323d0407baSopenharmony_ci{
17333d0407baSopenharmony_ci	struct rk817_charger *charge =  platform_get_drvdata(dev);
17343d0407baSopenharmony_ci
17353d0407baSopenharmony_ci	/* type-c only */
17363d0407baSopenharmony_ci	if (charge->pdata->extcon) {
17373d0407baSopenharmony_ci		cancel_delayed_work_sync(&charge->host_work);
17383d0407baSopenharmony_ci		cancel_delayed_work_sync(&charge->discnt_work);
17393d0407baSopenharmony_ci	}
17403d0407baSopenharmony_ci
17413d0407baSopenharmony_ci	rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
17423d0407baSopenharmony_ci	rk817_charge_boost_disable(charge);
17433d0407baSopenharmony_ci	disable_irq(charge->plugin_irq);
17443d0407baSopenharmony_ci	disable_irq(charge->plugout_irq);
17453d0407baSopenharmony_ci
17463d0407baSopenharmony_ci	cancel_delayed_work_sync(&charge->usb_work);
17473d0407baSopenharmony_ci	cancel_delayed_work_sync(&charge->dc_work);
17483d0407baSopenharmony_ci	cancel_delayed_work_sync(&charge->irq_work);
17493d0407baSopenharmony_ci	flush_workqueue(charge->usb_charger_wq);
17503d0407baSopenharmony_ci	flush_workqueue(charge->dc_charger_wq);
17513d0407baSopenharmony_ci
17523d0407baSopenharmony_ci	if (charge->pdata->extcon) {
17533d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
17543d0407baSopenharmony_ci					   EXTCON_CHG_USB_SDP,
17553d0407baSopenharmony_ci					   &charge->cable_cg_nb);
17563d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
17573d0407baSopenharmony_ci					   EXTCON_CHG_USB_DCP,
17583d0407baSopenharmony_ci					   &charge->cable_cg_nb);
17593d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
17603d0407baSopenharmony_ci					   EXTCON_CHG_USB_CDP,
17613d0407baSopenharmony_ci					   &charge->cable_cg_nb);
17623d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev,
17633d0407baSopenharmony_ci					   EXTCON_USB_VBUS_EN,
17643d0407baSopenharmony_ci					   &charge->cable_host_nb);
17653d0407baSopenharmony_ci		extcon_unregister_notifier(charge->cable_edev, EXTCON_USB,
17663d0407baSopenharmony_ci					   &charge->cable_discnt_nb);
17673d0407baSopenharmony_ci	} else {
17683d0407baSopenharmony_ci		rk_bc_detect_notifier_unregister(&charge->bc_nb);
17693d0407baSopenharmony_ci	}
17703d0407baSopenharmony_ci
17713d0407baSopenharmony_ci	DBG("shutdown: ac=%d usb=%d dc=%d otg=%d\n",
17723d0407baSopenharmony_ci	    charge->ac_in, charge->usb_in, charge->dc_in, charge->otg_in);
17733d0407baSopenharmony_ci}
17743d0407baSopenharmony_ci
17753d0407baSopenharmony_cistatic struct platform_driver rk817_charge_driver = {
17763d0407baSopenharmony_ci	.probe = rk817_charge_probe,
17773d0407baSopenharmony_ci	.shutdown = rk817_charger_shutdown,
17783d0407baSopenharmony_ci	.driver = {
17793d0407baSopenharmony_ci		.name = "rk817-charger",
17803d0407baSopenharmony_ci		.pm = &rk817_charge_pm_ops,
17813d0407baSopenharmony_ci		.of_match_table = of_match_ptr(rk817_charge_of_match),
17823d0407baSopenharmony_ci	},
17833d0407baSopenharmony_ci};
17843d0407baSopenharmony_ci
17853d0407baSopenharmony_cistatic int __init rk817_charge_init(void)
17863d0407baSopenharmony_ci{
17873d0407baSopenharmony_ci	return platform_driver_register(&rk817_charge_driver);
17883d0407baSopenharmony_ci}
17893d0407baSopenharmony_cifs_initcall_sync(rk817_charge_init);
17903d0407baSopenharmony_ci
17913d0407baSopenharmony_cistatic void __exit rk817_charge_exit(void)
17923d0407baSopenharmony_ci{
17933d0407baSopenharmony_ci	platform_driver_unregister(&rk817_charge_driver);
17943d0407baSopenharmony_ci}
17953d0407baSopenharmony_cimodule_exit(rk817_charge_exit);
17963d0407baSopenharmony_ci
17973d0407baSopenharmony_ciMODULE_DESCRIPTION("RK817 Charge driver");
17983d0407baSopenharmony_ciMODULE_LICENSE("GPL");
1799