Skip to content

Commit

Permalink
enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (a…
Browse files Browse the repository at this point in the history
…s a module)

1-wire: Add support for configuring pin for w1-gpio kernel module
See: #457

Add bitbanging pullups, use them for w1-gpio

Allows parasite power to work, uses module option pullup=1
  • Loading branch information
popcornmix committed Apr 14, 2014
1 parent 4c4e165 commit 8a0ec82
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 3 deletions.
23 changes: 23 additions & 0 deletions arch/arm/mach-bcm2708/bcm2708.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/w1-gpio.h>

#include <linux/version.h>
#include <linux/clkdev.h>
Expand Down Expand Up @@ -76,12 +77,16 @@
*/
#define DMA_MASK_BITS_COMMON 32

// use GPIO 4 for the one-wire GPIO pin, if enabled
#define W1_GPIO 4

/* command line parameters */
static unsigned boardrev, serial;
static unsigned uart_clock;
static unsigned disk_led_gpio = 16;
static unsigned disk_led_active_low = 1;
static unsigned reboot_part = 0;
static unsigned w1_gpio_pin = W1_GPIO;

static void __init bcm2708_init_led(void);

Expand Down Expand Up @@ -258,6 +263,19 @@ static struct platform_device bcm2708_dmaman_device = {
.num_resources = ARRAY_SIZE(bcm2708_dmaman_resources),
};

#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
static struct w1_gpio_platform_data w1_gpio_pdata = {
.pin = W1_GPIO,
.is_open_drain = 0,
};

static struct platform_device w1_device = {
.name = "w1-gpio",
.id = -1,
.dev.platform_data = &w1_gpio_pdata,
};
#endif

static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);

static struct platform_device bcm2708_fb_device = {
Expand Down Expand Up @@ -679,6 +697,10 @@ void __init bcm2708_init(void)
bcm_register_device(&bcm2708_vcio_device);
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device(&bcm2708_gpio_device);
#endif
#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
w1_gpio_pdata.pin = w1_gpio_pin;
platform_device_register(&w1_device);
#endif
bcm_register_device(&bcm2708_systemtimer_device);
bcm_register_device(&bcm2708_fb_device);
Expand Down Expand Up @@ -880,3 +902,4 @@ module_param(uart_clock, uint, 0644);
module_param(disk_led_gpio, uint, 0644);
module_param(disk_led_active_low, uint, 0644);
module_param(reboot_part, uint, 0644);
module_param(w1_gpio_pin, uint, 0644);
20 changes: 20 additions & 0 deletions drivers/w1/masters/w1-gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include "../w1.h"
#include "../w1_int.h"

static int w1_gpio_pullup = 0;
module_param_named(pullup, w1_gpio_pullup, int, 0);

static u8 w1_gpio_set_pullup(void *data, int delay)
{
struct w1_gpio_platform_data *pdata = data;
Expand Down Expand Up @@ -67,6 +70,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);
}

#if defined(CONFIG_OF)
static struct of_device_id w1_gpio_dt_ids[] = {
{ .compatible = "w1-gpio" },
Expand Down Expand Up @@ -156,6 +169,13 @@ static int w1_gpio_probe(struct platform_device *pdev)
master->set_pullup = w1_gpio_set_pullup;
}

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) {
dev_err(&pdev->dev, "w1_add_master device failed\n");
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
14 changes: 14 additions & 0 deletions drivers/w1/w1_int.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,20 @@ int w1_add_master_device(struct w1_bus_master *master)
return(-EINVAL);
}

/* 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
18 changes: 15 additions & 3 deletions drivers/w1/w1_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,22 @@ 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 8a0ec82

Please sign in to comment.