// SPDX-License-Identifier: GPL-2.0-only /* * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00 * series of PDAs * * Copyright (c) 2004-2005 Richard Purdie * * Based on code written by Sharp for 2.4 kernels
*/
externint max1111_read_channel(int); /* * Read MAX1111 ADC
*/ int sharpsl_pm_pxa_read_max1111(int channel)
{ /* max1111 accepts channels from 0-3, however, * it is encoded from 0-7 here in the code.
*/ return max1111_read_channel(channel >> 1);
}
staticint get_percentage(int voltage)
{ int i = sharpsl_pm.machinfo->bat_levels - 1; int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0; struct battery_thresh *thresh;
/* Corgi cannot confirm when battery fully charged so periodically kick! */ if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
&& time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL))
schedule_delayed_work(&toggle_charger, 0);
for (i = 0; i < 5; i++) {
voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); if (voltage > 0) break;
} if (voltage <= 0) {
voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
}
voltage = sharpsl_average_value(voltage);
apm_status = get_apm_status(voltage);
percent = get_percentage(voltage);
/* At low battery voltages, the voltage has a tendency to start
creeping back up so we try to avoid this here */ if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE)
|| (apm_status == APM_BATTERY_STATUS_HIGH)
|| percent <= sharpsl_pm.battstat.mainbat_percent) {
sharpsl_pm.battstat.mainbat_voltage = voltage;
sharpsl_pm.battstat.mainbat_status = apm_status;
sharpsl_pm.battstat.mainbat_percent = percent;
}
static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
{ /* Delay the event slightly to debounce */ /* Must be a smaller delay than the chrg_full_isr below */
mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
return IRQ_HANDLED;
}
staticvoid sharpsl_chrg_full_timer(struct timer_list *unused)
{
dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
/* Charging Finished Interrupt (Not present on Corgi) */ /* Can trigger at the same time as an AC status change so
delay until after that has been processed */ static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
{ if (sharpsl_pm.flags & SHARPSL_SUSPENDED) return IRQ_HANDLED;
/* delay until after any ac interrupt */
mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
sharpsl_ad[sharpsl_ad_index] = ad;
sharpsl_ad_index++; if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) { for (i = 0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
sharpsl_ad[i] = sharpsl_ad[i+1];
sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
} for (i = 0; i < sharpsl_ad_index; i++)
ad_val += sharpsl_ad[i];
return ad_val / sharpsl_ad_index;
}
/* * Take an array of 5 integers, remove the maximum and minimum values * and return the average.
*/ staticint get_select_val(int *val)
{ int i, j, k, temp, sum = 0;
/* Find MAX val */
temp = val[0];
j = 0; for (i = 1; i < 5; i++) { if (temp < val[i]) {
temp = val[i];
j = i;
}
}
/* Find MIN val */
temp = val[4];
k = 4; for (i = 3; i >= 0; i--) { if (temp > val[i]) {
temp = val[i];
k = i;
}
}
for (i = 0; i < 5; i++) if (i != j && i != k)
sum += val[i];
staticint sharpsl_check_battery_temp(void)
{ int val, i, buff[5];
/* Check battery temperature */ for (i = 0; i < 5; i++) {
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
sharpsl_pm.machinfo->measure_temp(1);
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
sharpsl_pm.machinfo->measure_temp(0);
}
val = get_select_val(buff);
dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val); if (val > sharpsl_pm.machinfo->charge_on_temp) {
printk(KERN_WARNING "Not charging: temperature out of limits.\n"); return -1;
}
return 0;
}
#ifdef CONFIG_PM staticint sharpsl_check_battery_voltage(void)
{ int val, i, buff[5];
if (sharpsl_pm.machinfo->discharge1)
sharpsl_pm.machinfo->discharge1(1);
/* Check battery voltage */ for (i = 0; i < 5; i++) {
buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
}
if (sharpsl_pm.machinfo->discharge1)
sharpsl_pm.machinfo->discharge1(0);
sharpsl_pm.machinfo->discharge(0);
val = get_select_val(buff);
dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
if (val < sharpsl_pm.machinfo->charge_on_volt) return -1;
return 0;
} #endif
staticint sharpsl_ac_check(void)
{ int temp, i, buff[5];
for (i = 0; i < 5; i++) {
buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT);
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
}
/* * Charging Control while suspended * Return 1 - go straight to sleep * Return 0 - sleep or wakeup depending on other factors
*/ staticint sharpsl_off_charge_battery(void)
{ int time;
time = RCNR; while (1) { /* Check if any wakeup event had occurred */ if (sharpsl_pm.machinfo->charger_wakeup()) return 0; /* Check for timeout */ if ((RCNR - time) > SHARPSL_WAIT_CO_TIME) return 1; if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
sharpsl_pm.full_count++;
sharpsl_pm.machinfo->charge(0);
mdelay(SHARPSL_CHARGE_WAIT_TIME);
sharpsl_pm.machinfo->charge(1); return 1;
}
}
}
/* Register interrupt handlers */
irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_acin); if (request_irq(irq, sharpsl_ac_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) {
dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
}
irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_batlock); if (request_irq(irq, sharpsl_fatal_isr, IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) {
dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
}
if (sharpsl_pm.machinfo->gpio_fatal) {
irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_fatal); if (request_irq(irq, sharpsl_fatal_isr, IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) {
dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
}
}
if (sharpsl_pm.machinfo->batfull_irq) { /* Register interrupt handler. */
irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_batfull); if (request_irq(irq, sharpsl_chrg_full_isr, IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) {
dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
}
}
ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage); if (ret != 0)
dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);
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.