/* * linux/drivers/misc/simpad-battery.c * * Copyright (C) 2005 Holger Hans Peter Freyther * Copyright (C) 2001 Juergen Messerer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * 2007 Bernhard Guillon changed code to fit on the new ucb1x00 * driver initialization. * * Read the Battery Level through the UCB1x00 chip. T-Sinuspad is * unsupported for now. * */ #include #include #include "../../mfd/ucb1x00.h" /* * Conversion from AD -> mV * 7.5V = 1023 7.3313mV/Digit * * 400 Units == 9.7V * a = ADC value * 21 = ADC error * 12600 = Divident to get 2*7.3242 * 860 = Divider to get 2*7.3242 * 170 = Voltagedrop over */ #define CALIBRATE_BATTERY(a) ((((a + 21)*12600)/860) + 170) /* * We have two types of batteries a small and a large one * To get the right value we to distinguish between those two * 450 Units == 15 V */ #define CALIBRATE_SUPPLY(a) (((a) * 1500) / 45) #define MIN_SUPPLY 12000 /* Less then 12V means no powersupply */ /* * Charging Current * if value is >= 50 then charging is on */ #define CALIBRATE_CHARGING(a) (((a)* 1000)/(152/4))) struct simpad_battery_t { struct battery battery; struct ucb1x00* ucb; /* * Variables for the values to one time support * T-Sinuspad as well */ int min_voltage; int min_current; int min_charge; int max_voltage; int max_current; int max_charge; int min_supply; int charging_led_label; int charging_max_label; int batt_full; int batt_low; int batt_critical; int batt_empty; }; static int simpad_get_min_voltage(struct battery* _battery ) { struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; return battery->min_voltage; } static int simpad_get_min_current(struct battery* _battery) { struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; return battery->min_current; } static int simpad_get_min_charge(struct battery* _battery) { struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; return battery->min_charge; } static int simpad_get_max_voltage(struct battery* _battery) { struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; return battery->max_voltage; } static int simpad_get_max_current(struct battery* _battery) { struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; return battery->max_current; } static int simpad_get_max_charge(struct battery* _battery) { struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; return battery->max_charge; } static int simpad_get_temp(struct battery* _battery) { return 0; } static int simpad_get_voltage(struct battery* _battery) { int val; struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; ucb1x00_adc_enable(battery->ucb); val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD1, UCB_NOSYNC); ucb1x00_adc_disable(battery->ucb); return CALIBRATE_BATTERY(val); } static int simpad_get_current(struct battery* _battery) { int val; struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; ucb1x00_adc_enable(battery->ucb); val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD3, UCB_NOSYNC); ucb1x00_adc_disable(battery->ucb); return val; } static int simpad_get_charge(struct battery* _battery) { int val; struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; ucb1x00_adc_enable(battery->ucb); val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD2, UCB_NOSYNC); ucb1x00_adc_disable(battery->ucb); return CALIBRATE_SUPPLY(val); } static int simpad_get_status(struct battery* _battery) { struct simpad_battery_t* battery = (struct simpad_battery_t*)(_battery); int vcharger = simpad_get_charge(_battery); int icharger = simpad_get_current(_battery); int status = BATTERY_STATUS_UNKNOWN; if(icharger > battery->charging_led_label) status = BATTERY_STATUS_CHARGING; else if(vcharger > battery->min_supply) status = BATTERY_STATUS_NOT_CHARGING; else status = BATTERY_STATUS_DISCHARGING; return status; } //For big size batterys (SL4, SLC) static struct simpad_battery_t simpad_battery_big = { .battery = { .name = "simpad-battery", .get_min_voltage = simpad_get_min_voltage, .get_min_current = simpad_get_min_current, .get_min_charge = simpad_get_min_charge, .get_max_voltage = simpad_get_max_voltage, .get_max_current = simpad_get_max_current, .get_max_charge = simpad_get_max_charge, .get_temp = simpad_get_temp, .get_voltage = simpad_get_voltage, .get_current = simpad_get_current, .get_charge = simpad_get_charge, .get_status = simpad_get_status, }, .min_voltage = 0, .min_current = 0, .min_charge = 0, .max_voltage = 0, //mrdata do you think we need to set this to something? .max_current = 0, //mrdata do you think we need to set this to something? .max_charge = 0, //mrdata do you think we need to set this to something? .min_supply = 12000, .charging_led_label = 28, .charging_max_label = 265, .batt_full = 8300, .batt_low = 7400, .batt_critical = 6800, .batt_empty = 6500, }; //For small size batterys (CL4, WP50, T-Sinuspad) static struct simpad_battery_t simpad_battery_small = { .battery = { .name = "simpad-battery", .get_min_voltage = simpad_get_min_voltage, .get_min_current = simpad_get_min_current, .get_min_charge = simpad_get_min_charge, .get_max_voltage = simpad_get_max_voltage, .get_max_current = simpad_get_max_current, .get_max_charge = simpad_get_max_charge, .get_temp = simpad_get_temp, .get_voltage = simpad_get_voltage, .get_current = simpad_get_current, .get_charge = simpad_get_charge, .get_status = simpad_get_status, }, .min_voltage = 0, .min_current = 0, .min_charge = 0, .max_voltage = 0, //mrdata do you think we need to set this to something? .max_current = 0, //mrdata do you think we need to set this to something? .max_charge = 0, //mrdata do you think we need to set this to something? .min_supply = 8500, .charging_led_label = 12, .charging_max_label = 120, .batt_full = 8100, .batt_low = 7300, .batt_critical = 6700, .batt_empty = 6400, }; /* * Module parameters */ static char *battery_type; MODULE_PARM (battery_type, "s"); MODULE_PARM_DESC (battery_type, "Choose big for SL4 and SLC and small for CL4,WP50 and T-Sinuspad"); /* * UCB glue code */ static int ucb1x00_battery_add(struct ucb1x00_dev *dev) { simpad_battery.ucb = dev->ucb; if (battery_type=="small") battery_class_register(&simpad_battery_small.battery); else if (battery_type=="big") battery_class_register(&simpad_battery_big.battery); else printk("\n You need to input the argument small or big \n"); return 0; } static void ucb1x00_battery_remove(struct ucb1x00_dev *dev) { if (battery_type=="small") return battery_class_unregister(&simpad_battery_small.battery); else if (battery_type=="big") return battery_class_unregister(&simpad_battery_big.battery); else return 0; } static struct ucb1x00_driver ucb1x00_battery_driver = { .add = ucb1x00_battery_add, .remove = ucb1x00_battery_remove, }; static int __init ucb1x00_battery_init(void) { return ucb1x00_register_driver(&ucb1x00_battery_driver); } static void __exit ucb1x00_battery_exit(void) { ucb1x00_unregister_driver(&ucb1x00_battery_driver); } module_init(ucb1x00_battery_init); module_exit(ucb1x00_battery_exit); MODULE_AUTHOR("Holger Hans Peter Freyther"); MODULE_LICENSE("GPL");