v4.19.13 snapshot.
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
new file mode 100644
index 0000000..6743bde
--- /dev/null
+++ b/drivers/w1/Kconfig
@@ -0,0 +1,31 @@
+menuconfig W1
+	tristate "Dallas's 1-wire support"
+	depends on HAS_IOMEM
+	---help---
+	  Dallas' 1-wire bus is useful to connect slow 1-pin devices
+	  such as iButtons and thermal sensors.
+
+	  If you want W1 support, you should say Y here.
+
+	  This W1 support can also be built as a module.  If so, the module
+	  will be called wire.
+
+if W1
+
+config W1_CON
+	depends on CONNECTOR
+	bool "Userspace communication over connector"
+	default y
+	---help---
+	  This allows to communicate with userspace using connector. For more
+	  information see <file:Documentation/connector/connector.txt>.
+	  There are three types of messages between w1 core and userspace:
+	  1. Events. They are generated each time new master or slave device found
+		either due to automatic or requested search.
+	  2. Userspace commands. Includes read/write and search/alarm search commands.
+	  3. Replies to userspace commands.
+
+source drivers/w1/masters/Kconfig
+source drivers/w1/slaves/Kconfig
+
+endif # W1
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile
new file mode 100644
index 0000000..6bb0b54
--- /dev/null
+++ b/drivers/w1/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the Dallas's 1-wire bus.
+#
+
+obj-$(CONFIG_W1)	+= wire.o
+wire-objs		:= w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
+
+obj-y			+= masters/ slaves/
+
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
new file mode 100644
index 0000000..00827d2
--- /dev/null
+++ b/drivers/w1/masters/Kconfig
@@ -0,0 +1,68 @@
+#
+# 1-wire bus master configuration
+#
+
+menu "1-wire Bus Masters"
+
+config W1_MASTER_MATROX
+	tristate "Matrox G400 transport layer for 1-wire"
+	depends on PCI
+	help
+	  Say Y here if you want to communicate with your 1-wire devices
+	  using Matrox's G400 GPIO pins.
+
+	  This support is also available as a module.  If so, the module
+	  will be called matrox_w1.
+
+config W1_MASTER_DS2490
+	tristate "DS2490 USB <-> W1 transport layer for 1-wire"
+  	depends on USB
+  	help
+	  Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges,
+	  for example DS9490*.
+
+  	  This support is also available as a module.  If so, the module
+	  will be called ds2490.
+
+config W1_MASTER_DS2482
+	tristate "Maxim DS2482 I2C to 1-Wire bridge"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Maxim DS2482
+	  I2C to 1-Wire bridge.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ds2482.
+
+config W1_MASTER_MXC
+	tristate "Freescale MXC 1-wire busmaster"
+	depends on ARCH_MXC || COMPILE_TEST
+	help
+	  Say Y here to enable MXC 1-wire host
+
+config W1_MASTER_DS1WM
+	tristate "Maxim DS1WM 1-wire busmaster"
+	help
+	  Say Y here to enable the DS1WM 1-wire driver, such as that
+	  in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
+	  hx4700.
+
+config W1_MASTER_GPIO
+	tristate "GPIO 1-wire busmaster"
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  Say Y here if you want to communicate with your 1-wire devices using
+	  GPIO pins. This driver uses the GPIO API to control the wire.
+
+	  This support is also available as a module.  If so, the module
+	  will be called w1-gpio.
+
+config HDQ_MASTER_OMAP
+	tristate "OMAP HDQ driver"
+	depends on ARCH_OMAP
+	help
+	  Say Y here if you want support for the 1-wire or HDQ Interface
+	  on an OMAP processor.
+
+endmenu
+
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
new file mode 100644
index 0000000..18954ca
--- /dev/null
+++ b/drivers/w1/masters/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for 1-wire bus master drivers.
+#
+
+obj-$(CONFIG_W1_MASTER_MATROX)		+= matrox_w1.o
+obj-$(CONFIG_W1_MASTER_DS2490)		+= ds2490.o
+obj-$(CONFIG_W1_MASTER_DS2482)		+= ds2482.o
+obj-$(CONFIG_W1_MASTER_MXC)		+= mxc_w1.o
+
+obj-$(CONFIG_W1_MASTER_DS1WM)		+= ds1wm.o
+obj-$(CONFIG_W1_MASTER_GPIO)		+= w1-gpio.o
+obj-$(CONFIG_HDQ_MASTER_OMAP)		+= omap_hdq.o
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
new file mode 100644
index 0000000..f661695
--- /dev/null
+++ b/drivers/w1/masters/ds1wm.c
@@ -0,0 +1,675 @@
+/*
+ * 1-wire busmaster driver for DS1WM and ASICs with embedded DS1WMs
+ * such as HP iPAQs (including h5xxx, h2200, and devices with ASIC3
+ * like hx4700).
+ *
+ * Copyright (c) 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
+ * Copyright (c) 2004-2007, Matt Reimer <mreimer@vpop.net>
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ds1wm.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+
+#include <linux/w1.h>
+
+
+#define DS1WM_CMD	0x00	/* R/W 4 bits command */
+#define DS1WM_DATA	0x01	/* R/W 8 bits, transmit/receive buffer */
+#define DS1WM_INT	0x02	/* R/W interrupt status */
+#define DS1WM_INT_EN	0x03	/* R/W interrupt enable */
+#define DS1WM_CLKDIV	0x04	/* R/W 5 bits of divisor and pre-scale */
+#define DS1WM_CNTRL	0x05	/* R/W master control register (not used yet) */
+
+#define DS1WM_CMD_1W_RESET  (1 << 0)	/* force reset on 1-wire bus */
+#define DS1WM_CMD_SRA	    (1 << 1)	/* enable Search ROM accelerator mode */
+#define DS1WM_CMD_DQ_OUTPUT (1 << 2)	/* write only - forces bus low */
+#define DS1WM_CMD_DQ_INPUT  (1 << 3)	/* read only - reflects state of bus */
+#define DS1WM_CMD_RST	    (1 << 5)	/* software reset */
+#define DS1WM_CMD_OD	    (1 << 7)	/* overdrive */
+
+#define DS1WM_INT_PD	    (1 << 0)	/* presence detect */
+#define DS1WM_INT_PDR	    (1 << 1)	/* presence detect result */
+#define DS1WM_INT_TBE	    (1 << 2)	/* tx buffer empty */
+#define DS1WM_INT_TSRE	    (1 << 3)	/* tx shift register empty */
+#define DS1WM_INT_RBF	    (1 << 4)	/* rx buffer full */
+#define DS1WM_INT_RSRF	    (1 << 5)	/* rx shift register full */
+
+#define DS1WM_INTEN_EPD	    (1 << 0)	/* enable presence detect int */
+#define DS1WM_INTEN_IAS	    (1 << 1)	/* INTR active state */
+#define DS1WM_INTEN_ETBE    (1 << 2)	/* enable tx buffer empty int */
+#define DS1WM_INTEN_ETMT    (1 << 3)	/* enable tx shift register empty int */
+#define DS1WM_INTEN_ERBF    (1 << 4)	/* enable rx buffer full int */
+#define DS1WM_INTEN_ERSRF   (1 << 5)	/* enable rx shift register full int */
+#define DS1WM_INTEN_DQO	    (1 << 6)	/* enable direct bus driving ops */
+
+#define DS1WM_INTEN_NOT_IAS (~DS1WM_INTEN_IAS)	/* all but INTR active state */
+
+#define DS1WM_TIMEOUT (HZ * 5)
+
+static struct {
+	unsigned long freq;
+	unsigned long divisor;
+} freq[] = {
+	{   1000000, 0x80 },
+	{   2000000, 0x84 },
+	{   3000000, 0x81 },
+	{   4000000, 0x88 },
+	{   5000000, 0x82 },
+	{   6000000, 0x85 },
+	{   7000000, 0x83 },
+	{   8000000, 0x8c },
+	{  10000000, 0x86 },
+	{  12000000, 0x89 },
+	{  14000000, 0x87 },
+	{  16000000, 0x90 },
+	{  20000000, 0x8a },
+	{  24000000, 0x8d },
+	{  28000000, 0x8b },
+	{  32000000, 0x94 },
+	{  40000000, 0x8e },
+	{  48000000, 0x91 },
+	{  56000000, 0x8f },
+	{  64000000, 0x98 },
+	{  80000000, 0x92 },
+	{  96000000, 0x95 },
+	{ 112000000, 0x93 },
+	{ 128000000, 0x9c },
+/* you can continue this table, consult the OPERATION - CLOCK DIVISOR
+   section of the ds1wm spec sheet. */
+};
+
+struct ds1wm_data {
+	void     __iomem *map;
+	unsigned int      bus_shift; /* # of shifts to calc register offsets */
+	bool      is_hw_big_endian;
+	struct platform_device *pdev;
+	const struct mfd_cell   *cell;
+	int      irq;
+	int      slave_present;
+	void     *reset_complete;
+	void     *read_complete;
+	void     *write_complete;
+	int      read_error;
+	/* last byte received */
+	u8       read_byte;
+	/* byte to write that makes all intr disabled, */
+	/* considering active_state (IAS) (optimization) */
+	u8       int_en_reg_none;
+	unsigned int reset_recover_delay; /* see ds1wm.h */
+};
+
+static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg,
+					u8 val)
+{
+	if (ds1wm_data->is_hw_big_endian) {
+		switch (ds1wm_data->bus_shift) {
+		case 0:
+			iowrite8(val, ds1wm_data->map + (reg << 0));
+			break;
+		case 1:
+			iowrite16be((u16)val, ds1wm_data->map + (reg << 1));
+			break;
+		case 2:
+			iowrite32be((u32)val, ds1wm_data->map + (reg << 2));
+			break;
+		}
+	} else {
+		switch (ds1wm_data->bus_shift) {
+		case 0:
+			iowrite8(val, ds1wm_data->map + (reg << 0));
+			break;
+		case 1:
+			iowrite16((u16)val, ds1wm_data->map + (reg << 1));
+			break;
+		case 2:
+			iowrite32((u32)val, ds1wm_data->map + (reg << 2));
+			break;
+		}
+	}
+}
+
+static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg)
+{
+	u32 val = 0;
+
+	if (ds1wm_data->is_hw_big_endian) {
+		switch (ds1wm_data->bus_shift) {
+		case 0:
+			val = ioread8(ds1wm_data->map + (reg << 0));
+			break;
+		case 1:
+			val = ioread16be(ds1wm_data->map + (reg << 1));
+			break;
+		case 2:
+			val = ioread32be(ds1wm_data->map + (reg << 2));
+			break;
+		}
+	} else {
+		switch (ds1wm_data->bus_shift) {
+		case 0:
+			val = ioread8(ds1wm_data->map + (reg << 0));
+			break;
+		case 1:
+			val = ioread16(ds1wm_data->map + (reg << 1));
+			break;
+		case 2:
+			val = ioread32(ds1wm_data->map + (reg << 2));
+			break;
+		}
+	}
+	dev_dbg(&ds1wm_data->pdev->dev,
+		"ds1wm_read_register reg: %d, 32 bit val:%x\n", reg, val);
+	return (u8)val;
+}
+
+
+static irqreturn_t ds1wm_isr(int isr, void *data)
+{
+	struct ds1wm_data *ds1wm_data = data;
+	u8 intr;
+	u8 inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN);
+	/* if no bits are set in int enable register (except the IAS)
+	than go no further, reading the regs below has side effects */
+	if (!(inten & DS1WM_INTEN_NOT_IAS))
+		return IRQ_NONE;
+
+	ds1wm_write_register(ds1wm_data,
+		DS1WM_INT_EN, ds1wm_data->int_en_reg_none);
+
+	/* this read action clears the INTR and certain flags in ds1wm */
+	intr = ds1wm_read_register(ds1wm_data, DS1WM_INT);
+
+	ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1;
+
+	if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete) {
+		inten &= ~DS1WM_INTEN_ETMT;
+		complete(ds1wm_data->write_complete);
+	}
+	if (intr & DS1WM_INT_RBF) {
+		/* this read clears the RBF flag */
+		ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data,
+		DS1WM_DATA);
+		inten &= ~DS1WM_INTEN_ERBF;
+		if (ds1wm_data->read_complete)
+			complete(ds1wm_data->read_complete);
+	}
+	if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete) {
+		inten &= ~DS1WM_INTEN_EPD;
+		complete(ds1wm_data->reset_complete);
+	}
+
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, inten);
+	return IRQ_HANDLED;
+}
+
+static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
+{
+	unsigned long timeleft;
+	DECLARE_COMPLETION_ONSTACK(reset_done);
+
+	ds1wm_data->reset_complete = &reset_done;
+
+	/* enable Presence detect only */
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD |
+	ds1wm_data->int_en_reg_none);
+
+	ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET);
+
+	timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT);
+	ds1wm_data->reset_complete = NULL;
+	if (!timeleft) {
+		dev_err(&ds1wm_data->pdev->dev, "reset failed, timed out\n");
+		return 1;
+	}
+
+	if (!ds1wm_data->slave_present) {
+		dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n");
+		return 1;
+	}
+
+	if (ds1wm_data->reset_recover_delay)
+		msleep(ds1wm_data->reset_recover_delay);
+
+	return 0;
+}
+
+static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data)
+{
+	unsigned long timeleft;
+	DECLARE_COMPLETION_ONSTACK(write_done);
+	ds1wm_data->write_complete = &write_done;
+
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+	ds1wm_data->int_en_reg_none | DS1WM_INTEN_ETMT);
+
+	ds1wm_write_register(ds1wm_data, DS1WM_DATA, data);
+
+	timeleft = wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT);
+
+	ds1wm_data->write_complete = NULL;
+	if (!timeleft) {
+		dev_err(&ds1wm_data->pdev->dev, "write failed, timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static u8 ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
+{
+	unsigned long timeleft;
+	u8 intEnable = DS1WM_INTEN_ERBF | ds1wm_data->int_en_reg_none;
+	DECLARE_COMPLETION_ONSTACK(read_done);
+
+	ds1wm_read_register(ds1wm_data, DS1WM_DATA);
+
+	ds1wm_data->read_complete = &read_done;
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, intEnable);
+
+	ds1wm_write_register(ds1wm_data, DS1WM_DATA, write_data);
+	timeleft = wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT);
+
+	ds1wm_data->read_complete = NULL;
+	if (!timeleft) {
+		dev_err(&ds1wm_data->pdev->dev, "read failed, timed out\n");
+		ds1wm_data->read_error = -ETIMEDOUT;
+		return 0xFF;
+	}
+	ds1wm_data->read_error = 0;
+	return ds1wm_data->read_byte;
+}
+
+static int ds1wm_find_divisor(int gclk)
+{
+	int i;
+
+	for (i = ARRAY_SIZE(freq)-1; i >= 0; --i)
+		if (gclk >= freq[i].freq)
+			return freq[i].divisor;
+
+	return 0;
+}
+
+static void ds1wm_up(struct ds1wm_data *ds1wm_data)
+{
+	int divisor;
+	struct device *dev = &ds1wm_data->pdev->dev;
+	struct ds1wm_driver_data *plat = dev_get_platdata(dev);
+
+	if (ds1wm_data->cell->enable)
+		ds1wm_data->cell->enable(ds1wm_data->pdev);
+
+	divisor = ds1wm_find_divisor(plat->clock_rate);
+	dev_dbg(dev, "found divisor 0x%x for clock %d\n",
+		divisor, plat->clock_rate);
+	if (divisor == 0) {
+		dev_err(dev, "no suitable divisor for %dHz clock\n",
+			plat->clock_rate);
+		return;
+	}
+	ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor);
+
+	/* Let the w1 clock stabilize. */
+	msleep(1);
+
+	ds1wm_reset(ds1wm_data);
+}
+
+static void ds1wm_down(struct ds1wm_data *ds1wm_data)
+{
+	ds1wm_reset(ds1wm_data);
+
+	/* Disable interrupts. */
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+		ds1wm_data->int_en_reg_none);
+
+	if (ds1wm_data->cell->disable)
+		ds1wm_data->cell->disable(ds1wm_data->pdev);
+}
+
+/* --------------------------------------------------------------------- */
+/* w1 methods */
+
+static u8 ds1wm_read_byte(void *data)
+{
+	struct ds1wm_data *ds1wm_data = data;
+
+	return ds1wm_read(ds1wm_data, 0xff);
+}
+
+static void ds1wm_write_byte(void *data, u8 byte)
+{
+	struct ds1wm_data *ds1wm_data = data;
+
+	ds1wm_write(ds1wm_data, byte);
+}
+
+static u8 ds1wm_reset_bus(void *data)
+{
+	struct ds1wm_data *ds1wm_data = data;
+
+	ds1wm_reset(ds1wm_data);
+
+	return 0;
+}
+
+static void ds1wm_search(void *data, struct w1_master *master_dev,
+			u8 search_type, w1_slave_found_callback slave_found)
+{
+	struct ds1wm_data *ds1wm_data = data;
+	int i;
+	int ms_discrep_bit = -1;
+	u64 r = 0; /* holds the progress of the search */
+	u64 r_prime, d;
+	unsigned slaves_found = 0;
+	unsigned int pass = 0;
+
+	dev_dbg(&ds1wm_data->pdev->dev, "search begin\n");
+	while (true) {
+		++pass;
+		if (pass > 100) {
+			dev_dbg(&ds1wm_data->pdev->dev,
+				"too many attempts (100), search aborted\n");
+			return;
+		}
+
+		mutex_lock(&master_dev->bus_mutex);
+		if (ds1wm_reset(ds1wm_data)) {
+			mutex_unlock(&master_dev->bus_mutex);
+			dev_dbg(&ds1wm_data->pdev->dev,
+				"pass: %d reset error (or no slaves)\n", pass);
+			break;
+		}
+
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d r : %0#18llx writing SEARCH_ROM\n", pass, r);
+		ds1wm_write(ds1wm_data, search_type);
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d entering ASM\n", pass);
+		ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d beginning nibble loop\n", pass);
+
+		r_prime = 0;
+		d = 0;
+		/* we work one nibble at a time */
+		/* each nibble is interleaved to form a byte */
+		for (i = 0; i < 16; i++) {
+
+			unsigned char resp, _r, _r_prime, _d;
+
+			_r = (r >> (4*i)) & 0xf;
+			_r = ((_r & 0x1) << 1) |
+			((_r & 0x2) << 2) |
+			((_r & 0x4) << 3) |
+			((_r & 0x8) << 4);
+
+			/* writes _r, then reads back: */
+			resp = ds1wm_read(ds1wm_data, _r);
+
+			if (ds1wm_data->read_error) {
+				dev_err(&ds1wm_data->pdev->dev,
+				"pass: %d nibble: %d read error\n", pass, i);
+				break;
+			}
+
+			_r_prime = ((resp & 0x02) >> 1) |
+			((resp & 0x08) >> 2) |
+			((resp & 0x20) >> 3) |
+			((resp & 0x80) >> 4);
+
+			_d = ((resp & 0x01) >> 0) |
+			((resp & 0x04) >> 1) |
+			((resp & 0x10) >> 2) |
+			((resp & 0x40) >> 3);
+
+			r_prime |= (unsigned long long) _r_prime << (i * 4);
+			d |= (unsigned long long) _d << (i * 4);
+
+		}
+		if (ds1wm_data->read_error) {
+			mutex_unlock(&master_dev->bus_mutex);
+			dev_err(&ds1wm_data->pdev->dev,
+				"pass: %d read error, retrying\n", pass);
+			break;
+		}
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d r\': %0#18llx d:%0#18llx\n",
+			pass, r_prime, d);
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d nibble loop complete, exiting ASM\n", pass);
+		ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d resetting bus\n", pass);
+		ds1wm_reset(ds1wm_data);
+		mutex_unlock(&master_dev->bus_mutex);
+		if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) {
+			dev_err(&ds1wm_data->pdev->dev,
+				"pass: %d bus error, retrying\n", pass);
+			continue; /* start over */
+		}
+
+
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d found %0#18llx\n", pass, r_prime);
+		slave_found(master_dev, r_prime);
+		++slaves_found;
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d complete, preparing next pass\n", pass);
+
+		/* any discrepency found which we already choose the
+		   '1' branch is now is now irrelevant we reveal the
+		   next branch with this: */
+		d &= ~r;
+		/* find last bit set, i.e. the most signif. bit set */
+		ms_discrep_bit = fls64(d) - 1;
+		dev_dbg(&ds1wm_data->pdev->dev,
+			"pass: %d new d:%0#18llx MS discrep bit:%d\n",
+			pass, d, ms_discrep_bit);
+
+		/* prev_ms_discrep_bit = ms_discrep_bit;
+		   prepare for next ROM search:		    */
+		if (ms_discrep_bit == -1)
+			break;
+
+		r = (r &  ~(~0ull << (ms_discrep_bit))) | 1 << ms_discrep_bit;
+	} /* end while true */
+	dev_dbg(&ds1wm_data->pdev->dev,
+		"pass: %d total: %d search done ms d bit pos: %d\n", pass,
+		slaves_found, ms_discrep_bit);
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct w1_bus_master ds1wm_master = {
+	.read_byte  = ds1wm_read_byte,
+	.write_byte = ds1wm_write_byte,
+	.reset_bus  = ds1wm_reset_bus,
+	.search	    = ds1wm_search,
+};
+
+static int ds1wm_probe(struct platform_device *pdev)
+{
+	struct ds1wm_data *ds1wm_data;
+	struct ds1wm_driver_data *plat;
+	struct resource *res;
+	int ret;
+	u8 inten;
+
+	if (!pdev)
+		return -ENODEV;
+
+	ds1wm_data = devm_kzalloc(&pdev->dev, sizeof(*ds1wm_data), GFP_KERNEL);
+	if (!ds1wm_data)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, ds1wm_data);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+	ds1wm_data->map = devm_ioremap(&pdev->dev, res->start,
+				       resource_size(res));
+	if (!ds1wm_data->map)
+		return -ENOMEM;
+
+	ds1wm_data->pdev = pdev;
+	ds1wm_data->cell = mfd_get_cell(pdev);
+	if (!ds1wm_data->cell)
+		return -ENODEV;
+	plat = dev_get_platdata(&pdev->dev);
+	if (!plat)
+		return -ENODEV;
+
+	/* how many bits to shift register number to get register offset */
+	if (plat->bus_shift > 2) {
+		dev_err(&ds1wm_data->pdev->dev,
+			"illegal bus shift %d, not written",
+			ds1wm_data->bus_shift);
+		return -EINVAL;
+	}
+
+	ds1wm_data->bus_shift = plat->bus_shift;
+	/* make sure resource has space for 8 registers */
+	if ((8 << ds1wm_data->bus_shift) > resource_size(res)) {
+		dev_err(&ds1wm_data->pdev->dev,
+			"memory resource size %d to small, should be %d\n",
+			(int)resource_size(res),
+			8 << ds1wm_data->bus_shift);
+		return -EINVAL;
+	}
+
+	ds1wm_data->is_hw_big_endian = plat->is_hw_big_endian;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res)
+		return -ENXIO;
+	ds1wm_data->irq = res->start;
+	ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0);
+	ds1wm_data->reset_recover_delay = plat->reset_recover_delay;
+
+	/* Mask interrupts, set IAS before claiming interrupt */
+	inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN);
+	ds1wm_write_register(ds1wm_data,
+		DS1WM_INT_EN, ds1wm_data->int_en_reg_none);
+
+	if (res->flags & IORESOURCE_IRQ_HIGHEDGE)
+		irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING);
+	if (res->flags & IORESOURCE_IRQ_LOWEDGE)
+		irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING);
+	if (res->flags & IORESOURCE_IRQ_HIGHLEVEL)
+		irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_HIGH);
+	if (res->flags & IORESOURCE_IRQ_LOWLEVEL)
+		irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_LOW);
+
+	ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr,
+			IRQF_SHARED, "ds1wm", ds1wm_data);
+	if (ret) {
+		dev_err(&ds1wm_data->pdev->dev,
+			"devm_request_irq %d failed with errno %d\n",
+			ds1wm_data->irq,
+			ret);
+
+		return ret;
+	}
+
+	ds1wm_up(ds1wm_data);
+
+	ds1wm_master.data = (void *)ds1wm_data;
+
+	ret = w1_add_master_device(&ds1wm_master);
+	if (ret)
+		goto err;
+
+	dev_dbg(&ds1wm_data->pdev->dev,
+		"ds1wm: probe successful, IAS: %d, rec.delay: %d, clockrate: %d, bus-shift: %d, is Hw Big Endian: %d\n",
+		plat->active_high,
+		plat->reset_recover_delay,
+		plat->clock_rate,
+		ds1wm_data->bus_shift,
+		ds1wm_data->is_hw_big_endian);
+	return 0;
+
+err:
+	ds1wm_down(ds1wm_data);
+
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int ds1wm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+	ds1wm_down(ds1wm_data);
+
+	return 0;
+}
+
+static int ds1wm_resume(struct platform_device *pdev)
+{
+	struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+	ds1wm_up(ds1wm_data);
+
+	return 0;
+}
+#else
+#define ds1wm_suspend NULL
+#define ds1wm_resume NULL
+#endif
+
+static int ds1wm_remove(struct platform_device *pdev)
+{
+	struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+	w1_remove_master_device(&ds1wm_master);
+	ds1wm_down(ds1wm_data);
+
+	return 0;
+}
+
+static struct platform_driver ds1wm_driver = {
+	.driver   = {
+		.name = "ds1wm",
+	},
+	.probe    = ds1wm_probe,
+	.remove   = ds1wm_remove,
+	.suspend  = ds1wm_suspend,
+	.resume   = ds1wm_resume
+};
+
+static int __init ds1wm_init(void)
+{
+	pr_info("DS1WM w1 busmaster driver - (c) 2004 Szabolcs Gyurko\n");
+	return platform_driver_register(&ds1wm_driver);
+}
+
+static void __exit ds1wm_exit(void)
+{
+	platform_driver_unregister(&ds1wm_driver);
+}
+
+module_init(ds1wm_init);
+module_exit(ds1wm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
+	"Matt Reimer <mreimer@vpop.net>,"
+	"Jean-Francois Dagenais <dagenaisj@sonatest.com>");
+MODULE_DESCRIPTION("DS1WM w1 busmaster driver");
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
new file mode 100644
index 0000000..8b5e598
--- /dev/null
+++ b/drivers/w1/masters/ds2482.c
@@ -0,0 +1,565 @@
+/**
+ * ds2482.c - provides i2c to w1-master bridge(s)
+ * Copyright (C) 2005  Ben Gardner <bgardner@wabtec.com>
+ *
+ * The DS2482 is a sensor chip made by Dallas Semiconductor (Maxim).
+ * It is a I2C to 1-wire bridge.
+ * There are two variations: -100 and -800, which have 1 or 8 1-wire ports.
+ * The complete datasheet can be obtained from MAXIM's website at:
+ *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/4382
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <asm/delay.h>
+
+#include <linux/w1.h>
+
+/**
+ * Allow the active pullup to be disabled, default is enabled.
+ *
+ * Note from the DS2482 datasheet:
+ * The APU bit controls whether an active pullup (controlled slew-rate
+ * transistor) or a passive pullup (Rwpu resistor) will be used to drive
+ * a 1-Wire line from low to high. When APU = 0, active pullup is disabled
+ * (resistor mode). Active Pullup should always be selected unless there is
+ * only a single slave on the 1-Wire line.
+ */
+static int ds2482_active_pullup = 1;
+module_param_named(active_pullup, ds2482_active_pullup, int, 0644);
+MODULE_PARM_DESC(active_pullup, "Active pullup (apply to all buses): " \
+				"0-disable, 1-enable (default)");
+
+/**
+ * The DS2482 registers - there are 3 registers that are addressed by a read
+ * pointer. The read pointer is set by the last command executed.
+ *
+ * To read the data, issue a register read for any address
+ */
+#define DS2482_CMD_RESET		0xF0	/* No param */
+#define DS2482_CMD_SET_READ_PTR		0xE1	/* Param: DS2482_PTR_CODE_xxx */
+#define DS2482_CMD_CHANNEL_SELECT	0xC3	/* Param: Channel byte - DS2482-800 only */
+#define DS2482_CMD_WRITE_CONFIG		0xD2	/* Param: Config byte */
+#define DS2482_CMD_1WIRE_RESET		0xB4	/* Param: None */
+#define DS2482_CMD_1WIRE_SINGLE_BIT	0x87	/* Param: Bit byte (bit7) */
+#define DS2482_CMD_1WIRE_WRITE_BYTE	0xA5	/* Param: Data byte */
+#define DS2482_CMD_1WIRE_READ_BYTE	0x96	/* Param: None */
+/* Note to read the byte, Set the ReadPtr to Data then read (any addr) */
+#define DS2482_CMD_1WIRE_TRIPLET	0x78	/* Param: Dir byte (bit7) */
+
+/* Values for DS2482_CMD_SET_READ_PTR */
+#define DS2482_PTR_CODE_STATUS		0xF0
+#define DS2482_PTR_CODE_DATA		0xE1
+#define DS2482_PTR_CODE_CHANNEL		0xD2	/* DS2482-800 only */
+#define DS2482_PTR_CODE_CONFIG		0xC3
+
+/**
+ * Configure Register bit definitions
+ * The top 4 bits always read 0.
+ * To write, the top nibble must be the 1's compl. of the low nibble.
+ */
+#define DS2482_REG_CFG_1WS		0x08	/* 1-wire speed */
+#define DS2482_REG_CFG_SPU		0x04	/* strong pull-up */
+#define DS2482_REG_CFG_PPM		0x02	/* presence pulse masking */
+#define DS2482_REG_CFG_APU		0x01	/* active pull-up */
+
+/* extra configurations - e.g. 1WS */
+static int extra_config;
+
+/**
+ * Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only).
+ * To set the channel, write the value at the index of the channel.
+ * Read and compare against the corresponding value to verify the change.
+ */
+static const u8 ds2482_chan_wr[8] =
+	{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 };
+static const u8 ds2482_chan_rd[8] =
+	{ 0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87 };
+
+
+/**
+ * Status Register bit definitions (read only)
+ */
+#define DS2482_REG_STS_DIR		0x80
+#define DS2482_REG_STS_TSB		0x40
+#define DS2482_REG_STS_SBR		0x20
+#define DS2482_REG_STS_RST		0x10
+#define DS2482_REG_STS_LL		0x08
+#define DS2482_REG_STS_SD		0x04
+#define DS2482_REG_STS_PPD		0x02
+#define DS2482_REG_STS_1WB		0x01
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct ds2482_data;
+
+struct ds2482_w1_chan {
+	struct ds2482_data	*pdev;
+	u8			channel;
+	struct w1_bus_master	w1_bm;
+};
+
+struct ds2482_data {
+	struct i2c_client	*client;
+	struct mutex		access_lock;
+
+	/* 1-wire interface(s) */
+	int			w1_count;	/* 1 or 8 */
+	struct ds2482_w1_chan	w1_ch[8];
+
+	/* per-device values */
+	u8			channel;
+	u8			read_prt;	/* see DS2482_PTR_CODE_xxx */
+	u8			reg_config;
+};
+
+
+/**
+ * Helper to calculate values for configuration register
+ * @param conf the raw config value
+ * @return the value w/ complements that can be written to register
+ */
+static inline u8 ds2482_calculate_config(u8 conf)
+{
+	if (ds2482_active_pullup)
+		conf |= DS2482_REG_CFG_APU;
+
+	return conf | ((~conf & 0x0f) << 4);
+}
+
+
+/**
+ * Sets the read pointer.
+ * @param pdev		The ds2482 client pointer
+ * @param read_ptr	see DS2482_PTR_CODE_xxx above
+ * @return -1 on failure, 0 on success
+ */
+static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
+{
+	if (pdev->read_prt != read_ptr) {
+		if (i2c_smbus_write_byte_data(pdev->client,
+					      DS2482_CMD_SET_READ_PTR,
+					      read_ptr) < 0)
+			return -1;
+
+		pdev->read_prt = read_ptr;
+	}
+	return 0;
+}
+
+/**
+ * Sends a command without a parameter
+ * @param pdev	The ds2482 client pointer
+ * @param cmd	DS2482_CMD_RESET,
+ *		DS2482_CMD_1WIRE_RESET,
+ *		DS2482_CMD_1WIRE_READ_BYTE
+ * @return -1 on failure, 0 on success
+ */
+static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
+{
+	if (i2c_smbus_write_byte(pdev->client, cmd) < 0)
+		return -1;
+
+	pdev->read_prt = DS2482_PTR_CODE_STATUS;
+	return 0;
+}
+
+/**
+ * Sends a command with a parameter
+ * @param pdev	The ds2482 client pointer
+ * @param cmd	DS2482_CMD_WRITE_CONFIG,
+ *		DS2482_CMD_1WIRE_SINGLE_BIT,
+ *		DS2482_CMD_1WIRE_WRITE_BYTE,
+ *		DS2482_CMD_1WIRE_TRIPLET
+ * @param byte	The data to send
+ * @return -1 on failure, 0 on success
+ */
+static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
+				       u8 cmd, u8 byte)
+{
+	if (i2c_smbus_write_byte_data(pdev->client, cmd, byte) < 0)
+		return -1;
+
+	/* all cmds leave in STATUS, except CONFIG */
+	pdev->read_prt = (cmd != DS2482_CMD_WRITE_CONFIG) ?
+			 DS2482_PTR_CODE_STATUS : DS2482_PTR_CODE_CONFIG;
+	return 0;
+}
+
+
+/*
+ * 1-Wire interface code
+ */
+
+#define DS2482_WAIT_IDLE_TIMEOUT	100
+
+/**
+ * Waits until the 1-wire interface is idle (not busy)
+ *
+ * @param pdev Pointer to the device structure
+ * @return the last value read from status or -1 (failure)
+ */
+static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
+{
+	int temp = -1;
+	int retries = 0;
+
+	if (!ds2482_select_register(pdev, DS2482_PTR_CODE_STATUS)) {
+		do {
+			temp = i2c_smbus_read_byte(pdev->client);
+		} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
+			 (++retries < DS2482_WAIT_IDLE_TIMEOUT));
+	}
+
+	if (retries >= DS2482_WAIT_IDLE_TIMEOUT)
+		pr_err("%s: timeout on channel %d\n",
+		       __func__, pdev->channel);
+
+	return temp;
+}
+
+/**
+ * Selects a w1 channel.
+ * The 1-wire interface must be idle before calling this function.
+ *
+ * @param pdev		The ds2482 client pointer
+ * @param channel	0-7
+ * @return		-1 (failure) or 0 (success)
+ */
+static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
+{
+	if (i2c_smbus_write_byte_data(pdev->client, DS2482_CMD_CHANNEL_SELECT,
+				      ds2482_chan_wr[channel]) < 0)
+		return -1;
+
+	pdev->read_prt = DS2482_PTR_CODE_CHANNEL;
+	pdev->channel = -1;
+	if (i2c_smbus_read_byte(pdev->client) == ds2482_chan_rd[channel]) {
+		pdev->channel = channel;
+		return 0;
+	}
+	return -1;
+}
+
+
+/**
+ * Performs the touch-bit function, which writes a 0 or 1 and reads the level.
+ *
+ * @param data	The ds2482 channel pointer
+ * @param bit	The level to write: 0 or non-zero
+ * @return	The level read: 0 or 1
+ */
+static u8 ds2482_w1_touch_bit(void *data, u8 bit)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int status = -1;
+
+	mutex_lock(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the touch command, wait until 1WB == 0, return the status */
+	if (!ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_SINGLE_BIT,
+				  bit ? 0xFF : 0))
+		status = ds2482_wait_1wire_idle(pdev);
+
+	mutex_unlock(&pdev->access_lock);
+
+	return (status & DS2482_REG_STS_SBR) ? 1 : 0;
+}
+
+/**
+ * Performs the triplet function, which reads two bits and writes a bit.
+ * The bit written is determined by the two reads:
+ *   00 => dbit, 01 => 0, 10 => 1
+ *
+ * @param data	The ds2482 channel pointer
+ * @param dbit	The direction to choose if both branches are valid
+ * @return	b0=read1 b1=read2 b3=bit written
+ */
+static u8 ds2482_w1_triplet(void *data, u8 dbit)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int status = (3 << 5);
+
+	mutex_lock(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the triplet command, wait until 1WB == 0, return the status */
+	if (!ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_TRIPLET,
+				  dbit ? 0xFF : 0))
+		status = ds2482_wait_1wire_idle(pdev);
+
+	mutex_unlock(&pdev->access_lock);
+
+	/* Decode the status */
+	return (status >> 5);
+}
+
+/**
+ * Performs the write byte function.
+ *
+ * @param data	The ds2482 channel pointer
+ * @param byte	The value to write
+ */
+static void ds2482_w1_write_byte(void *data, u8 byte)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+
+	mutex_lock(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the write byte command */
+	ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte);
+
+	mutex_unlock(&pdev->access_lock);
+}
+
+/**
+ * Performs the read byte function.
+ *
+ * @param data	The ds2482 channel pointer
+ * @return	The value read
+ */
+static u8 ds2482_w1_read_byte(void *data)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int result;
+
+	mutex_lock(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the read byte command */
+	ds2482_send_cmd(pdev, DS2482_CMD_1WIRE_READ_BYTE);
+
+	/* Wait until 1WB == 0 */
+	ds2482_wait_1wire_idle(pdev);
+
+	/* Select the data register */
+	ds2482_select_register(pdev, DS2482_PTR_CODE_DATA);
+
+	/* Read the data byte */
+	result = i2c_smbus_read_byte(pdev->client);
+
+	mutex_unlock(&pdev->access_lock);
+
+	return result;
+}
+
+
+/**
+ * Sends a reset on the 1-wire interface
+ *
+ * @param data	The ds2482 channel pointer
+ * @return	0=Device present, 1=No device present or error
+ */
+static u8 ds2482_w1_reset_bus(void *data)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int err;
+	u8 retval = 1;
+
+	mutex_lock(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the reset command */
+	err = ds2482_send_cmd(pdev, DS2482_CMD_1WIRE_RESET);
+	if (err >= 0) {
+		/* Wait until the reset is complete */
+		err = ds2482_wait_1wire_idle(pdev);
+		retval = !(err & DS2482_REG_STS_PPD);
+
+		/* If the chip did reset since detect, re-config it */
+		if (err & DS2482_REG_STS_RST)
+			ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+					ds2482_calculate_config(extra_config));
+	}
+
+	mutex_unlock(&pdev->access_lock);
+
+	return retval;
+}
+
+static u8 ds2482_w1_set_pullup(void *data, int delay)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	u8 retval = 1;
+
+	/* if delay is non-zero activate the pullup,
+	 * the strong pullup will be automatically deactivated
+	 * by the master, so do not explicitly deactive it
+	 */
+	if (delay) {
+		/* both waits are crucial, otherwise devices might not be
+		 * powered long enough, causing e.g. a w1_therm sensor to
+		 * provide wrong conversion results
+		 */
+		ds2482_wait_1wire_idle(pdev);
+		/* note: it seems like both SPU and APU have to be set! */
+		retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+			ds2482_calculate_config(extra_config|DS2482_REG_CFG_SPU|DS2482_REG_CFG_APU));
+		ds2482_wait_1wire_idle(pdev);
+	}
+
+	return retval;
+}
+
+
+static int ds2482_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct ds2482_data *data;
+	int err = -ENODEV;
+	int temp1;
+	int idx;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+				     I2C_FUNC_SMBUS_BYTE))
+		return -ENODEV;
+
+	if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	data->client = client;
+	i2c_set_clientdata(client, data);
+
+	/* Reset the device (sets the read_ptr to status) */
+	if (ds2482_send_cmd(data, DS2482_CMD_RESET) < 0) {
+		dev_warn(&client->dev, "DS2482 reset failed.\n");
+		goto exit_free;
+	}
+
+	/* Sleep at least 525ns to allow the reset to complete */
+	ndelay(525);
+
+	/* Read the status byte - only reset bit and line should be set */
+	temp1 = i2c_smbus_read_byte(client);
+	if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) {
+		dev_warn(&client->dev, "DS2482 reset status "
+			 "0x%02X - not a DS2482\n", temp1);
+		goto exit_free;
+	}
+
+	/* Detect the 8-port version */
+	data->w1_count = 1;
+	if (ds2482_set_channel(data, 7) == 0)
+		data->w1_count = 8;
+
+	/* Set all config items to 0 (off) */
+	ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG,
+		ds2482_calculate_config(extra_config));
+
+	mutex_init(&data->access_lock);
+
+	/* Register 1-wire interface(s) */
+	for (idx = 0; idx < data->w1_count; idx++) {
+		data->w1_ch[idx].pdev = data;
+		data->w1_ch[idx].channel = idx;
+
+		/* Populate all the w1 bus master stuff */
+		data->w1_ch[idx].w1_bm.data       = &data->w1_ch[idx];
+		data->w1_ch[idx].w1_bm.read_byte  = ds2482_w1_read_byte;
+		data->w1_ch[idx].w1_bm.write_byte = ds2482_w1_write_byte;
+		data->w1_ch[idx].w1_bm.touch_bit  = ds2482_w1_touch_bit;
+		data->w1_ch[idx].w1_bm.triplet    = ds2482_w1_triplet;
+		data->w1_ch[idx].w1_bm.reset_bus  = ds2482_w1_reset_bus;
+		data->w1_ch[idx].w1_bm.set_pullup = ds2482_w1_set_pullup;
+
+		err = w1_add_master_device(&data->w1_ch[idx].w1_bm);
+		if (err) {
+			data->w1_ch[idx].pdev = NULL;
+			goto exit_w1_remove;
+		}
+	}
+
+	return 0;
+
+exit_w1_remove:
+	for (idx = 0; idx < data->w1_count; idx++) {
+		if (data->w1_ch[idx].pdev != NULL)
+			w1_remove_master_device(&data->w1_ch[idx].w1_bm);
+	}
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int ds2482_remove(struct i2c_client *client)
+{
+	struct ds2482_data   *data = i2c_get_clientdata(client);
+	int idx;
+
+	/* Unregister the 1-wire bridge(s) */
+	for (idx = 0; idx < data->w1_count; idx++) {
+		if (data->w1_ch[idx].pdev != NULL)
+			w1_remove_master_device(&data->w1_ch[idx].w1_bm);
+	}
+
+	/* Free the memory */
+	kfree(data);
+	return 0;
+}
+
+/**
+ * Driver data (common to all clients)
+ */
+static const struct i2c_device_id ds2482_id[] = {
+	{ "ds2482", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ds2482_id);
+
+static struct i2c_driver ds2482_driver = {
+	.driver = {
+		.name	= "ds2482",
+	},
+	.probe		= ds2482_probe,
+	.remove		= ds2482_remove,
+	.id_table	= ds2482_id,
+};
+module_i2c_driver(ds2482_driver);
+
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("DS2482 driver");
+module_param(extra_config, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
new file mode 100644
index 0000000..0f4ecfc
--- /dev/null
+++ b/drivers/w1/masters/ds2490.c
@@ -0,0 +1,1105 @@
+/*
+ *	ds2490.c  USB to one wire bridge
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+
+#include <linux/w1.h>
+
+/* USB Standard */
+/* USB Control request vendor type */
+#define VENDOR				0x40
+
+/* COMMAND TYPE CODES */
+#define CONTROL_CMD			0x00
+#define COMM_CMD			0x01
+#define MODE_CMD			0x02
+
+/* CONTROL COMMAND CODES */
+#define CTL_RESET_DEVICE		0x0000
+#define CTL_START_EXE			0x0001
+#define CTL_RESUME_EXE			0x0002
+#define CTL_HALT_EXE_IDLE		0x0003
+#define CTL_HALT_EXE_DONE		0x0004
+#define CTL_FLUSH_COMM_CMDS		0x0007
+#define CTL_FLUSH_RCV_BUFFER		0x0008
+#define CTL_FLUSH_XMT_BUFFER		0x0009
+#define CTL_GET_COMM_CMDS		0x000A
+
+/* MODE COMMAND CODES */
+#define MOD_PULSE_EN			0x0000
+#define MOD_SPEED_CHANGE_EN		0x0001
+#define MOD_1WIRE_SPEED			0x0002
+#define MOD_STRONG_PU_DURATION		0x0003
+#define MOD_PULLDOWN_SLEWRATE		0x0004
+#define MOD_PROG_PULSE_DURATION		0x0005
+#define MOD_WRITE1_LOWTIME		0x0006
+#define MOD_DSOW0_TREC			0x0007
+
+/* COMMUNICATION COMMAND CODES */
+#define COMM_ERROR_ESCAPE		0x0601
+#define COMM_SET_DURATION		0x0012
+#define COMM_BIT_IO			0x0020
+#define COMM_PULSE			0x0030
+#define COMM_1_WIRE_RESET		0x0042
+#define COMM_BYTE_IO			0x0052
+#define COMM_MATCH_ACCESS		0x0064
+#define COMM_BLOCK_IO			0x0074
+#define COMM_READ_STRAIGHT		0x0080
+#define COMM_DO_RELEASE			0x6092
+#define COMM_SET_PATH			0x00A2
+#define COMM_WRITE_SRAM_PAGE		0x00B2
+#define COMM_WRITE_EPROM		0x00C4
+#define COMM_READ_CRC_PROT_PAGE		0x00D4
+#define COMM_READ_REDIRECT_PAGE_CRC	0x21E4
+#define COMM_SEARCH_ACCESS		0x00F4
+
+/* Communication command bits */
+#define COMM_TYPE			0x0008
+#define COMM_SE				0x0008
+#define COMM_D				0x0008
+#define COMM_Z				0x0008
+#define COMM_CH				0x0008
+#define COMM_SM				0x0008
+#define COMM_R				0x0008
+#define COMM_IM				0x0001
+
+#define COMM_PS				0x4000
+#define COMM_PST			0x4000
+#define COMM_CIB			0x4000
+#define COMM_RTS			0x4000
+#define COMM_DT				0x2000
+#define COMM_SPU			0x1000
+#define COMM_F				0x0800
+#define COMM_NTF			0x0400
+#define COMM_ICP			0x0200
+#define COMM_RST			0x0100
+
+#define PULSE_PROG			0x01
+#define PULSE_SPUE			0x02
+
+#define BRANCH_MAIN			0xCC
+#define BRANCH_AUX			0x33
+
+/* Status flags */
+#define ST_SPUA				0x01  /* Strong Pull-up is active */
+#define ST_PRGA				0x02  /* 12V programming pulse is being generated */
+#define ST_12VP				0x04  /* external 12V programming voltage is present */
+#define ST_PMOD				0x08  /* DS2490 powered from USB and external sources */
+#define ST_HALT				0x10  /* DS2490 is currently halted */
+#define ST_IDLE				0x20  /* DS2490 is currently idle */
+#define ST_EPOF				0x80
+/* Status transfer size, 16 bytes status, 16 byte result flags */
+#define ST_SIZE				0x20
+
+/* Result Register flags */
+#define RR_DETECT			0xA5 /* New device detected */
+#define RR_NRS				0x01 /* Reset no presence or ... */
+#define RR_SH				0x02 /* short on reset or set path */
+#define RR_APP				0x04 /* alarming presence on reset */
+#define RR_VPP				0x08 /* 12V expected not seen */
+#define RR_CMP				0x10 /* compare error */
+#define RR_CRC				0x20 /* CRC error detected */
+#define RR_RDP				0x40 /* redirected page */
+#define RR_EOS				0x80 /* end of search error */
+
+#define SPEED_NORMAL			0x00
+#define SPEED_FLEXIBLE			0x01
+#define SPEED_OVERDRIVE			0x02
+
+#define NUM_EP				4
+#define EP_CONTROL			0
+#define EP_STATUS			1
+#define EP_DATA_OUT			2
+#define EP_DATA_IN			3
+
+struct ds_device {
+	struct list_head	ds_entry;
+
+	struct usb_device	*udev;
+	struct usb_interface	*intf;
+
+	int			ep[NUM_EP];
+
+	/* Strong PullUp
+	 * 0: pullup not active, else duration in milliseconds
+	 */
+	int			spu_sleep;
+	/* spu_bit contains COMM_SPU or 0 depending on if the strong pullup
+	 * should be active or not for writes.
+	 */
+	u16			spu_bit;
+
+	u8			st_buf[ST_SIZE];
+	u8			byte_buf;
+
+	struct w1_bus_master	master;
+};
+
+struct ds_status {
+	u8			enable;
+	u8			speed;
+	u8			pullup_dur;
+	u8			ppuls_dur;
+	u8			pulldown_slew;
+	u8			write1_time;
+	u8			write0_time;
+	u8			reserved0;
+	u8			status;
+	u8			command0;
+	u8			command1;
+	u8			command_buffer_status;
+	u8			data_out_buffer_status;
+	u8			data_in_buffer_status;
+	u8			reserved1;
+	u8			reserved2;
+};
+
+static LIST_HEAD(ds_devices);
+static DEFINE_MUTEX(ds_mutex);
+
+static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
+{
+	int err;
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+			CONTROL_CMD, VENDOR, value, index, NULL, 0, 1000);
+	if (err < 0) {
+		pr_err("Failed to send command control message %x.%x: err=%d.\n",
+				value, index, err);
+		return err;
+	}
+
+	return err;
+}
+
+static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
+{
+	int err;
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+			MODE_CMD, VENDOR, value, index, NULL, 0, 1000);
+	if (err < 0) {
+		pr_err("Failed to send mode control message %x.%x: err=%d.\n",
+				value, index, err);
+		return err;
+	}
+
+	return err;
+}
+
+static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
+{
+	int err;
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+			COMM_CMD, VENDOR, value, index, NULL, 0, 1000);
+	if (err < 0) {
+		pr_err("Failed to send control message %x.%x: err=%d.\n",
+				value, index, err);
+		return err;
+	}
+
+	return err;
+}
+
+static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
+{
+	pr_info("%45s: %8x\n", str, buf[off]);
+}
+
+static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count)
+{
+	int i;
+
+	pr_info("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
+	for (i = 0; i < count; ++i)
+		pr_info("%02x ", buf[i]);
+	pr_info("\n");
+
+	if (count >= 16) {
+		ds_print_msg(buf, "enable flag", 0);
+		ds_print_msg(buf, "1-wire speed", 1);
+		ds_print_msg(buf, "strong pullup duration", 2);
+		ds_print_msg(buf, "programming pulse duration", 3);
+		ds_print_msg(buf, "pulldown slew rate control", 4);
+		ds_print_msg(buf, "write-1 low time", 5);
+		ds_print_msg(buf, "data sample offset/write-0 recovery time",
+			6);
+		ds_print_msg(buf, "reserved (test register)", 7);
+		ds_print_msg(buf, "device status flags", 8);
+		ds_print_msg(buf, "communication command byte 1", 9);
+		ds_print_msg(buf, "communication command byte 2", 10);
+		ds_print_msg(buf, "communication command buffer status", 11);
+		ds_print_msg(buf, "1-wire data output buffer status", 12);
+		ds_print_msg(buf, "1-wire data input buffer status", 13);
+		ds_print_msg(buf, "reserved", 14);
+		ds_print_msg(buf, "reserved", 15);
+	}
+	for (i = 16; i < count; ++i) {
+		if (buf[i] == RR_DETECT) {
+			ds_print_msg(buf, "new device detect", i);
+			continue;
+		}
+		ds_print_msg(buf, "Result Register Value: ", i);
+		if (buf[i] & RR_NRS)
+			pr_info("NRS: Reset no presence or ...\n");
+		if (buf[i] & RR_SH)
+			pr_info("SH: short on reset or set path\n");
+		if (buf[i] & RR_APP)
+			pr_info("APP: alarming presence on reset\n");
+		if (buf[i] & RR_VPP)
+			pr_info("VPP: 12V expected not seen\n");
+		if (buf[i] & RR_CMP)
+			pr_info("CMP: compare error\n");
+		if (buf[i] & RR_CRC)
+			pr_info("CRC: CRC error detected\n");
+		if (buf[i] & RR_RDP)
+			pr_info("RDP: redirected page\n");
+		if (buf[i] & RR_EOS)
+			pr_info("EOS: end of search error\n");
+	}
+}
+
+static int ds_recv_status(struct ds_device *dev, struct ds_status *st,
+			  bool dump)
+{
+	int count, err;
+
+	if (st)
+		memset(st, 0, sizeof(*st));
+
+	count = 0;
+	err = usb_interrupt_msg(dev->udev,
+				usb_rcvintpipe(dev->udev,
+					       dev->ep[EP_STATUS]),
+				dev->st_buf, sizeof(dev->st_buf),
+				&count, 1000);
+	if (err < 0) {
+		pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n",
+		       dev->ep[EP_STATUS], err);
+		return err;
+	}
+
+	if (dump)
+		ds_dump_status(dev, dev->st_buf, count);
+
+	if (st && count >= sizeof(*st))
+		memcpy(st, dev->st_buf, sizeof(*st));
+
+	return count;
+}
+
+static void ds_reset_device(struct ds_device *dev)
+{
+	ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+	/* Always allow strong pullup which allow individual writes to use
+	 * the strong pullup.
+	 */
+	if (ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE))
+		pr_err("ds_reset_device: Error allowing strong pullup\n");
+	/* Chip strong pullup time was cleared. */
+	if (dev->spu_sleep) {
+		/* lower 4 bits are 0, see ds_set_pullup */
+		u8 del = dev->spu_sleep>>4;
+		if (ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del))
+			pr_err("ds_reset_device: Error setting duration\n");
+	}
+}
+
+static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
+{
+	int count, err;
+
+	/* Careful on size.  If size is less than what is available in
+	 * the input buffer, the device fails the bulk transfer and
+	 * clears the input buffer.  It could read the maximum size of
+	 * the data buffer, but then do you return the first, last, or
+	 * some set of the middle size bytes?  As long as the rest of
+	 * the code is correct there will be size bytes waiting.  A
+	 * call to ds_wait_status will wait until the device is idle
+	 * and any data to be received would have been available.
+	 */
+	count = 0;
+	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
+				buf, size, &count, 1000);
+	if (err < 0) {
+		pr_info("Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
+		usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
+		ds_recv_status(dev, NULL, true);
+		return err;
+	}
+
+#if 0
+	{
+		int i;
+
+		printk("%s: count=%d: ", __func__, count);
+		for (i = 0; i < count; ++i)
+			printk("%02x ", buf[i]);
+		printk("\n");
+	}
+#endif
+	return count;
+}
+
+static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
+{
+	int count, err;
+
+	count = 0;
+	err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
+	if (err < 0) {
+		pr_err("Failed to write 1-wire data to ep0x%x: "
+			"err=%d.\n", dev->ep[EP_DATA_OUT], err);
+		return err;
+	}
+
+	return err;
+}
+
+#if 0
+
+int ds_stop_pulse(struct ds_device *dev, int limit)
+{
+	struct ds_status st;
+	int count = 0, err = 0;
+
+	do {
+		err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
+		if (err)
+			break;
+		err = ds_send_control(dev, CTL_RESUME_EXE, 0);
+		if (err)
+			break;
+		err = ds_recv_status(dev, &st, false);
+		if (err)
+			break;
+
+		if ((st.status & ST_SPUA) == 0) {
+			err = ds_send_control_mode(dev, MOD_PULSE_EN, 0);
+			if (err)
+				break;
+		}
+	} while (++count < limit);
+
+	return err;
+}
+
+int ds_detect(struct ds_device *dev, struct ds_status *st)
+{
+	int err;
+
+	err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+	if (err)
+		return err;
+
+	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
+	if (err)
+		return err;
+
+	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
+	if (err)
+		return err;
+
+	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
+	if (err)
+		return err;
+
+	err = ds_dump_status(dev, st);
+
+	return err;
+}
+
+#endif  /*  0  */
+
+static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
+{
+	int err, count = 0;
+
+	do {
+		st->status = 0;
+		err = ds_recv_status(dev, st, false);
+#if 0
+		if (err >= 0) {
+			int i;
+			printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
+			for (i = 0; i < err; ++i)
+				printk("%02x ", dev->st_buf[i]);
+			printk("\n");
+		}
+#endif
+	} while (!(st->status & ST_IDLE) && !(err < 0) && ++count < 100);
+
+	if (err >= 16 && st->status & ST_EPOF) {
+		pr_info("Resetting device after ST_EPOF.\n");
+		ds_reset_device(dev);
+		/* Always dump the device status. */
+		count = 101;
+	}
+
+	/* Dump the status for errors or if there is extended return data.
+	 * The extended status includes new device detection (maybe someone
+	 * can do something with it).
+	 */
+	if (err > 16 || count >= 100 || err < 0)
+		ds_dump_status(dev, dev->st_buf, err);
+
+	/* Extended data isn't an error.  Well, a short is, but the dump
+	 * would have already told the user that and we can't do anything
+	 * about it in software anyway.
+	 */
+	if (count >= 100 || err < 0)
+		return -1;
+	else
+		return 0;
+}
+
+static int ds_reset(struct ds_device *dev)
+{
+	int err;
+
+	/* Other potentionally interesting flags for reset.
+	 *
+	 * COMM_NTF: Return result register feedback.  This could be used to
+	 * detect some conditions such as short, alarming presence, or
+	 * detect if a new device was detected.
+	 *
+	 * COMM_SE which allows SPEED_NORMAL, SPEED_FLEXIBLE, SPEED_OVERDRIVE:
+	 * Select the data transfer rate.
+	 */
+	err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_IM, SPEED_NORMAL);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+#if 0
+static int ds_set_speed(struct ds_device *dev, int speed)
+{
+	int err;
+
+	if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE)
+		return -EINVAL;
+
+	if (speed != SPEED_OVERDRIVE)
+		speed = SPEED_FLEXIBLE;
+
+	speed &= 0xff;
+
+	err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
+	if (err)
+		return err;
+
+	return err;
+}
+#endif  /*  0  */
+
+static int ds_set_pullup(struct ds_device *dev, int delay)
+{
+	int err = 0;
+	u8 del = 1 + (u8)(delay >> 4);
+	/* Just storing delay would not get the trunication and roundup. */
+	int ms = del<<4;
+
+	/* Enable spu_bit if a delay is set. */
+	dev->spu_bit = delay ? COMM_SPU : 0;
+	/* If delay is zero, it has already been disabled, if the time is
+	 * the same as the hardware was last programmed to, there is also
+	 * nothing more to do.  Compare with the recalculated value ms
+	 * rather than del or delay which can have a different value.
+	 */
+	if (delay == 0 || ms == dev->spu_sleep)
+		return err;
+
+	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
+	if (err)
+		return err;
+
+	dev->spu_sleep = ms;
+
+	return err;
+}
+
+static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit ? COMM_D : 0),
+		0);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_recv_data(dev, tbit, sizeof(*tbit));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+#if 0
+static int ds_write_bit(struct ds_device *dev, u8 bit)
+{
+	int err;
+	struct ds_status st;
+
+	/* Set COMM_ICP to write without a readback.  Note, this will
+	 * produce one time slot, a down followed by an up with COMM_D
+	 * only determing the timing.
+	 */
+	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_ICP |
+		(bit ? COMM_D : 0), 0);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	return 0;
+}
+#endif
+
+static int ds_write_byte(struct ds_device *dev, u8 byte)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte);
+	if (err)
+		return err;
+
+	if (dev->spu_bit)
+		msleep(dev->spu_sleep);
+
+	err = ds_wait_status(dev, &st);
+	if (err)
+		return err;
+
+	err = ds_recv_data(dev, &dev->byte_buf, 1);
+	if (err < 0)
+		return err;
+
+	return !(byte == dev->byte_buf);
+}
+
+static int ds_read_byte(struct ds_device *dev, u8 *byte)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM, 0xff);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_recv_data(dev, byte, sizeof(*byte));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
+{
+	struct ds_status st;
+	int err;
+
+	if (len > 64*1024)
+		return -E2BIG;
+
+	memset(buf, 0xFF, len);
+
+	err = ds_send_data(dev, buf, len);
+	if (err < 0)
+		return err;
+
+	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM, len);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	memset(buf, 0x00, len);
+	err = ds_recv_data(dev, buf, len);
+
+	return err;
+}
+
+static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_data(dev, buf, len);
+	if (err < 0)
+		return err;
+
+	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | dev->spu_bit, len);
+	if (err)
+		return err;
+
+	if (dev->spu_bit)
+		msleep(dev->spu_sleep);
+
+	ds_wait_status(dev, &st);
+
+	err = ds_recv_data(dev, buf, len);
+	if (err < 0)
+		return err;
+
+	return !(err == len);
+}
+
+static void ds9490r_search(void *data, struct w1_master *master,
+	u8 search_type, w1_slave_found_callback callback)
+{
+	/* When starting with an existing id, the first id returned will
+	 * be that device (if it is still on the bus most likely).
+	 *
+	 * If the number of devices found is less than or equal to the
+	 * search_limit, that number of IDs will be returned.  If there are
+	 * more, search_limit IDs will be returned followed by a non-zero
+	 * discrepency value.
+	 */
+	struct ds_device *dev = data;
+	int err;
+	u16 value, index;
+	struct ds_status st;
+	int search_limit;
+	int found = 0;
+	int i;
+
+	/* DS18b20 spec, 13.16 ms per device, 75 per second, sleep for
+	 * discovering 8 devices (1 bulk transfer and 1/2 FIFO size) at a time.
+	 */
+	const unsigned long jtime = msecs_to_jiffies(1000*8/75);
+	/* FIFO 128 bytes, bulk packet size 64, read a multiple of the
+	 * packet size.
+	 */
+	const size_t bufsize = 2 * 64;
+	u64 *buf;
+
+	buf = kmalloc(bufsize, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	mutex_lock(&master->bus_mutex);
+
+	/* address to start searching at */
+	if (ds_send_data(dev, (u8 *)&master->search_id, 8) < 0)
+		goto search_out;
+	master->search_id = 0;
+
+	value = COMM_SEARCH_ACCESS | COMM_IM | COMM_RST | COMM_SM | COMM_F |
+		COMM_RTS;
+	search_limit = master->max_slave_count;
+	if (search_limit > 255)
+		search_limit = 0;
+	index = search_type | (search_limit << 8);
+	if (ds_send_control(dev, value, index) < 0)
+		goto search_out;
+
+	do {
+		schedule_timeout(jtime);
+
+		err = ds_recv_status(dev, &st, false);
+		if (err < 0 || err < sizeof(st))
+			break;
+
+		if (st.data_in_buffer_status) {
+			/* Bulk in can receive partial ids, but when it does
+			 * they fail crc and will be discarded anyway.
+			 * That has only been seen when status in buffer
+			 * is 0 and bulk is read anyway, so don't read
+			 * bulk without first checking if status says there
+			 * is data to read.
+			 */
+			err = ds_recv_data(dev, (u8 *)buf, bufsize);
+			if (err < 0)
+				break;
+			for (i = 0; i < err/8; ++i) {
+				++found;
+				if (found <= search_limit)
+					callback(master, buf[i]);
+				/* can't know if there will be a discrepancy
+				 * value after until the next id */
+				if (found == search_limit)
+					master->search_id = buf[i];
+			}
+		}
+
+		if (test_bit(W1_ABORT_SEARCH, &master->flags))
+			break;
+	} while (!(st.status & (ST_IDLE | ST_HALT)));
+
+	/* only continue the search if some weren't found */
+	if (found <= search_limit) {
+		master->search_id = 0;
+	} else if (!test_bit(W1_WARN_MAX_COUNT, &master->flags)) {
+		/* Only max_slave_count will be scanned in a search,
+		 * but it will start where it left off next search
+		 * until all ids are identified and then it will start
+		 * over.  A continued search will report the previous
+		 * last id as the first id (provided it is still on the
+		 * bus).
+		 */
+		dev_info(&dev->udev->dev, "%s: max_slave_count %d reached, "
+			"will continue next search.\n", __func__,
+			master->max_slave_count);
+		set_bit(W1_WARN_MAX_COUNT, &master->flags);
+	}
+search_out:
+	mutex_unlock(&master->bus_mutex);
+	kfree(buf);
+}
+
+#if 0
+/*
+ * FIXME: if this disabled code is ever used in the future all ds_send_data()
+ * calls must be changed to use a DMAable buffer.
+ */
+static int ds_match_access(struct ds_device *dev, u64 init)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	return 0;
+}
+
+static int ds_set_path(struct ds_device *dev, u64 init)
+{
+	int err;
+	struct ds_status st;
+	u8 buf[9];
+
+	memcpy(buf, &init, 8);
+	buf[8] = BRANCH_MAIN;
+
+	err = ds_send_data(dev, buf, sizeof(buf));
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	return 0;
+}
+
+#endif  /*  0  */
+
+static u8 ds9490r_touch_bit(void *data, u8 bit)
+{
+	struct ds_device *dev = data;
+
+	if (ds_touch_bit(dev, bit, &dev->byte_buf))
+		return 0;
+
+	return dev->byte_buf;
+}
+
+#if 0
+static void ds9490r_write_bit(void *data, u8 bit)
+{
+	struct ds_device *dev = data;
+
+	ds_write_bit(dev, bit);
+}
+
+static u8 ds9490r_read_bit(void *data)
+{
+	struct ds_device *dev = data;
+	int err;
+
+	err = ds_touch_bit(dev, 1, &dev->byte_buf);
+	if (err)
+		return 0;
+
+	return dev->byte_buf & 1;
+}
+#endif
+
+static void ds9490r_write_byte(void *data, u8 byte)
+{
+	struct ds_device *dev = data;
+
+	ds_write_byte(dev, byte);
+}
+
+static u8 ds9490r_read_byte(void *data)
+{
+	struct ds_device *dev = data;
+	int err;
+
+	err = ds_read_byte(dev, &dev->byte_buf);
+	if (err)
+		return 0;
+
+	return dev->byte_buf;
+}
+
+static void ds9490r_write_block(void *data, const u8 *buf, int len)
+{
+	struct ds_device *dev = data;
+	u8 *tbuf;
+
+	if (len <= 0)
+		return;
+
+	tbuf = kmemdup(buf, len, GFP_KERNEL);
+	if (!tbuf)
+		return;
+
+	ds_write_block(dev, tbuf, len);
+
+	kfree(tbuf);
+}
+
+static u8 ds9490r_read_block(void *data, u8 *buf, int len)
+{
+	struct ds_device *dev = data;
+	int err;
+	u8 *tbuf;
+
+	if (len <= 0)
+		return 0;
+
+	tbuf = kmalloc(len, GFP_KERNEL);
+	if (!tbuf)
+		return 0;
+
+	err = ds_read_block(dev, tbuf, len);
+	if (err >= 0)
+		memcpy(buf, tbuf, len);
+
+	kfree(tbuf);
+
+	return err >= 0 ? len : 0;
+}
+
+static u8 ds9490r_reset(void *data)
+{
+	struct ds_device *dev = data;
+	int err;
+
+	err = ds_reset(dev);
+	if (err)
+		return 1;
+
+	return 0;
+}
+
+static u8 ds9490r_set_pullup(void *data, int delay)
+{
+	struct ds_device *dev = data;
+
+	if (ds_set_pullup(dev, delay))
+		return 1;
+
+	return 0;
+}
+
+static int ds_w1_init(struct ds_device *dev)
+{
+	memset(&dev->master, 0, sizeof(struct w1_bus_master));
+
+	/* Reset the device as it can be in a bad state.
+	 * This is necessary because a block write will wait for data
+	 * to be placed in the output buffer and block any later
+	 * commands which will keep accumulating and the device will
+	 * not be idle.  Another case is removing the ds2490 module
+	 * while a bus search is in progress, somehow a few commands
+	 * get through, but the input transfers fail leaving data in
+	 * the input buffer.  This will cause the next read to fail
+	 * see the note in ds_recv_data.
+	 */
+	ds_reset_device(dev);
+
+	dev->master.data	= dev;
+	dev->master.touch_bit	= &ds9490r_touch_bit;
+	/* read_bit and write_bit in w1_bus_master are expected to set and
+	 * sample the line level.  For write_bit that means it is expected to
+	 * set it to that value and leave it there.  ds2490 only supports an
+	 * individual time slot at the lowest level.  The requirement from
+	 * pulling the bus state down to reading the state is 15us, something
+	 * that isn't realistic on the USB bus anyway.
+	dev->master.read_bit	= &ds9490r_read_bit;
+	dev->master.write_bit	= &ds9490r_write_bit;
+	*/
+	dev->master.read_byte	= &ds9490r_read_byte;
+	dev->master.write_byte	= &ds9490r_write_byte;
+	dev->master.read_block	= &ds9490r_read_block;
+	dev->master.write_block	= &ds9490r_write_block;
+	dev->master.reset_bus	= &ds9490r_reset;
+	dev->master.set_pullup	= &ds9490r_set_pullup;
+	dev->master.search	= &ds9490r_search;
+
+	return w1_add_master_device(&dev->master);
+}
+
+static void ds_w1_fini(struct ds_device *dev)
+{
+	w1_remove_master_device(&dev->master);
+}
+
+static int ds_probe(struct usb_interface *intf,
+		    const struct usb_device_id *udev_id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_host_interface *iface_desc;
+	struct ds_device *dev;
+	int i, err, alt;
+
+	dev = kzalloc(sizeof(struct ds_device), GFP_KERNEL);
+	if (!dev) {
+		pr_info("Failed to allocate new DS9490R structure.\n");
+		return -ENOMEM;
+	}
+	dev->udev = usb_get_dev(udev);
+	if (!dev->udev) {
+		err = -ENOMEM;
+		goto err_out_free;
+	}
+	memset(dev->ep, 0, sizeof(dev->ep));
+
+	usb_set_intfdata(intf, dev);
+
+	err = usb_reset_configuration(dev->udev);
+	if (err) {
+		dev_err(&dev->udev->dev,
+			"Failed to reset configuration: err=%d.\n", err);
+		goto err_out_clear;
+	}
+
+	/* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */
+	alt = 3;
+	err = usb_set_interface(dev->udev,
+		intf->altsetting[alt].desc.bInterfaceNumber, alt);
+	if (err) {
+		dev_err(&dev->udev->dev, "Failed to set alternative setting %d "
+			"for %d interface: err=%d.\n", alt,
+			intf->altsetting[alt].desc.bInterfaceNumber, err);
+		goto err_out_clear;
+	}
+
+	iface_desc = &intf->altsetting[alt];
+	if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
+		pr_info("Num endpoints=%d. It is not DS9490R.\n",
+			iface_desc->desc.bNumEndpoints);
+		err = -EINVAL;
+		goto err_out_clear;
+	}
+
+	/*
+	 * This loop doesn'd show control 0 endpoint,
+	 * so we will fill only 1-3 endpoints entry.
+	 */
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		dev->ep[i+1] = endpoint->bEndpointAddress;
+#if 0
+		printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
+			i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
+			(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
+			endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+#endif
+	}
+
+	err = ds_w1_init(dev);
+	if (err)
+		goto err_out_clear;
+
+	mutex_lock(&ds_mutex);
+	list_add_tail(&dev->ds_entry, &ds_devices);
+	mutex_unlock(&ds_mutex);
+
+	return 0;
+
+err_out_clear:
+	usb_set_intfdata(intf, NULL);
+	usb_put_dev(dev->udev);
+err_out_free:
+	kfree(dev);
+	return err;
+}
+
+static void ds_disconnect(struct usb_interface *intf)
+{
+	struct ds_device *dev;
+
+	dev = usb_get_intfdata(intf);
+	if (!dev)
+		return;
+
+	mutex_lock(&ds_mutex);
+	list_del(&dev->ds_entry);
+	mutex_unlock(&ds_mutex);
+
+	ds_w1_fini(dev);
+
+	usb_set_intfdata(intf, NULL);
+
+	usb_put_dev(dev->udev);
+	kfree(dev);
+}
+
+static const struct usb_device_id ds_id_table[] = {
+	{ USB_DEVICE(0x04fa, 0x2490) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, ds_id_table);
+
+static struct usb_driver ds_driver = {
+	.name =		"DS9490R",
+	.probe =	ds_probe,
+	.disconnect =	ds_disconnect,
+	.id_table =	ds_id_table,
+};
+module_usb_driver(ds_driver);
+
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
+MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
new file mode 100644
index 0000000..d83d7c9
--- /dev/null
+++ b/drivers/w1/masters/matrox_w1.c
@@ -0,0 +1,222 @@
+/*
+ *	matrox_w1.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/types.h>
+#include <linux/atomic.h>
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+#include <linux/pci.h>
+
+#include <linux/w1.h>
+
+/*
+ * Matrox G400 DDC registers.
+ */
+
+#define MATROX_G400_DDC_CLK		(1<<4)
+#define MATROX_G400_DDC_DATA		(1<<1)
+
+#define MATROX_BASE			0x3C00
+#define MATROX_STATUS			0x1e14
+
+#define MATROX_PORT_INDEX_OFFSET	0x00
+#define MATROX_PORT_DATA_OFFSET		0x0A
+
+#define MATROX_GET_CONTROL		0x2A
+#define MATROX_GET_DATA			0x2B
+#define MATROX_CURSOR_CTL		0x06
+
+struct matrox_device
+{
+	void __iomem *base_addr;
+	void __iomem *port_index;
+	void __iomem *port_data;
+	u8 data_mask;
+
+	unsigned long phys_addr;
+	void __iomem *virt_addr;
+	unsigned long found;
+
+	struct w1_bus_master *bus_master;
+};
+
+/*
+ * These functions read and write DDC Data bit.
+ *
+ * Using tristate pins, since i can't find any open-drain pin in whole motherboard.
+ * Unfortunately we can't connect to Intel's 82801xx IO controller
+ * since we don't know motherboard schema, which has pretty unused(may be not) GPIO.
+ *
+ * I've heard that PIIX also has open drain pin.
+ *
+ * Port mapping.
+ */
+static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg)
+{
+	u8 ret;
+
+	writeb(reg, dev->port_index);
+	ret = readb(dev->port_data);
+	barrier();
+
+	return ret;
+}
+
+static __inline__ void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val)
+{
+	writeb(reg, dev->port_index);
+	writeb(val, dev->port_data);
+	wmb();
+}
+
+static void matrox_w1_write_ddc_bit(void *data, u8 bit)
+{
+	u8 ret;
+	struct matrox_device *dev = data;
+
+	if (bit)
+		bit = 0;
+	else
+		bit = dev->data_mask;
+
+	ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL);
+	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
+	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
+}
+
+static u8 matrox_w1_read_ddc_bit(void *data)
+{
+	u8 ret;
+	struct matrox_device *dev = data;
+
+	ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
+
+	return ret;
+}
+
+static void matrox_w1_hw_init(struct matrox_device *dev)
+{
+	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
+	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
+}
+
+static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct matrox_device *dev;
+	int err;
+
+	if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
+		return -ENODEV;
+
+	dev = kzalloc(sizeof(struct matrox_device) +
+		       sizeof(struct w1_bus_master), GFP_KERNEL);
+	if (!dev) {
+		dev_err(&pdev->dev,
+			"%s: Failed to create new matrox_device object.\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+
+	dev->bus_master = (struct w1_bus_master *)(dev + 1);
+
+	/*
+	 * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
+	 */
+
+	dev->phys_addr = pci_resource_start(pdev, 1);
+
+	dev->virt_addr = ioremap_nocache(dev->phys_addr, 16384);
+	if (!dev->virt_addr) {
+		dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
+			__func__, dev->phys_addr, 16384);
+		err = -EIO;
+		goto err_out_free_device;
+	}
+
+	dev->base_addr = dev->virt_addr + MATROX_BASE;
+	dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
+	dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
+	dev->data_mask = (MATROX_G400_DDC_DATA);
+
+	matrox_w1_hw_init(dev);
+
+	dev->bus_master->data = dev;
+	dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
+	dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
+
+	err = w1_add_master_device(dev->bus_master);
+	if (err)
+		goto err_out_free_device;
+
+	pci_set_drvdata(pdev, dev);
+
+	dev->found = 1;
+
+	dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");
+
+	return 0;
+
+err_out_free_device:
+	if (dev->virt_addr)
+		iounmap(dev->virt_addr);
+	kfree(dev);
+
+	return err;
+}
+
+static void matrox_w1_remove(struct pci_dev *pdev)
+{
+	struct matrox_device *dev = pci_get_drvdata(pdev);
+
+	if (dev->found) {
+		w1_remove_master_device(dev->bus_master);
+		iounmap(dev->virt_addr);
+	}
+	kfree(dev);
+}
+
+static struct pci_device_id matrox_w1_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
+
+static struct pci_driver matrox_w1_pci_driver = {
+	.name = "matrox_w1",
+	.id_table = matrox_w1_tbl,
+	.probe = matrox_w1_probe,
+	.remove = matrox_w1_remove,
+};
+module_pci_driver(matrox_w1_pci_driver);
+
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
+MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire protocol) over VGA DDC(matrox gpio).");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c
new file mode 100644
index 0000000..50b46c4
--- /dev/null
+++ b/drivers/w1/masters/mxc_w1.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Luotao Fu, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include <linux/w1.h>
+
+/*
+ * MXC W1 Register offsets
+ */
+#define MXC_W1_CONTROL		0x00
+# define MXC_W1_CONTROL_RDST	BIT(3)
+# define MXC_W1_CONTROL_WR(x)	BIT(5 - (x))
+# define MXC_W1_CONTROL_PST	BIT(6)
+# define MXC_W1_CONTROL_RPP	BIT(7)
+#define MXC_W1_TIME_DIVIDER	0x02
+#define MXC_W1_RESET		0x04
+# define MXC_W1_RESET_RST	BIT(0)
+
+struct mxc_w1_device {
+	void __iomem *regs;
+	struct clk *clk;
+	struct w1_bus_master bus_master;
+};
+
+/*
+ * this is the low level routine to
+ * reset the device on the One Wire interface
+ * on the hardware
+ */
+static u8 mxc_w1_ds2_reset_bus(void *data)
+{
+	struct mxc_w1_device *dev = data;
+	unsigned long timeout;
+
+	writeb(MXC_W1_CONTROL_RPP, dev->regs + MXC_W1_CONTROL);
+
+	/* Wait for reset sequence 511+512us, use 1500us for sure */
+	timeout = jiffies + usecs_to_jiffies(1500);
+
+	udelay(511 + 512);
+
+	do {
+		u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
+
+		/* PST bit is valid after the RPP bit is self-cleared */
+		if (!(ctrl & MXC_W1_CONTROL_RPP))
+			return !(ctrl & MXC_W1_CONTROL_PST);
+	} while (time_is_after_jiffies(timeout));
+
+	return 1;
+}
+
+/*
+ * this is the low level routine to read/write a bit on the One Wire
+ * interface on the hardware. It does write 0 if parameter bit is set
+ * to 0, otherwise a write 1/read.
+ */
+static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
+{
+	struct mxc_w1_device *dev = data;
+	unsigned long timeout;
+
+	writeb(MXC_W1_CONTROL_WR(bit), dev->regs + MXC_W1_CONTROL);
+
+	/* Wait for read/write bit (60us, Max 120us), use 200us for sure */
+	timeout = jiffies + usecs_to_jiffies(200);
+
+	udelay(60);
+
+	do {
+		u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
+
+		/* RDST bit is valid after the WR1/RD bit is self-cleared */
+		if (!(ctrl & MXC_W1_CONTROL_WR(bit)))
+			return !!(ctrl & MXC_W1_CONTROL_RDST);
+	} while (time_is_after_jiffies(timeout));
+
+	return 0;
+}
+
+static int mxc_w1_probe(struct platform_device *pdev)
+{
+	struct mxc_w1_device *mdev;
+	unsigned long clkrate;
+	struct resource *res;
+	unsigned int clkdiv;
+	int err;
+
+	mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
+			    GFP_KERNEL);
+	if (!mdev)
+		return -ENOMEM;
+
+	mdev->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(mdev->clk))
+		return PTR_ERR(mdev->clk);
+
+	err = clk_prepare_enable(mdev->clk);
+	if (err)
+		return err;
+
+	clkrate = clk_get_rate(mdev->clk);
+	if (clkrate < 10000000)
+		dev_warn(&pdev->dev,
+			 "Low clock frequency causes improper function\n");
+
+	clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000);
+	clkrate /= clkdiv;
+	if ((clkrate < 980000) || (clkrate > 1020000))
+		dev_warn(&pdev->dev,
+			 "Incorrect time base frequency %lu Hz\n", clkrate);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mdev->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mdev->regs)) {
+		err = PTR_ERR(mdev->regs);
+		goto out_disable_clk;
+	}
+
+	/* Software reset 1-Wire module */
+	writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET);
+	writeb(0, mdev->regs + MXC_W1_RESET);
+
+	writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
+
+	mdev->bus_master.data = mdev;
+	mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
+	mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
+
+	platform_set_drvdata(pdev, mdev);
+
+	err = w1_add_master_device(&mdev->bus_master);
+	if (err)
+		goto out_disable_clk;
+
+	return 0;
+
+out_disable_clk:
+	clk_disable_unprepare(mdev->clk);
+	return err;
+}
+
+/*
+ * disassociate the w1 device from the driver
+ */
+static int mxc_w1_remove(struct platform_device *pdev)
+{
+	struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
+
+	w1_remove_master_device(&mdev->bus_master);
+
+	clk_disable_unprepare(mdev->clk);
+
+	return 0;
+}
+
+static const struct of_device_id mxc_w1_dt_ids[] = {
+	{ .compatible = "fsl,imx21-owire" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
+
+static struct platform_driver mxc_w1_driver = {
+	.driver = {
+		.name = "mxc_w1",
+		.of_match_table = mxc_w1_dt_ids,
+	},
+	.probe = mxc_w1_probe,
+	.remove = mxc_w1_remove,
+};
+module_platform_driver(mxc_w1_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductors Inc");
+MODULE_DESCRIPTION("Driver for One-Wire on MXC");
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
new file mode 100644
index 0000000..3099052
--- /dev/null
+++ b/drivers/w1/masters/omap_hdq.c
@@ -0,0 +1,790 @@
+/*
+ * drivers/w1/masters/omap_hdq.c
+ *
+ * Copyright (C) 2007,2012 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+
+#include <linux/w1.h>
+
+#define	MOD_NAME	"OMAP_HDQ:"
+
+#define OMAP_HDQ_REVISION			0x00
+#define OMAP_HDQ_TX_DATA			0x04
+#define OMAP_HDQ_RX_DATA			0x08
+#define OMAP_HDQ_CTRL_STATUS			0x0c
+#define OMAP_HDQ_CTRL_STATUS_SINGLE		BIT(7)
+#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK	BIT(6)
+#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE	BIT(5)
+#define OMAP_HDQ_CTRL_STATUS_GO                 BIT(4)
+#define OMAP_HDQ_CTRL_STATUS_PRESENCE		BIT(3)
+#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION	BIT(2)
+#define OMAP_HDQ_CTRL_STATUS_DIR		BIT(1)
+#define OMAP_HDQ_INT_STATUS			0x10
+#define OMAP_HDQ_INT_STATUS_TXCOMPLETE		BIT(2)
+#define OMAP_HDQ_INT_STATUS_RXCOMPLETE		BIT(1)
+#define OMAP_HDQ_INT_STATUS_TIMEOUT		BIT(0)
+#define OMAP_HDQ_SYSCONFIG			0x14
+#define OMAP_HDQ_SYSCONFIG_SOFTRESET		BIT(1)
+#define OMAP_HDQ_SYSCONFIG_AUTOIDLE		BIT(0)
+#define OMAP_HDQ_SYSCONFIG_NOIDLE		0x0
+#define OMAP_HDQ_SYSSTATUS			0x18
+#define OMAP_HDQ_SYSSTATUS_RESETDONE		BIT(0)
+
+#define OMAP_HDQ_FLAG_CLEAR			0
+#define OMAP_HDQ_FLAG_SET			1
+#define OMAP_HDQ_TIMEOUT			(HZ/5)
+
+#define OMAP_HDQ_MAX_USER			4
+
+static DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue);
+
+static int w1_id;
+module_param(w1_id, int, S_IRUSR);
+MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection in HDQ mode");
+
+struct hdq_data {
+	struct device		*dev;
+	void __iomem		*hdq_base;
+	/* lock status update */
+	struct  mutex		hdq_mutex;
+	int			hdq_usecount;
+	u8			hdq_irqstatus;
+	/* device lock */
+	spinlock_t		hdq_spinlock;
+	/*
+	 * Used to control the call to omap_hdq_get and omap_hdq_put.
+	 * HDQ Protocol: Write the CMD|REG_address first, followed by
+	 * the data wrire or read.
+	 */
+	int			init_trans;
+	int                     rrw;
+	/* mode: 0-HDQ 1-W1 */
+	int                     mode;
+
+};
+
+/* HDQ register I/O routines */
+static inline u8 hdq_reg_in(struct hdq_data *hdq_data, u32 offset)
+{
+	return __raw_readl(hdq_data->hdq_base + offset);
+}
+
+static inline void hdq_reg_out(struct hdq_data *hdq_data, u32 offset, u8 val)
+{
+	__raw_writel(val, hdq_data->hdq_base + offset);
+}
+
+static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
+			u8 val, u8 mask)
+{
+	u8 new_val = (__raw_readl(hdq_data->hdq_base + offset) & ~mask)
+			| (val & mask);
+	__raw_writel(new_val, hdq_data->hdq_base + offset);
+
+	return new_val;
+}
+
+static void hdq_disable_interrupt(struct hdq_data *hdq_data, u32 offset,
+				  u32 mask)
+{
+	u32 ie;
+
+	ie = readl(hdq_data->hdq_base + offset);
+	writel(ie & mask, hdq_data->hdq_base + offset);
+}
+
+/*
+ * Wait for one or more bits in flag change.
+ * HDQ_FLAG_SET: wait until any bit in the flag is set.
+ * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared.
+ * return 0 on success and -ETIMEDOUT in the case of timeout.
+ */
+static int hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
+		u8 flag, u8 flag_set, u8 *status)
+{
+	int ret = 0;
+	unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+
+	if (flag_set == OMAP_HDQ_FLAG_CLEAR) {
+		/* wait for the flag clear */
+		while (((*status = hdq_reg_in(hdq_data, offset)) & flag)
+			&& time_before(jiffies, timeout)) {
+			schedule_timeout_uninterruptible(1);
+		}
+		if (*status & flag)
+			ret = -ETIMEDOUT;
+	} else if (flag_set == OMAP_HDQ_FLAG_SET) {
+		/* wait for the flag set */
+		while (!((*status = hdq_reg_in(hdq_data, offset)) & flag)
+			&& time_before(jiffies, timeout)) {
+			schedule_timeout_uninterruptible(1);
+		}
+		if (!(*status & flag))
+			ret = -ETIMEDOUT;
+	} else
+		return -EINVAL;
+
+	return ret;
+}
+
+/* write out a byte and fill *status with HDQ_INT_STATUS */
+static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
+{
+	int ret;
+	u8 tmp_status;
+	unsigned long irqflags;
+
+	*status = 0;
+
+	spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+	/* clear interrupt flags via a dummy read */
+	hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+	/* ISR loads it with new INT_STATUS */
+	hdq_data->hdq_irqstatus = 0;
+	spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+	hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
+
+	/* set the GO bit */
+	hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
+		OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+	/* wait for the TXCOMPLETE bit */
+	ret = wait_event_timeout(hdq_wait_queue,
+		hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+	if (ret == 0) {
+		dev_dbg(hdq_data->dev, "TX wait elapsed\n");
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	*status = hdq_data->hdq_irqstatus;
+	/* check irqstatus */
+	if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
+		dev_dbg(hdq_data->dev, "timeout waiting for"
+			" TXCOMPLETE/RXCOMPLETE, %x", *status);
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	/* wait for the GO bit return to zero */
+	ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+			OMAP_HDQ_CTRL_STATUS_GO,
+			OMAP_HDQ_FLAG_CLEAR, &tmp_status);
+	if (ret) {
+		dev_dbg(hdq_data->dev, "timeout waiting GO bit"
+			" return to zero, %x", tmp_status);
+	}
+
+out:
+	return ret;
+}
+
+/* HDQ Interrupt service routine */
+static irqreturn_t hdq_isr(int irq, void *_hdq)
+{
+	struct hdq_data *hdq_data = _hdq;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+	hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+	spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+	dev_dbg(hdq_data->dev, "hdq_isr: %x", hdq_data->hdq_irqstatus);
+
+	if (hdq_data->hdq_irqstatus &
+		(OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
+		| OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+		/* wake up sleeping process */
+		wake_up(&hdq_wait_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* W1 search callback function  in HDQ mode */
+static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
+		u8 search_type, w1_slave_found_callback slave_found)
+{
+	u64 module_id, rn_le, cs, id;
+
+	if (w1_id)
+		module_id = w1_id;
+	else
+		module_id = 0x1;
+
+	rn_le = cpu_to_le64(module_id);
+	/*
+	 * HDQ might not obey truly the 1-wire spec.
+	 * So calculate CRC based on module parameter.
+	 */
+	cs = w1_calc_crc8((u8 *)&rn_le, 7);
+	id = (cs << 56) | module_id;
+
+	slave_found(master_dev, id);
+}
+
+static int _omap_hdq_reset(struct hdq_data *hdq_data)
+{
+	int ret;
+	u8 tmp_status;
+
+	hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+		    OMAP_HDQ_SYSCONFIG_SOFTRESET);
+	/*
+	 * Select HDQ/1W mode & enable clocks.
+	 * It is observed that INT flags can't be cleared via a read and GO/INIT
+	 * won't return to zero if interrupt is disabled. So we always enable
+	 * interrupt.
+	 */
+	hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+		OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+		OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+
+	/* wait for reset to complete */
+	ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS,
+		OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status);
+	if (ret)
+		dev_dbg(hdq_data->dev, "timeout waiting HDQ reset, %x",
+				tmp_status);
+	else {
+		hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+			OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+			OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
+			hdq_data->mode);
+		hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+			OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+	}
+
+	return ret;
+}
+
+/* Issue break pulse to the device */
+static int omap_hdq_break(struct hdq_data *hdq_data)
+{
+	int ret = 0;
+	u8 tmp_status;
+	unsigned long irqflags;
+
+	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+	if (ret < 0) {
+		dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+		ret = -EINTR;
+		goto rtn;
+	}
+
+	spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+	/* clear interrupt flags via a dummy read */
+	hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+	/* ISR loads it with new INT_STATUS */
+	hdq_data->hdq_irqstatus = 0;
+	spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+	/* set the INIT and GO bit */
+	hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+		OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
+		OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+		OMAP_HDQ_CTRL_STATUS_GO);
+
+	/* wait for the TIMEOUT bit */
+	ret = wait_event_timeout(hdq_wait_queue,
+		hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+	if (ret == 0) {
+		dev_dbg(hdq_data->dev, "break wait elapsed\n");
+		ret = -EINTR;
+		goto out;
+	}
+
+	tmp_status = hdq_data->hdq_irqstatus;
+	/* check irqstatus */
+	if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+		dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x",
+				tmp_status);
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	/*
+	 * check for the presence detect bit to get
+	 * set to show that the slave is responding
+	 */
+	if (!(hdq_reg_in(hdq_data, OMAP_HDQ_CTRL_STATUS) &
+			OMAP_HDQ_CTRL_STATUS_PRESENCE)) {
+		dev_dbg(hdq_data->dev, "Presence bit not set\n");
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	/*
+	 * wait for both INIT and GO bits rerurn to zero.
+	 * zero wait time expected for interrupt mode.
+	 */
+	ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+			OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+			OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR,
+			&tmp_status);
+	if (ret)
+		dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
+			" return to zero, %x", tmp_status);
+
+out:
+	mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+	return ret;
+}
+
+static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
+{
+	int ret = 0;
+	u8 status;
+
+	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+	if (ret < 0) {
+		ret = -EINTR;
+		goto rtn;
+	}
+
+	if (!hdq_data->hdq_usecount) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+		hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+			OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
+			OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+		/*
+		 * The RX comes immediately after TX.
+		 */
+		wait_event_timeout(hdq_wait_queue,
+				   (hdq_data->hdq_irqstatus
+				    & OMAP_HDQ_INT_STATUS_RXCOMPLETE),
+				   OMAP_HDQ_TIMEOUT);
+
+		hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0,
+			OMAP_HDQ_CTRL_STATUS_DIR);
+		status = hdq_data->hdq_irqstatus;
+		/* check irqstatus */
+		if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+			dev_dbg(hdq_data->dev, "timeout waiting for"
+				" RXCOMPLETE, %x", status);
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+	}
+	/* the data is ready. Read it in! */
+	*val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
+out:
+	mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+	return ret;
+
+}
+
+/* Enable clocks and set the controller to HDQ/1W mode */
+static int omap_hdq_get(struct hdq_data *hdq_data)
+{
+	int ret = 0;
+
+	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+	if (ret < 0) {
+		ret = -EINTR;
+		goto rtn;
+	}
+
+	if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) {
+		dev_dbg(hdq_data->dev, "attempt to exceed the max use count");
+		ret = -EINVAL;
+		goto out;
+	} else {
+		hdq_data->hdq_usecount++;
+		try_module_get(THIS_MODULE);
+		if (1 == hdq_data->hdq_usecount) {
+
+			pm_runtime_get_sync(hdq_data->dev);
+
+			/* make sure HDQ/1W is out of reset */
+			if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) &
+				OMAP_HDQ_SYSSTATUS_RESETDONE)) {
+				ret = _omap_hdq_reset(hdq_data);
+				if (ret)
+					/* back up the count */
+					hdq_data->hdq_usecount--;
+			} else {
+				/* select HDQ/1W mode & enable clocks */
+				hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+					OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+					OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
+					hdq_data->mode);
+				hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+					OMAP_HDQ_SYSCONFIG_NOIDLE);
+				hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+			}
+		}
+	}
+
+out:
+	mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+	return ret;
+}
+
+/* Disable clocks to the module */
+static int omap_hdq_put(struct hdq_data *hdq_data)
+{
+	int ret = 0;
+
+	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+	if (ret < 0)
+		return -EINTR;
+
+	hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+		    OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+	if (0 == hdq_data->hdq_usecount) {
+		dev_dbg(hdq_data->dev, "attempt to decrement use count"
+			" when it is zero");
+		ret = -EINVAL;
+	} else {
+		hdq_data->hdq_usecount--;
+		module_put(THIS_MODULE);
+		if (0 == hdq_data->hdq_usecount)
+			pm_runtime_put_sync(hdq_data->dev);
+	}
+	mutex_unlock(&hdq_data->hdq_mutex);
+
+	return ret;
+}
+
+/*
+ * W1 triplet callback function - used for searching ROM addresses.
+ * Registered only when controller is in 1-wire mode.
+ */
+static u8 omap_w1_triplet(void *_hdq, u8 bdir)
+{
+	u8 id_bit, comp_bit;
+	int err;
+	u8 ret = 0x3; /* no slaves responded */
+	struct hdq_data *hdq_data = _hdq;
+	u8 ctrl = OMAP_HDQ_CTRL_STATUS_SINGLE | OMAP_HDQ_CTRL_STATUS_GO |
+		  OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK;
+	u8 mask = ctrl | OMAP_HDQ_CTRL_STATUS_DIR;
+
+	omap_hdq_get(_hdq);
+
+	err = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+	if (err < 0) {
+		dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+		goto rtn;
+	}
+
+	hdq_data->hdq_irqstatus = 0;
+	/* read id_bit */
+	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
+		      ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
+	err = wait_event_timeout(hdq_wait_queue,
+				 (hdq_data->hdq_irqstatus
+				  & OMAP_HDQ_INT_STATUS_RXCOMPLETE),
+				 OMAP_HDQ_TIMEOUT);
+	if (err == 0) {
+		dev_dbg(hdq_data->dev, "RX wait elapsed\n");
+		goto out;
+	}
+	id_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01);
+
+	hdq_data->hdq_irqstatus = 0;
+	/* read comp_bit */
+	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
+		      ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
+	err = wait_event_timeout(hdq_wait_queue,
+				 (hdq_data->hdq_irqstatus
+				  & OMAP_HDQ_INT_STATUS_RXCOMPLETE),
+				 OMAP_HDQ_TIMEOUT);
+	if (err == 0) {
+		dev_dbg(hdq_data->dev, "RX wait elapsed\n");
+		goto out;
+	}
+	comp_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01);
+
+	if (id_bit && comp_bit) {
+		ret = 0x03;  /* no slaves responded */
+		goto out;
+	}
+	if (!id_bit && !comp_bit) {
+		/* Both bits are valid, take the direction given */
+		ret = bdir ? 0x04 : 0;
+	} else {
+		/* Only one bit is valid, take that direction */
+		bdir = id_bit;
+		ret = id_bit ? 0x05 : 0x02;
+	}
+
+	/* write bdir bit */
+	hdq_reg_out(_hdq, OMAP_HDQ_TX_DATA, bdir);
+	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, ctrl, mask);
+	err = wait_event_timeout(hdq_wait_queue,
+				 (hdq_data->hdq_irqstatus
+				  & OMAP_HDQ_INT_STATUS_TXCOMPLETE),
+				 OMAP_HDQ_TIMEOUT);
+	if (err == 0) {
+		dev_dbg(hdq_data->dev, "TX wait elapsed\n");
+		goto out;
+	}
+
+	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, 0,
+		      OMAP_HDQ_CTRL_STATUS_SINGLE);
+
+out:
+	mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+	omap_hdq_put(_hdq);
+	return ret;
+}
+
+/* reset callback */
+static u8 omap_w1_reset_bus(void *_hdq)
+{
+	omap_hdq_get(_hdq);
+	omap_hdq_break(_hdq);
+	omap_hdq_put(_hdq);
+	return 0;
+}
+
+/* Read a byte of data from the device */
+static u8 omap_w1_read_byte(void *_hdq)
+{
+	struct hdq_data *hdq_data = _hdq;
+	u8 val = 0;
+	int ret;
+
+	/* First write to initialize the transfer */
+	if (hdq_data->init_trans == 0)
+		omap_hdq_get(hdq_data);
+
+	ret = hdq_read_byte(hdq_data, &val);
+	if (ret) {
+		ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+		if (ret < 0) {
+			dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+			return -EINTR;
+		}
+		hdq_data->init_trans = 0;
+		mutex_unlock(&hdq_data->hdq_mutex);
+		omap_hdq_put(hdq_data);
+		return -1;
+	}
+
+	hdq_disable_interrupt(hdq_data, OMAP_HDQ_CTRL_STATUS,
+			      ~OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+
+	/* Write followed by a read, release the module */
+	if (hdq_data->init_trans) {
+		ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+		if (ret < 0) {
+			dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+			return -EINTR;
+		}
+		hdq_data->init_trans = 0;
+		mutex_unlock(&hdq_data->hdq_mutex);
+		omap_hdq_put(hdq_data);
+	}
+
+	return val;
+}
+
+/* Write a byte of data to the device */
+static void omap_w1_write_byte(void *_hdq, u8 byte)
+{
+	struct hdq_data *hdq_data = _hdq;
+	int ret;
+	u8 status;
+
+	/* First write to initialize the transfer */
+	if (hdq_data->init_trans == 0)
+		omap_hdq_get(hdq_data);
+
+	/*
+	 * We need to reset the slave before
+	 * issuing the SKIP ROM command, else
+	 * the slave will not work.
+	 */
+	if (byte == W1_SKIP_ROM)
+		omap_hdq_break(hdq_data);
+
+	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+	if (ret < 0) {
+		dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+		return;
+	}
+	hdq_data->init_trans++;
+	mutex_unlock(&hdq_data->hdq_mutex);
+
+	ret = hdq_write_byte(hdq_data, byte, &status);
+	if (ret < 0) {
+		dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
+		return;
+	}
+
+	/* Second write, data transferred. Release the module */
+	if (hdq_data->init_trans > 1) {
+		omap_hdq_put(hdq_data);
+		ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+		if (ret < 0) {
+			dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+			return;
+		}
+		hdq_data->init_trans = 0;
+		mutex_unlock(&hdq_data->hdq_mutex);
+	}
+}
+
+static struct w1_bus_master omap_w1_master = {
+	.read_byte	= omap_w1_read_byte,
+	.write_byte	= omap_w1_write_byte,
+	.reset_bus	= omap_w1_reset_bus,
+};
+
+static int omap_hdq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct hdq_data *hdq_data;
+	struct resource *res;
+	int ret, irq;
+	u8 rev;
+	const char *mode;
+
+	hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL);
+	if (!hdq_data) {
+		dev_dbg(&pdev->dev, "unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	hdq_data->dev = dev;
+	platform_set_drvdata(pdev, hdq_data);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hdq_data->hdq_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(hdq_data->hdq_base))
+		return PTR_ERR(hdq_data->hdq_base);
+
+	hdq_data->hdq_usecount = 0;
+	hdq_data->rrw = 0;
+	mutex_init(&hdq_data->hdq_mutex);
+
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n");
+		goto err_w1;
+	}
+
+	ret = _omap_hdq_reset(hdq_data);
+	if (ret) {
+		dev_dbg(&pdev->dev, "reset failed\n");
+		goto err_irq;
+	}
+
+	rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
+	dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
+		(rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt");
+
+	spin_lock_init(&hdq_data->hdq_spinlock);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq	< 0) {
+		dev_dbg(&pdev->dev, "Failed to get IRQ: %d\n", irq);
+		ret = irq;
+		goto err_irq;
+	}
+
+	ret = devm_request_irq(dev, irq, hdq_isr, 0, "omap_hdq", hdq_data);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "could not request irq\n");
+		goto err_irq;
+	}
+
+	omap_hdq_break(hdq_data);
+
+	pm_runtime_put_sync(&pdev->dev);
+
+	ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode);
+	if (ret < 0 || !strcmp(mode, "hdq")) {
+		hdq_data->mode = 0;
+		omap_w1_master.search = omap_w1_search_bus;
+	} else {
+		hdq_data->mode = 1;
+		omap_w1_master.triplet = omap_w1_triplet;
+	}
+
+	omap_w1_master.data = hdq_data;
+
+	ret = w1_add_master_device(&omap_w1_master);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Failure in registering w1 master\n");
+		goto err_w1;
+	}
+
+	return 0;
+
+err_irq:
+	pm_runtime_put_sync(&pdev->dev);
+err_w1:
+	pm_runtime_disable(&pdev->dev);
+
+	return ret;
+}
+
+static int omap_hdq_remove(struct platform_device *pdev)
+{
+	struct hdq_data *hdq_data = platform_get_drvdata(pdev);
+
+	mutex_lock(&hdq_data->hdq_mutex);
+
+	if (hdq_data->hdq_usecount) {
+		dev_dbg(&pdev->dev, "removed when use count is not zero\n");
+		mutex_unlock(&hdq_data->hdq_mutex);
+		return -EBUSY;
+	}
+
+	mutex_unlock(&hdq_data->hdq_mutex);
+
+	/* remove module dependency */
+	pm_runtime_disable(&pdev->dev);
+
+	w1_remove_master_device(&omap_w1_master);
+
+	return 0;
+}
+
+static const struct of_device_id omap_hdq_dt_ids[] = {
+	{ .compatible = "ti,omap3-1w" },
+	{ .compatible = "ti,am4372-hdq" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, omap_hdq_dt_ids);
+
+static struct platform_driver omap_hdq_driver = {
+	.probe = omap_hdq_probe,
+	.remove = omap_hdq_remove,
+	.driver = {
+		.name =	"omap_hdq",
+		.of_match_table = omap_hdq_dt_ids,
+	},
+};
+module_platform_driver(omap_hdq_driver);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("HDQ-1W driver Library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
new file mode 100644
index 0000000..55e11bf
--- /dev/null
+++ b/drivers/w1/masters/w1-gpio.c
@@ -0,0 +1,209 @@
+/*
+ * w1-gpio - GPIO w1 bus master driver
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/w1-gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+
+#include <linux/w1.h>
+
+static u8 w1_gpio_set_pullup(void *data, int delay)
+{
+	struct w1_gpio_platform_data *pdata = data;
+
+	if (delay) {
+		pdata->pullup_duration = delay;
+	} else {
+		if (pdata->pullup_duration) {
+			/*
+			 * This will OVERRIDE open drain emulation and force-pull
+			 * the line high for some time.
+			 */
+			gpiod_set_raw_value(pdata->gpiod, 1);
+			msleep(pdata->pullup_duration);
+			/*
+			 * This will simply set the line as input since we are doing
+			 * open drain emulation in the GPIO library.
+			 */
+			gpiod_set_value(pdata->gpiod, 1);
+		}
+		pdata->pullup_duration = 0;
+	}
+
+	return 0;
+}
+
+static void w1_gpio_write_bit(void *data, u8 bit)
+{
+	struct w1_gpio_platform_data *pdata = data;
+
+	gpiod_set_value(pdata->gpiod, bit);
+}
+
+static u8 w1_gpio_read_bit(void *data)
+{
+	struct w1_gpio_platform_data *pdata = data;
+
+	return gpiod_get_value(pdata->gpiod) ? 1 : 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id w1_gpio_dt_ids[] = {
+	{ .compatible = "w1-gpio" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
+#endif
+
+static int w1_gpio_probe(struct platform_device *pdev)
+{
+	struct w1_bus_master *master;
+	struct w1_gpio_platform_data *pdata;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	/* Enforce open drain mode by default */
+	enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
+	int err;
+
+	if (of_have_populated_dt()) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		/*
+		 * This parameter means that something else than the gpiolib has
+		 * already set the line into open drain mode, so we should just
+		 * driver it high/low like we are in full control of the line and
+		 * open drain will happen transparently.
+		 */
+		if (of_get_property(np, "linux,open-drain", NULL))
+			gflags = GPIOD_OUT_LOW;
+
+		pdev->dev.platform_data = pdata;
+	}
+	pdata = dev_get_platdata(dev);
+
+	if (!pdata) {
+		dev_err(dev, "No configuration data\n");
+		return -ENXIO;
+	}
+
+	master = devm_kzalloc(dev, sizeof(struct w1_bus_master),
+			GFP_KERNEL);
+	if (!master) {
+		dev_err(dev, "Out of memory\n");
+		return -ENOMEM;
+	}
+
+	pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags);
+	if (IS_ERR(pdata->gpiod)) {
+		dev_err(dev, "gpio_request (pin) failed\n");
+		return PTR_ERR(pdata->gpiod);
+	}
+
+	pdata->pullup_gpiod =
+		devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW);
+	if (IS_ERR(pdata->pullup_gpiod)) {
+		dev_err(dev, "gpio_request_one "
+			"(ext_pullup_enable_pin) failed\n");
+		return PTR_ERR(pdata->pullup_gpiod);
+	}
+
+	master->data = pdata;
+	master->read_bit = w1_gpio_read_bit;
+	gpiod_direction_output(pdata->gpiod, 1);
+	master->write_bit = w1_gpio_write_bit;
+
+	/*
+	 * If we are using open drain emulation from the GPIO library,
+	 * we need to use this pullup function that hammers the line
+	 * high using a raw accessor to provide pull-up for the w1
+	 * line.
+	 */
+	if (gflags == GPIOD_OUT_LOW_OPEN_DRAIN)
+		master->set_pullup = w1_gpio_set_pullup;
+
+	err = w1_add_master_device(master);
+	if (err) {
+		dev_err(dev, "w1_add_master device failed\n");
+		return err;
+	}
+
+	if (pdata->enable_external_pullup)
+		pdata->enable_external_pullup(1);
+
+	if (pdata->pullup_gpiod)
+		gpiod_set_value(pdata->pullup_gpiod, 1);
+
+	platform_set_drvdata(pdev, master);
+
+	return 0;
+}
+
+static int w1_gpio_remove(struct platform_device *pdev)
+{
+	struct w1_bus_master *master = platform_get_drvdata(pdev);
+	struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+	if (pdata->enable_external_pullup)
+		pdata->enable_external_pullup(0);
+
+	if (pdata->pullup_gpiod)
+		gpiod_set_value(pdata->pullup_gpiod, 0);
+
+	w1_remove_master_device(master);
+
+	return 0;
+}
+
+static int __maybe_unused w1_gpio_suspend(struct device *dev)
+{
+	struct w1_gpio_platform_data *pdata = dev_get_platdata(dev);
+
+	if (pdata->enable_external_pullup)
+		pdata->enable_external_pullup(0);
+
+	return 0;
+}
+
+static int __maybe_unused w1_gpio_resume(struct device *dev)
+{
+	struct w1_gpio_platform_data *pdata = dev_get_platdata(dev);
+
+	if (pdata->enable_external_pullup)
+		pdata->enable_external_pullup(1);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(w1_gpio_pm_ops, w1_gpio_suspend, w1_gpio_resume);
+
+static struct platform_driver w1_gpio_driver = {
+	.driver = {
+		.name	= "w1-gpio",
+		.pm	= &w1_gpio_pm_ops,
+		.of_match_table = of_match_ptr(w1_gpio_dt_ids),
+	},
+	.probe = w1_gpio_probe,
+	.remove = w1_gpio_remove,
+};
+
+module_platform_driver(w1_gpio_driver);
+
+MODULE_DESCRIPTION("GPIO w1 bus master driver");
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
new file mode 100644
index 0000000..e22fded
--- /dev/null
+++ b/drivers/w1/slaves/Kconfig
@@ -0,0 +1,154 @@
+#
+# 1-wire slaves configuration
+#
+
+menu "1-wire Slaves"
+
+config W1_SLAVE_THERM
+	tristate "Thermal family implementation"
+	help
+	  Say Y here if you want to connect 1-wire thermal sensors to your
+	  wire.
+
+config W1_SLAVE_SMEM
+	tristate "Simple 64bit memory family implementation"
+	help
+	  Say Y here if you want to connect 1-wire
+	  simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
+
+config W1_SLAVE_DS2405
+	tristate "DS2405 Addressable Switch"
+	help
+	  Say Y or M here if you want to use a DS2405 1-wire
+	  single-channel addressable switch.
+	  This device can also work as a single-channel
+	  binary remote sensor.
+
+config W1_SLAVE_DS2408
+	tristate "8-Channel Addressable Switch (IO Expander) 0x29 family support (DS2408)"
+	help
+	  Say Y here if you want to use a 1-wire
+	  DS2408 8-Channel Addressable Switch device support
+
+config W1_SLAVE_DS2408_READBACK
+	bool "Read-back values written to DS2408's output register"
+	depends on W1_SLAVE_DS2408
+	default y
+	help
+	  Enabling this will cause the driver to read back the values written
+	  to the chip's output register in order to detect errors.
+
+	  This is slower but useful when debugging chips and/or busses.
+
+config W1_SLAVE_DS2413
+	tristate "Dual Channel Addressable Switch 0x3a family support (DS2413)"
+	help
+	  Say Y here if you want to use a 1-wire
+	  DS2413 Dual Channel Addressable Switch device support
+
+config W1_SLAVE_DS2406
+	tristate "Dual Channel Addressable Switch 0x12 family support (DS2406)"
+	select CRC16
+	help
+	  Say Y or M here if you want to use a 1-wire
+	  DS2406 Dual Channel Addressable Switch.  EPROM read/write
+	  support for these devices is not implemented.
+
+config W1_SLAVE_DS2423
+	tristate "Counter 1-wire device (DS2423)"
+	select CRC16
+	help
+	  If you enable this you can read the counter values available
+	  in the DS2423 chipset from the w1_slave file under the
+	  sys file system.
+
+	  Say Y here if you want to use a 1-wire
+	  counter family device (DS2423).
+
+config W1_SLAVE_DS2805
+	tristate "112-byte EEPROM support (DS28E05)"
+	help
+	  Say Y here if you want to use a 1-wire
+	  is a 112-byte user-programmable EEPROM is
+          organized as 7 pages of 16 bytes each with 64bit
+          unique number. Requires OverDrive Speed to talk to.
+
+config W1_SLAVE_DS2431
+	tristate "1kb EEPROM family support (DS2431)"
+	help
+	  Say Y here if you want to use a 1-wire
+	  1kb EEPROM family device (DS2431)
+
+config W1_SLAVE_DS2433
+	tristate "4kb EEPROM family support (DS2433)"
+	help
+	  Say Y here if you want to use a 1-wire
+	  4kb EEPROM family device (DS2433).
+
+config W1_SLAVE_DS2433_CRC
+	bool "Protect DS2433 data with a CRC16"
+	depends on W1_SLAVE_DS2433
+	select CRC16
+	help
+	  Say Y here to protect DS2433 data with a CRC16.
+	  Each block has 30 bytes of data and a two byte CRC16.
+	  Full block writes are only allowed if the CRC is valid.
+
+config W1_SLAVE_DS2438
+	tristate "DS2438 Smart Battery Monitor 0x26 family support"
+	help
+	  Say Y here if you want to use a 1-wire
+	  DS2438 Smart Battery Monitor device support
+
+config W1_SLAVE_DS2780
+	tristate "Dallas 2780 battery monitor chip"
+	help
+	  If you enable this you will have the DS2780 battery monitor
+	  chip support.
+
+	  The battery monitor chip is used in many batteries/devices
+	  as the one who is responsible for charging/discharging/monitoring
+	  Li+ batteries.
+
+	  If you are unsure, say N.
+
+config W1_SLAVE_DS2781
+	tristate "Dallas 2781 battery monitor chip"
+	help
+	  If you enable this you will have the DS2781 battery monitor
+	  chip support.
+
+	  The battery monitor chip is used in many batteries/devices
+	  as the one who is responsible for charging/discharging/monitoring
+	  Li+ batteries.
+
+	  If you are unsure, say N.
+
+config W1_SLAVE_DS28E04
+	tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
+	select CRC16
+	help
+	  If you enable this you will have the DS28E04-100
+	  chip support.
+
+	  Say Y here if you want to use a 1-wire
+	  4kb EEPROM with PIO family device (DS28E04).
+
+	  If you are unsure, say N.
+
+config W1_SLAVE_DS28E17
+	tristate "1-wire-to-I2C master bridge (DS28E17)"
+	select CRC16
+	depends on I2C
+	help
+	  Say Y here if you want to use the DS28E17 1-wire-to-I2C master bridge.
+	  For each DS28E17 detected, a new I2C adapter is created within the
+	  kernel. I2C devices on that bus can be configured to be used by the
+	  kernel and userspace tools as on any other "native" I2C bus.
+
+	  This driver is also available as a module. If so, the module
+	  will be called w1_ds28e17.
+
+	  If you are unsure, say N.
+
+endmenu
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
new file mode 100644
index 0000000..eab29f1
--- /dev/null
+++ b/drivers/w1/slaves/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Dallas's 1-wire slaves.
+#
+
+obj-$(CONFIG_W1_SLAVE_THERM)	+= w1_therm.o
+obj-$(CONFIG_W1_SLAVE_SMEM)	+= w1_smem.o
+obj-$(CONFIG_W1_SLAVE_DS2405)	+= w1_ds2405.o
+obj-$(CONFIG_W1_SLAVE_DS2408)	+= w1_ds2408.o
+obj-$(CONFIG_W1_SLAVE_DS2413)	+= w1_ds2413.o
+obj-$(CONFIG_W1_SLAVE_DS2406)	+= w1_ds2406.o
+obj-$(CONFIG_W1_SLAVE_DS2423)	+= w1_ds2423.o
+obj-$(CONFIG_W1_SLAVE_DS2431)	+= w1_ds2431.o
+obj-$(CONFIG_W1_SLAVE_DS2805)	+= w1_ds2805.o
+obj-$(CONFIG_W1_SLAVE_DS2433)	+= w1_ds2433.o
+obj-$(CONFIG_W1_SLAVE_DS2438)	+= w1_ds2438.o
+obj-$(CONFIG_W1_SLAVE_DS2780)	+= w1_ds2780.o
+obj-$(CONFIG_W1_SLAVE_DS2781)	+= w1_ds2781.o
+obj-$(CONFIG_W1_SLAVE_DS28E04)	+= w1_ds28e04.o
+obj-$(CONFIG_W1_SLAVE_DS28E17)	+= w1_ds28e17.o
diff --git a/drivers/w1/slaves/w1_ds2405.c b/drivers/w1/slaves/w1_ds2405.c
new file mode 100644
index 0000000..42a1e81
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2405.c
@@ -0,0 +1,228 @@
+/*
+ *	w1_ds2405.c
+ *
+ * Copyright (c) 2017 Maciej S. Szmigiero <mail@maciej.szmigiero.name>
+ * Based on w1_therm.c copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the therms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_DS2405	0x05
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas DS2405 PIO.");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2405));
+
+static int w1_ds2405_select(struct w1_slave *sl, bool only_active)
+{
+	struct w1_master *dev = sl->master;
+
+	u64 dev_addr = le64_to_cpu(*(u64 *)&sl->reg_num);
+	unsigned int bit_ctr;
+
+	if (w1_reset_bus(dev) != 0)
+		return 0;
+
+	/*
+	 * We cannot use a normal Match ROM command
+	 * since doing so would toggle PIO state
+	 */
+	w1_write_8(dev, only_active ? W1_ALARM_SEARCH : W1_SEARCH);
+
+	for (bit_ctr = 0; bit_ctr < 64; bit_ctr++) {
+		int bit2send = !!(dev_addr & BIT(bit_ctr));
+		u8 ret;
+
+		ret = w1_triplet(dev, bit2send);
+
+		if ((ret & (BIT(0) | BIT(1))) ==
+		    (BIT(0) | BIT(1))) /* no devices found */
+			return 0;
+
+		if (!!(ret & BIT(2)) != bit2send)
+			/* wrong direction taken - no such device */
+			return 0;
+	}
+
+	return 1;
+}
+
+static int w1_ds2405_read_pio(struct w1_slave *sl)
+{
+	if (w1_ds2405_select(sl, true))
+		return 0; /* "active" means PIO is low */
+
+	if (w1_ds2405_select(sl, false))
+		return 1;
+
+	return -ENODEV;
+}
+
+static ssize_t state_show(struct device *device,
+			  struct device_attribute *attr, char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	struct w1_master *dev = sl->master;
+
+	int ret;
+	ssize_t f_retval;
+	u8 state;
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret)
+		return ret;
+
+	if (!w1_ds2405_select(sl, false)) {
+		f_retval = -ENODEV;
+		goto out_unlock;
+	}
+
+	state = w1_read_8(dev);
+	if (state != 0 &&
+	    state != 0xff) {
+		dev_err(device, "non-consistent state %x\n", state);
+		f_retval = -EIO;
+		goto out_unlock;
+	}
+
+	*buf = state ? '1' : '0';
+	f_retval = 1;
+
+out_unlock:
+	w1_reset_bus(dev);
+	mutex_unlock(&dev->bus_mutex);
+
+	return f_retval;
+}
+
+static ssize_t output_show(struct device *device,
+			   struct device_attribute *attr, char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	struct w1_master *dev = sl->master;
+
+	int ret;
+	ssize_t f_retval;
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret)
+		return ret;
+
+	ret = w1_ds2405_read_pio(sl);
+	if (ret < 0) {
+		f_retval = ret;
+		goto out_unlock;
+	}
+
+	*buf = ret ? '1' : '0';
+	f_retval = 1;
+
+out_unlock:
+	w1_reset_bus(dev);
+	mutex_unlock(&dev->bus_mutex);
+
+	return f_retval;
+}
+
+static ssize_t output_store(struct device *device,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	struct w1_master *dev = sl->master;
+
+	int ret, current_pio;
+	unsigned int val;
+	ssize_t f_retval;
+
+	if (count < 1)
+		return -EINVAL;
+
+	if (sscanf(buf, " %u%n", &val, &ret) < 1)
+		return -EINVAL;
+
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	f_retval = ret;
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret)
+		return ret;
+
+	current_pio = w1_ds2405_read_pio(sl);
+	if (current_pio < 0) {
+		f_retval = current_pio;
+		goto out_unlock;
+	}
+
+	if (current_pio == val)
+		goto out_unlock;
+
+	if (w1_reset_bus(dev) != 0) {
+		f_retval = -ENODEV;
+		goto out_unlock;
+	}
+
+	/*
+	 * can't use w1_reset_select_slave() here since it uses Skip ROM if
+	 * there is only one device on bus
+	 */
+	do {
+		u64 dev_addr = le64_to_cpu(*(u64 *)&sl->reg_num);
+		u8 cmd[9];
+
+		cmd[0] = W1_MATCH_ROM;
+		memcpy(&cmd[1], &dev_addr, sizeof(dev_addr));
+
+		w1_write_block(dev, cmd, sizeof(cmd));
+	} while (0);
+
+out_unlock:
+	w1_reset_bus(dev);
+	mutex_unlock(&dev->bus_mutex);
+
+	return f_retval;
+}
+
+static DEVICE_ATTR_RO(state);
+static DEVICE_ATTR_RW(output);
+
+static struct attribute *w1_ds2405_attrs[] = {
+	&dev_attr_state.attr,
+	&dev_attr_output.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(w1_ds2405);
+
+static struct w1_family_ops w1_ds2405_fops = {
+	.groups = w1_ds2405_groups
+};
+
+static struct w1_family w1_family_ds2405 = {
+	.fid = W1_FAMILY_DS2405,
+	.fops = &w1_ds2405_fops
+};
+
+module_w1_family(w1_family_ds2405);
diff --git a/drivers/w1/slaves/w1_ds2406.c b/drivers/w1/slaves/w1_ds2406.c
new file mode 100644
index 0000000..fac2663
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2406.c
@@ -0,0 +1,156 @@
+/*
+ * w1_ds2406.c - w1 family 12 (DS2406) driver
+ * based on w1_ds2413.c by Mariusz Bialonczyk <manio@skyboo.net>
+ *
+ * Copyright (c) 2014 Scott Alfter <scott@alfter.us>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/crc16.h>
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_DS2406	0x12
+
+#define W1_F12_FUNC_READ_STATUS		   0xAA
+#define W1_F12_FUNC_WRITE_STATUS	   0x55
+
+static ssize_t w1_f12_read_state(
+	struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr,
+	char *buf, loff_t off, size_t count)
+{
+	u8 w1_buf[6]={W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0};
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	u16 crc=0;
+	int i;
+	ssize_t rtnval=1;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_reset_select_slave(sl)) {
+		mutex_unlock(&sl->master->bus_mutex);
+		return -EIO;
+	}
+
+	w1_write_block(sl->master, w1_buf, 3);
+	w1_read_block(sl->master, w1_buf+3, 3);
+	for (i=0; i<6; i++)
+		crc=crc16_byte(crc, w1_buf[i]);
+	if (crc==0xb001) /* good read? */
+		*buf=((w1_buf[3]>>5)&3)|0x30;
+	else
+		rtnval=-EIO;
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return rtnval;
+}
+
+static ssize_t w1_f12_write_output(
+	struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr,
+	char *buf, loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	u8 w1_buf[6]={W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0};
+	u16 crc=0;
+	int i;
+	ssize_t rtnval=1;
+
+	if (count != 1 || off != 0)
+		return -EFAULT;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_reset_select_slave(sl)) {
+		mutex_unlock(&sl->master->bus_mutex);
+		return -EIO;
+	}
+
+	w1_buf[3] = (((*buf)&3)<<5)|0x1F;
+	w1_write_block(sl->master, w1_buf, 4);
+	w1_read_block(sl->master, w1_buf+4, 2);
+	for (i=0; i<6; i++)
+		crc=crc16_byte(crc, w1_buf[i]);
+	if (crc==0xb001) /* good read? */
+		w1_write_8(sl->master, 0xFF);
+	else
+		rtnval=-EIO;
+
+	mutex_unlock(&sl->master->bus_mutex);
+	return rtnval;
+}
+
+#define NB_SYSFS_BIN_FILES 2
+static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
+	{
+		.attr = {
+			.name = "state",
+			.mode = S_IRUGO,
+		},
+		.size = 1,
+		.read = w1_f12_read_state,
+	},
+	{
+		.attr = {
+			.name = "output",
+			.mode = S_IRUGO | S_IWUSR | S_IWGRP,
+		},
+		.size = 1,
+		.write = w1_f12_write_output,
+	}
+};
+
+static int w1_f12_add_slave(struct w1_slave *sl)
+{
+	int err = 0;
+	int i;
+
+	for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+		err = sysfs_create_bin_file(
+			&sl->dev.kobj,
+			&(w1_f12_sysfs_bin_files[i]));
+	if (err)
+		while (--i >= 0)
+			sysfs_remove_bin_file(&sl->dev.kobj,
+				&(w1_f12_sysfs_bin_files[i]));
+	return err;
+}
+
+static void w1_f12_remove_slave(struct w1_slave *sl)
+{
+	int i;
+	for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
+		sysfs_remove_bin_file(&sl->dev.kobj,
+			&(w1_f12_sysfs_bin_files[i]));
+}
+
+static struct w1_family_ops w1_f12_fops = {
+	.add_slave      = w1_f12_add_slave,
+	.remove_slave   = w1_f12_remove_slave,
+};
+
+static struct w1_family w1_family_12 = {
+	.fid = W1_FAMILY_DS2406,
+	.fops = &w1_f12_fops,
+};
+module_w1_family(w1_family_12);
+
+MODULE_AUTHOR("Scott Alfter <scott@alfter.us>");
+MODULE_DESCRIPTION("w1 family 12 driver for DS2406 2 Pin IO");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
new file mode 100644
index 0000000..b535d5e
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -0,0 +1,353 @@
+/*
+ *	w1_ds2408.c - w1 family 29 (DS2408) driver
+ *
+ * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_DS2408	0x29
+
+#define W1_F29_RETRIES		3
+
+#define W1_F29_REG_LOGIG_STATE             0x88 /* R */
+#define W1_F29_REG_OUTPUT_LATCH_STATE      0x89 /* R */
+#define W1_F29_REG_ACTIVITY_LATCH_STATE    0x8A /* R */
+#define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */
+#define W1_F29_REG_COND_SEARCH_POL_SELECT  0x8C /* RW */
+#define W1_F29_REG_CONTROL_AND_STATUS      0x8D /* RW */
+
+#define W1_F29_FUNC_READ_PIO_REGS          0xF0
+#define W1_F29_FUNC_CHANN_ACCESS_READ      0xF5
+#define W1_F29_FUNC_CHANN_ACCESS_WRITE     0x5A
+/* also used to write the control/status reg (0x8D): */
+#define W1_F29_FUNC_WRITE_COND_SEARCH_REG  0xCC
+#define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3
+
+#define W1_F29_SUCCESS_CONFIRM_BYTE        0xAA
+
+static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
+{
+	u8 wrbuf[3];
+	dev_dbg(&sl->dev,
+			"Reading with slave: %p, reg addr: %0#4x, buff addr: %p",
+			sl, (unsigned int)address, buf);
+
+	if (!buf)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex locked");
+
+	if (w1_reset_select_slave(sl)) {
+		mutex_unlock(&sl->master->bus_mutex);
+		return -EIO;
+	}
+
+	wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;
+	wrbuf[1] = address;
+	wrbuf[2] = 0;
+	w1_write_block(sl->master, wrbuf, 3);
+	*buf = w1_read_8(sl->master);
+
+	mutex_unlock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex unlocked");
+	return 1;
+}
+
+static ssize_t state_read(struct file *filp, struct kobject *kobj,
+			  struct bin_attribute *bin_attr, char *buf, loff_t off,
+			  size_t count)
+{
+	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+	if (count != 1 || off != 0)
+		return -EFAULT;
+	return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
+}
+
+static ssize_t output_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
+{
+	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+	if (count != 1 || off != 0)
+		return -EFAULT;
+	return _read_reg(kobj_to_w1_slave(kobj),
+					 W1_F29_REG_OUTPUT_LATCH_STATE, buf);
+}
+
+static ssize_t activity_read(struct file *filp, struct kobject *kobj,
+			     struct bin_attribute *bin_attr, char *buf,
+			     loff_t off, size_t count)
+{
+	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+	if (count != 1 || off != 0)
+		return -EFAULT;
+	return _read_reg(kobj_to_w1_slave(kobj),
+					 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
+}
+
+static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *bin_attr, char *buf,
+				     loff_t off, size_t count)
+{
+	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+	if (count != 1 || off != 0)
+		return -EFAULT;
+	return _read_reg(kobj_to_w1_slave(kobj),
+		W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
+}
+
+static ssize_t cond_search_polarity_read(struct file *filp,
+					 struct kobject *kobj,
+					 struct bin_attribute *bin_attr,
+					 char *buf, loff_t off, size_t count)
+{
+	if (count != 1 || off != 0)
+		return -EFAULT;
+	return _read_reg(kobj_to_w1_slave(kobj),
+		W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
+}
+
+static ssize_t status_control_read(struct file *filp, struct kobject *kobj,
+				   struct bin_attribute *bin_attr, char *buf,
+				   loff_t off, size_t count)
+{
+	if (count != 1 || off != 0)
+		return -EFAULT;
+	return _read_reg(kobj_to_w1_slave(kobj),
+		W1_F29_REG_CONTROL_AND_STATUS, buf);
+}
+
+static ssize_t output_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	u8 w1_buf[3];
+	u8 readBack;
+	unsigned int retries = W1_F29_RETRIES;
+
+	if (count != 1 || off != 0)
+		return -EFAULT;
+
+	dev_dbg(&sl->dev, "locking mutex for write_output");
+	mutex_lock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex locked");
+
+	if (w1_reset_select_slave(sl))
+		goto error;
+
+	while (retries--) {
+		w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
+		w1_buf[1] = *buf;
+		w1_buf[2] = ~(*buf);
+		w1_write_block(sl->master, w1_buf, 3);
+
+		readBack = w1_read_8(sl->master);
+
+		if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
+			if (w1_reset_resume_command(sl->master))
+				goto error;
+			/* try again, the slave is ready for a command */
+			continue;
+		}
+
+#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
+		/* here the master could read another byte which
+		   would be the PIO reg (the actual pin logic state)
+		   since in this driver we don't know which pins are
+		   in and outs, there's no value to read the state and
+		   compare. with (*buf) so end this command abruptly: */
+		if (w1_reset_resume_command(sl->master))
+			goto error;
+
+		/* go read back the output latches */
+		/* (the direct effect of the write above) */
+		w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
+		w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
+		w1_buf[2] = 0;
+		w1_write_block(sl->master, w1_buf, 3);
+		/* read the result of the READ_PIO_REGS command */
+		if (w1_read_8(sl->master) == *buf)
+#endif
+		{
+			/* success! */
+			mutex_unlock(&sl->master->bus_mutex);
+			dev_dbg(&sl->dev,
+				"mutex unlocked, retries:%d", retries);
+			return 1;
+		}
+	}
+error:
+	mutex_unlock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
+
+	return -EIO;
+}
+
+
+/**
+ * Writing to the activity file resets the activity latches.
+ */
+static ssize_t activity_write(struct file *filp, struct kobject *kobj,
+			      struct bin_attribute *bin_attr, char *buf,
+			      loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	unsigned int retries = W1_F29_RETRIES;
+
+	if (count != 1 || off != 0)
+		return -EFAULT;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_reset_select_slave(sl))
+		goto error;
+
+	while (retries--) {
+		w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
+		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
+			mutex_unlock(&sl->master->bus_mutex);
+			return 1;
+		}
+		if (w1_reset_resume_command(sl->master))
+			goto error;
+	}
+
+error:
+	mutex_unlock(&sl->master->bus_mutex);
+	return -EIO;
+}
+
+static ssize_t status_control_write(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *bin_attr, char *buf,
+				    loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	u8 w1_buf[4];
+	unsigned int retries = W1_F29_RETRIES;
+
+	if (count != 1 || off != 0)
+		return -EFAULT;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_reset_select_slave(sl))
+		goto error;
+
+	while (retries--) {
+		w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
+		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
+		w1_buf[2] = 0;
+		w1_buf[3] = *buf;
+
+		w1_write_block(sl->master, w1_buf, 4);
+		if (w1_reset_resume_command(sl->master))
+			goto error;
+
+		w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
+		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
+		w1_buf[2] = 0;
+
+		w1_write_block(sl->master, w1_buf, 3);
+		if (w1_read_8(sl->master) == *buf) {
+			/* success! */
+			mutex_unlock(&sl->master->bus_mutex);
+			return 1;
+		}
+	}
+error:
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return -EIO;
+}
+
+/*
+ * This is a special sequence we must do to ensure the P0 output is not stuck
+ * in test mode. This is described in rev 2 of the ds2408's datasheet
+ * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under
+ * "APPLICATION INFORMATION/Power-up timing".
+ */
+static int w1_f29_disable_test_mode(struct w1_slave *sl)
+{
+	int res;
+	u8 magic[10] = {0x96, };
+	u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
+
+	memcpy(&magic[1], &rn, 8);
+	magic[9] = 0x3C;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	res = w1_reset_bus(sl->master);
+	if (res)
+		goto out;
+	w1_write_block(sl->master, magic, ARRAY_SIZE(magic));
+
+	res = w1_reset_bus(sl->master);
+out:
+	mutex_unlock(&sl->master->bus_mutex);
+	return res;
+}
+
+static BIN_ATTR_RO(state, 1);
+static BIN_ATTR_RW(output, 1);
+static BIN_ATTR_RW(activity, 1);
+static BIN_ATTR_RO(cond_search_mask, 1);
+static BIN_ATTR_RO(cond_search_polarity, 1);
+static BIN_ATTR_RW(status_control, 1);
+
+static struct bin_attribute *w1_f29_bin_attrs[] = {
+	&bin_attr_state,
+	&bin_attr_output,
+	&bin_attr_activity,
+	&bin_attr_cond_search_mask,
+	&bin_attr_cond_search_polarity,
+	&bin_attr_status_control,
+	NULL,
+};
+
+static const struct attribute_group w1_f29_group = {
+	.bin_attrs = w1_f29_bin_attrs,
+};
+
+static const struct attribute_group *w1_f29_groups[] = {
+	&w1_f29_group,
+	NULL,
+};
+
+static struct w1_family_ops w1_f29_fops = {
+	.add_slave      = w1_f29_disable_test_mode,
+	.groups		= w1_f29_groups,
+};
+
+static struct w1_family w1_family_29 = {
+	.fid = W1_FAMILY_DS2408,
+	.fops = &w1_f29_fops,
+};
+module_w1_family(w1_family_29);
+
+MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");
+MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2408));
diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c
new file mode 100644
index 0000000..492e3d0
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2413.c
@@ -0,0 +1,138 @@
+/*
+ * w1_ds2413.c - w1 family 3a (DS2413) driver
+ * based on w1_ds2408.c by Jean-Francois Dagenais <dagenaisj@sonatest.com>
+ *
+ * Copyright (c) 2013 Mariusz Bialonczyk <manio@skyboo.net>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_DS2413	0x3A
+
+#define W1_F3A_RETRIES                     3
+#define W1_F3A_FUNC_PIO_ACCESS_READ        0xF5
+#define W1_F3A_FUNC_PIO_ACCESS_WRITE       0x5A
+#define W1_F3A_SUCCESS_CONFIRM_BYTE        0xAA
+
+static ssize_t state_read(struct file *filp, struct kobject *kobj,
+			  struct bin_attribute *bin_attr, char *buf, loff_t off,
+			  size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	dev_dbg(&sl->dev,
+		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex locked");
+
+	if (w1_reset_select_slave(sl)) {
+		mutex_unlock(&sl->master->bus_mutex);
+		return -EIO;
+	}
+
+	w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
+	*buf = w1_read_8(sl->master);
+
+	mutex_unlock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex unlocked");
+
+	/* check for correct complement */
+	if ((*buf & 0x0F) != ((~*buf >> 4) & 0x0F))
+		return -EIO;
+	else
+		return 1;
+}
+
+static BIN_ATTR_RO(state, 1);
+
+static ssize_t output_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	u8 w1_buf[3];
+	unsigned int retries = W1_F3A_RETRIES;
+
+	if (count != 1 || off != 0)
+		return -EFAULT;
+
+	dev_dbg(&sl->dev, "locking mutex for write_output");
+	mutex_lock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex locked");
+
+	if (w1_reset_select_slave(sl))
+		goto error;
+
+	/* according to the DS2413 datasheet the most significant 6 bits
+	   should be set to "1"s, so do it now */
+	*buf = *buf | 0xFC;
+
+	while (retries--) {
+		w1_buf[0] = W1_F3A_FUNC_PIO_ACCESS_WRITE;
+		w1_buf[1] = *buf;
+		w1_buf[2] = ~(*buf);
+		w1_write_block(sl->master, w1_buf, 3);
+
+		if (w1_read_8(sl->master) == W1_F3A_SUCCESS_CONFIRM_BYTE) {
+			mutex_unlock(&sl->master->bus_mutex);
+			dev_dbg(&sl->dev, "mutex unlocked, retries:%d", retries);
+			return 1;
+		}
+		if (w1_reset_resume_command(sl->master))
+			goto error;
+	}
+
+error:
+	mutex_unlock(&sl->master->bus_mutex);
+	dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
+	return -EIO;
+}
+
+static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1);
+
+static struct bin_attribute *w1_f3a_bin_attrs[] = {
+	&bin_attr_state,
+	&bin_attr_output,
+	NULL,
+};
+
+static const struct attribute_group w1_f3a_group = {
+	.bin_attrs = w1_f3a_bin_attrs,
+};
+
+static const struct attribute_group *w1_f3a_groups[] = {
+	&w1_f3a_group,
+	NULL,
+};
+
+static struct w1_family_ops w1_f3a_fops = {
+	.groups		= w1_f3a_groups,
+};
+
+static struct w1_family w1_family_3a = {
+	.fid = W1_FAMILY_DS2413,
+	.fops = &w1_f3a_fops,
+};
+module_w1_family(w1_family_3a);
+
+MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>");
+MODULE_DESCRIPTION("w1 family 3a driver for DS2413 2 Pin IO");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2413));
diff --git a/drivers/w1/slaves/w1_ds2423.c b/drivers/w1/slaves/w1_ds2423.c
new file mode 100644
index 0000000..050407c
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2423.c
@@ -0,0 +1,146 @@
+/*
+ *	w1_ds2423.c
+ *
+ * Copyright (c) 2010 Mika Laitio <lamikr@pilppa.org>
+ *
+ * This driver will read and write the value of 4 counters to w1_slave file in
+ * sys filesystem.
+ * Inspired by the w1_therm and w1_ds2431 drivers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the therms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/crc16.h>
+
+#include <linux/w1.h>
+
+#define W1_COUNTER_DS2423	0x1D
+
+#define CRC16_VALID	0xb001
+#define CRC16_INIT	0
+
+#define COUNTER_COUNT 4
+#define READ_BYTE_COUNT 42
+
+static ssize_t w1_slave_show(struct device *device,
+			     struct device_attribute *attr, char *out_buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	struct w1_master *dev = sl->master;
+	u8 rbuf[COUNTER_COUNT * READ_BYTE_COUNT];
+	u8 wrbuf[3];
+	int rom_addr;
+	int read_byte_count;
+	int result;
+	ssize_t c;
+	int ii;
+	int p;
+	int crc;
+
+	c		= PAGE_SIZE;
+	rom_addr	= (12 << 5) + 31;
+	wrbuf[0]	= 0xA5;
+	wrbuf[1]	= rom_addr & 0xFF;
+	wrbuf[2]	= rom_addr >> 8;
+	mutex_lock(&dev->bus_mutex);
+	if (!w1_reset_select_slave(sl)) {
+		w1_write_block(dev, wrbuf, 3);
+		read_byte_count = 0;
+		for (p = 0; p < 4; p++) {
+			/*
+			 * 1 byte for first bytes in ram page read
+			 * 4 bytes for counter
+			 * 4 bytes for zero bits
+			 * 2 bytes for crc
+			 * 31 remaining bytes from the ram page
+			 */
+			read_byte_count += w1_read_block(dev,
+				rbuf + (p * READ_BYTE_COUNT), READ_BYTE_COUNT);
+			for (ii = 0; ii < READ_BYTE_COUNT; ++ii)
+				c -= snprintf(out_buf + PAGE_SIZE - c,
+					c, "%02x ",
+					rbuf[(p * READ_BYTE_COUNT) + ii]);
+			if (read_byte_count != (p + 1) * READ_BYTE_COUNT) {
+				dev_warn(device,
+					"w1_counter_read() returned %u bytes "
+					"instead of %d bytes wanted.\n",
+					read_byte_count,
+					READ_BYTE_COUNT);
+				c -= snprintf(out_buf + PAGE_SIZE - c,
+					c, "crc=NO\n");
+			} else {
+				if (p == 0) {
+					crc = crc16(CRC16_INIT, wrbuf, 3);
+					crc = crc16(crc, rbuf, 11);
+				} else {
+					/*
+					 * DS2423 calculates crc from all bytes
+					 * read after the previous crc bytes.
+					 */
+					crc = crc16(CRC16_INIT,
+						(rbuf + 11) +
+						((p - 1) * READ_BYTE_COUNT),
+						READ_BYTE_COUNT);
+				}
+				if (crc == CRC16_VALID) {
+					result = 0;
+					for (ii = 4; ii > 0; ii--) {
+						result <<= 8;
+						result |= rbuf[(p *
+							READ_BYTE_COUNT) + ii];
+					}
+					c -= snprintf(out_buf + PAGE_SIZE - c,
+						c, "crc=YES c=%d\n", result);
+				} else {
+					c -= snprintf(out_buf + PAGE_SIZE - c,
+						c, "crc=NO\n");
+				}
+			}
+		}
+	} else {
+		c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error");
+	}
+	mutex_unlock(&dev->bus_mutex);
+	return PAGE_SIZE - c;
+}
+
+static DEVICE_ATTR_RO(w1_slave);
+
+static struct attribute *w1_f1d_attrs[] = {
+	&dev_attr_w1_slave.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(w1_f1d);
+
+static struct w1_family_ops w1_f1d_fops = {
+	.groups		= w1_f1d_groups,
+};
+
+static struct w1_family w1_family_1d = {
+	.fid = W1_COUNTER_DS2423,
+	.fops = &w1_f1d_fops,
+};
+module_w1_family(w1_family_1d);
+
+MODULE_AUTHOR("Mika Laitio <lamikr@pilppa.org>");
+MODULE_DESCRIPTION("w1 family 1d driver for DS2423, 4 counters and 4kb ram");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_COUNTER_DS2423));
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
new file mode 100644
index 0000000..5adecd3
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2431.c
@@ -0,0 +1,296 @@
+/*
+ * w1_ds2431.c - w1 family 2d (DS2431) driver
+ *
+ * Copyright (c) 2008 Bernhard Weirich <bernhard.weirich@riedel.net>
+ *
+ * Heavily inspired by w1_DS2433 driver from Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include <linux/w1.h>
+
+#define W1_EEPROM_DS2431	0x2D
+
+#define W1_F2D_EEPROM_SIZE		128
+#define W1_F2D_PAGE_COUNT		4
+#define W1_F2D_PAGE_BITS		5
+#define W1_F2D_PAGE_SIZE		(1<<W1_F2D_PAGE_BITS)
+#define W1_F2D_PAGE_MASK		0x1F
+
+#define W1_F2D_SCRATCH_BITS  3
+#define W1_F2D_SCRATCH_SIZE  (1<<W1_F2D_SCRATCH_BITS)
+#define W1_F2D_SCRATCH_MASK  (W1_F2D_SCRATCH_SIZE-1)
+
+#define W1_F2D_READ_EEPROM	0xF0
+#define W1_F2D_WRITE_SCRATCH	0x0F
+#define W1_F2D_READ_SCRATCH	0xAA
+#define W1_F2D_COPY_SCRATCH	0x55
+
+
+#define W1_F2D_TPROG_MS		11
+
+#define W1_F2D_READ_RETRIES		10
+#define W1_F2D_READ_MAXLEN		8
+
+/*
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f2d_fix_count(loff_t off, size_t count, size_t size)
+{
+	if (off > size)
+		return 0;
+
+	if ((off + count) > size)
+		return size - off;
+
+	return count;
+}
+
+/*
+ * Read a block from W1 ROM two times and compares the results.
+ * If they are equal they are returned, otherwise the read
+ * is repeated W1_F2D_READ_RETRIES times.
+ *
+ * count must not exceed W1_F2D_READ_MAXLEN.
+ */
+static int w1_f2d_readblock(struct w1_slave *sl, int off, int count, char *buf)
+{
+	u8 wrbuf[3];
+	u8 cmp[W1_F2D_READ_MAXLEN];
+	int tries = W1_F2D_READ_RETRIES;
+
+	do {
+		wrbuf[0] = W1_F2D_READ_EEPROM;
+		wrbuf[1] = off & 0xff;
+		wrbuf[2] = off >> 8;
+
+		if (w1_reset_select_slave(sl))
+			return -1;
+
+		w1_write_block(sl->master, wrbuf, 3);
+		w1_read_block(sl->master, buf, count);
+
+		if (w1_reset_select_slave(sl))
+			return -1;
+
+		w1_write_block(sl->master, wrbuf, 3);
+		w1_read_block(sl->master, cmp, count);
+
+		if (!memcmp(cmp, buf, count))
+			return 0;
+	} while (--tries);
+
+	dev_err(&sl->dev, "proof reading failed %d times\n",
+			W1_F2D_READ_RETRIES);
+
+	return -1;
+}
+
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int todo = count;
+
+	count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	/* read directly from the EEPROM in chunks of W1_F2D_READ_MAXLEN */
+	while (todo > 0) {
+		int block_read;
+
+		if (todo >= W1_F2D_READ_MAXLEN)
+			block_read = W1_F2D_READ_MAXLEN;
+		else
+			block_read = todo;
+
+		if (w1_f2d_readblock(sl, off, block_read, buf) < 0)
+			count = -EIO;
+
+		todo -= W1_F2D_READ_MAXLEN;
+		buf += W1_F2D_READ_MAXLEN;
+		off += W1_F2D_READ_MAXLEN;
+	}
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return count;
+}
+
+/*
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be aligned at W1_F2D_SCRATCH_SIZE bytes and
+ * must be W1_F2D_SCRATCH_SIZE bytes long.
+ * The master must be locked.
+ *
+ * @param sl	The slave structure
+ * @param addr	Address for the write
+ * @param len   length must be <= (W1_F2D_PAGE_SIZE - (addr & W1_F2D_PAGE_MASK))
+ * @param data	The data to write
+ * @return	0=Success -1=failure
+ */
+static int w1_f2d_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+	int tries = W1_F2D_READ_RETRIES;
+	u8 wrbuf[4];
+	u8 rdbuf[W1_F2D_SCRATCH_SIZE + 3];
+	u8 es = (addr + len - 1) % W1_F2D_SCRATCH_SIZE;
+
+retry:
+
+	/* Write the data to the scratchpad */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F2D_WRITE_SCRATCH;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_write_block(sl->master, data, len);
+
+	/* Read the scratchpad and verify */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	w1_write_8(sl->master, W1_F2D_READ_SCRATCH);
+	w1_read_block(sl->master, rdbuf, len + 3);
+
+	/* Compare what was read against the data written */
+	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0)) {
+
+		if (--tries)
+			goto retry;
+
+		dev_err(&sl->dev,
+			"could not write to eeprom, scratchpad compare failed %d times\n",
+			W1_F2D_READ_RETRIES);
+
+		return -1;
+	}
+
+	/* Copy the scratchpad to EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F2D_COPY_SCRATCH;
+	wrbuf[3] = es;
+	w1_write_block(sl->master, wrbuf, 4);
+
+	/* Sleep for tprog ms to wait for the write to complete */
+	msleep(W1_F2D_TPROG_MS);
+
+	/* Reset the bus to wake up the EEPROM  */
+	w1_reset_bus(sl->master);
+
+	return 0;
+}
+
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int addr, len;
+	int copy;
+
+	count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	/* Can only write data in blocks of the size of the scratchpad */
+	addr = off;
+	len = count;
+	while (len > 0) {
+
+		/* if len too short or addr not aligned */
+		if (len < W1_F2D_SCRATCH_SIZE || addr & W1_F2D_SCRATCH_MASK) {
+			char tmp[W1_F2D_SCRATCH_SIZE];
+
+			/* read the block and update the parts to be written */
+			if (w1_f2d_readblock(sl, addr & ~W1_F2D_SCRATCH_MASK,
+					W1_F2D_SCRATCH_SIZE, tmp)) {
+				count = -EIO;
+				goto out_up;
+			}
+
+			/* copy at most to the boundary of the PAGE or len */
+			copy = W1_F2D_SCRATCH_SIZE -
+				(addr & W1_F2D_SCRATCH_MASK);
+
+			if (copy > len)
+				copy = len;
+
+			memcpy(&tmp[addr & W1_F2D_SCRATCH_MASK], buf, copy);
+			if (w1_f2d_write(sl, addr & ~W1_F2D_SCRATCH_MASK,
+					W1_F2D_SCRATCH_SIZE, tmp) < 0) {
+				count = -EIO;
+				goto out_up;
+			}
+		} else {
+
+			copy = W1_F2D_SCRATCH_SIZE;
+			if (w1_f2d_write(sl, addr, copy, buf) < 0) {
+				count = -EIO;
+				goto out_up;
+			}
+		}
+		buf += copy;
+		addr += copy;
+		len -= copy;
+	}
+
+out_up:
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return count;
+}
+
+static BIN_ATTR_RW(eeprom, W1_F2D_EEPROM_SIZE);
+
+static struct bin_attribute *w1_f2d_bin_attrs[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group w1_f2d_group = {
+	.bin_attrs = w1_f2d_bin_attrs,
+};
+
+static const struct attribute_group *w1_f2d_groups[] = {
+	&w1_f2d_group,
+	NULL,
+};
+
+static struct w1_family_ops w1_f2d_fops = {
+	.groups		= w1_f2d_groups,
+};
+
+static struct w1_family w1_family_2d = {
+	.fid = W1_EEPROM_DS2431,
+	.fops = &w1_f2d_fops,
+};
+module_w1_family(w1_family_2d);
+
+MODULE_AUTHOR("Bernhard Weirich <bernhard.weirich@riedel.net>");
+MODULE_DESCRIPTION("w1 family 2d driver for DS2431, 1kb EEPROM");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2431));
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
new file mode 100644
index 0000000..75ad70c
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -0,0 +1,308 @@
+/*
+ *	w1_ds2433.c - w1 family 23 (DS2433) driver
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+#include <linux/crc16.h>
+
+#define CRC16_INIT		0
+#define CRC16_VALID		0xb001
+
+#endif
+
+#include <linux/w1.h>
+
+#define W1_EEPROM_DS2433	0x23
+
+#define W1_EEPROM_SIZE		512
+#define W1_PAGE_COUNT		16
+#define W1_PAGE_SIZE		32
+#define W1_PAGE_BITS		5
+#define W1_PAGE_MASK		0x1F
+
+#define W1_F23_TIME		300
+
+#define W1_F23_READ_EEPROM	0xF0
+#define W1_F23_WRITE_SCRATCH	0x0F
+#define W1_F23_READ_SCRATCH	0xAA
+#define W1_F23_COPY_SCRATCH	0x55
+
+struct w1_f23_data {
+	u8	memory[W1_EEPROM_SIZE];
+	u32	validcrc;
+};
+
+/**
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
+{
+	if (off > size)
+		return 0;
+
+	if ((off + count) > size)
+		return (size - off);
+
+	return count;
+}
+
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
+				int block)
+{
+	u8	wrbuf[3];
+	int	off = block * W1_PAGE_SIZE;
+
+	if (data->validcrc & (1 << block))
+		return 0;
+
+	if (w1_reset_select_slave(sl)) {
+		data->validcrc = 0;
+		return -EIO;
+	}
+
+	wrbuf[0] = W1_F23_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
+
+	/* cache the block if the CRC is valid */
+	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
+		data->validcrc |= (1 << block);
+
+	return 0;
+}
+#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
+
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+	struct w1_f23_data *data = sl->family_data;
+	int i, min_page, max_page;
+#else
+	u8 wrbuf[3];
+#endif
+
+	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
+		return 0;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+
+	min_page = (off >> W1_PAGE_BITS);
+	max_page = (off + count - 1) >> W1_PAGE_BITS;
+	for (i = min_page; i <= max_page; i++) {
+		if (w1_f23_refresh_block(sl, data, i)) {
+			count = -EIO;
+			goto out_up;
+		}
+	}
+	memcpy(buf, &data->memory[off], count);
+
+#else 	/* CONFIG_W1_SLAVE_DS2433_CRC */
+
+	/* read directly from the EEPROM */
+	if (w1_reset_select_slave(sl)) {
+		count = -EIO;
+		goto out_up;
+	}
+
+	wrbuf[0] = W1_F23_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, buf, count);
+
+#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
+
+out_up:
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return count;
+}
+
+/**
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be on one page.
+ * The master must be locked.
+ *
+ * @param sl	The slave structure
+ * @param addr	Address for the write
+ * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
+ * @param data	The data to write
+ * @return	0=Success -1=failure
+ */
+static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+	struct w1_f23_data *f23 = sl->family_data;
+#endif
+	u8 wrbuf[4];
+	u8 rdbuf[W1_PAGE_SIZE + 3];
+	u8 es = (addr + len - 1) & 0x1f;
+
+	/* Write the data to the scratchpad */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F23_WRITE_SCRATCH;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_write_block(sl->master, data, len);
+
+	/* Read the scratchpad and verify */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	w1_write_8(sl->master, W1_F23_READ_SCRATCH);
+	w1_read_block(sl->master, rdbuf, len + 3);
+
+	/* Compare what was read against the data written */
+	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
+		return -1;
+
+	/* Copy the scratchpad to EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F23_COPY_SCRATCH;
+	wrbuf[3] = es;
+	w1_write_block(sl->master, wrbuf, 4);
+
+	/* Sleep for 5 ms to wait for the write to complete */
+	msleep(5);
+
+	/* Reset the bus to wake up the EEPROM (this may not be needed) */
+	w1_reset_bus(sl->master);
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+	f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
+#endif
+	return 0;
+}
+
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int addr, len, idx;
+
+	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
+		return 0;
+
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+	/* can only write full blocks in cached mode */
+	if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
+		dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
+			(int)off, count);
+		return -EINVAL;
+	}
+
+	/* make sure the block CRCs are valid */
+	for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
+		if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
+			dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
+			return -EINVAL;
+		}
+	}
+#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	/* Can only write data to one page at a time */
+	idx = 0;
+	while (idx < count) {
+		addr = off + idx;
+		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
+		if (len > (count - idx))
+			len = count - idx;
+
+		if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) {
+			count = -EIO;
+			goto out_up;
+		}
+		idx += len;
+	}
+
+out_up:
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return count;
+}
+
+static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
+
+static struct bin_attribute *w1_f23_bin_attributes[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group w1_f23_group = {
+	.bin_attrs = w1_f23_bin_attributes,
+};
+
+static const struct attribute_group *w1_f23_groups[] = {
+	&w1_f23_group,
+	NULL,
+};
+
+static int w1_f23_add_slave(struct w1_slave *sl)
+{
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+	struct w1_f23_data *data;
+
+	data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	sl->family_data = data;
+
+#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
+	return 0;
+}
+
+static void w1_f23_remove_slave(struct w1_slave *sl)
+{
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+	kfree(sl->family_data);
+	sl->family_data = NULL;
+#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
+}
+
+static struct w1_family_ops w1_f23_fops = {
+	.add_slave      = w1_f23_add_slave,
+	.remove_slave   = w1_f23_remove_slave,
+	.groups		= w1_f23_groups,
+};
+
+static struct w1_family w1_family_23 = {
+	.fid = W1_EEPROM_DS2433,
+	.fops = &w1_f23_fops,
+};
+module_w1_family(w1_family_23);
+
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433));
diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c
new file mode 100644
index 0000000..bf641a1
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2438.c
@@ -0,0 +1,392 @@
+/*
+ * 1-Wire implementation for the ds2438 chip
+ *
+ * Copyright (c) 2017 Mariusz Bialonczyk <manio@skyboo.net>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_DS2438		0x26
+
+#define W1_DS2438_RETRIES		3
+
+/* Memory commands */
+#define W1_DS2438_READ_SCRATCH		0xBE
+#define W1_DS2438_WRITE_SCRATCH		0x4E
+#define W1_DS2438_COPY_SCRATCH		0x48
+#define W1_DS2438_RECALL_MEMORY		0xB8
+/* Register commands */
+#define W1_DS2438_CONVERT_TEMP		0x44
+#define W1_DS2438_CONVERT_VOLTAGE	0xB4
+
+#define DS2438_PAGE_SIZE		8
+#define DS2438_ADC_INPUT_VAD		0
+#define DS2438_ADC_INPUT_VDD		1
+#define DS2438_MAX_CONVERSION_TIME	10		/* ms */
+
+/* Page #0 definitions */
+#define DS2438_STATUS_REG		0x00		/* Status/Configuration Register */
+#define DS2438_STATUS_IAD		(1 << 0)	/* Current A/D Control Bit */
+#define DS2438_STATUS_CA		(1 << 1)	/* Current Accumulator Configuration */
+#define DS2438_STATUS_EE		(1 << 2)	/* Current Accumulator Shadow Selector bit */
+#define DS2438_STATUS_AD		(1 << 3)	/* Voltage A/D Input Select Bit */
+#define DS2438_STATUS_TB		(1 << 4)	/* Temperature Busy Flag */
+#define DS2438_STATUS_NVB		(1 << 5)	/* Nonvolatile Memory Busy Flag */
+#define DS2438_STATUS_ADB		(1 << 6)	/* A/D Converter Busy Flag */
+
+#define DS2438_TEMP_LSB			0x01
+#define DS2438_TEMP_MSB			0x02
+#define DS2438_VOLTAGE_LSB		0x03
+#define DS2438_VOLTAGE_MSB		0x04
+#define DS2438_CURRENT_LSB		0x05
+#define DS2438_CURRENT_MSB		0x06
+#define DS2438_THRESHOLD		0x07
+
+static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf)
+{
+	unsigned int retries = W1_DS2438_RETRIES;
+	u8 w1_buf[2];
+	u8 crc;
+	size_t count;
+
+	while (retries--) {
+		crc = 0;
+
+		if (w1_reset_select_slave(sl))
+			continue;
+		w1_buf[0] = W1_DS2438_RECALL_MEMORY;
+		w1_buf[1] = 0x00;
+		w1_write_block(sl->master, w1_buf, 2);
+
+		if (w1_reset_select_slave(sl))
+			continue;
+		w1_buf[0] = W1_DS2438_READ_SCRATCH;
+		w1_buf[1] = 0x00;
+		w1_write_block(sl->master, w1_buf, 2);
+
+		count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1);
+		if (count == DS2438_PAGE_SIZE + 1) {
+			crc = w1_calc_crc8(buf, DS2438_PAGE_SIZE);
+
+			/* check for correct CRC */
+			if ((u8)buf[DS2438_PAGE_SIZE] == crc)
+				return 0;
+		}
+	}
+	return -1;
+}
+
+static int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature)
+{
+	unsigned int retries = W1_DS2438_RETRIES;
+	u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
+	unsigned int tm = DS2438_MAX_CONVERSION_TIME;
+	unsigned long sleep_rem;
+	int ret;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	while (retries--) {
+		if (w1_reset_select_slave(sl))
+			continue;
+		w1_write_8(sl->master, W1_DS2438_CONVERT_TEMP);
+
+		mutex_unlock(&sl->master->bus_mutex);
+		sleep_rem = msleep_interruptible(tm);
+		if (sleep_rem != 0) {
+			ret = -1;
+			goto post_unlock;
+		}
+
+		if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) {
+			ret = -1;
+			goto post_unlock;
+		}
+
+		break;
+	}
+
+	if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
+		*temperature = (((int16_t) w1_buf[DS2438_TEMP_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_TEMP_LSB]);
+		ret = 0;
+	} else
+		ret = -1;
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+post_unlock:
+	return ret;
+}
+
+static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value)
+{
+	unsigned int retries = W1_DS2438_RETRIES;
+	u8 w1_buf[3];
+	u8 status;
+	int perform_write = 0;
+
+	while (retries--) {
+		if (w1_reset_select_slave(sl))
+			continue;
+		w1_buf[0] = W1_DS2438_RECALL_MEMORY;
+		w1_buf[1] = 0x00;
+		w1_write_block(sl->master, w1_buf, 2);
+
+		if (w1_reset_select_slave(sl))
+			continue;
+		w1_buf[0] = W1_DS2438_READ_SCRATCH;
+		w1_buf[1] = 0x00;
+		w1_write_block(sl->master, w1_buf, 2);
+
+		/* reading one byte of result */
+		status = w1_read_8(sl->master);
+
+		/* if bit0=1, set a value to a mask for easy compare */
+		if (value)
+			value = mask;
+
+		if ((status & mask) == value)
+			return 0;	/* already set as requested */
+		else {
+			/* changing bit */
+			status ^= mask;
+			perform_write = 1;
+		}
+		break;
+	}
+
+	if (perform_write) {
+		retries = W1_DS2438_RETRIES;
+		while (retries--) {
+			if (w1_reset_select_slave(sl))
+				continue;
+			w1_buf[0] = W1_DS2438_WRITE_SCRATCH;
+			w1_buf[1] = 0x00;
+			w1_buf[2] = status;
+			w1_write_block(sl->master, w1_buf, 3);
+
+			if (w1_reset_select_slave(sl))
+				continue;
+			w1_buf[0] = W1_DS2438_COPY_SCRATCH;
+			w1_buf[1] = 0x00;
+			w1_write_block(sl->master, w1_buf, 2);
+
+			return 0;
+		}
+	}
+	return -1;
+}
+
+static uint16_t w1_ds2438_get_voltage(struct w1_slave *sl,
+				      int adc_input, uint16_t *voltage)
+{
+	unsigned int retries = W1_DS2438_RETRIES;
+	u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
+	unsigned int tm = DS2438_MAX_CONVERSION_TIME;
+	unsigned long sleep_rem;
+	int ret;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_AD, adc_input)) {
+		ret = -1;
+		goto pre_unlock;
+	}
+
+	while (retries--) {
+		if (w1_reset_select_slave(sl))
+			continue;
+		w1_write_8(sl->master, W1_DS2438_CONVERT_VOLTAGE);
+
+		mutex_unlock(&sl->master->bus_mutex);
+		sleep_rem = msleep_interruptible(tm);
+		if (sleep_rem != 0) {
+			ret = -1;
+			goto post_unlock;
+		}
+
+		if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) {
+			ret = -1;
+			goto post_unlock;
+		}
+
+		break;
+	}
+
+	if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
+		*voltage = (((uint16_t) w1_buf[DS2438_VOLTAGE_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_VOLTAGE_LSB]);
+		ret = 0;
+	} else
+		ret = -1;
+
+pre_unlock:
+	mutex_unlock(&sl->master->bus_mutex);
+
+post_unlock:
+	return ret;
+}
+
+static ssize_t iad_write(struct file *filp, struct kobject *kobj,
+			 struct bin_attribute *bin_attr, char *buf,
+			 loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int ret;
+
+	if (count != 1 || off != 0)
+		return -EFAULT;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0)
+		ret = 1;
+	else
+		ret = -EIO;
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static ssize_t page0_read(struct file *filp, struct kobject *kobj,
+			  struct bin_attribute *bin_attr, char *buf,
+			  loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int ret;
+	u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
+		memcpy(buf, &w1_buf, DS2438_PAGE_SIZE);
+		ret = DS2438_PAGE_SIZE;
+	} else
+		ret = -EIO;
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
+				struct bin_attribute *bin_attr, char *buf,
+				loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int ret;
+	ssize_t c = PAGE_SIZE;
+	int16_t temp;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	if (w1_ds2438_get_temperature(sl, &temp) == 0) {
+		c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", temp);
+		ret = PAGE_SIZE - c;
+	} else
+		ret = -EIO;
+
+	return ret;
+}
+
+static ssize_t vad_read(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr, char *buf,
+			loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int ret;
+	ssize_t c = PAGE_SIZE;
+	uint16_t voltage;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) {
+		c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage);
+		ret = PAGE_SIZE - c;
+	} else
+		ret = -EIO;
+
+	return ret;
+}
+
+static ssize_t vdd_read(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr, char *buf,
+			loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int ret;
+	ssize_t c = PAGE_SIZE;
+	uint16_t voltage;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) {
+		c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage);
+		ret = PAGE_SIZE - c;
+	} else
+		ret = -EIO;
+
+	return ret;
+}
+
+static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, NULL, iad_write, 1);
+static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE);
+static BIN_ATTR_RO(temperature, 0/* real length varies */);
+static BIN_ATTR_RO(vad, 0/* real length varies */);
+static BIN_ATTR_RO(vdd, 0/* real length varies */);
+
+static struct bin_attribute *w1_ds2438_bin_attrs[] = {
+	&bin_attr_iad,
+	&bin_attr_page0,
+	&bin_attr_temperature,
+	&bin_attr_vad,
+	&bin_attr_vdd,
+	NULL,
+};
+
+static const struct attribute_group w1_ds2438_group = {
+	.bin_attrs = w1_ds2438_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2438_groups[] = {
+	&w1_ds2438_group,
+	NULL,
+};
+
+static struct w1_family_ops w1_ds2438_fops = {
+	.groups		= w1_ds2438_groups,
+};
+
+static struct w1_family w1_ds2438_family = {
+	.fid = W1_FAMILY_DS2438,
+	.fops = &w1_ds2438_fops,
+};
+module_w1_family(w1_ds2438_family);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>");
+MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438));
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
new file mode 100644
index 0000000..a605281
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -0,0 +1,163 @@
+/*
+ * 1-Wire implementation for the ds2780 chip
+ *
+ * Copyright (C) 2010 Indesign, LLC
+ *
+ * Author: Clifton Barnes <cabarnes@indesign-llc.com>
+ *
+ * Based on w1-ds2760 driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/idr.h>
+
+#include <linux/w1.h>
+
+#include "w1_ds2780.h"
+
+#define W1_FAMILY_DS2780	0x32
+
+static int w1_ds2780_do_io(struct device *dev, char *buf, int addr,
+			size_t count, int io)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+	if (addr > DS2780_DATA_SIZE || addr < 0)
+		return 0;
+
+	count = min_t(int, count, DS2780_DATA_SIZE - addr);
+
+	if (w1_reset_select_slave(sl) == 0) {
+		if (io) {
+			w1_write_8(sl->master, W1_DS2780_WRITE_DATA);
+			w1_write_8(sl->master, addr);
+			w1_write_block(sl->master, buf, count);
+		} else {
+			w1_write_8(sl->master, W1_DS2780_READ_DATA);
+			w1_write_8(sl->master, addr);
+			count = w1_read_block(sl->master, buf, count);
+		}
+	}
+
+	return count;
+}
+
+int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
+			int io)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	ret = w1_ds2780_do_io(dev, buf, addr, count, io);
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(w1_ds2780_io);
+
+int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+	if (!dev)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_reset_select_slave(sl) == 0) {
+		w1_write_8(sl->master, cmd);
+		w1_write_8(sl->master, addr);
+	}
+
+	mutex_unlock(&sl->master->bus_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(w1_ds2780_eeprom_cmd);
+
+static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj,
+			     struct bin_attribute *bin_attr, char *buf,
+			     loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	return w1_ds2780_io(dev, buf, off, count, 0);
+}
+
+static BIN_ATTR_RO(w1_slave, DS2780_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2780_bin_attrs[] = {
+	&bin_attr_w1_slave,
+	NULL,
+};
+
+static const struct attribute_group w1_ds2780_group = {
+	.bin_attrs = w1_ds2780_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2780_groups[] = {
+	&w1_ds2780_group,
+	NULL,
+};
+
+static int w1_ds2780_add_slave(struct w1_slave *sl)
+{
+	int ret;
+	struct platform_device *pdev;
+
+	pdev = platform_device_alloc("ds2780-battery", PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return -ENOMEM;
+	pdev->dev.parent = &sl->dev;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto pdev_add_failed;
+
+	dev_set_drvdata(&sl->dev, pdev);
+
+	return 0;
+
+pdev_add_failed:
+	platform_device_put(pdev);
+
+	return ret;
+}
+
+static void w1_ds2780_remove_slave(struct w1_slave *sl)
+{
+	struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+
+	platform_device_unregister(pdev);
+}
+
+static struct w1_family_ops w1_ds2780_fops = {
+	.add_slave    = w1_ds2780_add_slave,
+	.remove_slave = w1_ds2780_remove_slave,
+	.groups       = w1_ds2780_groups,
+};
+
+static struct w1_family w1_ds2780_family = {
+	.fid = W1_FAMILY_DS2780,
+	.fops = &w1_ds2780_fops,
+};
+module_w1_family(w1_ds2780_family);
+
+MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
+MODULE_DESCRIPTION("1-wire Driver for Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2780));
diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h
new file mode 100644
index 0000000..a1fba79
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2780.h
@@ -0,0 +1,129 @@
+/*
+ * 1-Wire implementation for the ds2780 chip
+ *
+ * Copyright (C) 2010 Indesign, LLC
+ *
+ * Author: Clifton Barnes <cabarnes@indesign-llc.com>
+ *
+ * Based on w1-ds2760 driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _W1_DS2780_H
+#define _W1_DS2780_H
+
+/* Function commands */
+#define W1_DS2780_READ_DATA		0x69
+#define W1_DS2780_WRITE_DATA		0x6C
+#define W1_DS2780_COPY_DATA		0x48
+#define W1_DS2780_RECALL_DATA		0xB8
+#define W1_DS2780_LOCK			0x6A
+
+/* Register map */
+/* Register 0x00 Reserved */
+#define DS2780_STATUS_REG		0x01
+#define DS2780_RAAC_MSB_REG		0x02
+#define DS2780_RAAC_LSB_REG		0x03
+#define DS2780_RSAC_MSB_REG		0x04
+#define DS2780_RSAC_LSB_REG		0x05
+#define DS2780_RARC_REG			0x06
+#define DS2780_RSRC_REG			0x07
+#define DS2780_IAVG_MSB_REG		0x08
+#define DS2780_IAVG_LSB_REG		0x09
+#define DS2780_TEMP_MSB_REG		0x0A
+#define DS2780_TEMP_LSB_REG		0x0B
+#define DS2780_VOLT_MSB_REG		0x0C
+#define DS2780_VOLT_LSB_REG		0x0D
+#define DS2780_CURRENT_MSB_REG		0x0E
+#define DS2780_CURRENT_LSB_REG		0x0F
+#define DS2780_ACR_MSB_REG		0x10
+#define DS2780_ACR_LSB_REG		0x11
+#define DS2780_ACRL_MSB_REG		0x12
+#define DS2780_ACRL_LSB_REG		0x13
+#define DS2780_AS_REG			0x14
+#define DS2780_SFR_REG			0x15
+#define DS2780_FULL_MSB_REG		0x16
+#define DS2780_FULL_LSB_REG		0x17
+#define DS2780_AE_MSB_REG		0x18
+#define DS2780_AE_LSB_REG		0x19
+#define DS2780_SE_MSB_REG		0x1A
+#define DS2780_SE_LSB_REG		0x1B
+/* Register 0x1C - 0x1E Reserved */
+#define DS2780_EEPROM_REG		0x1F
+#define DS2780_EEPROM_BLOCK0_START	0x20
+/* Register 0x20 - 0x2F User EEPROM */
+#define DS2780_EEPROM_BLOCK0_END	0x2F
+/* Register 0x30 - 0x5F Reserved */
+#define DS2780_EEPROM_BLOCK1_START	0x60
+#define DS2780_CONTROL_REG		0x60
+#define DS2780_AB_REG			0x61
+#define DS2780_AC_MSB_REG		0x62
+#define DS2780_AC_LSB_REG		0x63
+#define DS2780_VCHG_REG			0x64
+#define DS2780_IMIN_REG			0x65
+#define DS2780_VAE_REG			0x66
+#define DS2780_IAE_REG			0x67
+#define DS2780_AE_40_REG		0x68
+#define DS2780_RSNSP_REG		0x69
+#define DS2780_FULL_40_MSB_REG		0x6A
+#define DS2780_FULL_40_LSB_REG		0x6B
+#define DS2780_FULL_3040_SLOPE_REG	0x6C
+#define DS2780_FULL_2030_SLOPE_REG	0x6D
+#define DS2780_FULL_1020_SLOPE_REG	0x6E
+#define DS2780_FULL_0010_SLOPE_REG	0x6F
+#define DS2780_AE_3040_SLOPE_REG	0x70
+#define DS2780_AE_2030_SLOPE_REG	0x71
+#define DS2780_AE_1020_SLOPE_REG	0x72
+#define DS2780_AE_0010_SLOPE_REG	0x73
+#define DS2780_SE_3040_SLOPE_REG	0x74
+#define DS2780_SE_2030_SLOPE_REG	0x75
+#define DS2780_SE_1020_SLOPE_REG	0x76
+#define DS2780_SE_0010_SLOPE_REG	0x77
+#define DS2780_RSGAIN_MSB_REG		0x78
+#define DS2780_RSGAIN_LSB_REG		0x79
+#define DS2780_RSTC_REG			0x7A
+#define DS2780_FRSGAIN_MSB_REG		0x7B
+#define DS2780_FRSGAIN_LSB_REG		0x7C
+#define DS2780_EEPROM_BLOCK1_END	0x7C
+/* Register 0x7D - 0xFF Reserved */
+
+/* Number of valid register addresses */
+#define DS2780_DATA_SIZE		0x80
+
+/* Status register bits */
+#define DS2780_STATUS_REG_CHGTF		(1 << 7)
+#define DS2780_STATUS_REG_AEF		(1 << 6)
+#define DS2780_STATUS_REG_SEF		(1 << 5)
+#define DS2780_STATUS_REG_LEARNF	(1 << 4)
+/* Bit 3 Reserved */
+#define DS2780_STATUS_REG_UVF		(1 << 2)
+#define DS2780_STATUS_REG_PORF		(1 << 1)
+/* Bit 0 Reserved */
+
+/* Control register bits */
+/* Bit 7 Reserved */
+#define DS2780_CONTROL_REG_UVEN		(1 << 6)
+#define DS2780_CONTROL_REG_PMOD		(1 << 5)
+#define DS2780_CONTROL_REG_RNAOP	(1 << 4)
+/* Bit 0 - 3 Reserved */
+
+/* Special feature register bits */
+/* Bit 1 - 7 Reserved */
+#define DS2780_SFR_REG_PIOSC		(1 << 0)
+
+/* EEPROM register bits */
+#define DS2780_EEPROM_REG_EEC		(1 << 7)
+#define DS2780_EEPROM_REG_LOCK		(1 << 6)
+/* Bit 2 - 6 Reserved */
+#define DS2780_EEPROM_REG_BL1		(1 << 1)
+#define DS2780_EEPROM_REG_BL0		(1 << 0)
+
+extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
+			int io);
+extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd);
+
+#endif /* !_W1_DS2780_H */
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c
new file mode 100644
index 0000000..645be6e
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2781.c
@@ -0,0 +1,160 @@
+/*
+ * 1-Wire implementation for the ds2781 chip
+ *
+ * Author: Renata Sayakhova <renata@oktetlabs.ru>
+ *
+ * Based on w1-ds2780 driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include <linux/w1.h>
+
+#include "w1_ds2781.h"
+
+#define W1_FAMILY_DS2781	0x3D
+
+static int w1_ds2781_do_io(struct device *dev, char *buf, int addr,
+			size_t count, int io)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+	if (addr > DS2781_DATA_SIZE || addr < 0)
+		return 0;
+
+	count = min_t(int, count, DS2781_DATA_SIZE - addr);
+
+	if (w1_reset_select_slave(sl) == 0) {
+		if (io) {
+			w1_write_8(sl->master, W1_DS2781_WRITE_DATA);
+			w1_write_8(sl->master, addr);
+			w1_write_block(sl->master, buf, count);
+		} else {
+			w1_write_8(sl->master, W1_DS2781_READ_DATA);
+			w1_write_8(sl->master, addr);
+			count = w1_read_block(sl->master, buf, count);
+		}
+	}
+
+	return count;
+}
+
+int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
+			int io)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	ret = w1_ds2781_do_io(dev, buf, addr, count, io);
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(w1_ds2781_io);
+
+int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+	if (!dev)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_reset_select_slave(sl) == 0) {
+		w1_write_8(sl->master, cmd);
+		w1_write_8(sl->master, addr);
+	}
+
+	mutex_unlock(&sl->master->bus_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(w1_ds2781_eeprom_cmd);
+
+static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj,
+			     struct bin_attribute *bin_attr, char *buf,
+			     loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	return w1_ds2781_io(dev, buf, off, count, 0);
+}
+
+static BIN_ATTR_RO(w1_slave, DS2781_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2781_bin_attrs[] = {
+	&bin_attr_w1_slave,
+	NULL,
+};
+
+static const struct attribute_group w1_ds2781_group = {
+	.bin_attrs = w1_ds2781_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2781_groups[] = {
+	&w1_ds2781_group,
+	NULL,
+};
+
+static int w1_ds2781_add_slave(struct w1_slave *sl)
+{
+	int ret;
+	struct platform_device *pdev;
+
+	pdev = platform_device_alloc("ds2781-battery", PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return -ENOMEM;
+	pdev->dev.parent = &sl->dev;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto pdev_add_failed;
+
+	dev_set_drvdata(&sl->dev, pdev);
+
+	return 0;
+
+pdev_add_failed:
+	platform_device_put(pdev);
+
+	return ret;
+}
+
+static void w1_ds2781_remove_slave(struct w1_slave *sl)
+{
+	struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+
+	platform_device_unregister(pdev);
+}
+
+static struct w1_family_ops w1_ds2781_fops = {
+	.add_slave    = w1_ds2781_add_slave,
+	.remove_slave = w1_ds2781_remove_slave,
+	.groups       = w1_ds2781_groups,
+};
+
+static struct w1_family w1_ds2781_family = {
+	.fid = W1_FAMILY_DS2781,
+	.fops = &w1_ds2781_fops,
+};
+module_w1_family(w1_ds2781_family);
+
+MODULE_AUTHOR("Renata Sayakhova <renata@oktetlabs.ru>");
+MODULE_DESCRIPTION("1-wire Driver for Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2781));
diff --git a/drivers/w1/slaves/w1_ds2781.h b/drivers/w1/slaves/w1_ds2781.h
new file mode 100644
index 0000000..557dfb0
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2781.h
@@ -0,0 +1,134 @@
+/*
+ * 1-Wire implementation for the ds2780 chip
+ *
+ * Author: Renata Sayakhova <renata@oktetlabs.ru>
+ *
+ * Based on w1-ds2760 driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _W1_DS2781_H
+#define _W1_DS2781_H
+
+/* Function commands */
+#define W1_DS2781_READ_DATA		0x69
+#define W1_DS2781_WRITE_DATA		0x6C
+#define W1_DS2781_COPY_DATA		0x48
+#define W1_DS2781_RECALL_DATA		0xB8
+#define W1_DS2781_LOCK			0x6A
+
+/* Register map */
+/* Register 0x00 Reserved */
+#define DS2781_STATUS			0x01
+#define DS2781_RAAC_MSB			0x02
+#define DS2781_RAAC_LSB			0x03
+#define DS2781_RSAC_MSB			0x04
+#define DS2781_RSAC_LSB			0x05
+#define DS2781_RARC			0x06
+#define DS2781_RSRC			0x07
+#define DS2781_IAVG_MSB			0x08
+#define DS2781_IAVG_LSB			0x09
+#define DS2781_TEMP_MSB			0x0A
+#define DS2781_TEMP_LSB			0x0B
+#define DS2781_VOLT_MSB			0x0C
+#define DS2781_VOLT_LSB			0x0D
+#define DS2781_CURRENT_MSB		0x0E
+#define DS2781_CURRENT_LSB		0x0F
+#define DS2781_ACR_MSB			0x10
+#define DS2781_ACR_LSB			0x11
+#define DS2781_ACRL_MSB			0x12
+#define DS2781_ACRL_LSB			0x13
+#define DS2781_AS			0x14
+#define DS2781_SFR			0x15
+#define DS2781_FULL_MSB			0x16
+#define DS2781_FULL_LSB			0x17
+#define DS2781_AE_MSB			0x18
+#define DS2781_AE_LSB			0x19
+#define DS2781_SE_MSB			0x1A
+#define DS2781_SE_LSB			0x1B
+/* Register 0x1C - 0x1E Reserved */
+#define DS2781_EEPROM		0x1F
+#define DS2781_EEPROM_BLOCK0_START	0x20
+/* Register 0x20 - 0x2F User EEPROM */
+#define DS2781_EEPROM_BLOCK0_END	0x2F
+/* Register 0x30 - 0x5F Reserved */
+#define DS2781_EEPROM_BLOCK1_START	0x60
+#define DS2781_CONTROL			0x60
+#define DS2781_AB			0x61
+#define DS2781_AC_MSB			0x62
+#define DS2781_AC_LSB			0x63
+#define DS2781_VCHG			0x64
+#define DS2781_IMIN			0x65
+#define DS2781_VAE			0x66
+#define DS2781_IAE			0x67
+#define DS2781_AE_40			0x68
+#define DS2781_RSNSP			0x69
+#define DS2781_FULL_40_MSB		0x6A
+#define DS2781_FULL_40_LSB		0x6B
+#define DS2781_FULL_4_SLOPE		0x6C
+#define DS2781_FULL_3_SLOPE		0x6D
+#define DS2781_FULL_2_SLOPE		0x6E
+#define DS2781_FULL_1_SLOPE		0x6F
+#define DS2781_AE_4_SLOPE		0x70
+#define DS2781_AE_3_SLOPE		0x71
+#define DS2781_AE_2_SLOPE		0x72
+#define DS2781_AE_1_SLOPE		0x73
+#define DS2781_SE_4_SLOPE		0x74
+#define DS2781_SE_3_SLOPE		0x75
+#define DS2781_SE_2_SLOPE		0x76
+#define DS2781_SE_1_SLOPE		0x77
+#define DS2781_RSGAIN_MSB		0x78
+#define DS2781_RSGAIN_LSB		0x79
+#define DS2781_RSTC			0x7A
+#define DS2781_COB			0x7B
+#define DS2781_TBP34			0x7C
+#define DS2781_TBP23			0x7D
+#define DS2781_TBP12			0x7E
+#define DS2781_EEPROM_BLOCK1_END	0x7F
+/* Register 0x7D - 0xFF Reserved */
+
+#define DS2781_FSGAIN_MSB		0xB0
+#define DS2781_FSGAIN_LSB		0xB1
+
+/* Number of valid register addresses */
+#define DS2781_DATA_SIZE		0xB2
+
+/* Status register bits */
+#define DS2781_STATUS_CHGTF		(1 << 7)
+#define DS2781_STATUS_AEF		(1 << 6)
+#define DS2781_STATUS_SEF		(1 << 5)
+#define DS2781_STATUS_LEARNF		(1 << 4)
+/* Bit 3 Reserved */
+#define DS2781_STATUS_UVF		(1 << 2)
+#define DS2781_STATUS_PORF		(1 << 1)
+/* Bit 0 Reserved */
+
+/* Control register bits */
+/* Bit 7 Reserved */
+#define DS2781_CONTROL_NBEN		(1 << 7)
+#define DS2781_CONTROL_UVEN		(1 << 6)
+#define DS2781_CONTROL_PMOD		(1 << 5)
+#define DS2781_CONTROL_RNAOP		(1 << 4)
+#define DS1781_CONTROL_UVTH		(1 << 3)
+/* Bit 0 - 2 Reserved */
+
+/* Special feature register bits */
+/* Bit 1 - 7 Reserved */
+#define DS2781_SFR_PIOSC		(1 << 0)
+
+/* EEPROM register bits */
+#define DS2781_EEPROM_EEC		(1 << 7)
+#define DS2781_EEPROM_LOCK		(1 << 6)
+/* Bit 2 - 6 Reserved */
+#define DS2781_EEPROM_BL1		(1 << 1)
+#define DS2781_EEPROM_BL0		(1 << 0)
+
+extern int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
+			int io);
+extern int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd);
+
+#endif /* !_W1_DS2781_H */
diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c
new file mode 100644
index 0000000..29348d2
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2805.c
@@ -0,0 +1,313 @@
+/*
+ * w1_ds2805 - w1 family 0d (DS28E05) driver
+ *
+ * Copyright (c) 2016 Andrew Worsley amworsley@gmail.com
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include <linux/w1.h>
+
+#define W1_EEPROM_DS2805       0x0D
+
+#define W1_F0D_EEPROM_SIZE		128
+#define W1_F0D_PAGE_BITS		3
+#define W1_F0D_PAGE_SIZE		(1<<W1_F0D_PAGE_BITS)
+#define W1_F0D_PAGE_MASK		0x0F
+
+#define W1_F0D_SCRATCH_BITS  1
+#define W1_F0D_SCRATCH_SIZE  (1<<W1_F0D_SCRATCH_BITS)
+#define W1_F0D_SCRATCH_MASK  (W1_F0D_SCRATCH_SIZE-1)
+
+#define W1_F0D_READ_EEPROM	0xF0
+#define W1_F0D_WRITE_EEPROM	0x55
+#define W1_F0D_RELEASE		0xFF
+
+#define W1_F0D_CS_OK		0xAA /* Chip Status Ok */
+
+#define W1_F0D_TPROG_MS		16
+
+#define W1_F0D_READ_RETRIES		10
+#define W1_F0D_READ_MAXLEN		W1_F0D_EEPROM_SIZE
+
+/*
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f0d_fix_count(loff_t off, size_t count, size_t size)
+{
+	if (off > size)
+		return 0;
+
+	if ((off + count) > size)
+		return size - off;
+
+	return count;
+}
+
+/*
+ * Read a block from W1 ROM two times and compares the results.
+ * If they are equal they are returned, otherwise the read
+ * is repeated W1_F0D_READ_RETRIES times.
+ *
+ * count must not exceed W1_F0D_READ_MAXLEN.
+ */
+static int w1_f0d_readblock(struct w1_slave *sl, int off, int count, char *buf)
+{
+	u8 wrbuf[3];
+	u8 cmp[W1_F0D_READ_MAXLEN];
+	int tries = W1_F0D_READ_RETRIES;
+
+	do {
+		wrbuf[0] = W1_F0D_READ_EEPROM;
+		wrbuf[1] = off & 0x7f;
+		wrbuf[2] = 0;
+
+		if (w1_reset_select_slave(sl))
+			return -1;
+
+		w1_write_block(sl->master, wrbuf, sizeof(wrbuf));
+		w1_read_block(sl->master, buf, count);
+
+		if (w1_reset_select_slave(sl))
+			return -1;
+
+		w1_write_block(sl->master, wrbuf, sizeof(wrbuf));
+		w1_read_block(sl->master, cmp, count);
+
+		if (!memcmp(cmp, buf, count))
+			return 0;
+	} while (--tries);
+
+	dev_err(&sl->dev, "proof reading failed %d times\n",
+			W1_F0D_READ_RETRIES);
+
+	return -1;
+}
+
+static ssize_t w1_f0d_read_bin(struct file *filp, struct kobject *kobj,
+			       struct bin_attribute *bin_attr,
+			       char *buf, loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int todo = count;
+
+	count = w1_f0d_fix_count(off, count, W1_F0D_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	mutex_lock(&sl->master->mutex);
+
+	/* read directly from the EEPROM in chunks of W1_F0D_READ_MAXLEN */
+	while (todo > 0) {
+		int block_read;
+
+		if (todo >= W1_F0D_READ_MAXLEN)
+			block_read = W1_F0D_READ_MAXLEN;
+		else
+			block_read = todo;
+
+		if (w1_f0d_readblock(sl, off, block_read, buf) < 0) {
+			count = -EIO;
+			break;
+		}
+
+		todo -= W1_F0D_READ_MAXLEN;
+		buf += W1_F0D_READ_MAXLEN;
+		off += W1_F0D_READ_MAXLEN;
+	}
+
+	mutex_unlock(&sl->master->mutex);
+
+	return count;
+}
+
+/*
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be aligned at W1_F0D_SCRATCH_SIZE bytes and
+ * must be W1_F0D_SCRATCH_SIZE bytes long.
+ * The master must be locked.
+ *
+ * @param sl	The slave structure
+ * @param addr	Address for the write
+ * @param len   length must be <= (W1_F0D_PAGE_SIZE - (addr & W1_F0D_PAGE_MASK))
+ * @param data	The data to write
+ * @return	0=Success -1=failure
+ */
+static int w1_f0d_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+	int tries = W1_F0D_READ_RETRIES;
+	u8 wrbuf[3];
+	u8 rdbuf[W1_F0D_SCRATCH_SIZE];
+	u8 cs;
+
+	if ((addr & 1) || (len != 2)) {
+		dev_err(&sl->dev, "%s: bad addr/len -  addr=%#x len=%d\n",
+		    __func__, addr, len);
+		return -1;
+	}
+
+retry:
+
+	/* Write the data to the scratchpad */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F0D_WRITE_EEPROM;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = 0xff; /* ?? from Example */
+
+	w1_write_block(sl->master, wrbuf, sizeof(wrbuf));
+	w1_write_block(sl->master, data, len);
+
+	w1_read_block(sl->master, rdbuf, sizeof(rdbuf));
+	/* Compare what was read against the data written */
+	if ((rdbuf[0] != data[0]) || (rdbuf[1] != data[1])) {
+
+		if (--tries)
+			goto retry;
+
+		dev_err(&sl->dev,
+			"could not write to eeprom, scratchpad compare failed %d times\n",
+			W1_F0D_READ_RETRIES);
+		pr_info("%s: rdbuf = %#x %#x data = %#x %#x\n",
+		    __func__, rdbuf[0], rdbuf[1], data[0], data[1]);
+
+		return -1;
+	}
+
+	/* Trigger write out to EEPROM */
+	w1_write_8(sl->master, W1_F0D_RELEASE);
+
+	/* Sleep for tprog ms to wait for the write to complete */
+	msleep(W1_F0D_TPROG_MS);
+
+	/* Check CS (Command Status) == 0xAA ? */
+	cs = w1_read_8(sl->master);
+	if (cs != W1_F0D_CS_OK) {
+		dev_err(&sl->dev, "save to eeprom failed = CS=%#x\n", cs);
+		return -1;
+	}
+
+	return 0;
+}
+
+static ssize_t w1_f0d_write_bin(struct file *filp, struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int addr, len;
+	int copy;
+
+	count = w1_f0d_fix_count(off, count, W1_F0D_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	mutex_lock(&sl->master->mutex);
+
+	/* Can only write data in blocks of the size of the scratchpad */
+	addr = off;
+	len = count;
+	while (len > 0) {
+
+		/* if len too short or addr not aligned */
+		if (len < W1_F0D_SCRATCH_SIZE || addr & W1_F0D_SCRATCH_MASK) {
+			char tmp[W1_F0D_SCRATCH_SIZE];
+
+			/* read the block and update the parts to be written */
+			if (w1_f0d_readblock(sl, addr & ~W1_F0D_SCRATCH_MASK,
+					W1_F0D_SCRATCH_SIZE, tmp)) {
+				count = -EIO;
+				goto out_up;
+			}
+
+			/* copy at most to the boundary of the PAGE or len */
+			copy = W1_F0D_SCRATCH_SIZE -
+				(addr & W1_F0D_SCRATCH_MASK);
+
+			if (copy > len)
+				copy = len;
+
+			memcpy(&tmp[addr & W1_F0D_SCRATCH_MASK], buf, copy);
+			if (w1_f0d_write(sl, addr & ~W1_F0D_SCRATCH_MASK,
+					W1_F0D_SCRATCH_SIZE, tmp) < 0) {
+				count = -EIO;
+				goto out_up;
+			}
+		} else {
+
+			copy = W1_F0D_SCRATCH_SIZE;
+			if (w1_f0d_write(sl, addr, copy, buf) < 0) {
+				count = -EIO;
+				goto out_up;
+			}
+		}
+		buf += copy;
+		addr += copy;
+		len -= copy;
+	}
+
+out_up:
+	mutex_unlock(&sl->master->mutex);
+
+	return count;
+}
+
+static struct bin_attribute w1_f0d_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO | S_IWUSR,
+	},
+	.size = W1_F0D_EEPROM_SIZE,
+	.read = w1_f0d_read_bin,
+	.write = w1_f0d_write_bin,
+};
+
+static int w1_f0d_add_slave(struct w1_slave *sl)
+{
+	return sysfs_create_bin_file(&sl->dev.kobj, &w1_f0d_bin_attr);
+}
+
+static void w1_f0d_remove_slave(struct w1_slave *sl)
+{
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_f0d_bin_attr);
+}
+
+static struct w1_family_ops w1_f0d_fops = {
+	.add_slave      = w1_f0d_add_slave,
+	.remove_slave   = w1_f0d_remove_slave,
+};
+
+static struct w1_family w1_family_2d = {
+	.fid = W1_EEPROM_DS2805,
+	.fops = &w1_f0d_fops,
+};
+
+static int __init w1_f0d_init(void)
+{
+	pr_info("%s()\n", __func__);
+	return w1_register_family(&w1_family_2d);
+}
+
+static void __exit w1_f0d_fini(void)
+{
+	pr_info("%s()\n", __func__);
+	w1_unregister_family(&w1_family_2d);
+}
+
+module_init(w1_f0d_init);
+module_exit(w1_f0d_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrew Worsley amworsley@gmail.com");
+MODULE_DESCRIPTION("w1 family 0d driver for DS2805, 1kb EEPROM");
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
new file mode 100644
index 0000000..ec234b8
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -0,0 +1,430 @@
+/*
+ *	w1_ds28e04.c - w1 family 1C (DS28E04) driver
+ *
+ * Copyright (c) 2012 Markus Franke <franke.m@sebakmt.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/crc16.h>
+#include <linux/uaccess.h>
+
+#define CRC16_INIT		0
+#define CRC16_VALID		0xb001
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_DS28E04	0x1C
+
+/* Allow the strong pullup to be disabled, but default to enabled.
+ * If it was disabled a parasite powered device might not get the required
+ * current to copy the data from the scratchpad to EEPROM.  If it is enabled
+ * parasite powered devices have a better chance of getting the current
+ * required.
+ */
+static int w1_strong_pullup = 1;
+module_param_named(strong_pullup, w1_strong_pullup, int, 0);
+
+/* enable/disable CRC checking on DS28E04-100 memory accesses */
+static char w1_enable_crccheck = 1;
+
+#define W1_EEPROM_SIZE		512
+#define W1_PAGE_COUNT		16
+#define W1_PAGE_SIZE		32
+#define W1_PAGE_BITS		5
+#define W1_PAGE_MASK		0x1F
+
+#define W1_F1C_READ_EEPROM	0xF0
+#define W1_F1C_WRITE_SCRATCH	0x0F
+#define W1_F1C_READ_SCRATCH	0xAA
+#define W1_F1C_COPY_SCRATCH	0x55
+#define W1_F1C_ACCESS_WRITE	0x5A
+
+#define W1_1C_REG_LOGIC_STATE	0x220
+
+struct w1_f1C_data {
+	u8	memory[W1_EEPROM_SIZE];
+	u32	validcrc;
+};
+
+/**
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f1C_fix_count(loff_t off, size_t count, size_t size)
+{
+	if (off > size)
+		return 0;
+
+	if ((off + count) > size)
+		return size - off;
+
+	return count;
+}
+
+static int w1_f1C_refresh_block(struct w1_slave *sl, struct w1_f1C_data *data,
+				int block)
+{
+	u8	wrbuf[3];
+	int	off = block * W1_PAGE_SIZE;
+
+	if (data->validcrc & (1 << block))
+		return 0;
+
+	if (w1_reset_select_slave(sl)) {
+		data->validcrc = 0;
+		return -EIO;
+	}
+
+	wrbuf[0] = W1_F1C_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
+
+	/* cache the block if the CRC is valid */
+	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
+		data->validcrc |= (1 << block);
+
+	return 0;
+}
+
+static int w1_f1C_read(struct w1_slave *sl, int addr, int len, char *data)
+{
+	u8 wrbuf[3];
+
+	/* read directly from the EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -EIO;
+
+	wrbuf[0] = W1_F1C_READ_EEPROM;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, sizeof(wrbuf));
+	return w1_read_block(sl->master, data, len);
+}
+
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	struct w1_f1C_data *data = sl->family_data;
+	int i, min_page, max_page;
+
+	count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	mutex_lock(&sl->master->mutex);
+
+	if (w1_enable_crccheck) {
+		min_page = (off >> W1_PAGE_BITS);
+		max_page = (off + count - 1) >> W1_PAGE_BITS;
+		for (i = min_page; i <= max_page; i++) {
+			if (w1_f1C_refresh_block(sl, data, i)) {
+				count = -EIO;
+				goto out_up;
+			}
+		}
+		memcpy(buf, &data->memory[off], count);
+	} else {
+		count = w1_f1C_read(sl, off, count, buf);
+	}
+
+out_up:
+	mutex_unlock(&sl->master->mutex);
+
+	return count;
+}
+
+/**
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be on one page.
+ * The master must be locked.
+ *
+ * @param sl	The slave structure
+ * @param addr	Address for the write
+ * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
+ * @param data	The data to write
+ * @return	0=Success -1=failure
+ */
+static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+	u8 wrbuf[4];
+	u8 rdbuf[W1_PAGE_SIZE + 3];
+	u8 es = (addr + len - 1) & 0x1f;
+	unsigned int tm = 10;
+	int i;
+	struct w1_f1C_data *f1C = sl->family_data;
+
+	/* Write the data to the scratchpad */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F1C_WRITE_SCRATCH;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_write_block(sl->master, data, len);
+
+	/* Read the scratchpad and verify */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	w1_write_8(sl->master, W1_F1C_READ_SCRATCH);
+	w1_read_block(sl->master, rdbuf, len + 3);
+
+	/* Compare what was read against the data written */
+	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
+		return -1;
+
+	/* Copy the scratchpad to EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F1C_COPY_SCRATCH;
+	wrbuf[3] = es;
+
+	for (i = 0; i < sizeof(wrbuf); ++i) {
+		/* issue 10ms strong pullup (or delay) on the last byte
+		   for writing the data from the scratchpad to EEPROM */
+		if (w1_strong_pullup && i == sizeof(wrbuf)-1)
+			w1_next_pullup(sl->master, tm);
+
+		w1_write_8(sl->master, wrbuf[i]);
+	}
+
+	if (!w1_strong_pullup)
+		msleep(tm);
+
+	if (w1_enable_crccheck) {
+		/* invalidate cached data */
+		f1C->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
+	}
+
+	/* Reset the bus to wake up the EEPROM (this may not be needed) */
+	w1_reset_bus(sl->master);
+
+	return 0;
+}
+
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
+
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int addr, len, idx;
+
+	count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	if (w1_enable_crccheck) {
+		/* can only write full blocks in cached mode */
+		if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
+			dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
+				(int)off, count);
+			return -EINVAL;
+		}
+
+		/* make sure the block CRCs are valid */
+		for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
+			if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE)
+				!= CRC16_VALID) {
+				dev_err(&sl->dev, "bad CRC at offset %d\n",
+					(int)off);
+				return -EINVAL;
+			}
+		}
+	}
+
+	mutex_lock(&sl->master->mutex);
+
+	/* Can only write data to one page at a time */
+	idx = 0;
+	while (idx < count) {
+		addr = off + idx;
+		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
+		if (len > (count - idx))
+			len = count - idx;
+
+		if (w1_f1C_write(sl, addr, len, &buf[idx]) < 0) {
+			count = -EIO;
+			goto out_up;
+		}
+		idx += len;
+	}
+
+out_up:
+	mutex_unlock(&sl->master->mutex);
+
+	return count;
+}
+
+static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
+
+static ssize_t pio_read(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr, char *buf, loff_t off,
+			size_t count)
+
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int ret;
+
+	/* check arguments */
+	if (off != 0 || count != 1 || buf == NULL)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->mutex);
+	ret = w1_f1C_read(sl, W1_1C_REG_LOGIC_STATE, count, buf);
+	mutex_unlock(&sl->master->mutex);
+
+	return ret;
+}
+
+static ssize_t pio_write(struct file *filp, struct kobject *kobj,
+			 struct bin_attribute *bin_attr, char *buf, loff_t off,
+			 size_t count)
+
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	u8 wrbuf[3];
+	u8 ack;
+
+	/* check arguments */
+	if (off != 0 || count != 1 || buf == NULL)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->mutex);
+
+	/* Write the PIO data */
+	if (w1_reset_select_slave(sl)) {
+		mutex_unlock(&sl->master->mutex);
+		return -1;
+	}
+
+	/* set bit 7..2 to value '1' */
+	*buf = *buf | 0xFC;
+
+	wrbuf[0] = W1_F1C_ACCESS_WRITE;
+	wrbuf[1] = *buf;
+	wrbuf[2] = ~(*buf);
+	w1_write_block(sl->master, wrbuf, 3);
+
+	w1_read_block(sl->master, &ack, sizeof(ack));
+
+	mutex_unlock(&sl->master->mutex);
+
+	/* check for acknowledgement */
+	if (ack != 0xAA)
+		return -EIO;
+
+	return count;
+}
+
+static BIN_ATTR_RW(pio, 1);
+
+static ssize_t crccheck_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	if (put_user(w1_enable_crccheck + 0x30, buf))
+		return -EFAULT;
+
+	return sizeof(w1_enable_crccheck);
+}
+
+static ssize_t crccheck_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char val;
+
+	if (count != 1 || !buf)
+		return -EINVAL;
+
+	if (get_user(val, buf))
+		return -EFAULT;
+
+	/* convert to decimal */
+	val = val - 0x30;
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	/* set the new value */
+	w1_enable_crccheck = val;
+
+	return sizeof(w1_enable_crccheck);
+}
+
+static DEVICE_ATTR_RW(crccheck);
+
+static struct attribute *w1_f1C_attrs[] = {
+	&dev_attr_crccheck.attr,
+	NULL,
+};
+
+static struct bin_attribute *w1_f1C_bin_attrs[] = {
+	&bin_attr_eeprom,
+	&bin_attr_pio,
+	NULL,
+};
+
+static const struct attribute_group w1_f1C_group = {
+	.attrs		= w1_f1C_attrs,
+	.bin_attrs	= w1_f1C_bin_attrs,
+};
+
+static const struct attribute_group *w1_f1C_groups[] = {
+	&w1_f1C_group,
+	NULL,
+};
+
+static int w1_f1C_add_slave(struct w1_slave *sl)
+{
+	struct w1_f1C_data *data = NULL;
+
+	if (w1_enable_crccheck) {
+		data = kzalloc(sizeof(struct w1_f1C_data), GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		sl->family_data = data;
+	}
+
+	return 0;
+}
+
+static void w1_f1C_remove_slave(struct w1_slave *sl)
+{
+	kfree(sl->family_data);
+	sl->family_data = NULL;
+}
+
+static struct w1_family_ops w1_f1C_fops = {
+	.add_slave      = w1_f1C_add_slave,
+	.remove_slave   = w1_f1C_remove_slave,
+	.groups		= w1_f1C_groups,
+};
+
+static struct w1_family w1_family_1C = {
+	.fid = W1_FAMILY_DS28E04,
+	.fops = &w1_f1C_fops,
+};
+module_w1_family(w1_family_1C);
+
+MODULE_AUTHOR("Markus Franke <franke.m@sebakmt.com>, <franm@hrz.tu-chemnitz.de>");
+MODULE_DESCRIPTION("w1 family 1C driver for DS28E04, 4kb EEPROM and PIO");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E04));
diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c
new file mode 100644
index 0000000..e78b63e
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds28e17.c
@@ -0,0 +1,771 @@
+/*
+ *	w1_ds28e17.c - w1 family 19 (DS28E17) driver
+ *
+ * Copyright (c) 2016 Jan Kandziora <jjj@gmx.de>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/crc16.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#define CRC16_INIT 0
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_DS28E17 0x19
+
+/* Module setup. */
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jan Kandziora <jjj@gmx.de>");
+MODULE_DESCRIPTION("w1 family 19 driver for DS28E17, 1-wire to I2C master bridge");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E17));
+
+
+/* Default I2C speed to be set when a DS28E17 is detected. */
+static int i2c_speed = 100;
+module_param_named(speed, i2c_speed, int, (S_IRUSR | S_IWUSR));
+MODULE_PARM_DESC(speed, "Default I2C speed to be set when a DS28E17 is detected");
+
+/* Default I2C stretch value to be set when a DS28E17 is detected. */
+static char i2c_stretch = 1;
+module_param_named(stretch, i2c_stretch, byte, (S_IRUSR | S_IWUSR));
+MODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected");
+
+/* DS28E17 device command codes. */
+#define W1_F19_WRITE_DATA_WITH_STOP      0x4B
+#define W1_F19_WRITE_DATA_NO_STOP        0x5A
+#define W1_F19_WRITE_DATA_ONLY           0x69
+#define W1_F19_WRITE_DATA_ONLY_WITH_STOP 0x78
+#define W1_F19_READ_DATA_WITH_STOP       0x87
+#define W1_F19_WRITE_READ_DATA_WITH_STOP 0x2D
+#define W1_F19_WRITE_CONFIGURATION       0xD2
+#define W1_F19_READ_CONFIGURATION        0xE1
+#define W1_F19_ENABLE_SLEEP_MODE         0x1E
+#define W1_F19_READ_DEVICE_REVISION      0xC4
+
+/* DS28E17 status bits */
+#define W1_F19_STATUS_CRC     0x01
+#define W1_F19_STATUS_ADDRESS 0x02
+#define W1_F19_STATUS_START   0x08
+
+/*
+ * Maximum number of I2C bytes to transfer within one CRC16 protected onewire
+ * command.
+ * */
+#define W1_F19_WRITE_DATA_LIMIT 255
+
+/* Maximum number of I2C bytes to read with one onewire command. */
+#define W1_F19_READ_DATA_LIMIT 255
+
+/* Constants for calculating the busy sleep. */
+#define W1_F19_BUSY_TIMEBASES { 90, 23, 10 }
+#define W1_F19_BUSY_GRATUITY  1000
+
+/* Number of checks for the busy flag before timeout. */
+#define W1_F19_BUSY_CHECKS 1000
+
+
+/* Slave specific data. */
+struct w1_f19_data {
+	u8 speed;
+	u8 stretch;
+	struct i2c_adapter adapter;
+};
+
+
+/* Wait a while until the busy flag clears. */
+static int w1_f19_i2c_busy_wait(struct w1_slave *sl, size_t count)
+{
+	const unsigned long timebases[3] = W1_F19_BUSY_TIMEBASES;
+	struct w1_f19_data *data = sl->family_data;
+	unsigned int checks;
+
+	/* Check the busy flag first in any case.*/
+	if (w1_touch_bit(sl->master, 1) == 0)
+		return 0;
+
+	/*
+	 * Do a generously long sleep in the beginning,
+	 * as we have to wait at least this time for all
+	 * the I2C bytes at the given speed to be transferred.
+	 */
+	usleep_range(timebases[data->speed] * (data->stretch) * count,
+		timebases[data->speed] * (data->stretch) * count
+		+ W1_F19_BUSY_GRATUITY);
+
+	/* Now continusly check the busy flag sent by the DS28E17. */
+	checks = W1_F19_BUSY_CHECKS;
+	while ((checks--) > 0) {
+		/* Return success if the busy flag is cleared. */
+		if (w1_touch_bit(sl->master, 1) == 0)
+			return 0;
+
+		/* Wait one non-streched byte timeslot. */
+		udelay(timebases[data->speed]);
+	}
+
+	/* Timeout. */
+	dev_warn(&sl->dev, "busy timeout\n");
+	return -ETIMEDOUT;
+}
+
+
+/* Utility function: result. */
+static size_t w1_f19_error(struct w1_slave *sl, u8 w1_buf[])
+{
+	/* Warnings. */
+	if (w1_buf[0] & W1_F19_STATUS_CRC)
+		dev_warn(&sl->dev, "crc16 mismatch\n");
+	if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
+		dev_warn(&sl->dev, "i2c device not responding\n");
+	if ((w1_buf[0] & (W1_F19_STATUS_CRC | W1_F19_STATUS_ADDRESS)) == 0
+			&& w1_buf[1] != 0) {
+		dev_warn(&sl->dev, "i2c short write, %d bytes not acknowledged\n",
+			w1_buf[1]);
+	}
+
+	/* Check error conditions. */
+	if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
+		return -ENXIO;
+	if (w1_buf[0] & W1_F19_STATUS_START)
+		return -EAGAIN;
+	if (w1_buf[0] != 0 || w1_buf[1] != 0)
+		return -EIO;
+
+	/* All ok. */
+	return 0;
+}
+
+
+/* Utility function: write data to I2C slave, single chunk. */
+static int __w1_f19_i2c_write(struct w1_slave *sl,
+	const u8 *command, size_t command_count,
+	const u8 *buffer, size_t count)
+{
+	u16 crc;
+	int error;
+	u8 w1_buf[2];
+
+	/* Send command and I2C data to DS28E17. */
+	crc = crc16(CRC16_INIT, command, command_count);
+	w1_write_block(sl->master, command, command_count);
+
+	w1_buf[0] = count;
+	crc = crc16(crc, w1_buf, 1);
+	w1_write_8(sl->master, w1_buf[0]);
+
+	crc = crc16(crc, buffer, count);
+	w1_write_block(sl->master, buffer, count);
+
+	w1_buf[0] = ~(crc & 0xFF);
+	w1_buf[1] = ~((crc >> 8) & 0xFF);
+	w1_write_block(sl->master, w1_buf, 2);
+
+	/* Wait until busy flag clears (or timeout). */
+	if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
+		return -ETIMEDOUT;
+
+	/* Read status from DS28E17. */
+	w1_read_block(sl->master, w1_buf, 2);
+
+	/* Check error conditions. */
+	error = w1_f19_error(sl, w1_buf);
+	if (error < 0)
+		return error;
+
+	/* Return number of bytes written. */
+	return count;
+}
+
+
+/* Write data to I2C slave. */
+static int w1_f19_i2c_write(struct w1_slave *sl, u16 i2c_address,
+	const u8 *buffer, size_t count, bool stop)
+{
+	int result;
+	int remaining = count;
+	const u8 *p;
+	u8 command[2];
+
+	/* Check input. */
+	if (count == 0)
+		return -EOPNOTSUPP;
+
+	/* Check whether we need multiple commands. */
+	if (count <= W1_F19_WRITE_DATA_LIMIT) {
+		/*
+		 * Small data amount. Data can be sent with
+		 * a single onewire command.
+		 */
+
+		/* Send all data to DS28E17. */
+		command[0] = (stop ? W1_F19_WRITE_DATA_WITH_STOP
+			: W1_F19_WRITE_DATA_NO_STOP);
+		command[1] = i2c_address << 1;
+		result = __w1_f19_i2c_write(sl, command, 2, buffer, count);
+	} else {
+		/* Large data amount. Data has to be sent in multiple chunks. */
+
+		/* Send first chunk to DS28E17. */
+		p = buffer;
+		command[0] = W1_F19_WRITE_DATA_NO_STOP;
+		command[1] = i2c_address << 1;
+		result = __w1_f19_i2c_write(sl, command, 2, p,
+			W1_F19_WRITE_DATA_LIMIT);
+		if (result < 0)
+			return result;
+
+		/* Resume to same DS28E17. */
+		if (w1_reset_resume_command(sl->master))
+			return -EIO;
+
+		/* Next data chunk. */
+		p += W1_F19_WRITE_DATA_LIMIT;
+		remaining -= W1_F19_WRITE_DATA_LIMIT;
+
+		while (remaining > W1_F19_WRITE_DATA_LIMIT) {
+			/* Send intermediate chunk to DS28E17. */
+			command[0] = W1_F19_WRITE_DATA_ONLY;
+			result = __w1_f19_i2c_write(sl, command, 1, p,
+					W1_F19_WRITE_DATA_LIMIT);
+			if (result < 0)
+				return result;
+
+			/* Resume to same DS28E17. */
+			if (w1_reset_resume_command(sl->master))
+				return -EIO;
+
+			/* Next data chunk. */
+			p += W1_F19_WRITE_DATA_LIMIT;
+			remaining -= W1_F19_WRITE_DATA_LIMIT;
+		}
+
+		/* Send final chunk to DS28E17. */
+		command[0] = (stop ? W1_F19_WRITE_DATA_ONLY_WITH_STOP
+			: W1_F19_WRITE_DATA_ONLY);
+		result = __w1_f19_i2c_write(sl, command, 1, p, remaining);
+	}
+
+	return result;
+}
+
+
+/* Read data from I2C slave. */
+static int w1_f19_i2c_read(struct w1_slave *sl, u16 i2c_address,
+	u8 *buffer, size_t count)
+{
+	u16 crc;
+	int error;
+	u8 w1_buf[5];
+
+	/* Check input. */
+	if (count == 0)
+		return -EOPNOTSUPP;
+
+	/* Send command to DS28E17. */
+	w1_buf[0] = W1_F19_READ_DATA_WITH_STOP;
+	w1_buf[1] = i2c_address << 1 | 0x01;
+	w1_buf[2] = count;
+	crc = crc16(CRC16_INIT, w1_buf, 3);
+	w1_buf[3] = ~(crc & 0xFF);
+	w1_buf[4] = ~((crc >> 8) & 0xFF);
+	w1_write_block(sl->master, w1_buf, 5);
+
+	/* Wait until busy flag clears (or timeout). */
+	if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
+		return -ETIMEDOUT;
+
+	/* Read status from DS28E17. */
+	w1_buf[0] = w1_read_8(sl->master);
+	w1_buf[1] = 0;
+
+	/* Check error conditions. */
+	error = w1_f19_error(sl, w1_buf);
+	if (error < 0)
+		return error;
+
+	/* Read received I2C data from DS28E17. */
+	return w1_read_block(sl->master, buffer, count);
+}
+
+
+/* Write to, then read data from I2C slave. */
+static int w1_f19_i2c_write_read(struct w1_slave *sl, u16 i2c_address,
+	const u8 *wbuffer, size_t wcount, u8 *rbuffer, size_t rcount)
+{
+	u16 crc;
+	int error;
+	u8 w1_buf[3];
+
+	/* Check input. */
+	if (wcount == 0 || rcount == 0)
+		return -EOPNOTSUPP;
+
+	/* Send command and I2C data to DS28E17. */
+	w1_buf[0] = W1_F19_WRITE_READ_DATA_WITH_STOP;
+	w1_buf[1] = i2c_address << 1;
+	w1_buf[2] = wcount;
+	crc = crc16(CRC16_INIT, w1_buf, 3);
+	w1_write_block(sl->master, w1_buf, 3);
+
+	crc = crc16(crc, wbuffer, wcount);
+	w1_write_block(sl->master, wbuffer, wcount);
+
+	w1_buf[0] = rcount;
+	crc = crc16(crc, w1_buf, 1);
+	w1_buf[1] = ~(crc & 0xFF);
+	w1_buf[2] = ~((crc >> 8) & 0xFF);
+	w1_write_block(sl->master, w1_buf, 3);
+
+	/* Wait until busy flag clears (or timeout). */
+	if (w1_f19_i2c_busy_wait(sl, wcount + rcount + 2) < 0)
+		return -ETIMEDOUT;
+
+	/* Read status from DS28E17. */
+	w1_read_block(sl->master, w1_buf, 2);
+
+	/* Check error conditions. */
+	error = w1_f19_error(sl, w1_buf);
+	if (error < 0)
+		return error;
+
+	/* Read received I2C data from DS28E17. */
+	return w1_read_block(sl->master, rbuffer, rcount);
+}
+
+
+/* Do an I2C master transfer. */
+static int w1_f19_i2c_master_transfer(struct i2c_adapter *adapter,
+	struct i2c_msg *msgs, int num)
+{
+	struct w1_slave *sl = (struct w1_slave *) adapter->algo_data;
+	int i = 0;
+	int result = 0;
+
+	/* Start onewire transaction. */
+	mutex_lock(&sl->master->bus_mutex);
+
+	/* Select DS28E17. */
+	if (w1_reset_select_slave(sl)) {
+		i = -EIO;
+		goto error;
+	}
+
+	/* Loop while there are still messages to transfer. */
+	while (i < num) {
+		/*
+		 * Check for special case: Small write followed
+		 * by read to same I2C device.
+		 */
+		if (i < (num-1)
+			&& msgs[i].addr == msgs[i+1].addr
+			&& !(msgs[i].flags & I2C_M_RD)
+			&& (msgs[i+1].flags & I2C_M_RD)
+			&& (msgs[i].len <= W1_F19_WRITE_DATA_LIMIT)) {
+			/*
+			 * The DS28E17 has a combined transfer
+			 * for small write+read.
+			 */
+			result = w1_f19_i2c_write_read(sl, msgs[i].addr,
+				msgs[i].buf, msgs[i].len,
+				msgs[i+1].buf, msgs[i+1].len);
+			if (result < 0) {
+				i = result;
+				goto error;
+			}
+
+			/*
+			 * Check if we should interpret the read data
+			 * as a length byte. The DS28E17 unfortunately
+			 * has no read without stop, so we can just do
+			 * another simple read in that case.
+			 */
+			if (msgs[i+1].flags & I2C_M_RECV_LEN) {
+				result = w1_f19_i2c_read(sl, msgs[i+1].addr,
+					&(msgs[i+1].buf[1]), msgs[i+1].buf[0]);
+				if (result < 0) {
+					i = result;
+					goto error;
+				}
+			}
+
+			/* Eat up read message, too. */
+			i++;
+		} else if (msgs[i].flags & I2C_M_RD) {
+			/* Read transfer. */
+			result = w1_f19_i2c_read(sl, msgs[i].addr,
+				msgs[i].buf, msgs[i].len);
+			if (result < 0) {
+				i = result;
+				goto error;
+			}
+
+			/*
+			 * Check if we should interpret the read data
+			 * as a length byte. The DS28E17 unfortunately
+			 * has no read without stop, so we can just do
+			 * another simple read in that case.
+			 */
+			if (msgs[i].flags & I2C_M_RECV_LEN) {
+				result = w1_f19_i2c_read(sl,
+					msgs[i].addr,
+					&(msgs[i].buf[1]),
+					msgs[i].buf[0]);
+				if (result < 0) {
+					i = result;
+					goto error;
+				}
+			}
+		} else {
+			/*
+			 * Write transfer.
+			 * Stop condition only for last
+			 * transfer.
+			 */
+			result = w1_f19_i2c_write(sl,
+				msgs[i].addr,
+				msgs[i].buf,
+				msgs[i].len,
+				i == (num-1));
+			if (result < 0) {
+				i = result;
+				goto error;
+			}
+		}
+
+		/* Next message. */
+		i++;
+
+		/* Are there still messages to send/receive? */
+		if (i < num) {
+			/* Yes. Resume to same DS28E17. */
+			if (w1_reset_resume_command(sl->master)) {
+				i = -EIO;
+				goto error;
+			}
+		}
+	}
+
+error:
+	/* End onewire transaction. */
+	mutex_unlock(&sl->master->bus_mutex);
+
+	/* Return number of messages processed or error. */
+	return i;
+}
+
+
+/* Get I2C adapter functionality. */
+static u32 w1_f19_i2c_functionality(struct i2c_adapter *adapter)
+{
+	/*
+	 * Plain I2C functions only.
+	 * SMBus is emulated by the kernel's I2C layer.
+	 * No "I2C_FUNC_SMBUS_QUICK"
+	 * No "I2C_FUNC_SMBUS_READ_BLOCK_DATA"
+	 * No "I2C_FUNC_SMBUS_BLOCK_PROC_CALL"
+	 */
+	return I2C_FUNC_I2C |
+		I2C_FUNC_SMBUS_BYTE |
+		I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA |
+		I2C_FUNC_SMBUS_PROC_CALL |
+		I2C_FUNC_SMBUS_WRITE_BLOCK_DATA |
+		I2C_FUNC_SMBUS_I2C_BLOCK |
+		I2C_FUNC_SMBUS_PEC;
+}
+
+
+/* I2C adapter quirks. */
+static const struct i2c_adapter_quirks w1_f19_i2c_adapter_quirks = {
+	.max_read_len = W1_F19_READ_DATA_LIMIT,
+};
+
+/* I2C algorithm. */
+static const struct i2c_algorithm w1_f19_i2c_algorithm = {
+	.master_xfer    = w1_f19_i2c_master_transfer,
+	.functionality  = w1_f19_i2c_functionality,
+};
+
+
+/* Read I2C speed from DS28E17. */
+static int w1_f19_get_i2c_speed(struct w1_slave *sl)
+{
+	struct w1_f19_data *data = sl->family_data;
+	int result = -EIO;
+
+	/* Start onewire transaction. */
+	mutex_lock(&sl->master->bus_mutex);
+
+	/* Select slave. */
+	if (w1_reset_select_slave(sl))
+		goto error;
+
+	/* Read slave configuration byte. */
+	w1_write_8(sl->master, W1_F19_READ_CONFIGURATION);
+	result = w1_read_8(sl->master);
+	if (result < 0 || result > 2) {
+		result = -EIO;
+		goto error;
+	}
+
+	/* Update speed in slave specific data. */
+	data->speed = result;
+
+error:
+	/* End onewire transaction. */
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return result;
+}
+
+
+/* Set I2C speed on DS28E17. */
+static int __w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
+{
+	struct w1_f19_data *data = sl->family_data;
+	const int i2c_speeds[3] = { 100, 400, 900 };
+	u8 w1_buf[2];
+
+	/* Select slave. */
+	if (w1_reset_select_slave(sl))
+		return -EIO;
+
+	w1_buf[0] = W1_F19_WRITE_CONFIGURATION;
+	w1_buf[1] = speed;
+	w1_write_block(sl->master, w1_buf, 2);
+
+	/* Update speed in slave specific data. */
+	data->speed = speed;
+
+	dev_info(&sl->dev, "i2c speed set to %d kBaud\n", i2c_speeds[speed]);
+
+	return 0;
+}
+
+static int w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
+{
+	int result;
+
+	/* Start onewire transaction. */
+	mutex_lock(&sl->master->bus_mutex);
+
+	/* Set I2C speed on DS28E17. */
+	result = __w1_f19_set_i2c_speed(sl, speed);
+
+	/* End onewire transaction. */
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return result;
+}
+
+
+/* Sysfs attributes. */
+
+/* I2C speed attribute for a single chip. */
+static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+	int result;
+
+	/* Read current speed from slave. Updates data->speed. */
+	result = w1_f19_get_i2c_speed(sl);
+	if (result < 0)
+		return result;
+
+	/* Return current speed value. */
+	return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+	int error;
+
+	/* Valid values are: "100", "400", "900" */
+	if (count < 3 || count > 4 || !buf)
+		return -EINVAL;
+	if (count == 4 && buf[3] != '\n')
+		return -EINVAL;
+	if (buf[1] != '0' || buf[2] != '0')
+		return -EINVAL;
+
+	/* Set speed on slave. */
+	switch (buf[0]) {
+	case '1':
+		error = w1_f19_set_i2c_speed(sl, 0);
+		break;
+	case '4':
+		error = w1_f19_set_i2c_speed(sl, 1);
+		break;
+	case '9':
+		error = w1_f19_set_i2c_speed(sl, 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (error < 0)
+		return error;
+
+	/* Return bytes written. */
+	return count;
+}
+
+static DEVICE_ATTR_RW(speed);
+
+
+/* Busy stretch attribute for a single chip. */
+static ssize_t stretch_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+	struct w1_f19_data *data = sl->family_data;
+
+	/* Return current stretch value. */
+	return sprintf(buf, "%d\n", data->stretch);
+}
+
+static ssize_t stretch_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+	struct w1_f19_data *data = sl->family_data;
+
+	/* Valid values are '1' to '9' */
+	if (count < 1 || count > 2 || !buf)
+		return -EINVAL;
+	if (count == 2 && buf[1] != '\n')
+		return -EINVAL;
+	if (buf[0] < '1' || buf[0] > '9')
+		return -EINVAL;
+
+	/* Set busy stretch value. */
+	data->stretch = buf[0] & 0x0F;
+
+	/* Return bytes written. */
+	return count;
+}
+
+static DEVICE_ATTR_RW(stretch);
+
+
+/* All attributes. */
+static struct attribute *w1_f19_attrs[] = {
+	&dev_attr_speed.attr,
+	&dev_attr_stretch.attr,
+	NULL,
+};
+
+static const struct attribute_group w1_f19_group = {
+	.attrs		= w1_f19_attrs,
+};
+
+static const struct attribute_group *w1_f19_groups[] = {
+	&w1_f19_group,
+	NULL,
+};
+
+
+/* Slave add and remove functions. */
+static int w1_f19_add_slave(struct w1_slave *sl)
+{
+	struct w1_f19_data *data = NULL;
+
+	/* Allocate memory for slave specific data. */
+	data = devm_kzalloc(&sl->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	sl->family_data = data;
+
+	/* Setup default I2C speed on slave. */
+	switch (i2c_speed) {
+	case 100:
+		__w1_f19_set_i2c_speed(sl, 0);
+		break;
+	case 400:
+		__w1_f19_set_i2c_speed(sl, 1);
+		break;
+	case 900:
+		__w1_f19_set_i2c_speed(sl, 2);
+		break;
+	default:
+		/*
+		 * A i2c_speed module parameter of anything else
+		 * than 100, 400, 900 means not to touch the
+		 * speed of the DS28E17.
+		 * We assume 400kBaud, the power-on value.
+		 */
+		data->speed = 1;
+	}
+
+	/*
+	 * Setup default busy stretch
+	 * configuration for the DS28E17.
+	 */
+	data->stretch = i2c_stretch;
+
+	/* Setup I2C adapter. */
+	data->adapter.owner      = THIS_MODULE;
+	data->adapter.algo       = &w1_f19_i2c_algorithm;
+	data->adapter.algo_data  = sl;
+	strcpy(data->adapter.name, "w1-");
+	strcat(data->adapter.name, sl->name);
+	data->adapter.dev.parent = &sl->dev;
+	data->adapter.quirks     = &w1_f19_i2c_adapter_quirks;
+
+	return i2c_add_adapter(&data->adapter);
+}
+
+static void w1_f19_remove_slave(struct w1_slave *sl)
+{
+	struct w1_f19_data *family_data = sl->family_data;
+
+	/* Delete I2C adapter. */
+	i2c_del_adapter(&family_data->adapter);
+
+	/* Free slave specific data. */
+	devm_kfree(&sl->dev, family_data);
+	sl->family_data = NULL;
+}
+
+
+/* Declarations within the w1 subsystem. */
+static struct w1_family_ops w1_f19_fops = {
+	.add_slave = w1_f19_add_slave,
+	.remove_slave = w1_f19_remove_slave,
+	.groups = w1_f19_groups,
+};
+
+static struct w1_family w1_family_19 = {
+	.fid = W1_FAMILY_DS28E17,
+	.fops = &w1_f19_fops,
+};
+
+
+/* Module init and remove functions. */
+static int __init w1_f19_init(void)
+{
+	return w1_register_family(&w1_family_19);
+}
+
+static void __exit w1_f19_fini(void)
+{
+	w1_unregister_family(&w1_family_19);
+}
+
+module_init(w1_f19_init);
+module_exit(w1_f19_fini);
+
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c
new file mode 100644
index 0000000..e556b0c
--- /dev/null
+++ b/drivers/w1/slaves/w1_smem.c
@@ -0,0 +1,73 @@
+/*
+ *	w1_smem.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/types.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include <linux/w1.h>
+
+#define W1_FAMILY_SMEM_01	0x01
+#define W1_FAMILY_SMEM_81	0x81
+
+static struct w1_family w1_smem_family_01 = {
+	.fid = W1_FAMILY_SMEM_01,
+};
+
+static struct w1_family w1_smem_family_81 = {
+	.fid = W1_FAMILY_SMEM_81,
+};
+
+static int __init w1_smem_init(void)
+{
+	int err;
+
+	err = w1_register_family(&w1_smem_family_01);
+	if (err)
+		return err;
+
+	err = w1_register_family(&w1_smem_family_81);
+	if (err) {
+		w1_unregister_family(&w1_smem_family_01);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit w1_smem_fini(void)
+{
+	w1_unregister_family(&w1_smem_family_01);
+	w1_unregister_family(&w1_smem_family_81);
+}
+
+module_init(w1_smem_init);
+module_exit(w1_smem_fini);
+
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_SMEM_01));
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_SMEM_81));
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
new file mode 100644
index 0000000..3c350df
--- /dev/null
+++ b/drivers/w1/slaves/w1_therm.c
@@ -0,0 +1,761 @@
+/*
+ *	w1_therm.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the therms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/types.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/hwmon.h>
+
+#include <linux/w1.h>
+
+#define W1_THERM_DS18S20	0x10
+#define W1_THERM_DS1822		0x22
+#define W1_THERM_DS18B20	0x28
+#define W1_THERM_DS1825		0x3B
+#define W1_THERM_DS28EA00	0x42
+
+/* Allow the strong pullup to be disabled, but default to enabled.
+ * If it was disabled a parasite powered device might not get the require
+ * current to do a temperature conversion.  If it is enabled parasite powered
+ * devices have a better chance of getting the current required.
+ * In case the parasite power-detection is not working (seems to be the case
+ * for some DS18S20) the strong pullup can also be forced, regardless of the
+ * power state of the devices.
+ *
+ * Summary of options:
+ * - strong_pullup = 0	Disable strong pullup completely
+ * - strong_pullup = 1	Enable automatic strong pullup detection
+ * - strong_pullup = 2	Force strong pullup
+ */
+static int w1_strong_pullup = 1;
+module_param_named(strong_pullup, w1_strong_pullup, int, 0);
+
+struct w1_therm_family_data {
+	uint8_t rom[9];
+	atomic_t refcnt;
+};
+
+struct therm_info {
+	u8 rom[9];
+	u8 crc;
+	u8 verdict;
+};
+
+/* return the address of the refcnt in the family data */
+#define THERM_REFCNT(family_data) \
+	(&((struct w1_therm_family_data *)family_data)->refcnt)
+
+static int w1_therm_add_slave(struct w1_slave *sl)
+{
+	sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
+		GFP_KERNEL);
+	if (!sl->family_data)
+		return -ENOMEM;
+	atomic_set(THERM_REFCNT(sl->family_data), 1);
+	return 0;
+}
+
+static void w1_therm_remove_slave(struct w1_slave *sl)
+{
+	int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
+
+	while (refcnt) {
+		msleep(1000);
+		refcnt = atomic_read(THERM_REFCNT(sl->family_data));
+	}
+	kfree(sl->family_data);
+	sl->family_data = NULL;
+}
+
+static ssize_t w1_slave_show(struct device *device,
+	struct device_attribute *attr, char *buf);
+
+static ssize_t w1_slave_store(struct device *device,
+	struct device_attribute *attr, const char *buf, size_t size);
+
+static ssize_t w1_seq_show(struct device *device,
+	struct device_attribute *attr, char *buf);
+
+static DEVICE_ATTR_RW(w1_slave);
+static DEVICE_ATTR_RO(w1_seq);
+
+static struct attribute *w1_therm_attrs[] = {
+	&dev_attr_w1_slave.attr,
+	NULL,
+};
+
+static struct attribute *w1_ds28ea00_attrs[] = {
+	&dev_attr_w1_slave.attr,
+	&dev_attr_w1_seq.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(w1_therm);
+ATTRIBUTE_GROUPS(w1_ds28ea00);
+
+#if IS_REACHABLE(CONFIG_HWMON)
+static int w1_read_temp(struct device *dev, u32 attr, int channel,
+			long *val);
+
+static umode_t w1_is_visible(const void *_data, enum hwmon_sensor_types type,
+			     u32 attr, int channel)
+{
+	return attr == hwmon_temp_input ? 0444 : 0;
+}
+
+static int w1_read(struct device *dev, enum hwmon_sensor_types type,
+		   u32 attr, int channel, long *val)
+{
+	switch (type) {
+	case hwmon_temp:
+		return w1_read_temp(dev, attr, channel, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static const u32 w1_temp_config[] = {
+	HWMON_T_INPUT,
+	0
+};
+
+static const struct hwmon_channel_info w1_temp = {
+	.type = hwmon_temp,
+	.config = w1_temp_config,
+};
+
+static const struct hwmon_channel_info *w1_info[] = {
+	&w1_temp,
+	NULL
+};
+
+static const struct hwmon_ops w1_hwmon_ops = {
+	.is_visible = w1_is_visible,
+	.read = w1_read,
+};
+
+static const struct hwmon_chip_info w1_chip_info = {
+	.ops = &w1_hwmon_ops,
+	.info = w1_info,
+};
+#define W1_CHIPINFO	(&w1_chip_info)
+#else
+#define W1_CHIPINFO	NULL
+#endif
+
+static struct w1_family_ops w1_therm_fops = {
+	.add_slave	= w1_therm_add_slave,
+	.remove_slave	= w1_therm_remove_slave,
+	.groups		= w1_therm_groups,
+	.chip_info	= W1_CHIPINFO,
+};
+
+static struct w1_family_ops w1_ds28ea00_fops = {
+	.add_slave	= w1_therm_add_slave,
+	.remove_slave	= w1_therm_remove_slave,
+	.groups		= w1_ds28ea00_groups,
+	.chip_info	= W1_CHIPINFO,
+};
+
+static struct w1_family w1_therm_family_DS18S20 = {
+	.fid = W1_THERM_DS18S20,
+	.fops = &w1_therm_fops,
+};
+
+static struct w1_family w1_therm_family_DS18B20 = {
+	.fid = W1_THERM_DS18B20,
+	.fops = &w1_therm_fops,
+};
+
+static struct w1_family w1_therm_family_DS1822 = {
+	.fid = W1_THERM_DS1822,
+	.fops = &w1_therm_fops,
+};
+
+static struct w1_family w1_therm_family_DS28EA00 = {
+	.fid = W1_THERM_DS28EA00,
+	.fops = &w1_ds28ea00_fops,
+};
+
+static struct w1_family w1_therm_family_DS1825 = {
+	.fid = W1_THERM_DS1825,
+	.fops = &w1_therm_fops,
+};
+
+struct w1_therm_family_converter {
+	u8			broken;
+	u16			reserved;
+	struct w1_family	*f;
+	int			(*convert)(u8 rom[9]);
+	int			(*precision)(struct device *device, int val);
+	int			(*eeprom)(struct device *device);
+};
+
+/* write configuration to eeprom */
+static inline int w1_therm_eeprom(struct device *device);
+
+/* Set precision for conversion */
+static inline int w1_DS18B20_precision(struct device *device, int val);
+static inline int w1_DS18S20_precision(struct device *device, int val);
+
+/* The return value is millidegrees Centigrade. */
+static inline int w1_DS18B20_convert_temp(u8 rom[9]);
+static inline int w1_DS18S20_convert_temp(u8 rom[9]);
+
+static struct w1_therm_family_converter w1_therm_families[] = {
+	{
+		.f		= &w1_therm_family_DS18S20,
+		.convert	= w1_DS18S20_convert_temp,
+		.precision	= w1_DS18S20_precision,
+		.eeprom		= w1_therm_eeprom
+	},
+	{
+		.f		= &w1_therm_family_DS1822,
+		.convert	= w1_DS18B20_convert_temp,
+		.precision	= w1_DS18S20_precision,
+		.eeprom		= w1_therm_eeprom
+	},
+	{
+		.f		= &w1_therm_family_DS18B20,
+		.convert	= w1_DS18B20_convert_temp,
+		.precision	= w1_DS18B20_precision,
+		.eeprom		= w1_therm_eeprom
+	},
+	{
+		.f		= &w1_therm_family_DS28EA00,
+		.convert	= w1_DS18B20_convert_temp,
+		.precision	= w1_DS18S20_precision,
+		.eeprom		= w1_therm_eeprom
+	},
+	{
+		.f		= &w1_therm_family_DS1825,
+		.convert	= w1_DS18B20_convert_temp,
+		.precision	= w1_DS18S20_precision,
+		.eeprom		= w1_therm_eeprom
+	}
+};
+
+static inline int w1_therm_eeprom(struct device *device)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	struct w1_master *dev = sl->master;
+	u8 rom[9], external_power;
+	int ret, max_trying = 10;
+	u8 *family_data = sl->family_data;
+
+	if (!sl->family_data) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	/* prevent the slave from going away in sleep */
+	atomic_inc(THERM_REFCNT(family_data));
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret != 0)
+		goto dec_refcnt;
+
+	memset(rom, 0, sizeof(rom));
+
+	while (max_trying--) {
+		if (!w1_reset_select_slave(sl)) {
+			unsigned int tm = 10;
+			unsigned long sleep_rem;
+
+			/* check if in parasite mode */
+			w1_write_8(dev, W1_READ_PSUPPLY);
+			external_power = w1_read_8(dev);
+
+			if (w1_reset_select_slave(sl))
+				continue;
+
+			/* 10ms strong pullup/delay after the copy command */
+			if (w1_strong_pullup == 2 ||
+			    (!external_power && w1_strong_pullup))
+				w1_next_pullup(dev, tm);
+
+			w1_write_8(dev, W1_COPY_SCRATCHPAD);
+
+			if (external_power) {
+				mutex_unlock(&dev->bus_mutex);
+
+				sleep_rem = msleep_interruptible(tm);
+				if (sleep_rem != 0) {
+					ret = -EINTR;
+					goto dec_refcnt;
+				}
+
+				ret = mutex_lock_interruptible(&dev->bus_mutex);
+				if (ret != 0)
+					goto dec_refcnt;
+			} else if (!w1_strong_pullup) {
+				sleep_rem = msleep_interruptible(tm);
+				if (sleep_rem != 0) {
+					ret = -EINTR;
+					goto mt_unlock;
+				}
+			}
+
+			break;
+		}
+	}
+
+mt_unlock:
+	mutex_unlock(&dev->bus_mutex);
+dec_refcnt:
+	atomic_dec(THERM_REFCNT(family_data));
+error:
+	return ret;
+}
+
+/* DS18S20 does not feature configuration register */
+static inline int w1_DS18S20_precision(struct device *device, int val)
+{
+	return 0;
+}
+
+static inline int w1_DS18B20_precision(struct device *device, int val)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	struct w1_master *dev = sl->master;
+	u8 rom[9], crc;
+	int ret, max_trying = 10;
+	u8 *family_data = sl->family_data;
+	uint8_t precision_bits;
+	uint8_t mask = 0x60;
+
+	if (val > 12 || val < 9) {
+		pr_warn("Unsupported precision\n");
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (!sl->family_data) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	/* prevent the slave from going away in sleep */
+	atomic_inc(THERM_REFCNT(family_data));
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret != 0)
+		goto dec_refcnt;
+
+	memset(rom, 0, sizeof(rom));
+
+	/* translate precision to bitmask (see datasheet page 9) */
+	switch (val) {
+	case 9:
+		precision_bits = 0x00;
+		break;
+	case 10:
+		precision_bits = 0x20;
+		break;
+	case 11:
+		precision_bits = 0x40;
+		break;
+	case 12:
+	default:
+		precision_bits = 0x60;
+		break;
+	}
+
+	while (max_trying--) {
+		crc = 0;
+
+		if (!w1_reset_select_slave(sl)) {
+			int count = 0;
+
+			/* read values to only alter precision bits */
+			w1_write_8(dev, W1_READ_SCRATCHPAD);
+			count = w1_read_block(dev, rom, 9);
+			if (count != 9)
+				dev_warn(device, "w1_read_block() returned %u instead of 9.\n",	count);
+
+			crc = w1_calc_crc8(rom, 8);
+			if (rom[8] == crc) {
+				rom[4] = (rom[4] & ~mask) | (precision_bits & mask);
+
+				if (!w1_reset_select_slave(sl)) {
+					w1_write_8(dev, W1_WRITE_SCRATCHPAD);
+					w1_write_8(dev, rom[2]);
+					w1_write_8(dev, rom[3]);
+					w1_write_8(dev, rom[4]);
+
+					break;
+				}
+			}
+		}
+	}
+
+	mutex_unlock(&dev->bus_mutex);
+dec_refcnt:
+	atomic_dec(THERM_REFCNT(family_data));
+error:
+	return ret;
+}
+
+static inline int w1_DS18B20_convert_temp(u8 rom[9])
+{
+	s16 t = le16_to_cpup((__le16 *)rom);
+
+	return t*1000/16;
+}
+
+static inline int w1_DS18S20_convert_temp(u8 rom[9])
+{
+	int t, h;
+
+	if (!rom[7])
+		return 0;
+
+	if (rom[1] == 0)
+		t = ((s32)rom[0] >> 1)*1000;
+	else
+		t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
+
+	t -= 250;
+	h = 1000*((s32)rom[7] - (s32)rom[6]);
+	h /= (s32)rom[7];
+	t += h;
+
+	return t;
+}
+
+static inline int w1_convert_temp(u8 rom[9], u8 fid)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
+		if (w1_therm_families[i].f->fid == fid)
+			return w1_therm_families[i].convert(rom);
+
+	return 0;
+}
+
+static ssize_t w1_slave_store(struct device *device,
+			      struct device_attribute *attr, const char *buf,
+			      size_t size)
+{
+	int val, ret;
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	int i;
+
+	ret = kstrtoint(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
+		if (w1_therm_families[i].f->fid == sl->family->fid) {
+			/* zero value indicates to write current configuration to eeprom */
+			if (val == 0)
+				ret = w1_therm_families[i].eeprom(device);
+			else
+				ret = w1_therm_families[i].precision(device, val);
+			break;
+		}
+	}
+	return ret ? : size;
+}
+
+static ssize_t read_therm(struct device *device,
+			  struct w1_slave *sl, struct therm_info *info)
+{
+	struct w1_master *dev = sl->master;
+	u8 external_power;
+	int ret, max_trying = 10;
+	u8 *family_data = sl->family_data;
+
+	if (!family_data) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	/* prevent the slave from going away in sleep */
+	atomic_inc(THERM_REFCNT(family_data));
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret != 0)
+		goto dec_refcnt;
+
+	memset(info->rom, 0, sizeof(info->rom));
+
+	while (max_trying--) {
+
+		info->verdict = 0;
+		info->crc = 0;
+
+		if (!w1_reset_select_slave(sl)) {
+			int count = 0;
+			unsigned int tm = 750;
+			unsigned long sleep_rem;
+
+			w1_write_8(dev, W1_READ_PSUPPLY);
+			external_power = w1_read_8(dev);
+
+			if (w1_reset_select_slave(sl))
+				continue;
+
+			/* 750ms strong pullup (or delay) after the convert */
+			if (w1_strong_pullup == 2 ||
+					(!external_power && w1_strong_pullup))
+				w1_next_pullup(dev, tm);
+
+			w1_write_8(dev, W1_CONVERT_TEMP);
+
+			if (external_power) {
+				mutex_unlock(&dev->bus_mutex);
+
+				sleep_rem = msleep_interruptible(tm);
+				if (sleep_rem != 0) {
+					ret = -EINTR;
+					goto dec_refcnt;
+				}
+
+				ret = mutex_lock_interruptible(&dev->bus_mutex);
+				if (ret != 0)
+					goto dec_refcnt;
+			} else if (!w1_strong_pullup) {
+				sleep_rem = msleep_interruptible(tm);
+				if (sleep_rem != 0) {
+					ret = -EINTR;
+					goto mt_unlock;
+				}
+			}
+
+			if (!w1_reset_select_slave(sl)) {
+
+				w1_write_8(dev, W1_READ_SCRATCHPAD);
+				count = w1_read_block(dev, info->rom, 9);
+				if (count != 9) {
+					dev_warn(device, "w1_read_block() "
+						"returned %u instead of 9.\n",
+						count);
+				}
+
+				info->crc = w1_calc_crc8(info->rom, 8);
+
+				if (info->rom[8] == info->crc)
+					info->verdict = 1;
+			}
+		}
+
+		if (info->verdict)
+			break;
+	}
+
+mt_unlock:
+	mutex_unlock(&dev->bus_mutex);
+dec_refcnt:
+	atomic_dec(THERM_REFCNT(family_data));
+error:
+	return ret;
+}
+
+static ssize_t w1_slave_show(struct device *device,
+			     struct device_attribute *attr, char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	struct therm_info info;
+	u8 *family_data = sl->family_data;
+	int ret, i;
+	ssize_t c = PAGE_SIZE;
+	u8 fid = sl->family->fid;
+
+	ret = read_therm(device, sl, &info);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < 9; ++i)
+		c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", info.rom[i]);
+	c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
+		      info.crc, (info.verdict) ? "YES" : "NO");
+	if (info.verdict)
+		memcpy(family_data, info.rom, sizeof(info.rom));
+	else
+		dev_warn(device, "Read failed CRC check\n");
+
+	for (i = 0; i < 9; ++i)
+		c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ",
+			      ((u8 *)family_data)[i]);
+
+	c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
+			w1_convert_temp(info.rom, fid));
+	ret = PAGE_SIZE - c;
+	return ret;
+}
+
+#if IS_REACHABLE(CONFIG_HWMON)
+static int w1_read_temp(struct device *device, u32 attr, int channel,
+			long *val)
+{
+	struct w1_slave *sl = dev_get_drvdata(device);
+	struct therm_info info;
+	u8 fid = sl->family->fid;
+	int ret;
+
+	switch (attr) {
+	case hwmon_temp_input:
+		ret = read_therm(device, sl, &info);
+		if (ret)
+			return ret;
+
+		if (!info.verdict) {
+			ret = -EIO;
+			return ret;
+		}
+
+		*val = w1_convert_temp(info.rom, fid);
+		ret = 0;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+#endif
+
+#define W1_42_CHAIN	0x99
+#define W1_42_CHAIN_OFF	0x3C
+#define W1_42_CHAIN_OFF_INV	0xC3
+#define W1_42_CHAIN_ON	0x5A
+#define W1_42_CHAIN_ON_INV	0xA5
+#define W1_42_CHAIN_DONE 0x96
+#define W1_42_CHAIN_DONE_INV 0x69
+#define W1_42_COND_READ	0x0F
+#define W1_42_SUCCESS_CONFIRM_BYTE 0xAA
+#define W1_42_FINISHED_BYTE 0xFF
+static ssize_t w1_seq_show(struct device *device,
+	struct device_attribute *attr, char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	ssize_t c = PAGE_SIZE;
+	int rv;
+	int i;
+	u8 ack;
+	u64 rn;
+	struct w1_reg_num *reg_num;
+	int seq = 0;
+
+	mutex_lock(&sl->master->bus_mutex);
+	/* Place all devices in CHAIN state */
+	if (w1_reset_bus(sl->master))
+		goto error;
+	w1_write_8(sl->master, W1_SKIP_ROM);
+	w1_write_8(sl->master, W1_42_CHAIN);
+	w1_write_8(sl->master, W1_42_CHAIN_ON);
+	w1_write_8(sl->master, W1_42_CHAIN_ON_INV);
+	msleep(sl->master->pullup_duration);
+
+	/* check for acknowledgment */
+	ack = w1_read_8(sl->master);
+	if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
+		goto error;
+
+	/* In case the bus fails to send 0xFF, limit*/
+	for (i = 0; i <= 64; i++) {
+		if (w1_reset_bus(sl->master))
+			goto error;
+
+		w1_write_8(sl->master, W1_42_COND_READ);
+		rv = w1_read_block(sl->master, (u8 *)&rn, 8);
+		reg_num = (struct w1_reg_num *) &rn;
+		if (reg_num->family == W1_42_FINISHED_BYTE)
+			break;
+		if (sl->reg_num.id == reg_num->id)
+			seq = i;
+
+		w1_write_8(sl->master, W1_42_CHAIN);
+		w1_write_8(sl->master, W1_42_CHAIN_DONE);
+		w1_write_8(sl->master, W1_42_CHAIN_DONE_INV);
+		w1_read_block(sl->master, &ack, sizeof(ack));
+
+		/* check for acknowledgment */
+		ack = w1_read_8(sl->master);
+		if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
+			goto error;
+
+	}
+
+	/* Exit from CHAIN state */
+	if (w1_reset_bus(sl->master))
+		goto error;
+	w1_write_8(sl->master, W1_SKIP_ROM);
+	w1_write_8(sl->master, W1_42_CHAIN);
+	w1_write_8(sl->master, W1_42_CHAIN_OFF);
+	w1_write_8(sl->master, W1_42_CHAIN_OFF_INV);
+
+	/* check for acknowledgment */
+	ack = w1_read_8(sl->master);
+	if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
+		goto error;
+	mutex_unlock(&sl->master->bus_mutex);
+
+	c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq);
+	return PAGE_SIZE - c;
+error:
+	mutex_unlock(&sl->master->bus_mutex);
+	return -EIO;
+}
+
+static int __init w1_therm_init(void)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
+		err = w1_register_family(w1_therm_families[i].f);
+		if (err)
+			w1_therm_families[i].broken = 1;
+	}
+
+	return 0;
+}
+
+static void __exit w1_therm_fini(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
+		if (!w1_therm_families[i].broken)
+			w1_unregister_family(w1_therm_families[i].f);
+}
+
+module_init(w1_therm_init);
+module_exit(w1_therm_fini);
+
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18S20));
+MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1822));
+MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18B20));
+MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1825));
+MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00));
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
new file mode 100644
index 0000000..890c038
--- /dev/null
+++ b/drivers/w1/w1.c
@@ -0,0 +1,1254 @@
+/*
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/hwmon.h>
+#include <linux/of.h>
+
+#include <linux/atomic.h>
+
+#include "w1_internal.h"
+#include "w1_netlink.h"
+
+#define W1_FAMILY_DEFAULT	0
+
+static int w1_timeout = 10;
+module_param_named(timeout, w1_timeout, int, 0);
+MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
+
+static int w1_timeout_us = 0;
+module_param_named(timeout_us, w1_timeout_us, int, 0);
+MODULE_PARM_DESC(timeout_us,
+		 "time in microseconds between automatic slave searches");
+
+/* A search stops when w1_max_slave_count devices have been found in that
+ * search.  The next search will start over and detect the same set of devices
+ * on a static 1-wire bus.  Memory is not allocated based on this number, just
+ * on the number of devices known to the kernel.  Having a high number does not
+ * consume additional resources.  As a special case, if there is only one
+ * device on the network and w1_max_slave_count is set to 1, the device id can
+ * be read directly skipping the normal slower search process.
+ */
+int w1_max_slave_count = 64;
+module_param_named(max_slave_count, w1_max_slave_count, int, 0);
+MODULE_PARM_DESC(max_slave_count,
+	"maximum number of slaves detected in a search");
+
+int w1_max_slave_ttl = 10;
+module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
+MODULE_PARM_DESC(slave_ttl,
+	"Number of searches not seeing a slave before it will be removed");
+
+DEFINE_MUTEX(w1_mlock);
+LIST_HEAD(w1_masters);
+
+static int w1_master_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static int w1_master_probe(struct device *dev)
+{
+	return -ENODEV;
+}
+
+static void w1_master_release(struct device *dev)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+
+	dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name);
+	memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
+	kfree(md);
+}
+
+static void w1_slave_release(struct device *dev)
+{
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+
+	dev_dbg(dev, "%s: Releasing %s [%p]\n", __func__, sl->name, sl);
+
+	w1_family_put(sl->family);
+	sl->master->slave_count--;
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+
+	return sprintf(buf, "%s\n", sl->name);
+}
+static DEVICE_ATTR_RO(name);
+
+static ssize_t id_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+	ssize_t count = sizeof(sl->reg_num);
+
+	memcpy(buf, (u8 *)&sl->reg_num, count);
+	return count;
+}
+static DEVICE_ATTR_RO(id);
+
+static struct attribute *w1_slave_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_id.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(w1_slave);
+
+/* Default family */
+
+static ssize_t rw_write(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr, char *buf, loff_t off,
+			size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+
+	mutex_lock(&sl->master->mutex);
+	if (w1_reset_select_slave(sl)) {
+		count = 0;
+		goto out_up;
+	}
+
+	w1_write_block(sl->master, buf, count);
+
+out_up:
+	mutex_unlock(&sl->master->mutex);
+	return count;
+}
+
+static ssize_t rw_read(struct file *filp, struct kobject *kobj,
+		       struct bin_attribute *bin_attr, char *buf, loff_t off,
+		       size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+
+	mutex_lock(&sl->master->mutex);
+	w1_read_block(sl->master, buf, count);
+	mutex_unlock(&sl->master->mutex);
+	return count;
+}
+
+static BIN_ATTR_RW(rw, PAGE_SIZE);
+
+static struct bin_attribute *w1_slave_bin_attrs[] = {
+	&bin_attr_rw,
+	NULL,
+};
+
+static const struct attribute_group w1_slave_default_group = {
+	.bin_attrs = w1_slave_bin_attrs,
+};
+
+static const struct attribute_group *w1_slave_default_groups[] = {
+	&w1_slave_default_group,
+	NULL,
+};
+
+static struct w1_family_ops w1_default_fops = {
+	.groups		= w1_slave_default_groups,
+};
+
+static struct w1_family w1_default_family = {
+	.fops = &w1_default_fops,
+};
+
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
+
+static struct bus_type w1_bus_type = {
+	.name = "w1",
+	.match = w1_master_match,
+	.uevent = w1_uevent,
+};
+
+struct device_driver w1_master_driver = {
+	.name = "w1_master_driver",
+	.bus = &w1_bus_type,
+	.probe = w1_master_probe,
+};
+
+struct device w1_master_device = {
+	.parent = NULL,
+	.bus = &w1_bus_type,
+	.init_name = "w1 bus master",
+	.driver = &w1_master_driver,
+	.release = &w1_master_release
+};
+
+static struct device_driver w1_slave_driver = {
+	.name = "w1_slave_driver",
+	.bus = &w1_bus_type,
+};
+
+#if 0
+struct device w1_slave_device = {
+	.parent = NULL,
+	.bus = &w1_bus_type,
+	.init_name = "w1 bus slave",
+	.driver = &w1_slave_driver,
+	.release = &w1_slave_release
+};
+#endif  /*  0  */
+
+static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	ssize_t count;
+
+	mutex_lock(&md->mutex);
+	count = sprintf(buf, "%s\n", md->name);
+	mutex_unlock(&md->mutex);
+
+	return count;
+}
+
+static ssize_t w1_master_attribute_store_search(struct device * dev,
+						struct device_attribute *attr,
+						const char * buf, size_t count)
+{
+	long tmp;
+	struct w1_master *md = dev_to_w1_master(dev);
+	int ret;
+
+	ret = kstrtol(buf, 0, &tmp);
+	if (ret)
+		return ret;
+
+	mutex_lock(&md->mutex);
+	md->search_count = tmp;
+	mutex_unlock(&md->mutex);
+	/* Only wake if it is going to be searching. */
+	if (tmp)
+		wake_up_process(md->thread);
+
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_search(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	ssize_t count;
+
+	mutex_lock(&md->mutex);
+	count = sprintf(buf, "%d\n", md->search_count);
+	mutex_unlock(&md->mutex);
+
+	return count;
+}
+
+static ssize_t w1_master_attribute_store_pullup(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	long tmp;
+	struct w1_master *md = dev_to_w1_master(dev);
+	int ret;
+
+	ret = kstrtol(buf, 0, &tmp);
+	if (ret)
+		return ret;
+
+	mutex_lock(&md->mutex);
+	md->enable_pullup = tmp;
+	mutex_unlock(&md->mutex);
+
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_pullup(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	ssize_t count;
+
+	mutex_lock(&md->mutex);
+	count = sprintf(buf, "%d\n", md->enable_pullup);
+	mutex_unlock(&md->mutex);
+
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	ssize_t count;
+
+	mutex_lock(&md->mutex);
+	count = sprintf(buf, "0x%p\n", md->bus_master);
+	mutex_unlock(&md->mutex);
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	ssize_t count;
+	count = sprintf(buf, "%d\n", w1_timeout);
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_timeout_us(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t count;
+	count = sprintf(buf, "%d\n", w1_timeout_us);
+	return count;
+}
+
+static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int tmp;
+	struct w1_master *md = dev_to_w1_master(dev);
+
+	if (kstrtoint(buf, 0, &tmp) || tmp < 1)
+		return -EINVAL;
+
+	mutex_lock(&md->mutex);
+	md->max_slave_count = tmp;
+	/* allow each time the max_slave_count is updated */
+	clear_bit(W1_WARN_MAX_COUNT, &md->flags);
+	mutex_unlock(&md->mutex);
+
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	ssize_t count;
+
+	mutex_lock(&md->mutex);
+	count = sprintf(buf, "%d\n", md->max_slave_count);
+	mutex_unlock(&md->mutex);
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	ssize_t count;
+
+	mutex_lock(&md->mutex);
+	count = sprintf(buf, "%lu\n", md->attempts);
+	mutex_unlock(&md->mutex);
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	ssize_t count;
+
+	mutex_lock(&md->mutex);
+	count = sprintf(buf, "%d\n", md->slave_count);
+	mutex_unlock(&md->mutex);
+	return count;
+}
+
+static ssize_t w1_master_attribute_show_slaves(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	int c = PAGE_SIZE;
+	struct list_head *ent, *n;
+	struct w1_slave *sl = NULL;
+
+	mutex_lock(&md->list_mutex);
+
+	list_for_each_safe(ent, n, &md->slist) {
+		sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+
+		c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
+	}
+	if (!sl)
+		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
+
+	mutex_unlock(&md->list_mutex);
+
+	return PAGE_SIZE - c;
+}
+
+static ssize_t w1_master_attribute_show_add(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	int c = PAGE_SIZE;
+	c -= snprintf(buf+PAGE_SIZE - c, c,
+		"write device id xx-xxxxxxxxxxxx to add slave\n");
+	return PAGE_SIZE - c;
+}
+
+static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
+	struct w1_reg_num *rn)
+{
+	unsigned int family;
+	unsigned long long id;
+	int i;
+	u64 rn64_le;
+
+	/* The CRC value isn't read from the user because the sysfs directory
+	 * doesn't include it and most messages from the bus search don't
+	 * print it either.  It would be unreasonable for the user to then
+	 * provide it.
+	 */
+	const char *error_msg = "bad slave string format, expecting "
+		"ff-dddddddddddd\n";
+
+	if (buf[2] != '-') {
+		dev_err(dev, "%s", error_msg);
+		return -EINVAL;
+	}
+	i = sscanf(buf, "%02x-%012llx", &family, &id);
+	if (i != 2) {
+		dev_err(dev, "%s", error_msg);
+		return -EINVAL;
+	}
+	rn->family = family;
+	rn->id = id;
+
+	rn64_le = cpu_to_le64(*(u64 *)rn);
+	rn->crc = w1_calc_crc8((u8 *)&rn64_le, 7);
+
+#if 0
+	dev_info(dev, "With CRC device is %02x.%012llx.%02x.\n",
+		  rn->family, (unsigned long long)rn->id, rn->crc);
+#endif
+
+	return 0;
+}
+
+/* Searches the slaves in the w1_master and returns a pointer or NULL.
+ * Note: must not hold list_mutex
+ */
+struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+	struct w1_reg_num *rn)
+{
+	struct w1_slave *sl;
+	mutex_lock(&dev->list_mutex);
+	list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+		if (sl->reg_num.family == rn->family &&
+				sl->reg_num.id == rn->id &&
+				sl->reg_num.crc == rn->crc) {
+			mutex_unlock(&dev->list_mutex);
+			return sl;
+		}
+	}
+	mutex_unlock(&dev->list_mutex);
+	return NULL;
+}
+
+static ssize_t w1_master_attribute_store_add(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	struct w1_reg_num rn;
+	struct w1_slave *sl;
+	ssize_t result = count;
+
+	if (w1_atoreg_num(dev, buf, count, &rn))
+		return -EINVAL;
+
+	mutex_lock(&md->mutex);
+	sl = w1_slave_search_device(md, &rn);
+	/* It would be nice to do a targeted search one the one-wire bus
+	 * for the new device to see if it is out there or not.  But the
+	 * current search doesn't support that.
+	 */
+	if (sl) {
+		dev_info(dev, "Device %s already exists\n", sl->name);
+		result = -EINVAL;
+	} else {
+		w1_attach_slave_device(md, &rn);
+	}
+	mutex_unlock(&md->mutex);
+
+	return result;
+}
+
+static ssize_t w1_master_attribute_show_remove(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	int c = PAGE_SIZE;
+	c -= snprintf(buf+PAGE_SIZE - c, c,
+		"write device id xx-xxxxxxxxxxxx to remove slave\n");
+	return PAGE_SIZE - c;
+}
+
+static ssize_t w1_master_attribute_store_remove(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct w1_master *md = dev_to_w1_master(dev);
+	struct w1_reg_num rn;
+	struct w1_slave *sl;
+	ssize_t result = count;
+
+	if (w1_atoreg_num(dev, buf, count, &rn))
+		return -EINVAL;
+
+	mutex_lock(&md->mutex);
+	sl = w1_slave_search_device(md, &rn);
+	if (sl) {
+		result = w1_slave_detach(sl);
+		/* refcnt 0 means it was detached in the call */
+		if (result == 0)
+			result = count;
+	} else {
+		dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
+			(unsigned long long)rn.id);
+		result = -EINVAL;
+	}
+	mutex_unlock(&md->mutex);
+
+	return result;
+}
+
+#define W1_MASTER_ATTR_RO(_name, _mode)				\
+	struct device_attribute w1_master_attribute_##_name =	\
+		__ATTR(w1_master_##_name, _mode,		\
+		       w1_master_attribute_show_##_name, NULL)
+
+#define W1_MASTER_ATTR_RW(_name, _mode)				\
+	struct device_attribute w1_master_attribute_##_name =	\
+		__ATTR(w1_master_##_name, _mode,		\
+		       w1_master_attribute_show_##_name,	\
+		       w1_master_attribute_store_##_name)
+
+static W1_MASTER_ATTR_RO(name, S_IRUGO);
+static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
+static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);
+static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
+static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
+static W1_MASTER_ATTR_RO(timeout_us, S_IRUGO);
+static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
+static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUSR | S_IWGRP);
+static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUSR | S_IWGRP);
+static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUSR | S_IWGRP);
+static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static struct attribute *w1_master_default_attrs[] = {
+	&w1_master_attribute_name.attr,
+	&w1_master_attribute_slaves.attr,
+	&w1_master_attribute_slave_count.attr,
+	&w1_master_attribute_max_slave_count.attr,
+	&w1_master_attribute_attempts.attr,
+	&w1_master_attribute_timeout.attr,
+	&w1_master_attribute_timeout_us.attr,
+	&w1_master_attribute_pointer.attr,
+	&w1_master_attribute_search.attr,
+	&w1_master_attribute_pullup.attr,
+	&w1_master_attribute_add.attr,
+	&w1_master_attribute_remove.attr,
+	NULL
+};
+
+static const struct attribute_group w1_master_defattr_group = {
+	.attrs = w1_master_default_attrs,
+};
+
+int w1_create_master_attributes(struct w1_master *master)
+{
+	return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
+}
+
+void w1_destroy_master_attributes(struct w1_master *master)
+{
+	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
+}
+
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct w1_master *md = NULL;
+	struct w1_slave *sl = NULL;
+	char *event_owner, *name;
+	int err = 0;
+
+	if (dev->driver == &w1_master_driver) {
+		md = container_of(dev, struct w1_master, dev);
+		event_owner = "master";
+		name = md->name;
+	} else if (dev->driver == &w1_slave_driver) {
+		sl = container_of(dev, struct w1_slave, dev);
+		event_owner = "slave";
+		name = sl->name;
+	} else {
+		dev_dbg(dev, "Unknown event.\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n",
+			event_owner, name, dev_name(dev));
+
+	if (dev->driver != &w1_slave_driver || !sl)
+		goto end;
+
+	err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
+	if (err)
+		goto end;
+
+	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
+			     (unsigned long long)sl->reg_num.id);
+end:
+	return err;
+}
+
+static int w1_family_notify(unsigned long action, struct w1_slave *sl)
+{
+	struct w1_family_ops *fops;
+	int err;
+
+	fops = sl->family->fops;
+
+	if (!fops)
+		return 0;
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		/* if the family driver needs to initialize something... */
+		if (fops->add_slave) {
+			err = fops->add_slave(sl);
+			if (err < 0) {
+				dev_err(&sl->dev,
+					"add_slave() call failed. err=%d\n",
+					err);
+				return err;
+			}
+		}
+		if (fops->groups) {
+			err = sysfs_create_groups(&sl->dev.kobj, fops->groups);
+			if (err) {
+				dev_err(&sl->dev,
+					"sysfs group creation failed. err=%d\n",
+					err);
+				return err;
+			}
+		}
+		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info) {
+			struct device *hwmon
+				= hwmon_device_register_with_info(&sl->dev,
+						"w1_slave_temp", sl,
+						fops->chip_info,
+						NULL);
+			if (IS_ERR(hwmon)) {
+				dev_warn(&sl->dev,
+					 "could not create hwmon device\n");
+			} else {
+				sl->hwmon = hwmon;
+			}
+		}
+		break;
+	case BUS_NOTIFY_DEL_DEVICE:
+		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info &&
+			    sl->hwmon)
+			hwmon_device_unregister(sl->hwmon);
+		if (fops->remove_slave)
+			sl->family->fops->remove_slave(sl);
+		if (fops->groups)
+			sysfs_remove_groups(&sl->dev.kobj, fops->groups);
+		break;
+	}
+	return 0;
+}
+
+static int __w1_attach_slave_device(struct w1_slave *sl)
+{
+	int err;
+
+	sl->dev.parent = &sl->master->dev;
+	sl->dev.driver = &w1_slave_driver;
+	sl->dev.bus = &w1_bus_type;
+	sl->dev.release = &w1_slave_release;
+	sl->dev.groups = w1_slave_groups;
+	sl->dev.of_node = of_find_matching_node(sl->master->dev.of_node,
+						sl->family->of_match_table);
+
+	dev_set_name(&sl->dev, "%02x-%012llx",
+		 (unsigned int) sl->reg_num.family,
+		 (unsigned long long) sl->reg_num.id);
+	snprintf(&sl->name[0], sizeof(sl->name),
+		 "%02x-%012llx",
+		 (unsigned int) sl->reg_num.family,
+		 (unsigned long long) sl->reg_num.id);
+
+	dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__,
+		dev_name(&sl->dev), sl);
+
+	/* suppress for w1_family_notify before sending KOBJ_ADD */
+	dev_set_uevent_suppress(&sl->dev, true);
+
+	err = device_register(&sl->dev);
+	if (err < 0) {
+		dev_err(&sl->dev,
+			"Device registration [%s] failed. err=%d\n",
+			dev_name(&sl->dev), err);
+		put_device(&sl->dev);
+		return err;
+	}
+	w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl);
+
+	dev_set_uevent_suppress(&sl->dev, false);
+	kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
+
+	mutex_lock(&sl->master->list_mutex);
+	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
+	mutex_unlock(&sl->master->list_mutex);
+
+	return 0;
+}
+
+int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
+{
+	struct w1_slave *sl;
+	struct w1_family *f;
+	int err;
+	struct w1_netlink_msg msg;
+
+	sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
+	if (!sl) {
+		dev_err(&dev->dev,
+			 "%s: failed to allocate new slave device.\n",
+			 __func__);
+		return -ENOMEM;
+	}
+
+
+	sl->owner = THIS_MODULE;
+	sl->master = dev;
+	set_bit(W1_SLAVE_ACTIVE, &sl->flags);
+
+	memset(&msg, 0, sizeof(msg));
+	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
+	atomic_set(&sl->refcnt, 1);
+	atomic_inc(&sl->master->refcnt);
+	dev->slave_count++;
+	dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x\n",
+		  rn->family, (unsigned long long)rn->id, rn->crc);
+
+	/* slave modules need to be loaded in a context with unlocked mutex */
+	mutex_unlock(&dev->mutex);
+	request_module("w1-family-0x%02X", rn->family);
+	mutex_lock(&dev->mutex);
+
+	spin_lock(&w1_flock);
+	f = w1_family_registered(rn->family);
+	if (!f) {
+		f= &w1_default_family;
+		dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
+			  rn->family, rn->family,
+			  (unsigned long long)rn->id, rn->crc);
+	}
+	__w1_family_get(f);
+	spin_unlock(&w1_flock);
+
+	sl->family = f;
+
+	err = __w1_attach_slave_device(sl);
+	if (err < 0) {
+		dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
+			 sl->name);
+		dev->slave_count--;
+		w1_family_put(sl->family);
+		atomic_dec(&sl->master->refcnt);
+		kfree(sl);
+		return err;
+	}
+
+	sl->ttl = dev->slave_ttl;
+
+	memcpy(msg.id.id, rn, sizeof(msg.id));
+	msg.type = W1_SLAVE_ADD;
+	w1_netlink_send(dev, &msg);
+
+	return 0;
+}
+
+int w1_unref_slave(struct w1_slave *sl)
+{
+	struct w1_master *dev = sl->master;
+	int refcnt;
+	mutex_lock(&dev->list_mutex);
+	refcnt = atomic_sub_return(1, &sl->refcnt);
+	if (refcnt == 0) {
+		struct w1_netlink_msg msg;
+
+		dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__,
+			sl->name, sl);
+
+		list_del(&sl->w1_slave_entry);
+
+		memset(&msg, 0, sizeof(msg));
+		memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
+		msg.type = W1_SLAVE_REMOVE;
+		w1_netlink_send(sl->master, &msg);
+
+		w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl);
+		device_unregister(&sl->dev);
+		#ifdef DEBUG
+		memset(sl, 0, sizeof(*sl));
+		#endif
+		kfree(sl);
+	}
+	atomic_dec(&dev->refcnt);
+	mutex_unlock(&dev->list_mutex);
+	return refcnt;
+}
+
+int w1_slave_detach(struct w1_slave *sl)
+{
+	/* Only detach a slave once as it decreases the refcnt each time. */
+	int destroy_now;
+	mutex_lock(&sl->master->list_mutex);
+	destroy_now = !test_bit(W1_SLAVE_DETACH, &sl->flags);
+	set_bit(W1_SLAVE_DETACH, &sl->flags);
+	mutex_unlock(&sl->master->list_mutex);
+
+	if (destroy_now)
+		destroy_now = !w1_unref_slave(sl);
+	return destroy_now ? 0 : -EBUSY;
+}
+
+struct w1_master *w1_search_master_id(u32 id)
+{
+	struct w1_master *dev;
+	int found = 0;
+
+	mutex_lock(&w1_mlock);
+	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+		if (dev->id == id) {
+			found = 1;
+			atomic_inc(&dev->refcnt);
+			break;
+		}
+	}
+	mutex_unlock(&w1_mlock);
+
+	return (found)?dev:NULL;
+}
+
+struct w1_slave *w1_search_slave(struct w1_reg_num *id)
+{
+	struct w1_master *dev;
+	struct w1_slave *sl = NULL;
+	int found = 0;
+
+	mutex_lock(&w1_mlock);
+	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+		mutex_lock(&dev->list_mutex);
+		list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+			if (sl->reg_num.family == id->family &&
+					sl->reg_num.id == id->id &&
+					sl->reg_num.crc == id->crc) {
+				found = 1;
+				atomic_inc(&dev->refcnt);
+				atomic_inc(&sl->refcnt);
+				break;
+			}
+		}
+		mutex_unlock(&dev->list_mutex);
+
+		if (found)
+			break;
+	}
+	mutex_unlock(&w1_mlock);
+
+	return (found)?sl:NULL;
+}
+
+void w1_reconnect_slaves(struct w1_family *f, int attach)
+{
+	struct w1_slave *sl, *sln;
+	struct w1_master *dev;
+
+	mutex_lock(&w1_mlock);
+	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
+			"for family %02x.\n", dev->name, f->fid);
+		mutex_lock(&dev->mutex);
+		mutex_lock(&dev->list_mutex);
+		list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+			/* If it is a new family, slaves with the default
+			 * family driver and are that family will be
+			 * connected.  If the family is going away, devices
+			 * matching that family are reconneced.
+			 */
+			if ((attach && sl->family->fid == W1_FAMILY_DEFAULT
+				&& sl->reg_num.family == f->fid) ||
+				(!attach && sl->family->fid == f->fid)) {
+				struct w1_reg_num rn;
+
+				mutex_unlock(&dev->list_mutex);
+				memcpy(&rn, &sl->reg_num, sizeof(rn));
+				/* If it was already in use let the automatic
+				 * scan pick it up again later.
+				 */
+				if (!w1_slave_detach(sl))
+					w1_attach_slave_device(dev, &rn);
+				mutex_lock(&dev->list_mutex);
+			}
+		}
+		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
+			"has been finished.\n", dev->name);
+		mutex_unlock(&dev->list_mutex);
+		mutex_unlock(&dev->mutex);
+	}
+	mutex_unlock(&w1_mlock);
+}
+
+void w1_slave_found(struct w1_master *dev, u64 rn)
+{
+	struct w1_slave *sl;
+	struct w1_reg_num *tmp;
+	u64 rn_le = cpu_to_le64(rn);
+
+	atomic_inc(&dev->refcnt);
+
+	tmp = (struct w1_reg_num *) &rn;
+
+	sl = w1_slave_search_device(dev, tmp);
+	if (sl) {
+		set_bit(W1_SLAVE_ACTIVE, &sl->flags);
+	} else {
+		if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7))
+			w1_attach_slave_device(dev, tmp);
+	}
+
+	atomic_dec(&dev->refcnt);
+}
+
+/**
+ * w1_search() - Performs a ROM Search & registers any devices found.
+ * @dev: The master device to search
+ * @search_type: W1_SEARCH to search all devices, or W1_ALARM_SEARCH
+ * to return only devices in the alarmed state
+ * @cb: Function to call when a device is found
+ *
+ * The 1-wire search is a simple binary tree search.
+ * For each bit of the address, we read two bits and write one bit.
+ * The bit written will put to sleep all devies that don't match that bit.
+ * When the two reads differ, the direction choice is obvious.
+ * When both bits are 0, we must choose a path to take.
+ * When we can scan all 64 bits without having to choose a path, we are done.
+ *
+ * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com
+ *
+ */
+void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
+{
+	u64 last_rn, rn, tmp64;
+	int i, slave_count = 0;
+	int last_zero, last_device;
+	int search_bit, desc_bit;
+	u8  triplet_ret = 0;
+
+	search_bit = 0;
+	rn = dev->search_id;
+	last_rn = 0;
+	last_device = 0;
+	last_zero = -1;
+
+	desc_bit = 64;
+
+	while ( !last_device && (slave_count++ < dev->max_slave_count) ) {
+		last_rn = rn;
+		rn = 0;
+
+		/*
+		 * Reset bus and all 1-wire device state machines
+		 * so they can respond to our requests.
+		 *
+		 * Return 0 - device(s) present, 1 - no devices present.
+		 */
+		mutex_lock(&dev->bus_mutex);
+		if (w1_reset_bus(dev)) {
+			mutex_unlock(&dev->bus_mutex);
+			dev_dbg(&dev->dev, "No devices present on the wire.\n");
+			break;
+		}
+
+		/* Do fast search on single slave bus */
+		if (dev->max_slave_count == 1) {
+			int rv;
+			w1_write_8(dev, W1_READ_ROM);
+			rv = w1_read_block(dev, (u8 *)&rn, 8);
+			mutex_unlock(&dev->bus_mutex);
+
+			if (rv == 8 && rn)
+				cb(dev, rn);
+
+			break;
+		}
+
+		/* Start the search */
+		w1_write_8(dev, search_type);
+		for (i = 0; i < 64; ++i) {
+			/* Determine the direction/search bit */
+			if (i == desc_bit)
+				search_bit = 1;	  /* took the 0 path last time, so take the 1 path */
+			else if (i > desc_bit)
+				search_bit = 0;	  /* take the 0 path on the next branch */
+			else
+				search_bit = ((last_rn >> i) & 0x1);
+
+			/* Read two bits and write one bit */
+			triplet_ret = w1_triplet(dev, search_bit);
+
+			/* quit if no device responded */
+			if ( (triplet_ret & 0x03) == 0x03 )
+				break;
+
+			/* If both directions were valid, and we took the 0 path... */
+			if (triplet_ret == 0)
+				last_zero = i;
+
+			/* extract the direction taken & update the device number */
+			tmp64 = (triplet_ret >> 2);
+			rn |= (tmp64 << i);
+
+			if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {
+				mutex_unlock(&dev->bus_mutex);
+				dev_dbg(&dev->dev, "Abort w1_search\n");
+				return;
+			}
+		}
+		mutex_unlock(&dev->bus_mutex);
+
+		if ( (triplet_ret & 0x03) != 0x03 ) {
+			if ((desc_bit == last_zero) || (last_zero < 0)) {
+				last_device = 1;
+				dev->search_id = 0;
+			} else {
+				dev->search_id = rn;
+			}
+			desc_bit = last_zero;
+			cb(dev, rn);
+		}
+
+		if (!last_device && slave_count == dev->max_slave_count &&
+			!test_bit(W1_WARN_MAX_COUNT, &dev->flags)) {
+			/* Only max_slave_count will be scanned in a search,
+			 * but it will start where it left off next search
+			 * until all ids are identified and then it will start
+			 * over.  A continued search will report the previous
+			 * last id as the first id (provided it is still on the
+			 * bus).
+			 */
+			dev_info(&dev->dev, "%s: max_slave_count %d reached, "
+				"will continue next search.\n", __func__,
+				dev->max_slave_count);
+			set_bit(W1_WARN_MAX_COUNT, &dev->flags);
+		}
+	}
+}
+
+void w1_search_process_cb(struct w1_master *dev, u8 search_type,
+	w1_slave_found_callback cb)
+{
+	struct w1_slave *sl, *sln;
+
+	mutex_lock(&dev->list_mutex);
+	list_for_each_entry(sl, &dev->slist, w1_slave_entry)
+		clear_bit(W1_SLAVE_ACTIVE, &sl->flags);
+	mutex_unlock(&dev->list_mutex);
+
+	w1_search_devices(dev, search_type, cb);
+
+	mutex_lock(&dev->list_mutex);
+	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+		if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) {
+			mutex_unlock(&dev->list_mutex);
+			w1_slave_detach(sl);
+			mutex_lock(&dev->list_mutex);
+		}
+		else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))
+			sl->ttl = dev->slave_ttl;
+	}
+	mutex_unlock(&dev->list_mutex);
+
+	if (dev->search_count > 0)
+		dev->search_count--;
+}
+
+static void w1_search_process(struct w1_master *dev, u8 search_type)
+{
+	w1_search_process_cb(dev, search_type, w1_slave_found);
+}
+
+/**
+ * w1_process_callbacks() - execute each dev->async_list callback entry
+ * @dev: w1_master device
+ *
+ * The w1 master list_mutex must be held.
+ *
+ * Return: 1 if there were commands to executed 0 otherwise
+ */
+int w1_process_callbacks(struct w1_master *dev)
+{
+	int ret = 0;
+	struct w1_async_cmd *async_cmd, *async_n;
+
+	/* The list can be added to in another thread, loop until it is empty */
+	while (!list_empty(&dev->async_list)) {
+		list_for_each_entry_safe(async_cmd, async_n, &dev->async_list,
+			async_entry) {
+			/* drop the lock, if it is a search it can take a long
+			 * time */
+			mutex_unlock(&dev->list_mutex);
+			async_cmd->cb(dev, async_cmd);
+			ret = 1;
+			mutex_lock(&dev->list_mutex);
+		}
+	}
+	return ret;
+}
+
+int w1_process(void *data)
+{
+	struct w1_master *dev = (struct w1_master *) data;
+	/* As long as w1_timeout is only set by a module parameter the sleep
+	 * time can be calculated in jiffies once.
+	 */
+	const unsigned long jtime =
+	  usecs_to_jiffies(w1_timeout * 1000000 + w1_timeout_us);
+	/* remainder if it woke up early */
+	unsigned long jremain = 0;
+
+	for (;;) {
+
+		if (!jremain && dev->search_count) {
+			mutex_lock(&dev->mutex);
+			w1_search_process(dev, W1_SEARCH);
+			mutex_unlock(&dev->mutex);
+		}
+
+		mutex_lock(&dev->list_mutex);
+		/* Note, w1_process_callback drops the lock while processing,
+		 * but locks it again before returning.
+		 */
+		if (!w1_process_callbacks(dev) && jremain) {
+			/* a wake up is either to stop the thread, process
+			 * callbacks, or search, it isn't process callbacks, so
+			 * schedule a search.
+			 */
+			jremain = 1;
+		}
+
+		__set_current_state(TASK_INTERRUPTIBLE);
+
+		/* hold list_mutex until after interruptible to prevent loosing
+		 * the wakeup signal when async_cmd is added.
+		 */
+		mutex_unlock(&dev->list_mutex);
+
+		if (kthread_should_stop())
+			break;
+
+		/* Only sleep when the search is active. */
+		if (dev->search_count) {
+			if (!jremain)
+				jremain = jtime;
+			jremain = schedule_timeout(jremain);
+		}
+		else
+			schedule();
+	}
+
+	atomic_dec(&dev->refcnt);
+
+	return 0;
+}
+
+static int __init w1_init(void)
+{
+	int retval;
+
+	pr_info("Driver for 1-wire Dallas network protocol.\n");
+
+	w1_init_netlink();
+
+	retval = bus_register(&w1_bus_type);
+	if (retval) {
+		pr_err("Failed to register bus. err=%d.\n", retval);
+		goto err_out_exit_init;
+	}
+
+	retval = driver_register(&w1_master_driver);
+	if (retval) {
+		pr_err("Failed to register master driver. err=%d.\n",
+			retval);
+		goto err_out_bus_unregister;
+	}
+
+	retval = driver_register(&w1_slave_driver);
+	if (retval) {
+		pr_err("Failed to register slave driver. err=%d.\n",
+			retval);
+		goto err_out_master_unregister;
+	}
+
+	return 0;
+
+#if 0
+/* For undoing the slave register if there was a step after it. */
+err_out_slave_unregister:
+	driver_unregister(&w1_slave_driver);
+#endif
+
+err_out_master_unregister:
+	driver_unregister(&w1_master_driver);
+
+err_out_bus_unregister:
+	bus_unregister(&w1_bus_type);
+
+err_out_exit_init:
+	return retval;
+}
+
+static void __exit w1_fini(void)
+{
+	struct w1_master *dev;
+
+	/* Set netlink removal messages and some cleanup */
+	list_for_each_entry(dev, &w1_masters, w1_master_entry)
+		__w1_remove_master_device(dev);
+
+	w1_fini_netlink();
+
+	driver_unregister(&w1_slave_driver);
+	driver_unregister(&w1_master_driver);
+	bus_unregister(&w1_bus_type);
+}
+
+module_init(w1_init);
+module_exit(w1_fini);
+
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
new file mode 100644
index 0000000..f14ab0b
--- /dev/null
+++ b/drivers/w1/w1_family.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sched/signal.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+
+#include "w1_internal.h"
+
+DEFINE_SPINLOCK(w1_flock);
+static LIST_HEAD(w1_families);
+
+/**
+ * w1_register_family() - register a device family driver
+ * @newf:	family to register
+ */
+int w1_register_family(struct w1_family *newf)
+{
+	struct list_head *ent, *n;
+	struct w1_family *f;
+	int ret = 0;
+
+	spin_lock(&w1_flock);
+	list_for_each_safe(ent, n, &w1_families) {
+		f = list_entry(ent, struct w1_family, family_entry);
+
+		if (f->fid == newf->fid) {
+			ret = -EEXIST;
+			break;
+		}
+	}
+
+	if (!ret) {
+		atomic_set(&newf->refcnt, 0);
+		list_add_tail(&newf->family_entry, &w1_families);
+	}
+	spin_unlock(&w1_flock);
+
+	/* check default devices against the new set of drivers */
+	w1_reconnect_slaves(newf, 1);
+
+	return ret;
+}
+EXPORT_SYMBOL(w1_register_family);
+
+/**
+ * w1_unregister_family() - unregister a device family driver
+ * @fent:	family to unregister
+ */
+void w1_unregister_family(struct w1_family *fent)
+{
+	struct list_head *ent, *n;
+	struct w1_family *f;
+
+	spin_lock(&w1_flock);
+	list_for_each_safe(ent, n, &w1_families) {
+		f = list_entry(ent, struct w1_family, family_entry);
+
+		if (f->fid == fent->fid) {
+			list_del(&fent->family_entry);
+			break;
+		}
+	}
+	spin_unlock(&w1_flock);
+
+	/* deatch devices using this family code */
+	w1_reconnect_slaves(fent, 0);
+
+	while (atomic_read(&fent->refcnt)) {
+		pr_info("Waiting for family %u to become free: refcnt=%d.\n",
+				fent->fid, atomic_read(&fent->refcnt));
+
+		if (msleep_interruptible(1000))
+			flush_signals(current);
+	}
+}
+EXPORT_SYMBOL(w1_unregister_family);
+
+/*
+ * Should be called under w1_flock held.
+ */
+struct w1_family * w1_family_registered(u8 fid)
+{
+	struct list_head *ent, *n;
+	struct w1_family *f = NULL;
+	int ret = 0;
+
+	list_for_each_safe(ent, n, &w1_families) {
+		f = list_entry(ent, struct w1_family, family_entry);
+
+		if (f->fid == fid) {
+			ret = 1;
+			break;
+		}
+	}
+
+	return (ret) ? f : NULL;
+}
+
+static void __w1_family_put(struct w1_family *f)
+{
+	atomic_dec(&f->refcnt);
+}
+
+void w1_family_put(struct w1_family *f)
+{
+	spin_lock(&w1_flock);
+	__w1_family_put(f);
+	spin_unlock(&w1_flock);
+}
+
+#if 0
+void w1_family_get(struct w1_family *f)
+{
+	spin_lock(&w1_flock);
+	__w1_family_get(f);
+	spin_unlock(&w1_flock);
+}
+#endif  /*  0  */
+
+void __w1_family_get(struct w1_family *f)
+{
+	smp_mb__before_atomic();
+	atomic_inc(&f->refcnt);
+	smp_mb__after_atomic();
+}
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
new file mode 100644
index 0000000..1c77617
--- /dev/null
+++ b/drivers/w1/w1_int.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/sched/signal.h>
+#include <linux/export.h>
+#include <linux/moduleparam.h>
+
+#include "w1_internal.h"
+#include "w1_netlink.h"
+
+static int w1_search_count = -1; /* Default is continual scan */
+module_param_named(search_count, w1_search_count, int, 0);
+
+static int w1_enable_pullup = 1;
+module_param_named(enable_pullup, w1_enable_pullup, int, 0);
+
+static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
+				       struct device_driver *driver,
+				       struct device *device)
+{
+	struct w1_master *dev;
+	int err;
+
+	/*
+	 * We are in process context(kernel thread), so can sleep.
+	 */
+	dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
+	if (!dev) {
+		pr_err("Failed to allocate %zd bytes for new w1 device.\n",
+			sizeof(struct w1_master));
+		return NULL;
+	}
+
+
+	dev->bus_master = (struct w1_bus_master *)(dev + 1);
+
+	dev->owner		= THIS_MODULE;
+	dev->max_slave_count	= slave_count;
+	dev->slave_count	= 0;
+	dev->attempts		= 0;
+	dev->initialized	= 0;
+	dev->id			= id;
+	dev->slave_ttl		= slave_ttl;
+	dev->search_count	= w1_search_count;
+	dev->enable_pullup	= w1_enable_pullup;
+
+	/* 1 for w1_process to decrement
+	 * 1 for __w1_remove_master_device to decrement
+	 */
+	atomic_set(&dev->refcnt, 2);
+
+	INIT_LIST_HEAD(&dev->slist);
+	INIT_LIST_HEAD(&dev->async_list);
+	mutex_init(&dev->mutex);
+	mutex_init(&dev->bus_mutex);
+	mutex_init(&dev->list_mutex);
+
+	memcpy(&dev->dev, device, sizeof(struct device));
+	dev_set_name(&dev->dev, "w1_bus_master%u", dev->id);
+	snprintf(dev->name, sizeof(dev->name), "w1_bus_master%u", dev->id);
+	dev->dev.init_name = dev->name;
+
+	dev->driver = driver;
+
+	dev->seq = 1;
+
+	err = device_register(&dev->dev);
+	if (err) {
+		pr_err("Failed to register master device. err=%d\n", err);
+		put_device(&dev->dev);
+		dev = NULL;
+	}
+
+	return dev;
+}
+
+static void w1_free_dev(struct w1_master *dev)
+{
+	device_unregister(&dev->dev);
+}
+
+/**
+ * w1_add_master_device() - registers a new master device
+ * @master:	master bus device to register
+ */
+int w1_add_master_device(struct w1_bus_master *master)
+{
+	struct w1_master *dev, *entry;
+	int retval = 0;
+	struct w1_netlink_msg msg;
+	int id, found;
+
+	/* 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)) {
+		pr_err("w1_add_master_device: invalid function set\n");
+		return(-EINVAL);
+	}
+
+	/* Lock until the device is added (or not) to w1_masters. */
+	mutex_lock(&w1_mlock);
+	/* Search for the first available id (starting at 1). */
+	id = 0;
+	do {
+		++id;
+		found = 0;
+		list_for_each_entry(entry, &w1_masters, w1_master_entry) {
+			if (entry->id == id) {
+				found = 1;
+				break;
+			}
+		}
+	} while (found);
+
+	dev = w1_alloc_dev(id, w1_max_slave_count, w1_max_slave_ttl,
+		&w1_master_driver, &w1_master_device);
+	if (!dev) {
+		mutex_unlock(&w1_mlock);
+		return -ENOMEM;
+	}
+
+	retval =  w1_create_master_attributes(dev);
+	if (retval) {
+		mutex_unlock(&w1_mlock);
+		goto err_out_free_dev;
+	}
+
+	memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
+
+	dev->initialized = 1;
+
+	dev->thread = kthread_run(&w1_process, dev, "%s", dev->name);
+	if (IS_ERR(dev->thread)) {
+		retval = PTR_ERR(dev->thread);
+		dev_err(&dev->dev,
+			 "Failed to create new kernel thread. err=%d\n",
+			 retval);
+		mutex_unlock(&w1_mlock);
+		goto err_out_rm_attr;
+	}
+
+	list_add(&dev->w1_master_entry, &w1_masters);
+	mutex_unlock(&w1_mlock);
+
+	memset(&msg, 0, sizeof(msg));
+	msg.id.mst.id = dev->id;
+	msg.type = W1_MASTER_ADD;
+	w1_netlink_send(dev, &msg);
+
+	return 0;
+
+#if 0 /* Thread cleanup code, not required currently. */
+err_out_kill_thread:
+	set_bit(W1_ABORT_SEARCH, &dev->flags);
+	kthread_stop(dev->thread);
+#endif
+err_out_rm_attr:
+	w1_destroy_master_attributes(dev);
+err_out_free_dev:
+	w1_free_dev(dev);
+
+	return retval;
+}
+EXPORT_SYMBOL(w1_add_master_device);
+
+void __w1_remove_master_device(struct w1_master *dev)
+{
+	struct w1_netlink_msg msg;
+	struct w1_slave *sl, *sln;
+
+	mutex_lock(&w1_mlock);
+	list_del(&dev->w1_master_entry);
+	mutex_unlock(&w1_mlock);
+
+	set_bit(W1_ABORT_SEARCH, &dev->flags);
+	kthread_stop(dev->thread);
+
+	mutex_lock(&dev->mutex);
+	mutex_lock(&dev->list_mutex);
+	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+		mutex_unlock(&dev->list_mutex);
+		w1_slave_detach(sl);
+		mutex_lock(&dev->list_mutex);
+	}
+	w1_destroy_master_attributes(dev);
+	mutex_unlock(&dev->list_mutex);
+	mutex_unlock(&dev->mutex);
+	atomic_dec(&dev->refcnt);
+
+	while (atomic_read(&dev->refcnt)) {
+		dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
+				dev->name, atomic_read(&dev->refcnt));
+
+		if (msleep_interruptible(1000))
+			flush_signals(current);
+		mutex_lock(&dev->list_mutex);
+		w1_process_callbacks(dev);
+		mutex_unlock(&dev->list_mutex);
+	}
+	mutex_lock(&dev->list_mutex);
+	w1_process_callbacks(dev);
+	mutex_unlock(&dev->list_mutex);
+
+	memset(&msg, 0, sizeof(msg));
+	msg.id.mst.id = dev->id;
+	msg.type = W1_MASTER_REMOVE;
+	w1_netlink_send(dev, &msg);
+
+	w1_free_dev(dev);
+}
+
+/**
+ * w1_remove_master_device() - unregister a master device
+ * @bm:	master bus device to remove
+ */
+void w1_remove_master_device(struct w1_bus_master *bm)
+{
+	struct w1_master *dev, *found = NULL;
+
+	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+		if (!dev->initialized)
+			continue;
+
+		if (dev->bus_master->data == bm->data) {
+			found = dev;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_err("Device doesn't exist.\n");
+		return;
+	}
+
+	__w1_remove_master_device(found);
+}
+EXPORT_SYMBOL(w1_remove_master_device);
diff --git a/drivers/w1/w1_internal.h b/drivers/w1/w1_internal.h
new file mode 100644
index 0000000..1623e2f
--- /dev/null
+++ b/drivers/w1/w1_internal.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __W1_H
+#define __W1_H
+
+#include <linux/w1.h>
+
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+#define W1_SLAVE_ACTIVE		0
+#define W1_SLAVE_DETACH		1
+
+/**
+ * struct w1_async_cmd - execute callback from the w1_process kthread
+ * @async_entry: link entry
+ * @cb: callback function, must list_del and destroy this list before
+ * returning
+ *
+ * When inserted into the w1_master async_list, w1_process will execute
+ * the callback.  Embed this into the structure with the command details.
+ */
+struct w1_async_cmd {
+	struct list_head	async_entry;
+	void (*cb)(struct w1_master *dev, struct w1_async_cmd *async_cmd);
+};
+
+int w1_create_master_attributes(struct w1_master *master);
+void w1_destroy_master_attributes(struct w1_master *master);
+void w1_search(struct w1_master *dev, u8 search_type,
+	       w1_slave_found_callback cb);
+void w1_search_devices(struct w1_master *dev, u8 search_type,
+		       w1_slave_found_callback cb);
+/* call w1_unref_slave to release the reference counts w1_search_slave added */
+struct w1_slave *w1_search_slave(struct w1_reg_num *id);
+/*
+ * decrements the reference on sl->master and sl, and cleans up if zero
+ * returns the reference count after it has been decremented
+ */
+int w1_unref_slave(struct w1_slave *sl);
+void w1_slave_found(struct w1_master *dev, u64 rn);
+void w1_search_process_cb(struct w1_master *dev, u8 search_type,
+			  w1_slave_found_callback cb);
+struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+					struct w1_reg_num *rn);
+struct w1_master *w1_search_master_id(u32 id);
+
+/* Disconnect and reconnect devices in the given family.  Used for finding
+ * unclaimed devices after a family has been registered or releasing devices
+ * after a family has been unregistered.  Set attach to 1 when a new family
+ * has just been registered, to 0 when it has been unregistered.
+ */
+void w1_reconnect_slaves(struct w1_family *f, int attach);
+int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
+/* 0 success, otherwise EBUSY */
+int w1_slave_detach(struct w1_slave *sl);
+
+void __w1_remove_master_device(struct w1_master *dev);
+
+void w1_family_put(struct w1_family *f);
+void __w1_family_get(struct w1_family *f);
+struct w1_family *w1_family_registered(u8 fid);
+
+extern struct device_driver w1_master_driver;
+extern struct device w1_master_device;
+extern int w1_max_slave_count;
+extern int w1_max_slave_ttl;
+extern struct list_head w1_masters;
+extern struct mutex w1_mlock;
+extern spinlock_t w1_flock;
+
+int w1_process_callbacks(struct w1_master *dev);
+int w1_process(void *data);
+
+#endif /* __W1_H */
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
new file mode 100644
index 0000000..0364d33
--- /dev/null
+++ b/drivers/w1/w1_io.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+
+#include "w1_internal.h"
+
+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,
+	35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
+	190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
+	70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
+	219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
+	101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
+	248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
+	140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
+	17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
+	175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
+	50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
+	202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
+	87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
+	233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
+	116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
+};
+
+static void w1_delay(unsigned long tm)
+{
+	udelay(tm * w1_delay_parm);
+}
+
+static void w1_write_bit(struct w1_master *dev, int bit);
+static u8 w1_read_bit(struct w1_master *dev);
+
+/**
+ * w1_touch_bit() - Generates a write-0 or write-1 cycle and samples the level.
+ * @dev:	the master device
+ * @bit:	0 - write a 0, 1 - write a 0 read the level
+ */
+u8 w1_touch_bit(struct w1_master *dev, int bit)
+{
+	if (dev->bus_master->touch_bit)
+		return dev->bus_master->touch_bit(dev->bus_master->data, bit);
+	else if (bit)
+		return w1_read_bit(dev);
+	else {
+		w1_write_bit(dev, 0);
+		return 0;
+	}
+}
+EXPORT_SYMBOL_GPL(w1_touch_bit);
+
+/**
+ * w1_write_bit() - Generates a write-0 or write-1 cycle.
+ * @dev:	the master device
+ * @bit:	bit to write
+ *
+ * Only call if dev->bus_master->touch_bit is NULL
+ */
+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);
+		dev->bus_master->write_bit(dev->bus_master->data, 1);
+		w1_delay(64);
+	} else {
+		dev->bus_master->write_bit(dev->bus_master->data, 0);
+		w1_delay(60);
+		dev->bus_master->write_bit(dev->bus_master->data, 1);
+		w1_delay(10);
+	}
+
+	if(w1_disable_irqs) local_irq_restore(flags);
+}
+
+/**
+ * w1_pre_write() - pre-write operations
+ * @dev:	the master device
+ *
+ * Pre-write operation, currently only supporting strong pullups.
+ * Program the hardware for a strong pullup, if one has been requested and
+ * the hardware supports it.
+ */
+static void w1_pre_write(struct w1_master *dev)
+{
+	if (dev->pullup_duration &&
+		dev->enable_pullup && dev->bus_master->set_pullup) {
+		dev->bus_master->set_pullup(dev->bus_master->data,
+			dev->pullup_duration);
+	}
+}
+
+/**
+ * w1_post_write() - post-write options
+ * @dev:	the master device
+ *
+ * Post-write operation, currently only supporting strong pullups.
+ * If a strong pullup was requested, clear it if the hardware supports
+ * them, or execute the delay otherwise, in either case clear the request.
+ */
+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
+			msleep(dev->pullup_duration);
+		dev->pullup_duration = 0;
+	}
+}
+
+/**
+ * w1_write_8() - Writes 8 bits.
+ * @dev:	the master device
+ * @byte:	the byte to write
+ */
+void w1_write_8(struct w1_master *dev, u8 byte)
+{
+	int i;
+
+	if (dev->bus_master->write_byte) {
+		w1_pre_write(dev);
+		dev->bus_master->write_byte(dev->bus_master->data, byte);
+	}
+	else
+		for (i = 0; i < 8; ++i) {
+			if (i == 7)
+				w1_pre_write(dev);
+			w1_touch_bit(dev, (byte >> i) & 0x1);
+		}
+	w1_post_write(dev);
+}
+EXPORT_SYMBOL_GPL(w1_write_8);
+
+
+/**
+ * w1_read_bit() - Generates a write-1 cycle and samples the level.
+ * @dev:	the master device
+ *
+ * Only call if dev->bus_master->touch_bit is NULL
+ */
+static u8 w1_read_bit(struct w1_master *dev)
+{
+	int result;
+	unsigned long flags = 0;
+
+	/* sample timing is critical here */
+	local_irq_save(flags);
+	dev->bus_master->write_bit(dev->bus_master->data, 0);
+	w1_delay(6);
+	dev->bus_master->write_bit(dev->bus_master->data, 1);
+	w1_delay(9);
+
+	result = dev->bus_master->read_bit(dev->bus_master->data);
+	local_irq_restore(flags);
+
+	w1_delay(55);
+
+	return result & 0x1;
+}
+
+/**
+ * w1_triplet() - * Does a triplet - used for searching ROM addresses.
+ * @dev:	the master device
+ * @bdir:	the bit to write if both id_bit and comp_bit are 0
+ *
+ * Return bits:
+ *  bit 0 = id_bit
+ *  bit 1 = comp_bit
+ *  bit 2 = dir_taken
+ *
+ * If both bits 0 & 1 are set, the search should be restarted.
+ *
+ * Return:        bit fields - see above
+ */
+u8 w1_triplet(struct w1_master *dev, int bdir)
+{
+	if (dev->bus_master->triplet)
+		return dev->bus_master->triplet(dev->bus_master->data, bdir);
+	else {
+		u8 id_bit   = w1_touch_bit(dev, 1);
+		u8 comp_bit = w1_touch_bit(dev, 1);
+		u8 retval;
+
+		if (id_bit && comp_bit)
+			return 0x03;  /* error */
+
+		if (!id_bit && !comp_bit) {
+			/* Both bits are valid, take the direction given */
+			retval = bdir ? 0x04 : 0;
+		} else {
+			/* Only one bit is valid, take that direction */
+			bdir = id_bit;
+			retval = id_bit ? 0x05 : 0x02;
+		}
+
+		if (dev->bus_master->touch_bit)
+			w1_touch_bit(dev, bdir);
+		else
+			w1_write_bit(dev, bdir);
+		return retval;
+	}
+}
+EXPORT_SYMBOL_GPL(w1_triplet);
+
+/**
+ * w1_read_8() - Reads 8 bits.
+ * @dev:	the master device
+ *
+ * Return:        the byte read
+ */
+u8 w1_read_8(struct w1_master *dev)
+{
+	int i;
+	u8 res = 0;
+
+	if (dev->bus_master->read_byte)
+		res = dev->bus_master->read_byte(dev->bus_master->data);
+	else
+		for (i = 0; i < 8; ++i)
+			res |= (w1_touch_bit(dev,1) << i);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(w1_read_8);
+
+/**
+ * w1_write_block() - Writes a series of bytes.
+ * @dev:	the master device
+ * @buf:	pointer to the data to write
+ * @len:	the number of bytes to write
+ */
+void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
+{
+	int i;
+
+	if (dev->bus_master->write_block) {
+		w1_pre_write(dev);
+		dev->bus_master->write_block(dev->bus_master->data, buf, len);
+	}
+	else
+		for (i = 0; i < len; ++i)
+			w1_write_8(dev, buf[i]); /* calls w1_pre_write */
+	w1_post_write(dev);
+}
+EXPORT_SYMBOL_GPL(w1_write_block);
+
+/**
+ * w1_touch_block() - Touches a series of bytes.
+ * @dev:	the master device
+ * @buf:	pointer to the data to write
+ * @len:	the number of bytes to write
+ */
+void w1_touch_block(struct w1_master *dev, u8 *buf, int len)
+{
+	int i, j;
+	u8 tmp;
+
+	for (i = 0; i < len; ++i) {
+		tmp = 0;
+		for (j = 0; j < 8; ++j) {
+			if (j == 7)
+				w1_pre_write(dev);
+			tmp |= w1_touch_bit(dev, (buf[i] >> j) & 0x1) << j;
+		}
+
+		buf[i] = tmp;
+	}
+}
+EXPORT_SYMBOL_GPL(w1_touch_block);
+
+/**
+ * w1_read_block() - Reads a series of bytes.
+ * @dev:	the master device
+ * @buf:	pointer to the buffer to fill
+ * @len:	the number of bytes to read
+ * Return:	the number of bytes read
+ */
+u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
+{
+	int i;
+	u8 ret;
+
+	if (dev->bus_master->read_block)
+		ret = dev->bus_master->read_block(dev->bus_master->data, buf, len);
+	else {
+		for (i = 0; i < len; ++i)
+			buf[i] = w1_read_8(dev);
+		ret = len;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(w1_read_block);
+
+/**
+ * w1_reset_bus() - Issues a reset bus sequence.
+ * @dev:	the master device
+ * Return:	0=Device present, 1=No device present or error
+ */
+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;
+	else {
+		dev->bus_master->write_bit(dev->bus_master->data, 0);
+		/* minimum 480, max ? us
+		 * be nice and sleep, except 18b20 spec lists 960us maximum,
+		 * so until we can sleep with microsecond accuracy, spin.
+		 * Feel free to come up with some other way to give up the
+		 * cpu for such a short amount of time AND get it back in
+		 * the maximum amount of time.
+		 */
+		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;
+		/* minimum 70 (above) + 430 = 500 us
+		 * There aren't any timing requirements between a reset and
+		 * the following transactions.  Sleeping is safe here.
+		 */
+		/* w1_delay(430); min required time */
+		msleep(1);
+	}
+
+	if(w1_disable_irqs) local_irq_restore(flags);
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(w1_reset_bus);
+
+u8 w1_calc_crc8(u8 * data, int len)
+{
+	u8 crc = 0;
+
+	while (len--)
+		crc = w1_crc8_table[crc ^ *data++];
+
+	return crc;
+}
+EXPORT_SYMBOL_GPL(w1_calc_crc8);
+
+void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
+{
+	dev->attempts++;
+	if (dev->bus_master->search)
+		dev->bus_master->search(dev->bus_master->data, dev,
+			search_type, cb);
+	else
+		w1_search(dev, search_type, cb);
+}
+
+/**
+ * w1_reset_select_slave() - reset and select a slave
+ * @sl:		the slave to select
+ *
+ * Resets the bus and then selects the slave by sending either a skip rom
+ * or a rom match.  A skip rom is issued if there is only one device
+ * registered on the bus.
+ * The w1 master lock must be held.
+ *
+ * Return:	0=success, anything else=error
+ */
+int w1_reset_select_slave(struct w1_slave *sl)
+{
+	if (w1_reset_bus(sl->master))
+		return -1;
+
+	if (sl->master->slave_count == 1)
+		w1_write_8(sl->master, W1_SKIP_ROM);
+	else {
+		u8 match[9] = {W1_MATCH_ROM, };
+		u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
+
+		memcpy(&match[1], &rn, 8);
+		w1_write_block(sl->master, match, 9);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(w1_reset_select_slave);
+
+/**
+ * w1_reset_resume_command() - resume instead of another match ROM
+ * @dev:	the master device
+ *
+ * When the workflow with a slave amongst many requires several
+ * successive commands a reset between each, this function is similar
+ * to doing a reset then a match ROM for the last matched ROM. The
+ * advantage being that the matched ROM step is skipped in favor of the
+ * resume command. The slave must support the command of course.
+ *
+ * If the bus has only one slave, traditionnaly the match ROM is skipped
+ * and a "SKIP ROM" is done for efficiency. On multi-slave busses, this
+ * doesn't work of course, but the resume command is the next best thing.
+ *
+ * The w1 master lock must be held.
+ */
+int w1_reset_resume_command(struct w1_master *dev)
+{
+	if (w1_reset_bus(dev))
+		return -1;
+
+	/* This will make only the last matched slave perform a skip ROM. */
+	w1_write_8(dev, W1_RESUME_CMD);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(w1_reset_resume_command);
+
+/**
+ * w1_next_pullup() - register for a strong pullup
+ * @dev:	the master device
+ * @delay:	time in milliseconds
+ *
+ * Put out a strong pull-up of the specified duration after the next write
+ * operation.  Not all hardware supports strong pullups.  Hardware that
+ * doesn't support strong pullups will sleep for the given time after the
+ * write operation without a strong pullup.  This is a one shot request for
+ * the next write, specifying zero will clear a previous request.
+ * The w1 master lock must be held.
+ *
+ * Return:	0=success, anything else=error
+ */
+void w1_next_pullup(struct w1_master *dev, int delay)
+{
+	dev->pullup_duration = delay;
+}
+EXPORT_SYMBOL_GPL(w1_next_pullup);
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
new file mode 100644
index 0000000..f2f099c
--- /dev/null
+++ b/drivers/w1/w1_netlink.c
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/connector.h>
+
+#include "w1_internal.h"
+#include "w1_netlink.h"
+
+#if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE)))
+
+/* Bundle together everything required to process a request in one memory
+ * allocation.
+ */
+struct w1_cb_block {
+	atomic_t refcnt;
+	u32 portid; /* Sending process port ID */
+	/* maximum value for first_cn->len */
+	u16 maxlen;
+	/* pointers to building up the reply message */
+	struct cn_msg *first_cn; /* fixed once the structure is populated */
+	struct cn_msg *cn; /* advances as cn_msg is appeneded */
+	struct w1_netlink_msg *msg; /* advances as w1_netlink_msg is appened */
+	struct w1_netlink_cmd *cmd; /* advances as cmds are appened */
+	struct w1_netlink_msg *cur_msg; /* currently message being processed */
+	/* copy of the original request follows */
+	struct cn_msg request_cn;
+	/* followed by variable length:
+	 * cn_msg, data (w1_netlink_msg and w1_netlink_cmd)
+	 * one or more struct w1_cb_node
+	 * reply first_cn, data (w1_netlink_msg and w1_netlink_cmd)
+	 */
+};
+struct w1_cb_node {
+	struct w1_async_cmd async;
+	/* pointers within w1_cb_block and cn data */
+	struct w1_cb_block *block;
+	struct w1_netlink_msg *msg;
+	struct w1_slave *sl;
+	struct w1_master *dev;
+};
+
+/**
+ * w1_reply_len() - calculate current reply length, compare to maxlen
+ * @block: block to calculate
+ *
+ * Calculates the current message length including possible multiple
+ * cn_msg and data, excludes the first sizeof(struct cn_msg).  Direclty
+ * compariable to maxlen and usable to send the message.
+ */
+static u16 w1_reply_len(struct w1_cb_block *block)
+{
+	if (!block->cn)
+		return 0;
+	return (u8 *)block->cn - (u8 *)block->first_cn + block->cn->len;
+}
+
+static void w1_unref_block(struct w1_cb_block *block)
+{
+	if (atomic_sub_return(1, &block->refcnt) == 0) {
+		u16 len = w1_reply_len(block);
+		if (len) {
+			cn_netlink_send_mult(block->first_cn, len,
+				block->portid, 0, GFP_KERNEL);
+		}
+		kfree(block);
+	}
+}
+
+/**
+ * w1_reply_make_space() - send message if needed to make space
+ * @block: block to make space on
+ * @space: how many bytes requested
+ *
+ * Verify there is enough room left for the caller to add "space" bytes to the
+ * message, if there isn't send the message and reset.
+ */
+static void w1_reply_make_space(struct w1_cb_block *block, u16 space)
+{
+	u16 len = w1_reply_len(block);
+	if (len + space >= block->maxlen) {
+		cn_netlink_send_mult(block->first_cn, len, block->portid, 0, GFP_KERNEL);
+		block->first_cn->len = 0;
+		block->cn = NULL;
+		block->msg = NULL;
+		block->cmd = NULL;
+	}
+}
+
+/* Early send when replies aren't bundled. */
+static void w1_netlink_check_send(struct w1_cb_block *block)
+{
+	if (!(block->request_cn.flags & W1_CN_BUNDLE) && block->cn)
+		w1_reply_make_space(block, block->maxlen);
+}
+
+/**
+ * w1_netlink_setup_msg() - prepare to write block->msg
+ * @block: block to operate on
+ * @ack: determines if cn can be reused
+ *
+ * block->cn will be setup with the correct ack, advancing if needed
+ * block->cn->len does not include space for block->msg
+ * block->msg advances but remains uninitialized
+ */
+static void w1_netlink_setup_msg(struct w1_cb_block *block, u32 ack)
+{
+	if (block->cn && block->cn->ack == ack) {
+		block->msg = (struct w1_netlink_msg *)(block->cn->data + block->cn->len);
+	} else {
+		/* advance or set to data */
+		if (block->cn)
+			block->cn = (struct cn_msg *)(block->cn->data +
+				block->cn->len);
+		else
+			block->cn = block->first_cn;
+
+		memcpy(block->cn, &block->request_cn, sizeof(*block->cn));
+		block->cn->len = 0;
+		block->cn->ack = ack;
+		block->msg = (struct w1_netlink_msg *)block->cn->data;
+	}
+}
+
+/* Append cmd to msg, include cmd->data as well.  This is because
+ * any following data goes with the command and in the case of a read is
+ * the results.
+ */
+static void w1_netlink_queue_cmd(struct w1_cb_block *block,
+	struct w1_netlink_cmd *cmd)
+{
+	u32 space;
+	w1_reply_make_space(block, sizeof(struct cn_msg) +
+		sizeof(struct w1_netlink_msg) + sizeof(*cmd) + cmd->len);
+
+	/* There's a status message sent after each command, so no point
+	 * in trying to bundle this cmd after an existing one, because
+	 * there won't be one.  Allocate and copy over a new cn_msg.
+	 */
+	w1_netlink_setup_msg(block, block->request_cn.seq + 1);
+	memcpy(block->msg, block->cur_msg, sizeof(*block->msg));
+	block->cn->len += sizeof(*block->msg);
+	block->msg->len = 0;
+	block->cmd = (struct w1_netlink_cmd *)(block->msg->data);
+
+	space = sizeof(*cmd) + cmd->len;
+	if (block->cmd != cmd)
+		memcpy(block->cmd, cmd, space);
+	block->cn->len += space;
+	block->msg->len += space;
+}
+
+/* Append req_msg and req_cmd, no other commands and no data from req_cmd are
+ * copied.
+ */
+static void w1_netlink_queue_status(struct w1_cb_block *block,
+	struct w1_netlink_msg *req_msg, struct w1_netlink_cmd *req_cmd,
+	int error)
+{
+	u16 space = sizeof(struct cn_msg) + sizeof(*req_msg) + sizeof(*req_cmd);
+	w1_reply_make_space(block, space);
+	w1_netlink_setup_msg(block, block->request_cn.ack);
+
+	memcpy(block->msg, req_msg, sizeof(*req_msg));
+	block->cn->len += sizeof(*req_msg);
+	block->msg->len = 0;
+	block->msg->status = (u8)-error;
+	if (req_cmd) {
+		struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)block->msg->data;
+		memcpy(cmd, req_cmd, sizeof(*cmd));
+		block->cn->len += sizeof(*cmd);
+		block->msg->len += sizeof(*cmd);
+		cmd->len = 0;
+	}
+	w1_netlink_check_send(block);
+}
+
+/**
+ * w1_netlink_send_error() - sends the error message now
+ * @cn: original cn_msg
+ * @msg: original w1_netlink_msg
+ * @portid: where to send it
+ * @error: error status
+ *
+ * Use when a block isn't available to queue the message to and cn, msg
+ * might not be contiguous.
+ */
+static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg,
+	int portid, int error)
+{
+	struct {
+		struct cn_msg cn;
+		struct w1_netlink_msg msg;
+	} packet;
+	memcpy(&packet.cn, cn, sizeof(packet.cn));
+	memcpy(&packet.msg, msg, sizeof(packet.msg));
+	packet.cn.len = sizeof(packet.msg);
+	packet.msg.len = 0;
+	packet.msg.status = (u8)-error;
+	cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL);
+}
+
+/**
+ * w1_netlink_send() - sends w1 netlink notifications
+ * @dev: w1_master the even is associated with or for
+ * @msg: w1_netlink_msg message to be sent
+ *
+ * This are notifications generated from the kernel.
+ */
+void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
+{
+	struct {
+		struct cn_msg cn;
+		struct w1_netlink_msg msg;
+	} packet;
+	memset(&packet, 0, sizeof(packet));
+
+	packet.cn.id.idx = CN_W1_IDX;
+	packet.cn.id.val = CN_W1_VAL;
+
+	packet.cn.seq = dev->seq++;
+	packet.cn.len = sizeof(*msg);
+
+	memcpy(&packet.msg, msg, sizeof(*msg));
+	packet.msg.len = 0;
+
+	cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL);
+}
+
+static void w1_send_slave(struct w1_master *dev, u64 rn)
+{
+	struct w1_cb_block *block = dev->priv;
+	struct w1_netlink_cmd *cache_cmd = block->cmd;
+	u64 *data;
+
+	w1_reply_make_space(block, sizeof(*data));
+
+	/* Add cmd back if the packet was sent */
+	if (!block->cmd) {
+		cache_cmd->len = 0;
+		w1_netlink_queue_cmd(block, cache_cmd);
+	}
+
+	data = (u64 *)(block->cmd->data + block->cmd->len);
+
+	*data = rn;
+	block->cn->len += sizeof(*data);
+	block->msg->len += sizeof(*data);
+	block->cmd->len += sizeof(*data);
+}
+
+static void w1_found_send_slave(struct w1_master *dev, u64 rn)
+{
+	/* update kernel slave list */
+	w1_slave_found(dev, rn);
+
+	w1_send_slave(dev, rn);
+}
+
+/* Get the current slave list, or search (with or without alarm) */
+static int w1_get_slaves(struct w1_master *dev, struct w1_netlink_cmd *req_cmd)
+{
+	struct w1_slave *sl;
+
+	req_cmd->len = 0;
+	w1_netlink_queue_cmd(dev->priv, req_cmd);
+
+	if (req_cmd->cmd == W1_CMD_LIST_SLAVES) {
+		u64 rn;
+		mutex_lock(&dev->list_mutex);
+		list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+			memcpy(&rn, &sl->reg_num, sizeof(rn));
+			w1_send_slave(dev, rn);
+		}
+		mutex_unlock(&dev->list_mutex);
+	} else {
+		w1_search_process_cb(dev, req_cmd->cmd == W1_CMD_ALARM_SEARCH ?
+			W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave);
+	}
+
+	return 0;
+}
+
+static int w1_process_command_io(struct w1_master *dev,
+	struct w1_netlink_cmd *cmd)
+{
+	int err = 0;
+
+	switch (cmd->cmd) {
+	case W1_CMD_TOUCH:
+		w1_touch_block(dev, cmd->data, cmd->len);
+		w1_netlink_queue_cmd(dev->priv, cmd);
+		break;
+	case W1_CMD_READ:
+		w1_read_block(dev, cmd->data, cmd->len);
+		w1_netlink_queue_cmd(dev->priv, cmd);
+		break;
+	case W1_CMD_WRITE:
+		w1_write_block(dev, cmd->data, cmd->len);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int w1_process_command_addremove(struct w1_master *dev,
+	struct w1_netlink_cmd *cmd)
+{
+	struct w1_slave *sl;
+	int err = 0;
+	struct w1_reg_num *id;
+
+	if (cmd->len != sizeof(*id))
+		return -EINVAL;
+
+	id = (struct w1_reg_num *)cmd->data;
+
+	sl = w1_slave_search_device(dev, id);
+	switch (cmd->cmd) {
+	case W1_CMD_SLAVE_ADD:
+		if (sl)
+			err = -EINVAL;
+		else
+			err = w1_attach_slave_device(dev, id);
+		break;
+	case W1_CMD_SLAVE_REMOVE:
+		if (sl)
+			w1_slave_detach(sl);
+		else
+			err = -EINVAL;
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int w1_process_command_master(struct w1_master *dev,
+	struct w1_netlink_cmd *req_cmd)
+{
+	int err = -EINVAL;
+
+	/* drop bus_mutex for search (does it's own locking), and add/remove
+	 * which doesn't use the bus
+	 */
+	switch (req_cmd->cmd) {
+	case W1_CMD_SEARCH:
+	case W1_CMD_ALARM_SEARCH:
+	case W1_CMD_LIST_SLAVES:
+		mutex_unlock(&dev->bus_mutex);
+		err = w1_get_slaves(dev, req_cmd);
+		mutex_lock(&dev->bus_mutex);
+		break;
+	case W1_CMD_READ:
+	case W1_CMD_WRITE:
+	case W1_CMD_TOUCH:
+		err = w1_process_command_io(dev, req_cmd);
+		break;
+	case W1_CMD_RESET:
+		err = w1_reset_bus(dev);
+		break;
+	case W1_CMD_SLAVE_ADD:
+	case W1_CMD_SLAVE_REMOVE:
+		mutex_unlock(&dev->bus_mutex);
+		mutex_lock(&dev->mutex);
+		err = w1_process_command_addremove(dev, req_cmd);
+		mutex_unlock(&dev->mutex);
+		mutex_lock(&dev->bus_mutex);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int w1_process_command_slave(struct w1_slave *sl,
+		struct w1_netlink_cmd *cmd)
+{
+	dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
+		__func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id,
+		sl->reg_num.crc, cmd->cmd, cmd->len);
+
+	return w1_process_command_io(sl->master, cmd);
+}
+
+static int w1_process_command_root(struct cn_msg *req_cn, u32 portid)
+{
+	struct w1_master *dev;
+	struct cn_msg *cn;
+	struct w1_netlink_msg *msg;
+	u32 *id;
+
+	cn = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!cn)
+		return -ENOMEM;
+
+	cn->id.idx = CN_W1_IDX;
+	cn->id.val = CN_W1_VAL;
+
+	cn->seq = req_cn->seq;
+	cn->ack = req_cn->seq + 1;
+	cn->len = sizeof(struct w1_netlink_msg);
+	msg = (struct w1_netlink_msg *)cn->data;
+
+	msg->type = W1_LIST_MASTERS;
+	msg->status = 0;
+	msg->len = 0;
+	id = (u32 *)msg->data;
+
+	mutex_lock(&w1_mlock);
+	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+		if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
+			cn_netlink_send(cn, portid, 0, GFP_KERNEL);
+			cn->len = sizeof(struct w1_netlink_msg);
+			msg->len = 0;
+			id = (u32 *)msg->data;
+		}
+
+		*id = dev->id;
+		msg->len += sizeof(*id);
+		cn->len += sizeof(*id);
+		id++;
+	}
+	cn_netlink_send(cn, portid, 0, GFP_KERNEL);
+	mutex_unlock(&w1_mlock);
+
+	kfree(cn);
+	return 0;
+}
+
+static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)
+{
+	struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node,
+		async);
+	u16 mlen = node->msg->len;
+	u16 len;
+	int err = 0;
+	struct w1_slave *sl = node->sl;
+	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)node->msg->data;
+
+	mutex_lock(&dev->bus_mutex);
+	dev->priv = node->block;
+	if (sl && w1_reset_select_slave(sl))
+		err = -ENODEV;
+	node->block->cur_msg = node->msg;
+
+	while (mlen && !err) {
+		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
+			err = -E2BIG;
+			break;
+		}
+
+		if (sl)
+			err = w1_process_command_slave(sl, cmd);
+		else
+			err = w1_process_command_master(dev, cmd);
+		w1_netlink_check_send(node->block);
+
+		w1_netlink_queue_status(node->block, node->msg, cmd, err);
+		err = 0;
+
+		len = sizeof(*cmd) + cmd->len;
+		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
+		mlen -= len;
+	}
+
+	if (!cmd || err)
+		w1_netlink_queue_status(node->block, node->msg, cmd, err);
+
+	/* ref taken in w1_search_slave or w1_search_master_id when building
+	 * the block
+	 */
+	if (sl)
+		w1_unref_slave(sl);
+	else
+		atomic_dec(&dev->refcnt);
+	dev->priv = NULL;
+	mutex_unlock(&dev->bus_mutex);
+
+	mutex_lock(&dev->list_mutex);
+	list_del(&async_cmd->async_entry);
+	mutex_unlock(&dev->list_mutex);
+
+	w1_unref_block(node->block);
+}
+
+static void w1_list_count_cmds(struct w1_netlink_msg *msg, int *cmd_count,
+	u16 *slave_len)
+{
+	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)msg->data;
+	u16 mlen = msg->len;
+	u16 len;
+	int slave_list = 0;
+	while (mlen) {
+		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen)
+			break;
+
+		switch (cmd->cmd) {
+		case W1_CMD_SEARCH:
+		case W1_CMD_ALARM_SEARCH:
+		case W1_CMD_LIST_SLAVES:
+			++slave_list;
+		}
+		++*cmd_count;
+		len = sizeof(*cmd) + cmd->len;
+		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
+		mlen -= len;
+	}
+
+	if (slave_list) {
+		struct w1_master *dev = w1_search_master_id(msg->id.mst.id);
+		if (dev) {
+			/* Bytes, and likely an overstimate, and if it isn't
+			 * the results can still be split between packets.
+			 */
+			*slave_len += sizeof(struct w1_reg_num) * slave_list *
+				(dev->slave_count + dev->max_slave_count);
+			/* search incremented it */
+			atomic_dec(&dev->refcnt);
+		}
+	}
+}
+
+static void w1_cn_callback(struct cn_msg *cn, struct netlink_skb_parms *nsp)
+{
+	struct w1_netlink_msg *msg = (struct w1_netlink_msg *)(cn + 1);
+	struct w1_slave *sl;
+	struct w1_master *dev;
+	u16 msg_len;
+	u16 slave_len = 0;
+	int err = 0;
+	struct w1_cb_block *block = NULL;
+	struct w1_cb_node *node = NULL;
+	int node_count = 0;
+	int cmd_count = 0;
+
+	/* If any unknown flag is set let the application know, that way
+	 * applications can detect the absence of features in kernels that
+	 * don't know about them.  http://lwn.net/Articles/587527/
+	 */
+	if (cn->flags & ~(W1_CN_BUNDLE)) {
+		w1_netlink_send_error(cn, msg, nsp->portid, -EINVAL);
+		return;
+	}
+
+	/* Count the number of master or slave commands there are to allocate
+	 * space for one cb_node each.
+	 */
+	msg_len = cn->len;
+	while (msg_len && !err) {
+		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
+			err = -E2BIG;
+			break;
+		}
+
+		/* count messages for nodes and allocate any additional space
+		 * required for slave lists
+		 */
+		if (msg->type == W1_MASTER_CMD || msg->type == W1_SLAVE_CMD) {
+			++node_count;
+			w1_list_count_cmds(msg, &cmd_count, &slave_len);
+		}
+
+		msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
+		msg = (struct w1_netlink_msg *)(((u8 *)msg) +
+			sizeof(struct w1_netlink_msg) + msg->len);
+	}
+	msg = (struct w1_netlink_msg *)(cn + 1);
+	if (node_count) {
+		int size;
+		int reply_size = sizeof(*cn) + cn->len + slave_len;
+		if (cn->flags & W1_CN_BUNDLE) {
+			/* bundling duplicats some of the messages */
+			reply_size += 2 * cmd_count * (sizeof(struct cn_msg) +
+				sizeof(struct w1_netlink_msg) +
+				sizeof(struct w1_netlink_cmd));
+		}
+		reply_size = min(CONNECTOR_MAX_MSG_SIZE, reply_size);
+
+		/* allocate space for the block, a copy of the original message,
+		 * one node per cmd to point into the original message,
+		 * space for replies which is the original message size plus
+		 * space for any list slave data and status messages
+		 * cn->len doesn't include itself which is part of the block
+		 * */
+		size =  /* block + original message */
+			sizeof(struct w1_cb_block) + sizeof(*cn) + cn->len +
+			/* space for nodes */
+			node_count * sizeof(struct w1_cb_node) +
+			/* replies */
+			sizeof(struct cn_msg) + reply_size;
+		block = kzalloc(size, GFP_KERNEL);
+		if (!block) {
+			/* if the system is already out of memory,
+			 * (A) will this work, and (B) would it be better
+			 * to not try?
+			 */
+			w1_netlink_send_error(cn, msg, nsp->portid, -ENOMEM);
+			return;
+		}
+		atomic_set(&block->refcnt, 1);
+		block->portid = nsp->portid;
+		memcpy(&block->request_cn, cn, sizeof(*cn) + cn->len);
+		node = (struct w1_cb_node *)(block->request_cn.data + cn->len);
+
+		/* Sneeky, when not bundling, reply_size is the allocated space
+		 * required for the reply, cn_msg isn't part of maxlen so
+		 * it should be reply_size - sizeof(struct cn_msg), however
+		 * when checking if there is enough space, w1_reply_make_space
+		 * is called with the full message size including cn_msg,
+		 * because it isn't known at that time if an additional cn_msg
+		 * will need to be allocated.  So an extra cn_msg is added
+		 * above in "size".
+		 */
+		block->maxlen = reply_size;
+		block->first_cn = (struct cn_msg *)(node + node_count);
+		memset(block->first_cn, 0, sizeof(*block->first_cn));
+	}
+
+	msg_len = cn->len;
+	while (msg_len && !err) {
+
+		dev = NULL;
+		sl = NULL;
+
+		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
+			err = -E2BIG;
+			break;
+		}
+
+		/* execute on this thread, no need to process later */
+		if (msg->type == W1_LIST_MASTERS) {
+			err = w1_process_command_root(cn, nsp->portid);
+			goto out_cont;
+		}
+
+		/* All following message types require additional data,
+		 * check here before references are taken.
+		 */
+		if (!msg->len) {
+			err = -EPROTO;
+			goto out_cont;
+		}
+
+		/* both search calls take references */
+		if (msg->type == W1_MASTER_CMD) {
+			dev = w1_search_master_id(msg->id.mst.id);
+		} else if (msg->type == W1_SLAVE_CMD) {
+			sl = w1_search_slave((struct w1_reg_num *)msg->id.id);
+			if (sl)
+				dev = sl->master;
+		} else {
+			pr_notice("%s: cn: %x.%x, wrong type: %u, len: %u.\n",
+				__func__, cn->id.idx, cn->id.val,
+				msg->type, msg->len);
+			err = -EPROTO;
+			goto out_cont;
+		}
+
+		if (!dev) {
+			err = -ENODEV;
+			goto out_cont;
+		}
+
+		err = 0;
+
+		atomic_inc(&block->refcnt);
+		node->async.cb = w1_process_cb;
+		node->block = block;
+		node->msg = (struct w1_netlink_msg *)((u8 *)&block->request_cn +
+			(size_t)((u8 *)msg - (u8 *)cn));
+		node->sl = sl;
+		node->dev = dev;
+
+		mutex_lock(&dev->list_mutex);
+		list_add_tail(&node->async.async_entry, &dev->async_list);
+		wake_up_process(dev->thread);
+		mutex_unlock(&dev->list_mutex);
+		++node;
+
+out_cont:
+		/* Can't queue because that modifies block and another
+		 * thread could be processing the messages by now and
+		 * there isn't a lock, send directly.
+		 */
+		if (err)
+			w1_netlink_send_error(cn, msg, nsp->portid, err);
+		msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
+		msg = (struct w1_netlink_msg *)(((u8 *)msg) +
+			sizeof(struct w1_netlink_msg) + msg->len);
+
+		/*
+		 * Let's allow requests for nonexisting devices.
+		 */
+		if (err == -ENODEV)
+			err = 0;
+	}
+	if (block)
+		w1_unref_block(block);
+}
+
+int w1_init_netlink(void)
+{
+	struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
+
+	return cn_add_callback(&w1_id, "w1", &w1_cn_callback);
+}
+
+void w1_fini_netlink(void)
+{
+	struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
+
+	cn_del_callback(&w1_id);
+}
+#else
+void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *cn)
+{
+}
+
+int w1_init_netlink(void)
+{
+	return 0;
+}
+
+void w1_fini_netlink(void)
+{
+}
+#endif
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
new file mode 100644
index 0000000..f876772
--- /dev/null
+++ b/drivers/w1/w1_netlink.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __W1_NETLINK_H
+#define __W1_NETLINK_H
+
+#include <asm/types.h>
+#include <linux/connector.h>
+
+#include "w1_internal.h"
+
+/**
+ * enum w1_cn_msg_flags - bitfield flags for struct cn_msg.flags
+ *
+ * @W1_CN_BUNDLE: Request bundling replies into fewer messagse.  Be prepared
+ * to handle multiple struct cn_msg, struct w1_netlink_msg, and
+ * struct w1_netlink_cmd in one packet.
+ */
+enum w1_cn_msg_flags {
+	W1_CN_BUNDLE = 1,
+};
+
+/**
+ * enum w1_netlink_message_types - message type
+ *
+ * @W1_SLAVE_ADD: notification that a slave device was added
+ * @W1_SLAVE_REMOVE: notification that a slave device was removed
+ * @W1_MASTER_ADD: notification that a new bus master was added
+ * @W1_MASTER_REMOVE: notification that a bus masterwas removed
+ * @W1_MASTER_CMD: initiate operations on a specific master
+ * @W1_SLAVE_CMD: sends reset, selects the slave, then does a read/write/touch
+ * operation
+ * @W1_LIST_MASTERS: used to determine the bus master identifiers
+ */
+enum w1_netlink_message_types {
+	W1_SLAVE_ADD = 0,
+	W1_SLAVE_REMOVE,
+	W1_MASTER_ADD,
+	W1_MASTER_REMOVE,
+	W1_MASTER_CMD,
+	W1_SLAVE_CMD,
+	W1_LIST_MASTERS,
+};
+
+/**
+ * struct w1_netlink_msg - holds w1 message type, id, and result
+ *
+ * @type: one of enum w1_netlink_message_types
+ * @status: kernel feedback for success 0 or errno failure value
+ * @len: length of data following w1_netlink_msg
+ * @id: union holding bus master id (msg.id) and slave device id (id[8]).
+ * @id.id: Slave ID (8 bytes)
+ * @id.mst: bus master identification
+ * @id.mst.id: bus master ID
+ * @id.mst.res: bus master reserved
+ * @data: start address of any following data
+ *
+ * The base message structure for w1 messages over netlink.
+ * The netlink connector data sequence is, struct nlmsghdr, struct cn_msg,
+ * then one or more struct w1_netlink_msg (each with optional data).
+ */
+struct w1_netlink_msg
+{
+	__u8				type;
+	__u8				status;
+	__u16				len;
+	union {
+		__u8			id[8];
+		struct w1_mst {
+			__u32		id;
+			__u32		res;
+		} mst;
+	} id;
+	__u8				data[0];
+};
+
+/**
+ * enum w1_commands - commands available for master or slave operations
+ *
+ * @W1_CMD_READ: read len bytes
+ * @W1_CMD_WRITE: write len bytes
+ * @W1_CMD_SEARCH: initiate a standard search, returns only the slave
+ * devices found during that search
+ * @W1_CMD_ALARM_SEARCH: search for devices that are currently alarming
+ * @W1_CMD_TOUCH: Touches a series of bytes.
+ * @W1_CMD_RESET: sends a bus reset on the given master
+ * @W1_CMD_SLAVE_ADD: adds a slave to the given master,
+ * 8 byte slave id at data[0]
+ * @W1_CMD_SLAVE_REMOVE: removes a slave to the given master,
+ * 8 byte slave id at data[0]
+ * @W1_CMD_LIST_SLAVES: list of slaves registered on this master
+ * @W1_CMD_MAX: number of available commands
+ */
+enum w1_commands {
+	W1_CMD_READ = 0,
+	W1_CMD_WRITE,
+	W1_CMD_SEARCH,
+	W1_CMD_ALARM_SEARCH,
+	W1_CMD_TOUCH,
+	W1_CMD_RESET,
+	W1_CMD_SLAVE_ADD,
+	W1_CMD_SLAVE_REMOVE,
+	W1_CMD_LIST_SLAVES,
+	W1_CMD_MAX
+};
+
+/**
+ * struct w1_netlink_cmd - holds the command and data
+ *
+ * @cmd: one of enum w1_commands
+ * @res: reserved
+ * @len: length of data following w1_netlink_cmd
+ * @data: start address of any following data
+ *
+ * One or more struct w1_netlink_cmd is placed starting at w1_netlink_msg.data
+ * each with optional data.
+ */
+struct w1_netlink_cmd
+{
+	__u8				cmd;
+	__u8				res;
+	__u16				len;
+	__u8				data[0];
+};
+
+#ifdef __KERNEL__
+
+void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *);
+int w1_init_netlink(void);
+void w1_fini_netlink(void);
+
+#endif /* __KERNEL__ */
+#endif /* __W1_NETLINK_H */