From d3f94435245f6d1bcfdf0cb9cbf796dc5218802f Mon Sep 17 00:00:00 2001 From: blm Date: Tue, 16 Feb 2016 10:50:51 +0100 Subject: [PATCH] merge bassed on https://github.com/raspberrypi/linux/pull/186 to enable pullup=1 option --- linux-3.4/drivers/w1/masters/w1-gpio.c | 20 ++++++++++++++ linux-3.4/drivers/w1/w1.h | 7 +++++ linux-3.4/drivers/w1/w1_int.c | 8 ++++++ linux-3.4/drivers/w1/w1_io.c | 36 +++++++++++++++++++++----- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/linux-3.4/drivers/w1/masters/w1-gpio.c b/linux-3.4/drivers/w1/masters/w1-gpio.c index ca31e5b0..694728a8 100644 --- a/linux-3.4/drivers/w1/masters/w1-gpio.c +++ b/linux-3.4/drivers/w1/masters/w1-gpio.c @@ -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; @@ -47,6 +50,16 @@ static u8 w1_gpio_read_bit(void *data) return pin_val; } +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; @@ -83,6 +96,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; diff --git a/linux-3.4/drivers/w1/w1.h b/linux-3.4/drivers/w1/w1.h index 4d012ca3..463d019d 100644 --- a/linux-3.4/drivers/w1/w1.h +++ b/linux-3.4/drivers/w1/w1.h @@ -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. */ @@ -180,6 +186,7 @@ struct w1_master struct task_struct *thread; struct mutex mutex; + struct mutex bus_mutex; struct device_driver *driver; struct device dev; diff --git a/linux-3.4/drivers/w1/w1_int.c b/linux-3.4/drivers/w1/w1_int.c index 68288355..34e97bc6 100644 --- a/linux-3.4/drivers/w1/w1_int.c +++ b/linux-3.4/drivers/w1/w1_int.c @@ -76,6 +76,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, INIT_LIST_HEAD(&dev->slist); mutex_init(&dev->mutex); + mutex_init(&dev->bus_mutex); memcpy(&dev->dev, device, sizeof(struct device)); dev_set_name(&dev->dev, "w1_bus_master%u", dev->id); @@ -129,6 +130,13 @@ int w1_add_master_device(struct w1_bus_master *master) 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). */ diff --git a/linux-3.4/drivers/w1/w1_io.c b/linux-3.4/drivers/w1/w1_io.c index 3135b2c6..e546fdcb 100644 --- a/linux-3.4/drivers/w1/w1_io.c +++ b/linux-3.4/drivers/w1/w1_io.c @@ -31,6 +31,9 @@ static int w1_delay_parm = 1; module_param_named(delay_coef, w1_delay_parm, int, 0); +static int w1_disable_irqs = 0; +module_param_named(disable_irqs, w1_disable_irqs, int, 0); + static u8 w1_crc8_table[] = { 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, @@ -79,6 +82,10 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit) */ static void w1_write_bit(struct w1_master *dev, int bit) { + unsigned long flags = 0; + + if(w1_disable_irqs) local_irq_save(flags); + if (bit) { dev->bus_master->write_bit(dev->bus_master->data, 0); w1_delay(6); @@ -90,6 +97,8 @@ static void w1_write_bit(struct w1_master *dev, int bit) dev->bus_master->write_bit(dev->bus_master->data, 1); w1_delay(10); } + + if(w1_disable_irqs) local_irq_restore(flags); } /** @@ -118,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; } } @@ -158,7 +175,7 @@ EXPORT_SYMBOL_GPL(w1_write_8); static u8 w1_read_bit(struct w1_master *dev) { int result; - unsigned long flags; + unsigned long flags = 0; /* sample timing is critical here */ local_irq_save(flags); @@ -318,6 +335,9 @@ EXPORT_SYMBOL_GPL(w1_read_block); int w1_reset_bus(struct w1_master *dev) { int result; + unsigned long flags = 0; + + if(w1_disable_irqs) local_irq_save(flags); if (dev->bus_master->reset_bus) result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1; @@ -330,19 +350,21 @@ int w1_reset_bus(struct w1_master *dev) * cpu for such a short amount of time AND get it back in * the maximum amount of time. */ - w1_delay(480); + w1_delay(500); dev->bus_master->write_bit(dev->bus_master->data, 1); w1_delay(70); result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1; - /* minmum 70 (above) + 410 = 480 us + /* minmum 70 (above) + 430 = 500 us * There aren't any timing requirements between a reset and * the following transactions. Sleeping is safe here. */ - /* w1_delay(410); min required time */ + /* w1_delay(430); min required time */ msleep(1); } + if(w1_disable_irqs) local_irq_restore(flags); + return result; } EXPORT_SYMBOL_GPL(w1_reset_bus);