[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/linux/v4.14/drivers/w1/slaves/Kconfig b/src/kernel/linux/v4.14/drivers/w1/slaves/Kconfig
new file mode 100644
index 0000000..3c945f9
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/w1/slaves/Kconfig
@@ -0,0 +1,151 @@
+#
+# 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_DS2760
+	tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)"
+	help
+	  If you enable this you will have the DS2760 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_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.
+
+endmenu
diff --git a/src/kernel/linux/v4.14/drivers/w1/slaves/Makefile b/src/kernel/linux/v4.14/drivers/w1/slaves/Makefile
new file mode 100644
index 0000000..79c611c
--- /dev/null
+++ b/src/kernel/linux/v4.14/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_DS2760)	+= w1_ds2760.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
diff --git a/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2405.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2405.c
new file mode 100644
index 0000000..42a1e81
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2406.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2406.c
new file mode 100644
index 0000000..fac2663
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2408.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2408.c
new file mode 100644
index 0000000..b535d5e
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2413.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2413.c
new file mode 100644
index 0000000..492e3d0
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2423.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2423.c
new file mode 100644
index 0000000..050407c
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2431.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2431.c
new file mode 100644
index 0000000..5adecd3
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2433.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2433.c
new file mode 100644
index 0000000..75ad70c
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2438.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2438.c
new file mode 100644
index 0000000..7c4e33d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2438.c
@@ -0,0 +1,430 @@
+/*
+ * 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 int 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 int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage)
+{
+	u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
+	int ret;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
+		/* The voltage measured across current sense resistor RSENS. */
+		*voltage = (((int16_t) w1_buf[DS2438_CURRENT_MSB]) << 8) | ((int16_t) w1_buf[DS2438_CURRENT_LSB]);
+		ret = 0;
+	} else
+		ret = -1;
+
+	mutex_unlock(&sl->master->bus_mutex);
+
+	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 iad_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;
+	int16_t voltage;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	if (w1_ds2438_get_current(sl, &voltage) == 0) {
+		ret = snprintf(buf, count, "%i\n", voltage);
+	} else
+		ret = -EIO;
+
+	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);
+
+	/* Read no more than page0 size */
+	if (count > DS2438_PAGE_SIZE)
+		count = DS2438_PAGE_SIZE;
+
+	if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
+		memcpy(buf, &w1_buf, count);
+		ret = count;
+	} 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;
+	int16_t temp;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	if (w1_ds2438_get_temperature(sl, &temp) == 0) {
+		ret = snprintf(buf, count, "%i\n", temp);
+	} 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;
+	uint16_t voltage;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) {
+		ret = snprintf(buf, count, "%u\n", voltage);
+	} 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;
+	uint16_t voltage;
+
+	if (off != 0)
+		return 0;
+	if (!buf)
+		return -EINVAL;
+
+	if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) {
+		ret = snprintf(buf, count, "%u\n", voltage);
+	} else
+		ret = -EIO;
+
+	return ret;
+}
+
+static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, iad_read, iad_write, 0);
+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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2760.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2760.c
new file mode 100644
index 0000000..26168ab
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2760.c
@@ -0,0 +1,175 @@
+/*
+ * 1-Wire implementation for the ds2760 chip
+ *
+ * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
+ *
+ * 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/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/gfp.h>
+
+#include <linux/w1.h>
+
+#include "w1_ds2760.h"
+
+#define W1_FAMILY_DS2760	0x30
+
+static int w1_ds2760_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 (!dev)
+		return 0;
+
+	mutex_lock(&sl->master->bus_mutex);
+
+	if (addr > DS2760_DATA_SIZE || addr < 0) {
+		count = 0;
+		goto out;
+	}
+	if (addr + count > DS2760_DATA_SIZE)
+		count = DS2760_DATA_SIZE - addr;
+
+	if (!w1_reset_select_slave(sl)) {
+		if (!io) {
+			w1_write_8(sl->master, W1_DS2760_READ_DATA);
+			w1_write_8(sl->master, addr);
+			count = w1_read_block(sl->master, buf, count);
+		} else {
+			w1_write_8(sl->master, W1_DS2760_WRITE_DATA);
+			w1_write_8(sl->master, addr);
+			w1_write_block(sl->master, buf, count);
+			/* XXX w1_write_block returns void, not n_written */
+		}
+	}
+
+out:
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return count;
+}
+
+int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count)
+{
+	return w1_ds2760_io(dev, buf, addr, count, 0);
+}
+EXPORT_SYMBOL(w1_ds2760_read);
+
+int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count)
+{
+	return w1_ds2760_io(dev, buf, addr, count, 1);
+}
+EXPORT_SYMBOL(w1_ds2760_write);
+
+static int w1_ds2760_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;
+}
+
+int w1_ds2760_store_eeprom(struct device *dev, int addr)
+{
+	return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_COPY_DATA);
+}
+EXPORT_SYMBOL(w1_ds2760_store_eeprom);
+
+int w1_ds2760_recall_eeprom(struct device *dev, int addr)
+{
+	return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA);
+}
+EXPORT_SYMBOL(w1_ds2760_recall_eeprom);
+
+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_ds2760_read(dev, buf, off, count);
+}
+
+static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2760_bin_attrs[] = {
+	&bin_attr_w1_slave,
+	NULL,
+};
+
+static const struct attribute_group w1_ds2760_group = {
+	.bin_attrs = w1_ds2760_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2760_groups[] = {
+	&w1_ds2760_group,
+	NULL,
+};
+
+static int w1_ds2760_add_slave(struct w1_slave *sl)
+{
+	int ret;
+	struct platform_device *pdev;
+
+	pdev = platform_device_alloc("ds2760-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_ds2760_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_ds2760_fops = {
+	.add_slave    = w1_ds2760_add_slave,
+	.remove_slave = w1_ds2760_remove_slave,
+	.groups       = w1_ds2760_groups,
+};
+
+static struct w1_family w1_ds2760_family = {
+	.fid = W1_FAMILY_DS2760,
+	.fops = &w1_ds2760_fops,
+};
+module_w1_family(w1_ds2760_family);
+
+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>");
+MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2760));
diff --git a/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2760.h b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2760.h
new file mode 100644
index 0000000..24168c9
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2760.h
@@ -0,0 +1,59 @@
+/*
+ * 1-Wire implementation for the ds2760 chip
+ *
+ * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ */
+
+#ifndef __w1_ds2760_h__
+#define __w1_ds2760_h__
+
+/* Known commands to the DS2760 chip */
+#define W1_DS2760_SWAP			0xAA
+#define W1_DS2760_READ_DATA		0x69
+#define W1_DS2760_WRITE_DATA		0x6C
+#define W1_DS2760_COPY_DATA		0x48
+#define W1_DS2760_RECALL_DATA		0xB8
+#define W1_DS2760_LOCK			0x6A
+
+/* Number of valid register addresses */
+#define DS2760_DATA_SIZE		0x40
+
+#define DS2760_PROTECTION_REG		0x00
+
+#define DS2760_STATUS_REG		0x01
+#define DS2760_STATUS_IE		(1 << 2)
+#define DS2760_STATUS_SWEN		(1 << 3)
+#define DS2760_STATUS_RNAOP		(1 << 4)
+#define DS2760_STATUS_PMOD		(1 << 5)
+
+#define DS2760_EEPROM_REG		0x07
+#define DS2760_SPECIAL_FEATURE_REG	0x08
+#define DS2760_VOLTAGE_MSB		0x0c
+#define DS2760_VOLTAGE_LSB		0x0d
+#define DS2760_CURRENT_MSB		0x0e
+#define DS2760_CURRENT_LSB		0x0f
+#define DS2760_CURRENT_ACCUM_MSB	0x10
+#define DS2760_CURRENT_ACCUM_LSB	0x11
+#define DS2760_TEMP_MSB			0x18
+#define DS2760_TEMP_LSB			0x19
+#define DS2760_EEPROM_BLOCK0		0x20
+#define DS2760_ACTIVE_FULL		0x20
+#define DS2760_EEPROM_BLOCK1		0x30
+#define DS2760_STATUS_WRITE_REG		0x31
+#define DS2760_RATED_CAPACITY		0x32
+#define DS2760_CURRENT_OFFSET_BIAS	0x33
+#define DS2760_ACTIVE_EMPTY		0x3b
+
+extern int w1_ds2760_read(struct device *dev, char *buf, int addr,
+			  size_t count);
+extern int w1_ds2760_write(struct device *dev, char *buf, int addr,
+			   size_t count);
+extern int w1_ds2760_store_eeprom(struct device *dev, int addr);
+extern int w1_ds2760_recall_eeprom(struct device *dev, int addr);
+
+#endif /* !__w1_ds2760_h__ */
diff --git a/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2780.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2780.c
new file mode 100644
index 0000000..a605281
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2780.h b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2780.h
new file mode 100644
index 0000000..a1fba79
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2781.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2781.c
new file mode 100644
index 0000000..645be6e
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2781.h b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2781.h
new file mode 100644
index 0000000..557dfb0
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2805.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds2805.c
new file mode 100644
index 0000000..29348d2
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds28e04.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_ds28e04.c
new file mode 100644
index 0000000..ec234b8
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_smem.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_smem.c
new file mode 100644
index 0000000..e556b0c
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/drivers/w1/slaves/w1_therm.c b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_therm.c
new file mode 100644
index 0000000..259525c
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/w1/slaves/w1_therm.c
@@ -0,0 +1,758 @@
+/*
+ *	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;
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret != 0)
+		goto post_unlock;
+
+	if (!sl->family_data) {
+		ret = -ENODEV;
+		goto pre_unlock;
+	}
+
+	/* prevent the slave from going away in sleep */
+	atomic_inc(THERM_REFCNT(family_data));
+	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 post_unlock;
+				}
+
+				ret = mutex_lock_interruptible(&dev->bus_mutex);
+				if (ret != 0)
+					goto post_unlock;
+			} else if (!w1_strong_pullup) {
+				sleep_rem = msleep_interruptible(tm);
+				if (sleep_rem != 0) {
+					ret = -EINTR;
+					goto pre_unlock;
+				}
+			}
+
+			break;
+		}
+	}
+
+pre_unlock:
+	mutex_unlock(&dev->bus_mutex);
+
+post_unlock:
+	atomic_dec(THERM_REFCNT(family_data));
+	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");
+		return -1;
+	}
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret != 0)
+		goto post_unlock;
+
+	if (!sl->family_data) {
+		ret = -ENODEV;
+		goto pre_unlock;
+	}
+
+	/* prevent the slave from going away in sleep */
+	atomic_inc(THERM_REFCNT(family_data));
+	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;
+				}
+			}
+		}
+	}
+
+pre_unlock:
+	mutex_unlock(&dev->bus_mutex);
+
+post_unlock:
+	atomic_dec(THERM_REFCNT(family_data));
+	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;
+
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
+	if (ret != 0)
+		goto error;
+
+	if (!family_data) {
+		ret = -ENODEV;
+		goto mt_unlock;
+	}
+
+	/* prevent the slave from going away in sleep */
+	atomic_inc(THERM_REFCNT(family_data));
+	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 dec_refcnt;
+				}
+			}
+
+			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;
+	}
+
+dec_refcnt:
+	atomic_dec(THERM_REFCNT(family_data));
+mt_unlock:
+	mutex_unlock(&dev->bus_mutex);
+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));