示例#1
0
int ltc294x_get_current( int *val) {
	struct ltc294x_info *info = &ltc2943_info;
    int ret;
    u8 datar[2];
    s32 value;
	
	// reset will have manual trigger control flag sent
	// ltc294x_reset(2);
	
//	for(i=0;i<5;i++)
//	{
//		nrf_delay_ms(40);
//		ret = ltc294x_read_regs(info->client,
//                LTC294X_REG_CONTROL, &datar[0], 1);
//		if((datar[0]&LTC2943_REG_CONTROL_MODE_MASK)==0)
//			break;
//	}
//	if (i>=5) return -1;
	
	
	ret = ltc294x_read_regs(info->client,
			LTC294X_REG_CURRENT_MSB, &datar[0], 2);
	value = (datar[0] << 8) | datar[1];
	value -= 0x7FFF;
	/* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm,
	 * the formula below keeps everything in s32 range while preserving
	 * enough digits */
	*val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); 			/* in uA */
	return ret;
}
示例#2
0
static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
{
        int ret;
        u8 value;
        u8 control;

        /* Read status and control registers */
        ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
        if (ret < 0) {
                dev_err(&info->client->dev,
                        "Could not read registers from device\n");
                goto error_exit;
        }

        control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
                                LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
        /* Put the 2943 into "monitor" mode, so it measures every 10 sec */
        if (info->num_regs == LTC2943_NUM_REGS)
                control |= LTC2943_REG_CONTROL_MODE_SCAN;

        if (value != control) {
                ret = ltc294x_write_regs(info->client,
                        LTC294X_REG_CONTROL, &control, 1);
                if (ret < 0) {
                        dev_err(&info->client->dev,
                                "Could not write register\n");
                        goto error_exit;
                }
        }

        return 0;

error_exit:
        return ret;
}
示例#3
0
static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val)
{
	int ret;
	u8 datar[2];
	u32 value;

	ret = ltc294x_read_regs(info->client,
		LTC294X_REG_VOLTAGE_MSB, &datar[0], 2);
	value = (datar[0] << 8) | datar[1];
	switch (info->id) {
	case LTC2943_ID:
		value *= 23600 * 2;
		value /= 0xFFFF;
		value *= 1000 / 2;
		break;
	case LTC2944_ID:
		value *= 70800 / 5*4;
		value /= 0xFFFF;
		value *= 1000 * 5/4;
		break;
	default:
		value *= 6000 * 10;
		value /= 0xFFFF;
		value *= 1000 / 10;
		break;
	}
	*val = value;
	return ret;
}
示例#4
0
int ltc294x_reset( int prescaler_exp) {
		struct ltc294x_info *info = &ltc2943_info;
        int ret;
        u8 value[3];
        u8 control;

        /* Read status and control registers */
	ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value[0], 1);
        if (ret < 0) {
                dev_err(&info->client->dev,
                        "Could not read registers from device\n");
                goto error_exit;
        }

        control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
                                LTC294X_REG_CONTROL_ALCC_CONFIG_OUTPUT_ALERT;
        /* Set the 2943 mode*/
        if (info->num_regs == LTC2943_NUM_REGS)
                control |= LTC2943_REG_CONTROL_MODE_SCAN;

		do {
			if (value[0] != control) {
					ret = ltc294x_write_regs(info->client,
							LTC294X_REG_CONTROL, &control, 1);
					if (ret < 0) {
							dev_err(&info->client->dev,
									"Could not write register\n");
							goto error_exit;
					}
			}
			/* Read status and control registers again */
			ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value[0], 1);
			if (ret < 0) {
					dev_err(&info->client->dev,
							"Could not read registers from device\n");
					goto error_exit;
			}
		}
		while(value[0]!= control);
		
        return 0;

