diff options
Diffstat (limited to 'drivers/w1/w1_therm.c')
-rw-r--r-- | drivers/w1/w1_therm.c | 104 |
1 files changed, 81 insertions, 23 deletions
diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index 0b1817890503..165526c9360a 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_therm.c | 2 | * w1_therm.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the therms of the GNU General Public License as published by | 8 | * it under the therms of the GNU General Public License as published by |
@@ -38,31 +38,78 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | |||
38 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family."); | 38 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family."); |
39 | 39 | ||
40 | static u8 bad_roms[][9] = { | 40 | static u8 bad_roms[][9] = { |
41 | {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87}, | 41 | {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87}, |
42 | {} | 42 | {} |
43 | }; | 43 | }; |
44 | 44 | ||
45 | static ssize_t w1_therm_read_name(struct device *, char *); | 45 | static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *); |
46 | static ssize_t w1_therm_read_temp(struct device *, char *); | ||
47 | static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); | 46 | static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); |
48 | 47 | ||
49 | static struct w1_family_ops w1_therm_fops = { | 48 | static struct w1_family_ops w1_therm_fops = { |
50 | .rname = &w1_therm_read_name, | 49 | .rname = &w1_therm_read_name, |
51 | .rbin = &w1_therm_read_bin, | 50 | .rbin = &w1_therm_read_bin, |
52 | .rval = &w1_therm_read_temp, | ||
53 | .rvalname = "temp1_input", | ||
54 | }; | 51 | }; |
55 | 52 | ||
56 | static ssize_t w1_therm_read_name(struct device *dev, char *buf) | 53 | static struct w1_family w1_therm_family_DS18S20 = { |
54 | .fid = W1_THERM_DS18S20, | ||
55 | .fops = &w1_therm_fops, | ||
56 | }; | ||
57 | |||
58 | static struct w1_family w1_therm_family_DS18B20 = { | ||
59 | .fid = W1_THERM_DS18B20, | ||
60 | .fops = &w1_therm_fops, | ||
61 | }; | ||
62 | static struct w1_family w1_therm_family_DS1822 = { | ||
63 | .fid = W1_THERM_DS1822, | ||
64 | .fops = &w1_therm_fops, | ||
65 | }; | ||
66 | |||
67 | struct w1_therm_family_converter | ||
68 | { | ||
69 | u8 broken; | ||
70 | u16 reserved; | ||
71 | struct w1_family *f; | ||
72 | int (*convert)(u8 rom[9]); | ||
73 | }; | ||
74 | |||
75 | static inline int w1_DS18B20_convert_temp(u8 rom[9]); | ||
76 | static inline int w1_DS18S20_convert_temp(u8 rom[9]); | ||
77 | |||
78 | static struct w1_therm_family_converter w1_therm_families[] = { | ||
79 | { | ||
80 | .f = &w1_therm_family_DS18S20, | ||
81 | .convert = w1_DS18S20_convert_temp | ||
82 | }, | ||
83 | { | ||
84 | .f = &w1_therm_family_DS1822, | ||
85 | .convert = w1_DS18B20_convert_temp | ||
86 | }, | ||
87 | { | ||
88 | .f = &w1_therm_family_DS18B20, | ||
89 | .convert = w1_DS18B20_convert_temp | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf) | ||
57 | { | 94 | { |
58 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | 95 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); |
59 | 96 | ||
60 | return sprintf(buf, "%s\n", sl->name); | 97 | return sprintf(buf, "%s\n", sl->name); |
61 | } | 98 | } |
62 | 99 | ||
63 | static inline int w1_convert_temp(u8 rom[9]) | 100 | static inline int w1_DS18B20_convert_temp(u8 rom[9]) |
101 | { | ||
102 | int t = (rom[1] << 8) | rom[0]; | ||
103 | t /= 16; | ||
104 | return t; | ||
105 | } | ||
106 | |||
107 | static inline int w1_DS18S20_convert_temp(u8 rom[9]) | ||
64 | { | 108 | { |
65 | int t, h; | 109 | int t, h; |
110 | |||
111 | if (!rom[7]) | ||
112 | return 0; | ||
66 | 113 | ||
67 | if (rom[1] == 0) | 114 | if (rom[1] == 0) |
68 | t = ((s32)rom[0] >> 1)*1000; | 115 | t = ((s32)rom[0] >> 1)*1000; |
@@ -77,11 +124,15 @@ static inline int w1_convert_temp(u8 rom[9]) | |||
77 | return t; | 124 | return t; |
78 | } | 125 | } |
79 | 126 | ||
80 | static ssize_t w1_therm_read_temp(struct device *dev, char *buf) | 127 | static inline int w1_convert_temp(u8 rom[9], u8 fid) |
81 | { | 128 | { |
82 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | 129 | int i; |
130 | |||
131 | for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) | ||
132 | if (w1_therm_families[i].f->fid == fid) | ||
133 | return w1_therm_families[i].convert(rom); | ||
83 | 134 | ||
84 | return sprintf(buf, "%d\n", w1_convert_temp(sl->rom)); | 135 | return 0; |
85 | } | 136 | } |
86 | 137 | ||
87 | static int w1_therm_check_rom(u8 rom[9]) | 138 | static int w1_therm_check_rom(u8 rom[9]) |
@@ -98,7 +149,7 @@ static int w1_therm_check_rom(u8 rom[9]) | |||
98 | static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) | 149 | static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) |
99 | { | 150 | { |
100 | struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), | 151 | struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), |
101 | struct w1_slave, dev); | 152 | struct w1_slave, dev); |
102 | struct w1_master *dev = sl->master; | 153 | struct w1_master *dev = sl->master; |
103 | u8 rom[9], crc, verdict; | 154 | u8 rom[9], crc, verdict; |
104 | int i, max_trying = 10; | 155 | int i, max_trying = 10; |
@@ -133,7 +184,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
133 | unsigned int tm = 750; | 184 | unsigned int tm = 750; |
134 | 185 | ||
135 | memcpy(&match[1], (u64 *) & sl->reg_num, 8); | 186 | memcpy(&match[1], (u64 *) & sl->reg_num, 8); |
136 | 187 | ||
137 | w1_write_block(dev, match, 9); | 188 | w1_write_block(dev, match, 9); |
138 | 189 | ||
139 | w1_write_8(dev, W1_CONVERT_TEMP); | 190 | w1_write_8(dev, W1_CONVERT_TEMP); |
@@ -146,7 +197,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
146 | 197 | ||
147 | if (!w1_reset_bus (dev)) { | 198 | if (!w1_reset_bus (dev)) { |
148 | w1_write_block(dev, match, 9); | 199 | w1_write_block(dev, match, 9); |
149 | 200 | ||
150 | w1_write_8(dev, W1_READ_SCRATCHPAD); | 201 | w1_write_8(dev, W1_READ_SCRATCHPAD); |
151 | if ((count = w1_read_block(dev, rom, 9)) != 9) { | 202 | if ((count = w1_read_block(dev, rom, 9)) != 9) { |
152 | dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count); | 203 | dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count); |
@@ -176,7 +227,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
176 | for (i = 0; i < 9; ++i) | 227 | for (i = 0; i < 9; ++i) |
177 | count += sprintf(buf + count, "%02x ", sl->rom[i]); | 228 | count += sprintf(buf + count, "%02x ", sl->rom[i]); |
178 | 229 | ||
179 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom)); | 230 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); |
180 | out: | 231 | out: |
181 | up(&dev->mutex); | 232 | up(&dev->mutex); |
182 | out_dec: | 233 | out_dec: |
@@ -186,19 +237,26 @@ out_dec: | |||
186 | return count; | 237 | return count; |
187 | } | 238 | } |
188 | 239 | ||
189 | static struct w1_family w1_therm_family = { | ||
190 | .fid = W1_FAMILY_THERM, | ||
191 | .fops = &w1_therm_fops, | ||
192 | }; | ||
193 | |||
194 | static int __init w1_therm_init(void) | 240 | static int __init w1_therm_init(void) |
195 | { | 241 | { |
196 | return w1_register_family(&w1_therm_family); | 242 | int err, i; |
243 | |||
244 | for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) { | ||
245 | err = w1_register_family(w1_therm_families[i].f); | ||
246 | if (err) | ||
247 | w1_therm_families[i].broken = 1; | ||
248 | } | ||
249 | |||
250 | return 0; | ||
197 | } | 251 | } |
198 | 252 | ||
199 | static void __exit w1_therm_fini(void) | 253 | static void __exit w1_therm_fini(void) |
200 | { | 254 | { |
201 | w1_unregister_family(&w1_therm_family); | 255 | int i; |
256 | |||
257 | for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) | ||
258 | if (!w1_therm_families[i].broken) | ||
259 | w1_unregister_family(w1_therm_families[i].f); | ||
202 | } | 260 | } |
203 | 261 | ||
204 | module_init(w1_therm_init); | 262 | module_init(w1_therm_init); |