1 /** 2 * Register map access API - ENCX24J600 support 3 * 4 * Copyright 2015 Gridpoint 5 * 6 * Author: Jon Ringle <jringle@gridpoint.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/errno.h> 15 #include <linux/init.h> 16 #include <linux/module.h> 17 #include <linux/netdevice.h> 18 #include <linux/regmap.h> 19 #include <linux/spi/spi.h> 20 21 #include "encx24j600_hw.h" 22 23 static inline bool is_bits_set(int value, int mask) 24 { 25 return (value & mask) == mask; 26 } 27 28 static int encx24j600_switch_bank(struct encx24j600_context *ctx, 29 int bank) 30 { 31 int ret = 0; 32 int bank_opcode = BANK_SELECT(bank); 33 34 ret = spi_write(ctx->spi, &bank_opcode, 1); 35 if (ret == 0) 36 ctx->bank = bank; 37 38 return ret; 39 } 40 41 static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode, 42 const void *buf, size_t len) 43 { 44 struct spi_message m; 45 struct spi_transfer t[2] = { { .tx_buf = &opcode, .len = 1, }, 46 { .tx_buf = buf, .len = len }, }; 47 spi_message_init(&m); 48 spi_message_add_tail(&t[0], &m); 49 spi_message_add_tail(&t[1], &m); 50 51 return spi_sync(ctx->spi, &m); 52 } 53 54 static void regmap_lock_mutex(void *context) 55 { 56 struct encx24j600_context *ctx = context; 57 58 mutex_lock(&ctx->mutex); 59 } 60 61 static void regmap_unlock_mutex(void *context) 62 { 63 struct encx24j600_context *ctx = context; 64 65 mutex_unlock(&ctx->mutex); 66 } 67 68 static int regmap_encx24j600_sfr_read(void *context, u8 reg, u8 *val, 69 size_t len) 70 { 71 struct encx24j600_context *ctx = context; 72 u8 banked_reg = reg & ADDR_MASK; 73 u8 bank = ((reg & BANK_MASK) >> BANK_SHIFT); 74 u8 cmd = RCRU; 75 int ret = 0; 76 int i = 0; 77 u8 tx_buf[2]; 78 79 if (reg < 0x80) { 80 cmd = RCRCODE | banked_reg; 81 if ((banked_reg < 0x16) && (ctx->bank != bank)) 82 ret = encx24j600_switch_bank(ctx, bank); 83 if (unlikely(ret)) 84 return ret; 85 } else { 86 /* Translate registers that are more effecient using 87 * 3-byte SPI commands 88 */ 89 switch (reg) { 90 case EGPRDPT: 91 cmd = RGPRDPT; break; 92 case EGPWRPT: 93 cmd = RGPWRPT; break; 94 case ERXRDPT: 95 cmd = RRXRDPT; break; 96 case ERXWRPT: 97 cmd = RRXWRPT; break; 98 case EUDARDPT: 99 cmd = RUDARDPT; break; 100 case EUDAWRPT: 101 cmd = RUDAWRPT; break; 102 case EGPDATA: 103 case ERXDATA: 104 case EUDADATA: 105 default: 106 return -EINVAL; 107 } 108 } 109 110 tx_buf[i++] = cmd; 111 if (cmd == RCRU) 112 tx_buf[i++] = reg; 113 114 ret = spi_write_then_read(ctx->spi, tx_buf, i, val, len); 115 116 return ret; 117 } 118 119 static int regmap_encx24j600_sfr_update(struct encx24j600_context *ctx, 120 u8 reg, u8 *val, size_t len, 121 u8 unbanked_cmd, u8 banked_code) 122 { 123 u8 banked_reg = reg & ADDR_MASK; 124 u8 bank = ((reg & BANK_MASK) >> BANK_SHIFT); 125 u8 cmd = unbanked_cmd; 126 struct spi_message m; 127 struct spi_transfer t[3] = { { .tx_buf = &cmd, .len = sizeof(cmd), }, 128 { .tx_buf = ®, .len = sizeof(reg), }, 129 { .tx_buf = val, .len = len }, }; 130 131 if (reg < 0x80) { 132 int ret = 0; 133 134 cmd = banked_code | banked_reg; 135 if ((banked_reg < 0x16) && (ctx->bank != bank)) 136 ret = encx24j600_switch_bank(ctx, bank); 137 if (unlikely(ret)) 138 return ret; 139 } else { 140 /* Translate registers that are more effecient using 141 * 3-byte SPI commands 142 */ 143 switch (reg) { 144 case EGPRDPT: 145 cmd = WGPRDPT; break; 146 case EGPWRPT: 147 cmd = WGPWRPT; break; 148 case ERXRDPT: 149 cmd = WRXRDPT; break; 150 case ERXWRPT: 151 cmd = WRXWRPT; break; 152 case EUDARDPT: 153 cmd = WUDARDPT; break; 154 case EUDAWRPT: 155 cmd = WUDAWRPT; break; 156 case EGPDATA: 157 case ERXDATA: 158 case EUDADATA: 159 default: 160 return -EINVAL; 161 } 162 } 163 164 spi_message_init(&m); 165 spi_message_add_tail(&t[0], &m); 166 167 if (cmd == unbanked_cmd) { 168 t[1].tx_buf = ® 169 spi_message_add_tail(&t[1], &m); 170 } 171 172 spi_message_add_tail(&t[2], &m); 173 return spi_sync(ctx->spi, &m); 174 } 175 176 static int regmap_encx24j600_sfr_write(void *context, u8 reg, u8 *val, 177 size_t len) 178 { 179 struct encx24j600_context *ctx = context; 180 181 return regmap_encx24j600_sfr_update(ctx, reg, val, len, WCRU, WCRCODE); 182 } 183 184 static int regmap_encx24j600_sfr_set_bits(struct encx24j600_context *ctx, 185 u8 reg, u8 val) 186 { 187 return regmap_encx24j600_sfr_update(ctx, reg, &val, 1, BFSU, BFSCODE); 188 } 189 190 static int regmap_encx24j600_sfr_clr_bits(struct encx24j600_context *ctx, 191 u8 reg, u8 val) 192 { 193 return regmap_encx24j600_sfr_update(ctx, reg, &val, 1, BFCU, BFCCODE); 194 } 195 196 static int regmap_encx24j600_reg_update_bits(void *context, unsigned int reg, 197 unsigned int mask, 198 unsigned int val) 199 { 200 struct encx24j600_context *ctx = context; 201 202 int ret = 0; 203 unsigned int set_mask = mask & val; 204 unsigned int clr_mask = mask & ~val; 205 206 if ((reg >= 0x40 && reg < 0x6c) || reg >= 0x80) 207 return -EINVAL; 208 209 if (set_mask & 0xff) 210 ret = regmap_encx24j600_sfr_set_bits(ctx, reg, set_mask); 211 212 set_mask = (set_mask & 0xff00) >> 8; 213 214 if ((set_mask & 0xff) && (ret == 0)) 215 ret = regmap_encx24j600_sfr_set_bits(ctx, reg + 1, set_mask); 216 217 if ((clr_mask & 0xff) && (ret == 0)) 218 ret = regmap_encx24j600_sfr_clr_bits(ctx, reg, clr_mask); 219 220 clr_mask = (clr_mask & 0xff00) >> 8; 221 222 if ((clr_mask & 0xff) && (ret == 0)) 223 ret = regmap_encx24j600_sfr_clr_bits(ctx, reg + 1, clr_mask); 224 225 return ret; 226 } 227 228 int regmap_encx24j600_spi_write(void *context, u8 reg, const u8 *data, 229 size_t count) 230 { 231 struct encx24j600_context *ctx = context; 232 233 if (reg < 0xc0) 234 return encx24j600_cmdn(ctx, reg, data, count); 235 236 /* SPI 1-byte command. Ignore data */ 237 return spi_write(ctx->spi, ®, 1); 238 } 239 EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_write); 240 241 int regmap_encx24j600_spi_read(void *context, u8 reg, u8 *data, size_t count) 242 { 243 struct encx24j600_context *ctx = context; 244 245 if (reg == RBSEL && count > 1) 246 count = 1; 247 248 return spi_write_then_read(ctx->spi, ®, sizeof(reg), data, count); 249 } 250 EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_read); 251 252 static int regmap_encx24j600_write(void *context, const void *data, 253 size_t len) 254 { 255 u8 *dout = (u8 *)data; 256 u8 reg = dout[0]; 257 ++dout; 258 --len; 259 260 if (reg > 0xa0) 261 return regmap_encx24j600_spi_write(context, reg, dout, len); 262 263 if (len > 2) 264 return -EINVAL; 265 266 return regmap_encx24j600_sfr_write(context, reg, dout, len); 267 } 268 269 static int regmap_encx24j600_read(void *context, 270 const void *reg_buf, size_t reg_size, 271 void *val, size_t val_size) 272 { 273 u8 reg = *(const u8 *)reg_buf; 274 275 if (reg_size != 1) { 276 pr_err("%s: reg=%02x reg_size=%zu\n", __func__, reg, reg_size); 277 return -EINVAL; 278 } 279 280 if (reg > 0xa0) 281 return regmap_encx24j600_spi_read(context, reg, val, val_size); 282 283 if (val_size > 2) { 284 pr_err("%s: reg=%02x val_size=%zu\n", __func__, reg, val_size); 285 return -EINVAL; 286 } 287 288 return regmap_encx24j600_sfr_read(context, reg, val, val_size); 289 } 290 291 static bool encx24j600_regmap_readable(struct device *dev, unsigned int reg) 292 { 293 if ((reg < 0x36) || 294 ((reg >= 0x40) && (reg < 0x4c)) || 295 ((reg >= 0x52) && (reg < 0x56)) || 296 ((reg >= 0x60) && (reg < 0x66)) || 297 ((reg >= 0x68) && (reg < 0x80)) || 298 ((reg >= 0x86) && (reg < 0x92)) || 299 (reg == 0xc8)) 300 return true; 301 else 302 return false; 303 } 304 305 static bool encx24j600_regmap_writeable(struct device *dev, unsigned int reg) 306 { 307 if ((reg < 0x12) || 308 ((reg >= 0x14) && (reg < 0x1a)) || 309 ((reg >= 0x1c) && (reg < 0x36)) || 310 ((reg >= 0x40) && (reg < 0x4c)) || 311 ((reg >= 0x52) && (reg < 0x56)) || 312 ((reg >= 0x60) && (reg < 0x68)) || 313 ((reg >= 0x6c) && (reg < 0x80)) || 314 ((reg >= 0x86) && (reg < 0x92)) || 315 ((reg >= 0xc0) && (reg < 0xc8)) || 316 ((reg >= 0xca) && (reg < 0xf0))) 317 return true; 318 else 319 return false; 320 } 321 322 static bool encx24j600_regmap_volatile(struct device *dev, unsigned int reg) 323 { 324 switch (reg) { 325 case ERXHEAD: 326 case EDMACS: 327 case ETXSTAT: 328 case ETXWIRE: 329 case ECON1: /* Can be modified via single byte cmds */ 330 case ECON2: /* Can be modified via single byte cmds */ 331 case ESTAT: 332 case EIR: /* Can be modified via single byte cmds */ 333 case MIRD: 334 case MISTAT: 335 return true; 336 default: 337 break; 338 } 339 340 return false; 341 } 342 343 static bool encx24j600_regmap_precious(struct device *dev, unsigned int reg) 344 { 345 /* single byte cmds are precious */ 346 if (((reg >= 0xc0) && (reg < 0xc8)) || 347 ((reg >= 0xca) && (reg < 0xf0))) 348 return true; 349 else 350 return false; 351 } 352 353 static int regmap_encx24j600_phy_reg_read(void *context, unsigned int reg, 354 unsigned int *val) 355 { 356 struct encx24j600_context *ctx = context; 357 int ret; 358 unsigned int mistat; 359 360 reg = MIREGADR_VAL | (reg & PHREG_MASK); 361 ret = regmap_write(ctx->regmap, MIREGADR, reg); 362 if (unlikely(ret)) 363 goto err_out; 364 365 ret = regmap_write(ctx->regmap, MICMD, MIIRD); 366 if (unlikely(ret)) 367 goto err_out; 368 369 usleep_range(26, 100); 370 while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) && 371 (mistat & BUSY)) 372 cpu_relax(); 373 374 if (unlikely(ret)) 375 goto err_out; 376 377 ret = regmap_write(ctx->regmap, MICMD, 0); 378 if (unlikely(ret)) 379 goto err_out; 380 381 ret = regmap_read(ctx->regmap, MIRD, val); 382 383 err_out: 384 if (ret) 385 pr_err("%s: error %d reading reg %02x\n", __func__, ret, 386 reg & PHREG_MASK); 387 388 return ret; 389 } 390 391 static int regmap_encx24j600_phy_reg_write(void *context, unsigned int reg, 392 unsigned int val) 393 { 394 struct encx24j600_context *ctx = context; 395 int ret; 396 unsigned int mistat; 397 398 reg = MIREGADR_VAL | (reg & PHREG_MASK); 399 ret = regmap_write(ctx->regmap, MIREGADR, reg); 400 if (unlikely(ret)) 401 goto err_out; 402 403 ret = regmap_write(ctx->regmap, MIWR, val); 404 if (unlikely(ret)) 405 goto err_out; 406 407 usleep_range(26, 100); 408 while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) && 409 (mistat & BUSY)) 410 cpu_relax(); 411 412 err_out: 413 if (ret) 414 pr_err("%s: error %d writing reg %02x=%04x\n", __func__, ret, 415 reg & PHREG_MASK, val); 416 417 return ret; 418 } 419 420 static bool encx24j600_phymap_readable(struct device *dev, unsigned int reg) 421 { 422 switch (reg) { 423 case PHCON1: 424 case PHSTAT1: 425 case PHANA: 426 case PHANLPA: 427 case PHANE: 428 case PHCON2: 429 case PHSTAT2: 430 case PHSTAT3: 431 return true; 432 default: 433 return false; 434 } 435 } 436 437 static bool encx24j600_phymap_writeable(struct device *dev, unsigned int reg) 438 { 439 switch (reg) { 440 case PHCON1: 441 case PHCON2: 442 case PHANA: 443 return true; 444 case PHSTAT1: 445 case PHSTAT2: 446 case PHSTAT3: 447 case PHANLPA: 448 case PHANE: 449 default: 450 return false; 451 } 452 } 453 454 static bool encx24j600_phymap_volatile(struct device *dev, unsigned int reg) 455 { 456 switch (reg) { 457 case PHSTAT1: 458 case PHSTAT2: 459 case PHSTAT3: 460 case PHANLPA: 461 case PHANE: 462 case PHCON2: 463 return true; 464 default: 465 return false; 466 } 467 } 468 469 static struct regmap_config regcfg = { 470 .name = "reg", 471 .reg_bits = 8, 472 .val_bits = 16, 473 .max_register = 0xee, 474 .reg_stride = 2, 475 .cache_type = REGCACHE_RBTREE, 476 .val_format_endian = REGMAP_ENDIAN_LITTLE, 477 .readable_reg = encx24j600_regmap_readable, 478 .writeable_reg = encx24j600_regmap_writeable, 479 .volatile_reg = encx24j600_regmap_volatile, 480 .precious_reg = encx24j600_regmap_precious, 481 .lock = regmap_lock_mutex, 482 .unlock = regmap_unlock_mutex, 483 }; 484 485 static struct regmap_bus regmap_encx24j600 = { 486 .write = regmap_encx24j600_write, 487 .read = regmap_encx24j600_read, 488 .reg_update_bits = regmap_encx24j600_reg_update_bits, 489 }; 490 491 static struct regmap_config phycfg = { 492 .name = "phy", 493 .reg_bits = 8, 494 .val_bits = 16, 495 .max_register = 0x1f, 496 .cache_type = REGCACHE_RBTREE, 497 .val_format_endian = REGMAP_ENDIAN_LITTLE, 498 .readable_reg = encx24j600_phymap_readable, 499 .writeable_reg = encx24j600_phymap_writeable, 500 .volatile_reg = encx24j600_phymap_volatile, 501 }; 502 503 static struct regmap_bus phymap_encx24j600 = { 504 .reg_write = regmap_encx24j600_phy_reg_write, 505 .reg_read = regmap_encx24j600_phy_reg_read, 506 }; 507 508 void devm_regmap_init_encx24j600(struct device *dev, 509 struct encx24j600_context *ctx) 510 { 511 mutex_init(&ctx->mutex); 512 regcfg.lock_arg = ctx; 513 ctx->regmap = devm_regmap_init(dev, ®map_encx24j600, ctx, ®cfg); 514 ctx->phymap = devm_regmap_init(dev, &phymap_encx24j600, ctx, &phycfg); 515 } 516 EXPORT_SYMBOL_GPL(devm_regmap_init_encx24j600); 517 518 MODULE_LICENSE("GPL"); 519