Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

w1: new w1_ds2406 driver

Some preliminary work at making use of this driver led me to implement
CRC-16 checks on read and write to deal with the occasional glitchiness of
the 1-Wire bus. The revised driver (attached) returns an I/O error if the
CRC check fails. When reading the chip's state, either you get a valid
indication or you get an I/O error. When changing its state, either the
change is successful or an I/O error is returned.

Signed-off-by: Scott Alfter <scott@alfter.us>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Scott Alfter and committed by
Greg Kroah-Hartman
94859308 7242d42a

+202
+25
Documentation/w1/slaves/w1_ds2406
··· 1 + w1_ds2406 kernel driver 2 + ======================= 3 + 4 + Supported chips: 5 + * Maxim DS2406 (and other family 0x12) addressable switches 6 + 7 + Author: Scott Alfter <scott@alfter.us> 8 + 9 + Description 10 + ----------- 11 + 12 + The w1_ds2406 driver allows connected devices to be switched on and off. 13 + These chips also provide 128 bytes of OTP EPROM, but reading/writing it is 14 + not supported. In TSOC-6 form, the DS2406 provides two switch outputs and 15 + can be provided with power on a dedicated input. In TO-92 form, it provides 16 + one output and uses parasitic power only. 17 + 18 + The driver provides two sysfs files. state is readable; it gives the 19 + current state of each switch, with PIO A in bit 0 and PIO B in bit 1. The 20 + driver ORs this state with 0x30, so shell scripts get an ASCII 0/1/2/3 to 21 + work with. output is writable; bits 0 and 1 control PIO A and B, 22 + respectively. Bits 2-7 are ignored, so it's safe to write ASCII data. 23 + 24 + CRCs are checked on read and write. Failed checks cause an I/O error to be 25 + returned. On a failed write, the switch status is not changed.
+7
drivers/w1/slaves/Kconfig
··· 38 38 Say Y here if you want to use a 1-wire 39 39 DS2413 Dual Channel Addressable Switch device support 40 40 41 + config W1_SLAVE_DS2406 42 + tristate "Dual Channel Addressable Switch 0x12 family support (DS2406)" 43 + help 44 + Say Y or M here if you want to use a 1-wire 45 + DS2406 Dual Channel Addressable Switch. EPROM read/write 46 + support for these devices is not implemented. 47 + 41 48 config W1_SLAVE_DS2423 42 49 tristate "Counter 1-wire device (DS2423)" 43 50 select CRC16
+1
drivers/w1/slaves/Makefile
··· 6 6 obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o 7 7 obj-$(CONFIG_W1_SLAVE_DS2408) += w1_ds2408.o 8 8 obj-$(CONFIG_W1_SLAVE_DS2413) += w1_ds2413.o 9 + obj-$(CONFIG_W1_SLAVE_DS2406) += w1_ds2406.o 9 10 obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o 10 11 obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o 11 12 obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
+168
drivers/w1/slaves/w1_ds2406.c
··· 1 + /* 2 + * w1_ds2406.c - w1 family 12 (DS2406) driver 3 + * based on w1_ds2413.c by Mariusz Bialonczyk <manio@skyboo.net> 4 + * 5 + * Copyright (c) 2014 Scott Alfter <scott@alfter.us> 6 + * 7 + * This source code is licensed under the GNU General Public License, 8 + * Version 2. See the file COPYING for more details. 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/moduleparam.h> 14 + #include <linux/device.h> 15 + #include <linux/types.h> 16 + #include <linux/delay.h> 17 + #include <linux/slab.h> 18 + #include <linux/crc16.h> 19 + 20 + #include "../w1.h" 21 + #include "../w1_int.h" 22 + #include "../w1_family.h" 23 + 24 + MODULE_LICENSE("GPL"); 25 + MODULE_AUTHOR("Scott Alfter <scott@alfter.us>"); 26 + MODULE_DESCRIPTION("w1 family 12 driver for DS2406 2 Pin IO"); 27 + 28 + #define W1_F12_FUNC_READ_STATUS 0xAA 29 + #define W1_F12_FUNC_WRITE_STATUS 0x55 30 + 31 + static ssize_t w1_f12_read_state( 32 + struct file *filp, struct kobject *kobj, 33 + struct bin_attribute *bin_attr, 34 + char *buf, loff_t off, size_t count) 35 + { 36 + u8 w1_buf[6]={W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0}; 37 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 38 + u16 crc=0; 39 + int i; 40 + ssize_t rtnval=1; 41 + 42 + if (off != 0) 43 + return 0; 44 + if (!buf) 45 + return -EINVAL; 46 + 47 + mutex_lock(&sl->master->bus_mutex); 48 + 49 + if (w1_reset_select_slave(sl)) { 50 + mutex_unlock(&sl->master->bus_mutex); 51 + return -EIO; 52 + } 53 + 54 + w1_write_block(sl->master, w1_buf, 3); 55 + w1_read_block(sl->master, w1_buf+3, 3); 56 + for (i=0; i<6; i++) 57 + crc=crc16_byte(crc, w1_buf[i]); 58 + if (crc==0xb001) /* good read? */ 59 + *buf=((w1_buf[3]>>5)&3)|0x30; 60 + else 61 + rtnval=-EIO; 62 + 63 + mutex_unlock(&sl->master->bus_mutex); 64 + 65 + return rtnval; 66 + } 67 + 68 + static ssize_t w1_f12_write_output( 69 + struct file *filp, struct kobject *kobj, 70 + struct bin_attribute *bin_attr, 71 + char *buf, loff_t off, size_t count) 72 + { 73 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 74 + u8 w1_buf[6]={W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0}; 75 + u16 crc=0; 76 + int i; 77 + ssize_t rtnval=1; 78 + 79 + if (count != 1 || off != 0) 80 + return -EFAULT; 81 + 82 + mutex_lock(&sl->master->bus_mutex); 83 + 84 + if (w1_reset_select_slave(sl)) { 85 + mutex_unlock(&sl->master->bus_mutex); 86 + return -EIO; 87 + } 88 + 89 + w1_buf[3] = (((*buf)&3)<<5)|0x1F; 90 + w1_write_block(sl->master, w1_buf, 4); 91 + w1_read_block(sl->master, w1_buf+4, 2); 92 + for (i=0; i<6; i++) 93 + crc=crc16_byte(crc, w1_buf[i]); 94 + if (crc==0xb001) /* good read? */ 95 + w1_write_8(sl->master, 0xFF); 96 + else 97 + rtnval=-EIO; 98 + 99 + mutex_unlock(&sl->master->bus_mutex); 100 + return rtnval; 101 + } 102 + 103 + #define NB_SYSFS_BIN_FILES 2 104 + static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { 105 + { 106 + .attr = { 107 + .name = "state", 108 + .mode = S_IRUGO, 109 + }, 110 + .size = 1, 111 + .read = w1_f12_read_state, 112 + }, 113 + { 114 + .attr = { 115 + .name = "output", 116 + .mode = S_IRUGO | S_IWUSR | S_IWGRP, 117 + }, 118 + .size = 1, 119 + .write = w1_f12_write_output, 120 + } 121 + }; 122 + 123 + static int w1_f12_add_slave(struct w1_slave *sl) 124 + { 125 + int err = 0; 126 + int i; 127 + 128 + for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i) 129 + err = sysfs_create_bin_file( 130 + &sl->dev.kobj, 131 + &(w1_f12_sysfs_bin_files[i])); 132 + if (err) 133 + while (--i >= 0) 134 + sysfs_remove_bin_file(&sl->dev.kobj, 135 + &(w1_f12_sysfs_bin_files[i])); 136 + return err; 137 + } 138 + 139 + static void w1_f12_remove_slave(struct w1_slave *sl) 140 + { 141 + int i; 142 + for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i) 143 + sysfs_remove_bin_file(&sl->dev.kobj, 144 + &(w1_f12_sysfs_bin_files[i])); 145 + } 146 + 147 + static struct w1_family_ops w1_f12_fops = { 148 + .add_slave = w1_f12_add_slave, 149 + .remove_slave = w1_f12_remove_slave, 150 + }; 151 + 152 + static struct w1_family w1_family_12 = { 153 + .fid = W1_FAMILY_DS2406, 154 + .fops = &w1_f12_fops, 155 + }; 156 + 157 + static int __init w1_f12_init(void) 158 + { 159 + return w1_register_family(&w1_family_12); 160 + } 161 + 162 + static void __exit w1_f12_exit(void) 163 + { 164 + w1_unregister_family(&w1_family_12); 165 + } 166 + 167 + module_init(w1_f12_init); 168 + module_exit(w1_f12_exit);
+1
drivers/w1/w1_family.h
··· 40 40 #define W1_FAMILY_DS2760 0x30 41 41 #define W1_FAMILY_DS2780 0x32 42 42 #define W1_FAMILY_DS2413 0x3A 43 + #define W1_FAMILY_DS2406 0x12 43 44 #define W1_THERM_DS1825 0x3B 44 45 #define W1_FAMILY_DS2781 0x3D 45 46 #define W1_THERM_DS28EA00 0x42