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