xref: /openbmc/linux/drivers/w1/slaves/w1_ds2423.c (revision 57de2dfc)
153c8ab35SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
217fecb55SMika Laitio /*
317fecb55SMika Laitio  *	w1_ds2423.c
417fecb55SMika Laitio  *
517fecb55SMika Laitio  * Copyright (c) 2010 Mika Laitio <lamikr@pilppa.org>
617fecb55SMika Laitio  *
717fecb55SMika Laitio  * This driver will read and write the value of 4 counters to w1_slave file in
817fecb55SMika Laitio  * sys filesystem.
917fecb55SMika Laitio  * Inspired by the w1_therm and w1_ds2431 drivers.
1017fecb55SMika Laitio  */
1117fecb55SMika Laitio 
1217fecb55SMika Laitio #include <linux/kernel.h>
1317fecb55SMika Laitio #include <linux/module.h>
1417fecb55SMika Laitio #include <linux/moduleparam.h>
1517fecb55SMika Laitio #include <linux/device.h>
1617fecb55SMika Laitio #include <linux/types.h>
1717fecb55SMika Laitio #include <linux/delay.h>
1817fecb55SMika Laitio #include <linux/crc16.h>
1917fecb55SMika Laitio 
20de0d6dbdSAndrew F. Davis #include <linux/w1.h>
21de0d6dbdSAndrew F. Davis 
22de0d6dbdSAndrew F. Davis #define W1_COUNTER_DS2423	0x1D
2317fecb55SMika Laitio 
2417fecb55SMika Laitio #define CRC16_VALID	0xb001
2517fecb55SMika Laitio #define CRC16_INIT	0
2617fecb55SMika Laitio 
2717fecb55SMika Laitio #define COUNTER_COUNT 4
2817fecb55SMika Laitio #define READ_BYTE_COUNT 42
2917fecb55SMika Laitio 
w1_slave_show(struct device * device,struct device_attribute * attr,char * out_buf)3094c9e6d6SGreg Kroah-Hartman static ssize_t w1_slave_show(struct device *device,
3117fecb55SMika Laitio 			     struct device_attribute *attr, char *out_buf)
3217fecb55SMika Laitio {
3317fecb55SMika Laitio 	struct w1_slave *sl = dev_to_w1_slave(device);
3417fecb55SMika Laitio 	struct w1_master *dev = sl->master;
3517fecb55SMika Laitio 	u8 rbuf[COUNTER_COUNT * READ_BYTE_COUNT];
3617fecb55SMika Laitio 	u8 wrbuf[3];
3717fecb55SMika Laitio 	int rom_addr;
3817fecb55SMika Laitio 	int read_byte_count;
3917fecb55SMika Laitio 	int result;
4017fecb55SMika Laitio 	ssize_t c;
4117fecb55SMika Laitio 	int ii;
4217fecb55SMika Laitio 	int p;
4317fecb55SMika Laitio 	int crc;
4417fecb55SMika Laitio 
4517fecb55SMika Laitio 	c		= PAGE_SIZE;
4617fecb55SMika Laitio 	rom_addr	= (12 << 5) + 31;
4717fecb55SMika Laitio 	wrbuf[0]	= 0xA5;
4817fecb55SMika Laitio 	wrbuf[1]	= rom_addr & 0xFF;
4917fecb55SMika Laitio 	wrbuf[2]	= rom_addr >> 8;
50b02f8bedSNeilBrown 	mutex_lock(&dev->bus_mutex);
5117fecb55SMika Laitio 	if (!w1_reset_select_slave(sl)) {
5217fecb55SMika Laitio 		w1_write_block(dev, wrbuf, 3);
5317fecb55SMika Laitio 		read_byte_count = 0;
5417fecb55SMika Laitio 		for (p = 0; p < 4; p++) {
5517fecb55SMika Laitio 			/*
5617fecb55SMika Laitio 			 * 1 byte for first bytes in ram page read
5717fecb55SMika Laitio 			 * 4 bytes for counter
5817fecb55SMika Laitio 			 * 4 bytes for zero bits
5917fecb55SMika Laitio 			 * 2 bytes for crc
6017fecb55SMika Laitio 			 * 31 remaining bytes from the ram page
6117fecb55SMika Laitio 			 */
6217fecb55SMika Laitio 			read_byte_count += w1_read_block(dev,
6317fecb55SMika Laitio 				rbuf + (p * READ_BYTE_COUNT), READ_BYTE_COUNT);
6417fecb55SMika Laitio 			for (ii = 0; ii < READ_BYTE_COUNT; ++ii)
6517fecb55SMika Laitio 				c -= snprintf(out_buf + PAGE_SIZE - c,
6617fecb55SMika Laitio 					c, "%02x ",
6717fecb55SMika Laitio 					rbuf[(p * READ_BYTE_COUNT) + ii]);
6817fecb55SMika Laitio 			if (read_byte_count != (p + 1) * READ_BYTE_COUNT) {
6917fecb55SMika Laitio 				dev_warn(device,
7017fecb55SMika Laitio 					"w1_counter_read() returned %u bytes "
7117fecb55SMika Laitio 					"instead of %d bytes wanted.\n",
7217fecb55SMika Laitio 					read_byte_count,
7317fecb55SMika Laitio 					READ_BYTE_COUNT);
7417fecb55SMika Laitio 				c -= snprintf(out_buf + PAGE_SIZE - c,
7517fecb55SMika Laitio 					c, "crc=NO\n");
7617fecb55SMika Laitio 			} else {
7717fecb55SMika Laitio 				if (p == 0) {
7817fecb55SMika Laitio 					crc = crc16(CRC16_INIT, wrbuf, 3);
7917fecb55SMika Laitio 					crc = crc16(crc, rbuf, 11);
8017fecb55SMika Laitio 				} else {
8117fecb55SMika Laitio 					/*
8217fecb55SMika Laitio 					 * DS2423 calculates crc from all bytes
8317fecb55SMika Laitio 					 * read after the previous crc bytes.
8417fecb55SMika Laitio 					 */
8517fecb55SMika Laitio 					crc = crc16(CRC16_INIT,
8617fecb55SMika Laitio 						(rbuf + 11) +
8717fecb55SMika Laitio 						((p - 1) * READ_BYTE_COUNT),
8817fecb55SMika Laitio 						READ_BYTE_COUNT);
8917fecb55SMika Laitio 				}
9017fecb55SMika Laitio 				if (crc == CRC16_VALID) {
9117fecb55SMika Laitio 					result = 0;
9217fecb55SMika Laitio 					for (ii = 4; ii > 0; ii--) {
9317fecb55SMika Laitio 						result <<= 8;
9417fecb55SMika Laitio 						result |= rbuf[(p *
9517fecb55SMika Laitio 							READ_BYTE_COUNT) + ii];
9617fecb55SMika Laitio 					}
9717fecb55SMika Laitio 					c -= snprintf(out_buf + PAGE_SIZE - c,
9817fecb55SMika Laitio 						c, "crc=YES c=%d\n", result);
9917fecb55SMika Laitio 				} else {
10017fecb55SMika Laitio 					c -= snprintf(out_buf + PAGE_SIZE - c,
10117fecb55SMika Laitio 						c, "crc=NO\n");
10217fecb55SMika Laitio 				}
10317fecb55SMika Laitio 			}
10417fecb55SMika Laitio 		}
10517fecb55SMika Laitio 	} else {
10617fecb55SMika Laitio 		c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error");
10717fecb55SMika Laitio 	}
108b02f8bedSNeilBrown 	mutex_unlock(&dev->bus_mutex);
10917fecb55SMika Laitio 	return PAGE_SIZE - c;
11017fecb55SMika Laitio }
11117fecb55SMika Laitio 
11294c9e6d6SGreg Kroah-Hartman static DEVICE_ATTR_RO(w1_slave);
11317fecb55SMika Laitio 
11494c9e6d6SGreg Kroah-Hartman static struct attribute *w1_f1d_attrs[] = {
11594c9e6d6SGreg Kroah-Hartman 	&dev_attr_w1_slave.attr,
11694c9e6d6SGreg Kroah-Hartman 	NULL,
11794c9e6d6SGreg Kroah-Hartman };
11894c9e6d6SGreg Kroah-Hartman ATTRIBUTE_GROUPS(w1_f1d);
11917fecb55SMika Laitio 
12057de2dfcSRikard Falkeborn static const struct w1_family_ops w1_f1d_fops = {
12194c9e6d6SGreg Kroah-Hartman 	.groups		= w1_f1d_groups,
12217fecb55SMika Laitio };
12317fecb55SMika Laitio 
12417fecb55SMika Laitio static struct w1_family w1_family_1d = {
12517fecb55SMika Laitio 	.fid = W1_COUNTER_DS2423,
12617fecb55SMika Laitio 	.fops = &w1_f1d_fops,
12717fecb55SMika Laitio };
128939fc832SAndrew F. Davis module_w1_family(w1_family_1d);
12917fecb55SMika Laitio 
13017fecb55SMika Laitio MODULE_AUTHOR("Mika Laitio <lamikr@pilppa.org>");
13117fecb55SMika Laitio MODULE_DESCRIPTION("w1 family 1d driver for DS2423, 4 counters and 4kb ram");
13250fa2951SAndrew F. Davis MODULE_LICENSE("GPL");
1338d7bda51SAlexander Stein MODULE_ALIAS("w1-family-" __stringify(W1_COUNTER_DS2423));
134