Hi! > > Boot your notebook with init=/bin/bash, and launch fsck on low > > battery. It will blink, it may beep, but in the end it will power off > > abruptly at maybe 3.6V per cell, before battery is damaged. Now try > > the same on N900. It will not blink, and it will run battery down to > > less then 3.0V; various components will fail, you'll get screen > > flicker, and presumably your MMC will be _really_ unhappy. Eventually, > > CPU fails, machine reboots, and machine will attempt to do _the same > > again_. > > > > Basically we are missing one layer of protection here, compared to the > > PC case. > > It should be fine to add something like Tony's orderly_poweroff to > the rx51 battery driver. Yep, I actually have a patch for that. Needs some cleanups, but if it is basically acceptable, there's no problem doing them. Aha, and probably breaks boot or something, that's why I disable it. But you should get the idea... > > Problem is that bootloader does not even know about battery charging, > > and is far from having required drivers. That's why I'd try to get > > buy-in ;-). > > Actually Nokia Loader does know about battery charging and does so > for really empty batteries. Once the battery is full enough it tries > to boot operating system with better monitoring capabilities, > though. So to be exact... u-boot does not know about battery charging. And NoLo can only do very, very slow charging. Yes, unfortunately that does not work quite well here. Voltage goes too low before Linux can boot, so it resets, but it is still high enough for the bootloader, so it attempts to boot Linux one more time, but battery is empty and voltage goes too low before Linux can boot, ... > > It is not perfect, indeed. > > > > So we currently have GPSes on serial, producing NMEA. Gpsd there may > > be good enough. But then we have different hardware, not producing > > NMEA (GPS on N900 is exposed as network packet over PHONET > > interface, there's drivers/usb/serial/garmin_gps.c with who-knows-what > > interface)... and it would be nice to have good, "native" GPS > > interface which would work in this case. (We'd like timestamps for > > incoming data and lat/long/alt + speed in lat/long/alt + error in > > lat/long/alt sampled at the same time, at the very least). > > > > Its similar to mice, really. We used to have gpm, now we have real > > drivers. > > > > Plus there's still issue of AGPS data upload. > > On N950 there is an unsupported gps connected via i2c iirc (with > unknown protocol that needs to be RE'd) and TI's WiLink provides > GPS on a shared UART link with bluetooth-style header using yet > another protocol. I agree, that we should have a GPS subsystem. Two GPSes in one box, interesting design. Are both of them connected to useful antenna? Best regards, Pavel diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 398801a..db9c69e 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -808,11 +809,9 @@ static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di) { int soc; + bool single = di->chip == BQ27000 || di->chip == BQ27010; - if (di->chip == BQ27000 || di->chip == BQ27010) - soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true); - else - soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false); + soc = bq27xxx_read(di, BQ27XXX_REG_SOC, single); if (soc < 0) dev_dbg(di->dev, "error reading State-of-Charge\n"); @@ -876,11 +875,9 @@ static inline int bq27xxx_battery_read_fcc(struct bq27xxx_device_info *di) static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) { int dcap; + bool single = di->chip == BQ27000 || di->chip == BQ27010; - if (di->chip == BQ27000 || di->chip == BQ27010) - dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true); - else - dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false); + dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, single); if (dcap < 0) { dev_dbg(di->dev, "error reading initial last measured discharge\n"); @@ -1061,10 +1058,10 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) /* Unlikely but important to return first */ if (unlikely(bq27xxx_battery_overtemp(di, flags))) return POWER_SUPPLY_HEALTH_OVERHEAT; - if (unlikely(bq27xxx_battery_undertemp(di, flags))) - return POWER_SUPPLY_HEALTH_COLD; if (unlikely(bq27xxx_battery_dead(di, flags))) return POWER_SUPPLY_HEALTH_DEAD; + if (unlikely(bq27xxx_battery_undertemp(di, flags))) + return POWER_SUPPLY_HEALTH_COLD; return POWER_SUPPLY_HEALTH_GOOD; } @@ -1122,6 +1119,49 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di) } EXPORT_SYMBOL_GPL(bq27xxx_battery_update); +static void shutdown(char *reason) +{ + pr_alert("%s Forcing shutdown\n", reason); + orderly_poweroff(true); +} + +static int generic_protect(struct power_supply *psy) +{ + union power_supply_propval val; + int res; + int mV, mA, mOhm = 430, mVadj = 0; + + res = psy->desc->get_property(psy, POWER_SUPPLY_PROP_HEALTH, &val); + if (res) + return res; + + if (val.intval == POWER_SUPPLY_HEALTH_OVERHEAT) + shutdown("Battery overheat."); + if (val.intval == POWER_SUPPLY_HEALTH_DEAD) + shutdown("Battery dead."); + + res = psy->desc->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); + if (res) + return res; + mV = val.intval / 1000; + + if (mV < 2950) + shutdown("Battery below 2.95V."); + + res = psy->desc->get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &val); + if (res) + return res; + mA = val.intval / 1000; + mVadj = mV + (mA * mOhm) / 1000; + + if (mVadj < 3150) + shutdown("Battery internal voltage below 3.15V."); + + printk(KERN_INFO "Main battery %d mV, internal voltage %d mV\n", + mV, mVadj); + return 0; +} + static void bq27xxx_battery_poll(struct work_struct *work) { struct bq27xxx_device_info *di = @@ -1129,6 +1169,7 @@ static void bq27xxx_battery_poll(struct work_struct *work) work.work); bq27xxx_battery_update(di); + //generic_protect(di->bat); if (poll_interval > 0) schedule_delayed_work(&di->work, poll_interval * HZ); @@ -1226,8 +1267,8 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, } /* - * Return the battery Voltage in millivolts - * Or < 0 if something fails. + * Set val->intval to the battery Voltage in millivolts. + * Return < 0 if something fails. */ static int bq27xxx_battery_voltage(struct bq27xxx_device_info *di, union power_supply_propval *val) -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html