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