charging hw bq25601充电驱动笔记

#include "../bq25601.h"/* ============================================================ // */
/* Define */
/* ============================================================ // */
#define STATUS_OK   0
#define STATUS_FAIL 1
#define STATUS_UNSUPPORTED  -1
#define GETARRAYNUM(array) (sizeof(array)/sizeof(array[0]))/* ============================================================ // */
/* Global variable */
/* ============================================================ // */const unsigned int VBAT_CV_VTH[] = {//充电电压(下面调用函数会获取最接近的充电电压)3856000, 3888000, 3920000, 3952000,3984000, 4016000, 4048000, 4080000,4112000, 4144000, 4176000, 4208000,4240000, 4272000, 4304000, 4336000,4368000, 4400000, 4432000, 4464000,4496000, 4528000, 4560000, 4592000,4624000
};const unsigned int CS_VTH[] = { //充电电流(下面调用函数会获取最接近的充电电流)0,6000, 12000, 18000, 24000,30000, 36000, 42000, 48000,54000, 60000, 66000, 72000,78000, 84000, 90000, 96000,102000, 108000, 114000, 120000,126000, 132000, 138000, 144000,150000, 156000, 162000, 168000,174000, 180000, 186000, 192000,198000, 204000, 210000, 216000, 222000, 228000, 234000, 240000, 246000, 252000, 258000, 264000,270000, 276000, 282000, 288000, 294000, 300000
};const unsigned int INPUT_CS_VTH[] = {//输入电流(下面调用函数会获取最接近的输入电流)10000, 20000, 30000, 40000,50000, 60000, 70000, 80000,90000, 100000, 110000, 120000,130000, 140000, 150000, 160000, 170000, 180000, 190000, 200000,210000, 220000, 230000, 240000,250000, 260000, 270000, 280000,290000, 300000, 310000, 320000, CHARGE_CURRENT_MAX
};const unsigned int VCDT_HV_VTH[] = {高压检测的时的电压 (下面调用函数会获取最接近的高压检测的时的电压,pmic最高支持10.5V的充电电压,超过10.5V会停止充电或者不使能pmic的高压检测功能在static unsigned int charging_hw_init(void *data)函数中加上   pmic_set_register_value(PMIC_RG_VCDT_HV_EN, 0);Pmic high pressure detection is not enabled*/)BATTERY_VOLT_04_200000_V, BATTERY_VOLT_04_250000_V, BATTERY_VOLT_04_300000_V,BATTERY_VOLT_04_350000_V,BATTERY_VOLT_04_400000_V, BATTERY_VOLT_04_450000_V, BATTERY_VOLT_04_500000_V,BATTERY_VOLT_04_550000_V,BATTERY_VOLT_04_600000_V, BATTERY_VOLT_06_000000_V, BATTERY_VOLT_06_500000_V,BATTERY_VOLT_07_000000_V,BATTERY_VOLT_07_500000_V, BATTERY_VOLT_08_500000_V, BATTERY_VOLT_09_500000_V,BATTERY_VOLT_10_500000_V
};#ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT
#ifndef CUST_GPIO_VIN_SEL
#define CUST_GPIO_VIN_SEL 18
#endif
#if !defined(MTK_AUXADC_IRQ_SUPPORT)
#define SW_POLLING_PERIOD 100   /* 100 ms */
#define MSEC_TO_NSEC(x)     (x * 1000000UL)static DEFINE_MUTEX(diso_polling_mutex);
static DECLARE_WAIT_QUEUE_HEAD(diso_polling_thread_wq);
static struct hrtimer diso_kthread_timer;
static kal_bool diso_thread_timeout = KAL_FALSE;
static struct delayed_work diso_polling_work;
static void diso_polling_handler(struct work_struct *work);
static DISO_Polling_Data DISO_Polling;
#endif
int g_diso_state = 0;
int vin_sel_gpio_number = (CUST_GPIO_VIN_SEL | 0x80000000);static char *DISO_state_s[8] = {"IDLE","OTG_ONLY","USB_ONLY","USB_WITH_OTG","DC_ONLY","DC_WITH_OTG","DC_WITH_USB","DC_USB_OTG",
};
#endif/* ============================================================ // */
/* function prototype 函数原型*/
/* ============================================================ // *//* ============================================================ // */
/* extern variable 外部变量*/
/* ============================================================ // *//* ============================================================ // */
/* extern function 外部函数*/
/* ============================================================ // */
static unsigned int charging_error;
static unsigned int charging_get_error_state(void);
static unsigned int charging_set_error_state(void *data);
/* ============================================================ // */
unsigned int charging_value_to_parameter(const unsigned int *parameter, const unsigned int array_size,const unsigned int val) //充电值到参数
{unsigned int temp_param;if (val < array_size) {temp_param = parameter[val];} else {battery_log(BAT_LOG_CRTI, "Can't find the parameter \r\n");temp_param = parameter[0];}return temp_param;
}unsigned int charging_parameter_to_value(const unsigned int *parameter, const unsigned int array_size,const unsigned int val)//充电参数至值
{unsigned int i;battery_log(BAT_LOG_FULL, "array_size = %d \r\n", array_size);for (i = 0; i < array_size; i++) {if (val == *(parameter + i))return i;}battery_log(BAT_LOG_CRTI, "NO register value match. val=%d\r\n", val);return 0;
}static unsigned int bmt_find_closest_level(const unsigned int *pList, unsigned int number,unsigned int level) //bmt找到最接近的水平
{unsigned int i, temp_param;unsigned int max_value_in_last_element;if (pList[0] < pList[1])max_value_in_last_element = KAL_TRUE;elsemax_value_in_last_element = KAL_FALSE;if (max_value_in_last_element == KAL_TRUE) {/* max value in the last element 最后一个元素的最大值 */for (i = (number - 1); i != 0; i--)    {if (pList[i] <= level)return pList[i];}battery_log(BAT_LOG_CRTI, "Can't find closest level, small value first \r\n");temp_param = pList[0];} else {/* max value in the first element 第一个元素的最大值*/for (i = 0; i < number; i++) {if (pList[i] <= level)return pList[i];}battery_log(BAT_LOG_CRTI, "Can't find closest level, large value first \r\n");temp_param = pList[number - 1];}return temp_param;
}static unsigned int charging_hw_init(void *data) //充电硬件初始化
{//一些寄存器的初始化unsigned int status = STATUS_OK;bq25601_set_en_hiz(0x0);bq25601_set_vindpm(0x5); //VIN DPM check 4.4V  //VIN DPM 核对是否是4.4Vbq25601_set_reg_rst(0x0);bq25601_set_wdt_rst(0x1); //Kick watchdog 复位看门狗bq25601_set_sys_min(0x4); //Minimum system voltage 3.4V     设置最小系统电压是3.4Vbq25601_set_iprechg(0x7);  //Precharge current 480mA  预先充电电流  480mAbq25601_set_iterm(0x4);    //Termination current 240mA 终止充电电流 240mA if (batt_cust_data.high_battery_voltage_support)  //如果支持高压 bq25601_set_vreg(0xF);  /* VREG 4.352V(4336) */ 调整电压 4.352Velsebq25601_set_vreg(0xB); /* VREG 4.208V */否则调整电压 4.208Vbq25601_set_min_vbat_sel(0x0); //BATLOWV 2.8V 设置低压 2.8Vbq25601_set_vrechg(0x0); //VRECHG 0.1V (4.108V)  VRECHG:以及再充电阈值 4.108Vbq25601_set_en_term(0x1); //Enable termination 停止使能bq25601_set_watchdog(0x1); //WDT 40s 监视定时器 40Sbq25601_set_en_timer(0x0); //Disable charge timer 禁用充电定时器bq25601_set_ovp(0x0); //0x01//Battery overvoltage Protection 6.5v 电池过电压保护 6.5V//bq25601_set_boostv(0x2); //Boost Regulation Voltage 5.15v  提高调节电压  5.15v bq25601_set_vindpm_int_mask(0x0); //Mask VINDPM INT pulse 屏蔽VINDPM INT脉冲bq25601_set_iindpm_int_mask(0x0); //Mask IINDPM INT pulse 屏蔽IINDPM INT脉冲bq25601_set_batfet_rst_en(0x0); //复位使能
#ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT //如果支持双攻充电输入mt_set_gpio_mode(vin_sel_gpio_number, 0);  /* 0:GPIO mode */  设置GPIO模式mt_set_gpio_dir(vin_sel_gpio_number, 0); /* 0: input, 1: output */ 设置输入模式
#endifreturn status;
}static unsigned int charging_dump_register(void *data) //遍历读取bq25601所有保存在寄存器的值
{battery_log(BAT_LOG_FULL, "charging_dump_register\r\n");bq25601_dump_register();return STATUS_OK;
}void bq25601_dump_register(void)//读bq25601所有保存在寄存器的值
{int i = 0;battery_log(BAT_LOG_FULL, "[bq25601] ");for (i = 0; i < bq25601_REG_NUM; i++) {bq25601_read_byte(i, &bq25601_reg[i]);battery_log(BAT_LOG_CRTI, "bq25601_reg[0x%x]=0x%x\n", i, bq25601_reg[i]);}battery_log(BAT_LOG_FULL, "\n");
}static unsigned int charging_enable(void *data) //充电使能
{unsigned int status = STATUS_OK;unsigned int enable = *(unsigned int *) (data); //强制类型转换成 unsigned int unsigned int bootmode = 0;printk("1111charging_enable\r\n");if (KAL_TRUE == enable) {如果传进来的值为1bq25601_set_en_hiz(0x0);bq25601_set_chg_config(0x1);   /* charger enable *///充电使能} else {否侧
#if defined(CONFIG_USB_MTK_HDRC_HCD) //如果定义usb这个宏if (mt_usb_is_device()) {
#endifbq25601_set_chg_config(0x0); //充电失能if (charging_get_error_state()) { //返回一个错误状态battery_log(BAT_LOG_CRTI, "[charging_enable] bq25601_set_en_hiz(0x1)\n");bq25601_set_en_hiz(0x1);    /* disable power path */ 启用HIZ模式0-禁用(默认)1-启用}
#if defined(CONFIG_USB_MTK_HDRC_HCD) //如果定义usb这个宏}
#endifbootmode = get_boot_mode(); //获取boot这个状态if ((bootmode == META_BOOT) || (bootmode == ADVMETA_BOOT))bq25601_set_en_hiz(0x1); // 启用HIZ模式0-禁用(默认)1-启用#if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)bq25601_set_chg_config(0x0);  //0-电荷禁用1-电荷启用 默认:充电电池(1)  注意:1 在电荷cE引脚在拉低和chg_config是1这两种情况下,电荷启用。bq25601_set_en_hiz(0x1);  /* disable power path */启用HIZ模式0-禁用(默认)1-启用
#endif}return status;
}static unsigned int charging_set_cv_voltage(void *data) //设置工作电压
{unsigned int status = STATUS_OK;unsigned int array_size;unsigned int set_cv_voltage;unsigned short register_value;unsigned int cv_value = *(unsigned int *) (data);static short pre_register_value = -1;if (batt_cust_data.high_battery_voltage_support) {cv_value = 4352000;}/* use nearest value 使用最近的值 */ if (BATTERY_VOLT_04_200000_V == cv_value)cv_value = 4208000;array_size = GETARRAYNUM(VBAT_CV_VTH); //获取vth数组个数set_cv_voltage = bmt_find_closest_level(VBAT_CV_VTH, array_size, cv_value); //bmt找到最接近的水平register_value = charging_parameter_to_value(VBAT_CV_VTH, array_size, set_cv_voltage); //充电参数转化成值bq25601_set_vreg(register_value);
/*  Tg |512 mV T |256 mV | 128 mV gT64 mVgT 32 mV g
充电电压抵消:3.856 V范围:3.856 V至4.624 V (11000)
默认值:4.208 V (01011)特殊的价值:(01111):4.352 V注:超过11000 (4.624 V)的值夹紧,注册值11000 (4.624 V) *//* for jeita recharging issue 为jeita充电问题 */if (pre_register_value != register_value)bq25601_set_chg_config(1);  //0-电荷禁用1-电荷启用 默认:充电电池(1)  //注意:1 在电荷cE引脚在拉低和chg_config是1这两种情况下,电荷启用。pre_register_value = register_value;return status;
}static unsigned int charging_get_current(void *data)//获取充电电流
{unsigned int status = STATUS_OK;/* unsigned int array_size; *//* unsigned char reg_value; */unsigned char ret_val = 0;//unsigned char ret_force_20pct = 0;/* Get current level 读寄存器2 得到当前电流电平*/bq25601_read_interface(bq25601_CON2, &ret_val, CON2_ICHG_MASK, CON2_ICHG_SHIFT);/* Get Force 20% option *///bq25601_read_interface(bq25601_CON2, &ret_force_20pct, CON2_FORCE_20PCT_MASK,//CON2_FORCE_20PCT_SHIFT);/* Parsing 分析*/ret_val = ret_val * 60;//if (ret_force_20pct == 0) {/* Get current level *//* array_size = GETARRAYNUM(CS_VTH); *//* *(unsigned int *)data = charging_value_to_parameter(CS_VTH,array_size,reg_value); */*(unsigned int *) data = ret_val;//} else {/* Get current level *//* array_size = GETARRAYNUM(CS_VTH_20PCT); *//* *(unsigned int *)data = charging_value_to_parameter(CS_VTH,array_size,reg_value); *//* return (int)(ret_val<<1)/10; *///*(unsigned int *) data = (int)(ret_val << 1) / 10;//}
时return status;
}static unsigned int charging_set_current(void *data)//设置充电电流
{unsigned int status = STATUS_OK;unsigned int set_chr_current;unsigned int array_size;unsigned int register_value;unsigned int current_value = *(unsigned int *) data;array_size = GETARRAYNUM(CS_VTH); //获取vth数组个数set_chr_current = bmt_find_closest_level(CS_VTH, array_size, current_value); //bmt找到最接近的水平register_value = charging_parameter_to_value(CS_VTH, array_size, set_chr_current);  //充电参数转化成值printk("[%s] register_value = 0x%x \n", __func__, register_value);bq25601_set_ichg(register_value);//设置充电电流其中有个充电电流曲线return status;
}static unsigned int charging_set_input_current(void *data)  //设置输入电流
{unsigned int status = STATUS_OK;unsigned int current_value = *(unsigned int *) data;unsigned int set_chr_current;unsigned int array_size;unsigned int register_value;array_size = GETARRAYNUM(INPUT_CS_VTH);//获取vth数组个数set_chr_current = bmt_find_closest_level(INPUT_CS_VTH, array_size, current_value);//bmt找到最接近的水平register_value = charging_parameter_to_value(INPUT_CS_VTH, array_size, set_chr_current);//充电参数转化成值printk("[%s] register_value = 0x%x \n", __func__, register_value);bq25601_set_iindpm(register_value); //设置极限电流 其中有个极限电流 曲线return status;
}static unsigned int charging_get_charging_status(void *data) //得到充电状态
{unsigned int status = STATUS_OK;unsigned int ret_val;ret_val = bq25601_get_chrg_stat(); //充电状态:00-Not充电 01-Pre-charge(< VBATLOw) 10-Fast充电 11充电终止if (ret_val == 0x3)*(unsigned int *) data = KAL_TRUE;else*(unsigned int *) data = KAL_FALSE;return status;
}static unsigned int charging_reset_watch_dog_timer(void *data) //复位看门狗
{unsigned int status = STATUS_OK;battery_log(BAT_LOG_FULL, "charging_reset_watch_dog_timer\r\n");bq25601_set_wdt_rst(0x1);   /* Kick watchdog */  默认:正常(0)回到0后,1 看门狗定时器重置return status;
}static unsigned int charging_set_hv_threshold(void *data) //设置电压极限值
{unsigned int status = STATUS_OK;unsigned int set_hv_voltage;unsigned int array_size;unsigned short register_value;unsigned int voltage = *(unsigned int *)(data);array_size = GETARRAYNUM(VCDT_HV_VTH);//获取vth数组个数set_hv_voltage = bmt_find_closest_level(VCDT_HV_VTH, array_size, voltage); //bmt找到最接近的水平register_value = charging_parameter_to_value(VCDT_HV_VTH, array_size, set_hv_voltage); //充电参数转化成值upmu_set_rg_vcdt_hv_vth(register_value);return status;
}static unsigned int charging_get_hv_status(void *data) //获取电压的状态
{unsigned int status = STATUS_OK;#if defined(CONFIG_POWER_EXT) || defined(CONFIG_MTK_FPGA)*(kal_bool *) (data) = 0;pr_notice("[charging_get_hv_status] charger ok for bring up.\n");
#else*(kal_bool *)(data) = upmu_get_rgs_vcdt_hv_det();
#endifreturn status;
}static unsigned int charging_get_battery_status(void *data) //得到充电电池状态
{unsigned int status = STATUS_OK;unsigned int val = 0;battery_log(BAT_LOG_FULL, "[charging_get_battery_status] BATON_TDET_EN = %d\n", val);upmu_set_baton_tdet_en(1);upmu_set_rg_baton_en(1);*(kal_bool *)(data) = upmu_get_rgs_baton_undet();return status;
}static unsigned int charging_get_charger_det_status(void *data)//得到充电det的状态
{unsigned int status = STATUS_OK;*(kal_bool *)(data) = upmu_get_rgs_chrdet();return status;
}static unsigned int charging_get_charger_type(void *data) //得到充电类型
{unsigned int status = STATUS_OK;#if defined(CONFIG_POWER_EXT) || defined(CONFIG_MTK_FPGA)*(CHARGER_TYPE *) (data) = STANDARD_HOST;
#else*(CHARGER_TYPE *) (data) = hw_charging_get_charger_type();
#endifreturn status;
}static unsigned int charging_set_platform_reset(void *data) //设置平台复位状态
{unsigned int status = STATUS_OK;#if defined(CONFIG_POWER_EXT) || defined(CONFIG_MTK_FPGA)
#elsebattery_log(BAT_LOG_CRTI, "charging_set_platform_reset\n");kernel_restart("battery service reboot system");/* arch_reset(0,NULL); */
#endifreturn status;
}static unsigned int charging_get_platform_boot_mode(void *data) //得到平台boot的模式
{unsigned int status = STATUS_OK;
#if defined(CONFIG_POWER_EXT) || defined(CONFIG_MTK_FPGA)
#else*(unsigned int *) (data) = get_boot_mode();battery_log(BAT_LOG_CRTI, "get_boot_mode=%d\n", get_boot_mode());
#endifreturn status;
}static unsigned int charging_set_power_off(void *data)//设置电池电源关闭
{unsigned int status = STATUS_OK;#if defined(CONFIG_POWER_EXT) || defined(CONFIG_MTK_FPGA)
#elsebattery_log(BAT_LOG_CRTI, "charging_set_power_off\n");kernel_power_off();
#endifreturn status;
}static unsigned int charging_set_ta_current_pattern(void *data)//设置电池充电电流的模式
{unsigned int increase = *(unsigned int *) (data);unsigned int charging_status = KAL_FALSE;BATTERY_VOLTAGE_ENUM cv_voltage = BATTERY_VOLT_04_200000_V;if (batt_cust_data.high_battery_voltage_support)cv_voltage = BATTERY_VOLT_04_340000_V;charging_get_charging_status(&charging_status); //获取充电状态if (KAL_FALSE == charging_status) {charging_set_cv_voltage(&cv_voltage);  /* Set CV 设置cv电压*/ bq25601_set_ichg(0x9);   /* Set charging current 500ma 设置充电电流为500ma */bq25601_set_chg_config(0x1);   /* Enable Charging使能充电 */}if (increase == KAL_TRUE) { //输入极限电流设置bq25601_set_iindpm(0x0);  /* 100mA */msleep(85);bq25601_set_iindpm(0x4);  /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() on 1");msleep(85);bq25601_set_iindpm(0x0);    /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() off 1");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() on 2");msleep(85);bq25601_set_iindpm(0x0);    /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() off 2");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() on 3");msleep(281);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() off 3");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() on 4");msleep(281);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() off 4");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() on 5");msleep(281);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() off 5");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() on 6");msleep(485);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_increase() off 6");msleep(50);battery_log(BAT_LOG_CRTI, "mtk_ta_increase() end\n");bq25601_set_iindpm(0x4);    /* 500mA */msleep(200);} else {bq25601_set_iindpm(0x0); /* 100mA */msleep(85);bq25601_set_iindpm(0x4);  /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() on 1");msleep(281);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() off 1");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() on 2");msleep(281);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() off 2");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() on 3");msleep(281);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() off 3");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() on 4");msleep(85);bq25601_set_iindpm(0x0);    /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() off 4");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() on 5");msleep(85);bq25601_set_iindpm(0x0);    /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() off 5");msleep(85);bq25601_set_iindpm(0x4);   /* 500mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() on 6");msleep(485);bq25601_set_iindpm(0x0);   /* 100mA */battery_log(BAT_LOG_FULL, "mtk_ta_decrease() off 6");msleep(50);battery_log(BAT_LOG_CRTI, "mtk_ta_decrease() end\n");bq25601_set_iindpm(0x4);    /* 500mA */}return STATUS_OK;
}static unsigned int charging_diso_init(void *data) //初始化DISO结构体
{unsigned int status = STATUS_OK;#if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)DISO_ChargerStruct *pDISO_data = (DISO_ChargerStruct *) data;/* Initialization DISO Struct  初始化DISO结构体*/pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE; //otg状态pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE;//vusb状态pDISO_data->diso_state.cur_vdc_state = DISO_OFFLINE;//vdc状态pDISO_data->diso_state.pre_otg_state = DISO_OFFLINE;//前置otg状态pDISO_data->diso_state.pre_vusb_state = DISO_OFFLINE;//前置vusb状态pDISO_data->diso_state.pre_vdc_state = DISO_OFFLINE;//前置vdc状态pDISO_data->chr_get_diso_state = KAL_FALSE;pDISO_data->hv_voltage = VBUS_MAX_VOLTAGE;hrtimer_init(&diso_kthread_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);//hr计时器初始化diso_kthread_timer.function = diso_kthread_hrtimer_func; //diso内核线程函数INIT_DELAYED_WORK(&diso_polling_work, diso_polling_handler); //初始化等待队列kthread_run(diso_thread_kthread, NULL, "diso_thread_kthread"); //开一个diso的内核线程battery_log(BAT_LOG_CRTI, "[%s] done\n", __func__);#if defined(MTK_DISCRETE_SWITCH) && defined(MTK_DSC_USE_EINT)battery_log(BAT_LOG_CRTI, "[diso_eint]vdc eint irq registitation\n");mt_eint_set_hw_debounce(CUST_EINT_VDC_NUM, CUST_EINT_VDC_DEBOUNCE_CN);mt_eint_registration(CUST_EINT_VDC_NUM, CUST_EINTF_TRIGGER_LOW, vdc_eint_handler, 0);mt_eint_mask(CUST_EINT_VDC_NUM);
#endif
#endifreturn status;
}enum hrtimer_restart diso_kthread_hrtimer_func(struct hrtimer *timer) //diso内核线程函数
{diso_thread_timeout = KAL_TRUE;wake_up(&diso_polling_thread_wq); //轮询事件若有事件则唤醒等待队列return HRTIMER_NORESTART;
}int diso_thread_kthread(void *x) //diso内核线程函数启动
{/* Run on a process content 在流程内容上运行*/while (1) {wait_event(diso_polling_thread_wq, (diso_thread_timeout == KAL_TRUE));diso_thread_timeout = KAL_FALSE;mutex_lock(&diso_polling_mutex);_get_polling_state();//得到轮询状态事件if (DISO_Polling.vdc_polling_measure.notify_irq_en ||DISO_Polling.vusb_polling_measure.notify_irq_en)hrtimer_start(&diso_kthread_timer,ktime_set(0, MSEC_TO_NSEC(SW_POLLING_PERIOD)),HRTIMER_MODE_REL);elsehrtimer_cancel(&diso_kthread_timer);mutex_unlock(&diso_polling_mutex);}return 0;
}sstatic void _get_polling_state(void)//得到轮询状态
{int vdc_vol = 0, vusb_vol = 0;int vdc_vol_dir = -1;int vusb_vol_dir = -1;DISO_polling_channel *VDC_Polling = &DISO_Polling.vdc_polling_measure;DISO_polling_channel *VUSB_Polling = &DISO_Polling.vusb_polling_measure;vdc_vol = diso_get_current_voltage(AP_AUXADC_DISO_VDC_CHANNEL); //得到VDC当前电压vdc_vol =(R_DISO_DC_PULL_UP + R_DISO_DC_PULL_DOWN) * 100 * vdc_vol / (R_DISO_DC_PULL_DOWN) / 100;vusb_vol = diso_get_current_voltage(AP_AUXADC_DISO_VUSB_CHANNEL);//得到VUSB当前电压vusb_vol =(R_DISO_VBUS_PULL_UP +R_DISO_VBUS_PULL_DOWN) * 100 * vusb_vol / (R_DISO_VBUS_PULL_DOWN) / 100;VDC_Polling->preVoltage = VDC_Polling->curVoltage;VUSB_Polling->preVoltage = VUSB_Polling->curVoltage;VDC_Polling->curVoltage = vdc_vol;VUSB_Polling->curVoltage = vusb_vol;if (DISO_Polling.reset_polling) {DISO_Polling.reset_polling = KAL_FALSE;VDC_Polling->preVoltage = vdc_vol;VUSB_Polling->preVoltage = vusb_vol;if (vdc_vol > 1000)vdc_vol_dir = DISO_IRQ_RISING;elsevdc_vol_dir = DISO_IRQ_FALLING;if (vusb_vol > 1000)vusb_vol_dir = DISO_IRQ_RISING;elsevusb_vol_dir = DISO_IRQ_FALLING;} else {/* get voltage direction 得到电压方向 */vdc_vol_dir = _get_irq_direction(VDC_Polling->preVoltage, VDC_Polling->curVoltage); //得到电压方向vusb_vol_dir =_get_irq_direction(VUSB_Polling->preVoltage, VUSB_Polling->curVoltage);}if (VDC_Polling->notify_irq_en && (vdc_vol_dir == VDC_Polling->notify_irq)) {schedule_delayed_work(&diso_polling_work, 10 * HZ / 1000);    /* 10ms */battery_log(BAT_LOG_CRTI, "[%s] ready to trig VDC irq, irq: %d\n",__func__, VDC_Polling->notify_irq);} else if (VUSB_Polling->notify_irq_en && (vusb_vol_dir == VUSB_Polling->notify_irq)) {schedule_delayed_work(&diso_polling_work, 10 * HZ / 1000);battery_log(BAT_LOG_CRTI, "[%s] ready to trig VUSB irq, irq: %d\n",__func__, VUSB_Polling->notify_irq);} else if ((vdc_vol == 0) && (vusb_vol == 0)) {VDC_Polling->notify_irq_en = 0;VUSB_Polling->notify_irq_en = 0;}
}
static unsigned int diso_get_current_voltage(int Channel)//得到当前电压
{int ret = 0, data[4], i, ret_value = 0, ret_temp = 0, times = 5;if (IMM_IsAdcInitReady() == 0) {battery_log(BAT_LOG_CRTI, "[DISO] AUXADC is not ready");return 0;}i = times;while (i--) {ret_value = IMM_GetOneChannelValue(Channel, data, &ret_temp);if (ret_value == 0) {ret += ret_temp;} else {times = times > 1 ? times - 1 : 1;battery_log(BAT_LOG_CRTI, "[diso_get_current_voltage] ret_value=%d, times=%d\n",ret_value, times);}}ret = ret * 1500 / 4096;ret = ret / times;return ret;
}
int _get_irq_direction(int pre_vol, int cur_vol)//得到中断电压方向
{int ret = -1;/* threshold 阈值1000mv */if ((cur_vol - pre_vol) > 1000)ret = DISO_IRQ_RISING;
xelse if ((pre_vol - cur_vol) > 1000)ret = DISO_IRQ_FALLING;return ret;
}tatic void diso_polling_handler(struct work_struct *work)  //等待队列处理的事件
{int trigger_channel = -1;int trigger_flag = -1;if (DISO_Polling.vdc_polling_measure.notify_irq_en)trigger_channel = AP_AUXADC_DISO_VDC_CHANNEL;else if (DISO_Polling.vusb_polling_measure.notify_irq_en)trigger_channel = AP_AUXADC_DISO_VUSB_CHANNEL;battery_log(BAT_LOG_CRTI, "[DISO]auxadc handler triggered\n");switch (trigger_channel) {case AP_AUXADC_DISO_VDC_CHANNEL:trigger_flag = DISO_Polling.vdc_polling_measure.notify_irq;battery_log(BAT_LOG_CRTI, "[DISO]VDC IRQ triggered, channel ==%d, flag ==%d\n", trigger_channel,trigger_flag);
#ifdef MTK_DISCRETE_SWITCH  /*for DSC DC plugin handle 用于DSC DC插件处理事件*/set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); //dc中断处理事件set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0);//usb中断处理事件set_vusb_auxadc_irq(DISO_IRQ_ENABLE, DISO_IRQ_FALLING);//使能usb事件 if (trigger_flag == DISO_IRQ_RISING) {DISO_data.diso_state.pre_vusb_state = DISO_ONLINE;DISO_data.diso_state.pre_vdc_state = DISO_OFFLINE;DISO_data.diso_state.pre_otg_state = DISO_OFFLINE;DISO_data.diso_state.cur_vusb_state = DISO_ONLINE;DISO_data.diso_state.cur_vdc_state = DISO_ONLINE;DISO_data.diso_state.cur_otg_state = DISO_OFFLINE;battery_log(BAT_LOG_CRTI, " cur diso_state is %s!\n", DISO_state_s[2]);}
#else               /* for load switch OTG leakage handle 用于负载开关OTG泄漏手柄*/set_vdc_auxadc_irq(DISO_IRQ_ENABLE, (~trigger_flag) & 0x1);if (trigger_flag == DISO_IRQ_RISING) {DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE;DISO_data.diso_state.pre_vdc_state = DISO_OFFLINE;DISO_data.diso_state.pre_otg_state = DISO_ONLINE;DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE;DISO_data.diso_state.cur_vdc_state = DISO_ONLINE;DISO_data.diso_state.cur_otg_state = DISO_ONLINE;battery_log(BAT_LOG_CRTI, " cur diso_state is %s!\n", DISO_state_s[5]);} else if (trigger_flag == DISO_IRQ_FALLING) {DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE;DISO_data.diso_state.pre_vdc_state = DISO_ONLINE;DISO_data.diso_state.pre_otg_state = DISO_ONLINE;DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE;DISO_data.diso_state.cur_vdc_state = DISO_OFFLINE;DISO_data.diso_state.cur_otg_state = DISO_ONLINE;battery_log(BAT_LOG_CRTI, " cur diso_state is %s!\n", DISO_state_s[1]);} elsebattery_log(BAT_LOG_CRTI, "[%s] wrong trigger flag!\n", __func__);
#endifbreak;case AP_AUXADC_DISO_VUSB_CHANNEL:trigger_flag = DISO_Polling.vusb_polling_measure.notify_irq;battery_log(BAT_LOG_CRTI, "[DISO]VUSB IRQ triggered, channel ==%d, flag ==%d\n", trigger_channel,trigger_flag);set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0);if (trigger_flag == DISO_IRQ_FALLING) {DISO_data.diso_state.pre_vusb_state = DISO_ONLINE;DISO_data.diso_state.pre_vdc_state = DISO_ONLINE;DISO_data.diso_state.pre_otg_state = DISO_OFFLINE;DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE;DISO_data.diso_state.cur_vdc_state = DISO_ONLINE;DISO_data.diso_state.cur_otg_state = DISO_OFFLINE;battery_log(BAT_LOG_CRTI, " cur diso_state is %s!\n", DISO_state_s[4]);} else if (trigger_flag == DISO_IRQ_RISING) {DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE;DISO_data.diso_state.pre_vdc_state = DISO_ONLINE;DISO_data.diso_state.pre_otg_state = DISO_OFFLINE;DISO_data.diso_state.cur_vusb_state = DISO_ONLINE;DISO_data.diso_state.cur_vdc_state = DISO_ONLINE;DISO_data.diso_state.cur_otg_state = DISO_OFFLINE;battery_log(BAT_LOG_CRTI, " cur diso_state is %s!\n", DISO_state_s[6]);} elsebattery_log(BAT_LOG_CRTI, "[%s] wrong trigger flag!\n", __func__);set_vusb_auxadc_irq(DISO_IRQ_ENABLE, (~trigger_flag) & 0x1);break;default:set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0);battery_log(BAT_LOG_CRTI, "[DISO]VUSB auxadc IRQ triggered ERROR OR TEST\n");return;     /* in error or unexecpt state just return在错误或不称职的状态下才返回 */}g_diso_state = *(int *)&DISO_data.diso_state;battery_log(BAT_LOG_CRTI, "[DISO]g_diso_state: 0x%x\n", g_diso_state);DISO_data.irq_callback_func(0, NULL);
}#if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
void set_vusb_auxadc_irq(bool enable, bool flag) //usb中断处理事件
{hrtimer_cancel(&diso_kthread_timer);DISO_Polling.reset_polling = KAL_TRUE;DISO_Polling.vusb_polling_measure.notify_irq_en = enable;DISO_Polling.vusb_polling_measure.notify_irq = flag;hrtimer_start(&diso_kthread_timer, ktime_set(0, MSEC_TO_NSEC(SW_POLLING_PERIOD)),HRTIMER_MODE_REL);battery_log(BAT_LOG_FULL, " [%s] enable: %d, flag: %d!\n", __func__, enable, flag);
}void set_vdc_auxadc_irq(bool enable, bool flag)//dc中断处理事件
{hrtimer_cancel(&diso_kthread_timer);DISO_Polling.reset_polling = KAL_TRUE;DISO_Polling.vdc_polling_measure.notify_irq_en = enable;DISO_Polling.vdc_polling_measure.notify_irq = flag;hrtimer_start(&diso_kthread_timer, ktime_set(0, MSEC_TO_NSEC(SW_POLLING_PERIOD)),HRTIMER_MODE_REL);battery_log(BAT_LOG_FULL, " [%s] enable: %d, flag: %d!\n", __func__, enable, flag);
}#if defined(MTK_DISCRETE_SWITCH) && defined(MTK_DSC_USE_EINT)
void vdc_eint_handler(void) //中断处理
{battery_log(BAT_LOG_CRTI, "[diso_eint] vdc eint irq triger\n");DISO_data.diso_state.cur_vdc_state = DISO_ONLINE;mt_eint_mask(CUST_EINT_VDC_NUM);do_chrdet_int_task();
}
#endifstatic void _get_diso_interrupt_state(void) //得到diso中断状态
{int vol = 0;int diso_state = 0;int check_times = 30;kal_bool vin_state = KAL_FALSE;#ifndef VIN_SEL_FLAGmdelay(AUXADC_CHANNEL_DELAY_PERIOD);
#endifvol = diso_get_current_voltage(AP_AUXADC_DISO_VDC_CHANNEL);vol = (R_DISO_DC_PULL_UP + R_DISO_DC_PULL_DOWN) * 100 * vol / (R_DISO_DC_PULL_DOWN) / 100;battery_log(BAT_LOG_CRTI, "[DISO]  Current DC voltage mV = %d\n", vol);#ifdef VIN_SEL_FLAG/* set gpio mode for kpoc issue as DWS has no default setting 为kpoc问题设置gpio模式,因为DWS没有默认设置*/mt_set_gpio_mode(vin_sel_gpio_number, 0);  /* 0:GPIO mode */mt_set_gpio_dir(vin_sel_gpio_number, 0);   /* 0: input, 1: output */if (vol > VDC_MIN_VOLTAGE / 1000 && vol < VDC_MAX_VOLTAGE / 1000) {/* make sure load switch already switch done 确保负载开关已经完成 */do {check_times--;
#ifdef VIN_SEL_FLAG_DEFAULT_LOWvin_state = mt_get_gpio_in(vin_sel_gpio_number);
#elsevin_state = mt_get_gpio_in(vin_sel_gpio_number);vin_state = (~vin_state) & 0x1;
#endifif (!vin_state)mdelay(5);} while ((!vin_state) && check_times);battery_log(BAT_LOG_CRTI, "[DISO] i==%d  gpio_state= %d\n",check_times, mt_get_gpio_in(vin_sel_gpio_number));if (0 == check_times)diso_state &= ~0x4;  /* SET DC bit as 0 */elsediso_state |= 0x4;    /* SET DC bit as 1 */} else {diso_state &= ~0x4;   /* SET DC bit as 0 */}
#else/* force delay for switching as no flag for check switching done 强制延迟切换作为没有标志的检查切换完成*/mdelay(SWITCH_RISING_TIMING + LOAD_SWITCH_TIMING_MARGIN);if (vol > VDC_MIN_VOLTAGE / 1000 && vol < VDC_MAX_VOLTAGE / 1000)diso_state |= 0x4; /* SET DC bit as 1 */elsediso_state &= ~0x4;   /* SET DC bit as 0 */
#endifvol = diso_get_current_voltage(AP_AUXADC_DISO_VUSB_CHANNEL);vol =(R_DISO_VBUS_PULL_UP +R_DISO_VBUS_PULL_DOWN) * 100 * vol / (R_DISO_VBUS_PULL_DOWN) / 100;battery_log(BAT_LOG_CRTI, "[DISO]  Current VBUS voltage  mV = %d\n", vol);if (vol > VBUS_MIN_VOLTAGE / 1000 && vol < VBUS_MAX_VOLTAGE / 1000) {if (!mt_usb_is_device()) {diso_state |= 0x1;    /* SET OTG bit as 1 */diso_state &= ~0x2;  /* SET VBUS bit as 0 */} else {diso_state &= ~0x1; /* SET OTG bit as 0 */diso_state |= 0x2;   /* SET VBUS bit as 1; */}} else {diso_state &= 0x4;    /* SET OTG and VBUS bit as 0 */}battery_log(BAT_LOG_CRTI, "[DISO] DISO_STATE==0x%x\n", diso_state);g_diso_state = diso_state;
}#endif
static unsigned int charging_get_diso_state(void *data)//获取diso 电池状态
{unsigned int status = STATUS_OK;#if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)int diso_state = 0x0;DISO_ChargerStruct *pDISO_data = (DISO_ChargerStruct *) data;_get_diso_interrupt_state();diso_state = g_diso_state;battery_log(BAT_LOG_CRTI, "[do_chrdet_int_task] current diso state is %s!\n", DISO_state_s[diso_state]);if (((diso_state >> 1) & 0x3) != 0x0) {switch (diso_state) {case USB_ONLY:set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0);
#ifdef MTK_DISCRETE_SWITCH
#ifdef MTK_DSC_USE_EINTmt_eint_unmask(CUST_EINT_VDC_NUM);
#elseset_vdc_auxadc_irq(DISO_IRQ_ENABLE, 1);
#endif
#endifpDISO_data->diso_state.cur_vusb_state = DISO_ONLINE;pDISO_data->diso_state.cur_vdc_state = DISO_OFFLINE;pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE;break;case DC_ONLY:set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_ENABLE, DISO_IRQ_RISING);pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE;pDISO_data->diso_state.cur_vdc_state = DISO_ONLINE;pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE;break;case DC_WITH_USB:set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_ENABLE, DISO_IRQ_FALLING);pDISO_data->diso_state.cur_vusb_state = DISO_ONLINE;pDISO_data->diso_state.cur_vdc_state = DISO_ONLINE;pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE;break;case DC_WITH_OTG:set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0);set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0);pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE;pDISO_data->diso_state.cur_vdc_state = DISO_ONLINE;pDISO_data->diso_state.cur_otg_state = DISO_ONLINE;break;default: /* OTG only also can trigger vcdt IRQ OTG也只能触发vcdt IRQ */pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE;pDISO_data->diso_state.cur_vdc_state = DISO_OFFLINE;pDISO_data->diso_state.cur_otg_state = DISO_ONLINE;battery_log(BAT_LOG_CRTI, " switch load vcdt irq triggerd by OTG Boost!\n");break;   /* OTG plugin no need battery sync action OTG插件不需要电池同步动作*/}}if (DISO_ONLINE == pDISO_data->diso_state.cur_vdc_state)pDISO_data->hv_voltage = VDC_MAX_VOLTAGE;elsepDISO_data->hv_voltage = VBUS_MAX_VOLTAGE;
#endifreturn status;
}static unsigned int charging_get_error_state(void)//得到充电错误状态
{return charging_error;
}static unsigned int charging_set_error_state(void *data) //设置充电错误状态
{unsigned int status = STATUS_OK;charging_error = *(unsigned int *) (data);return status;
}static unsigned int charging_set_vbus_ovp_en(void *data)//充电设置使能
{return STATUS_OK;
}static unsigned int charging_set_vindpm(void *data)//设置电池vindpm
{return STATUS_OK;
}

下面就是mtk 充电中提供一个函数指针chr_control_interface指向下面的函数接口,从而实现各个功能

/*
* FUNCTION 函数
*       Internal_chr_control_handler
*
* DESCRIPTION 描述
*        This function is called to set the charger hw 调用此功能设置充电器hw
*
*
* CALLS 电话
*
* PARAMETERS 参数
*       None 没有
*
* RETURNS 返回
*
*
* GLOBALS AFFECTED  全局的影响
*      None 没有
*/
static unsigned int(*charging_func[CHARGING_CMD_NUMBER]) (void *data);signed int chr_control_interface(CHARGING_CTRL_CMD cmd, void *data)  //调用此功能设置充电器hw
{static signed int init = -1;if (init == -1) {init = 0;charging_func[CHARGING_CMD_INIT] = charging_hw_init; //充电硬件初始化charging_func[CHARGING_CMD_DUMP_REGISTER] = charging_dump_register;//遍历读取bq25601所有保存在寄存器的值charging_func[CHARGING_CMD_ENABLE] = charging_enable;//充电使能charging_func[CHARGING_CMD_SET_CV_VOLTAGE] = charging_set_cv_voltage;//设置工作电压charging_func[CHARGING_CMD_GET_CURRENT] = charging_get_current;//获取充电电流charging_func[CHARGING_CMD_SET_CURRENT] = charging_set_current;//设置充电电流charging_func[CHARGING_CMD_SET_INPUT_CURRENT] = charging_set_input_current; //设置输入电流charging_func[CHARGING_CMD_GET_CHARGING_STATUS] = charging_get_charging_status;//得到充电状态charging_func[CHARGING_CMD_RESET_WATCH_DOG_TIMER] = charging_reset_watch_dog_timer;//复位看门狗charging_func[CHARGING_CMD_SET_HV_THRESHOLD] = charging_set_hv_threshold;//设置电压极限值charging_func[CHARGING_CMD_GET_HV_STATUS] = charging_get_hv_status;//获取电压的状态charging_func[CHARGING_CMD_GET_BATTERY_STATUS] = charging_get_battery_status;//得到充电电池状态charging_func[CHARGING_CMD_GET_CHARGER_DET_STATUS] = charging_get_charger_det_status;//得到充电det的状态charging_func[CHARGING_CMD_GET_CHARGER_TYPE] = charging_get_charger_type;//得到充电类型charging_func[CHARGING_CMD_SET_PLATFORM_RESET] = charging_set_platform_reset;//设置平台复位状态charging_func[CHARGING_CMD_GET_PLATFORM_BOOT_MODE] = charging_get_platform_boot_mode; //得到平台boot的模式charging_func[CHARGING_CMD_SET_POWER_OFF] = charging_set_power_off;//设置电池电源关闭charging_func[CHARGING_CMD_SET_TA_CURRENT_PATTERN] = charging_set_ta_current_pattern;//设置电池充电电流的模式charging_func[CHARGING_CMD_SET_ERROR_STATE] = charging_set_error_state;//设置充电错误状态charging_func[CHARGING_CMD_DISO_INIT] = charging_diso_init; //初始化DISO结构体charging_func[CHARGING_CMD_GET_DISO_STATE] = charging_get_diso_state;//获取diso 电池状态charging_func[CHARGING_CMD_SET_VBUS_OVP_EN] = charging_set_vbus_ovp_en;//充电设置使能charging_func[CHARGING_CMD_SET_VINDPM] = charging_set_vindpm;//设置电池vindpm}if (cmd < CHARGING_CMD_NUMBER) {if (charging_func[cmd] != NULL)return charging_func[cmd](data);}pr_debug("[%s]UNSUPPORT Function: %d\n", __func__, cmd);return STATUS_UNSUPPORTED;}

charging hw bq25601充电驱动笔记相关推荐

  1. Linux-USB驱动笔记(五)--主机控制器驱动框架

    Linux-USB驱动笔记(五)--主机控制器驱动框架 1.前言 2.主机控制器框架 3.重要结构体 3.1.usb_hcd -- 主机控制器驱动 3.2.hc_driver -- 控制器操作函数 3 ...

  2. 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】

    转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...

  3. 嵌入式Linux驱动笔记--转自风筝丶

    为了阅读学习方便,将系列博客的网址进行粘贴,感谢原博客的分享. 嵌入式Linux驱动笔记(一)------第一个LED驱动程序 嵌入式Linux驱动笔记(二)------定时器 嵌入式Linux驱动笔 ...

  4. 展讯sprd_battery.c 充电驱动

    sprd_battery.c 是充电驱动,这个是充电功能的核心内容,电量显示策略.温度检测策略.充电保护机制等功能在这里实现,功能实现与硬件细节剥离,调用通用接口实现逻辑控制: 1 sprdbat_p ...

  5. 嵌入式Linux驱动笔记(十六)------设备驱动模型(kobject、kset、ktype)

    ###你好!这里是风筝的博客, ###欢迎和我一起交流. 前几天去面试,被问到Linux设备驱动模型这个问题,没答好,回来后恶补知识,找了些资料,希望下次能答出个满意答案. Linux早期时候,一个驱 ...

  6. 嵌入式Linux驱动笔记(五)------学习platform设备驱动

    你好!这里是风筝的博客, 欢迎和我一起交流. 设备是设备,驱动是驱动. 如果把两个糅合写一起,当设备发生变化时,势必要改写整个文件,这是非常愚蠢的做法.如果把他们分开来,当设备发生变化时,只要改写设备 ...

  7. 嵌入式Linux驱动笔记(二十四)------framebuffer之使用spi-tft屏幕(上)

    你好!这里是风筝的博客, 欢迎和我一起交流. 最近入手了一块spi接口的tft彩屏,想着在我的h3板子上使用framebuffer驱动起来. 我们知道: Linux抽象出FrameBuffer这个设备 ...

  8. mtk+android+之mt6577驱动笔记,MTK6577+Android之音频(audio)移植

    MTK6577+Android之音频(audio)移植 备注:audio PA音频功放(power amplifier) 先借用<Y1MT6577 design notice V0.1>关 ...

  9. M62429驱动笔记

    M62429驱动笔记 M62429是一款串行数据控制的双声道电子音量控制器芯片,它的规格书(中文),三菱(英文), RENESAS(英文) 1.功能框图 2.引脚说明 Pin no. Symbol F ...

最新文章

  1. 如何改变android5.1音量进度条,HTML5音频audio属性
  2. 中国厂商加速5G前瞻性部署
  3. 【qduoj】C语言_求整数各位数之和
  4. Apollo进阶课程 ② | 开源模块讲解(上)
  5. MySQL 创建用户
  6. Gson实现自定义解析json格式
  7. linux uwsgi 非root,ubuntu-除非root用户,否则uWSGI Emperor权限被拒...
  8. 确保着法合规:象棋通用规则解析
  9. ERP系统-销售子系统-销售发货通知单
  10. 驱动器存在问题-U盘量产-主控SM3255AB
  11. Oracle批量低耗清除历史数据
  12. pimple学习(1)pimple的使用
  13. 方根法公式_方根的简易算法
  14. 树模型之三种常见的决策树:CART,…
  15. 数据访问安全代理 CASB
  16. java毕业设计疫情返乡人员管理系统Mybatis+系统+数据库+调试部署
  17. 推荐一位大神,手握 GitHub 16000 star
  18. uniapp 文本 字体 样式总结
  19. java手机游戏开发人才短缺
  20. Tyvj 1039 忠诚2

热门文章

  1. 如何让C盘可用空间变大
  2. 红米note9pro和华为nova7哪个好
  3. 如何用MATLAB把一个三维矩阵里的数据中的一页画成三维图并加密网格
  4. 实验四+126+黄晟
  5. GD32F303固件库开发(17)----内部Flash读写
  6. AutoCAD 2012安装错误,与.net framework (1603错误)以及ms2005vc++的问题。
  7. PAT_乙级_1003_筱筱
  8. 广东开放大学学习指引(A)(本专,2022春)
  9. Elasticsearch入门到精通教程 - 学习资料综合
  10. 诗词格律[1] 诗词入门