#include "kszsw_reg_acc_spi.h"

#if LIP_SW_SUPPORT_KSZ8567

#define KSZSW_CMD_REG_RD 3
#define KSZSW_CMD_REG_WR 2

static t_lip_errs kszsw_reg_exchange(const void *ctx, uint8_t cmd, uint16_t regaddr,
                             const uint8_t *tx, uint8_t *rx, uint8_t len) {
    t_kszsw_reg_acc_spi_ctx *reg_acc_ctx = (t_kszsw_reg_acc_spi_ctx *)ctx;
    uint8_t tx_hdr[4];
    tx_hdr[0] = cmd << 5;
    tx_hdr[1] = (regaddr >> 11) & 0x1F;
    tx_hdr[2] = (regaddr >>  3) & 0xFF;
    tx_hdr[3] = (regaddr & 0x7) << 5;
    return reg_acc_ctx->exchange_cb(reg_acc_ctx->exchange_ctx, tx_hdr, sizeof(tx_hdr), tx, rx, len);
}


static t_lip_errs kszsw_spi_reg_read8(void *ctx, uint16_t regaddr, uint8_t *rdval) {
    return kszsw_reg_exchange(ctx, KSZSW_CMD_REG_RD, regaddr, NULL, rdval, 1);
}

static t_lip_errs kszsw_spi_reg_read16(void *ctx, uint16_t regaddr, uint16_t *rdval) {
    uint8_t rx_arr[2];
    t_lip_errs err = kszsw_reg_exchange(ctx, KSZSW_CMD_REG_RD, regaddr, NULL, rx_arr, sizeof(rx_arr));
    if ((err == LIP_ERR_SUCCESS)  && rdval) {
        *rdval = ((uint16_t)rx_arr[0] << 8) | rx_arr[1];
    }
    return err;
}

static t_lip_errs kszsw_spi_reg_read32(void *ctx, uint16_t regaddr, uint32_t *rdval) {
    uint8_t rx_arr[4];
    t_lip_errs err = kszsw_reg_exchange(ctx, KSZSW_CMD_REG_RD, regaddr, NULL, rx_arr, sizeof(rx_arr));
    if ((err == LIP_ERR_SUCCESS)  && rdval) {
        *rdval = ((uint32_t)rx_arr[0] << 24)
                | ((uint32_t)rx_arr[1] << 16)
                | ((uint32_t)rx_arr[2] << 8)
                | rx_arr[3];
    }
    return err;
}


static t_lip_errs kszsw_spi_reg_write8(void *ctx, uint16_t regaddr, uint8_t val) {
    return kszsw_reg_exchange(ctx, KSZSW_CMD_REG_WR, regaddr, &val, NULL, 1);
}


static t_lip_errs kszsw_spi_reg_write16(void *ctx, uint16_t regaddr, uint16_t val) {
    const uint8_t tx_arr[2] = {(val >> 8) & 0xFF, val & 0xFF};
    return kszsw_reg_exchange(ctx, KSZSW_CMD_REG_WR, regaddr, tx_arr, NULL, sizeof (tx_arr));
}

static t_lip_errs kszsw_spi_reg_write32(void *ctx, uint16_t regaddr, uint32_t val) {
    const uint8_t tx_arr[4] = {(val >> 24) & 0xFF,
                               (val >> 16) & 0xFF,
                               (val >> 8) & 0xFF,
                               val & 0xFF};
    return kszsw_reg_exchange(ctx, KSZSW_CMD_REG_WR, regaddr, tx_arr, NULL, sizeof (tx_arr));
}

static const  t_kszsw_reg_iface kszsw_reg_spi_iface = {
    .rd8  = kszsw_spi_reg_read8,
    .rd16 = kszsw_spi_reg_read16,
    .rd32 = kszsw_spi_reg_read32,
    .wr8  = kszsw_spi_reg_write8,
    .wr16 = kszsw_spi_reg_write16,
    .wr32 = kszsw_spi_reg_write32,
} ;



void kszsw_reg_acc_spi_init(t_kszsw_reg_acc *reg_acc, t_kszsw_reg_acc_spi_ctx *ctx) {
    reg_acc->iface = &kszsw_reg_spi_iface;
    reg_acc->ctx = ctx;
}

#endif

