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 <linux/w1.h> 21 22 #define W1_FAMILY_DS2406 0x12 23 24 #define W1_F12_FUNC_READ_STATUS 0xAA 25 #define W1_F12_FUNC_WRITE_STATUS 0x55 26 27 static ssize_t w1_f12_read_state( 28 struct file *filp, struct kobject *kobj, 29 struct bin_attribute *bin_attr, 30 char *buf, loff_t off, size_t count) 31 { 32 u8 w1_buf[6]={W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0}; 33 struct w1_slave *sl = kobj_to_w1_slave(kobj); 34 u16 crc=0; 35 int i; 36 ssize_t rtnval=1; 37 38 if (off != 0) 39 return 0; 40 if (!buf) 41 return -EINVAL; 42 43 mutex_lock(&sl->master->bus_mutex); 44 45 if (w1_reset_select_slave(sl)) { 46 mutex_unlock(&sl->master->bus_mutex); 47 return -EIO; 48 } 49 50 w1_write_block(sl->master, w1_buf, 3); 51 w1_read_block(sl->master, w1_buf+3, 3); 52 for (i=0; i<6; i++) 53 crc=crc16_byte(crc, w1_buf[i]); 54 if (crc==0xb001) /* good read? */ 55 *buf=((w1_buf[3]>>5)&3)|0x30; 56 else 57 rtnval=-EIO; 58 59 mutex_unlock(&sl->master->bus_mutex); 60 61 return rtnval; 62 } 63 64 static ssize_t w1_f12_write_output( 65 struct file *filp, struct kobject *kobj, 66 struct bin_attribute *bin_attr, 67 char *buf, loff_t off, size_t count) 68 { 69 struct w1_slave *sl = kobj_to_w1_slave(kobj); 70 u8 w1_buf[6]={W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0}; 71 u16 crc=0; 72 int i; 73 ssize_t rtnval=1; 74 75 if (count != 1 || off != 0) 76 return -EFAULT; 77 78 mutex_lock(&sl->master->bus_mutex); 79 80 if (w1_reset_select_slave(sl)) { 81 mutex_unlock(&sl->master->bus_mutex); 82 return -EIO; 83 } 84 85 w1_buf[3] = (((*buf)&3)<<5)|0x1F; 86 w1_write_block(sl->master, w1_buf, 4); 87 w1_read_block(sl->master, w1_buf+4, 2); 88 for (i=0; i<6; i++) 89 crc=crc16_byte(crc, w1_buf[i]); 90 if (crc==0xb001) /* good read? */ 91 w1_write_8(sl->master, 0xFF); 92 else 93 rtnval=-EIO; 94 95 mutex_unlock(&sl->master->bus_mutex); 96 return rtnval; 97 } 98 99 #define NB_SYSFS_BIN_FILES 2 100 static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { 101 { 102 .attr = { 103 .name = "state", 104 .mode = S_IRUGO, 105 }, 106 .size = 1, 107 .read = w1_f12_read_state, 108 }, 109 { 110 .attr = { 111 .name = "output", 112 .mode = S_IRUGO | S_IWUSR | S_IWGRP, 113 }, 114 .size = 1, 115 .write = w1_f12_write_output, 116 } 117 }; 118 119 static int w1_f12_add_slave(struct w1_slave *sl) 120 { 121 int err = 0; 122 int i; 123 124 for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i) 125 err = sysfs_create_bin_file( 126 &sl->dev.kobj, 127 &(w1_f12_sysfs_bin_files[i])); 128 if (err) 129 while (--i >= 0) 130 sysfs_remove_bin_file(&sl->dev.kobj, 131 &(w1_f12_sysfs_bin_files[i])); 132 return err; 133 } 134 135 static void w1_f12_remove_slave(struct w1_slave *sl) 136 { 137 int i; 138 for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i) 139 sysfs_remove_bin_file(&sl->dev.kobj, 140 &(w1_f12_sysfs_bin_files[i])); 141 } 142 143 static struct w1_family_ops w1_f12_fops = { 144 .add_slave = w1_f12_add_slave, 145 .remove_slave = w1_f12_remove_slave, 146 }; 147 148 static struct w1_family w1_family_12 = { 149 .fid = W1_FAMILY_DS2406, 150 .fops = &w1_f12_fops, 151 }; 152 module_w1_family(w1_family_12); 153 154 MODULE_AUTHOR("Scott Alfter <scott@alfter.us>"); 155 MODULE_DESCRIPTION("w1 family 12 driver for DS2406 2 Pin IO"); 156 MODULE_LICENSE("GPL"); 157