xref: /openbmc/linux/drivers/w1/slaves/w1_ds2406.c (revision 50fa2951bd744d2a82aa33074001efac12d4e1cf)
194859308SScott Alfter /*
294859308SScott Alfter  * w1_ds2406.c - w1 family 12 (DS2406) driver
394859308SScott Alfter  * based on w1_ds2413.c by Mariusz Bialonczyk <manio@skyboo.net>
494859308SScott Alfter  *
594859308SScott Alfter  * Copyright (c) 2014 Scott Alfter <scott@alfter.us>
694859308SScott Alfter  *
794859308SScott Alfter  * This source code is licensed under the GNU General Public License,
894859308SScott Alfter  * Version 2. See the file COPYING for more details.
994859308SScott Alfter  */
1094859308SScott Alfter 
1194859308SScott Alfter #include <linux/kernel.h>
1294859308SScott Alfter #include <linux/module.h>
1394859308SScott Alfter #include <linux/moduleparam.h>
1494859308SScott Alfter #include <linux/device.h>
1594859308SScott Alfter #include <linux/types.h>
1694859308SScott Alfter #include <linux/delay.h>
1794859308SScott Alfter #include <linux/slab.h>
1894859308SScott Alfter #include <linux/crc16.h>
1994859308SScott Alfter 
2094859308SScott Alfter #include "../w1.h"
2194859308SScott Alfter #include "../w1_int.h"
2294859308SScott Alfter #include "../w1_family.h"
2394859308SScott Alfter 
2494859308SScott Alfter #define W1_F12_FUNC_READ_STATUS		   0xAA
2594859308SScott Alfter #define W1_F12_FUNC_WRITE_STATUS	   0x55
2694859308SScott Alfter 
2794859308SScott Alfter static ssize_t w1_f12_read_state(
2894859308SScott Alfter 	struct file *filp, struct kobject *kobj,
2994859308SScott Alfter 	struct bin_attribute *bin_attr,
3094859308SScott Alfter 	char *buf, loff_t off, size_t count)
3194859308SScott Alfter {
3294859308SScott Alfter 	u8 w1_buf[6]={W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0};
3394859308SScott Alfter 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
3494859308SScott Alfter 	u16 crc=0;
3594859308SScott Alfter 	int i;
3694859308SScott Alfter 	ssize_t rtnval=1;
3794859308SScott Alfter 
3894859308SScott Alfter 	if (off != 0)
3994859308SScott Alfter 		return 0;
4094859308SScott Alfter 	if (!buf)
4194859308SScott Alfter 		return -EINVAL;
4294859308SScott Alfter 
4394859308SScott Alfter 	mutex_lock(&sl->master->bus_mutex);
4494859308SScott Alfter 
4594859308SScott Alfter 	if (w1_reset_select_slave(sl)) {
4694859308SScott Alfter 		mutex_unlock(&sl->master->bus_mutex);
4794859308SScott Alfter 		return -EIO;
4894859308SScott Alfter 	}
4994859308SScott Alfter 
5094859308SScott Alfter 	w1_write_block(sl->master, w1_buf, 3);
5194859308SScott Alfter 	w1_read_block(sl->master, w1_buf+3, 3);
5294859308SScott Alfter 	for (i=0; i<6; i++)
5394859308SScott Alfter 		crc=crc16_byte(crc, w1_buf[i]);
5494859308SScott Alfter 	if (crc==0xb001) /* good read? */
5594859308SScott Alfter 		*buf=((w1_buf[3]>>5)&3)|0x30;
5694859308SScott Alfter 	else
5794859308SScott Alfter 		rtnval=-EIO;
5894859308SScott Alfter 
5994859308SScott Alfter 	mutex_unlock(&sl->master->bus_mutex);
6094859308SScott Alfter 
6194859308SScott Alfter 	return rtnval;
6294859308SScott Alfter }
6394859308SScott Alfter 
6494859308SScott Alfter static ssize_t w1_f12_write_output(
6594859308SScott Alfter 	struct file *filp, struct kobject *kobj,
6694859308SScott Alfter 	struct bin_attribute *bin_attr,
6794859308SScott Alfter 	char *buf, loff_t off, size_t count)
6894859308SScott Alfter {
6994859308SScott Alfter 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
7094859308SScott Alfter 	u8 w1_buf[6]={W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0};
7194859308SScott Alfter 	u16 crc=0;
7294859308SScott Alfter 	int i;
7394859308SScott Alfter 	ssize_t rtnval=1;
7494859308SScott Alfter 
7594859308SScott Alfter 	if (count != 1 || off != 0)
7694859308SScott Alfter 		return -EFAULT;
7794859308SScott Alfter 
7894859308SScott Alfter 	mutex_lock(&sl->master->bus_mutex);
7994859308SScott Alfter 
8094859308SScott Alfter 	if (w1_reset_select_slave(sl)) {
8194859308SScott Alfter 		mutex_unlock(&sl->master->bus_mutex);
8294859308SScott Alfter 		return -EIO;
8394859308SScott Alfter 	}
8494859308SScott Alfter 
8594859308SScott Alfter 	w1_buf[3] = (((*buf)&3)<<5)|0x1F;
8694859308SScott Alfter 	w1_write_block(sl->master, w1_buf, 4);
8794859308SScott Alfter 	w1_read_block(sl->master, w1_buf+4, 2);
8894859308SScott Alfter 	for (i=0; i<6; i++)
8994859308SScott Alfter 		crc=crc16_byte(crc, w1_buf[i]);
9094859308SScott Alfter 	if (crc==0xb001) /* good read? */
9194859308SScott Alfter 		w1_write_8(sl->master, 0xFF);
9294859308SScott Alfter 	else
9394859308SScott Alfter 		rtnval=-EIO;
9494859308SScott Alfter 
9594859308SScott Alfter 	mutex_unlock(&sl->master->bus_mutex);
9694859308SScott Alfter 	return rtnval;
9794859308SScott Alfter }
9894859308SScott Alfter 
9994859308SScott Alfter #define NB_SYSFS_BIN_FILES 2
10094859308SScott Alfter static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
10194859308SScott Alfter 	{
10294859308SScott Alfter 		.attr = {
10394859308SScott Alfter 			.name = "state",
10494859308SScott Alfter 			.mode = S_IRUGO,
10594859308SScott Alfter 		},
10694859308SScott Alfter 		.size = 1,
10794859308SScott Alfter 		.read = w1_f12_read_state,
10894859308SScott Alfter 	},
10994859308SScott Alfter 	{
11094859308SScott Alfter 		.attr = {
11194859308SScott Alfter 			.name = "output",
11294859308SScott Alfter 			.mode = S_IRUGO | S_IWUSR | S_IWGRP,
11394859308SScott Alfter 		},
11494859308SScott Alfter 		.size = 1,
11594859308SScott Alfter 		.write = w1_f12_write_output,
11694859308SScott Alfter 	}
11794859308SScott Alfter };
11894859308SScott Alfter 
11994859308SScott Alfter static int w1_f12_add_slave(struct w1_slave *sl)
12094859308SScott Alfter {
12194859308SScott Alfter 	int err = 0;
12294859308SScott Alfter 	int i;
12394859308SScott Alfter 
12494859308SScott Alfter 	for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
12594859308SScott Alfter 		err = sysfs_create_bin_file(
12694859308SScott Alfter 			&sl->dev.kobj,
12794859308SScott Alfter 			&(w1_f12_sysfs_bin_files[i]));
12894859308SScott Alfter 	if (err)
12994859308SScott Alfter 		while (--i >= 0)
13094859308SScott Alfter 			sysfs_remove_bin_file(&sl->dev.kobj,
13194859308SScott Alfter 				&(w1_f12_sysfs_bin_files[i]));
13294859308SScott Alfter 	return err;
13394859308SScott Alfter }
13494859308SScott Alfter 
13594859308SScott Alfter static void w1_f12_remove_slave(struct w1_slave *sl)
13694859308SScott Alfter {
13794859308SScott Alfter 	int i;
13894859308SScott Alfter 	for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
13994859308SScott Alfter 		sysfs_remove_bin_file(&sl->dev.kobj,
14094859308SScott Alfter 			&(w1_f12_sysfs_bin_files[i]));
14194859308SScott Alfter }
14294859308SScott Alfter 
14394859308SScott Alfter static struct w1_family_ops w1_f12_fops = {
14494859308SScott Alfter 	.add_slave      = w1_f12_add_slave,
14594859308SScott Alfter 	.remove_slave   = w1_f12_remove_slave,
14694859308SScott Alfter };
14794859308SScott Alfter 
14894859308SScott Alfter static struct w1_family w1_family_12 = {
14994859308SScott Alfter 	.fid = W1_FAMILY_DS2406,
15094859308SScott Alfter 	.fops = &w1_f12_fops,
15194859308SScott Alfter };
152939fc832SAndrew F. Davis module_w1_family(w1_family_12);
153*50fa2951SAndrew F. Davis 
154*50fa2951SAndrew F. Davis MODULE_AUTHOR("Scott Alfter <scott@alfter.us>");
155*50fa2951SAndrew F. Davis MODULE_DESCRIPTION("w1 family 12 driver for DS2406 2 Pin IO");
156*50fa2951SAndrew F. Davis MODULE_LICENSE("GPL");
157