Hi all,
As I was advised by Phil, I restructured the battery interface to three
sections:
- shamcop_owm
This module implements the interface to the shamcop 1-wire busmaster
- shamcop_owm_ds2760
Since the ipaq_ds2760 config name was taken by the 3800 guys which is
based on their asic a choose this name.
These are the basic ds2760 programming functions. It uses the shamcop_owm
module of course.
- h2200_battery
The hardware dependent module which implements the actual querying thru
the ds2760 module.
And since I haven't got a cvs account yet (I applied for it) i post my
codes here:
-------------------------------------------------------------------------------------
arch/arm/common/ipaq/shamcop_base.c: in the shamcop_blocks structure:
-------------------------------------------------------------------------------------
{
#if SAMCOP
.id = IPAQ_SAMCOP_ONEWIRE_DEVICE_ID,
#else
.id = IPAQ_HAMCOP_ONEWIRE_DEVICE_ID,
#endif
.name = "shamcop owm",
.start = _SHAMCOP_OWM_Base,
.end = _SHAMCOP_OWM_Base + 0x1f, /* 0x47 */
.irq = -1, /* XXX until RnB interrupt code is written */
},
-------------------------------------------------------------------------------------
include/asm/hardware/shamcop_owm.h
-------------------------------------------------------------------------------------
/*
* 1-Wire busmaster lowlevel interface for the SHAMCOP ASIC
*
* Copyright (c) 2004 Szabolcs Gyurko
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* Author:
* Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>
* September 2004
*/
#ifndef __shamcop_owm_h__
#define __shamcop_owm_h__
struct owm_data {
struct device *parent;
void *map;
};
void shamcop_owm_up(void);
void shamcop_owm_down(void);
void shamcop_owm_write_data(u8);
void shamcop_owm_write_command(u8);
void shamcop_owm_write_interrupt(u8);
void shamcop_owm_write_interrupt_enable(u8);
void shamcop_owm_write_clock_divisor(u8);
int shamcop_owm_read_data(void);
int shamcop_owm_read_command(void);
int shamcop_owm_read_interrupt(void);
int shamcop_owm_read_interrupt_enable(void);
int shamcop_owm_read_clock_divisor(void);
#endif /* !__shamcop_owm_h__ */
/*
* Local Variables:
* mode:c
* c-style:"K&R"
* c-basic-offset:8
* End:
*
*/
---------------------------------------------------------------------------------------
include/asm/hardware/shamcop_owm_ds2760.h
---------------------------------------------------------------------------------------
/*
* DS2760 lowlevel interface using an OWM interface
*
* Note: so far compatible only with the SHAMCOP OWM driver
*
* Copyright (c) 2004 Szabolcs Gyurko
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* Author:
* Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>
* September 2004
*/
#ifndef __shamcop_owm_ds2760_h__
#define __shamcop_owm_ds2760_h__
#define DS2760_STATE_IDLE 0
#define DS2760_STATE_RESET 1
#define DS2760_STATE_READ 2
#define DS2760_STATE_WRITE 3
struct owm_net_address {
char address[8];
};
int shamcop_owm_ds2760_reset(void);
int shamcop_owm_ds2760_write(u8);
int shamcop_owm_ds2760_read(void);
int shamcop_owm_ds2760_setup(struct owm_net_address *);
int shamcop_owm_ds2760_read_bytes(struct owm_net_address *net, u8, u8 *,
unsigned short);
int shamcop_owm_ds2760_wait_for_interrupt(int);
#endif /* !__shamcop_owm_ds2760_h__ */
/*
* Local Variables:
* mode:c
* c-style:"K&R"
* c-basic-offset:8
* End:
*
*/
------------------------------------------------------------------------------------------
arch/arm/common/ipaq/shamcop_owm.c
------------------------------------------------------------------------------------------
/*
* 1-Wire busmaster lowlevel interface for the SHAMCOP ASIC
*
* Copyright (c) 2004 Szabolcs Gyurko
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* Author:
* Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>
* September 2004
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soc-device.h>
#include <linux/battery.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/hardware.h>
#include <asm/hardware/ipaq-hamcop.h>
#include <asm/arch-pxa/h2200-asic.h>
#include <asm/arch-pxa/h2200-gpio.h>
#include <asm/arch-pxa/h2200-init.h>
#include <asm/hardware/shamcop_owm.h>
#define DEBUG(format, args...) if (shamcop_owm_debug) printk(__FILE__ ":%s
- " format "\n", __FUNCTION__, ## args)
int shamcop_owm_debug = 0;
MODULE_PARM(shamcop_owm_debug, "i");
MODULE_PARM_DESC(shamcop_owm_debug, "If it's non-zero then the module will
generate debug output");
extern void shamcop_clock_enable(struct device *, u32, int);
static void *h2200_owm_map;
static struct device *h2200_owm_dev;
void
shamcop_owm_down(void)
{
shamcop_clock_enable(h2200_owm_dev,
SHAMCOP_CPM_CLKCON_1WIRE_CLKEN, 0);
}
void
shamcop_owm_up(void)
{
shamcop_clock_enable(h2200_owm_dev,
SHAMCOP_CPM_CLKCON_1WIRE_CLKEN, 1);
shamcop_owm_write_clock_divisor(0x13);
shamcop_owm_write_interrupt_enable(OWM_INTEN_ERBF | OWM_INTEN_IAS
| OWM_INTEN_EPD);
}
void
shamcop_owm_write_data(u8 val)
{
SHAMCOP_OWM_Data(h2200_owm_map) = val;
}
int
shamcop_owm_read_data(void)
{
return SHAMCOP_OWM_Data(h2200_owm_map);
}
void
shamcop_owm_write_interrupt(u8 val)
{
SHAMCOP_OWM_Interrupt(h2200_owm_map) = val;
}
int
shamcop_owm_read_interrupt(void)
{
return SHAMCOP_OWM_Interrupt(h2200_owm_map);
}
void
shamcop_owm_write_interrupt_enable(u8 val)
{
SHAMCOP_OWM_InterruptEnable(h2200_owm_map) = val;
}
int
shamcop_owm_read_interrupt_enable(void)
{
return SHAMCOP_OWM_InterruptEnable(h2200_owm_map);
}
void
shamcop_owm_write_command(u8 val)
{
SHAMCOP_OWM_Command(h2200_owm_map) = val;
}
int
shamcop_owm_read_command(void)
{
return SHAMCOP_OWM_Command(h2200_owm_map);
}
void
shamcop_owm_write_clock_divisor(u8 val)
{
SHAMCOP_OWM_ClockDivisor(h2200_owm_map) = val;
}
int
shamcop_owm_read_clock_divisor(void)
{
return SHAMCOP_OWM_ClockDivisor(h2200_owm_map);
}
static int
shamcop_owm_suspend(struct device *dev, u32 state, u32 level)
{
DEBUG("start");
shamcop_owm_down();
DEBUG("finish");
return 0;
}
static int
shamcop_owm_resume(struct device *dev, u32 level)
{
shamcop_owm_up();
return 0;
}
static int
shamcop_owm_remove(struct device *dev)
{
struct owm_data *owm = dev->driver_data;
shamcop_owm_down();
kfree(owm);
return 0;
}
static void
shamcop_owm_shutdown(struct device *dev)
{
shamcop_owm_remove(dev);
}
static int
shamcop_owm_probe(struct device *dev)
{
struct owm_data *owm;
struct soc_device *sdev = to_soc_device(dev);
owm = kmalloc(sizeof(struct owm_data), GFP_KERNEL);
memset(owm, 0, sizeof(struct owm_data));
owm->parent = dev->parent;
dev->driver_data = owm;
owm->map = (void *)sdev->resource[1].start;
h2200_owm_map = owm->map;
h2200_owm_dev = owm->parent;
shamcop_owm_up();
return 0;
}
static soc_device_id shamcop_owm_device_ids[] = {
IPAQ_HAMCOP_ONEWIRE_DEVICE_ID, 0
};
struct soc_device_driver shamcop_owm_soc_device_driver = {
.device_ids = shamcop_owm_device_ids,
.driver = {
.name = "shamcop owm",
.probe = shamcop_owm_probe,
.shutdown = shamcop_owm_shutdown,
.remove = shamcop_owm_remove,
.suspend = shamcop_owm_suspend,
.resume = shamcop_owm_resume
}
};
static int
shamcop_owm_init(void)
{
printk("SHAMCOP 1-Wire busmaster driver - (c) 2004 Szabolcs
Gyurko\n");
return soc_driver_register(&shamcop_owm_soc_device_driver);
}
static void
shamcop_owm_exit(void)
{
soc_driver_unregister(&shamcop_owm_soc_device_driver);
}
module_init(shamcop_owm_init);
module_exit(shamcop_owm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>");
MODULE_DESCRIPTION("1-Wire busmaster interface for the SHAMCOP ASIC");
EXPORT_SYMBOL(shamcop_owm_down);
EXPORT_SYMBOL(shamcop_owm_up);
EXPORT_SYMBOL(shamcop_owm_write_data);
EXPORT_SYMBOL(shamcop_owm_read_data);
EXPORT_SYMBOL(shamcop_owm_write_command);
EXPORT_SYMBOL(shamcop_owm_read_command);
EXPORT_SYMBOL(shamcop_owm_write_interrupt);
EXPORT_SYMBOL(shamcop_owm_read_interrupt);
EXPORT_SYMBOL(shamcop_owm_write_interrupt_enable);
EXPORT_SYMBOL(shamcop_owm_read_interrupt_enable);
EXPORT_SYMBOL(shamcop_owm_write_clock_divisor);
EXPORT_SYMBOL(shamcop_owm_read_clock_divisor);
/*
* Local Variables:
* mode:c
* c-style:"K&R"
* c-basic-offset:8
* End:
*
*/
---------------------------------------------------------------------------------------
arch/arm/common/ipaq/shamcop_owm_ds2760.c
---------------------------------------------------------------------------------------
/*
* DS2760 lowlevel interface using an OWM interface
*
* Note: so far compatible only with the SHAMCOP OWM driver
*
* Copyright (c) 2004 Szabolcs Gyurko
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* Author:
* Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>
* September 2004
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soc-device.h>
#include <linux/battery.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/hardware.h>
#include <asm/hardware/ipaq-hamcop.h>
#include <asm/arch-pxa/h2200-asic.h>
#include <asm/arch-pxa/h2200-gpio.h>
#include <asm/arch-pxa/h2200-init.h>
#include <asm/hardware/shamcop_owm.h>
#include <asm/hardware/shamcop_owm_ds2760.h>
#define DEBUG(format, args...) if (shamcop_owm_ds2760_debug)
printk(__FILE__ ":%s - " format "\n", __FUNCTION__, ## args)
int shamcop_owm_ds2760_debug = 0;
int owm_sample_delay = 200; /* Sample delay in msec */
int owm_rw_delay = 100; /* R/W delay in msec */
MODULE_PARM(owm_sample_delay, "i");
MODULE_PARM_DESC(owm_sample_delay, "Set OWM sample delay (msec)");
MODULE_PARM(owm_rw_delay, "i");
MODULE_PARM_DESC(owm_rw_delay, "Set OWM R/W delay (msec)");
MODULE_PARM(shamcop_owm_ds2760_debug, "i");
MODULE_PARM_DESC(shamcop_owm_ds2760_debug, "If it's non-zero then the
module will generate debug output");
static int ds2760_state;
static int ds2760_last;
static int
shamcop_owm_ds2760_sample(void)
{
int value = shamcop_owm_read_interrupt();
if ((value & OWM_INT_PD) && ds2760_state == DS2760_STATE_RESET)
return 0;
if ((value & OWM_INT_TBE) && (value & OWM_INT_RBF) && ds2760_state
== DS2760_STATE_WRITE) {
ds2760_last = shamcop_owm_read_data();
return 0;
}
if ((value & OWM_INT_RBF)) {
ds2760_last = shamcop_owm_read_data();
if (ds2760_state == DS2760_STATE_READ) return 0;
}
return 1;
}
int
shamcop_owm_ds2760_wait_for_interrupt(int msec)
{
signed long timeout;
timeout = msec * HZ / 1000;
while (timeout > 0) {
timeout = schedule_timeout(timeout);
if (timeout <= 0) {
if (shamcop_owm_ds2760_sample()) return 1;
}
}
return 0;
}
int
shamcop_owm_ds2760_reset(void)
{
int retval;
ds2760_state = DS2760_STATE_RESET;
retval = shamcop_owm_read_interrupt();
shamcop_owm_write_command(shamcop_owm_read_command() |
OWM_CMD_ONE_WIRE_RESET);
retval = shamcop_owm_ds2760_wait_for_interrupt(owm_sample_delay);
if (retval) {
DEBUG("DS2760 reset FAILED: OWM reset failed");
return retval;
}
if (shamcop_owm_read_interrupt() & OWM_INT_PDR) {
DEBUG("DS2760 reset FAILED: no battery found");
return 1;
}
udelay(owm_sample_delay);
DEBUG("DS2760 reset successfully completed");
return 0;
}
int
shamcop_owm_ds2760_write(u8 data)
{
int result;
ds2760_state = DS2760_STATE_WRITE;
result = shamcop_owm_read_interrupt();
shamcop_owm_write_data(data);
result = shamcop_owm_ds2760_wait_for_interrupt(owm_sample_delay);
if (result) DEBUG("DS2760 write failed %d (0x%04x)", result,
shamcop_owm_read_interrupt());
udelay(owm_rw_delay);
return result;
}
int
shamcop_owm_ds2760_read(void)
{
int result;
ds2760_state = DS2760_STATE_READ;
result = shamcop_owm_read_interrupt();
shamcop_owm_write_data(0xff);
result = shamcop_owm_ds2760_wait_for_interrupt(owm_sample_delay);
if (result) {
DEBUG("OWM read failed %d (0x%04x)", result,
shamcop_owm_read_interrupt());
return result;
}
udelay(owm_rw_delay);
return ds2760_last;
}
int
shamcop_owm_ds2760_setup(struct owm_net_address *net) {
int result, i;
if ((result = shamcop_owm_ds2760_reset()) != 0) return result;
if (net) {
if ((result = shamcop_owm_ds2760_write(0x55)) != 0) return
result;
for ( i = 0 ; i < 8 ; i++ ) {
if ((result =
shamcop_owm_ds2760_write(net->address[i])) != 0) return result;
}
} else {
if ((result = shamcop_owm_ds2760_write(0xcc)) != 0) return
result;
}
return 0;
}
int
shamcop_owm_ds2760_read_bytes(struct owm_net_address *net, u8 address, u8
*data, unsigned short len)
{
int result;
int i;
if ((result = shamcop_owm_ds2760_setup(net)) != 0) return result;
if ((result = shamcop_owm_ds2760_write(0x69)) != 0) return result;
if ((result = shamcop_owm_ds2760_write(address)) != 0) return
result;
for ( i = 0 ; i < len ; i++ ) {
if ((result = shamcop_owm_ds2760_read()) < 0) return
result;
data[i] = result;
}
return 0;
}
int __init
shamcop_owm_ds2760_init(void)
{
printk("DS2760 driver for the SHAMCOP ASIC - (c) 2004 Szabolcs
Gyurko\n");
return 0;
}
void __exit
shamcop_owm_ds2760_exit(void)
{
}
module_init(shamcop_owm_ds2760_init);
module_exit(shamcop_owm_ds2760_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>");
MODULE_DESCRIPTION("DS2760 interface based on an OWM driver");
EXPORT_SYMBOL(shamcop_owm_ds2760_reset);
EXPORT_SYMBOL(shamcop_owm_ds2760_read);
EXPORT_SYMBOL(shamcop_owm_ds2760_write);
EXPORT_SYMBOL(shamcop_owm_ds2760_setup);
EXPORT_SYMBOL(shamcop_owm_ds2760_read_bytes);
EXPORT_SYMBOL(shamcop_owm_ds2760_wait_for_interrupt);
/*
* Local Variables:
* mode:c
* c-style:"K&R"
* c-basic-offset:8
* End:
*
*/
-----------------------------------------------------------------------------------------------
arch/arm/mach-pxa/h2200_battery.c
-----------------------------------------------------------------------------------------------
/*
* Battery driver lowlevel interface for iPAQ H2200 series
*
* Copyright (c) 2004 Matt Reimer
* 2004 Szabolcs Gyurko
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* Author: Matt Reimer <mreimer_at_vpop.net>
* April 2004
*
* Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>
* September 2004
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soc-device.h>
#include <linux/battery.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/hardware.h>
#include <asm/hardware/ipaq-hamcop.h>
#include <asm/arch-pxa/h2200-asic.h>
#include <asm/arch-pxa/h2200-gpio.h>
#include <asm/arch-pxa/h2200-init.h>
#include <asm/hardware/shamcop_owm.h>
#include <asm/hardware/shamcop_owm_ds2760.h>
#define DEBUG(format, args...) if (h2200_battery_debug) printk(__FILE__
":%s - " format "\n", __FUNCTION__, ## args)
int h2200_battery_debug = 0;
MODULE_PARM(h2200_battery_debug, "i");
MODULE_PARM_DESC(h2200_battery_debug, "If not zero debug messages will be
printed");
#define H2200_BATTERY_MAX_VOLTAGE 440 /* My measurements */
#define H2200_BATTERY_MIN_VOLTAGE 0 /* Maybe incorrect */
#define H2200_BATTERY_MAX_CURRENT 0 /* MUST BE MEASURED */
#define H2200_BATTERY_MIN_CURRENT 0 /* Maybe incorrect */
int
h2200_battery_get_max_voltage(struct battery *bat)
{
return H2200_BATTERY_MAX_VOLTAGE;
}
int
h2200_battery_get_min_voltage(struct battery *bat)
{
return H2200_BATTERY_MIN_VOLTAGE;
}
int
h2200_battery_get_voltage(struct battery *bat)
{
int result;
unsigned char buf[32];
int battery_voltage;
result = shamcop_owm_ds2760_read_bytes(NULL, 0, buf, 32);
if (result != 0) return result;
battery_voltage = (buf[12] << 2) | (buf[13] >> 5);
if (battery_voltage > 1023) return -EINVAL;
return battery_voltage;
}
int
h2200_battery_get_max_current(struct battery *bat)
{
return H2200_BATTERY_MAX_CURRENT;
}
int
h2200_battery_get_min_current(struct battery *bat)
{
return H2200_BATTERY_MIN_CURRENT;
}
int
h2200_battery_get_current(struct battery *bat)
{
int result;
unsigned char buf[32];
int battery_current;
result = shamcop_owm_ds2760_read_bytes(NULL, 0, buf, 32);
if (result != 0) return result;
battery_current = (buf[14] << 5) | (buf[15] >> 3);
if (battery_current > 4095) battery_current -= 8192;
return battery_current;
}
int
h2200_battery_get_temp(struct battery *bat)
{
int result;
unsigned char buf[32];
int battery_temp;
result = shamcop_owm_ds2760_read_bytes(NULL, 0, buf, 32);
if (result != 0) return result;
battery_temp = (buf[24] << 3) | (buf[25] >> 5);
if (battery_temp > 1023) battery_temp -= 2024;
return battery_temp;
}
int
h2200_battery_get_status(struct battery *bat)
{
return (GET_H2200_GPIO(AC_IN_N)) ? BATTERY_STATUS_NOT_CHARGING :
BATTERY_STATUS_CHARGING;
}
static struct battery h2200_battery = {
.name = "h2200 battery",
.id = "battery0",
.get_voltage = h2200_battery_get_voltage,
.get_min_voltage = h2200_battery_get_min_voltage,
.get_max_voltage = h2200_battery_get_max_voltage,
.get_current = h2200_battery_get_current,
.get_min_current = h2200_battery_get_min_current,
.get_max_current = h2200_battery_get_max_current,
.get_temp = h2200_battery_get_temp,
.get_status = h2200_battery_get_status,
};
static int
h2200_battery_class_hotplug(struct class_device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
return 0;
}
static void
h2200_battery_class_release(struct class_device *dev)
{
}
static void
h2200_battery_class_class_release(struct class *class)
{
}
static int __init
h2200_battery_init(void)
{
int retval;
printk("Battery inerface for iPAQ h2200 series - (c) 2004 Szabolcs
Gyurko\n");
retval = battery_class_register(&h2200_battery);
h2200_battery.class_dev.class->release =
h2200_battery_class_release;
h2200_battery.class_dev.class->hotplug =
h2200_battery_class_hotplug;
h2200_battery.class_dev.class->class_release =
h2200_battery_class_class_release;
return retval;
}
static void __exit h2200_battery_exit(void)
{
battery_class_unregister(&h2200_battery);
}
module_init(h2200_battery_init);
module_exit(h2200_battery_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko_at_tlt.hu>");
MODULE_DESCRIPTION("Battery interface for iPAQ h2200 series PDA");
EXPORT_SYMBOL(h2200_battery_get_status);
EXPORT_SYMBOL(h2200_battery_get_min_voltage);
EXPORT_SYMBOL(h2200_battery_get_max_voltage);
EXPORT_SYMBOL(h2200_battery_get_voltage);
EXPORT_SYMBOL(h2200_battery_get_min_current);
EXPORT_SYMBOL(h2200_battery_get_max_current);
EXPORT_SYMBOL(h2200_battery_get_current);
EXPORT_SYMBOL(h2200_battery_get_temp);
/*
* Local Variables:
* mode:c
* c-style:"K&R"
* c-basic-offset:8
* End:
*
*/
-- Szabolcs GyurkoReceived on Wed Sep 08 2004 - 07:38:04 EDT
This archive was generated by hypermail 2.2.0 : Mon Jul 25 2005 - 17:19:29 EDT