All pastes #409063 Raw Edit

Anonymous

public text v1 · immutable
#409063 ·published 2007-03-25 12:25 UTC
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.
 *
 * Read the Battery Level through the UCB1x00 chip. T-Sinuspad is
 * unsupported for now.
 *
 */

#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)))

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,
	.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,
};

/*
 * Module parameters
 */

static char small_battery = 'n';
module_param( small_battery, byte, 0 );
MODULE_PARM_DESC (small_battery, "Do you have a small battery? choose n (default) for SL4 and SLC and y for CL4,WP50 and T-Sinuspad");

/*
 * UCB glue code
 */
static int ucb1x00_battery_add(struct ucb1x00_dev *dev)
{
    if (small_battery=='y') {
        simpad_battery_small.ucb = dev->ucb;
        battery_class_register(&simpad_battery_small.battery);
        printk("USING SMALL BAT\n");
    }
    else if (small_battery=='n') { 
        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=='y') 
        return battery_class_unregister(&simpad_battery_small.battery);
    else if (small_battery=='n')
        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");