Commit 23e5e116 authored by Evgeniy Polyakov's avatar Evgeniy Polyakov Committed by Greg Kroah-Hartman

[PATCH] w1: Added w1_read_block() and w1_write_block() callbacks.

Added w1_read_block() and w1_write_block().
w1_therm.c now uses them.
w1_therm: Chnaged snprintf to sprintf in w1_therm_read_bin() and added max_trying -
        number of tryings to read temperature before failng. By default it is 10.
        Added w1_therm_check_rom() - checks if read rom is in black list.
        If rom is in black list it is probably due to unsufficient of "power" in the sensor -
        either add strong pullup or connect it to Vcc.
Signed-off-by: default avatarEvgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 6a06b166
......@@ -73,6 +73,16 @@ struct w1_bus_master
u8 (*read_bit)(unsigned long);
void (*write_bit)(unsigned long, u8);
u8 (*read_byte)(unsigned long);
void (*write_byte)(unsigned long, u8);
u8 (*read_block)(unsigned long, u8 *, int);
void (*write_block)(unsigned long, u8 *, int);
u8 (*touch_bit)(unsigned long, u8);
u8 (*reset_bus)(unsigned long);
};
struct w1_master
......
......@@ -55,6 +55,14 @@ void w1_delay(unsigned long tm)
udelay(tm * w1_delay_parm);
}
u8 w1_touch_bit(struct w1_master *dev, int bit)
{
if (dev->bus_master->touch_bit)
return dev->bus_master->touch_bit(dev->bus_master->data, bit);
else
return w1_read_bit(dev);
}
void w1_write_bit(struct w1_master *dev, int bit)
{
if (bit) {
......@@ -74,8 +82,11 @@ void w1_write_8(struct w1_master *dev, u8 byte)
{
int i;
for (i = 0; i < 8; ++i)
w1_write_bit(dev, (byte >> i) & 0x1);
if (dev->bus_master->write_byte)
dev->bus_master->write_byte(dev->bus_master->data, byte);
else
for (i = 0; i < 8; ++i)
w1_write_bit(dev, (byte >> i) & 0x1);
}
u8 w1_read_bit(struct w1_master *dev)
......@@ -98,23 +109,59 @@ u8 w1_read_8(struct w1_master * dev)
int i;
u8 res = 0;
for (i = 0; i < 8; ++i)
res |= (w1_read_bit(dev) << i);
if (dev->bus_master->read_byte)
res = dev->bus_master->read_byte(dev->bus_master->data);
else
for (i = 0; i < 8; ++i)
res |= (w1_read_bit(dev) << i);
return res;
}
void w1_write_block(struct w1_master *dev, u8 *buf, int len)
{
int i;
if (dev->bus_master->write_block)
dev->bus_master->write_block(dev->bus_master->data, buf, len);
else
for (i = 0; i < len; ++i)
w1_write_8(dev, buf[i]);
}
u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
{
int i;
u8 ret;
if (dev->bus_master->read_block)
ret = dev->bus_master->read_block(dev->bus_master->data, buf, len);
else
{
for (i = 0; i < len; ++i)
buf[i] = w1_read_8(dev);
ret = len;
}
return ret;
}
int w1_reset_bus(struct w1_master *dev)
{
int result;
int result = 0;
dev->bus_master->write_bit(dev->bus_master->data, 0);
w1_delay(480);
dev->bus_master->write_bit(dev->bus_master->data, 1);
w1_delay(70);
if (dev->bus_master->reset_bus)
result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
else
{
dev->bus_master->write_bit(dev->bus_master->data, 0);
w1_delay(480);
dev->bus_master->write_bit(dev->bus_master->data, 1);
w1_delay(70);
result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
w1_delay(410);
result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
w1_delay(410);
}
return result;
}
......@@ -136,3 +183,5 @@ EXPORT_SYMBOL(w1_read_8);
EXPORT_SYMBOL(w1_reset_bus);
EXPORT_SYMBOL(w1_calc_crc8);
EXPORT_SYMBOL(w1_delay);
EXPORT_SYMBOL(w1_read_block);
EXPORT_SYMBOL(w1_write_block);
......@@ -25,11 +25,14 @@
#include "w1.h"
void w1_delay(unsigned long);
u8 w1_touch_bit(struct w1_master *, int);
void w1_write_bit(struct w1_master *, int);
void w1_write_8(struct w1_master *, u8);
u8 w1_read_bit(struct w1_master *);
u8 w1_read_8(struct w1_master *);
int w1_reset_bus(struct w1_master *);
u8 w1_calc_crc8(u8 *, int);
void w1_write_block(struct w1_master *, u8 *, int);
u8 w1_read_block(struct w1_master *, u8 *, int);
#endif /* __W1_IO_H */
......@@ -36,6 +36,11 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
static u8 bad_roms[][9] = {
{0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
{}
};
static ssize_t w1_therm_read_name(struct device *, char *);
static ssize_t w1_therm_read_temp(struct device *, char *);
static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
......@@ -69,14 +74,24 @@ static ssize_t w1_therm_read_temp(struct device *dev, char *buf)
return sprintf(buf, "%d\n", temp * 1000);
}
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_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
struct w1_slave, dev);
struct w1_master *dev = sl->master;
u8 rom[9], crc, verdict;
size_t icount;
int i;
int i, max_trying = 10;
u16 temp;
atomic_inc(&sl->refcnt);
......@@ -89,10 +104,10 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
count = 0;
goto out;
}
if (off + count > W1_SLAVE_DATA_SIZE)
count = W1_SLAVE_DATA_SIZE - off;
icount = count;
if (off + count > W1_SLAVE_DATA_SIZE) {
count = 0;
goto out;
}
memset(buf, 0, count);
memset(rom, 0, sizeof(rom));
......@@ -100,56 +115,56 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
count = 0;
verdict = 0;
crc = 0;
if (!w1_reset_bus(dev)) {
u64 id = *(u64 *) & sl->reg_num;
int count = 0;
w1_write_8(dev, W1_MATCH_ROM);
for (i = 0; i < 8; ++i)
w1_write_8(dev, (id >> i * 8) & 0xff);
while (max_trying--)
{
if (!w1_reset_bus (dev)) {
int count = 0;
u8 match[9] = {W1_MATCH_ROM, };
w1_write_8(dev, W1_CONVERT_TEMP);
memcpy(&match[1], (u64 *) & sl->reg_num, 8);
w1_write_block(dev, match, 9);
while (dev->bus_master->read_bit(dev->bus_master->data) == 0
&& count < 10) {
w1_delay(1);
count++;
}
w1_write_8(dev, W1_CONVERT_TEMP);
if (count < 10) {
if (!w1_reset_bus(dev)) {
w1_write_8(dev, W1_MATCH_ROM);
for (i = 0; i < 8; ++i)
w1_write_8(dev,
(id >> i * 8) & 0xff);
if (count < 10) {
if (!w1_reset_bus(dev)) {
w1_write_block(dev, match, 9);
w1_write_8(dev, W1_READ_SCRATCHPAD);
for (i = 0; i < 9; ++i)
rom[i] = w1_read_8(dev);
w1_write_8(dev, W1_READ_SCRATCHPAD);
if ((count = w1_read_block(dev, rom, 9)) != 9)
{
dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
}
crc = w1_calc_crc8(rom, 8);
crc = w1_calc_crc8(rom, 8);
if (rom[8] == crc && rom[0])
verdict = 1;
if (rom[8] == crc && rom[0])
verdict = 1;
}
}
else
dev_warn(&dev->dev,
"18S20 doesn't respond to CONVERT_TEMP.\n");
}
else
dev_warn(&dev->dev,
"18S20 doesn't respond to CONVERT_TEMP.\n");
if (!w1_therm_check_rom(rom))
break;
}
for (i = 0; i < 9; ++i)
count += snprintf(buf + count, icount - count, "%02x ", rom[i]);
count += snprintf(buf + count, icount - count, ": crc=%02x %s\n",
count += sprintf(buf + count, "%02x ", rom[i]);
count += sprintf(buf + count, ": crc=%02x %s\n",
crc, (verdict) ? "YES" : "NO");
if (verdict)
memcpy(sl->rom, rom, sizeof(sl->rom));
for (i = 0; i < 9; ++i)
count += snprintf(buf + count, icount - count, "%02x ", sl->rom[i]);
count += sprintf(buf + count, "%02x ", sl->rom[i]);
temp = 0;
temp <<= sl->rom[1] / 2;
temp |= sl->rom[0] / 2;
count += snprintf(buf + count, icount - count, "t=%u\n", temp);
count += sprintf(buf + count, "t=%u\n", temp);
out:
up(&dev->mutex);
out_dec:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment