/*
 * Return the battery Voltage in milivolts
 * Or < 0 if something fails.
 */
static int bq27541_battery_voltage(struct bq27541_device_info *di)
{
    int ret;
    int volt = 0;

#ifdef CONFIG_MACH_OPPO
    if (atomic_read(&di->suspended) == 1) {
        return di->batt_vol_pre;
    }

    if (di->alow_reading) {
        ret = bq27541_read(BQ27541_REG_VOLT, &volt, 0, di);
        if (ret) {
            dev_err(di->dev, "error reading voltage,ret:%d\n", ret);
            return ret;
        }
    } else {
        return di->batt_vol_pre;
    }
    di->batt_vol_pre = volt * 1000;
#else
    ret = bq27541_read(BQ27541_REG_VOLT, &volt, 0, di);
    if (ret) {
        dev_err(di->dev, "error reading voltage\n");
        return ret;
    }
#endif

    return volt * 1000;
}
예제 #2
0
static void bq27541_hw_config(struct work_struct *work)
{
	int ret = 0, flags = 0, type = 0, fw_ver = 0;
	struct bq27541_device_info *di;

	di  = container_of(work, struct bq27541_device_info, hw_config.work);
	ret = bq27541_chip_config(di);
	if (ret) {
		dev_err(di->dev, "Failed to config Bq27541\n");
		return;
	}
	msm_battery_gauge_register(&bq27541_batt_gauge);

	bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS);
	udelay(66);
	bq27541_read(BQ27541_REG_CNTL, &flags, 0, di);
	bq27541_cntl_cmd(di, BQ27541_SUBCMD_DEVCIE_TYPE);
	udelay(66);
	bq27541_read(BQ27541_REG_CNTL, &type, 0, di);
	bq27541_cntl_cmd(di, BQ27541_SUBCMD_FW_VER);
	udelay(66);
	bq27541_read(BQ27541_REG_CNTL, &fw_ver, 0, di);

	dev_info(di->dev, "DEVICE_TYPE is 0x%02X, FIRMWARE_VERSION is 0x%02X\n",
			type, fw_ver);
	dev_info(di->dev, "Complete bq27541 configuration 0x%02X\n", flags);
}
예제 #3
0
static int bq27541_battery_rsoc(struct bq27541_device_info *di)
{
	int ret;
	int rsoc = 0;
	int flags = 0;
	int status = 0;
	u8 buf[2];

#if defined (CONFIG_NO_BATTERY_IC)
	return 100;
#endif
	if(virtual_battery_enable == 1)
		return 50/*100*/;

	ret = bq27541_read(di->client,BQ27500_REG_SOC,buf,2); 
	if (ret<0) {
		dev_err(di->dev, "error reading relative State-of-Charge\n");
		return ret;
	}
	rsoc = get_unaligned_le16(buf);
	DBG("Enter:%s %d--read rsoc = %d\n",__FUNCTION__,__LINE__,rsoc);

	/* covert the capacity range */
	rsoc = min(rsoc, 100);
	if ((g_pdata != NULL) && g_pdata->capacity_max && g_pdata->capacity_min) {
		rsoc = max(rsoc, g_pdata->capacity_min);
		rsoc = ((rsoc - g_pdata->capacity_min) * 100 +
			(g_pdata->capacity_max - g_pdata->capacity_min) / 2)
			/ (g_pdata->capacity_max - g_pdata->capacity_min);
	}

	bq27541_cap = rsoc;

#if 0
	/*check full flags,if not full, show 99%*/
	ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2);
	if (ret < 0) {
		dev_err(di->dev, "error reading flags\n");
		return ret;
	}
	flags = get_unaligned_le16(buf);
	DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags);
	if (flags & BQ27500_FLAG_FC)
		status = POWER_SUPPLY_STATUS_FULL;

	if(status != POWER_SUPPLY_STATUS_FULL)
		rsoc = min(rsoc, 99);
#endif
	DBG("Enter:%s %d--cal rsoc = %d\n",__FUNCTION__,__LINE__,rsoc);

#if defined (CONFIG_NO_BATTERY_IC)
	rsoc = 100;
