aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Vorontsov <cbou@mail.ru>2007-04-11 17:03:55 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-07-10 06:28:31 -0400
commitd7ce6d1d5f6e307a2fbb69626cf120e20e793fe7 (patch)
tree9ef6d649e0d6c432c2e3d250267f206f2fddd924
parentfb972873a767220333ffb509de8d9131336e212c (diff)
[BATTERY] ds2760 W1 slave
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>
-rw-r--r--drivers/w1/slaves/Kconfig13
-rw-r--r--drivers/w1/slaves/Makefile1
-rw-r--r--drivers/w1/slaves/w1_ds2760.c213
-rw-r--r--drivers/w1/slaves/w1_ds2760.h50
-rw-r--r--drivers/w1/w1_family.h1
5 files changed, 278 insertions, 0 deletions
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index 904e5aeb696..df95d6c2cef 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -35,4 +35,17 @@ config W1_SLAVE_DS2433_CRC
35 Each block has 30 bytes of data and a two byte CRC16. 35 Each block has 30 bytes of data and a two byte CRC16.
36 Full block writes are only allowed if the CRC is valid. 36 Full block writes are only allowed if the CRC is valid.
37 37
38config W1_SLAVE_DS2760
39 tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)"
40 depends on W1
41 help
42 If you enable this you will have the DS2760 battery monitor
43 chip support.
44
45 The battery monitor chip is used in many batteries/devices
46 as the one who is responsible for charging/discharging/monitoring
47 Li+ batteries.
48
49 If you are unsure, say N.
50
38endmenu 51endmenu
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 725dcfdfddb..a8eb7524df1 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -5,4 +5,5 @@
5obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o 5obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o
6obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o 6obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o
7obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o 7obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
8obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
8 9
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c
new file mode 100644
index 00000000000..88a37fbccc3
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2760.c
@@ -0,0 +1,213 @@
1/*
2 * 1-Wire implementation for the ds2760 chip
3 *
4 * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
5 *
6 * Use consistent with the GNU GPL is permitted,
7 * provided that this copyright notice is
8 * preserved in its entirety in all copies and derived works.
9 *
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/device.h>
15#include <linux/types.h>
16#include <linux/platform_device.h>
17#include <linux/mutex.h>
18#include <linux/idr.h>
19
20#include "../w1.h"
21#include "../w1_int.h"
22#include "../w1_family.h"
23#include "w1_ds2760.h"
24
25static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count,
26 int io)
27{
28 struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
29
30 if (!dev)
31 return 0;
32
33 mutex_lock(&sl->master->mutex);
34
35 if (addr > DS2760_DATA_SIZE || addr < 0) {
36 count = 0;
37 goto out;
38 }
39 if (addr + count > DS2760_DATA_SIZE)
40 count = DS2760_DATA_SIZE - addr;
41
42 if (!w1_reset_select_slave(sl)) {
43 if (!io) {
44 w1_write_8(sl->master, W1_DS2760_READ_DATA);
45 w1_write_8(sl->master, addr);
46 count = w1_read_block(sl->master, buf, count);
47 } else {
48 w1_write_8(sl->master, W1_DS2760_WRITE_DATA);
49 w1_write_8(sl->master, addr);
50 w1_write_block(sl->master, buf, count);
51 /* XXX w1_write_block returns void, not n_written */
52 }
53 }
54
55out:
56 mutex_unlock(&sl->master->mutex);
57
58 return count;
59}
60
61int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count)
62{
63 return w1_ds2760_io(dev, buf, addr, count, 0);
64}
65
66int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count)
67{
68 return w1_ds2760_io(dev, buf, addr, count, 1);
69}
70
71static ssize_t w1_ds2760_read_bin(struct kobject *kobj, char *buf, loff_t off,
72 size_t count)
73{
74 struct device *dev = container_of(kobj, struct device, kobj);
75 return w1_ds2760_read(dev, buf, off, count);
76}
77
78static struct bin_attribute w1_ds2760_bin_attr = {
79 .attr = {
80 .name = "w1_slave",
81 .mode = S_IRUGO,
82 .owner = THIS_MODULE,
83 },
84 .size = DS2760_DATA_SIZE,
85 .read = w1_ds2760_read_bin,
86};
87
88static DEFINE_IDR(bat_idr);
89static DEFINE_MUTEX(bat_idr_lock);
90
91static int new_bat_id(void)
92{
93 int ret;
94
95 while (1) {
96 int id;
97
98 ret = idr_pre_get(&bat_idr, GFP_KERNEL);
99 if (ret == 0)
100 return -ENOMEM;
101
102 mutex_lock(&bat_idr_lock);
103 ret = idr_get_new(&bat_idr, NULL, &id);
104 mutex_unlock(&bat_idr_lock);
105
106 if (ret == 0) {
107 ret = id & MAX_ID_MASK;
108 break;
109 } else if (ret == -EAGAIN) {
110 continue;
111 } else {
112 break;
113 }
114 }
115
116 return ret;
117}
118
119static void release_bat_id(int id)
120{
121 mutex_lock(&bat_idr_lock);
122 idr_remove(&bat_idr, id);
123 mutex_unlock(&bat_idr_lock);
124
125 return;
126}
127
128static int w1_ds2760_add_slave(struct w1_slave *sl)
129{
130 int ret;
131 int id;
132 struct platform_device *pdev;
133
134 id = new_bat_id();
135 if (id < 0) {
136 ret = id;
137 goto noid;
138 }
139
140 pdev = platform_device_alloc("ds2760-battery", id);
141 if (!pdev) {
142 ret = -ENOMEM;
143 goto pdev_alloc_failed;
144 }
145 pdev->dev.parent = &sl->dev;
146
147 ret = platform_device_add(pdev);
148 if (ret)
149 goto pdev_add_failed;
150
151 ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
152 if (ret)
153 goto bin_attr_failed;
154
155 dev_set_drvdata(&sl->dev, pdev);
156
157 goto success;
158
159bin_attr_failed:
160pdev_add_failed:
161 platform_device_unregister(pdev);
162pdev_alloc_failed:
163 release_bat_id(id);
164noid:
165success:
166 return ret;
167}
168
169static void w1_ds2760_remove_slave(struct w1_slave *sl)
170{
171 struct platform_device *pdev = dev_get_drvdata(&sl->dev);
172 int id = pdev->id;
173
174 platform_device_unregister(pdev);
175 release_bat_id(id);
176 sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
177
178 return;
179}
180
181static struct w1_family_ops w1_ds2760_fops = {
182 .add_slave = w1_ds2760_add_slave,
183 .remove_slave = w1_ds2760_remove_slave,
184};
185
186static struct w1_family w1_ds2760_family = {
187 .fid = W1_FAMILY_DS2760,
188 .fops = &w1_ds2760_fops,
189};
190
191static int __init w1_ds2760_init(void)
192{
193 printk(KERN_INFO "1-Wire driver for the DS2760 battery monitor "
194 " chip - (c) 2004-2005, Szabolcs Gyurko\n");
195 idr_init(&bat_idr);
196 return w1_register_family(&w1_ds2760_family);
197}
198
199static void __exit w1_ds2760_exit(void)
200{
201 w1_unregister_family(&w1_ds2760_family);
202 idr_destroy(&bat_idr);
203}
204
205EXPORT_SYMBOL(w1_ds2760_read);
206EXPORT_SYMBOL(w1_ds2760_write);
207
208module_init(w1_ds2760_init);
209module_exit(w1_ds2760_exit);
210
211MODULE_LICENSE("GPL");
212MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>");
213MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip");
diff --git a/drivers/w1/slaves/w1_ds2760.h b/drivers/w1/slaves/w1_ds2760.h
new file mode 100644
index 00000000000..f1302429cb0
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2760.h
@@ -0,0 +1,50 @@
1/*
2 * 1-Wire implementation for the ds2760 chip
3 *
4 * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
5 *
6 * Use consistent with the GNU GPL is permitted,
7 * provided that this copyright notice is
8 * preserved in its entirety in all copies and derived works.
9 *
10 */
11
12#ifndef __w1_ds2760_h__
13#define __w1_ds2760_h__
14
15/* Known commands to the DS2760 chip */
16#define W1_DS2760_SWAP 0xAA
17#define W1_DS2760_READ_DATA 0x69
18#define W1_DS2760_WRITE_DATA 0x6C
19#define W1_DS2760_COPY_DATA 0x48
20#define W1_DS2760_RECALL_DATA 0xB8
21#define W1_DS2760_LOCK 0x6A
22
23/* Number of valid register addresses */
24#define DS2760_DATA_SIZE 0x40
25
26#define DS2760_PROTECTION_REG 0x00
27#define DS2760_STATUS_REG 0x01
28#define DS2760_EEPROM_REG 0x07
29#define DS2760_SPECIAL_FEATURE_REG 0x08
30#define DS2760_VOLTAGE_MSB 0x0c
31#define DS2760_VOLTAGE_LSB 0x0d
32#define DS2760_CURRENT_MSB 0x0e
33#define DS2760_CURRENT_LSB 0x0f
34#define DS2760_CURRENT_ACCUM_MSB 0x10
35#define DS2760_CURRENT_ACCUM_LSB 0x11
36#define DS2760_TEMP_MSB 0x18
37#define DS2760_TEMP_LSB 0x19
38#define DS2760_EEPROM_BLOCK0 0x20
39#define DS2760_ACTIVE_FULL 0x20
40#define DS2760_EEPROM_BLOCK1 0x30
41#define DS2760_RATED_CAPACITY 0x32
42#define DS2760_CURRENT_OFFSET_BIAS 0x33
43#define DS2760_ACTIVE_EMPTY 0x3b
44
45extern int w1_ds2760_read(struct device *dev, char *buf, int addr,
46 size_t count);
47extern int w1_ds2760_write(struct device *dev, char *buf, int addr,
48 size_t count);
49
50#endif /* !__w1_ds2760_h__ */
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 1e2ac40c2c1..ef1e1dafa19 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -33,6 +33,7 @@
33#define W1_THERM_DS1822 0x22 33#define W1_THERM_DS1822 0x22
34#define W1_EEPROM_DS2433 0x23 34#define W1_EEPROM_DS2433 0x23
35#define W1_THERM_DS18B20 0x28 35#define W1_THERM_DS18B20 0x28
36#define W1_FAMILY_DS2760 0x30
36 37
37#define MAXNAMELEN 32 38#define MAXNAMELEN 32
38 39