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