aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1/slaves
diff options
context:
space:
mode:
authorClifton Barnes <cabarnes@indesign-llc.com>2011-05-26 19:26:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-26 20:12:38 -0400
commit275ac74629c4d8ec430d7edecb16d936f46a47c5 (patch)
tree4b1afa61ec2547d10f07084d9c33fd96d28350a5 /drivers/w1/slaves
parent963bb101010169b9bb32b5c21af785e2f9abdaf3 (diff)
w1: add Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC support
Add support for the Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC. It was suggested to combine this functionality with the current ds2782 driver. Unfortunately, I'm unable to commit the time to refactoring this driver to that extent and I don't have a platform with the ds2782 part to validate that there are no regression issues by adding this functionality. [akpm@linux-foundation.org: use min_t()] Signed-off-by: Clifton Barnes <cabarnes@indesign-llc.com> Tested-by: Haojian Zhuang <haojian.zhuang@gmail.com> Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Cc: Ryan Mallon <ryan@bluewatersys.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/w1/slaves')
-rw-r--r--drivers/w1/slaves/Kconfig13
-rw-r--r--drivers/w1/slaves/Makefile1
-rw-r--r--drivers/w1/slaves/w1_ds2780.c217
-rw-r--r--drivers/w1/slaves/w1_ds2780.h129
4 files changed, 360 insertions, 0 deletions
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index cd1b72411bd4..d0cb01b42012 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -68,6 +68,19 @@ config W1_SLAVE_DS2760
68 68
69 If you are unsure, say N. 69 If you are unsure, say N.
70 70
71config W1_SLAVE_DS2780
72 tristate "Dallas 2780 battery monitor chip"
73 depends on W1
74 help
75 If you enable this you will have the DS2780 battery monitor
76 chip support.
77
78 The battery monitor chip is used in many batteries/devices
79 as the one who is responsible for charging/discharging/monitoring
80 Li+ batteries.
81
82 If you are unsure, say N.
83
71config W1_SLAVE_BQ27000 84config W1_SLAVE_BQ27000
72 tristate "BQ27000 slave support" 85 tristate "BQ27000 slave support"
73 depends on W1 86 depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 75e3913910bb..1f31e9fb0b25 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o
9obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o 9obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o
10obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o 10obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
11obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o 11obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
12obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o
12obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o 13obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
new file mode 100644
index 000000000000..274c8f38303f
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -0,0 +1,217 @@
1/*
2 * 1-Wire implementation for the ds2780 chip
3 *
4 * Copyright (C) 2010 Indesign, LLC
5 *
6 * Author: Clifton Barnes <cabarnes@indesign-llc.com>
7 *
8 * Based on w1-ds2760 driver
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/device.h>
19#include <linux/types.h>
20#include <linux/platform_device.h>
21#include <linux/mutex.h>
22#include <linux/idr.h>
23
24#include "../w1.h"
25#include "../w1_int.h"
26#include "../w1_family.h"
27#include "w1_ds2780.h"
28
29int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
30 int io)
31{
32 struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
33
34 if (!dev)
35 return -ENODEV;
36
37 mutex_lock(&sl->master->mutex);
38
39 if (addr > DS2780_DATA_SIZE || addr < 0) {
40 count = 0;
41 goto out;
42 }
43 count = min_t(int, count, DS2780_DATA_SIZE - addr);
44
45 if (w1_reset_select_slave(sl) == 0) {
46 if (io) {
47 w1_write_8(sl->master, W1_DS2780_WRITE_DATA);
48 w1_write_8(sl->master, addr);
49 w1_write_block(sl->master, buf, count);
50 /* XXX w1_write_block returns void, not n_written */
51 } else {
52 w1_write_8(sl->master, W1_DS2780_READ_DATA);
53 w1_write_8(sl->master, addr);
54 count = w1_read_block(sl->master, buf, count);
55 }
56 }
57
58out:
59 mutex_unlock(&sl->master->mutex);
60
61 return count;
62}
63EXPORT_SYMBOL(w1_ds2780_io);
64
65int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
66{
67 struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
68
69 if (!dev)
70 return -EINVAL;
71
72 mutex_lock(&sl->master->mutex);
73
74 if (w1_reset_select_slave(sl) == 0) {
75 w1_write_8(sl->master, cmd);
76 w1_write_8(sl->master, addr);
77 }
78
79 mutex_unlock(&sl->master->mutex);
80 return 0;
81}
82EXPORT_SYMBOL(w1_ds2780_eeprom_cmd);
83
84static ssize_t w1_ds2780_read_bin(struct file *filp,
85 struct kobject *kobj,
86 struct bin_attribute *bin_attr,
87 char *buf, loff_t off, size_t count)
88{
89 struct device *dev = container_of(kobj, struct device, kobj);
90 return w1_ds2780_io(dev, buf, off, count, 0);
91}
92
93static struct bin_attribute w1_ds2780_bin_attr = {
94 .attr = {
95 .name = "w1_slave",
96 .mode = S_IRUGO,
97 },
98 .size = DS2780_DATA_SIZE,
99 .read = w1_ds2780_read_bin,
100};
101
102static DEFINE_IDR(bat_idr);
103static DEFINE_MUTEX(bat_idr_lock);
104
105static int new_bat_id(void)
106{
107 int ret;
108
109 while (1) {
110 int id;
111
112 ret = idr_pre_get(&bat_idr, GFP_KERNEL);
113 if (ret == 0)
114 return -ENOMEM;
115
116 mutex_lock(&bat_idr_lock);
117 ret = idr_get_new(&bat_idr, NULL, &id);
118 mutex_unlock(&bat_idr_lock);
119
120 if (ret == 0) {
121 ret = id & MAX_ID_MASK;
122 break;
123 } else if (ret == -EAGAIN) {
124 continue;
125 } else {
126 break;
127 }
128 }
129
130 return ret;
131}
132
133static void release_bat_id(int id)
134{
135 mutex_lock(&bat_idr_lock);
136 idr_remove(&bat_idr, id);
137 mutex_unlock(&bat_idr_lock);
138}
139
140static int w1_ds2780_add_slave(struct w1_slave *sl)
141{
142 int ret;
143 int id;
144 struct platform_device *pdev;
145
146 id = new_bat_id();
147 if (id < 0) {
148 ret = id;
149 goto noid;
150 }
151
152 pdev = platform_device_alloc("ds2780-battery", id);
153 if (!pdev) {
154 ret = -ENOMEM;
155 goto pdev_alloc_failed;
156 }
157 pdev->dev.parent = &sl->dev;
158
159 ret = platform_device_add(pdev);
160 if (ret)
161 goto pdev_add_failed;
162
163 ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
164 if (ret)
165 goto bin_attr_failed;
166
167 dev_set_drvdata(&sl->dev, pdev);
168
169 return 0;
170
171bin_attr_failed:
172pdev_add_failed:
173 platform_device_unregister(pdev);
174pdev_alloc_failed:
175 release_bat_id(id);
176noid:
177 return ret;
178}
179
180static void w1_ds2780_remove_slave(struct w1_slave *sl)
181{
182 struct platform_device *pdev = dev_get_drvdata(&sl->dev);
183 int id = pdev->id;
184
185 platform_device_unregister(pdev);
186 release_bat_id(id);
187 sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
188}
189
190static struct w1_family_ops w1_ds2780_fops = {
191 .add_slave = w1_ds2780_add_slave,
192 .remove_slave = w1_ds2780_remove_slave,
193};
194
195static struct w1_family w1_ds2780_family = {
196 .fid = W1_FAMILY_DS2780,
197 .fops = &w1_ds2780_fops,
198};
199
200static int __init w1_ds2780_init(void)
201{
202 idr_init(&bat_idr);
203 return w1_register_family(&w1_ds2780_family);
204}
205
206static void __exit w1_ds2780_exit(void)
207{
208 w1_unregister_family(&w1_ds2780_family);
209 idr_destroy(&bat_idr);
210}
211
212module_init(w1_ds2780_init);
213module_exit(w1_ds2780_exit);
214
215MODULE_LICENSE("GPL");
216MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
217MODULE_DESCRIPTION("1-wire Driver for Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC");
diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h
new file mode 100644
index 000000000000..a1fba79eb1b5
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2780.h
@@ -0,0 +1,129 @@
1/*
2 * 1-Wire implementation for the ds2780 chip
3 *
4 * Copyright (C) 2010 Indesign, LLC
5 *
6 * Author: Clifton Barnes <cabarnes@indesign-llc.com>
7 *
8 * Based on w1-ds2760 driver
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15
16#ifndef _W1_DS2780_H
17#define _W1_DS2780_H
18
19/* Function commands */
20#define W1_DS2780_READ_DATA 0x69
21#define W1_DS2780_WRITE_DATA 0x6C
22#define W1_DS2780_COPY_DATA 0x48
23#define W1_DS2780_RECALL_DATA 0xB8
24#define W1_DS2780_LOCK 0x6A
25
26/* Register map */
27/* Register 0x00 Reserved */
28#define DS2780_STATUS_REG 0x01
29#define DS2780_RAAC_MSB_REG 0x02
30#define DS2780_RAAC_LSB_REG 0x03
31#define DS2780_RSAC_MSB_REG 0x04
32#define DS2780_RSAC_LSB_REG 0x05
33#define DS2780_RARC_REG 0x06
34#define DS2780_RSRC_REG 0x07
35#define DS2780_IAVG_MSB_REG 0x08
36#define DS2780_IAVG_LSB_REG 0x09
37#define DS2780_TEMP_MSB_REG 0x0A
38#define DS2780_TEMP_LSB_REG 0x0B
39#define DS2780_VOLT_MSB_REG 0x0C
40#define DS2780_VOLT_LSB_REG 0x0D
41#define DS2780_CURRENT_MSB_REG 0x0E
42#define DS2780_CURRENT_LSB_REG 0x0F
43#define DS2780_ACR_MSB_REG 0x10
44#define DS2780_ACR_LSB_REG 0x11
45#define DS2780_ACRL_MSB_REG 0x12
46#define DS2780_ACRL_LSB_REG 0x13
47#define DS2780_AS_REG 0x14
48#define DS2780_SFR_REG 0x15
49#define DS2780_FULL_MSB_REG 0x16
50#define DS2780_FULL_LSB_REG 0x17
51#define DS2780_AE_MSB_REG 0x18
52#define DS2780_AE_LSB_REG 0x19
53#define DS2780_SE_MSB_REG 0x1A
54#define DS2780_SE_LSB_REG 0x1B
55/* Register 0x1C - 0x1E Reserved */
56#define DS2780_EEPROM_REG 0x1F
57#define DS2780_EEPROM_BLOCK0_START 0x20
58/* Register 0x20 - 0x2F User EEPROM */
59#define DS2780_EEPROM_BLOCK0_END 0x2F
60/* Register 0x30 - 0x5F Reserved */
61#define DS2780_EEPROM_BLOCK1_START 0x60
62#define DS2780_CONTROL_REG 0x60
63#define DS2780_AB_REG 0x61
64#define DS2780_AC_MSB_REG 0x62
65#define DS2780_AC_LSB_REG 0x63
66#define DS2780_VCHG_REG 0x64
67#define DS2780_IMIN_REG 0x65
68#define DS2780_VAE_REG 0x66
69#define DS2780_IAE_REG 0x67
70#define DS2780_AE_40_REG 0x68
71#define DS2780_RSNSP_REG 0x69
72#define DS2780_FULL_40_MSB_REG 0x6A
73#define DS2780_FULL_40_LSB_REG 0x6B
74#define DS2780_FULL_3040_SLOPE_REG 0x6C
75#define DS2780_FULL_2030_SLOPE_REG 0x6D
76#define DS2780_FULL_1020_SLOPE_REG 0x6E
77#define DS2780_FULL_0010_SLOPE_REG 0x6F
78#define DS2780_AE_3040_SLOPE_REG 0x70
79#define DS2780_AE_2030_SLOPE_REG 0x71
80#define DS2780_AE_1020_SLOPE_REG 0x72
81#define DS2780_AE_0010_SLOPE_REG 0x73
82#define DS2780_SE_3040_SLOPE_REG 0x74
83#define DS2780_SE_2030_SLOPE_REG 0x75
84#define DS2780_SE_1020_SLOPE_REG 0x76
85#define DS2780_SE_0010_SLOPE_REG 0x77
86#define DS2780_RSGAIN_MSB_REG 0x78
87#define DS2780_RSGAIN_LSB_REG 0x79
88#define DS2780_RSTC_REG 0x7A
89#define DS2780_FRSGAIN_MSB_REG 0x7B
90#define DS2780_FRSGAIN_LSB_REG 0x7C
91#define DS2780_EEPROM_BLOCK1_END 0x7C
92/* Register 0x7D - 0xFF Reserved */
93
94/* Number of valid register addresses */
95#define DS2780_DATA_SIZE 0x80
96
97/* Status register bits */
98#define DS2780_STATUS_REG_CHGTF (1 << 7)
99#define DS2780_STATUS_REG_AEF (1 << 6)
100#define DS2780_STATUS_REG_SEF (1 << 5)
101#define DS2780_STATUS_REG_LEARNF (1 << 4)
102/* Bit 3 Reserved */
103#define DS2780_STATUS_REG_UVF (1 << 2)
104#define DS2780_STATUS_REG_PORF (1 << 1)
105/* Bit 0 Reserved */
106
107/* Control register bits */
108/* Bit 7 Reserved */
109#define DS2780_CONTROL_REG_UVEN (1 << 6)
110#define DS2780_CONTROL_REG_PMOD (1 << 5)
111#define DS2780_CONTROL_REG_RNAOP (1 << 4)
112/* Bit 0 - 3 Reserved */
113
114/* Special feature register bits */
115/* Bit 1 - 7 Reserved */
116#define DS2780_SFR_REG_PIOSC (1 << 0)
117
118/* EEPROM register bits */
119#define DS2780_EEPROM_REG_EEC (1 << 7)
120#define DS2780_EEPROM_REG_LOCK (1 << 6)
121/* Bit 2 - 6 Reserved */
122#define DS2780_EEPROM_REG_BL1 (1 << 1)
123#define DS2780_EEPROM_REG_BL0 (1 << 0)
124
125extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
126 int io);
127extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd);
128
129#endif /* !_W1_DS2780_H */