]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/w1/slaves/w1_ds2406.c
Merge tag 'nfs-for-4.13-5' of git://git.linux-nfs.org/projects/anna/linux-nfs
[mirror_ubuntu-bionic-kernel.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");