w1_ds2433.c 7.3 KB
Newer Older
1 2 3 4 5
/*
 *	w1_ds2433.c - w1 family 23 (DS2433) driver
 *
 * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
 *
6 7
 * This source code is licensed under the GNU General Public License,
 * Version 2. See the file COPYING for more details.
8 9 10 11 12 13 14 15
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/delay.h>
16
#include <linux/slab.h>
17
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
18
#include <linux/crc16.h>
19 20 21 22

#define CRC16_INIT		0
#define CRC16_VALID		0xb001

23
#endif
24

25 26 27
#include "../w1.h"
#include "../w1_int.h"
#include "../w1_family.h"
28 29 30 31

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
32
MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433));
33 34

#define W1_EEPROM_SIZE		512
35
#define W1_PAGE_COUNT		16
36 37 38 39
#define W1_PAGE_SIZE		32
#define W1_PAGE_BITS		5
#define W1_PAGE_MASK		0x1F

40 41
#define W1_F23_TIME		300

42 43 44 45 46
#define W1_F23_READ_EEPROM	0xF0
#define W1_F23_WRITE_SCRATCH	0x0F
#define W1_F23_READ_SCRATCH	0xAA
#define W1_F23_COPY_SCRATCH	0x55

47 48 49 50 51
struct w1_f23_data {
	u8	memory[W1_EEPROM_SIZE];
	u32	validcrc;
};

52 53
/**
 * Check the file size bounds and adjusts count as needed.
54
 * This would not be needed if the file size didn't reset to 0 after a write.
55 56 57 58 59 60 61 62 63 64 65 66
 */
static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
{
	if (off > size)
		return 0;

	if ((off + count) > size)
		return (size - off);

	return count;
}

67
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
				int block)
{
	u8	wrbuf[3];
	int	off = block * W1_PAGE_SIZE;

	if (data->validcrc & (1 << block))
		return 0;

	if (w1_reset_select_slave(sl)) {
		data->validcrc = 0;
		return -EIO;
	}

	wrbuf[0] = W1_F23_READ_EEPROM;
	wrbuf[1] = off & 0xff;
	wrbuf[2] = off >> 8;
	w1_write_block(sl->master, wrbuf, 3);
	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);

	/* cache the block if the CRC is valid */
	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
		data->validcrc |= (1 << block);

	return 0;
}
94
#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
95

96 97 98
static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
			   struct bin_attribute *bin_attr, char *buf,
			   loff_t off, size_t count)
99 100
{
	struct w1_slave *sl = kobj_to_w1_slave(kobj);
101
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
102 103 104
	struct w1_f23_data *data = sl->family_data;
	int i, min_page, max_page;
#else
105
	u8 wrbuf[3];
106
#endif
107 108 109 110

	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
		return 0;

111
	mutex_lock(&sl->master->bus_mutex);
112

113
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
114 115 116 117 118 119 120 121 122 123 124

	min_page = (off >> W1_PAGE_BITS);
	max_page = (off + count - 1) >> W1_PAGE_BITS;
	for (i = min_page; i <= max_page; i++) {
		if (w1_f23_refresh_block(sl, data, i)) {
			count = -EIO;
			goto out_up;
		}
	}
	memcpy(buf, &data->memory[off], count);

125
#else 	/* CONFIG_W1_SLAVE_DS2433_CRC */
126

127 128 129 130 131 132 133 134 135 136 137 138
	/* read directly from the EEPROM */
	if (w1_reset_select_slave(sl)) {
		count = -EIO;
		goto out_up;
	}

	wrbuf[0] = W1_F23_READ_EEPROM;
	wrbuf[1] = off & 0xff;
	wrbuf[2] = off >> 8;
	w1_write_block(sl->master, wrbuf, 3);
	w1_read_block(sl->master, buf, count);

139
#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
140

141
out_up:
142
	mutex_unlock(&sl->master->bus_mutex);
143 144 145 146 147 148

	return count;
}

/**
 * Writes to the scratchpad and reads it back for verification.
149 150
 * Then copies the scratchpad to EEPROM.
 * The data must be on one page.
151 152 153 154 155 156 157 158 159 160
 * The master must be locked.
 *
 * @param sl	The slave structure
 * @param addr	Address for the write
 * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
 * @param data	The data to write
 * @return	0=Success -1=failure
 */
