* [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
@ 2012-03-16 21:24 Markus Franke
2012-03-18 21:40 ` Evgeniy Polyakov
2012-04-09 22:08 ` Greg KH
0 siblings, 2 replies; 14+ messages in thread
From: Markus Franke @ 2012-03-16 21:24 UTC (permalink / raw)
To: linux-kernel; +Cc: gregkh, Evgeniy Polyakov
This patch adds a 1-wire slave device driver for the DS28E04-100.
It applies to the current linux kernel git tree.
Signed-off-by: Markus Franke <franm@hrz.tu-chemnitz.de>
---
drivers/w1/slaves/Kconfig | 7 +
drivers/w1/slaves/Makefile | 1 +
drivers/w1/slaves/w1_ds28e04.c | 458 ++++++++++++++++++++++++++++++++++++++++
drivers/w1/w1_family.h | 1 +
4 files changed, 467 insertions(+), 0 deletions(-)
create mode 100644 drivers/w1/slaves/w1_ds28e04.c
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index d0cb01b..609b175 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -81,6 +81,13 @@ config W1_SLAVE_DS2780
If you are unsure, say N.
+config W1_SLAVE_DS28E04
+ tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
+ depends on W1
+ help
+ Say Y here if you want to use a 1-wire
+ 4kb EEPROM with PIO family device (DS28E04).
+
config W1_SLAVE_BQ27000
tristate "BQ27000 slave support"
depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 1f31e9f..aa1c8db 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o
obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
+obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
new file mode 100644
index 0000000..e838526
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -0,0 +1,458 @@
+/*
+ * 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 "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+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");
+
+/* 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 w1_f1C_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);
+ struct w1_f1C_data *data = sl->family_data;
+ int i, min_page, max_page;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 w1_f1C_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, idx;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 ssize_t w1_f1C_read_pio(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 w1_f1C_write_pio(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))
+ 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 ssize_t w1_f1C_show_crccheck(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", w1_enable_crccheck);
+}
+
+static ssize_t w1_f1C_store_crccheck(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char val;
+
+ if(count != 1 || !buf) return -EINVAL;
+
+ val = *buf;
+
+ /* 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);
+}
+
+#define NB_SYSFS_BIN_FILES 2
+static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
+ {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = W1_EEPROM_SIZE,
+ .read = w1_f1C_read_bin,
+ .write = w1_f1C_write_bin,
+ },
+ {
+ .attr = {
+ .name = "pio",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = 1,
+ .read = w1_f1C_read_pio,
+ .write = w1_f1C_write_pio,
+ }
+};
+
+static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO, w1_f1C_show_crccheck, w1_f1C_store_crccheck);
+
+static int w1_f1C_add_slave(struct w1_slave *sl)
+{
+ int err = 0;
+ int i;
+ 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;
+ }
+
+ /* create binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+ err = sysfs_create_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+
+ if(err)
+ goto out;
+
+ /* create device attributes */
+ err = device_create_file(&sl->dev, &dev_attr_crccheck);
+
+ if(err) {
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+ }
+
+out:
+ if(err) {
+ if(w1_enable_crccheck)
+ kfree(data);
+ }
+
+ return err;
+}
+
+static void w1_f1C_remove_slave(struct w1_slave *sl)
+{
+ int i;
+
+ if(w1_enable_crccheck) {
+ kfree(sl->family_data);
+ sl->family_data = NULL;
+ }
+
+ /* remove device attributes */
+ device_remove_file(&sl->dev, &dev_attr_crccheck);
+
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+}
+
+static struct w1_family_ops w1_f1C_fops = {
+ .add_slave = w1_f1C_add_slave,
+ .remove_slave = w1_f1C_remove_slave,
+};
+
+static struct w1_family w1_family_1C = {
+ .fid = W1_FAMILY_DS28E04,
+ .fops = &w1_f1C_fops,
+};
+
+static int __init w1_f1C_init(void)
+{
+ return w1_register_family(&w1_family_1C);
+}
+
+static void __exit w1_f1C_fini(void)
+{
+ w1_unregister_family(&w1_family_1C);
+}
+
+module_init(w1_f1C_init);
+module_exit(w1_f1C_fini);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 490cda2..aa79c28 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -30,6 +30,7 @@
#define W1_FAMILY_SMEM_01 0x01
#define W1_FAMILY_SMEM_81 0x81
#define W1_THERM_DS18S20 0x10
+#define W1_FAMILY_DS28E04 0x1C
#define W1_COUNTER_DS2423 0x1D
#define W1_THERM_DS1822 0x22
#define W1_EEPROM_DS2433 0x23
--
1.7.4.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-03-16 21:24 [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100 Markus Franke
@ 2012-03-18 21:40 ` Evgeniy Polyakov
2012-03-25 20:21 ` Markus Franke
2012-04-09 22:08 ` Greg KH
1 sibling, 1 reply; 14+ messages in thread
From: Evgeniy Polyakov @ 2012-03-18 21:40 UTC (permalink / raw)
To: Markus Franke; +Cc: linux-kernel, gregkh
Hi
On Fri, Mar 16, 2012 at 10:24:46PM +0100, Markus Franke (markus.franke@s2002.tu-chemnitz.de) wrote:
> This patch adds a 1-wire slave device driver for the DS28E04-100.
>
> It applies to the current linux kernel git tree.
As discussed with Markus already - looks very good
Greg, please pull it into your tree
> Signed-off-by: Markus Franke <franm@hrz.tu-chemnitz.de>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
--
Evgeniy Polyakov
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-03-18 21:40 ` Evgeniy Polyakov
@ 2012-03-25 20:21 ` Markus Franke
2012-03-26 18:39 ` Greg KH
0 siblings, 1 reply; 14+ messages in thread
From: Markus Franke @ 2012-03-25 20:21 UTC (permalink / raw)
To: linux-kernel; +Cc: gregkh
Dear Greg,
have you received this patch? Just wondering because I have not heard
something about this anymore from your side.
Please do also have a look at
[PATCH 2/2] w1: Disable irqs during 1-wire bus operations, extend 1-wire
reset pulse
Both patches have already been signed by Evgeniy Polyakov.
Thanks and with best regards,
Markus Franke
Am 18.03.2012 22:40, schrieb Evgeniy Polyakov:
> Hi
>
> On Fri, Mar 16, 2012 at 10:24:46PM +0100, Markus Franke (markus.franke@s2002.tu-chemnitz.de) wrote:
>> This patch adds a 1-wire slave device driver for the DS28E04-100.
>>
>> It applies to the current linux kernel git tree.
>
> As discussed with Markus already - looks very good
> Greg, please pull it into your tree
>
>> Signed-off-by: Markus Franke<franm@hrz.tu-chemnitz.de>
>
> Acked-by: Evgeniy Polyakov<zbr@ioremap.net>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-03-25 20:21 ` Markus Franke
@ 2012-03-26 18:39 ` Greg KH
2012-03-26 21:17 ` Markus Franke
0 siblings, 1 reply; 14+ messages in thread
From: Greg KH @ 2012-03-26 18:39 UTC (permalink / raw)
To: Markus Franke; +Cc: linux-kernel
On Sun, Mar 25, 2012 at 10:21:11PM +0200, Markus Franke wrote:
> Dear Greg,
>
> have you received this patch? Just wondering because I have not
> heard something about this anymore from your side.
> Please do also have a look at
>
> [PATCH 2/2] w1: Disable irqs during 1-wire bus operations, extend
> 1-wire reset pulse
>
> Both patches have already been signed by Evgeniy Polyakov.
They are in my queue to apply after 3.4-rc1 is out as they came in after
the merge window closed for my trees.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-03-26 18:39 ` Greg KH
@ 2012-03-26 21:17 ` Markus Franke
0 siblings, 0 replies; 14+ messages in thread
From: Markus Franke @ 2012-03-26 21:17 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel
Oh, perfect. Thanks for the information! :-)
Best regards,
Markus Franke
Am 26.03.2012 20:39, schrieb Greg KH:
> They are in my queue to apply after 3.4-rc1 is out as they came in after
> the merge window closed for my trees.
>
> thanks,
>
> greg k-h
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-03-16 21:24 [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100 Markus Franke
2012-03-18 21:40 ` Evgeniy Polyakov
@ 2012-04-09 22:08 ` Greg KH
2012-04-10 5:55 ` Markus Franke
2012-04-11 22:44 ` Markus Franke
1 sibling, 2 replies; 14+ messages in thread
From: Greg KH @ 2012-04-09 22:08 UTC (permalink / raw)
To: Markus Franke; +Cc: linux-kernel, Evgeniy Polyakov
On Fri, Mar 16, 2012 at 10:24:46PM +0100, Markus Franke wrote:
> This patch adds a 1-wire slave device driver for the DS28E04-100.
>
> It applies to the current linux kernel git tree.
It's corrupted somehow and doesn't apply at all :(
Care to redo this one, and your 2/2 patch, against the 3.4-rc2 release
and resend it, with Evgeniy's acks, so that I can apply it? Please
ensure that your email client doesn't mess it up again (hint, it is
adding spaces at the front of the line of some parts of the diff.)
thanks,
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-04-09 22:08 ` Greg KH
@ 2012-04-10 5:55 ` Markus Franke
2012-04-10 14:07 ` Greg KH
2012-04-11 22:44 ` Markus Franke
1 sibling, 1 reply; 14+ messages in thread
From: Markus Franke @ 2012-04-10 5:55 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, Evgeniy Polyakov
Dear Greg,
Zitat von Greg KH <gregkh@linuxfoundation.org>:
> On Fri, Mar 16, 2012 at 10:24:46PM +0100, Markus Franke wrote:
>> This patch adds a 1-wire slave device driver for the DS28E04-100.
>>
>> It applies to the current linux kernel git tree.
>
> It's corrupted somehow and doesn't apply at all :(
>
> Care to redo this one, and your 2/2 patch, against the 3.4-rc2 release
> and resend it, with Evgeniy's acks, so that I can apply it? Please
> ensure that your email client doesn't mess it up again (hint, it is
> adding spaces at the front of the line of some parts of the diff.)
I don't have a clue what might go wrong within my email client. Would
sending it as an attachement be an option? If not I might have to
switch to another client.
Best regards,
Markus Franke
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-04-10 5:55 ` Markus Franke
@ 2012-04-10 14:07 ` Greg KH
0 siblings, 0 replies; 14+ messages in thread
From: Greg KH @ 2012-04-10 14:07 UTC (permalink / raw)
To: Markus Franke; +Cc: linux-kernel, Evgeniy Polyakov
On Tue, Apr 10, 2012 at 07:55:32AM +0200, Markus Franke wrote:
> Dear Greg,
>
> Zitat von Greg KH <gregkh@linuxfoundation.org>:
>
> >On Fri, Mar 16, 2012 at 10:24:46PM +0100, Markus Franke wrote:
> >>This patch adds a 1-wire slave device driver for the DS28E04-100.
> >>
> >>It applies to the current linux kernel git tree.
> >
> >It's corrupted somehow and doesn't apply at all :(
> >
> >Care to redo this one, and your 2/2 patch, against the 3.4-rc2 release
> >and resend it, with Evgeniy's acks, so that I can apply it? Please
> >ensure that your email client doesn't mess it up again (hint, it is
> >adding spaces at the front of the line of some parts of the diff.)
>
> I don't have a clue what might go wrong within my email client.
> Would sending it as an attachement be an option? If not I might have
> to switch to another client.
Have you read Documentation/email_clients.txt yet?
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-04-09 22:08 ` Greg KH
2012-04-10 5:55 ` Markus Franke
@ 2012-04-11 22:44 ` Markus Franke
2012-04-11 23:45 ` Greg KH
1 sibling, 1 reply; 14+ messages in thread
From: Markus Franke @ 2012-04-11 22:44 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, Evgeniy Polyakov
Am 10.04.2012 00:08, schrieb Greg KH:
> On Fri, Mar 16, 2012 at 10:24:46PM +0100, Markus Franke wrote:
>> This patch adds a 1-wire slave device driver for the DS28E04-100.
>>
>> It applies to the current linux kernel git tree.
>
> It's corrupted somehow and doesn't apply at all :(
>
> Care to redo this one, and your 2/2 patch, against the 3.4-rc2 release
> and resend it, with Evgeniy's acks, so that I can apply it? Please
> ensure that your email client doesn't mess it up again (hint, it is
> adding spaces at the front of the line of some parts of the diff.)
Used Thunderbird with external editor (vi) now, sent the patches to
myself and applied successfully. Hope it is in a shape which can be
accepted now.
Best regards,
Markus
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-04-11 22:44 ` Markus Franke
@ 2012-04-11 23:45 ` Greg KH
0 siblings, 0 replies; 14+ messages in thread
From: Greg KH @ 2012-04-11 23:45 UTC (permalink / raw)
To: Markus Franke; +Cc: linux-kernel, Evgeniy Polyakov
On Thu, Apr 12, 2012 at 12:44:28AM +0200, Markus Franke wrote:
> Am 10.04.2012 00:08, schrieb Greg KH:
>
> > On Fri, Mar 16, 2012 at 10:24:46PM +0100, Markus Franke wrote:
> >> This patch adds a 1-wire slave device driver for the DS28E04-100.
> >>
> >> It applies to the current linux kernel git tree.
> >
> > It's corrupted somehow and doesn't apply at all :(
> >
> > Care to redo this one, and your 2/2 patch, against the 3.4-rc2 release
> > and resend it, with Evgeniy's acks, so that I can apply it? Please
> > ensure that your email client doesn't mess it up again (hint, it is
> > adding spaces at the front of the line of some parts of the diff.)
>
>
> Used Thunderbird with external editor (vi) now, sent the patches to
> myself and applied successfully. Hope it is in a shape which can be
> accepted now.
They worked fine, thanks for resending them.
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
[not found] <4F86061D.10501@hrz.tu-chemnitz.de>
@ 2012-04-11 22:40 ` Markus Franke
0 siblings, 0 replies; 14+ messages in thread
From: Markus Franke @ 2012-04-11 22:40 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, Evgeniy Polyakov
This patch adds a 1-wire slave device driver for the DS28E04-100.
It applies to the current linux kernel git tree.
Signed-off-by: Markus Franke <franm@hrz.tu-chemnitz.de>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
---
drivers/w1/slaves/Kconfig | 7 +
drivers/w1/slaves/Makefile | 1 +
drivers/w1/slaves/w1_ds28e04.c | 462 ++++++++++++++++++++++++++++++++++++++++
drivers/w1/w1_family.h | 1 +
4 files changed, 471 insertions(+), 0 deletions(-)
create mode 100644 drivers/w1/slaves/w1_ds28e04.c
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index eb9e376..605ee36 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -94,6 +94,13 @@ config W1_SLAVE_DS2781
If you are unsure, say N.
+config W1_SLAVE_DS28E04
+ tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
+ depends on W1
+ help
+ Say Y here if you want to use a 1-wire
+ 4kb EEPROM with PIO family device (DS28E04).
+
config W1_SLAVE_BQ27000
tristate "BQ27000 slave support"
depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index c4f1859..05188f6 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -12,3 +12,4 @@ 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_BQ27000) += w1_bq27000.o
+obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
new file mode 100644
index 0000000..f652db3
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -0,0 +1,462 @@
+/*
+ * 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 "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+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");
+
+/* 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 w1_f1C_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);
+ struct w1_f1C_data *data = sl->family_data;
+ int i, min_page, max_page;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 w1_f1C_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, idx;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 ssize_t w1_f1C_read_pio(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 w1_f1C_write_pio(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))
+ 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 ssize_t w1_f1C_show_crccheck(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 w1_f1C_store_crccheck(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);
+}
+
+#define NB_SYSFS_BIN_FILES 2
+static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
+ {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = W1_EEPROM_SIZE,
+ .read = w1_f1C_read_bin,
+ .write = w1_f1C_write_bin,
+ },
+ {
+ .attr = {
+ .name = "pio",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = 1,
+ .read = w1_f1C_read_pio,
+ .write = w1_f1C_write_pio,
+ }
+};
+
+static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO, w1_f1C_show_crccheck, w1_f1C_store_crccheck);
+
+static int w1_f1C_add_slave(struct w1_slave *sl)
+{
+ int err = 0;
+ int i;
+ 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;
+ }
+
+ /* create binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+ err = sysfs_create_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+
+ if(err)
+ goto out;
+
+ /* create device attributes */
+ err = device_create_file(&sl->dev, &dev_attr_crccheck);
+
+ if(err) {
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+ }
+
+out:
+ if(err) {
+ if(w1_enable_crccheck)
+ kfree(data);
+ }
+
+ return err;
+}
+
+static void w1_f1C_remove_slave(struct w1_slave *sl)
+{
+ int i;
+
+ if(w1_enable_crccheck) {
+ kfree(sl->family_data);
+ sl->family_data = NULL;
+ }
+
+ /* remove device attributes */
+ device_remove_file(&sl->dev, &dev_attr_crccheck);
+
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+}
+
+static struct w1_family_ops w1_f1C_fops = {
+ .add_slave = w1_f1C_add_slave,
+ .remove_slave = w1_f1C_remove_slave,
+};
+
+static struct w1_family w1_family_1C = {
+ .fid = W1_FAMILY_DS28E04,
+ .fops = &w1_f1C_fops,
+};
+
+static int __init w1_f1C_init(void)
+{
+ return w1_register_family(&w1_family_1C);
+}
+
+static void __exit w1_f1C_fini(void)
+{
+ w1_unregister_family(&w1_family_1C);
+}
+
+module_init(w1_f1C_init);
+module_exit(w1_f1C_fini);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 874aeb0..b00ada4 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -30,6 +30,7 @@
#define W1_FAMILY_SMEM_01 0x01
#define W1_FAMILY_SMEM_81 0x81
#define W1_THERM_DS18S20 0x10
+#define W1_FAMILY_DS28E04 0x1C
#define W1_COUNTER_DS2423 0x1D
#define W1_THERM_DS1822 0x22
#define W1_EEPROM_DS2433 0x23
--
1.7.5.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
2012-03-15 22:05 Markus Franke
@ 2012-03-15 23:18 ` Greg KH
0 siblings, 0 replies; 14+ messages in thread
From: Greg KH @ 2012-03-15 23:18 UTC (permalink / raw)
To: Markus Franke; +Cc: linux-kernel
On Thu, Mar 15, 2012 at 11:05:08PM +0100, Markus Franke wrote:
> This patch adds a 1-wire slave device driver for the DS28E04-100.
>
> It applies to the current linux kernel git tree.
>
> Signed-off-by: Markus Franke <franm@hrz.tu-chemnitz.de>
> ---
> drivers/w1/slaves/Kconfig | 7 +
> drivers/w1/slaves/Makefile | 1 +
> drivers/w1/slaves/w1_ds28e04.c | 458
> ++++++++++++++++++++++++++++++++++++++++
Your email client munged the patch to be line-wrapped and added an extra
space at the beginning of each line, making this impossible to apply.
Also, please cc: the w1 maintainer for patches like this, I need his ACK
before I can accept them.
care to try again?
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
@ 2012-03-15 22:53 Markus Franke
0 siblings, 0 replies; 14+ messages in thread
From: Markus Franke @ 2012-03-15 22:53 UTC (permalink / raw)
To: linux-kernel; +Cc: gregkh
This patch adds a 1-wire slave device driver for the DS28E04-100.
It applies to the current linux kernel git tree.
Signed-off-by: Markus Franke <franm@hrz.tu-chemnitz.de>
---
drivers/w1/slaves/Kconfig | 7 +
drivers/w1/slaves/Makefile | 1 +
drivers/w1/slaves/w1_ds28e04.c | 458
++++++++++++++++++++++++++++++++++++++++
drivers/w1/w1_family.h | 1 +
4 files changed, 467 insertions(+), 0 deletions(-)
create mode 100644 drivers/w1/slaves/w1_ds28e04.c
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index d0cb01b..609b175 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -81,6 +81,13 @@ config W1_SLAVE_DS2780
If you are unsure, say N.
+config W1_SLAVE_DS28E04
+ tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
+ depends on W1
+ help
+ Say Y here if you want to use a 1-wire
+ 4kb EEPROM with PIO family device (DS28E04).
+
config W1_SLAVE_BQ27000
tristate "BQ27000 slave support"
depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 1f31e9f..aa1c8db 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o
obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
+obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
new file mode 100644
index 0000000..e838526
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -0,0 +1,458 @@
+/*
+ * 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 "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+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");
+
+/* 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 w1_f1C_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);
+ struct w1_f1C_data *data = sl->family_data;
+ int i, min_page, max_page;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 w1_f1C_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, idx;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 ssize_t w1_f1C_read_pio(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 w1_f1C_write_pio(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))
+ 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 ssize_t w1_f1C_show_crccheck(struct device *dev, struct
device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", w1_enable_crccheck);
+}
+
+static ssize_t w1_f1C_store_crccheck(struct device *dev, struct
device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char val;
+
+ if(count != 1 || !buf) return -EINVAL;
+
+ val = *buf;
+
+ /* 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);
+}
+
+#define NB_SYSFS_BIN_FILES 2
+static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
+ {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = W1_EEPROM_SIZE,
+ .read = w1_f1C_read_bin,
+ .write = w1_f1C_write_bin,
+ },
+ {
+ .attr = {
+ .name = "pio",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = 1,
+ .read = w1_f1C_read_pio,
+ .write = w1_f1C_write_pio,
+ }
+};
+
+static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO, w1_f1C_show_crccheck,
w1_f1C_store_crccheck);
+
+static int w1_f1C_add_slave(struct w1_slave *sl)
+{
+ int err = 0;
+ int i;
+ 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;
+ }
+
+ /* create binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+ err = sysfs_create_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+
+ if(err)
+ goto out;
+
+ /* create device attributes */
+ err = device_create_file(&sl->dev, &dev_attr_crccheck);
+
+ if(err) {
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+ }
+
+out:
+ if(err) {
+ if(w1_enable_crccheck)
+ kfree(data);
+ }
+
+ return err;
+}
+
+static void w1_f1C_remove_slave(struct w1_slave *sl)
+{
+ int i;
+
+ if(w1_enable_crccheck) {
+ kfree(sl->family_data);
+ sl->family_data = NULL;
+ }
+
+ /* remove device attributes */
+ device_remove_file(&sl->dev, &dev_attr_crccheck);
+
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+}
+
+static struct w1_family_ops w1_f1C_fops = {
+ .add_slave = w1_f1C_add_slave,
+ .remove_slave = w1_f1C_remove_slave,
+};
+
+static struct w1_family w1_family_1C = {
+ .fid = W1_FAMILY_DS28E04,
+ .fops = &w1_f1C_fops,
+};
+
+static int __init w1_f1C_init(void)
+{
+ return w1_register_family(&w1_family_1C);
+}
+
+static void __exit w1_f1C_fini(void)
+{
+ w1_unregister_family(&w1_family_1C);
+}
+
+module_init(w1_f1C_init);
+module_exit(w1_f1C_fini);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 490cda2..aa79c28 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -30,6 +30,7 @@
#define W1_FAMILY_SMEM_01 0x01
#define W1_FAMILY_SMEM_81 0x81
#define W1_THERM_DS18S20 0x10
+#define W1_FAMILY_DS28E04 0x1C
#define W1_COUNTER_DS2423 0x1D
#define W1_THERM_DS1822 0x22
#define W1_EEPROM_DS2433 0x23
--
1.7.4.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100
@ 2012-03-15 22:05 Markus Franke
2012-03-15 23:18 ` Greg KH
0 siblings, 1 reply; 14+ messages in thread
From: Markus Franke @ 2012-03-15 22:05 UTC (permalink / raw)
To: linux-kernel; +Cc: gregkh
This patch adds a 1-wire slave device driver for the DS28E04-100.
It applies to the current linux kernel git tree.
Signed-off-by: Markus Franke <franm@hrz.tu-chemnitz.de>
---
drivers/w1/slaves/Kconfig | 7 +
drivers/w1/slaves/Makefile | 1 +
drivers/w1/slaves/w1_ds28e04.c | 458
++++++++++++++++++++++++++++++++++++++++
drivers/w1/w1_family.h | 1 +
4 files changed, 467 insertions(+), 0 deletions(-)
create mode 100644 drivers/w1/slaves/w1_ds28e04.c
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index d0cb01b..609b175 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -81,6 +81,13 @@ config W1_SLAVE_DS2780
If you are unsure, say N.
+config W1_SLAVE_DS28E04
+ tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
+ depends on W1
+ help
+ Say Y here if you want to use a 1-wire
+ 4kb EEPROM with PIO family device (DS28E04).
+
config W1_SLAVE_BQ27000
tristate "BQ27000 slave support"
depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 1f31e9f..aa1c8db 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o
obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
+obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
new file mode 100644
index 0000000..e838526
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -0,0 +1,458 @@
+/*
+ * 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 "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+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");
+
+/* 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 w1_f1C_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);
+ struct w1_f1C_data *data = sl->family_data;
+ int i, min_page, max_page;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 w1_f1C_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, idx;
+
+ if ((count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE)) == 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 ssize_t w1_f1C_read_pio(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 w1_f1C_write_pio(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))
+ 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 ssize_t w1_f1C_show_crccheck(struct device *dev, struct
device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", w1_enable_crccheck);
+}
+
+static ssize_t w1_f1C_store_crccheck(struct device *dev, struct
device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char val;
+
+ if(count != 1 || !buf) return -EINVAL;
+
+ val = *buf;
+
+ /* 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);
+}
+
+#define NB_SYSFS_BIN_FILES 2
+static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
+ {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = W1_EEPROM_SIZE,
+ .read = w1_f1C_read_bin,
+ .write = w1_f1C_write_bin,
+ },
+ {
+ .attr = {
+ .name = "pio",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = 1,
+ .read = w1_f1C_read_pio,
+ .write = w1_f1C_write_pio,
+ }
+};
+
+static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO, w1_f1C_show_crccheck,
w1_f1C_store_crccheck);
+
+static int w1_f1C_add_slave(struct w1_slave *sl)
+{
+ int err = 0;
+ int i;
+ 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;
+ }
+
+ /* create binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+ err = sysfs_create_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+
+ if(err)
+ goto out;
+
+ /* create device attributes */
+ err = device_create_file(&sl->dev, &dev_attr_crccheck);
+
+ if(err) {
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+ }
+
+out:
+ if(err) {
+ if(w1_enable_crccheck)
+ kfree(data);
+ }
+
+ return err;
+}
+
+static void w1_f1C_remove_slave(struct w1_slave *sl)
+{
+ int i;
+
+ if(w1_enable_crccheck) {
+ kfree(sl->family_data);
+ sl->family_data = NULL;
+ }
+
+ /* remove device attributes */
+ device_remove_file(&sl->dev, &dev_attr_crccheck);
+
+ /* remove binary sysfs attributes */
+ for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+ sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+}
+
+static struct w1_family_ops w1_f1C_fops = {
+ .add_slave = w1_f1C_add_slave,
+ .remove_slave = w1_f1C_remove_slave,
+};
+
+static struct w1_family w1_family_1C = {
+ .fid = W1_FAMILY_DS28E04,
+ .fops = &w1_f1C_fops,
+};
+
+static int __init w1_f1C_init(void)
+{
+ return w1_register_family(&w1_family_1C);
+}
+
+static void __exit w1_f1C_fini(void)
+{
+ w1_unregister_family(&w1_family_1C);
+}
+
+module_init(w1_f1C_init);
+module_exit(w1_f1C_fini);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 490cda2..aa79c28 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -30,6 +30,7 @@
#define W1_FAMILY_SMEM_01 0x01
#define W1_FAMILY_SMEM_81 0x81
#define W1_THERM_DS18S20 0x10
+#define W1_FAMILY_DS28E04 0x1C
#define W1_COUNTER_DS2423 0x1D
#define W1_THERM_DS1822 0x22
#define W1_EEPROM_DS2433 0x23
--
1.7.4.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2012-04-11 23:45 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-16 21:24 [PATCH 1/2] w1: Add 1-wire slave device driver for DS28E04-100 Markus Franke
2012-03-18 21:40 ` Evgeniy Polyakov
2012-03-25 20:21 ` Markus Franke
2012-03-26 18:39 ` Greg KH
2012-03-26 21:17 ` Markus Franke
2012-04-09 22:08 ` Greg KH
2012-04-10 5:55 ` Markus Franke
2012-04-10 14:07 ` Greg KH
2012-04-11 22:44 ` Markus Franke
2012-04-11 23:45 ` Greg KH
[not found] <4F86061D.10501@hrz.tu-chemnitz.de>
2012-04-11 22:40 ` Markus Franke
-- strict thread matches above, loose matches on Subject: below --
2012-03-15 22:53 Markus Franke
2012-03-15 22:05 Markus Franke
2012-03-15 23:18 ` Greg KH
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.