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