error_exit:
        return ret;
}
示例#5
0
static int ltc294x_read_charge_register(const struct ltc294x_info *info)
{
        int ret;
        u8 datar[2];

        ret = ltc294x_read_regs(info->client,
                LTC294X_REG_ACC_CHARGE_MSB, &datar[0], 2);
        if (ret < 0)
                return ret;
        return (datar[0] << 8) + datar[1];
}
示例#6
0
static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val)
{
        int ret;
        u8 datar[2];
        u32 value;

        ret = ltc294x_read_regs(info->client,
                LTC294X_REG_VOLTAGE_MSB, &datar[0], 2);
        value = (datar[0] << 8) | datar[1];
        *val = ((value * 23600) / 0xFFFF) * 1000; /* in uV */
        return ret;
}
示例#7
0
static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val)
{
        int ret;
        u8 datar[2];
        u32 value;

        ret = ltc294x_read_regs(info->client,
                LTC294X_REG_TEMPERATURE_MSB, &datar[0], 2);
        value = (datar[0] << 8) | datar[1];
        /* Full-scale is 510 Kelvin, convert to centidegrees  */
        *val = (((51000 * value) / 0xFFFF) - 27215);
        return ret;
}
示例#8
0
static int ltc294x_get_current(const struct ltc294x_info *info, int *val)
{
        int ret;
        u8 datar[2];
        s32 value;

        ret = ltc294x_read_regs(info->client,
                LTC294X_REG_CURRENT_MSB, &datar[0], 2);
        value = (datar[0] << 8) | datar[1];
        value -= 0x7FFF;
        /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm,
         * the formula below keeps everything in s32 range while preserving
         * enough digits */
        *val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); /* in uA */
        return ret;
}
示例#9
0
static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
{
	int ret;
	u8 value;
	u8 control;

	/* Read status and control registers */
	ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
	if (ret < 0) {
		dev_err(&info->client->dev,
			"Could not read registers from device\n");
		goto error_exit;
	}

	control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
				LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
	/* Put device into "monitor" mode */
	switch (info->id) {
	case LTC2942_ID:	/* 2942 measures every 2 sec */
		control |= LTC2942_REG_CONTROL_MODE_SCAN;
		break;
	case LTC2943_ID:
	case LTC2944_ID:	/* 2943 and 2944 measure every 10 sec */
		control |= LTC2943_REG_CONTROL_MODE_SCAN;
		break;
	default:
		break;
	}

	if (value != control) {
		ret = ltc294x_write_regs(info->client,
			LTC294X_REG_CONTROL, &control, 1);
		if (ret < 0) {
			dev_err(&info->client->dev,
				"Could not write register\n");
			goto error_exit;
		}
	}

	return 0;

error_exit:
	return ret;
}
示例#10
0
static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val)
{
	enum ltc294x_reg reg;
	int ret;
	u8 datar[2];
	u32 value;

	if (info->id == LTC2942_ID) {
		reg = LTC2942_REG_TEMPERATURE_MSB;
		value = 60000;	/* Full-scale is 600 Kelvin */
	} else {
		reg = LTC2943_REG_TEMPERATURE_MSB;
		value = 51000;	/* Full-scale is 510 Kelvin */
	}
	ret = ltc294x_read_regs(info->client, reg, &datar[0], 2);
	value *= (datar[0] << 8) | datar[1];
	/* Convert to centidegrees  */
	*val = value / 0xFFFF - 27215;
	return ret;
}
示例#11
0
static int ltc294x_set_charge_now(const struct ltc294x_info *info, int val)
{
        int ret;
        u8 dataw[2];
        u8 ctrl_reg;
        s32 value;

        value = convert_uAh_to_bin(info, val);
        /* Direction depends on how sense+/- were connected */
        if (info->Qlsb < 0)
                value += 0xFFFF;
        if ((value < 0) || (value > 0xFFFF)) /* input validation */
                return -EINVAL;

        /* Read control register */
        ret = ltc294x_read_regs(info->client,
                LTC294X_REG_CONTROL, &ctrl_reg, 1);
        if (ret < 0)
                return ret;
        /* Disable analog section */
        ctrl_reg |= LTC294X_REG_CONTROL_SHUTDOWN_MASK;
        ret = ltc294x_write_regs(info->client,
                LTC294X_REG_CONTROL, &ctrl_reg, 1);
        if (ret < 0)
                return ret;
        /* Set new charge value */
        dataw[0] = I16_MSB(value);
        dataw[1] = I16_LSB(value);
        ret = ltc294x_write_regs(info->client,
                LTC294X_REG_ACC_CHARGE_MSB, &dataw[0], 2);
        if (ret < 0)
                goto error_exit;
        /* Enable analog section */
error_exit:
        ctrl_reg &= ~LTC294X_REG_CONTROL_SHUTDOWN_MASK;
        ret = ltc294x_write_regs(info->client,
                LTC294X_REG_CONTROL, &ctrl_reg, 1);

        return ret < 0 ? ret : 0;
}
示例#12
0
static int ltc294x_i2c_probe(struct i2c_client *client,
	const struct i2c_device_id *id)
{
	struct ltc294x_platform_data *platform_data;
	struct ltc294x_info *info;
	int ret;
	u32 prescaler_exp;
	u8 status;

	info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
	if (info == NULL)
		return -ENOMEM;

	i2c_set_clientdata(client, info);

	platform_data = client->dev.platform_data;

	info->id = (enum ltc294x_id)id->driver_data;
	info->supply.name = platform_data->name;

	/* r_sense can be negative, when sense+ is connected to the battery
	 * instead of the sense-. This results in reversed measurements. */
	info->r_sense = platform_data->r_sense;

	prescaler_exp = platform_data->prescaler_exp;

	if (info->id == LTC2943_ID) {
		if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP)
			prescaler_exp = LTC2943_MAX_PRESCALER_EXP;
		info->Qlsb = ((340 * 50000) / info->r_sense) /
				(4096 / (1 << (2*prescaler_exp)));
	} else {
		if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP)
			prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
		info->Qlsb = ((85 * 50000) / info->r_sense) /
				(128 / (1 << prescaler_exp));
	}

	/* Read status register to check for LTC2942 */
	if (info->id == LTC2941_ID || info->id == LTC2942_ID) {
		ret = ltc294x_read_regs(client, LTC294X_REG_STATUS, &status, 1);
		if (ret < 0) {
			dev_err(&client->dev,
				"Could not read status register\n");
			return ret;
		}
		if (status & LTC2941_REG_STATUS_CHIP_ID)
			info->id = LTC2941_ID;
		else
			info->id = LTC2942_ID;
	}

	info->client = client;
	info->supply.type = POWER_SUPPLY_TYPE_BATTERY;
	info->supply.properties = ltc294x_properties;
	switch (info->id) {
	case LTC2944_ID:
	case LTC2943_ID:
		info->supply.num_properties =
			ARRAY_SIZE(ltc294x_properties);
		break;
	case LTC2942_ID:
		info->supply.num_properties =
			ARRAY_SIZE(ltc294x_properties) - 1;
		break;
	case LTC2941_ID:
	default:
		info->supply.num_properties =
			ARRAY_SIZE(ltc294x_properties) - 3;
		break;
	}
	info->supply.get_property = ltc294x_get_property;
	info->supply.set_property = ltc294x_set_property;
	info->supply.property_is_writeable = ltc294x_property_is_writeable;
	info->supply.external_power_changed	= NULL;

	INIT_DELAYED_WORK(&info->work, ltc294x_work);

	ret = ltc294x_reset(info, prescaler_exp);
	if (ret < 0) {
		dev_err(&client->dev, "Communication with chip failed\n");
		return ret;
	}

	ret = power_supply_register(&client->dev, &info->supply);
	if (ret) {
		dev_err(&client->dev, "failed to register ltc2941\n");
		return ret;
	} else {
		schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
	}

	return 0;
}