#endif

	return rsoc;
}
예제 #4
0
static int bq27541_battery_temperature(struct bq27541_device_info *di)
{
	int ret;
	int temp = 0;
	u8 buf[2] ={0};

#if defined (CONFIG_NO_BATTERY_IC)
	return 258;
#endif
	if(virtual_battery_enable == 1)
		return 125/*258*/;

	ret = bq27541_read(di->client,BQ27x00_REG_TEMP,buf,2);
	if (ret<0) {
		dev_err(di->dev, "error reading temperature\n");
		return ret;
	}
	temp = get_unaligned_le16(buf);
	temp = temp - 2731;  //K
	DBG("Enter:%s %d--temp = %d\n",__FUNCTION__,__LINE__,temp);
#if defined(CONFIG_CHARGER_LIMITED_BY_TEMP)
	if((temp >= DIS_CHARGING_TEMP) && (0 == charge_en_flags)){
		bq24196_charge_disable();
		charge_en_flags = 1;
	}else if((temp <= EN_CHARGING_TEMP) && (1 == charge_en_flags)){
		bq24196_charge_en();
		charge_en_flags = 0;
	}
#endif
//	rk29_pm_power_off();
	return temp;
}
예제 #5
0
static int bq27541_health_status(struct bq27541_device_info *di,
				  union power_supply_propval *val)
{
	u8 buf[2] = {0};
	int flags = 0;
	int status;
	int ret;
	
#if defined (CONFIG_NO_BATTERY_IC)
	val->intval = POWER_SUPPLY_HEALTH_GOOD;
	return 0;
#endif
	if(virtual_battery_enable == 1)
	{
		val->intval = POWER_SUPPLY_HEALTH_GOOD;
		return 0;
	}

	ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2);
	if (ret < 0) {
		dev_err(di->dev, "error reading flags\n");
		return ret;
	}
	flags = get_unaligned_le16(buf);
	DBG("Enter:%s %d--status = %x\n",__FUNCTION__,__LINE__,flags);
	
	if ((flags & BQ27500_FLAG_OTD)||(flags & BQ27500_FLAG_OTC))
		status = POWER_SUPPLY_HEALTH_OVERHEAT;
	else
		status = POWER_SUPPLY_HEALTH_GOOD;

	val->intval = status;

	return 0;
}
static int bq27541_average_current(struct bq27541_device_info *di)
{
    int ret;
    int curr = 0;

    if (atomic_read(&di->suspended) == 1) {
        return -di->current_pre;
    }

    if (di->alow_reading == true) {
        ret = bq27541_read(BQ27541_REG_AI, &curr, 0, di);
        if (ret) {
            dev_err(di->dev, "error reading current.\n");
            return ret;
        }
    } else {
        return -di->current_pre;
    }
    // negative current
    if (curr & 0x8000)
        curr = -((~(curr - 1)) & 0xFFFF);
    di->current_pre = curr;

    return -curr;
}
예제 #7
0
static int bq27541_battery_status(struct bq27541_device_info *di,
				  union power_supply_propval *val)
{
	u8 buf[2] = {0};
	int flags = 0;
	int status = 0;
	int ret = 0;

	#if defined (CONFIG_NO_BATTERY_IC)
		val->intval = POWER_SUPPLY_STATUS_FULL;
	return 0;
	#endif

	if(virtual_battery_enable == 1)
	{
		val->intval = POWER_SUPPLY_STATUS_FULL;
		return 0;
	}
	ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2);
	if (ret < 0) {
		dev_err(di->dev, "error reading flags\n");
		return ret;
	}
	flags = get_unaligned_le16(buf);
	DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags);
	if (flags & BQ27500_FLAG_FC)
		status = POWER_SUPPLY_STATUS_FULL;
#if 0
	else if (flags & BQ27500_FLAG_DSC)
		status = POWER_SUPPLY_STATUS_DISCHARGING;
	else
		status = POWER_SUPPLY_STATUS_CHARGING;
#else
	else if ((g_pdata != NULL) && g_pdata->get_charging_stat)
예제 #8
0
static ssize_t bq27541_read_subcmd(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	int ret;
	int temp = 0;
	struct platform_device *client;
	struct bq27541_device_info *di;

	client = to_platform_device(dev);
	di = platform_get_drvdata(client);

	if (subcmd == BQ27541_SUBCMD_DEVCIE_TYPE ||
		 subcmd == BQ27541_SUBCMD_FW_VER ||
		 subcmd == BQ27541_SUBCMD_HW_VER ||
		 subcmd == BQ27541_SUBCMD_CHEM_ID) {

		bq27541_cntl_cmd(di, subcmd); /* Retrieve Chip status */
		udelay(66);
		ret = bq27541_read(BQ27541_REG_CNTL, &temp, 0, di);

		if (ret)
			ret = snprintf(buf, PAGE_SIZE, "Read Error!\n");
		else
			ret = snprintf(buf, PAGE_SIZE, "0x%02x\n", temp);
	} else
		ret = snprintf(buf, PAGE_SIZE, "Register Error!\n");

	return ret;
}
예제 #9
0
/*
 * Return the battery average current
 * Note that current can be negative signed as well
 * Or 0 if something fails.
 */
static int bq27541_battery_current(struct bq27541_device_info *di)
{
	int ret;
	int curr = 0;
	u8 buf[2] = {0};

	#if defined (CONFIG_NO_BATTERY_IC)
		return 22000;
	#endif
	if(virtual_battery_enable == 1)
		return 11000/*22000*/;
	ret = bq27541_read(di->client,BQ27x00_REG_AI,buf,2);
	if (ret<0) {
		dev_err(di->dev, "error reading current\n");
		return 0;
	}

	curr = get_unaligned_le16(buf);
	DBG("curr = %x \n",curr);
	if(curr>0x8000){
		curr = 0xFFFF^(curr-1);
	}
	curr = curr * 1000;
	DBG("Enter:%s %d--curr = %d\n",__FUNCTION__,__LINE__,curr);
	return curr;
}
예제 #10
0
static void bq27541_set(void)
{
	struct bq27541_device_info *di;
	int i = 0;
	u8 buf[2];

	di = bq27541_di;

	printk("enter 0x41\n");
	buf[0] = 0x41;
	buf[1] = 0x00;
	bq27541_write(di->client,0x00,buf,2);
	msleep(1500);
		
	printk("enter 0x21\n");
	buf[0] = 0x21;
	buf[1] = 0x00;
	bq27541_write(di->client,0x00,buf,2);


	buf[0] = 0;
	buf[1] = 0;
	bq27541_read(di->client,0x00,buf,2);


	while((buf[0] & 0x04)&&(i<5))
	{
		printk("enter more 0x21 times i = %d\n",i);
		mdelay(1000);
		buf[0] = 0x21;
		buf[1] = 0x00;
		bq27541_write(di->client,0x00,buf,2);

		buf[0] = 0;
		buf[1] = 0;
		bq27541_read(di->client,0x00,buf,2);
		i++;
	}

	if(i>5)
	   	printk("write 0x21 error\n");
	else
		printk("bq27541 write 0x21 success\n");
}
/*
 * Return the battery temperature in tenths of degree Celsius
 * Or < 0 if something fails.
 */
static int bq27541_battery_temperature(struct bq27541_device_info *di)
{
    int ret;
    int temp = 0;

#ifdef CONFIG_MACH_OPPO
    static int count = 0;

    if (atomic_read(&di->suspended) == 1) {
        return di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
    }

    if (di->alow_reading == true) {
        ret = bq27541_read(BQ27541_REG_TEMP, &temp, 0, di);
        if (ret) {
            count++;
            dev_err(di->dev, "error reading temperature\n");
            if (count > 1) {
                count = 0;
                di->temp_pre = -400 -
                               ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
                return -400;
            } else {
                return di->temp_pre +
                       ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
            }
        }
        count = 0;
    } else {
        return di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
    }

    di->temp_pre = temp;
#else
    ret = bq27541_read(BQ27541_REG_TEMP, &temp, 0, di);
    if (ret) {
        dev_err(di->dev, "error reading temperature\n");
        return ret;
    }
#endif

    return temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
}
static void bq27541_hw_config(struct work_struct *work)
{
    int ret = 0, flags = 0, type = 0, fw_ver = 0;
    struct bq27541_device_info *di;

    di  = container_of(work, struct bq27541_device_info, hw_config.work);
    ret = bq27541_chip_config(di);
    if (ret) {
        dev_err(di->dev, "Failed to config Bq27541\n");
#ifdef CONFIG_MACH_OPPO
        di->retry_count--;
        if (di->retry_count > 0) {
            schedule_delayed_work(&di->hw_config, HZ);
        }
#endif
        return;
    }
#ifdef CONFIG_MACH_OPPO
    qpnp_battery_gauge_register(&bq27541_batt_gauge);
#else
    msm_battery_gauge_register(&bq27541_batt_gauge);
#endif

    bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS);
    udelay(66);
    bq27541_read(BQ27541_REG_CNTL, &flags, 0, di);
    bq27541_cntl_cmd(di, BQ27541_SUBCMD_DEVCIE_TYPE);
    udelay(66);
    bq27541_read(BQ27541_REG_CNTL, &type, 0, di);
    bq27541_cntl_cmd(di, BQ27541_SUBCMD_FW_VER);
    udelay(66);
    bq27541_read(BQ27541_REG_CNTL, &fw_ver, 0, di);

#ifdef CONFIG_MACH_OPPO
    di->is_authenticated = bq27541_authenticate(di->client);
    di->battery_type = bq27541_batt_type_detect(di->client);
#endif

    dev_info(di->dev, "DEVICE_TYPE is 0x%02X, FIRMWARE_VERSION is 0x%02X\n",
             type, fw_ver);
    dev_info(di->dev, "Complete bq27541 configuration 0x%02X\n", flags);
}
예제 #13
0
static void bq27541_coulomb_counter_work(struct work_struct *work)
{
	int value = 0, temp = 0, index = 0, ret = 0;
	struct bq27541_device_info *di;
	unsigned long flags;
	int count = 0;

	di = container_of(work, struct bq27541_device_info, counter);

	/* retrieve 30 values from FIFO of coulomb data logging buffer
	 * and average over time
	 */
	do {
		ret = bq27541_read(BQ27541_REG_LOGBUF, &temp, 0, di);
		if (ret < 0)
			break;
		if (temp != 0x7FFF) {
			++count;
			value += temp;
		}
		/* delay 66uS, waiting time between continuous reading
		 * results
		 */
		udelay(66);
		ret = bq27541_read(BQ27541_REG_LOGIDX, &index, 0, di);
		if (ret < 0)
			break;
		udelay(66);
	} while (index != 0 || temp != 0x7FFF);

	if (ret < 0) {
		dev_err(di->dev, "Error reading datalog register\n");
		return;
	}

	if (count) {
		spin_lock_irqsave(&lock, flags);
		coulomb_counter = value/count;
		spin_unlock_irqrestore(&lock, flags);
	}
}
예제 #14
0
/*
 * Return the battery temperature in tenths of degree Celsius
 * Or < 0 if something fails.
 */
static int bq27541_battery_temperature(struct bq27541_device_info *di)
{
	int ret;
	int temp = 0;

	ret = bq27541_read(BQ27541_REG_TEMP, &temp, 0, di);
	if (ret) {
		dev_err(di->dev, "error reading temperature\n");
		return ret;
	}

	return temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
}
예제 #15
0
/*
 * Return the battery Voltage in milivolts
 * Or < 0 if something fails.
 */
