GNU Linux-libre 4.19.264-gnu1
[releases.git] / 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 <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");