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