static int bq27541_battery_voltage(struct bq27541_device_info *di)
{
	int ret;
	int volt = 0;

	ret = bq27541_read(BQ27541_REG_VOLT, &volt, 0, di);
	if (ret) {
		dev_err(di->dev, "error reading voltage\n");
		return ret;
	}

	return volt * 1000;
}
static int bq27541_remaining_capacity(struct bq27541_device_info *di)
{
    int ret;
    int cap = 0;

    if(di->alow_reading == true) {
        ret = bq27541_read(BQ27541_REG_RM, &cap, 0, di);
        if (ret) {
            dev_err(di->dev, "error reading capacity.\n");
            return ret;
        }
    }

    return cap;
}
예제 #17
0
static int bq27541_battery_voltage(struct bq27541_device_info *di)
{
	int ret;
	u8 buf[2] = {0};
	int volt = 0;

	#if defined (CONFIG_NO_BATTERY_IC)
		return 4000000;
	#endif
	if(virtual_battery_enable == 1)
		return 2000000/*4000000*/;

	ret = bq27541_read(di->client,BQ27x00_REG_VOLT,buf,2); 
	if (ret<0) {
		dev_err(di->dev, "error reading voltage\n");
//		gpio_set_value(POWER_ON_PIN, GPIO_LOW);
		return ret;
	}
	volt = get_unaligned_le16(buf);

	//bp27510 can only measure one li-lion bat
	if(di->bat_num == 2){
		volt = volt * 1000 * 2;
	}else{
		volt = volt * 1000;
	}
		


	
	if ((volt <= 3400000)  && (volt > 0) && gpio_get_value(di->dc_check_pin)){
		printk("vol smaller then 3.4V, report to android!");
		di->power_down = 1;
	}else{
		di->power_down = 0;
	}

	
	DBG("Enter:%s %d--volt = %d\n",__FUNCTION__,__LINE__,volt);
	return volt;
}
예제 #18
0
/*
 * Read a time register.
 * Return < 0 if something fails.
 */
static int bq27541_battery_time(struct bq27541_device_info *di, int reg,
				union power_supply_propval *val)
{
	u8 buf[2] = {0};
	int tval = 0;
	int ret;

	ret = bq27541_read(di->client,reg,buf,2);
	if (ret<0) {
		dev_err(di->dev, "error reading register %02x\n", reg);
		return ret;
	}
	tval = get_unaligned_le16(buf);
	DBG("Enter:%s %d--tval=%d\n",__FUNCTION__,__LINE__,tval);
	if (tval == 65535)
		return -ENODATA;

	val->intval = tval * 60;
	DBG("Enter:%s %d val->intval = %d\n",__FUNCTION__,__LINE__,val->intval);
	return 0;
}
static int bq27541_battery_soc(struct bq27541_device_info *di, bool raw)
{
    int ret;
    int soc = 0;

    if (atomic_read(&di->suspended) == 1) {
        return di->soc_pre;
    }

    if (di->alow_reading == true) {
        ret = bq27541_read(BQ27541_REG_SOC, &soc, 0, di);
        if (ret) {
            dev_err(di->dev, "error reading soc.ret:%d\n",ret);
            goto read_soc_err;
        }
    } else {
        if(di->soc_pre)
            return di->soc_pre;
        else
            return 0;
    }

    if (raw == true) {
        if(soc > 90) {
            soc += 2;
        }
        if(soc <= di->soc_pre) {
            di->soc_pre = soc;
        }
    }

    soc = bq27541_soc_calibrate(di,soc);
    return soc;

read_soc_err:
    if (di->soc_pre)
        return di->soc_pre;
    else
        return 0;
}
예제 #20
0
static ssize_t bq27541_read_stdcmd(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	int ret;
	int temp = 0;
	struct platform_device *client;
	struct bq27541_device_info *di;

	client = to_platform_device(dev);
	di = platform_get_drvdata(client);

	if (reg <= BQ27541_REG_ICR && reg > 0x00) {
		ret = bq27541_read(reg, &temp, 0, di);
		if (ret)
			ret = snprintf(buf, PAGE_SIZE, "Read Error!\n");
		else
			ret = snprintf(buf, PAGE_SIZE, "0x%02x\n", temp);
	} else
		ret = snprintf(buf, PAGE_SIZE, "Register Error!\n");

	return ret;
}
예제 #21
0
static int bq27541_battery_temperature(struct bq27541_device_info *di)
{
	int ret;
	int temp = 0;
	u8 buf[2] ={0};

	#if defined (CONFIG_NO_BATTERY_IC)
	return 258;
	#endif

	if(virtual_battery_enable == 1)
		return 125/*258*/;
	ret = bq27541_read(di->client,BQ27x00_REG_TEMP,buf,2);
	if (ret<0) {
		dev_err(di->dev, "error reading temperature\n");
		return ret;
	}
	temp = get_unaligned_le16(buf);
	temp = temp - 2731;  //K
	DBG("Enter:%s %d--temp = %d\n",__FUNCTION__,__LINE__,temp);

//	rk29_pm_power_off();
	return temp;
}
예제 #22
0
static int bq27541_chip_config(struct bq27541_device_info *di)
{
	int flags = 0, ret = 0;

	bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS);
	udelay(66);
	ret = bq27541_read(BQ27541_REG_CNTL, &flags, 0, di);
	if (ret < 0) {
		dev_err(di->dev, "error reading register %02x ret = %d\n",
			 BQ27541_REG_CNTL, ret);
		return ret;
	}
	udelay(66);

	bq27541_cntl_cmd(di, BQ27541_SUBCMD_ENABLE_IT);
	udelay(66);

	if (!(flags & BQ27541_CS_DLOGEN)) {
		bq27541_cntl_cmd(di, BQ27541_SUBCMD_ENABLE_DLOG);
		udelay(66);
	}

	return 0;
}
예제 #23
0
/*
 * Return the battery Relative State-of-Charge
 * Or < 0 if something fails.
 */
