diff options
Diffstat (limited to 'drivers/w1/slaves/w1_ds2413.c')
| -rw-r--r-- | drivers/w1/slaves/w1_ds2413.c | 175 |
1 files changed, 79 insertions, 96 deletions
diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c index 85937773a96a..94d3cd2a0ec9 100644 --- a/drivers/w1/slaves/w1_ds2413.c +++ b/drivers/w1/slaves/w1_ds2413.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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> @@ -16,26 +14,25 @@ #include <linux/delay.h> #include <linux/slab.h> -#include "../w1.h" -#include "../w1_int.h" -#include "../w1_family.h" +#include <linux/w1.h> -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>"); -MODULE_DESCRIPTION("w1 family 3a driver for DS2413 2 Pin IO"); -MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2413)); +#define W1_FAMILY_DS2413 0x3A #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 +#define W1_F3A_INVALID_PIO_STATE 0xFF -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) +static ssize_t state_read(struct file *filp, struct kobject *kobj, + const struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); + unsigned int retries = W1_F3A_RETRIES; + ssize_t bytes_read = -EIO; + u8 state; + 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); @@ -48,32 +45,49 @@ static ssize_t w1_f3a_read_state( 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; - } +next: + if (w1_reset_select_slave(sl)) + goto out; - w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ); - *buf = w1_read_8(sl->master); + while (retries--) { + w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ); + + state = w1_read_8(sl->master); + if ((state & 0x0F) == ((~state >> 4) & 0x0F)) { + /* complement is correct */ + *buf = state; + bytes_read = 1; + goto out; + } else if (state == W1_F3A_INVALID_PIO_STATE) { + /* slave didn't respond, try to select it again */ + dev_warn(&sl->dev, "slave device did not respond to PIO_ACCESS_READ, " \ + "reselecting, retries left: %d\n", retries); + goto next; + } - mutex_unlock(&sl->master->bus_mutex); - dev_dbg(&sl->dev, "mutex unlocked"); + if (w1_reset_resume_command(sl->master)) + goto out; /* unrecoverable error */ - /* check for correct complement */ - if ((*buf & 0x0F) != ((~*buf >> 4) & 0x0F)) - return -EIO; - else - return 1; + dev_warn(&sl->dev, "PIO_ACCESS_READ error, retries left: %d\n", retries); + } + +out: + mutex_unlock(&sl->master->bus_mutex); + dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n", + (bytes_read > 0) ? "succeeded" : "error", retries); + return bytes_read; } -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) +static const BIN_ATTR_RO(state, 1); + +static ssize_t output_write(struct file *filp, struct kobject *kobj, + const 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; + ssize_t bytes_written = -EIO; if (count != 1 || off != 0) return -EFAULT; @@ -83,10 +97,12 @@ static ssize_t w1_f3a_write_output( dev_dbg(&sl->dev, "mutex locked"); if (w1_reset_select_slave(sl)) - goto error; + goto out; - /* according to the DS2413 datasheet the most significant 6 bits - should be set to "1"s, so do it now */ + /* + * 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--) { @@ -96,83 +112,50 @@ static ssize_t w1_f3a_write_output( 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; + bytes_written = 1; + goto out; } if (w1_reset_resume_command(sl->master)) - goto error; + goto out; /* unrecoverable error */ + + dev_warn(&sl->dev, "PIO_ACCESS_WRITE error, retries left: %d\n", retries); } -error: +out: mutex_unlock(&sl->master->bus_mutex); - dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries); - return -EIO; + dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n", + (bytes_written > 0) ? "succeeded" : "error", retries); + return bytes_written; } -#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 const BIN_ATTR(output, 0664, NULL, output_write, 1); + +static const struct bin_attribute *const w1_f3a_bin_attrs[] = { + &bin_attr_state, + &bin_attr_output, + NULL, }; -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 const struct attribute_group w1_f3a_group = { + .bin_attrs = w1_f3a_bin_attrs, +}; -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 const struct attribute_group *w1_f3a_groups[] = { + &w1_f3a_group, + NULL, +}; -static struct w1_family_ops w1_f3a_fops = { - .add_slave = w1_f3a_add_slave, - .remove_slave = w1_f3a_remove_slave, +static const struct w1_family_ops w1_f3a_fops = { + .groups = w1_f3a_groups, }; static struct w1_family w1_family_3a = { .fid = W1_FAMILY_DS2413, .fops = &w1_f3a_fops, }; +module_w1_family(w1_family_3a); -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); +MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>"); +MODULE_DESCRIPTION("w1 family 3a driver for DS2413 2 Pin IO"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2413)); |
