w1_ds2433.c (7201B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * w1_ds2433.c - w1 family 23 (DS2433) driver 4 * 5 * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> 6 */ 7 8#include <linux/kernel.h> 9#include <linux/module.h> 10#include <linux/moduleparam.h> 11#include <linux/device.h> 12#include <linux/types.h> 13#include <linux/delay.h> 14#include <linux/slab.h> 15#ifdef CONFIG_W1_SLAVE_DS2433_CRC 16#include <linux/crc16.h> 17 18#define CRC16_INIT 0 19#define CRC16_VALID 0xb001 20 21#endif 22 23#include <linux/w1.h> 24 25#define W1_EEPROM_DS2433 0x23 26 27#define W1_EEPROM_SIZE 512 28#define W1_PAGE_COUNT 16 29#define W1_PAGE_SIZE 32 30#define W1_PAGE_BITS 5 31#define W1_PAGE_MASK 0x1F 32 33#define W1_F23_TIME 300 34 35#define W1_F23_READ_EEPROM 0xF0 36#define W1_F23_WRITE_SCRATCH 0x0F 37#define W1_F23_READ_SCRATCH 0xAA 38#define W1_F23_COPY_SCRATCH 0x55 39 40struct w1_f23_data { 41 u8 memory[W1_EEPROM_SIZE]; 42 u32 validcrc; 43}; 44 45/** 46 * Check the file size bounds and adjusts count as needed. 47 * This would not be needed if the file size didn't reset to 0 after a write. 48 */ 49static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size) 50{ 51 if (off > size) 52 return 0; 53 54 if ((off + count) > size) 55 return (size - off); 56 57 return count; 58} 59 60#ifdef CONFIG_W1_SLAVE_DS2433_CRC 61static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data, 62 int block) 63{ 64 u8 wrbuf[3]; 65 int off = block * W1_PAGE_SIZE; 66 67 if (data->validcrc & (1 << block)) 68 return 0; 69 70 if (w1_reset_select_slave(sl)) { 71 data->validcrc = 0; 72 return -EIO; 73 } 74 75 wrbuf[0] = W1_F23_READ_EEPROM; 76 wrbuf[1] = off & 0xff; 77 wrbuf[2] = off >> 8; 78 w1_write_block(sl->master, wrbuf, 3); 79 w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE); 80 81 /* cache the block if the CRC is valid */ 82 if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID) 83 data->validcrc |= (1 << block); 84 85 return 0; 86} 87#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ 88 89static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, 90 struct bin_attribute *bin_attr, char *buf, 91 loff_t off, size_t count) 92{ 93 struct w1_slave *sl = kobj_to_w1_slave(kobj); 94#ifdef CONFIG_W1_SLAVE_DS2433_CRC 95 struct w1_f23_data *data = sl->family_data; 96 int i, min_page, max_page; 97#else 98 u8 wrbuf[3]; 99#endif 100 101 if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) 102 return 0; 103 104 mutex_lock(&sl->master->bus_mutex); 105 106#ifdef CONFIG_W1_SLAVE_DS2433_CRC 107 108 min_page = (off >> W1_PAGE_BITS); 109 max_page = (off + count - 1) >> W1_PAGE_BITS; 110 for (i = min_page; i <= max_page; i++) { 111 if (w1_f23_refresh_block(sl, data, i)) { 112 count = -EIO; 113 goto out_up; 114 } 115 } 116 memcpy(buf, &data->memory[off], count); 117 118#else /* CONFIG_W1_SLAVE_DS2433_CRC */ 119 120 /* read directly from the EEPROM */ 121 if (w1_reset_select_slave(sl)) { 122 count = -EIO; 123 goto out_up; 124 } 125 126 wrbuf[0] = W1_F23_READ_EEPROM; 127 wrbuf[1] = off & 0xff; 128 wrbuf[2] = off >> 8; 129 w1_write_block(sl->master, wrbuf, 3); 130 w1_read_block(sl->master, buf, count); 131 132#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ 133 134out_up: 135 mutex_unlock(&sl->master->bus_mutex); 136 137 return count; 138} 139 140/** 141 * Writes to the scratchpad and reads it back for verification. 142 * Then copies the scratchpad to EEPROM. 143 * The data must be on one page. 144 * The master must be locked. 145 * 146 * @param sl The slave structure 147 * @param addr Address for the write 148 * @param len length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) 149 * @param data The data to write 150 * @return 0=Success -1=failure 151 */ 152static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data) 153{ 154#ifdef CONFIG_W1_SLAVE_DS2433_CRC 155 struct w1_f23_data *f23 = sl->family_data; 156#endif 157 u8 wrbuf[4]; 158 u8 rdbuf[W1_PAGE_SIZE + 3]; 159 u8 es = (addr + len - 1) & 0x1f; 160 161 /* Write the data to the scratchpad */ 162 if (w1_reset_select_slave(sl)) 163 return -1; 164 165 wrbuf[0] = W1_F23_WRITE_SCRATCH; 166 wrbuf[1] = addr & 0xff; 167 wrbuf[2] = addr >> 8; 168 169 w1_write_block(sl->master, wrbuf, 3); 170 w1_write_block(sl->master, data, len); 171 172 /* Read the scratchpad and verify */ 173 if (w1_reset_select_slave(sl)) 174 return -1; 175 176 w1_write_8(sl->master, W1_F23_READ_SCRATCH); 177 w1_read_block(sl->master, rdbuf, len + 3); 178 179 /* Compare what was read against the data written */ 180 if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) || 181 (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0)) 182 return -1; 183 184 /* Copy the scratchpad to EEPROM */ 185 if (w1_reset_select_slave(sl)) 186 return -1; 187 188 wrbuf[0] = W1_F23_COPY_SCRATCH; 189 wrbuf[3] = es; 190 w1_write_block(sl->master, wrbuf, 4); 191 192 /* Sleep for 5 ms to wait for the write to complete */ 193 msleep(5); 194 195 /* Reset the bus to wake up the EEPROM (this may not be needed) */ 196 w1_reset_bus(sl->master); 197#ifdef CONFIG_W1_SLAVE_DS2433_CRC 198 f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS)); 199#endif 200 return 0; 201} 202 203static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, 204 struct bin_attribute *bin_attr, char *buf, 205 loff_t off, size_t count) 206{ 207 struct w1_slave *sl = kobj_to_w1_slave(kobj); 208 int addr, len, idx; 209 210 if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) 211 return 0; 212 213#ifdef CONFIG_W1_SLAVE_DS2433_CRC 214 /* can only write full blocks in cached mode */ 215 if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) { 216 dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n", 217 (int)off, count); 218 return -EINVAL; 219 } 220 221 /* make sure the block CRCs are valid */ 222 for (idx = 0; idx < count; idx += W1_PAGE_SIZE) { 223 if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) { 224 dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off); 225 return -EINVAL; 226 } 227 } 228#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ 229 230 mutex_lock(&sl->master->bus_mutex); 231 232 /* Can only write data to one page at a time */ 233 idx = 0; 234 while (idx < count) { 235 addr = off + idx; 236 len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK); 237 if (len > (count - idx)) 238 len = count - idx; 239 240 if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) { 241 count = -EIO; 242 goto out_up; 243 } 244 idx += len; 245 } 246 247out_up: 248 mutex_unlock(&sl->master->bus_mutex); 249 250 return count; 251} 252 253static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE); 254 255static struct bin_attribute *w1_f23_bin_attributes[] = { 256 &bin_attr_eeprom, 257 NULL, 258}; 259 260static const struct attribute_group w1_f23_group = { 261 .bin_attrs = w1_f23_bin_attributes, 262}; 263 264static const struct attribute_group *w1_f23_groups[] = { 265 &w1_f23_group, 266 NULL, 267}; 268 269static int w1_f23_add_slave(struct w1_slave *sl) 270{ 271#ifdef CONFIG_W1_SLAVE_DS2433_CRC 272 struct w1_f23_data *data; 273 274 data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL); 275 if (!data) 276 return -ENOMEM; 277 sl->family_data = data; 278 279#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ 280 return 0; 281} 282 283static void w1_f23_remove_slave(struct w1_slave *sl) 284{ 285#ifdef CONFIG_W1_SLAVE_DS2433_CRC 286 kfree(sl->family_data); 287 sl->family_data = NULL; 288#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ 289} 290 291static const struct w1_family_ops w1_f23_fops = { 292 .add_slave = w1_f23_add_slave, 293 .remove_slave = w1_f23_remove_slave, 294 .groups = w1_f23_groups, 295}; 296 297static struct w1_family w1_family_23 = { 298 .fid = W1_EEPROM_DS2433, 299 .fops = &w1_f23_fops, 300}; 301module_w1_family(w1_family_23); 302 303MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); 304MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM"); 305MODULE_LICENSE("GPL"); 306MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433));