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