aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1/w1_ds2433.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/w1/w1_ds2433.c')
-rw-r--r--drivers/w1/w1_ds2433.c117
1 files changed, 111 insertions, 6 deletions
diff --git a/drivers/w1/w1_ds2433.c b/drivers/w1/w1_ds2433.c
index 9ec9163a0a9b..b7c24b34d270 100644
--- a/drivers/w1/w1_ds2433.c
+++ b/drivers/w1/w1_ds2433.c
@@ -3,9 +3,8 @@
3 * 3 *
4 * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> 4 * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This source code is licensed under the GNU General Public License,
7 * it under the smems of the GNU General Public License as published by 7 * Version 2. See the file COPYING for more details.
8 * the Free Software Foundation; version 2 of the License.
9 */ 8 */
10 9
11#include <linux/kernel.h> 10#include <linux/kernel.h>
@@ -14,6 +13,9 @@
14#include <linux/device.h> 13#include <linux/device.h>
15#include <linux/types.h> 14#include <linux/types.h>
16#include <linux/delay.h> 15#include <linux/delay.h>
16#ifdef CONFIG_W1_F23_CRC
17#include <linux/crc16.h>
18#endif
17 19
18#include "w1.h" 20#include "w1.h"
19#include "w1_io.h" 21#include "w1_io.h"
@@ -25,18 +27,26 @@ MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
25MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM"); 27MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
26 28
27#define W1_EEPROM_SIZE 512 29#define W1_EEPROM_SIZE 512
30#define W1_PAGE_COUNT 16
28#define W1_PAGE_SIZE 32 31#define W1_PAGE_SIZE 32
29#define W1_PAGE_BITS 5 32#define W1_PAGE_BITS 5
30#define W1_PAGE_MASK 0x1F 33#define W1_PAGE_MASK 0x1F
31 34
35#define W1_F23_TIME 300
36
32#define W1_F23_READ_EEPROM 0xF0 37#define W1_F23_READ_EEPROM 0xF0
33#define W1_F23_WRITE_SCRATCH 0x0F 38#define W1_F23_WRITE_SCRATCH 0x0F
34#define W1_F23_READ_SCRATCH 0xAA 39#define W1_F23_READ_SCRATCH 0xAA
35#define W1_F23_COPY_SCRATCH 0x55 40#define W1_F23_COPY_SCRATCH 0x55
36 41
42struct w1_f23_data {
43 u8 memory[W1_EEPROM_SIZE];
44 u32 validcrc;
45};
46
37/** 47/**
38 * Check the file size bounds and adjusts count as needed. 48 * Check the file size bounds and adjusts count as needed.
39 * This may not be needed if the sysfs layer checks bounds. 49 * This would not be needed if the file size didn't reset to 0 after a write.
40 */ 50 */
41static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size) 51static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
42{ 52{
@@ -49,10 +59,45 @@ static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
49 return count; 59 return count;
50} 60}
51 61
52static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) 62#ifdef CONFIG_W1_F23_CRC
63static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
64 int block)
65{
66 u8 wrbuf[3];
67 int off = block * W1_PAGE_SIZE;
68
69 if (data->validcrc & (1 << block))
70 return 0;
71
72 if (w1_reset_select_slave(sl)) {
73 data->validcrc = 0;
74 return -EIO;
75 }
76
77 wrbuf[0] = W1_F23_READ_EEPROM;
78 wrbuf[1] = off & 0xff;
79 wrbuf[2] = off >> 8;
80 w1_write_block(sl->master, wrbuf, 3);
81 w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
82
83 /* cache the block if the CRC is valid */
84 if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
85 data->validcrc |= (1 << block);
86
87 return 0;
88}
89#endif /* CONFIG_W1_F23_CRC */
90
91static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
92 size_t count)
53{ 93{
54 struct w1_slave *sl = kobj_to_w1_slave(kobj); 94 struct w1_slave *sl = kobj_to_w1_slave(kobj);
95#ifdef CONFIG_W1_F23_CRC
96 struct w1_f23_data *data = sl->family_data;
97 int i, min_page, max_page;
98#else
55 u8 wrbuf[3]; 99 u8 wrbuf[3];
100#endif
56 101
57 if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) 102 if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
58 return 0; 103 return 0;
@@ -63,6 +108,20 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, size
63 goto out_dec; 108 goto out_dec;
64 } 109 }
65 110
111#ifdef CONFIG_W1_F23_CRC
112
113 min_page = (off >> W1_PAGE_BITS);
114 max_page = (off + count - 1) >> W1_PAGE_BITS;
115 for (i = min_page; i <= max_page; i++) {
116 if (w1_f23_refresh_block(sl, data, i)) {
117 count = -EIO;
118 goto out_up;
119 }
120 }
121 memcpy(buf, &data->memory[off], count);
122
123#else /* CONFIG_W1_F23_CRC */
124
66 /* read directly from the EEPROM */ 125 /* read directly from the EEPROM */
67 if (w1_reset_select_slave(sl)) { 126 if (w1_reset_select_slave(sl)) {
68 count = -EIO; 127 count = -EIO;
@@ -75,6 +134,8 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, size
75 w1_write_block(sl->master, wrbuf, 3); 134 w1_write_block(sl->master, wrbuf, 3);
76 w1_read_block(sl->master, buf, count); 135 w1_read_block(sl->master, buf, count);
77 136
137#endif /* CONFIG_W1_F23_CRC */
138
78out_up: 139out_up:
79 up(&sl->master->mutex); 140 up(&sl->master->mutex);
80out_dec: 141out_dec:
@@ -85,6 +146,8 @@ out_dec:
85 146
86/** 147/**
87 * Writes to the scratchpad and reads it back for verification. 148 * Writes to the scratchpad and reads it back for verification.
149 * Then copies the scratchpad to EEPROM.
150 * The data must be on one page.
88 * The master must be locked. 151 * The master must be locked.
89 * 152 *
90 * @param sl The slave structure 153 * @param sl The slave structure
@@ -148,6 +211,23 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
148 if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) 211 if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
149 return 0; 212 return 0;
150 213
214#ifdef CONFIG_W1_F23_CRC
215 /* can only write full blocks in cached mode */
216 if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
217 dev_err(&sl->dev, "invalid offset/count off=%d cnt=%d\n",
218 (int)off, count);
219 return -EINVAL;
220 }
221
222 /* make sure the block CRCs are valid */
223 for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
224 if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
225 dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
226 return -EINVAL;
227 }
228 }
229#endif /* CONFIG_W1_F23_CRC */
230
151 atomic_inc(&sl->refcnt); 231 atomic_inc(&sl->refcnt);
152 if (down_interruptible(&sl->master->mutex)) { 232 if (down_interruptible(&sl->master->mutex)) {
153 count = 0; 233 count = 0;
@@ -190,11 +270,36 @@ static struct bin_attribute w1_f23_bin_attr = {
190 270
191static int w1_f23_add_slave(struct w1_slave *sl) 271static int w1_f23_add_slave(struct w1_slave *sl)
192{ 272{
193 return sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); 273 int err;
274#ifdef CONFIG_W1_F23_CRC
275 struct w1_f23_data *data;
276
277 data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
278 if (!data)
279 return -ENOMEM;
280 memset(data, 0, sizeof(struct w1_f23_data));
281 sl->family_data = data;
282
283#endif /* CONFIG_W1_F23_CRC */
284
285 err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
286
287#ifdef CONFIG_W1_F23_CRC
288 if (err)
289 kfree(data);
290#endif /* CONFIG_W1_F23_CRC */
291
292 return err;
194} 293}
195 294
196static void w1_f23_remove_slave(struct w1_slave *sl) 295static void w1_f23_remove_slave(struct w1_slave *sl)
197{ 296{
297#ifdef CONFIG_W1_F23_CRC
298 if (sl->family_data) {
299 kfree(sl->family_data);
300 sl->family_data = NULL;
301 }
302#endif /* CONFIG_W1_F23_CRC */
198 sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); 303 sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
199} 304}
200 305