staticint ltc294x_reset(conststruct 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) return ret;
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) return ret;
}
ret = ltc294x_read_regs(info->client, reg, &datar[0], 2); if (ret < 0) return ret; return (datar[0] << 8) + datar[1];
}
staticint ltc294x_get_charge(conststruct ltc294x_info *info, enum ltc294x_reg reg, int *val)
{ int value = ltc294x_read_charge_register(info, reg);
if (value < 0) return value; /* When r_sense < 0, this counts up when the battery discharges */ if (info->Qlsb < 0)
value -= 0xFFFF;
*val = convert_bin_to_uAh(info, value); return 0;
}
staticint ltc294x_set_charge_now(conststruct 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);
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;
/* Set new charge value */
dataw[0] = I16_MSB(value);
dataw[1] = I16_LSB(value); return ltc294x_write_regs(info->client, reg, &dataw[0], 2);
}
staticint ltc294x_get_charge_counter( conststruct ltc294x_info *info, int *val)
{ int value = ltc294x_read_charge_register(info, LTC294X_REG_ACC_CHARGE_MSB);
if (value < 0) return value;
value -= LTC294X_MID_SUPPLY;
*val = convert_bin_to_uAh(info, value); return 0;
}
staticint ltc294x_get_voltage(conststruct 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;
}
staticint ltc294x_get_current(conststruct ltc294x_info *info, int *val)
{ int ret;
u8 datar[2];
s32 value;
ret = ltc294x_read_regs(info->client,
LTC2943_REG_CURRENT_MSB, &datar[0], 2);
value = (datar[0] << 8) | datar[1];
value -= 0x7FFF; if (info->id == LTC2944_ID)
value *= 64000; else
value *= 60000; /* 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 * (value / (info->r_sense * 0x7FFF)); /* in uA */ return ret;
}
staticint ltc294x_get_temperature(conststruct 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 = 6000; /* Full-scale is 600 Kelvin */
} else {
reg = LTC2943_REG_TEMPERATURE_MSB;
value = 5100; /* Full-scale is 510 Kelvin */
}
ret = ltc294x_read_regs(info->client, reg, &datar[0], 2);
value *= (datar[0] << 8) | datar[1]; /* Convert to tenths of degree Celsius */
*val = value / 0xFFFF - 2722; return ret;
}
/* r_sense can be negative, when sense+ is connected to the battery
* instead of the sense-. This results in reversed measurements. */
ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense); if (ret < 0) return dev_err_probe(&client->dev, ret, "Could not find lltc,resistor-sense in devicetree\n");
info->r_sense = r_sense;
ret = of_property_read_u32(np, "lltc,prescaler-exponent",
&prescaler_exp); if (ret < 0) {
dev_warn(&client->dev, "lltc,prescaler-exponent not in devicetree\n");
prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
}
/* The LTC2941 does not need any special handling */ if (info->id == LTC2941_ID) return;
/* Read control register */
ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1); if (ret < 0) return;
/* Disable continuous ADC conversion as this drains the battery */
control = LTC294X_REG_CONTROL_ADC_DISABLE(value); if (control != value)
ltc294x_write_regs(info->client, LTC294X_REG_CONTROL,
&control, 1);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.