Skip to content

Commit

Permalink
Add bitbanging pullups, use them for w1-gpio
Browse files Browse the repository at this point in the history
Allows parasite power to work, uses module option pullup=1
  • Loading branch information
mkj committed Mar 8, 2013
1 parent a9b0e8b commit c16b5f8
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 14 deletions.
20 changes: 20 additions & 0 deletions drivers/w1/masters/w1-gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions drivers/w1/w1.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
25 changes: 14 additions & 11 deletions drivers/w1/w1_int.c
Original file line number Diff line number Diff line change
Expand Up @@ -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). */
Expand Down
14 changes: 11 additions & 3 deletions drivers/w1/w1_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down

0 comments on commit c16b5f8

Please sign in to comment.