Skip to content

Commit

Permalink
[ARM] 3385/1: Battery support for sharp zaurus sl-5500 (collie)
Browse files Browse the repository at this point in the history
Patch from Pavel Machek

This adds support for battery reading on collie. Collie slowly charges
battery even with charging disabled, so I did not yet enable fast
charge.

Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Pavel Machek authored and Russell King committed Mar 25, 2006
1 parent 091c539 commit 48a03ae
Showing 1 changed file with 278 additions and 0 deletions.
278 changes: 278 additions & 0 deletions arch/arm/mach-sa1100/collie_pm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
/*
* Based on spitz_pm.c and sharp code.
*
* Copyright (C) 2001 SHARP
* Copyright 2005 Pavel Machek <pavel@suse.cz>
*
* Distribute under GPLv2.
*
* Li-ion batteries are angry beasts, and they like to explode. This driver is not finished,
* and sometimes charges them when it should not. If it makes angry lithium to come your way...
* ...well, you have been warned.
*/

#include <linux/module.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>

#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/hardware.h>
#include <asm/hardware/scoop.h>
#include <asm/dma.h>
#include <asm/arch/collie.h>
#include <asm/mach/sharpsl_param.h>
#include <asm/hardware/sharpsl_pm.h>

#include "../drivers/mfd/ucb1x00.h"

static struct ucb1x00 *ucb;
static int ad_revise;

#define ADCtoPower(x) ((330 * x * 2) / 1024)

static void collie_charger_init(void)
{
int err;

if (sharpsl_param.adadj != -1) {
ad_revise = sharpsl_param.adadj;
}

/* Register interrupt handler. */
if ((err = request_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr, SA_INTERRUPT,
"ACIN", sharpsl_ac_isr))) {
printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_AC_IN);
return;
}
if ((err = request_irq(COLLIE_IRQ_GPIO_CO, sharpsl_chrg_full_isr, SA_INTERRUPT,
"CO", sharpsl_chrg_full_isr))) {
free_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr);
printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_CO);
return;
}

ucb1x00_io_set_dir(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON | COLLIE_TC35143_GPIO_TMP_ON |
COLLIE_TC35143_GPIO_BBAT_ON);
return;
}

static void collie_measure_temp(int on)
{
if (on)
ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
else
ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
}

static void collie_charge(int on)
{
if (on) {
printk("Should start charger\n");
} else {
printk("Should stop charger\n");
}
#ifdef I_AM_SURE

/* Zaurus seems to contain LTC1731 ; it should know when to
* stop charging itself, so setting charge on should be
* relatively harmless (as long as it is not done too often).
*/
#define CF_BUF_CTRL_BASE 0xF0800000
#define SCOOP_REG(adr) (*(volatile unsigned short*)(CF_BUF_CTRL_BASE+(adr)))
#define SCOOP_REG_GPWR SCOOP_REG(SCOOP_GPWR)

if (on) {
set_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON);
} else {
reset_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON);
}
#endif
}

static void collie_discharge(int on)
{
}

static void collie_discharge1(int on)
{
}

static void collie_presuspend(void)
{
}

static void collie_postsuspend(void)
{
}

static int collie_should_wakeup(unsigned int resume_on_alarm)
{
return 0;
}

static unsigned long collie_charger_wakeup(void)
{
return 0;
}

int collie_read_backup_battery(void)
{
int voltage;

ucb1x00_adc_enable(ucb);

/* Gives 75..130 */
ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0);
voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);

ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
ucb1x00_adc_disable(ucb);

printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage);

return ADCtoPower(voltage);
}

int collie_read_main_battery(void)
{
int voltage, voltage_rev, voltage_volts;

ucb1x00_adc_enable(ucb);
ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0);
/* gives values 160..255 with battery removed... and
145..255 with battery inserted. (on AC), goes as low as
80 on DC. */
voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);

ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON);
ucb1x00_adc_disable(ucb);

voltage_rev = voltage + ((ad_revise * voltage) / 652);
voltage_volts = ADCtoPower(voltage_rev);

printk("Main battery = %d(%d)\n", voltage_volts, voltage);

if (voltage != -1)
return voltage_volts;
else
return voltage;
}

int collie_read_temp(void)
{
int voltage;

/* According to Sharp, temp must be > 973, main battery must be < 465,
FIXME: sharpsl_pm.c has both conditions negated? FIXME: values
are way out of range? */

ucb1x00_adc_enable(ucb);
ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
/* >1010 = battery removed, 460 = 22C ?, higer = lower temp ? */
voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC);
ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
ucb1x00_adc_disable(ucb);

printk("Battery temp = %d\n", voltage);
return voltage;
}

static unsigned long read_devdata(int which)
{
switch (which) {
case SHARPSL_BATT_VOLT:
return collie_read_main_battery();
case SHARPSL_BATT_TEMP:
return collie_read_temp();
case SHARPSL_ACIN_VOLT:
return 0x1;
case SHARPSL_STATUS_ACIN: {
int ret = GPLR & COLLIE_GPIO_AC_IN;
printk("AC status = %d\n", ret);
return ret;
}
case SHARPSL_STATUS_FATAL: {
int ret = GPLR & COLLIE_GPIO_MAIN_BAT_LOW;
printk("Fatal bat = %d\n", ret);
return ret;
}
default:
return ~0;
}
}

struct battery_thresh collie_battery_levels[] = {
{ 368, 100},
{ 358, 25},
{ 356, 5},
{ 0, 0},
};

struct sharpsl_charger_machinfo collie_pm_machinfo = {
.init = collie_charger_init,
.read_devdata = read_devdata,
.discharge = collie_discharge,
.discharge1 = collie_discharge1,
.charge = collie_charge,
.measure_temp = collie_measure_temp,
.presuspend = collie_presuspend,
.postsuspend = collie_postsuspend,
.charger_wakeup = collie_charger_wakeup,
.should_wakeup = collie_should_wakeup,
.bat_levels = 3,
.bat_levels_noac = collie_battery_levels,
.bat_levels_acin = collie_battery_levels,
.status_high_acin = 368,
.status_low_acin = 358,
.status_high_noac = 368,
.status_low_noac = 358,
};

static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev)
{
sharpsl_pm.machinfo = &collie_pm_machinfo;
ucb = pdev->ucb;
return 0;
}

static struct ucb1x00_driver collie_pm_ucb_driver = {
.add = collie_pm_ucb_add,
};

static struct platform_device *collie_pm_device;

static int __init collie_pm_init(void)
{
int ret;

collie_pm_device = platform_device_alloc("sharpsl-pm", -1);
if (!collie_pm_device)
return -ENOMEM;

collie_pm_device->dev.platform_data = &collie_pm_machinfo;
ret = platform_device_add(collie_pm_device);

if (ret)
platform_device_put(collie_pm_device);

if (!ret)
ret = ucb1x00_register_driver(&collie_pm_ucb_driver);

return ret;
}

static void __exit collie_pm_exit(void)
{
ucb1x00_unregister_driver(&collie_pm_ucb_driver);
platform_device_unregister(collie_pm_device);
}

module_init(collie_pm_init);
module_exit(collie_pm_exit);

0 comments on commit 48a03ae

Please sign in to comment.