]> git.hungrycats.org Git - linux/commitdiff
Add bitbanging pullups, use them for w1-gpio
authorMatt Johnston <matt@ucc.asn.au>
Fri, 7 Dec 2012 15:21:31 +0000 (23:21 +0800)
committerMatt Johnston <matt@ucc.asn.au>
Fri, 8 Mar 2013 15:24:00 +0000 (23:24 +0800)
Allows parasite power to work, uses module option pullup=1

drivers/w1/masters/w1-gpio.c
drivers/w1/w1.h
drivers/w1/w1_int.c
drivers/w1/w1_io.c

index df600d14974d6ddcbe2ec00bdbb6b199b779537c..cc761f2a63ae21a18e5854afdbccfe11ec9acd73 100644 (file)
@@ -18,6 +18,9 @@
 #include "../w1.h"
 #include "../w1_int.h"
 
+static int w1_gpio_pullup = 0;
+module_param_named(pullup, w1_gpio_pullup, int, 0);
+
 static void w1_gpio_write_bit_dir(void *data, u8 bit)
 {
        struct w1_gpio_platform_data *pdata = data;
@@ -42,6 +45,16 @@ static u8 w1_gpio_read_bit(void *data)
        return gpio_get_value(pdata->pin) ? 1 : 0;
 }
 
+static void w1_gpio_bitbang_pullup(void *data, u8 on)
+{
+       struct w1_gpio_platform_data *pdata = data;
+
+       if (on)
+               gpio_direction_output(pdata->pin, 1);
+       else
+               gpio_direction_input(pdata->pin);
+}
+
 static int __init w1_gpio_probe(struct platform_device *pdev)
 {
        struct w1_bus_master *master;
@@ -70,6 +83,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
                master->write_bit = w1_gpio_write_bit_dir;
        }
 
+       if (w1_gpio_pullup)
+               if (pdata->is_open_drain)
+                       printk(KERN_ERR "w1-gpio 'pullup' option "
+                               "doesn't work with open drain GPIO\n");
+               else
+                       master->bitbang_pullup = w1_gpio_bitbang_pullup;
+
        err = w1_add_master_device(master);
        if (err)
                goto free_gpio;
index 45908e56c2f834180ca0b166e44bd9fca50a5e2d..463d019d8ddcc22c4da73dfed3034a0f00f4c887 100644 (file)
@@ -148,6 +148,12 @@ struct w1_bus_master
         */
        u8              (*set_pullup)(void *, int);
 
+       /**
+        * Turns the pullup on/off in bitbanging mode, takes an on/off argument.
+        * @return -1=Error, 0=completed
+        */
+       void    (*bitbang_pullup)(void *, u8);
+
        /** Really nice hardware can handles the different types of ROM search
         *  w1_master* is passed to the slave found callback.
         */
index 5a98649f6abc27d563bf8ac957ddc0523a21f8e0..eb906e850d999f61488a80a0efe5db1da4485358 100644 (file)
@@ -110,26 +110,29 @@ int w1_add_master_device(struct w1_bus_master *master)
        struct w1_netlink_msg msg;
        int id, found;
 
-        /* validate minimum functionality */
-        if (!(master->touch_bit && master->reset_bus) &&
-            !(master->write_bit && master->read_bit) &&
+       /* validate minimum functionality */
+       if (!(master->touch_bit && master->reset_bus) &&
+           !(master->write_bit && master->read_bit) &&
            !(master->write_byte && master->read_byte && master->reset_bus)) {
                printk(KERN_ERR "w1_add_master_device: invalid function set\n");
                return(-EINVAL);
-        }
-       /* While it would be electrically possible to make a device that
-        * generated a strong pullup in bit bang mode, only hardware that
-        * controls 1-wire time frames are even expected to support a strong
-        * pullup.  w1_io.c would need to support calling set_pullup before
-        * the last write_bit operation of a w1_write_8 which it currently
-        * doesn't.
-        */
+       }
+
+       /* bitbanging hardware uses bitbang_pullup, other hardware uses set_pullup
+        * and takes care of timing itself */
        if (!master->write_byte && !master->touch_bit && master->set_pullup) {
                printk(KERN_ERR "w1_add_master_device: set_pullup requires "
                        "write_byte or touch_bit, disabling\n");
                master->set_pullup = NULL;
        }
 
+       if (master->set_pullup && master->bitbang_pullup)
+       {
+               printk(KERN_ERR "w1_add_master_device: set_pullup should not "
+                       "be set when bitbang_pullup is used, disabling\n");
+               master->set_pullup = NULL;
+       }
+
        /* Lock until the device is added (or not) to w1_masters. */
        mutex_lock(&w1_mlock);
        /* Search for the first available id (starting at 1). */
index e10acc23773395699d2bc8f19b37cb32f781fcc3..e546fdcbd7f320f8c29f0d496dbce961201e4983 100644 (file)
@@ -127,10 +127,18 @@ static void w1_pre_write(struct w1_master *dev)
 static void w1_post_write(struct w1_master *dev)
 {
        if (dev->pullup_duration) {
-               if (dev->enable_pullup && dev->bus_master->set_pullup)
-                       dev->bus_master->set_pullup(dev->bus_master->data, 0);
-               else
+               if (dev->enable_pullup) {
+                       if (dev->bus_master->set_pullup) {
+                               dev->bus_master->set_pullup(dev->bus_master->data, 0);
+                       } else if (dev->bus_master->bitbang_pullup) {
+                               dev->bus_master->bitbang_pullup(dev->bus_master->data, 1);
+                               msleep(dev->pullup_duration);
+                               dev->bus_master->bitbang_pullup(dev->bus_master->data, 0);
+                       }
+        } else {
                        msleep(dev->pullup_duration);
+        }
+
                dev->pullup_duration = 0;
        }
 }