brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · b6bd18d Raw
134 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *	w1_ds2423.c4 *5 * Copyright (c) 2010 Mika Laitio <lamikr@pilppa.org>6 *7 * This driver will read and write the value of 4 counters to w1_slave file in8 * sys filesystem.9 * Inspired by the w1_therm and w1_ds2431 drivers.10 */11 12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/moduleparam.h>15#include <linux/device.h>16#include <linux/types.h>17#include <linux/delay.h>18#include <linux/crc16.h>19 20#include <linux/w1.h>21 22#define W1_COUNTER_DS2423	0x1D23 24#define CRC16_VALID	0xb00125#define CRC16_INIT	026 27#define COUNTER_COUNT 428#define READ_BYTE_COUNT 4229 30static ssize_t w1_slave_show(struct device *device,31			     struct device_attribute *attr, char *out_buf)32{33	struct w1_slave *sl = dev_to_w1_slave(device);34	struct w1_master *dev = sl->master;35	u8 rbuf[COUNTER_COUNT * READ_BYTE_COUNT];36	u8 wrbuf[3];37	int rom_addr;38	int read_byte_count;39	int result;40	ssize_t c;41	int ii;42	int p;43	int crc;44 45	c		= PAGE_SIZE;46	rom_addr	= (12 << 5) + 31;47	wrbuf[0]	= 0xA5;48	wrbuf[1]	= rom_addr & 0xFF;49	wrbuf[2]	= rom_addr >> 8;50	mutex_lock(&dev->bus_mutex);51	if (!w1_reset_select_slave(sl)) {52		w1_write_block(dev, wrbuf, 3);53		read_byte_count = 0;54		for (p = 0; p < 4; p++) {55			/*56			 * 1 byte for first bytes in ram page read57			 * 4 bytes for counter58			 * 4 bytes for zero bits59			 * 2 bytes for crc60			 * 31 remaining bytes from the ram page61			 */62			read_byte_count += w1_read_block(dev,63				rbuf + (p * READ_BYTE_COUNT), READ_BYTE_COUNT);64			for (ii = 0; ii < READ_BYTE_COUNT; ++ii)65				c -= snprintf(out_buf + PAGE_SIZE - c,66					c, "%02x ",67					rbuf[(p * READ_BYTE_COUNT) + ii]);68			if (read_byte_count != (p + 1) * READ_BYTE_COUNT) {69				dev_warn(device,70					"w1_counter_read() returned %u bytes "71					"instead of %d bytes wanted.\n",72					read_byte_count,73					READ_BYTE_COUNT);74				c -= snprintf(out_buf + PAGE_SIZE - c,75					c, "crc=NO\n");76			} else {77				if (p == 0) {78					crc = crc16(CRC16_INIT, wrbuf, 3);79					crc = crc16(crc, rbuf, 11);80				} else {81					/*82					 * DS2423 calculates crc from all bytes83					 * read after the previous crc bytes.84					 */85					crc = crc16(CRC16_INIT,86						(rbuf + 11) +87						((p - 1) * READ_BYTE_COUNT),88						READ_BYTE_COUNT);89				}90				if (crc == CRC16_VALID) {91					result = 0;92					for (ii = 4; ii > 0; ii--) {93						result <<= 8;94						result |= rbuf[(p *95							READ_BYTE_COUNT) + ii];96					}97					c -= snprintf(out_buf + PAGE_SIZE - c,98						c, "crc=YES c=%d\n", result);99				} else {100					c -= snprintf(out_buf + PAGE_SIZE - c,101						c, "crc=NO\n");102				}103			}104		}105	} else {106		c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error");107	}108	mutex_unlock(&dev->bus_mutex);109	return PAGE_SIZE - c;110}111 112static DEVICE_ATTR_RO(w1_slave);113 114static struct attribute *w1_f1d_attrs[] = {115	&dev_attr_w1_slave.attr,116	NULL,117};118ATTRIBUTE_GROUPS(w1_f1d);119 120static const struct w1_family_ops w1_f1d_fops = {121	.groups		= w1_f1d_groups,122};123 124static struct w1_family w1_family_1d = {125	.fid = W1_COUNTER_DS2423,126	.fops = &w1_f1d_fops,127};128module_w1_family(w1_family_1d);129 130MODULE_AUTHOR("Mika Laitio <lamikr@pilppa.org>");131MODULE_DESCRIPTION("w1 family 1d driver for DS2423, 4 counters and 4kb ram");132MODULE_LICENSE("GPL");133MODULE_ALIAS("w1-family-" __stringify(W1_COUNTER_DS2423));134