aboutsummaryrefslogtreecommitdiff
path: root/drivers/w1
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/w1')
-rw-r--r--drivers/w1/masters/ds1wm.c52
-rw-r--r--drivers/w1/masters/ds2482.c51
-rw-r--r--drivers/w1/masters/mxc_w1.c49
-rw-r--r--drivers/w1/masters/omap_hdq.c8
-rw-r--r--drivers/w1/masters/w1-gpio.c2
-rw-r--r--drivers/w1/slaves/Kconfig13
-rw-r--r--drivers/w1/slaves/Makefile3
-rw-r--r--drivers/w1/slaves/w1_ds2413.c177
-rw-r--r--drivers/w1/slaves/w1_therm.c36
-rw-r--r--drivers/w1/w1_family.h1
10 files changed, 282 insertions, 110 deletions
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 7c294f4dc0e..96cab6ac2b4 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
@@ -459,43 +460,34 @@ static int ds1wm_probe(struct platform_device *pdev)
if (!pdev)
return -ENODEV;
- ds1wm_data = kzalloc(sizeof(*ds1wm_data), GFP_KERNEL);
+ ds1wm_data = devm_kzalloc(&pdev->dev, sizeof(*ds1wm_data), GFP_KERNEL);
if (!ds1wm_data)
return -ENOMEM;
platform_set_drvdata(pdev, ds1wm_data);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENXIO;
- goto err0;
- }
- ds1wm_data->map = ioremap(res->start, resource_size(res));
- if (!ds1wm_data->map) {
- ret = -ENOMEM;
- goto err0;
- }
+ if (!res)
+ return -ENXIO;
+ ds1wm_data->map = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ds1wm_data->map)
+ return -ENOMEM;
/* calculate bus shift from mem resource */
ds1wm_data->bus_shift = resource_size(res) >> 3;
ds1wm_data->pdev = pdev;
ds1wm_data->cell = mfd_get_cell(pdev);
- if (!ds1wm_data->cell) {
- ret = -ENODEV;
- goto err1;
- }
+ if (!ds1wm_data->cell)
+ return -ENODEV;
plat = pdev->dev.platform_data;
- if (!plat) {
- ret = -ENODEV;
- goto err1;
- }
+ if (!plat)
+ return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- ret = -ENXIO;
- goto err1;
- }
+ if (!res)
+ return -ENXIO;
ds1wm_data->irq = res->start;
ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0);
ds1wm_data->reset_recover_delay = plat->reset_recover_delay;
@@ -505,10 +497,10 @@ static int ds1wm_probe(struct platform_device *pdev)
if (res->flags & IORESOURCE_IRQ_LOWEDGE)
irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING);
- ret = request_irq(ds1wm_data->irq, ds1wm_isr,
+ ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr,
IRQF_DISABLED | IRQF_SHARED, "ds1wm", ds1wm_data);
if (ret)
- goto err1;
+ return ret;
ds1wm_up(ds1wm_data);
@@ -516,17 +508,12 @@ static int ds1wm_probe(struct platform_device *pdev)
ret = w1_add_master_device(&ds1wm_master);
if (ret)
- goto err2;
+ goto err;
return 0;
-err2:
+err:
ds1wm_down(ds1wm_data);
- free_irq(ds1wm_data->irq, ds1wm_data);
-err1:
- iounmap(ds1wm_data->map);
-err0:
- kfree(ds1wm_data);
return ret;
}
@@ -560,9 +547,6 @@ static int ds1wm_remove(struct platform_device *pdev)
w1_remove_master_device(&ds1wm_master);
ds1wm_down(ds1wm_data);
- free_irq(ds1wm_data->irq, ds1wm_data);
- iounmap(ds1wm_data->map);
- kfree(ds1wm_data);
return 0;
}
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index 6429b9e9fb8..e033491fe30 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -51,10 +51,10 @@
* The top 4 bits always read 0.
* To write, the top nibble must be the 1's compl. of the low nibble.
*/
-#define DS2482_REG_CFG_1WS 0x08
-#define DS2482_REG_CFG_SPU 0x04
-#define DS2482_REG_CFG_PPM 0x02
-#define DS2482_REG_CFG_APU 0x01
+#define DS2482_REG_CFG_1WS 0x08 /* 1-wire speed */
+#define DS2482_REG_CFG_SPU 0x04 /* strong pull-up */
+#define DS2482_REG_CFG_PPM 0x02 /* presence pulse masking */
+#define DS2482_REG_CFG_APU 0x01 /* active pull-up */
/**
@@ -132,6 +132,17 @@ struct ds2482_data {
/**
+ * Helper to calculate values for configuration register
+ * @param conf the raw config value
+ * @return the value w/ complements that can be written to register
+ */
+static inline u8 ds2482_calculate_config(u8 conf)
+{
+ return conf | ((~conf & 0x0f) << 4);
+}
+
+
+/**
* Sets the read pointer.
* @param pdev The ds2482 client pointer
* @param read_ptr see DS2482_PTR_CODE_xxx above
@@ -399,7 +410,7 @@ static u8 ds2482_w1_reset_bus(void *data)
/* If the chip did reset since detect, re-config it */
if (err & DS2482_REG_STS_RST)
ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
- 0xF0);
+ ds2482_calculate_config(0x00));
}
mutex_unlock(&pdev->access_lock);
@@ -407,6 +418,32 @@ static u8 ds2482_w1_reset_bus(void *data)
return retval;
}
+static u8 ds2482_w1_set_pullup(void *data, int delay)
+{
+ struct ds2482_w1_chan *pchan = data;
+ struct ds2482_data *pdev = pchan->pdev;
+ u8 retval = 1;
+
+ /* if delay is non-zero activate the pullup,
+ * the strong pullup will be automatically deactivated
+ * by the master, so do not explicitly deactive it
+ */
+ if (delay) {
+ /* both waits are crucial, otherwise devices might not be
+ * powered long enough, causing e.g. a w1_therm sensor to
+ * provide wrong conversion results
+ */
+ ds2482_wait_1wire_idle(pdev);
+ /* note: it seems like both SPU and APU have to be set! */
+ retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+ ds2482_calculate_config(DS2482_REG_CFG_SPU |
+ DS2482_REG_CFG_APU));
+ ds2482_wait_1wire_idle(pdev);
+ }
+
+ return retval;
+}
+
static int ds2482_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -452,7 +489,8 @@ static int ds2482_probe(struct i2c_client *client,
data->w1_count = 8;
/* Set all config items to 0 (off) */
- ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, 0xF0);
+ ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG,
+ ds2482_calculate_config(0x00));
mutex_init(&data->access_lock);
@@ -468,6 +506,7 @@ static int ds2482_probe(struct i2c_client *client,
data->w1_ch[idx].w1_bm.touch_bit = ds2482_w1_touch_bit;
data->w1_ch[idx].w1_bm.triplet = ds2482_w1_triplet;
data->w1_ch[idx].w1_bm.reset_bus = ds2482_w1_reset_bus;
+ data->w1_ch[idx].w1_bm.set_pullup = ds2482_w1_set_pullup;
err = w1_add_master_device(&data->w1_ch[idx].w1_bm);
if (err) {
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c
index 949e5666954..950d354d50e 100644
--- a/drivers/w1/masters/mxc_w1.c
+++ b/drivers/w1/masters/mxc_w1.c
@@ -109,34 +109,21 @@ static int mxc_w1_probe(struct platform_device *pdev)
struct resource *res;
int err = 0;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL);
+ mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
+ GFP_KERNEL);
if (!mdev)
return -ENOMEM;
- mdev->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(mdev->clk)) {
- err = PTR_ERR(mdev->clk);
- goto failed_clk;
- }
+ mdev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mdev->clk))
+ return PTR_ERR(mdev->clk);
mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1;
- res = request_mem_region(res->start, resource_size(res),
- "mxc_w1");
- if (!res) {
- err = -EBUSY;
- goto failed_req;
- }
-
- mdev->regs = ioremap(res->start, resource_size(res));
- if (!mdev->regs) {
- dev_err(&pdev->dev, "Cannot map mxc_w1 registers\n");
- goto failed_ioremap;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mdev->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!mdev->regs)
+ return -EBUSY;
clk_prepare_enable(mdev->clk);
__raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER);
@@ -148,20 +135,10 @@ static int mxc_w1_probe(struct platform_device *pdev)
err = w1_add_master_device(&mdev->bus_master);
if (err)
- goto failed_add;
+ return err;
platform_set_drvdata(pdev, mdev);
return 0;
-
-failed_add:
- iounmap(mdev->regs);
-failed_ioremap:
- release_mem_region(res->start, resource_size(res));
-failed_req:
- clk_put(mdev->clk);
-failed_clk:
- kfree(mdev);
- return err;
}
/*
@@ -170,16 +147,10 @@ failed_clk:
static int mxc_w1_remove(struct platform_device *pdev)
{
struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
w1_remove_master_device(&mdev->bus_master);
- iounmap(mdev->regs);
- release_mem_region(res->start, resource_size(res));
clk_disable_unprepare(mdev->clk);
- clk_put(mdev->clk);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 184dbce4abd..db2390aed38 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -560,11 +560,9 @@ static int omap_hdq_probe(struct platform_device *pdev)
return -ENXIO;
}
- hdq_data->hdq_base = devm_request_and_ioremap(dev, res);
- if (!hdq_data->hdq_base) {
- dev_dbg(&pdev->dev, "ioremap failed\n");
- return -ENOMEM;
- }
+ hdq_data->hdq_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdq_data->hdq_base))
+ return PTR_ERR(hdq_data->hdq_base);
hdq_data->hdq_usecount = 0;
mutex_init(&hdq_data->hdq_mutex);
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index 85b363a5bd0..d39dfa4cc23 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -72,7 +72,7 @@ static int w1_gpio_probe_dt(struct platform_device *pdev)
return 0;
}
-static int __init w1_gpio_probe(struct platform_device *pdev)
+static int w1_gpio_probe(struct platform_device *pdev)
{
struct w1_bus_master *master;
struct w1_gpio_platform_data *pdata;
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index 67526690acb..762561fbabb 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -17,11 +17,16 @@ config W1_SLAVE_SMEM
simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
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
+ 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
- DS2408 8-Channel Addressable Switch device support
+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_DS2423
tristate "Counter 1-wire device (DS2423)"
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 05188f6aab5..06529f3157a 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -4,7 +4,8 @@
obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o
obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o
-obj-$(CONFIG_W1_SLAVE_DS2408) += w1_ds2408.o
+obj-$(CONFIG_W1_SLAVE_DS2408) += w1_ds2408.o
+obj-$(CONFIG_W1_SLAVE_DS2413) += w1_ds2413.o
obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o
obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o
obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c
new file mode 100644
index 00000000000..829786252c6
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2413.c
@@ -0,0 +1,177 @@
+/*
+ * 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 "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>");
+MODULE_DESCRIPTION("w1 family 3a driver for DS2413 2 Pin IO");
+
+#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 w1_f3a_read_state(
+ 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 ssize_t w1_f3a_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[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;
+}
+
+#define NB_SYSFS_BIN_FILES 2
+static struct bin_attribute w1_f3a_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
+ {
+ .attr = {
+ .name = "state",
+ .mode = S_IRUGO,
+ },
+ .size = 1,
+ .read = w1_f3a_read_state,
+ },
+ {
+ .attr = {
+ .name = "output",
+ .mode = S_IRUGO | S_IWUSR | S_IWGRP,
+ },
+ .size = 1,
+ .write = w1_f3a_write_output,
+ }
+};
+
+static int w1_f3a_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_f3a_sysfs_bin_files[i]));
+ if (err)
+ while (--i >= 0)
+ sysfs_remove_bin_file(&sl->dev.kobj,
+ &(w1_f3a_sysfs_bin_files[i]));
+ return err;
+}
+
+static void w1_f3a_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_f3a_sysfs_bin_files[i]));
+}
+
+static struct w1_family_ops w1_f3a_fops = {
+ .add_slave = w1_f3a_add_slave,
+ .remove_slave = w1_f3a_remove_slave,
+};
+
+static struct w1_family w1_family_3a = {
+ .fid = W1_FAMILY_DS2413,
+ .fops = &w1_f3a_fops,
+};
+
+static int __init w1_f3a_init(void)
+{
+ return w1_register_family(&w1_family_3a);
+}
+
+static void __exit w1_f3a_exit(void)
+{
+ w1_unregister_family(&w1_family_3a);
+}
+
+module_init(w1_f3a_init);
+module_exit(w1_f3a_exit);
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 92d08e7fcba..c1a702f8c80 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -41,14 +41,18 @@ MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature famil
* 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);
-static u8 bad_roms[][9] = {
- {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
- {}
- };
static ssize_t w1_therm_read(struct device *device,
struct device_attribute *attr, char *buf);
@@ -168,16 +172,6 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid)
return 0;
}
-static int w1_therm_check_rom(u8 rom[9])
-{
- int i;
-
- for (i=0; i<sizeof(bad_roms)/9; ++i)
- if (!memcmp(bad_roms[i], rom, 9))
- return 1;
-
- return 0;
-}
static ssize_t w1_therm_read(struct device *device,
struct device_attribute *attr, char *buf)
@@ -194,10 +188,11 @@ static ssize_t w1_therm_read(struct device *device,
memset(rom, 0, sizeof(rom));
- verdict = 0;
- crc = 0;
-
while (max_trying--) {
+
+ verdict = 0;
+ crc = 0;
+
if (!w1_reset_select_slave(sl)) {
int count = 0;
unsigned int tm = 750;
@@ -210,7 +205,8 @@ static ssize_t w1_therm_read(struct device *device,
continue;
/* 750ms strong pullup (or delay) after the convert */
- if (!external_power && w1_strong_pullup)
+ if (w1_strong_pullup == 2 ||
+ (!external_power && w1_strong_pullup))
w1_next_pullup(dev, tm);
w1_write_8(dev, W1_CONVERT_TEMP);
@@ -249,7 +245,7 @@ static ssize_t w1_therm_read(struct device *device,
}
}
- if (!w1_therm_check_rom(rom))
+ if (verdict)
break;
}
@@ -260,7 +256,7 @@ static ssize_t w1_therm_read(struct device *device,
if (verdict)
memcpy(sl->rom, rom, sizeof(sl->rom));
else
- dev_warn(device, "18S20 doesn't respond to CONVERT_TEMP.\n");
+ dev_warn(device, "Read failed CRC check\n");
for (i = 0; i < 9; ++i)
c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", sl->rom[i]);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index a1f0ce151d5..625dd08f775 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -39,6 +39,7 @@
#define W1_EEPROM_DS2431 0x2D
#define W1_FAMILY_DS2760 0x30
#define W1_FAMILY_DS2780 0x32
+#define W1_FAMILY_DS2413 0x3A
#define W1_THERM_DS1825 0x3B
#define W1_FAMILY_DS2781 0x3D
#define W1_THERM_DS28EA00 0x42