static int bq27541_battery_rsoc(struct bq27541_device_info *di)
{
	int ret;
	int rsoc = 0;
	int flags = 0;
	int status = 0;
	#if 0
	int nvcap = 0,facap = 0,remcap=0,fccap=0,full=0,cnt=0;
	int art = 0, artte = 0, ai = 0, tte = 0, ttf = 0, si = 0;
	int stte = 0, mli = 0, mltte = 0, ae = 0, ap = 0, ttecp = 0, cc = 0;
	#endif
	u8 buf[2];

	#if defined (CONFIG_NO_BATTERY_IC)
		return 100;
	#endif
	if(virtual_battery_enable == 1)
		return 50/*100*/;
	
	ret = bq27541_read(di->client,BQ27500_REG_SOC,buf,2); 
	if (ret<0) {
		dev_err(di->dev, "error reading relative State-of-Charge\n");
		return ret;
	}
	rsoc = get_unaligned_le16(buf);
	DBG("Enter:%s %d--read rsoc = %d\n",__FUNCTION__,__LINE__,rsoc);

	/* covert the capacity range */
	rsoc = min(rsoc, 100);
	if ((g_pdata != NULL) && g_pdata->capacity_max && g_pdata->capacity_min) {
		rsoc = max(rsoc, g_pdata->capacity_min);
		rsoc = ((rsoc - g_pdata->capacity_min) * 100 +
			(g_pdata->capacity_max - g_pdata->capacity_min) / 2)
			/ (g_pdata->capacity_max - g_pdata->capacity_min);
	}
	bq27541_cap = rsoc;

	/*check full flags,if not full, show 99%*/
	ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2);
	if (ret < 0) {
		dev_err(di->dev, "error reading flags\n");
		return ret;
	}
	flags = get_unaligned_le16(buf);
	DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags);
	if ((bq27541_cap > 99) && (flags & BQ27500_FLAG_FC))
		status = POWER_SUPPLY_STATUS_FULL;

	if(status != POWER_SUPPLY_STATUS_FULL)
		rsoc = min(rsoc, 99);

	DBG("Enter:%s %d--cal rsoc = %d\n",__FUNCTION__,__LINE__,rsoc);
	#if defined (CONFIG_NO_BATTERY_IC)
	rsoc = 100;
	#endif
	#if 0     //other register information, for debug use
	ret = bq27541_read(di->client,0x0c,buf,2);		//NominalAvailableCapacity
	nvcap = get_unaligned_le16(buf);
	DBG("\nEnter:%s %d--nvcap = %d\n",__FUNCTION__,__LINE__,nvcap);
	ret = bq27541_read(di->client,0x0e,buf,2);		//FullAvailableCapacity
	facap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--facap = %d\n",__FUNCTION__,__LINE__,facap);
	ret = bq27541_read(di->client,0x10,buf,2);		//RemainingCapacity
	remcap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--remcap = %d\n",__FUNCTION__,__LINE__,remcap);
	ret = bq27541_read(di->client,0x12,buf,2);		//FullChargeCapacity
	fccap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--fccap = %d\n",__FUNCTION__,__LINE__,fccap);
	ret = bq27541_read(di->client,0x3c,buf,2);		//DesignCapacity
	full = get_unaligned_le16(buf);
	DBG("Enter:%s %d--DesignCapacity = %d\n",__FUNCTION__,__LINE__,full);
	
	buf[0] = 0x00;						//CONTROL_STATUS
	buf[1] = 0x00;
	bq27541_write(di->client,0x00,buf,2);
	ret = bq27541_read(di->client,0x00,buf,2);
	cnt = get_unaligned_le16(buf);
	DBG("Enter:%s %d--Control status = %x\n",__FUNCTION__,__LINE__,cnt);

	ret = bq27541_read(di->client,0x02,buf,2);		//AtRate
	art = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AtRate = %d\n",__FUNCTION__,__LINE__,art);
	ret = bq27541_read(di->client,0x04,buf,2);		//AtRateTimeToEmpty
	artte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AtRateTimeToEmpty = %d\n",__FUNCTION__,__LINE__,artte);
	ret = bq27541_read(di->client,0x14,buf,2);		//AverageCurrent
	ai = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AverageCurrent = %d\n",__FUNCTION__,__LINE__,ai);
	ret = bq27541_read(di->client,0x16,buf,2);		//TimeToEmpty
	tte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--TimeToEmpty = %d\n",__FUNCTION__,__LINE__,tte);
	ret = bq27541_read(di->client,0x18,buf,2);		//TimeToFull
	ttf = get_unaligned_le16(buf);
	DBG("Enter:%s %d--TimeToFull = %d\n",__FUNCTION__,__LINE__,ttf);
	ret = bq27541_read(di->client,0x1a,buf,2);		//StandbyCurrent
	si = get_unaligned_le16(buf);
	DBG("Enter:%s %d--StandbyCurrent = %d\n",__FUNCTION__,__LINE__,si);
	ret = bq27541_read(di->client,0x1c,buf,2);		//StandbyTimeToEmpty
	stte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--StandbyTimeToEmpty = %d\n",__FUNCTION__,__LINE__,stte);
	ret = bq27541_read(di->client,0x1e,buf,2);		//MaxLoadCurrent
	mli = get_unaligned_le16(buf);
	DBG("Enter:%s %d--MaxLoadCurrent = %d\n",__FUNCTION__,__LINE__,mli);
	ret = bq27541_read(di->client,0x20,buf,2);		//MaxLoadTimeToEmpty
	mltte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--MaxLoadTimeToEmpty = %d\n",__FUNCTION__,__LINE__,mltte);
	ret = bq27541_read(di->client,0x22,buf,2);		//AvailableEnergy
	ae = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AvailableEnergy = %d\n",__FUNCTION__,__LINE__,ae);
	ret = bq27541_read(di->client,0x24,buf,2);		//AveragePower
	ap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AveragePower = %d\n",__FUNCTION__,__LINE__,ap);
	ret = bq27541_read(di->client,0x26,buf,2);		//TTEatConstantPower
	ttecp = get_unaligned_le16(buf);
	DBG("Enter:%s %d--TTEatConstantPower = %d\n",__FUNCTION__,__LINE__,ttecp);
	ret = bq27541_read(di->client,0x2a,buf,2);		//CycleCount
	cc = get_unaligned_le16(buf);
	DBG("Enter:%s %d--CycleCount = %d\n",__FUNCTION__,__LINE__,cc);
	#endif
	return rsoc;
}
예제 #24
0
static int bq27541_battery_probe(struct i2c_client *client,
				 const struct i2c_device_id *id)
{
	struct bq27541_device_info *di;
	int retval = 0;
	struct bq27541_platform_data *pdata;
	int val =0;
	char buf[2];
	int volt;
	DBG("**********  bq27541_battery_probe**************  ");
	pdata = client->dev.platform_data;
	g_pdata = pdata;

	di = kzalloc(sizeof(*di), GFP_KERNEL);
	if (!di) {
		dev_err(&client->dev, "failed to allocate device info data\n");
		retval = -ENOMEM;
		goto batt_failed_2;
	}
	i2c_set_clientdata(client, di);
	di->dev = &client->dev;
	di->bat.name = "battery";
	di->client = client;
	/* 1 seconds between monotor runs interval */
	di->interval = msecs_to_jiffies(4 * 1000);
	
	di->bat_num = pdata->bat_num;
	di->dc_check_pin = pdata->dc_check_pin;
	di->bat_check_pin = pdata->bat_check_pin;
	
	if (pdata->init_dc_check_pin)
		pdata->init_dc_check_pin( );
	
	bq27541_powersupply_init(di);
	mutex_init(&g_bq27541_mutex);

	retval = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2);
	if (retval < 0) {
		printk("can't find bq27541\n");
		goto batt_failed_2;
	}else{
		rk30_bat_unregister();
		bq27541_init = 1;
	}
	
	retval = power_supply_register(&client->dev, &di->bat);
	if (retval) {
		dev_err(&client->dev, "failed to register battery\n");
		goto batt_failed_4;
	}
	bq27541_di = di;
