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