-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is W1 slave for ds2760 chip, found inside almost every HP iPaq and HTC PDAs/phones. Signed-off-by: Anton Vorontsov <cbou@mail.ru> Acked-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
- Loading branch information
Anton Vorontsov
authored and
David Woodhouse
committed
Jul 10, 2007
1 parent
fb97287
commit d7ce6d1
Showing
5 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
/* | ||
* 1-Wire implementation for the ds2760 chip | ||
* | ||
* Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> | ||
* | ||
* Use consistent with the GNU GPL is permitted, | ||
* provided that this copyright notice is | ||
* preserved in its entirety in all copies and derived works. | ||
* | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/device.h> | ||
#include <linux/types.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/mutex.h> | ||
#include <linux/idr.h> | ||
|
||
#include "../w1.h" | ||
#include "../w1_int.h" | ||
#include "../w1_family.h" | ||
#include "w1_ds2760.h" | ||
|
||
static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count, | ||
int io) | ||
{ | ||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
|
||
if (!dev) | ||
return 0; | ||
|
||
mutex_lock(&sl->master->mutex); | ||
|
||
if (addr > DS2760_DATA_SIZE || addr < 0) { | ||
count = 0; | ||
goto out; | ||
} | ||
if (addr + count > DS2760_DATA_SIZE) | ||
count = DS2760_DATA_SIZE - addr; | ||
|
||
if (!w1_reset_select_slave(sl)) { | ||
if (!io) { | ||
w1_write_8(sl->master, W1_DS2760_READ_DATA); | ||
w1_write_8(sl->master, addr); | ||
count = w1_read_block(sl->master, buf, count); | ||
} else { | ||
w1_write_8(sl->master, W1_DS2760_WRITE_DATA); | ||
w1_write_8(sl->master, addr); | ||
w1_write_block(sl->master, buf, count); | ||
/* XXX w1_write_block returns void, not n_written */ | ||
} | ||
} | ||
|
||
out: | ||
mutex_unlock(&sl->master->mutex); | ||
|
||
return count; | ||
} | ||
|
||
int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count) | ||
{ | ||
return w1_ds2760_io(dev, buf, addr, count, 0); | ||
} | ||
|
||
int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count) | ||
{ | ||
return w1_ds2760_io(dev, buf, addr, count, 1); | ||
} | ||
|
||
static ssize_t w1_ds2760_read_bin(struct kobject *kobj, char *buf, loff_t off, | ||
size_t count) | ||
{ | ||
struct device *dev = container_of(kobj, struct device, kobj); | ||
return w1_ds2760_read(dev, buf, off, count); | ||
} | ||
|
||
static struct bin_attribute w1_ds2760_bin_attr = { | ||
.attr = { | ||
.name = "w1_slave", | ||
.mode = S_IRUGO, | ||
.owner = THIS_MODULE, | ||
}, | ||
.size = DS2760_DATA_SIZE, | ||
.read = w1_ds2760_read_bin, | ||
}; | ||
|
||
static DEFINE_IDR(bat_idr); | ||
static DEFINE_MUTEX(bat_idr_lock); | ||
|
||
static int new_bat_id(void) | ||
{ | ||
int ret; | ||
|
||
while (1) { | ||
int id; | ||
|
||
ret = idr_pre_get(&bat_idr, GFP_KERNEL); | ||
if (ret == 0) | ||
return -ENOMEM; | ||
|
||
mutex_lock(&bat_idr_lock); | ||
ret = idr_get_new(&bat_idr, NULL, &id); | ||
mutex_unlock(&bat_idr_lock); | ||
|
||
if (ret == 0) { | ||
ret = id & MAX_ID_MASK; | ||
break; | ||
} else if (ret == -EAGAIN) { | ||
continue; | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
static void release_bat_id(int id) | ||
{ | ||
mutex_lock(&bat_idr_lock); | ||
idr_remove(&bat_idr, id); | ||
mutex_unlock(&bat_idr_lock); | ||
|
||
return; | ||
} | ||
|
||
static int w1_ds2760_add_slave(struct w1_slave *sl) | ||
{ | ||
int ret; | ||
int id; | ||
struct platform_device *pdev; | ||
|
||
id = new_bat_id(); | ||
if (id < 0) { | ||
ret = id; | ||
goto noid; | ||
} | ||
|
||
pdev = platform_device_alloc("ds2760-battery", id); | ||
if (!pdev) { | ||
ret = -ENOMEM; | ||
goto pdev_alloc_failed; | ||
} | ||
pdev->dev.parent = &sl->dev; | ||
|
||
ret = platform_device_add(pdev); | ||
if (ret) | ||
goto pdev_add_failed; | ||
|
||
ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr); | ||
if (ret) | ||
goto bin_attr_failed; | ||
|
||
dev_set_drvdata(&sl->dev, pdev); | ||
|
||
goto success; | ||
|
||
bin_attr_failed: | ||
pdev_add_failed: | ||
platform_device_unregister(pdev); | ||
pdev_alloc_failed: | ||
release_bat_id(id); | ||
noid: | ||
success: | ||
return ret; | ||
} | ||
|
||
static void w1_ds2760_remove_slave(struct w1_slave *sl) | ||
{ | ||
struct platform_device *pdev = dev_get_drvdata(&sl->dev); | ||
int id = pdev->id; | ||
|
||
platform_device_unregister(pdev); | ||
release_bat_id(id); | ||
sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr); | ||
|
||
return; | ||
} | ||
|
||
static struct w1_family_ops w1_ds2760_fops = { | ||
.add_slave = w1_ds2760_add_slave, | ||
.remove_slave = w1_ds2760_remove_slave, | ||
}; | ||
|
||
static struct w1_family w1_ds2760_family = { | ||
.fid = W1_FAMILY_DS2760, | ||
.fops = &w1_ds2760_fops, | ||
}; | ||
|
||
static int __init w1_ds2760_init(void) | ||
{ | ||
printk(KERN_INFO "1-Wire driver for the DS2760 battery monitor " | ||
" chip - (c) 2004-2005, Szabolcs Gyurko\n"); | ||
idr_init(&bat_idr); | ||
return w1_register_family(&w1_ds2760_family); | ||
} | ||
|
||
static void __exit w1_ds2760_exit(void) | ||
{ | ||
w1_unregister_family(&w1_ds2760_family); | ||
idr_destroy(&bat_idr); | ||
} | ||
|
||
EXPORT_SYMBOL(w1_ds2760_read); | ||
EXPORT_SYMBOL(w1_ds2760_write); | ||
|
||
module_init(w1_ds2760_init); | ||
module_exit(w1_ds2760_exit); | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>"); | ||
MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* 1-Wire implementation for the ds2760 chip | ||
* | ||
* Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> | ||
* | ||
* Use consistent with the GNU GPL is permitted, | ||
* provided that this copyright notice is | ||
* preserved in its entirety in all copies and derived works. | ||
* | ||
*/ | ||
|
||
#ifndef __w1_ds2760_h__ | ||
#define __w1_ds2760_h__ | ||
|
||
/* Known commands to the DS2760 chip */ | ||
#define W1_DS2760_SWAP 0xAA | ||
#define W1_DS2760_READ_DATA 0x69 | ||
#define W1_DS2760_WRITE_DATA 0x6C | ||
#define W1_DS2760_COPY_DATA 0x48 | ||
#define W1_DS2760_RECALL_DATA 0xB8 | ||
#define W1_DS2760_LOCK 0x6A | ||
|
||
/* Number of valid register addresses */ | ||
#define DS2760_DATA_SIZE 0x40 | ||
|
||
#define DS2760_PROTECTION_REG 0x00 | ||
#define DS2760_STATUS_REG 0x01 | ||
#define DS2760_EEPROM_REG 0x07 | ||
#define DS2760_SPECIAL_FEATURE_REG 0x08 | ||
#define DS2760_VOLTAGE_MSB 0x0c | ||
#define DS2760_VOLTAGE_LSB 0x0d | ||
#define DS2760_CURRENT_MSB 0x0e | ||
#define DS2760_CURRENT_LSB 0x0f | ||
#define DS2760_CURRENT_ACCUM_MSB 0x10 | ||
#define DS2760_CURRENT_ACCUM_LSB 0x11 | ||
#define DS2760_TEMP_MSB 0x18 | ||
#define DS2760_TEMP_LSB 0x19 | ||
#define DS2760_EEPROM_BLOCK0 0x20 | ||
#define DS2760_ACTIVE_FULL 0x20 | ||
#define DS2760_EEPROM_BLOCK1 0x30 | ||
#define DS2760_RATED_CAPACITY 0x32 | ||
#define DS2760_CURRENT_OFFSET_BIAS 0x33 | ||
#define DS2760_ACTIVE_EMPTY 0x3b | ||
|
||
extern int w1_ds2760_read(struct device *dev, char *buf, int addr, | ||
size_t count); | ||
extern int w1_ds2760_write(struct device *dev, char *buf, int addr, | ||
size_t count); | ||
|
||
#endif /* !__w1_ds2760_h__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters