Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9411e57 authored by Matt Campbell's avatar Matt Campbell Committed by Greg Kroah-Hartman
Browse files

w1: Add support for DS28EA00 sequence to w1-therm



This patch provides support for the DS28EA00 digital thermometer.

The DS28EA00 provides an additional two pins for implementing a sequence
detection algorithm.  This feature allows you to determine the physical
location of the chip in the 1-wire bus without needing pre-existing
knowledge of the bus ordering.  Support is provided through the sysfs
w1_seq file.  The file will contain a single line with an integer value
representing the device index in the bus starting at 0.

Signed-off-by: default avatarMatt Campbell <mattrcampbell@gmail.com>
Acked-by: default avatarEvgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f7134eea
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
What:		/sys/bus/w1/devices/.../w1_seq
Date:		Apr 2015
Contact:	Matt Campbell <mattrcampbell@gmail.com>
Description:	Support for the DS28EA00 chain sequence function
		see Documentation/w1/slaves/w1_therm for detailed information
Users:		any user space application which wants to communicate with DS28EA00
+10 −1
Original line number Original line Diff line number Diff line
@@ -11,12 +11,14 @@ Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Description
Description
-----------
-----------


w1_therm provides basic temperature conversion for ds18*20 devices.
w1_therm provides basic temperature conversion for ds18*20 devices, and the
ds28ea00 device.
supported family codes:
supported family codes:
W1_THERM_DS18S20	0x10
W1_THERM_DS18S20	0x10
W1_THERM_DS1822		0x22
W1_THERM_DS1822		0x22
W1_THERM_DS18B20	0x28
W1_THERM_DS18B20	0x28
W1_THERM_DS1825		0x3B
W1_THERM_DS1825		0x3B
W1_THERM_DS28EA00	0x42


Support is provided through the sysfs w1_slave file.  Each open and
Support is provided through the sysfs w1_slave file.  Each open and
read sequence will initiate a temperature conversion then provide two
read sequence will initiate a temperature conversion then provide two
@@ -48,3 +50,10 @@ resistor). The DS18b20 temperature sensor specification lists a
maximum current draw of 1.5mA and that a 5k pullup resistor is not
maximum current draw of 1.5mA and that a 5k pullup resistor is not
sufficient.  The strong pullup is designed to provide the additional
sufficient.  The strong pullup is designed to provide the additional
current required.
current required.

The DS28EA00 provides an additional two pins for implementing a sequence
detection algorithm.  This feature allows you to determine the physical
location of the chip in the 1-wire bus without needing pre-existing
knowledge of the bus ordering.  Support is provided through the sysfs
w1_seq file.  The file will contain a single line with an integer value
representing the device index in the bus starting at 0.
+101 −1
Original line number Original line Diff line number Diff line
@@ -92,13 +92,24 @@ static void w1_therm_remove_slave(struct w1_slave *sl)
static ssize_t w1_slave_show(struct device *device,
static ssize_t w1_slave_show(struct device *device,
	struct device_attribute *attr, char *buf);
	struct device_attribute *attr, char *buf);


static ssize_t w1_seq_show(struct device *device,
	struct device_attribute *attr, char *buf);

static DEVICE_ATTR_RO(w1_slave);
static DEVICE_ATTR_RO(w1_slave);
static DEVICE_ATTR_RO(w1_seq);


static struct attribute *w1_therm_attrs[] = {
static struct attribute *w1_therm_attrs[] = {
	&dev_attr_w1_slave.attr,
	&dev_attr_w1_slave.attr,
	NULL,
	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_therm);
ATTRIBUTE_GROUPS(w1_ds28ea00);


static struct w1_family_ops w1_therm_fops = {
static struct w1_family_ops w1_therm_fops = {
	.add_slave	= w1_therm_add_slave,
	.add_slave	= w1_therm_add_slave,
@@ -106,6 +117,12 @@ static struct w1_family_ops w1_therm_fops = {
	.groups		= w1_therm_groups,
	.groups		= w1_therm_groups,
};
};


static struct w1_family_ops w1_ds28ea00_fops = {
	.add_slave	= w1_therm_add_slave,
	.remove_slave	= w1_therm_remove_slave,
	.groups		= w1_ds28ea00_groups,
};

static struct w1_family w1_therm_family_DS18S20 = {
static struct w1_family w1_therm_family_DS18S20 = {
	.fid = W1_THERM_DS18S20,
	.fid = W1_THERM_DS18S20,
	.fops = &w1_therm_fops,
	.fops = &w1_therm_fops,
@@ -123,7 +140,7 @@ static struct w1_family w1_therm_family_DS1822 = {


static struct w1_family w1_therm_family_DS28EA00 = {
static struct w1_family w1_therm_family_DS28EA00 = {
	.fid = W1_THERM_DS28EA00,
	.fid = W1_THERM_DS28EA00,
	.fops = &w1_therm_fops,
	.fops = &w1_ds28ea00_fops,
};
};


static struct w1_family w1_therm_family_DS1825 = {
static struct w1_family w1_therm_family_DS1825 = {
@@ -316,6 +333,89 @@ static ssize_t w1_slave_show(struct device *device,
	return ret;
	return ret;
}
}


#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->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 ((char)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->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)
static int __init w1_therm_init(void)
{
{
	int err, i;
	int err, i;