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