Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * w1_ds2406.c - w1 family 12 (DS2406) driver
0004  * based on w1_ds2413.c by Mariusz Bialonczyk <manio@skyboo.net>
0005  *
0006  * Copyright (c) 2014 Scott Alfter <scott@alfter.us>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/device.h>
0013 #include <linux/types.h>
0014 #include <linux/delay.h>
0015 #include <linux/slab.h>
0016 #include <linux/crc16.h>
0017 
0018 #include <linux/w1.h>
0019 
0020 #define W1_FAMILY_DS2406    0x12
0021 
0022 #define W1_F12_FUNC_READ_STATUS        0xAA
0023 #define W1_F12_FUNC_WRITE_STATUS       0x55
0024 
0025 static ssize_t w1_f12_read_state(
0026     struct file *filp, struct kobject *kobj,
0027     struct bin_attribute *bin_attr,
0028     char *buf, loff_t off, size_t count)
0029 {
0030     u8 w1_buf[6]={W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0};
0031     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0032     u16 crc=0;
0033     int i;
0034     ssize_t rtnval=1;
0035 
0036     if (off != 0)
0037         return 0;
0038     if (!buf)
0039         return -EINVAL;
0040 
0041     mutex_lock(&sl->master->bus_mutex);
0042 
0043     if (w1_reset_select_slave(sl)) {
0044         mutex_unlock(&sl->master->bus_mutex);
0045         return -EIO;
0046     }
0047 
0048     w1_write_block(sl->master, w1_buf, 3);
0049     w1_read_block(sl->master, w1_buf+3, 3);
0050     for (i=0; i<6; i++)
0051         crc=crc16_byte(crc, w1_buf[i]);
0052     if (crc==0xb001) /* good read? */
0053         *buf=((w1_buf[3]>>5)&3)|0x30;
0054     else
0055         rtnval=-EIO;
0056 
0057     mutex_unlock(&sl->master->bus_mutex);
0058 
0059     return rtnval;
0060 }
0061 
0062 static ssize_t w1_f12_write_output(
0063     struct file *filp, struct kobject *kobj,
0064     struct bin_attribute *bin_attr,
0065     char *buf, loff_t off, size_t count)
0066 {
0067     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0068     u8 w1_buf[6]={W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0};
0069     u16 crc=0;
0070     int i;
0071     ssize_t rtnval=1;
0072 
0073     if (count != 1 || off != 0)
0074         return -EFAULT;
0075 
0076     mutex_lock(&sl->master->bus_mutex);
0077 
0078     if (w1_reset_select_slave(sl)) {
0079         mutex_unlock(&sl->master->bus_mutex);
0080         return -EIO;
0081     }
0082 
0083     w1_buf[3] = (((*buf)&3)<<5)|0x1F;
0084     w1_write_block(sl->master, w1_buf, 4);
0085     w1_read_block(sl->master, w1_buf+4, 2);
0086     for (i=0; i<6; i++)
0087         crc=crc16_byte(crc, w1_buf[i]);
0088     if (crc==0xb001) /* good read? */
0089         w1_write_8(sl->master, 0xFF);
0090     else
0091         rtnval=-EIO;
0092 
0093     mutex_unlock(&sl->master->bus_mutex);
0094     return rtnval;
0095 }
0096 
0097 #define NB_SYSFS_BIN_FILES 2
0098 static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
0099     {
0100         .attr = {
0101             .name = "state",
0102             .mode = S_IRUGO,
0103         },
0104         .size = 1,
0105         .read = w1_f12_read_state,
0106     },
0107     {
0108         .attr = {
0109             .name = "output",
0110             .mode = S_IRUGO | S_IWUSR | S_IWGRP,
0111         },
0112         .size = 1,
0113         .write = w1_f12_write_output,
0114     }
0115 };
0116 
0117 static int w1_f12_add_slave(struct w1_slave *sl)
0118 {
0119     int err = 0;
0120     int i;
0121 
0122     for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
0123         err = sysfs_create_bin_file(
0124             &sl->dev.kobj,
0125             &(w1_f12_sysfs_bin_files[i]));
0126     if (err)
0127         while (--i >= 0)
0128             sysfs_remove_bin_file(&sl->dev.kobj,
0129                 &(w1_f12_sysfs_bin_files[i]));
0130     return err;
0131 }
0132 
0133 static void w1_f12_remove_slave(struct w1_slave *sl)
0134 {
0135     int i;
0136     for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
0137         sysfs_remove_bin_file(&sl->dev.kobj,
0138             &(w1_f12_sysfs_bin_files[i]));
0139 }
0140 
0141 static const struct w1_family_ops w1_f12_fops = {
0142     .add_slave      = w1_f12_add_slave,
0143     .remove_slave   = w1_f12_remove_slave,
0144 };
0145 
0146 static struct w1_family w1_family_12 = {
0147     .fid = W1_FAMILY_DS2406,
0148     .fops = &w1_f12_fops,
0149 };
0150 module_w1_family(w1_family_12);
0151 
0152 MODULE_AUTHOR("Scott Alfter <scott@alfter.us>");
0153 MODULE_DESCRIPTION("w1 family 12 driver for DS2406 2 Pin IO");
0154 MODULE_LICENSE("GPL");