The Letux 400 MIPS netbook contains an LPC915 microcontroller to measure the battery voltage, detect the presence of a charger, and to power the device off. It is controlled via I2C address 0x28.
Signed-off-by: Daniel Glöckner <daniel...@gmx.net> --- drivers/power/minipc-mcu.c | 167 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 drivers/power/minipc-mcu.c diff --git a/drivers/power/minipc-mcu.c b/drivers/power/minipc-mcu.c new file mode 100644 index 0000000..29d779a --- /dev/null +++ b/drivers/power/minipc-mcu.c @@ -0,0 +1,167 @@ +/* + * An I2C driver for the MCU used on the Letux 400 + * Copyright 2012 Daniel Gloeckner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/i2c.h> +#include <linux/power_supply.h> +#include <linux/pm.h> + +#define DRV_VERSION "1.0" + +static struct i2c_client *mcu; + +static int minipc_battery_get_properties(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + switch (psp) { + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = 7000000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = 8400000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = i2c_smbus_read_byte_data(mcu, 0xdb); + if (ret >= 0) { + /* resistor divider scales 8.4V to 3V */ + /* lpc915 is powered from 3.3V */ + /* ergo voltage = value * 2.8 * 3.3 / 255 */ + val->intval = ret * 616000 / 17; + ret = 0; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static enum power_supply_property minipc_battery_properties[] = { + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +static struct power_supply minipc_battery = { + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = minipc_battery_properties, + .num_properties = ARRAY_SIZE(minipc_battery_properties), + .get_property = minipc_battery_get_properties, +}; + +static int minipc_psu_get_properties(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = i2c_smbus_read_byte_data(mcu, 0xd9) & 1; + if (val->intval < 0) + ret = val->intval; + break; + default: + ret = -EINVAL; + } + return ret; +} + +static enum power_supply_property minipc_psu_properties[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static struct power_supply minipc_psu = { + .name = "psu", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = minipc_psu_properties, + .num_properties = ARRAY_SIZE(minipc_psu_properties), + .get_property = minipc_psu_get_properties, +}; + +static void minipc_mcu_power_off(void) +{ + i2c_smbus_write_byte_data(mcu, 0xd8, 0x01); +} + +static int minipc_mcu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + dev_dbg(&client->dev, "%s\n", __func__); + + if (mcu) + return -EBUSY; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + + minipc_battery.use_for_apm = power_supply_register(&client->dev, + &minipc_battery); + minipc_psu.use_for_apm = power_supply_register(&client->dev, + &minipc_psu); + + mcu = client; + pm_power_off = minipc_mcu_power_off; + + return 0; +} + +static int minipc_mcu_remove(struct i2c_client *client) +{ + if (!mcu) + return 0; + if (!minipc_battery.use_for_apm) + power_supply_unregister(&minipc_battery); + if (!minipc_psu.use_for_apm) + power_supply_unregister(&minipc_psu); + pm_power_off = NULL; + mcu = NULL; + + return 0; +} + +static const struct i2c_device_id minipc_mcu_id[] = { + { "minipc-mcu", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, minipc_mcu_id); + +static struct i2c_driver minipc_mcu_driver = { + .driver = { + .name = "minipc-mcu", + }, + .probe = minipc_mcu_probe, + .remove = minipc_mcu_remove, + .id_table = minipc_mcu_id, +}; + +static int __init minipc_mcu_init(void) +{ + return i2c_add_driver(&minipc_mcu_driver); +} + +static void __exit minipc_mcu_exit(void) +{ + i2c_del_driver(&minipc_mcu_driver); +} + +MODULE_AUTHOR("Daniel Gloeckner <daniel...@gmx.net>"); +MODULE_DESCRIPTION("Letux 400 LPC915 MCU driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(minipc_mcu_init); +module_exit(minipc_mcu_exit); -- 1.8.3.4 _______________________________________________ Mipsbook-devel mailing list Mipsbook-devel@linuxtogo.org http://lists.linuxtogo.org/cgi-bin/mailman/listinfo/mipsbook-devel