w1_ds250x.c (6418B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * w1_ds250x.c - w1 family 09/0b/89/91 (DS250x) driver 4 */ 5 6#include <linux/kernel.h> 7#include <linux/module.h> 8#include <linux/moduleparam.h> 9#include <linux/device.h> 10#include <linux/types.h> 11#include <linux/delay.h> 12#include <linux/slab.h> 13#include <linux/crc16.h> 14 15#include <linux/w1.h> 16#include <linux/nvmem-provider.h> 17 18#define W1_DS2501_UNW_FAMILY 0x91 19#define W1_DS2501_SIZE 64 20 21#define W1_DS2502_FAMILY 0x09 22#define W1_DS2502_UNW_FAMILY 0x89 23#define W1_DS2502_SIZE 128 24 25#define W1_DS2505_FAMILY 0x0b 26#define W1_DS2505_SIZE 2048 27 28#define W1_PAGE_SIZE 32 29 30#define W1_EXT_READ_MEMORY 0xA5 31#define W1_READ_DATA_CRC 0xC3 32 33#define OFF2PG(off) ((off) / W1_PAGE_SIZE) 34 35#define CRC16_INIT 0 36#define CRC16_VALID 0xb001 37 38struct w1_eprom_data { 39 size_t size; 40 int (*read)(struct w1_slave *sl, int pageno); 41 u8 eprom[W1_DS2505_SIZE]; 42 DECLARE_BITMAP(page_present, W1_DS2505_SIZE / W1_PAGE_SIZE); 43 char nvmem_name[64]; 44}; 45 46static int w1_ds2502_read_page(struct w1_slave *sl, int pageno) 47{ 48 struct w1_eprom_data *data = sl->family_data; 49 int pgoff = pageno * W1_PAGE_SIZE; 50 int ret = -EIO; 51 u8 buf[3]; 52 u8 crc8; 53 54 if (test_bit(pageno, data->page_present)) 55 return 0; /* page already present */ 56 57 mutex_lock(&sl->master->bus_mutex); 58 59 if (w1_reset_select_slave(sl)) 60 goto err; 61 62 buf[0] = W1_READ_DATA_CRC; 63 buf[1] = pgoff & 0xff; 64 buf[2] = pgoff >> 8; 65 w1_write_block(sl->master, buf, 3); 66 67 crc8 = w1_read_8(sl->master); 68 if (w1_calc_crc8(buf, 3) != crc8) 69 goto err; 70 71 w1_read_block(sl->master, &data->eprom[pgoff], W1_PAGE_SIZE); 72 73 crc8 = w1_read_8(sl->master); 74 if (w1_calc_crc8(&data->eprom[pgoff], W1_PAGE_SIZE) != crc8) 75 goto err; 76 77 set_bit(pageno, data->page_present); /* mark page present */ 78 ret = 0; 79err: 80 mutex_unlock(&sl->master->bus_mutex); 81 return ret; 82} 83 84static int w1_ds2505_read_page(struct w1_slave *sl, int pageno) 85{ 86 struct w1_eprom_data *data = sl->family_data; 87 int redir_retries = 16; 88 int pgoff, epoff; 89 int ret = -EIO; 90 u8 buf[6]; 91 u8 redir; 92 u16 crc; 93 94 if (test_bit(pageno, data->page_present)) 95 return 0; /* page already present */ 96 97 epoff = pgoff = pageno * W1_PAGE_SIZE; 98 mutex_lock(&sl->master->bus_mutex); 99 100retry: 101 if (w1_reset_select_slave(sl)) 102 goto err; 103 104 buf[0] = W1_EXT_READ_MEMORY; 105 buf[1] = pgoff & 0xff; 106 buf[2] = pgoff >> 8; 107 w1_write_block(sl->master, buf, 3); 108 w1_read_block(sl->master, buf + 3, 3); /* redir, crc16 */ 109 redir = buf[3]; 110 crc = crc16(CRC16_INIT, buf, 6); 111 112 if (crc != CRC16_VALID) 113 goto err; 114 115 116 if (redir != 0xff) { 117 redir_retries--; 118 if (redir_retries < 0) 119 goto err; 120 121 pgoff = (redir ^ 0xff) * W1_PAGE_SIZE; 122 goto retry; 123 } 124 125 w1_read_block(sl->master, &data->eprom[epoff], W1_PAGE_SIZE); 126 w1_read_block(sl->master, buf, 2); /* crc16 */ 127 crc = crc16(CRC16_INIT, &data->eprom[epoff], W1_PAGE_SIZE); 128 crc = crc16(crc, buf, 2); 129 130 if (crc != CRC16_VALID) 131 goto err; 132 133 set_bit(pageno, data->page_present); 134 ret = 0; 135err: 136 mutex_unlock(&sl->master->bus_mutex); 137 return ret; 138} 139 140static int w1_nvmem_read(void *priv, unsigned int off, void *buf, size_t count) 141{ 142 struct w1_slave *sl = priv; 143 struct w1_eprom_data *data = sl->family_data; 144 size_t eprom_size = data->size; 145 int ret; 146 int i; 147 148 if (off > eprom_size) 149 return -EINVAL; 150 151 if ((off + count) > eprom_size) 152 count = eprom_size - off; 153 154 i = OFF2PG(off); 155 do { 156 ret = data->read(sl, i++); 157 if (ret < 0) 158 return ret; 159 } while (i < OFF2PG(off + count)); 160 161 memcpy(buf, &data->eprom[off], count); 162 return 0; 163} 164 165static int w1_eprom_add_slave(struct w1_slave *sl) 166{ 167 struct w1_eprom_data *data; 168 struct nvmem_device *nvmem; 169 struct nvmem_config nvmem_cfg = { 170 .dev = &sl->dev, 171 .reg_read = w1_nvmem_read, 172 .type = NVMEM_TYPE_OTP, 173 .read_only = true, 174 .word_size = 1, 175 .priv = sl, 176 .id = -1 177 }; 178 179 data = devm_kzalloc(&sl->dev, sizeof(struct w1_eprom_data), GFP_KERNEL); 180 if (!data) 181 return -ENOMEM; 182 183 sl->family_data = data; 184 switch (sl->family->fid) { 185 case W1_DS2501_UNW_FAMILY: 186 data->size = W1_DS2501_SIZE; 187 data->read = w1_ds2502_read_page; 188 break; 189 case W1_DS2502_FAMILY: 190 case W1_DS2502_UNW_FAMILY: 191 data->size = W1_DS2502_SIZE; 192 data->read = w1_ds2502_read_page; 193 break; 194 case W1_DS2505_FAMILY: 195 data->size = W1_DS2505_SIZE; 196 data->read = w1_ds2505_read_page; 197 break; 198 } 199 200 if (sl->master->bus_master->dev_id) 201 snprintf(data->nvmem_name, sizeof(data->nvmem_name), 202 "%s-%02x-%012llx", 203 sl->master->bus_master->dev_id, sl->reg_num.family, 204 (unsigned long long)sl->reg_num.id); 205 else 206 snprintf(data->nvmem_name, sizeof(data->nvmem_name), 207 "%02x-%012llx", 208 sl->reg_num.family, 209 (unsigned long long)sl->reg_num.id); 210 211 nvmem_cfg.name = data->nvmem_name; 212 nvmem_cfg.size = data->size; 213 214 nvmem = devm_nvmem_register(&sl->dev, &nvmem_cfg); 215 return PTR_ERR_OR_ZERO(nvmem); 216} 217 218static const struct w1_family_ops w1_eprom_fops = { 219 .add_slave = w1_eprom_add_slave, 220}; 221 222static struct w1_family w1_family_09 = { 223 .fid = W1_DS2502_FAMILY, 224 .fops = &w1_eprom_fops, 225}; 226 227static struct w1_family w1_family_0b = { 228 .fid = W1_DS2505_FAMILY, 229 .fops = &w1_eprom_fops, 230}; 231 232static struct w1_family w1_family_89 = { 233 .fid = W1_DS2502_UNW_FAMILY, 234 .fops = &w1_eprom_fops, 235}; 236 237static struct w1_family w1_family_91 = { 238 .fid = W1_DS2501_UNW_FAMILY, 239 .fops = &w1_eprom_fops, 240}; 241 242static int __init w1_ds250x_init(void) 243{ 244 int err; 245 246 err = w1_register_family(&w1_family_09); 247 if (err) 248 return err; 249 250 err = w1_register_family(&w1_family_0b); 251 if (err) 252 goto err_0b; 253 254 err = w1_register_family(&w1_family_89); 255 if (err) 256 goto err_89; 257 258 err = w1_register_family(&w1_family_91); 259 if (err) 260 goto err_91; 261 262 return 0; 263 264err_91: 265 w1_unregister_family(&w1_family_89); 266err_89: 267 w1_unregister_family(&w1_family_0b); 268err_0b: 269 w1_unregister_family(&w1_family_09); 270 return err; 271} 272 273static void __exit w1_ds250x_exit(void) 274{ 275 w1_unregister_family(&w1_family_09); 276 w1_unregister_family(&w1_family_0b); 277 w1_unregister_family(&w1_family_89); 278 w1_unregister_family(&w1_family_91); 279} 280 281module_init(w1_ds250x_init); 282module_exit(w1_ds250x_exit); 283 284MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfe@suse.de>"); 285MODULE_DESCRIPTION("w1 family driver for DS250x Add Only Memory"); 286MODULE_LICENSE("GPL"); 287MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_FAMILY)); 288MODULE_ALIAS("w1-family-" __stringify(W1_DS2505_FAMILY)); 289MODULE_ALIAS("w1-family-" __stringify(W1_DS2501_UNW_FAMILY)); 290MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_UNW_FAMILY));