rendered paste body/*
* 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 and added CL4 Class (WP50,T-Sinuspad) support.
*
* Read the Battery Level through the UCB1x00 chip.
*
*/
#include <linux/battery.h>
#include <asm/dma.h>
#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 + 3)*12610)/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 8500 /* Less then 8.5V means no powersupply */
/*
* Charging Current
* if value is >= 50 then charging is on
*/
#define CALIBRATE_CHARGING(a) (((a)* 1000)/(152/4)))
/*
* Module parameters. If you have a small battery you need to give the driver
* the right module parameter small_battery=1. As default the driver uses
* the big size battery.
*/
static int small_battery = 0;
module_param( small_battery, int, 0 );
MODULE_PARM_DESC (small_battery, "Choose 0 (default) for SL4 and SLC (big size battery) and 1 for CL4,WP50 and T-Sinuspad (small size battery)");
struct simpad_battery_t {
struct battery battery;
struct ucb1x00* ucb;
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 (CL4, WP50, T-Sinuspad)
*/
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,
.max_current = 0,
.max_charge = 0,
.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,
.max_current = 0,
.max_charge = 0,
.min_supply = 8500,
.charging_led_label = 12,
.charging_max_label = 120,
.batt_full = 8100,
.batt_low = 7300,
.batt_critical = 6700,
.batt_empty = 6400,
};
/*
* UCB glue code
*/
static int ucb1x00_battery_add(struct ucb1x00_dev *dev)
{
if (small_battery==1) {
simpad_battery_small.ucb = dev->ucb;
battery_class_register(&simpad_battery_small.battery);
printk("USING SMALL BAT\n");
}
else if (small_battery==0) {
simpad_battery_big.ucb = dev->ucb;
battery_class_register(&simpad_battery_big.battery);
printk("USING BIG BAT\n");
}
return 0;
}
static void ucb1x00_battery_remove(struct ucb1x00_dev *dev)
{
if (small_battery==1)
return battery_class_unregister(&simpad_battery_small.battery);
else if (small_battery==0)
return battery_class_unregister(&simpad_battery_big.battery);
}
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");