diff options
-rw-r--r-- | drivers/w1/w1.c | 40 | ||||
-rw-r--r-- | drivers/w1/w1.h | 12 | ||||
-rw-r--r-- | drivers/w1/w1_int.c | 16 | ||||
-rw-r--r-- | drivers/w1/w1_io.c | 68 |
4 files changed, 131 insertions, 5 deletions
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 9b5c11701c37..32418d4e555a 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -246,10 +246,14 @@ static ssize_t w1_master_attribute_store_search(struct device * dev, | |||
246 | struct device_attribute *attr, | 246 | struct device_attribute *attr, |
247 | const char * buf, size_t count) | 247 | const char * buf, size_t count) |
248 | { | 248 | { |
249 | long tmp; | ||
249 | struct w1_master *md = dev_to_w1_master(dev); | 250 | struct w1_master *md = dev_to_w1_master(dev); |
250 | 251 | ||
252 | if (strict_strtol(buf, 0, &tmp) == -EINVAL) | ||
253 | return -EINVAL; | ||
254 | |||
251 | mutex_lock(&md->mutex); | 255 | mutex_lock(&md->mutex); |
252 | md->search_count = simple_strtol(buf, NULL, 0); | 256 | md->search_count = tmp; |
253 | mutex_unlock(&md->mutex); | 257 | mutex_unlock(&md->mutex); |
254 | wake_up_process(md->thread); | 258 | wake_up_process(md->thread); |
255 | 259 | ||
@@ -270,6 +274,38 @@ static ssize_t w1_master_attribute_show_search(struct device *dev, | |||
270 | return count; | 274 | return count; |
271 | } | 275 | } |
272 | 276 | ||
277 | static ssize_t w1_master_attribute_store_pullup(struct device *dev, | ||
278 | struct device_attribute *attr, | ||
279 | const char *buf, size_t count) | ||
280 | { | ||
281 | long tmp; | ||
282 | struct w1_master *md = dev_to_w1_master(dev); | ||
283 | |||
284 | if (strict_strtol(buf, 0, &tmp) == -EINVAL) | ||
285 | return -EINVAL; | ||
286 | |||
287 | mutex_lock(&md->mutex); | ||
288 | md->enable_pullup = tmp; | ||
289 | mutex_unlock(&md->mutex); | ||
290 | wake_up_process(md->thread); | ||
291 | |||
292 | return count; | ||
293 | } | ||
294 | |||
295 | static ssize_t w1_master_attribute_show_pullup(struct device *dev, | ||
296 | struct device_attribute *attr, | ||
297 | char *buf) | ||
298 | { | ||
299 | struct w1_master *md = dev_to_w1_master(dev); | ||
300 | ssize_t count; | ||
301 | |||
302 | mutex_lock(&md->mutex); | ||
303 | count = sprintf(buf, "%d\n", md->enable_pullup); | ||
304 | mutex_unlock(&md->mutex); | ||
305 | |||
306 | return count; | ||
307 | } | ||
308 | |||
273 | static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf) | 309 | static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf) |
274 | { | 310 | { |
275 | struct w1_master *md = dev_to_w1_master(dev); | 311 | struct w1_master *md = dev_to_w1_master(dev); |
@@ -365,6 +401,7 @@ static W1_MASTER_ATTR_RO(attempts, S_IRUGO); | |||
365 | static W1_MASTER_ATTR_RO(timeout, S_IRUGO); | 401 | static W1_MASTER_ATTR_RO(timeout, S_IRUGO); |
366 | static W1_MASTER_ATTR_RO(pointer, S_IRUGO); | 402 | static W1_MASTER_ATTR_RO(pointer, S_IRUGO); |
367 | static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO); | 403 | static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO); |
404 | static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUGO); | ||
368 | 405 | ||
369 | static struct attribute *w1_master_default_attrs[] = { | 406 | static struct attribute *w1_master_default_attrs[] = { |
370 | &w1_master_attribute_name.attr, | 407 | &w1_master_attribute_name.attr, |
@@ -375,6 +412,7 @@ static struct attribute *w1_master_default_attrs[] = { | |||
375 | &w1_master_attribute_timeout.attr, | 412 | &w1_master_attribute_timeout.attr, |
376 | &w1_master_attribute_pointer.attr, | 413 | &w1_master_attribute_pointer.attr, |
377 | &w1_master_attribute_search.attr, | 414 | &w1_master_attribute_search.attr, |
415 | &w1_master_attribute_pullup.attr, | ||
378 | NULL | 416 | NULL |
379 | }; | 417 | }; |
380 | 418 | ||
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 34ee01e008ad..00b84ab22808 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -142,6 +142,12 @@ struct w1_bus_master | |||
142 | */ | 142 | */ |
143 | u8 (*reset_bus)(void *); | 143 | u8 (*reset_bus)(void *); |
144 | 144 | ||
145 | /** | ||
146 | * Put out a strong pull-up pulse of the specified duration. | ||
147 | * @return -1=Error, 0=completed | ||
148 | */ | ||
149 | u8 (*set_pullup)(void *, int); | ||
150 | |||
145 | /** Really nice hardware can handles the different types of ROM search | 151 | /** Really nice hardware can handles the different types of ROM search |
146 | * w1_master* is passed to the slave found callback. | 152 | * w1_master* is passed to the slave found callback. |
147 | */ | 153 | */ |
@@ -167,6 +173,11 @@ struct w1_master | |||
167 | void *priv; | 173 | void *priv; |
168 | int priv_size; | 174 | int priv_size; |
169 | 175 | ||
176 | /** 5V strong pullup enabled flag, 1 enabled, zero disabled. */ | ||
177 | int enable_pullup; | ||
178 | /** 5V strong pullup duration in milliseconds, zero disabled. */ | ||
179 | int pullup_duration; | ||
180 | |||
170 | struct task_struct *thread; | 181 | struct task_struct *thread; |
171 | struct mutex mutex; | 182 | struct mutex mutex; |
172 | 183 | ||
@@ -201,6 +212,7 @@ u8 w1_calc_crc8(u8 *, int); | |||
201 | void w1_write_block(struct w1_master *, const u8 *, int); | 212 | void w1_write_block(struct w1_master *, const u8 *, int); |
202 | u8 w1_read_block(struct w1_master *, u8 *, int); | 213 | u8 w1_read_block(struct w1_master *, u8 *, int); |
203 | int w1_reset_select_slave(struct w1_slave *sl); | 214 | int w1_reset_select_slave(struct w1_slave *sl); |
215 | void w1_next_pullup(struct w1_master *, int); | ||
204 | 216 | ||
205 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) | 217 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) |
206 | { | 218 | { |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index bd877b24ce42..9d723efdf915 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -31,6 +31,9 @@ | |||
31 | 31 | ||
32 | static u32 w1_ids = 1; | 32 | static u32 w1_ids = 1; |
33 | 33 | ||
34 | static int w1_enable_pullup = 1; | ||
35 | module_param_named(enable_pullup, w1_enable_pullup, int, 0); | ||
36 | |||
34 | static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | 37 | static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, |
35 | struct device_driver *driver, | 38 | struct device_driver *driver, |
36 | struct device *device) | 39 | struct device *device) |
@@ -59,6 +62,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
59 | dev->initialized = 0; | 62 | dev->initialized = 0; |
60 | dev->id = id; | 63 | dev->id = id; |
61 | dev->slave_ttl = slave_ttl; | 64 | dev->slave_ttl = slave_ttl; |
65 | dev->enable_pullup = w1_enable_pullup; | ||
62 | dev->search_count = -1; /* continual scan */ | 66 | dev->search_count = -1; /* continual scan */ |
63 | 67 | ||
64 | /* 1 for w1_process to decrement | 68 | /* 1 for w1_process to decrement |
@@ -107,6 +111,18 @@ int w1_add_master_device(struct w1_bus_master *master) | |||
107 | printk(KERN_ERR "w1_add_master_device: invalid function set\n"); | 111 | printk(KERN_ERR "w1_add_master_device: invalid function set\n"); |
108 | return(-EINVAL); | 112 | return(-EINVAL); |
109 | } | 113 | } |
114 | /* While it would be electrically possible to make a device that | ||
115 | * generated a strong pullup in bit bang mode, only hardare that | ||
116 | * controls 1-wire time frames are even expected to support a strong | ||
117 | * pullup. w1_io.c would need to support calling set_pullup before | ||
118 | * the last write_bit operation of a w1_write_8 which it currently | ||
119 | * doesn't. | ||
120 | */ | ||
121 | if (!master->write_byte && !master->touch_bit && master->set_pullup) { | ||
122 | printk(KERN_ERR "w1_add_master_device: set_pullup requires " | ||
123 | "write_byte or touch_bit, disabling\n"); | ||
124 | master->set_pullup = NULL; | ||
125 | } | ||
110 | 126 | ||
111 | dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_master_driver, &w1_master_device); | 127 | dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_master_driver, &w1_master_device); |
112 | if (!dev) | 128 | if (!dev) |
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 0056ef69009b..97b338a16abc 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
@@ -93,6 +93,40 @@ static void w1_write_bit(struct w1_master *dev, int bit) | |||
93 | } | 93 | } |
94 | 94 | ||
95 | /** | 95 | /** |
96 | * Pre-write operation, currently only supporting strong pullups. | ||
97 | * Program the hardware for a strong pullup, if one has been requested and | ||
98 | * the hardware supports it. | ||
99 | * | ||
100 | * @param dev the master device | ||
101 | */ | ||
102 | static void w1_pre_write(struct w1_master *dev) | ||
103 | { | ||
104 | if (dev->pullup_duration && | ||
105 | dev->enable_pullup && dev->bus_master->set_pullup) { | ||
106 | dev->bus_master->set_pullup(dev->bus_master->data, | ||
107 | dev->pullup_duration); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Post-write operation, currently only supporting strong pullups. | ||
113 | * If a strong pullup was requested, clear it if the hardware supports | ||
114 | * them, or execute the delay otherwise, in either case clear the request. | ||
115 | * | ||
116 | * @param dev the master device | ||
117 | */ | ||
118 | static void w1_post_write(struct w1_master *dev) | ||
119 | { | ||
120 | if (dev->pullup_duration) { | ||
121 | if (dev->enable_pullup && dev->bus_master->set_pullup) | ||
122 | dev->bus_master->set_pullup(dev->bus_master->data, 0); | ||
123 | else | ||
124 | msleep(dev->pullup_duration); | ||
125 | dev->pullup_duration = 0; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /** | ||
96 | * Writes 8 bits. | 130 | * Writes 8 bits. |
97 | * | 131 | * |
98 | * @param dev the master device | 132 | * @param dev the master device |
@@ -102,11 +136,17 @@ void w1_write_8(struct w1_master *dev, u8 byte) | |||
102 | { | 136 | { |
103 | int i; | 137 | int i; |
104 | 138 | ||
105 | if (dev->bus_master->write_byte) | 139 | if (dev->bus_master->write_byte) { |
140 | w1_pre_write(dev); | ||
106 | dev->bus_master->write_byte(dev->bus_master->data, byte); | 141 | dev->bus_master->write_byte(dev->bus_master->data, byte); |
142 | } | ||
107 | else | 143 | else |
108 | for (i = 0; i < 8; ++i) | 144 | for (i = 0; i < 8; ++i) { |
145 | if (i == 7) | ||
146 | w1_pre_write(dev); | ||
109 | w1_touch_bit(dev, (byte >> i) & 0x1); | 147 | w1_touch_bit(dev, (byte >> i) & 0x1); |
148 | } | ||
149 | w1_post_write(dev); | ||
110 | } | 150 | } |
111 | EXPORT_SYMBOL_GPL(w1_write_8); | 151 | EXPORT_SYMBOL_GPL(w1_write_8); |
112 | 152 | ||
@@ -203,11 +243,14 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len) | |||
203 | { | 243 | { |
204 | int i; | 244 | int i; |
205 | 245 | ||
206 | if (dev->bus_master->write_block) | 246 | if (dev->bus_master->write_block) { |
247 | w1_pre_write(dev); | ||
207 | dev->bus_master->write_block(dev->bus_master->data, buf, len); | 248 | dev->bus_master->write_block(dev->bus_master->data, buf, len); |
249 | } | ||
208 | else | 250 | else |
209 | for (i = 0; i < len; ++i) | 251 | for (i = 0; i < len; ++i) |
210 | w1_write_8(dev, buf[i]); | 252 | w1_write_8(dev, buf[i]); /* calls w1_pre_write */ |
253 | w1_post_write(dev); | ||
211 | } | 254 | } |
212 | EXPORT_SYMBOL_GPL(w1_write_block); | 255 | EXPORT_SYMBOL_GPL(w1_write_block); |
213 | 256 | ||
@@ -306,3 +349,20 @@ int w1_reset_select_slave(struct w1_slave *sl) | |||
306 | return 0; | 349 | return 0; |
307 | } | 350 | } |
308 | EXPORT_SYMBOL_GPL(w1_reset_select_slave); | 351 | EXPORT_SYMBOL_GPL(w1_reset_select_slave); |
352 | |||
353 | /** | ||
354 | * Put out a strong pull-up of the specified duration after the next write | ||
355 | * operation. Not all hardware supports strong pullups. Hardware that | ||
356 | * doesn't support strong pullups will sleep for the given time after the | ||
357 | * write operation without a strong pullup. This is a one shot request for | ||
358 | * the next write, specifying zero will clear a previous request. | ||
359 | * The w1 master lock must be held. | ||
360 | * | ||
361 | * @param delay time in milliseconds | ||
362 | * @return 0=success, anything else=error | ||
363 | */ | ||
364 | void w1_next_pullup(struct w1_master *dev, int delay) | ||
365 | { | ||
366 | dev->pullup_duration = delay; | ||
367 | } | ||
368 | EXPORT_SYMBOL_GPL(w1_next_pullup); | ||