#if 0
	retval = power_supply_register(&client->dev, &di->ac);
	if (retval) {
		dev_err(&client->dev, "failed to register ac\n");
		goto batt_failed_4;
	}
#endif

	INIT_DELAYED_WORK(&di->work, bq27541_battery_work);
	schedule_delayed_work(&di->work, di->interval);
	dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);

	battery_capacity_check(di);
#if defined(CONFIG_CHARGER_LIMITED_BY_TEMP)
	bq27541_sysfs_init();
#endif

	return 0;

batt_failed_4:
	kfree(di);
batt_failed_2:

err_batirq_failed:
	gpio_free(pdata->bat_check_pin);

	return retval;
}
예제 #25
0
static int bq27541_battery_probe(struct i2c_client *client,
				 const struct i2c_device_id *id)
{
	struct bq27541_device_info *di;
	int retval = 0;
	struct bq27541_platform_data *pdata;
	int val =0;
	char buf[2];
	int volt;
	DBG("**********  bq27541_battery_probe**************  ");
	pdata = client->dev.platform_data;
	
	di = kzalloc(sizeof(*di), GFP_KERNEL);
	if (!di) {
		dev_err(&client->dev, "failed to allocate device info data\n");
		retval = -ENOMEM;
		goto batt_failed_2;
	}
	i2c_set_clientdata(client, di);
	di->dev = &client->dev;
	di->bat.name = "bq27541-battery";
	di->client = client;
	/* 4 seconds between monotor runs interval */
	di->interval = msecs_to_jiffies(4 * 1000);
	
	di->bat_num = pdata->bat_num;
	di->dc_check_pin = pdata->dc_check_pin;
	di->bat_check_pin = pdata->bat_check_pin;
	
	if (pdata->init_dc_check_pin)
		pdata->init_dc_check_pin( );
	
	bq27541_powersupply_init(di);

	
	
	retval = power_supply_register(&client->dev, &di->bat);
	if (retval) {
		dev_err(&client->dev, "failed to register battery\n");
		goto batt_failed_4;
	}
	bq27541_di = di;
	retval = power_supply_register(&client->dev, &di->ac);
	if (retval) {
		dev_err(&client->dev, "failed to register ac\n");
		goto batt_failed_4;
	}
	INIT_DELAYED_WORK(&di->work, bq27541_battery_work);
	schedule_delayed_work(&di->work, di->interval);
	dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);

