OSHW-DEIMOS/SOFTWARE/A64-TERES/linux-a64/drivers/power/axp_power/axp-state.c
Dimitar Gamishev f9b0e7a283 linux
2017-10-13 14:07:04 +03:00

263 lines
9.0 KiB
C
Executable File

/*
* Battery charger driver for AW-POWERS
*
* Copyright (C) 2014 ALLWINNERTECH.
* Ming Li <liming@allwinnertech.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "axp-cfg.h"
#ifdef CONFIG_AW_AXP81X
#include "axp81x-sply.h"
#include "axp81x-common.h"
static const struct axp_config_info *axp_config = &axp81x_config;
#endif
struct axp_adc_res adc;
s32 axp_read_bat_cap(void)
{
s32 bat_cap;
u8 tmp;
axp_read(axp_charger->master, AXP_CAP,&tmp);
bat_cap = (s32) (tmp & 0x7F);
return bat_cap;
}
EXPORT_SYMBOL_GPL(axp_read_bat_cap);
static inline s32 axp_vts_to_temp(s32 data, const struct axp_config_info *axp_config)
{
s32 temp;
if (data < 80)
return 30;
else if (data < axp_config->pmu_bat_temp_para16)
return 80;
else if (data <= axp_config->pmu_bat_temp_para15) {
temp = 70 + (axp_config->pmu_bat_temp_para15-data)*10/(axp_config->pmu_bat_temp_para15-axp_config->pmu_bat_temp_para16);
} else if (data <= axp_config->pmu_bat_temp_para14) {
temp = 60 + (axp_config->pmu_bat_temp_para14-data)*10/(axp_config->pmu_bat_temp_para14-axp_config->pmu_bat_temp_para15);
} else if (data <= axp_config->pmu_bat_temp_para13) {
temp = 55 + (axp_config->pmu_bat_temp_para13-data)*5/(axp_config->pmu_bat_temp_para13-axp_config->pmu_bat_temp_para14);
} else if (data <= axp_config->pmu_bat_temp_para12) {
temp = 50 + (axp_config->pmu_bat_temp_para12-data)*5/(axp_config->pmu_bat_temp_para12-axp_config->pmu_bat_temp_para13);
} else if (data <= axp_config->pmu_bat_temp_para11) {
temp = 45 + (axp_config->pmu_bat_temp_para11-data)*5/(axp_config->pmu_bat_temp_para11-axp_config->pmu_bat_temp_para12);
} else if (data <= axp_config->pmu_bat_temp_para10) {
temp = 40 + (axp_config->pmu_bat_temp_para10-data)*5/(axp_config->pmu_bat_temp_para10-axp_config->pmu_bat_temp_para11);
} else if (data <= axp_config->pmu_bat_temp_para9) {
temp = 30 + (axp_config->pmu_bat_temp_para9-data)*10/(axp_config->pmu_bat_temp_para9-axp_config->pmu_bat_temp_para10);
} else if (data <= axp_config->pmu_bat_temp_para8) {
temp = 20 + (axp_config->pmu_bat_temp_para8-data)*10/(axp_config->pmu_bat_temp_para8-axp_config->pmu_bat_temp_para9);
} else if (data <= axp_config->pmu_bat_temp_para7) {
temp = 10 + (axp_config->pmu_bat_temp_para7-data)*10/(axp_config->pmu_bat_temp_para7-axp_config->pmu_bat_temp_para8);
} else if (data <= axp_config->pmu_bat_temp_para6) {
temp = 5 + (axp_config->pmu_bat_temp_para6-data)*5/(axp_config->pmu_bat_temp_para6-axp_config->pmu_bat_temp_para7);
} else if (data <= axp_config->pmu_bat_temp_para5) {
temp = 0 + (axp_config->pmu_bat_temp_para5-data)*5/(axp_config->pmu_bat_temp_para5-axp_config->pmu_bat_temp_para6);
} else if (data <= axp_config->pmu_bat_temp_para4) {
temp = -5 + (axp_config->pmu_bat_temp_para4-data)*5/(axp_config->pmu_bat_temp_para4-axp_config->pmu_bat_temp_para5);
} else if (data <= axp_config->pmu_bat_temp_para3) {
temp = -10 + (axp_config->pmu_bat_temp_para3-data)*5/(axp_config->pmu_bat_temp_para3-axp_config->pmu_bat_temp_para4);
} else if (data <= axp_config->pmu_bat_temp_para2) {
temp = -15 + (axp_config->pmu_bat_temp_para2-data)*5/(axp_config->pmu_bat_temp_para2-axp_config->pmu_bat_temp_para3);
} else if (data <= axp_config->pmu_bat_temp_para1) {
temp = -25 + (axp_config->pmu_bat_temp_para1-data)*10/(axp_config->pmu_bat_temp_para1-axp_config->pmu_bat_temp_para2);
} else
temp = -25;
return temp;
}
static inline s32 axp_vts_to_mV(u16 reg)
{
return ((s32)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 800 / 1000;
}
static inline s32 axp_vbat_to_mV(u16 reg)
{
return ((s32)((( reg >> 8) << 4 ) | (reg & 0x000F))) * 1100 / 1000;
}
static inline s32 axp_ocvbat_to_mV(u16 reg)
{
return ((s32)((( reg >> 8) << 4 ) | (reg & 0x000F))) * 1100 / 1000;
}
static inline s32 axp_vdc_to_mV(u16 reg)
{
return ((s32)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 1700 / 1000;
}
static inline s32 axp_ibat_to_mA(u16 reg)
{
return ((s32)(((reg >> 8) << 4 ) | (reg & 0x000F))) ;
}
static inline s32 axp_icharge_to_mA(u16 reg)
{
return ((s32)(((reg >> 8) << 4 ) | (reg & 0x000F)));
}
static inline s32 axp_iac_to_mA(u16 reg)
{
return ((s32)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 625 / 1000;
}
static inline s32 axp_iusb_to_mA(u16 reg)
{
return ((s32)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 375 / 1000;
}
static inline void axp_read_adc(struct axp_charger *charger,
struct axp_adc_res *adc)
{
u8 tmp[8];
adc->vac_res = 0;
adc->iac_res = 0;
adc->vusb_res = 0;
adc->iusb_res = 0;
axp_reads(charger->master,AXP_OCVBATH_RES,2,tmp);
adc->ocvbat_res = ((u16) tmp[0] << 8 )| tmp[1];
axp_reads(charger->master,AXP_VTS_RES,2,tmp);
adc->ts_res = ((u16) tmp[0] << 8 )| tmp[1];
axp_reads(charger->master,AXP_VBATH_RES,6,tmp);
adc->vbat_res = ((u16) tmp[0] << 8 )| tmp[1];
adc->ichar_res = ((u16) tmp[2] << 8 )| tmp[3];
adc->idischar_res = ((u16) tmp[4] << 8 )| tmp[5];
}
u64 axp_read_power_sply(void)
{
u16 tmp;
int disvbat;
int disibat;
u64 power_sply = 0;
axp_read_adc(axp_charger, &adc);
tmp = adc.vbat_res;
disvbat = axp_vbat_to_mV(tmp);
tmp = adc.idischar_res;
disibat = axp_ibat_to_mA(tmp);
printk(KERN_ERR "vbat = %d mV, disibat=%d mA\n", disvbat, disibat);
power_sply = disvbat * disibat;
if (0 != power_sply)
power_sply = power_sply/1000;
return power_sply;
}
EXPORT_SYMBOL(axp_read_power_sply);
void axp_battery_update_vol(struct axp_charger * charger)
{
u8 val, temp_val[2];
s32 ocv_percentage = 0, coulumb_percentage = 0, rest_vol = 0;
axp_reads(charger->master,0xe4,2,temp_val);
ocv_percentage = temp_val[0] & 0x7f;
coulumb_percentage = temp_val[1] & 0x7f;
axp_read(charger->master, AXP_CAP,&val);
rest_vol = (s32) (val & 0x7F);
DBG_PSY_MSG(DEBUG_SPLY, "AXP rest_vol = %d\n", rest_vol);
DBG_PSY_MSG(DEBUG_SPLY, "Axp OCV_percentage = %d\n", ocv_percentage);
DBG_PSY_MSG(DEBUG_SPLY, "Axp Coulumb_percentage = %d\n", coulumb_percentage);
spin_lock(&charger->charger_lock);
charger->rest_vol = rest_vol;
if ((axp_config->ocv_coulumb_100) && (100 == ocv_percentage) && (100 == coulumb_percentage)) {
charger->rest_vol = 100;
}
if((charger->bat_det == 0) || (charger->rest_vol == 127)){
charger->rest_vol = 100;
}
spin_unlock(&charger->charger_lock);
DBG_PSY_MSG(DEBUG_SPLY, "charger->rest_vol = %d\n",charger->rest_vol);
return;
}
void axp_charger_update_state(struct axp_charger *charger)
{
u8 val[2];
u16 tmp;
/* wait for the stability of ACIN valid and VBUS valid */
msleep(2);
axp_reads(charger->master,AXP_CHARGE_STATUS,2,val);
tmp = (val[1] << 8 )+ val[0];
DBG_PSY_MSG(DEBUG_CHG, "Axp read again charger->ext_valid: %d\n", \
charger->ext_valid);
spin_lock(&charger->charger_lock);
charger->is_on = (val[1] & AXP_IN_CHARGE) ? 1 : 0;
charger->fault = val[1];
charger->bat_det = (tmp & AXP_STATUS_BATEN)?1:0;
charger->ac_det = (tmp & AXP_STATUS_ACEN)?1:0;
charger->usb_det = (tmp & AXP_STATUS_USBEN)?1:0;
charger->ext_valid = (tmp & (AXP_STATUS_USBVA |AXP_STATUS_ACVA))?1:0;
charger->in_short = (tmp& AXP_STATUS_ACUSBSH)?1:0;
if(!charger->in_short) {
charger->ac_valid = (tmp & AXP_STATUS_ACVA)?1:0;
}
charger->bat_current_direction = (tmp & AXP_STATUS_BATCURDIR)?1:0;
charger->batery_active = (tmp & AXP_STATUS_BATINACT)?1:0;
charger->int_over_temp = (tmp & AXP_STATUS_ICTEMOV)?1:0;
spin_unlock(&charger->charger_lock);
axp_read(charger->master,AXP_CHARGE_CONTROL1,val);
spin_lock(&charger->charger_lock);
charger->charge_on = ((val[0] >> 7) & 0x01);
spin_unlock(&charger->charger_lock);
}
void axp_charger_update(struct axp_charger *charger, const struct axp_config_info *axp_config)
{
u16 tmp;
u8 val[2];
s32 bat_temp_mv;
charger->adc = &adc;
axp_read_adc(charger, &adc);
tmp = charger->adc->vbat_res;
spin_lock(&charger->charger_lock);
charger->vbat = axp_vbat_to_mV(tmp);
spin_unlock(&charger->charger_lock);
//tmp = charger->adc->ichar_res + charger->adc->idischar_res;
spin_lock(&charger->charger_lock);
charger->ibat = axp_icharge_to_mA(charger->adc->ichar_res)-axp_ibat_to_mA(charger->adc->idischar_res);
tmp = 00;///qin
charger->vac = axp_vdc_to_mV(tmp);
tmp = 00;
charger->iac = axp_iac_to_mA(tmp);
tmp = 00;
charger->vusb = axp_vdc_to_mV(tmp);
tmp = 00;
charger->iusb = axp_iusb_to_mA(tmp);
spin_unlock(&charger->charger_lock);
axp_reads(charger->master,AXP_INTTEMP,2,val);
//DBG_PSY_MSG("TEMPERATURE:val1=0x%x,val2=0x%x\n",val[1],val[0]);
tmp = (val[0] << 4 ) + (val[1] & 0x0F);
spin_lock(&charger->charger_lock);
charger->ic_temp = (s32) tmp *1063/10000 - 2667/10;
charger->disvbat = charger->vbat;
charger->disibat = axp_ibat_to_mA(charger->adc->idischar_res);
spin_unlock(&charger->charger_lock);
tmp = charger->adc->ocvbat_res;
spin_lock(&charger->charger_lock);
charger->ocv = axp_ocvbat_to_mV(tmp);
spin_unlock(&charger->charger_lock);
tmp = charger->adc->ts_res;
bat_temp_mv = axp_vts_to_mV(tmp);
spin_lock(&charger->charger_lock);
charger->bat_temp = axp_vts_to_temp(bat_temp_mv, axp_config);
spin_unlock(&charger->charger_lock);
}