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: Matt Campbell <mattrcampbell@gmail.com>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Matt Campbell 2015-04-28 07:44:17 -04:00 коммит произвёл Greg Kroah-Hartman
Родитель f7134eea05
Коммит d9411e57dc
3 изменённых файлов: 117 добавлений и 2 удалений

Просмотреть файл

@ -0,0 +1,6 @@
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

Просмотреть файл

@ -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.

Просмотреть файл

@ -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 @@ post_unlock:
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;