#if  !defined (CONFIG_NO_BATTERY_IC)

	// no battery  , no power up
	gpio_request(POWER_ON_PIN, "poweronpin");
	gpio_request(pdata->bat_check_pin, NULL);
	gpio_direction_input(pdata->bat_check_pin);
	gpio_request(pdata->chgok_check_pin, "CHG_OK");
	gpio_direction_input(pdata->chgok_check_pin);

	val = gpio_get_value(pdata->bat_check_pin);
	if (val == 1){
		printk("\n\n!!! bat_low  high !!!\n\n");
		val = bq27541_read(di->client,BQ27x00_REG_VOLT,buf,2);
		if (val < 0){
			printk("\n\n!!! bq i2c err! no battery,  power down\n!!!\n\n");
			gpio_direction_output(POWER_ON_PIN, GPIO_LOW);	
			while(1){
				gpio_set_value(POWER_ON_PIN, GPIO_LOW);
				mdelay(100);
			}
		}

	}else{
			
		printk("\n\n!!! bat_low  low !!!\n\n");
		val = gpio_get_value(pdata->chgok_check_pin);
		if (val == 1){
			printk("no battery, power down \n");
			gpio_direction_output(POWER_ON_PIN, GPIO_LOW);
			while(1){
				gpio_set_value(POWER_ON_PIN, GPIO_LOW);
				mdelay(100);
			}
		}else{
			mdelay(1000);
			val = gpio_get_value(pdata->chgok_check_pin);
			if (val == 1){
				printk("no battery, power down \n");
				gpio_direction_output(POWER_ON_PIN, GPIO_LOW);			
				while(1){
					gpio_set_value(POWER_ON_PIN, GPIO_LOW);
					mdelay(100);
				}
			}
		}

	}

//	gpio_free(POWER_ON_PIN);
//	gpio_free(pdata->bat_check_pin);
	gpio_free(pdata->chgok_check_pin);


	//smaller  3.4V , no power up
	if (gpio_get_value(di->dc_check_pin) && (gpio_get_value(pdata->bat_check_pin) == 0)){
			printk("no AC && battery low ,so power down \n");
			gpio_direction_output(POWER_ON_PIN, GPIO_LOW);			
			while(1){
				printk("no AC && battery low ,so power down \n");
				gpio_set_value(POWER_ON_PIN, GPIO_LOW);
				mdelay(100);
			}
	}	

	
	// battery low irq
	di->wake_irq = gpio_to_irq(pdata->bat_check_pin);
	retval = request_irq(di->wake_irq, bq27541_bat_wakeup, IRQF_TRIGGER_FALLING, "bq27541_battery", di);
	if (retval) {
		printk("failed to request bat det irq\n");
		goto err_batirq_failed;
	}
	
	INIT_DELAYED_WORK(&di->wakeup_work, bq27541_battery_wake_work);
	enable_irq_wake(di->wake_irq);


#endif
	
	return 0;

batt_failed_4:
	kfree(di);
batt_failed_2:

err_batirq_failed:
	gpio_free(pdata->bat_check_pin);

	return retval;
}
예제 #26
0
/*
 * Return the battery Relative State-of-Charge
 * Or < 0 if something fails.
 */
