/* DS2760 data, valid after calling ds2760_battery_read_status() */ unsignedlong update_time; /* jiffies when data read */ char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */ int voltage_raw; /* units of 4.88 mV */ int voltage_uV; /* units of µV */ int current_raw; /* units of 0.625 mA */ int current_uA; /* units of µA */ int accum_current_raw; /* units of 0.25 mAh */ int accum_current_uAh; /* units of µAh */ int temp_raw; /* units of 0.125 °C */ int temp_C; /* units of 0.1 °C */ int rated_capacity; /* units of µAh */ int rem_capacity; /* percentage */ int full_active_uAh; /* units of µAh */ int empty_uAh; /* units of µAh */ int life_sec; /* units of seconds */ int charge_status; /* POWER_SUPPLY_STATUS_* */
staticconststruct attribute_group *w1_ds2760_groups[] = {
&w1_ds2760_group,
NULL,
}; /* Some batteries have their rated capacity stored a N * 10 mAh, while
* others use an index into this table. */ staticint rated_capacities[] = {
0,
920, /* Samsung */
920, /* BYD */
920, /* Lishen */
920, /* NEC */
1440, /* Samsung */
1440, /* BYD */
1440, /* Lishen */
1440, /* NEC */
2880, /* Samsung */
2880, /* BYD */
2880, /* Lishen */
2880, /* NEC */
};
/* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C
* temp is in Celsius */ staticint battery_interpolate(int array[], int temp)
{ int index, dt;
if (temp <= 0) return array[0]; if (temp >= 40) return array[4];
staticint ds2760_battery_read_status(struct ds2760_device_info *di)
{ int ret, i, start, count, scale[5];
if (di->update_time && time_before(jiffies, di->update_time +
msecs_to_jiffies(cache_time))) return 0;
/* The first time we read the entire contents of SRAM/EEPROM,
* but after that we just read the interesting bits that change. */ if (di->update_time == 0) {
start = 0;
count = DS2760_DATA_SIZE;
} else {
start = DS2760_VOLTAGE_MSB;
count = DS2760_TEMP_LSB - start + 1;
}
ret = w1_ds2760_read(di->dev, di->raw + start, start, count); if (ret != count) {
dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n",
di->dev); return 1;
}
di->update_time = jiffies;
/* DS2760 reports voltage in units of 4.88mV, but the battery class
* reports in units of uV, so convert by multiplying by 4880. */
di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) |
(di->raw[DS2760_VOLTAGE_LSB] >> 5);
di->voltage_uV = di->voltage_raw * 4880;
/* DS2760 reports current in signed units of 0.625mA, but the battery
* class reports in units of µA, so convert by multiplying by 625. */
di->current_raw =
(((signedchar)di->raw[DS2760_CURRENT_MSB]) << 5) |
(di->raw[DS2760_CURRENT_LSB] >> 3);
di->current_uA = di->current_raw * 625;
/* DS2760 reports accumulated current in signed units of 0.25mAh. */
di->accum_current_raw =
(((signedchar)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) |
di->raw[DS2760_CURRENT_ACCUM_LSB];
di->accum_current_uAh = di->accum_current_raw * 250;
/* DS2760 reports temperature in signed units of 0.125°C, but the * battery class reports in units of 1/10 °C, so we convert by
* multiplying by .125 * 10 = 1.25. */
di->temp_raw = (((signedchar)di->raw[DS2760_TEMP_MSB]) << 3) |
(di->raw[DS2760_TEMP_LSB] >> 5);
di->temp_C = di->temp_raw + (di->temp_raw / 4);
/* At least some battery monitors (e.g. HP iPAQ) store the battery's
* maximum rated capacity. */ if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities))
di->rated_capacity = rated_capacities[
(unsignedint)di->raw[DS2760_RATED_CAPACITY]]; else
di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10;
di->rated_capacity *= 1000; /* convert to µAh */
/* Calculate the full level at the present temperature. */
di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 |
di->raw[DS2760_ACTIVE_FULL + 1];
/* If the full_active_uAh value is not given, fall back to the rated * capacity. This is likely to happen when chips are not part of the
* battery pack and is therefore not bootstrapped. */ if (di->full_active_uAh == 0)
di->full_active_uAh = di->rated_capacity / 1000L;
scale[0] = di->full_active_uAh; for (i = 1; i < 5; i++)
scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 1 + i];
/* Write to the di->raw[] buffer directly - the DS2760_ACTIVE_FULL
* values won't be read back by ds2760_battery_read_status() */
di->raw[DS2760_ACTIVE_FULL] = tmp[0];
di->raw[DS2760_ACTIVE_FULL + 1] = tmp[1];
}
switch (psp) { case POWER_SUPPLY_PROP_CHARGE_FULL: /* the interface counts in uAh, convert the value */
ds2760_battery_write_active_full(di, val->intval / 1000L); break;
case POWER_SUPPLY_PROP_CHARGE_NOW: /* ds2760_battery_set_current_accum() does the conversion */
ds2760_battery_set_current_accum(di, val->intval); break;
default: return -EPERM;
}
return 0;
}
staticint ds2760_battery_property_is_writeable(struct power_supply *psy, enum power_supply_property psp)
{ switch (psp) { case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_NOW: return 1;
switch (pm_event) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE:
di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; break;
case PM_POST_RESTORE: case PM_POST_HIBERNATION: case PM_POST_SUSPEND:
di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
power_supply_changed(di->bat);
mod_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
if (!of_property_read_bool(dev->of_node, "maxim,pmod-enabled"))
pmod_enabled = true;
if (!of_property_read_u32(dev->of_node, "maxim,cache-time-ms", &tmp))
cache_time = tmp;
if (!of_property_read_u32(dev->of_node, "rated-capacity-microamp-hours",
&tmp))
rated_capacity = tmp / 10; /* property is in mAh */
}
di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
sl->family_data = di;
/* enable sleep mode feature */
ds2760_battery_read_status(di);
status = di->raw[DS2760_STATUS_REG]; if (pmod_enabled)
status |= DS2760_STATUS_PMOD; else
status &= ~DS2760_STATUS_PMOD;
ds2760_battery_write_status(di, status);
/* set rated capacity from module param or device tree */ if (rated_capacity)
ds2760_battery_write_rated_capacity(di, rated_capacity);
/* set current accumulator if given as parameter.
* this should only be done for bootstrapping the value */ if (current_accum)
ds2760_battery_set_current_accum(di, current_accum);
di->bat = devm_power_supply_register(dev, &di->bat_desc, &psy_cfg); if (IS_ERR(di->bat)) {
dev_err(di->dev, "failed to register battery\n");
retval = PTR_ERR(di->bat); goto batt_failed;
}
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.