static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
{
161 162 163
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
	struct w1_f23_data *f23 = sl->family_data;
#endif
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	u8 wrbuf[4];
	u8 rdbuf[W1_PAGE_SIZE + 3];
	u8 es = (addr + len - 1) & 0x1f;

	/* Write the data to the scratchpad */
	if (w1_reset_select_slave(sl))
		return -1;

	wrbuf[0] = W1_F23_WRITE_SCRATCH;
	wrbuf[1] = addr & 0xff;
	wrbuf[2] = addr >> 8;

	w1_write_block(sl->master, wrbuf, 3);
	w1_write_block(sl->master, data, len);

	/* Read the scratchpad and verify */
	if (w1_reset_select_slave(sl))
		return -1;

	w1_write_8(sl->master, W1_F23_READ_SCRATCH);
	w1_read_block(sl->master, rdbuf, len + 3);

	/* Compare what was read against the data written */
	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
		return -1;

	/* Copy the scratchpad to EEPROM */
	if (w1_reset_select_slave(sl))
		return -1;

	wrbuf[0] = W1_F23_COPY_SCRATCH;
	wrbuf[3] = es;
	w1_write_block(sl->master, wrbuf, 4);

	/* Sleep for 5 ms to wait for the write to complete */
	msleep(5);

	/* Reset the bus to wake up the EEPROM (this may not be needed) */
	w1_reset_bus(sl->master);
204 205 206
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
	f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
#endif
207 208 209
	return 0;
}

210 211 212
static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
			    struct bin_attribute *bin_attr, char *buf,
			    loff_t off, size_t count)
213 214 215 216 217 218 219
{
	struct w1_slave *sl = kobj_to_w1_slave(kobj);
	int addr, len, idx;

	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
		return 0;

220
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
221 222
	/* can only write full blocks in cached mode */
	if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
223
		dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
224 225 226 227 228 229 230 231 232 233 234
			(int)off, count);
		return -EINVAL;
	}

	/* make sure the block CRCs are valid */
	for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
		if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
			dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
			return -EINVAL;
		}
	}
235
#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
236

237
	mutex_lock(&sl->master->bus_mutex);
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

	/* Can only write data to one page at a time */
	idx = 0;
	while (idx < count) {
		addr = off + idx;
		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
		if (len > (count - idx))
			len = count - idx;

		if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) {
			count = -EIO;
			goto out_up;
		}
		idx += len;
	}

out_up:
255
	mutex_unlock(&sl->master->bus_mutex);
256 257 258 259

	return count;
}

260 261 262 263 264 265 266 267 268 269 270 271 272 273
static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);

static struct bin_attribute *w1_f23_bin_attributes[] = {
	&bin_attr_eeprom,
	NULL,
};

static const struct attribute_group w1_f23_group = {
	.bin_attrs = w1_f23_bin_attributes,
};

static const struct attribute_group *w1_f23_groups[] = {
	&w1_f23_group,
	NULL,
274 275 276 277
};

static int w1_f23_add_slave(struct w1_slave *sl)
{
278
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
279 280
	struct w1_f23_data *data;

281
	data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
282 283 284 285
	if (!data)
		return -ENOMEM;
	sl->family_data = data;

286
#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
287
	return 0;
288 289 290 291
}

static void w1_f23_remove_slave(struct w1_slave *sl)
{
292
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
293 294
	kfree(sl->family_data);
	sl->family_data = NULL;
295
#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
296 297 298 299 300
}

static struct w1_family_ops w1_f23_fops = {
	.add_slave      = w1_f23_add_slave,
	.remove_slave   = w1_f23_remove_slave,
301
	.groups		= w1_f23_groups,
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
};

static struct w1_family w1_family_23 = {
	.fid = W1_EEPROM_DS2433,
	.fops = &w1_f23_fops,
};

static int __init w1_f23_init(void)
{
	return w1_register_family(&w1_family_23);
}

static void __exit w1_f23_fini(void)
{
	w1_unregister_family(&w1_family_23);
}

module_init(w1_f23_init);
module_exit(w1_f23_fini);