static int bq27541_battery_rsoc(struct bq27541_device_info *di)
{
	int ret;
	int rsoc = 0;
	#if 0
	int nvcap = 0,facap = 0,remcap=0,fccap=0,full=0,cnt=0;
	int art = 0, artte = 0, ai = 0, tte = 0, ttf = 0, si = 0;
	int stte = 0, mli = 0, mltte = 0, ae = 0, ap = 0, ttecp = 0, cc = 0;
	#endif
	u8 buf[2];

	#if defined (CONFIG_NO_BATTERY_IC)
		return 100;
	#endif
	if(virtual_battery_enable == 1)
		return 50/*100*/;
	
	ret = bq27541_read(di->client,BQ27500_REG_SOC,buf,2); 
	if (ret<0) {
		dev_err(di->dev, "error reading relative State-of-Charge\n");
		return ret;
	}
	rsoc = get_unaligned_le16(buf);
	DBG("Enter:%s %d--rsoc = %d\n",__FUNCTION__,__LINE__,rsoc);

	#if defined (CONFIG_NO_BATTERY_IC)
	rsoc = 100;
	#endif
	#if 0     //other register information, for debug use
	ret = bq27541_read(di->client,0x0c,buf,2);		//NominalAvailableCapacity
	nvcap = get_unaligned_le16(buf);
	DBG("\nEnter:%s %d--nvcap = %d\n",__FUNCTION__,__LINE__,nvcap);
	ret = bq27541_read(di->client,0x0e,buf,2);		//FullAvailableCapacity
	facap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--facap = %d\n",__FUNCTION__,__LINE__,facap);
	ret = bq27541_read(di->client,0x10,buf,2);		//RemainingCapacity
	remcap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--remcap = %d\n",__FUNCTION__,__LINE__,remcap);
	ret = bq27541_read(di->client,0x12,buf,2);		//FullChargeCapacity
	fccap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--fccap = %d\n",__FUNCTION__,__LINE__,fccap);
	ret = bq27541_read(di->client,0x3c,buf,2);		//DesignCapacity
	full = get_unaligned_le16(buf);
	DBG("Enter:%s %d--DesignCapacity = %d\n",__FUNCTION__,__LINE__,full);
	
	buf[0] = 0x00;						//CONTROL_STATUS
	buf[1] = 0x00;
	bq27541_write(di->client,0x00,buf,2);
	ret = bq27541_read(di->client,0x00,buf,2);
	cnt = get_unaligned_le16(buf);
	DBG("Enter:%s %d--Control status = %x\n",__FUNCTION__,__LINE__,cnt);

	ret = bq27541_read(di->client,0x02,buf,2);		//AtRate
	art = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AtRate = %d\n",__FUNCTION__,__LINE__,art);
	ret = bq27541_read(di->client,0x04,buf,2);		//AtRateTimeToEmpty
	artte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AtRateTimeToEmpty = %d\n",__FUNCTION__,__LINE__,artte);
	ret = bq27541_read(di->client,0x14,buf,2);		//AverageCurrent
	ai = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AverageCurrent = %d\n",__FUNCTION__,__LINE__,ai);
	ret = bq27541_read(di->client,0x16,buf,2);		//TimeToEmpty
	tte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--TimeToEmpty = %d\n",__FUNCTION__,__LINE__,tte);
	ret = bq27541_read(di->client,0x18,buf,2);		//TimeToFull
	ttf = get_unaligned_le16(buf);
	DBG("Enter:%s %d--TimeToFull = %d\n",__FUNCTION__,__LINE__,ttf);
	ret = bq27541_read(di->client,0x1a,buf,2);		//StandbyCurrent
	si = get_unaligned_le16(buf);
	DBG("Enter:%s %d--StandbyCurrent = %d\n",__FUNCTION__,__LINE__,si);
	ret = bq27541_read(di->client,0x1c,buf,2);		//StandbyTimeToEmpty
	stte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--StandbyTimeToEmpty = %d\n",__FUNCTION__,__LINE__,stte);
	ret = bq27541_read(di->client,0x1e,buf,2);		//MaxLoadCurrent
	mli = get_unaligned_le16(buf);
	DBG("Enter:%s %d--MaxLoadCurrent = %d\n",__FUNCTION__,__LINE__,mli);
	ret = bq27541_read(di->client,0x20,buf,2);		//MaxLoadTimeToEmpty
	mltte = get_unaligned_le16(buf);
	DBG("Enter:%s %d--MaxLoadTimeToEmpty = %d\n",__FUNCTION__,__LINE__,mltte);
	ret = bq27541_read(di->client,0x22,buf,2);		//AvailableEnergy
	ae = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AvailableEnergy = %d\n",__FUNCTION__,__LINE__,ae);
	ret = bq27541_read(di->client,0x24,buf,2);		//AveragePower
	ap = get_unaligned_le16(buf);
	DBG("Enter:%s %d--AveragePower = %d\n",__FUNCTION__,__LINE__,ap);
	ret = bq27541_read(di->client,0x26,buf,2);		//TTEatConstantPower
	ttecp = get_unaligned_le16(buf);
	DBG("Enter:%s %d--TTEatConstantPower = %d\n",__FUNCTION__,__LINE__,ttecp);
	ret = bq27541_read(di->client,0x2a,buf,2);		//CycleCount
	cc = get_unaligned_le16(buf);
	DBG("Enter:%s %d--CycleCount = %d\n",__FUNCTION__,__LINE__,cc);
	#endif
	return rsoc;
}
예제 #27
0
static int bq27541_battery_status(struct bq27541_device_info *di,
				  union power_supply_propval *val)
{
	u8 buf[2] = {0};
	int flags = 0;
	int status = 0;
	int ret = 0;

#if defined (CONFIG_NO_BATTERY_IC)
	val->intval = POWER_SUPPLY_STATUS_FULL;
	return 0;
#endif
	if(virtual_battery_enable == 1)
	{
		val->intval = POWER_SUPPLY_STATUS_FULL;
		return 0;
	}

	ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2);
	if (ret < 0) {
		dev_err(di->dev, "error reading flags\n");
		return ret;
	}
	flags = get_unaligned_le16(buf);
	DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags);

#if 0
	if (flags & BQ27500_FLAG_FC)
		status = POWER_SUPPLY_STATUS_FULL;
	else if (flags & BQ27500_FLAG_DSC)
		status = POWER_SUPPLY_STATUS_DISCHARGING;
	else
		status = POWER_SUPPLY_STATUS_CHARGING;
#else
	if ((g_pdata != NULL) && g_pdata->get_charging_stat)
	{
#ifdef CONFIG_BATTERY_BQ24196_OTG_MODE
		if(!(*g_pdata->get_charging_stat)() || (bq24196_mode == 1))
#else
		if(!(*g_pdata->get_charging_stat)())
#endif
			status = POWER_SUPPLY_STATUS_DISCHARGING;
		else if(1 == (*g_pdata->get_charging_stat)()){
			if ((bq27541_cap > 99) && (flags & BQ27500_FLAG_FC))
				status = POWER_SUPPLY_STATUS_FULL;
			else
				status = POWER_SUPPLY_STATUS_CHARGING;
		}
	}
#endif
#if defined(CONFIG_CHARGER_LIMITED_BY_TEMP)
		if((1 == check_charge_ok) && (!strstr(saved_command_line,"charger"))){
			if(1 == charge_en_flags)
			{
				if(status != POWER_SUPPLY_STATUS_DISCHARGING){
					status = POWER_SUPPLY_STATUS_DISCHARGING;
					stop_charging = 1;
				}
			}else{
				stop_charging = 0;
			}

			if(1 == update_temp_ok){
                        	if(1 == charge_en_flags)
                                        status = POWER_SUPPLY_STATUS_NOT_CHARGING;
                                else
                                        update_temp_ok = 0; 
			}
		}
#endif

	val->intval = status;
	DBG("Enter:%s %d--status = %x\n",__FUNCTION__,__LINE__,status);
	return 0;
}