#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/delay.h>

#include "sony_fpga_xpt.h"

static void (*qsfp_detect_function)(struct qsfp_control*);

static int qsfp_select(void __iomem* pci_addr, uint bit)
{
    struct i2c_dev_info dev_info;
    u8 sel = 0;
    dev_info.slave_addr = I2C_SLAVE_ADDR_IOEXPANDER1;
    dev_info.addr_size = 1;

    sel = (1 << bit);
    if (i2c_tx(pci_addr, &dev_info, 0x03, &sel, 1) < 0) {
        pr_err("buffer select error %llx(%x)\n", (u64 __force)pci_addr, bit);
        return -EFAULT;
    }
    return 0;
}

static void qsfp_detect_gpio(struct qsfp_control* qsfp_ctrl)
{
    void __iomem *bar0_addr, *addr;
    u32 mod_prs;
    struct sony_fpga_ctrl* fpga_ctrl;
    u32 i;

    if (qsfp_ctrl == NULL || (fpga_ctrl = qsfp_ctrl->fpga_ctrl_addr) == NULL) {
        pr_err("ctrl is NULL");
        return;
    }

    bar0_addr = qsfp_ctrl->fpga_ctrl_addr->bar[FPGA_CTRL_BAR];
    addr = (bar0_addr + EXT_MOD_PRS_L_BASE_ADDR);
    mod_prs = IO_READ_32(addr);

    mod_prs >>= qsfp_ctrl->ctrl_index * 8;
    for (i = 0; i < 8; i++) {
        u32 prs = 0;
        prs = ((mod_prs & (1 << i)) == 0);
        if (qsfp_ctrl->status[i].mod_prs_l != 0 && prs == 0) {
            memset(&qsfp_ctrl->status[i], 0x00, sizeof(struct qsfp_status));
        }
        qsfp_ctrl->status[i].mod_prs_l = prs;
    }
}

static void qsfp_detect_ioexpander(struct qsfp_control* qsfp_ctrl)
{
    struct i2c_dev_info dev_info = {0};
    struct sony_fpga_ctrl* fpga_ctrl;
    u8 mod_prs_l = 0;
    void __iomem *bar0_addr;
    u32 i;

    if (qsfp_ctrl == NULL || (fpga_ctrl = qsfp_ctrl->fpga_ctrl_addr) == NULL) {
        pr_err("ctrl is NULL");
        return;
    }
    dev_info.addr_size = 1;
    dev_info.slave_addr = I2C_SLAVE_ADDR_IOEXPANDER3;
    bar0_addr = fpga_ctrl->bar[FPGA_CTRL_BAR];
    if (i2c_rx(bar0_addr + qsfp_ctrl->io_expander_addr, &dev_info, 0x01, &mod_prs_l, 1)) {
        pr_err("mod_prs_l read error\n");
    } else {
        for (i = 0; i < 8; i++) {
            u32 prs = 0;
            prs = ((mod_prs_l & (1 << i)) == 0);
            if (qsfp_ctrl->status[i].mod_prs_l != 0 && prs == 0) {
                memset(&qsfp_ctrl->status[i], 0x00, sizeof(struct qsfp_status));
            }
            qsfp_ctrl->status[i].mod_prs_l = prs;
        }
    }
}

static void qsfp_read_status(struct qsfp_control* qsfp_ctrl)
{
    u32 i;
    struct i2c_dev_info dev_info;
    u8 rbuff[8];
    u8 power[2];
    void __iomem* bar0_addr;
    void __iomem* ctrl_addr;

    dev_info.addr_size = 1;
    bar0_addr = qsfp_ctrl->fpga_ctrl_addr->bar[FPGA_CTRL_BAR];
    for (i = 0; i < 8; i++) {
        dev_info.slave_addr = I2C_SLAVE_ADDR_QSFP;

        // QSFP Status取得
        if (qsfp_ctrl->status[i].mod_prs_l == 0 || !qsfp_ctrl->status[i].initialized) {
            continue;
        }

        pr_debug("read-start %d", qsfp_ctrl->ctrl_index);
        // とりあえず2Burstのみ使う
        if (qsfp_select(qsfp_ctrl->io_expander_addr + bar0_addr, i) < 0) {
            continue;
        }

        ctrl_addr = qsfp_ctrl->ctrl_addr + bar0_addr;
        if (i2c_rx(ctrl_addr, &dev_info, 0x03, rbuff, 3) < 0) {
            continue;
        } else {
            qsfp_ctrl->status[i].rx_signal_loss = rbuff[0];
            qsfp_ctrl->status[i].rx_cdr_unlock = rbuff[2];
        }
        if (i2c_rx(ctrl_addr, &dev_info, 0x16, power, 2) < 0) {
            continue;
        } else {
            qsfp_ctrl->status[i].temperature = (s16)power[0] << 8 | (s16)power[1];
        }

        if (i2c_rx(ctrl_addr, &dev_info, 0x22, rbuff, 8) < 0) {
            continue;
        } else {
            qsfp_ctrl->status[i].rx_power_ch1 = rbuff[0] << 8 | rbuff[1];
            qsfp_ctrl->status[i].rx_power_ch2 = rbuff[2] << 8 | rbuff[3];
            qsfp_ctrl->status[i].rx_power_ch3 = rbuff[4] << 8 | rbuff[5];
            qsfp_ctrl->status[i].rx_power_ch4 = rbuff[6] << 8 | rbuff[7];
        }
        usleep_range(module_param_qsfp_poll_spare_time, module_param_qsfp_poll_spare_time + 1);
        if (i2c_rx(ctrl_addr, &dev_info, 0x32, rbuff, 8) < 0) {
            continue;
        } else {
            qsfp_ctrl->status[i].tx_power_ch1 = rbuff[0] << 8 | rbuff[1];
            qsfp_ctrl->status[i].tx_power_ch2 = rbuff[2] << 8 | rbuff[3];
            qsfp_ctrl->status[i].tx_power_ch3 = rbuff[4] << 8 | rbuff[5];
            qsfp_ctrl->status[i].tx_power_ch4 = rbuff[6] << 8 | rbuff[7];
        }
        usleep_range(module_param_qsfp_poll_spare_time, module_param_qsfp_poll_spare_time + 1);
        if (i2c_rx(ctrl_addr, &dev_info, 0x9, power, 2) < 0) {
            continue;
        } else {
            qsfp_ctrl->status[i].rx_power_mon[0] = power[0];
            qsfp_ctrl->status[i].rx_power_mon[1] = power[1];
        }
        if (i2c_rx(ctrl_addr, &dev_info, 0xd, power, 2) < 0) {
            continue;
        } else {
            qsfp_ctrl->status[i].tx_power_mon[0] = power[0];
            qsfp_ctrl->status[i].tx_power_mon[1] = power[1];
        }

        pr_debug("read-end %d", qsfp_ctrl->ctrl_index);
        usleep_range(module_param_qsfp_poll_spare_time, module_param_qsfp_poll_spare_time + 1);
    }
}

static int qsfp_poll_thread(void* data)
{
    struct qsfp_control* qsfp_ctrl = (struct qsfp_control*)data;
    struct sony_fpga_ctrl* fpga_ctrl;
    uint i = 0;
    struct i2c_dev_info dev_info = {0};
    void __iomem* bar0_addr;
    int ret = 0;
    u8 led_setting = 0;

    if (qsfp_ctrl == NULL || (fpga_ctrl = qsfp_ctrl->fpga_ctrl_addr) == NULL) {
        pr_err("ctrl is NULL");
        return -EINVAL;
    }
    dev_info.addr_size = 1;
    bar0_addr = fpga_ctrl->bar[FPGA_CTRL_BAR];
    while(!kthread_should_stop()) {
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(HZ / 4);

        if (qsfp_ctrl->pause) {
            continue;
        }

        qsfp_ctrl->counter++;

        ret = mutex_lock_interruptible(&(qsfp_ctrl->qsfp_mutex));
        if (ret != 0) {
            mutex_unlock(&(qsfp_ctrl->qsfp_mutex));
            pr_err("mutex_lock error\n");
            continue;
        }

        (*qsfp_detect_function)(qsfp_ctrl);

        led_setting = 0;
        for (i = 0; i < 8; i++) {
            // LED Blink制御
            if (qsfp_ctrl->led_status[i] == QSFP_LED_BLINK) {
                if (qsfp_ctrl->counter & 1) {
                    led_setting |= 1 << i;
                } else {
                    led_setting &= ~(1 << i);
                }
            } else {
                led_setting |= qsfp_ctrl->led_status[i] << i;
            }
        }
        dev_info.slave_addr = I2C_SLAVE_ADDR_IOEXPANDER1;
        if (i2c_tx(bar0_addr + qsfp_ctrl->io_expander_addr, &dev_info, 6, &led_setting, 1) < 0) {
            pr_err("I2C LED Setting Error %x \n", qsfp_ctrl->ctrl_addr);
        }

        if (qsfp_ctrl->counter & 1) {
            qsfp_read_status(qsfp_ctrl);
        }
        mutex_unlock(&(qsfp_ctrl->qsfp_mutex));
    }
    return 0;
}

static const u32 qsfp_addrs[I2C_MAX][2] = {
    { QSFP_1_BASE_ADDR, QSFP_CTRL1_BASE_ADDR },
    { QSFP_2_BASE_ADDR, QSFP_CTRL2_BASE_ADDR },
    { QSFP_3_BASE_ADDR, QSFP_CTRL3_BASE_ADDR },
    { RTM_BASE_ADDR, 0 }
};

static const struct i2c_settings IO_EXPANDER_SETTINGS[] = {
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x02, 0, 0 },
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x03, 0, 0 },
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x06, 0, 0 }, // EXT_IO_01〜08 LED
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x07, 0, 0 }, // EXT_IO_01〜08 I2C Buffer EN
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x02, 0, 0 },
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x03, 0, 0 },
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x06, 0, 0 }, // EXT_IO_01〜08 Reset
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x07, 0, 0 }, // EXT_IO_01〜08 LPMODE
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x04, 0, 0 },
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x05, 0, 0 },
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x06, 0xff, 0 }, // EXT_IO_01〜08 INIT
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x07, 0xff, 0 }, // EXT_IO_01〜08 MOD_PRS_L

    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x02, 0, 0 },
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x03, 0, 0 },
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x06, 0, 0 }, // EXT_IO_09〜16 LED
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x07, 0, 0 }, // EXT_IO_09〜16 I2C Buffer EN
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x02, 0, 0 },
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x03, 0, 0 },
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x06, 0, 0 }, // EXT_IO_09〜16 Reset
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x07, 0, 0 }, // EXT_IO_09〜16 LPMODE
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x04, 0, 0 },
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x05, 0, 0 },
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x06, 0xff, 0 }, // EXT_IO_09〜16 INIT
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x07, 0xff, 0 }, // EXT_IO_09〜16 MOD_PRS_L

    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x02, 0, 0 },
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x03, 0, 0 },
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x06, 0, 0 }, // EXT_IO_17〜24 LED
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x07, 0, 0 }, // EXT_IO_17〜24 I2C Buffer EN
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x02, 0, 0 },
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x03, 0, 0 },
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x06, 0, 0 }, // EXT_IO_17〜24 Reset
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x07, 0, 0 }, // EXT_IO_17〜24 LPMODE
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x04, 0, 0 },
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x05, 0, 0 },
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x06, 0xff, 0 }, // EXT_IO_17〜24 INIT
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER3, 0x07, 0xff, 0 }, // EXT_IO_17〜24 MOD_PRS_L

    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x04, 0xff, 0 },
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x05, 0xff, 0 },
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x06, 0xff, 0 }, // RTM_INT01〜06
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER1, 0x07, 0xff, 0 }, // RTM_INT07〜12
};

static const struct i2c_settings QSFP_RESET_RELEASE[] = {
    { QSFP_CTRL1_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x02, 0xff, 0 }, // EXT_IO  1〜8  RESET RELEASE
    { QSFP_CTRL2_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x02, 0xff, 0 }, // EXT_IO  9〜16 RESET RELEASE
    { QSFP_CTRL3_BASE_ADDR, I2C_SLAVE_ADDR_IOEXPANDER2, 0x02, 0xff, 0 }, // EXT_IO 17〜24 RESET RELEASE
};

static const u32 QSFP_SETTINGS[][4] = {
    { QSFP_CTRL1_BASE_ADDR, 0x0000, QSFP_1_BASE_ADDR,  4 }, // EXT_IO_01(QSFP#03)
    { QSFP_CTRL1_BASE_ADDR, 0x0001, QSFP_1_BASE_ADDR,  1 }, // EXT_IO_02(QSFP#00)
    { QSFP_CTRL1_BASE_ADDR, 0x0002, QSFP_1_BASE_ADDR,  5 }, // EXT_IO_03(QSFP#04)
    { QSFP_CTRL1_BASE_ADDR, 0x0003, QSFP_1_BASE_ADDR,  2 }, // EXT_IO_04(QSFP#01)
    { QSFP_CTRL1_BASE_ADDR, 0x0004, QSFP_1_BASE_ADDR,  6 }, // EXT_IO_05(QSFP#05)
    { QSFP_CTRL1_BASE_ADDR, 0x0005, QSFP_1_BASE_ADDR,  3 }, // EXT_IO_06(QSFP#02)
    { QSFP_CTRL1_BASE_ADDR, 0x0006, QSFP_1_BASE_ADDR, 10 }, // EXT_IO_07(QSFP#09)
    { QSFP_CTRL1_BASE_ADDR, 0x0007, QSFP_1_BASE_ADDR,  7 }, // EXT_IO_08(QSFP#06)

    { QSFP_CTRL2_BASE_ADDR, 0x0000, QSFP_2_BASE_ADDR, 11 }, // EXT_IO_09(QSFP#10)
    { QSFP_CTRL2_BASE_ADDR, 0x0001, QSFP_2_BASE_ADDR,  8 }, // EXT_IO_10(QSFP#07)
    { QSFP_CTRL2_BASE_ADDR, 0x0002, QSFP_2_BASE_ADDR, 12 }, // EXT_IO_11(QSFP#11)
    { QSFP_CTRL2_BASE_ADDR, 0x0003, QSFP_2_BASE_ADDR,  9 }, // EXT_IO_12(QSFP#08)
    { QSFP_CTRL2_BASE_ADDR, 0x0004, QSFP_2_BASE_ADDR, 16 }, // EXT_IO_13(QSFP#15)
    { QSFP_CTRL2_BASE_ADDR, 0x0005, QSFP_2_BASE_ADDR, 13 }, // EXT_IO_14(QSFP#12)
    { QSFP_CTRL2_BASE_ADDR, 0x0006, QSFP_2_BASE_ADDR, 17 }, // EXT_IO_15(QSFP#16)
    { QSFP_CTRL2_BASE_ADDR, 0x0007, QSFP_2_BASE_ADDR, 14 }, // EXT_IO_16(QSFP#13)

    { QSFP_CTRL3_BASE_ADDR, 0x0000, QSFP_3_BASE_ADDR, 18 }, // EXT_IO_17(QSFP#17)
    { QSFP_CTRL3_BASE_ADDR, 0x0001, QSFP_3_BASE_ADDR, 15 }, // EXT_IO_18(QSFP#14)
    { QSFP_CTRL3_BASE_ADDR, 0x0002, QSFP_3_BASE_ADDR, 22 }, // EXT_IO_19(QSFP#21)
    { QSFP_CTRL3_BASE_ADDR, 0x0003, QSFP_3_BASE_ADDR, 19 }, // EXT_IO_20(QSFP#18)
    { QSFP_CTRL3_BASE_ADDR, 0x0004, QSFP_3_BASE_ADDR, 23 }, // EXT_IO_21(QSFP#22)
    { QSFP_CTRL3_BASE_ADDR, 0x0005, QSFP_3_BASE_ADDR, 20 }, // EXT_IO_22(QSFP#19)
    { QSFP_CTRL3_BASE_ADDR, 0x0006, QSFP_3_BASE_ADDR, 24 }, // EXT_IO_23(QSFP#23)
    { QSFP_CTRL3_BASE_ADDR, 0x0007, QSFP_3_BASE_ADDR, 21 }, // EXT_IO_24(QSFP#20)
};

static const struct i2c_settings RETIMER_SETTINGS_REV12[] = {
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0xfc, 0x01, 0xff }, // Set to reading channel is 0
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0xff, 0x03, 0x03 }, // Set to broadcast mode
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x00, 0x04, 0x04 }, // All channel register reset
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x0a, 0x0c, 0x0c }, // CDR reset
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x2f, 0x50, 0xf0 }, // Data rate set to 25.78125Gbps
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3d, 0x80, 0x80 }, // FIR Enable
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3d, 0x0a, 0x1f }, // Set Main-cursor tap magnitude
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3f, 0x02, 0x0f }, // Set Post-cursor tap magnitude
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3e, 0x01, 0x0f }, // Set Pre-cursor tap magnitude
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x0a, 0x00, 0x0c }, // CDR reset release
};

static const struct i2c_settings RETIMER_SETTINGS_REV13[] = {
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0xfc, 0x01, 0xff }, // Set to reading channel is 0
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0xff, 0x03, 0x03 }, // Set to broadcast mode
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x00, 0x04, 0x04 }, // All channel register reset
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3f, 0x40, 0x40 }, // Post-cursor sign bit
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3e, 0x40, 0x40 }, // Pre-cursor sign bit
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x0a, 0x0c, 0x0c }, // CDR reset
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x2f, 0x50, 0xf0 }, // Data rate set to 25.78125Gbps
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3d, 0x80, 0x80 }, // FIR Enable
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3d, 0x0a, 0x1f }, // Set Main-cursor tap magnitude
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3f, 0x00, 0x0f }, // Set Post-cursor tap magnitude
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x3e, 0x01, 0x0f }, // Set Pre-cursor tap magnitude
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, 0x0a, 0x00, 0x0c }, // CDR reset release
};

static const u32 RTM_CDR_RESET_ADDRS[][3] = {
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, RETIMER_UP },     // EXT_IO_01 ( QSFP#03 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM0, RETIMER_DOWN },   // EXT_IO_02 ( QSFP#00 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM1, RETIMER_UP },     // EXT_IO_03 ( QSFP#04 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM1, RETIMER_DOWN },   // EXT_IO_04 ( QSFP#01 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM2, RETIMER_UP },     // EXT_IO_05 ( QSFP#05 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM2, RETIMER_DOWN },   // EXT_IO_06 ( QSFP#02 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM3, RETIMER_UP },     // EXT_IO_07 ( QSFP#09 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM3, RETIMER_DOWN },   // EXT_IO_08 ( QSFP#06 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM4, RETIMER_UP },     // EXT_IO_09 ( QSFP#10 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM4, RETIMER_DOWN },   // EXT_IO_10 ( QSFP#07 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM5, RETIMER_UP },     // EXT_IO_11 ( QSFP#11 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM5, RETIMER_DOWN },   // EXT_IO_12 ( QSFP#08 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM6, RETIMER_UP },     // EXT_IO_13 ( QSFP#15 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM6, RETIMER_DOWN },   // EXT_IO_14 ( QSFP#12 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM7, RETIMER_UP },     // EXT_IO_15 ( QSFP#16 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM7, RETIMER_DOWN },   // EXT_IO_16 ( QSFP#13 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM8, RETIMER_UP },     // EXT_IO_17 ( QSFP#17 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM8, RETIMER_DOWN },   // EXT_IO_18 ( QSFP#14 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM9, RETIMER_UP },     // EXT_IO_19 ( QSFP#21 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM9, RETIMER_DOWN },   // EXT_IO_20 ( QSFP#18 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM10, RETIMER_UP },    // EXT_IO_21 ( QSFP#22 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM10, RETIMER_DOWN },  // EXT_IO_22 ( QSFP#19 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM11, RETIMER_UP },    // EXT_IO_23 ( QSFP#23 )
    { RTM_BASE_ADDR, I2C_SLAVE_ADDR_RTM11, RETIMER_DOWN },  // EXT_IO_24 ( QSFP#20 )
};

static const u32 RETIMER_CDR_RESET_SETTINGS[2][6][4] = {
    {
        { 0xff, 0x01, 0x03, 0 }, // Enables SMBUS access to the channels specified int Reg_0xFC
        { 0xfc, 0x0f, 0xff, 0 }, // Set to writing channel is 0-3
        { 0x0a, 0x0c, 0x00, 1 }, // CDR reset ( after 1msec sleep )
        { 0x0a, 0x00, 0x00, 0 }, // CDR reset release
        { 0xfc, 0x01, 0xff, 0 }, // Set to reading channel is 0
        { 0xff, 0x03, 0x03, 0 }, // Set to broadcast mode
    },
    {
        { 0xff, 0x01, 0x03, 0 }, // Enables SMBUS access to the channels specified int Reg_0xFC
        { 0xfc, 0xf0, 0xff, 0 }, // Set to writing channel is 4-7
        { 0x0a, 0x0c, 0x00, 1 }, // CDR reset ( after 1msec sleep )
        { 0x0a, 0x00, 0x00, 0 }, // CDR reset release
        { 0xfc, 0x01, 0xff, 0 }, // Set to reading channel is 0
        { 0xff, 0x03, 0x03, 0 }, // Set to broadcast mode
    }
};
static const u32 RTM_SLAVE_ADDRS[] = {
    I2C_SLAVE_ADDR_RTM0,
    I2C_SLAVE_ADDR_RTM1,
    I2C_SLAVE_ADDR_RTM2,
    I2C_SLAVE_ADDR_RTM3,
    I2C_SLAVE_ADDR_RTM4,
    I2C_SLAVE_ADDR_RTM5,
    I2C_SLAVE_ADDR_RTM6,
    I2C_SLAVE_ADDR_RTM7,
    I2C_SLAVE_ADDR_RTM8,
    I2C_SLAVE_ADDR_RTM9,
    I2C_SLAVE_ADDR_RTM10,
    I2C_SLAVE_ADDR_RTM11,
};

const u32 qsfp_number_resolve[][2] = {
    { I2C_QSFP_CTRL_1, 1 }, // QSFP1
    { I2C_QSFP_CTRL_1, 3 }, // QSFP2
    { I2C_QSFP_CTRL_1, 5 }, // QSFP3
    { I2C_QSFP_CTRL_1, 0 }, // QSFP4
    { I2C_QSFP_CTRL_1, 2 }, // QSFP5
    { I2C_QSFP_CTRL_1, 4 }, // QSFP6
    { I2C_QSFP_CTRL_1, 7 }, // QSFP7
    { I2C_QSFP_CTRL_2, 1 }, // QSFP8
    { I2C_QSFP_CTRL_2, 3 }, // QSFP9
    { I2C_QSFP_CTRL_1, 6 }, // QSFP10
    { I2C_QSFP_CTRL_2, 0 }, // QSFP11
    { I2C_QSFP_CTRL_2, 2 }, // QSFP12
    { I2C_QSFP_CTRL_2, 5 }, // QSFP13
    { I2C_QSFP_CTRL_2, 7 }, // QSFP14
    { I2C_QSFP_CTRL_3, 1 }, // QSFP15
    { I2C_QSFP_CTRL_2, 4 }, // QSFP16
    { I2C_QSFP_CTRL_2, 6 }, // QSFP17
    { I2C_QSFP_CTRL_3, 0 }, // QSFP18
    { I2C_QSFP_CTRL_3, 3 }, // QSFP19
    { I2C_QSFP_CTRL_3, 5 }, // QSFP20
    { I2C_QSFP_CTRL_3, 7 }, // QSFP21
    { I2C_QSFP_CTRL_3, 2 }, // QSFP22
    { I2C_QSFP_CTRL_3, 4 }, // QSFP23
    { I2C_QSFP_CTRL_3, 6 }, // QSFP24
};

static const u32 TX_POLARITY_SETTING[2][8][2] = {
    { // XPT-42-21以降
        { 0x000080fc, 0x000b0b0a },  // EXT_IO 06/04/02
        { 0x000082fc, 0x00000206 },  // EXT_IO 05/03/01
        { 0x000084fc, 0x00030303 },  // EXT_IO 12/10/08
        { 0x000086fc, 0x00000000 },  // EXT_IO 11/09/07
        { 0x000088fc, 0x000a0904 },  // EXT_IO 18/16/14
        { 0x00008afc, 0x00080201 },  // EXT_IO 17/15/13
        { 0x00008cfc, 0x000a0a0a },  // EXT_IO 24/22/20
        { 0x00008efc, 0x00080808 }   // EXT_IO 23/21/19
    },
    { // XPT-42-13以前
        { 0x000080fc, 0x00000000 },  // EXT_IO 06/04/02
        { 0x000082fc, 0x00000000 },  // EXT_IO 05/03/01
        { 0x000084fc, 0x00000000 },  // EXT_IO 12/10/08
        { 0x000086fc, 0x00000000 },  // EXT_IO 11/09/07
        { 0x000088fc, 0x00000000 },  // EXT_IO 18/16/14
        { 0x00008afc, 0x00000000 },  // EXT_IO 17/15/13
        { 0x00008cfc, 0x00000000 },  // EXT_IO 24/22/20
        { 0x00008efc, 0x00000000 }   // EXT_IO 23/21/19
    }
};

static const u32 TX_DIFFCTRL_SETTING[2][24][2] = {
    { // XPT-42-21以降
        { 0x000080d0, 0x10101010 },  // QSFP#00 780mV
        { 0x000080d4, 0x10101010 },  // QSFP#01 780mV
        { 0x000080d8, 0x10101010 },  // QSFP#02 780mV
        { 0x000082d0, 0x10101010 },  // QSFP#03 780mV
        { 0x000082d4, 0x10101010 },  // QSFP#04 780mV
        { 0x000082d8, 0x10101010 },  // QSFP#05 780mV
        { 0x000084d0, 0x10101010 },  // QSFP#06 780mV
        { 0x000084d4, 0x10101010 },  // QSFP#07 780mV
        { 0x000084d8, 0x10101010 },  // QSFP#08 780mV
        { 0x000086d0, 0x10101010 },  // QSFP#09 780mV
        { 0x000086d4, 0x10101010 },  // QSFP#10 780mV
        { 0x000086d8, 0x10101010 },  // QSFP#11 780mV
        { 0x000088d0, 0x10101010 },  // QSFP#12 780mV
        { 0x000088d4, 0x10101010 },  // QSFP#13 780mV
        { 0x000088d8, 0x10101010 },  // QSFP#14 780mV
        { 0x00008ad0, 0x10101010 },  // QSFP#15 780mV
        { 0x00008ad4, 0x10101010 },  // QSFP#16 780mV
        { 0x00008ad8, 0x10101010 },  // QSFP#17 780mV
        { 0x00008cd0, 0x10101010 },  // QSFP#18 780mV
        { 0x00008cd4, 0x10101010 },  // QSFP#19 780mV
        { 0x00008cd8, 0x10101010 },  // QSFP#20 780mV
        { 0x00008ed0, 0x10101010 },  // QSFP#21 780mV
        { 0x00008ed4, 0x10101010 },  // QSFP#22 780mV
        { 0x00008ed8, 0x10101010 },  // QSFP#23 780mV
    },
    { // XPT-42-13以前
        { 0x000080d0, 0x0b0b0b0b },  // QSFP#00 670mV
        { 0x000080d4, 0x0b0b0b0b },  // QSFP#01 670mV
        { 0x000080d8, 0x0b0b0b0b },  // QSFP#02 670mV
        { 0x000082d0, 0x0b0b0b0b },  // QSFP#03 670mV
        { 0x000082d4, 0x0b0b0b0b },  // QSFP#04 670mV
        { 0x000082d8, 0x0b0b0b0b },  // QSFP#05 670mV
        { 0x000084d0, 0x0b0b0b0b },  // QSFP#06 670mV
        { 0x000084d4, 0x0b0b0b0b },  // QSFP#07 670mV
        { 0x000084d8, 0x0b0b0b0b },  // QSFP#08 670mV
        { 0x000086d0, 0x0b0b0b0b },  // QSFP#09 670mV
        { 0x000086d4, 0x0b0b0b0b },  // QSFP#10 670mV
        { 0x000086d8, 0x0b0b0b0b },  // QSFP#11 670mV
        { 0x000088d0, 0x0b0b0b0b },  // QSFP#12 670mV
        { 0x000088d4, 0x0b0b0b0b },  // QSFP#13 670mV
        { 0x000088d8, 0x0b0b0b0b },  // QSFP#14 670mV
        { 0x00008ad0, 0x0b0b0b0b },  // QSFP#15 670mV
        { 0x00008ad4, 0x0b0b0b0b },  // QSFP#16 670mV
        { 0x00008ad8, 0x0b0b0b0b },  // QSFP#17 670mV
        { 0x00008cd0, 0x0b0b0b0b },  // QSFP#18 670mV
        { 0x00008cd4, 0x0b0b0b0b },  // QSFP#19 670mV
        { 0x00008cd8, 0x0b0b0b0b },  // QSFP#20 670mV
        { 0x00008ed0, 0x0b0b0b0b },  // QSFP#21 670mV
        { 0x00008ed4, 0x0b0b0b0b },  // QSFP#22 670mV
        { 0x00008ed8, 0x0b0b0b0b },  // QSFP#23 670mV
    },
};

static const u32 TX_PRECURSOR_SETTING[2][24][2] = {
    { // XPT-42-21以降
        { 0x000080f0, 0x05050505 },  // QSFP#00 1.17dB
        { 0x000080f4, 0x05050505 },  // QSFP#01 1.17dB
        { 0x000080f8, 0x05050505 },  // QSFP#02 1.17dB
        { 0x000082f0, 0x05050505 },  // QSFP#03 1.17dB
        { 0x000082f4, 0x05050505 },  // QSFP#04 1.17dB
        { 0x000082f8, 0x05050505 },  // QSFP#05 1.17dB
        { 0x000084f0, 0x05050505 },  // QSFP#06 1.17dB
        { 0x000084f4, 0x05050505 },  // QSFP#07 1.17dB
        { 0x000084f8, 0x05050505 },  // QSFP#08 1.17dB
        { 0x000086f0, 0x05050505 },  // QSFP#09 1.17dB
        { 0x000086f4, 0x05050505 },  // QSFP#10 1.17dB
        { 0x000086f8, 0x05050505 },  // QSFP#11 1.17dB
        { 0x000088f0, 0x05050505 },  // QSFP#12 1.17dB
        { 0x000088f4, 0x05050505 },  // QSFP#13 1.17dB
        { 0x000088f8, 0x05050505 },  // QSFP#14 1.17dB
        { 0x00008af0, 0x05050505 },  // QSFP#15 1.17dB
        { 0x00008af4, 0x05050505 },  // QSFP#16 1.17dB
        { 0x00008af8, 0x05050505 },  // QSFP#17 1.17dB
        { 0x00008cf0, 0x05050505 },  // QSFP#18 1.17dB
        { 0x00008cf4, 0x05050505 },  // QSFP#19 1.17dB
        { 0x00008cf8, 0x05050505 },  // QSFP#20 1.17dB
        { 0x00008ef0, 0x05050505 },  // QSFP#21 1.17dB
        { 0x00008ef4, 0x05050505 },  // QSFP#22 1.17dB
        { 0x00008ef8, 0x05050505 },  // QSFP#23 1.17dB
    },
    { // XPT-42-13以前
        { 0x000080f0, 0x01010101 },  // QSFP#00 0.20dB
        { 0x000080f4, 0x01010101 },  // QSFP#01 0.20dB
        { 0x000080f8, 0x01010101 },  // QSFP#02 0.20dB
        { 0x000082f0, 0x01010101 },  // QSFP#03 0.20dB
        { 0x000082f4, 0x01010101 },  // QSFP#04 0.20dB
        { 0x000082f8, 0x01010101 },  // QSFP#05 0.20dB
        { 0x000084f0, 0x01010101 },  // QSFP#06 0.20dB
        { 0x000084f4, 0x01010101 },  // QSFP#07 0.20dB
        { 0x000084f8, 0x01010101 },  // QSFP#08 0.20dB
        { 0x000086f0, 0x01010101 },  // QSFP#09 0.20dB
        { 0x000086f4, 0x01010101 },  // QSFP#10 0.20dB
        { 0x000086f8, 0x01010101 },  // QSFP#11 0.20dB
        { 0x000088f0, 0x01010101 },  // QSFP#12 0.20dB
        { 0x000088f4, 0x01010101 },  // QSFP#13 0.20dB
        { 0x000088f8, 0x01010101 },  // QSFP#14 0.20dB
        { 0x00008af0, 0x01010101 },  // QSFP#15 0.20dB
        { 0x00008af4, 0x01010101 },  // QSFP#16 0.20dB
        { 0x00008af8, 0x01010101 },  // QSFP#17 0.20dB
        { 0x00008cf0, 0x01010101 },  // QSFP#18 0.20dB
        { 0x00008cf4, 0x01010101 },  // QSFP#19 0.20dB
        { 0x00008cf8, 0x01010101 },  // QSFP#20 0.20dB
        { 0x00008ef0, 0x01010101 },  // QSFP#21 0.20dB
        { 0x00008ef4, 0x01010101 },  // QSFP#22 0.20dB
        { 0x00008ef8, 0x01010101 },  // QSFP#23 0.20dB
    }
};

static const u32 TX_EQUALIZER_SETTINGS_REV21[] = {
    0x55, // EXT_IO_01
    0x88, // EXT_IO_02
    0x55, // EXT_IO_03
    0x77, // EXT_IO_04
    0x55, // EXT_IO_05
    0x55, // EXT_IO_06
    0x44, // EXT_IO_07
    0x55, // EXT_IO_08
    0x33, // EXT_IO_09
    0x55, // EXT_IO_10
    0x33, // EXT_IO_11
    0x44, // EXT_IO_12
    0x33, // EXT_IO_13
    0x44, // EXT_IO_14
    0x33, // EXT_IO_15
    0x44, // EXT_IO_16
    0x33, // EXT_IO_17
    0x44, // EXT_IO_18
    0x44, // EXT_IO_19
    0x44, // EXT_IO_20
    0x44, // EXT_IO_21
    0x66, // EXT_IO_22
    0x55, // EXT_IO_23
    0x66  // EXT_IO_24
};

static int sony_fpga_xpt_read_thresholds(void __iomem* base_addr, u32 start_address, struct qsfp_thresholds* thresholds, u32 qsfp_number)
{
    u8 value[8];
    struct i2c_dev_info dev_info;
    dev_info.addr_size = 1;
    dev_info.slave_addr = I2C_SLAVE_ADDR_QSFP;
    // Page3に設定されていることが前提

    // thresholds読み出し
    if (i2c_rx(base_addr, &dev_info, start_address, value, 8) < 0) {
        pr_err("thresholds read error %d\n", qsfp_number);
        return -1;
    }
    thresholds->high_alarm = value[0] << 8 | value[1];
    thresholds->low_alarm = value[2] << 8 | value[3];
    thresholds->high_warning = value[4] << 8 | value[5];
    thresholds->low_warning = value[6] << 8 | value[7];
    return 0;
}

static void chop_space(u8* str, u32 last)
{
    u32 i = 0;
    for (i = last; i > 0; i--) {
        if (str[i] == 0x20) {
            str[i] = 0x00;
        } else {
            break;
        }
    }
}

int sony_fpga_xpt_qsfp_setting(struct sony_fpga_ctrl* ctrl_data, u32 qsfp_number)
{
    u8 value[2];
    u8 vendor[17];
    u8 part[17];

    u32 ctrl_num = 0;
    u32 extio_num = 0;
    u32 setting_num = 0;
    u32 board_revision = 0;
    u32 tx_equalizer_enable = 0;
    u32 tx_equalizer_setting = 0;
    struct qsfp_status* qsfp_status = NULL;

    void __iomem* bar0_addr;
    struct i2c_dev_info dev_info;
    dev_info.addr_size = 1;

    vendor[16] = 0x00;
    part[16] = 0x00;
    if (qsfp_number > 23) {
        return -EINVAL;
    }
    ctrl_num  = qsfp_number_resolve[qsfp_number][0];
    extio_num = qsfp_number_resolve[qsfp_number][1];
    setting_num = ctrl_num * 8 + extio_num;

    qsfp_status = &(ctrl_data->qsfp_ctrl[ctrl_num].status[extio_num]);
    if (qsfp_status->mod_prs_l == 0) {
        pr_info("[%d] qsfp[%d][%d] is not present\n", setting_num, ctrl_num, extio_num);
        return 0;
    }

    bar0_addr = ctrl_data->bar[FPGA_CTRL_BAR];
    // buffer select
    if (qsfp_select(bar0_addr + QSFP_SETTINGS[setting_num][0], QSFP_SETTINGS[setting_num][1]) < 0) {
        return 0;
    }

    // setting
    dev_info.slave_addr = I2C_SLAVE_ADDR_QSFP;

    msleep(100);
    // vendor nameをロギング
    if (i2c_rx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0x94, vendor, 16) < 0) {
        pr_info("QSFP%d(io:%d) Skip QSFP Setting I2C Read Error\n", qsfp_number, setting_num);
        qsfp_status->initialized = true;
        return 0;
    }
    chop_space(vendor, 15);
    if (i2c_rx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xa8, part, 16) < 0) {
        pr_info("QSFP%d(io:%d) Skip QSFP Setting I2C Read Error\n", qsfp_number, setting_num);
        qsfp_status->initialized = true;
        return 0;
    }
    chop_space(part, 15);

    pr_info("QSFP%d(io:%d) vendor name=[%s], vendor part number=[%s]", qsfp_number, setting_num, vendor, part);

    // Page select
    value[0] = 0x03;
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0x7f, value, 1) < 0) {
        pr_err("page select error %d\n", qsfp_number);
        return 0;
    }
    msleep(1);

    // thresholds読み出し
    if (sony_fpga_xpt_read_thresholds(bar0_addr + QSFP_SETTINGS[setting_num][2], 176, &(qsfp_status->rx_power_threshold), qsfp_number) < 0) {
        return 0;
    }
    if (sony_fpga_xpt_read_thresholds(bar0_addr + QSFP_SETTINGS[setting_num][2], 192, &(qsfp_status->tx_power_threshold), qsfp_number) < 0) {
        return 0;
    }

    board_revision = BOARD_REVISION(ctrl_data->local_id);
    // TXイコライザ有効化
    switch (board_revision) {
    case XPT_BOARD_REV11:
    case XPT_BOARD_REV12:
        tx_equalizer_enable = 0x0f;
        tx_equalizer_setting = 0x22;
        break;
    case XPT_BOARD_REV13:
        tx_equalizer_enable = 0x00;
        tx_equalizer_setting = 0x11;
        break;
    case XPT_BOARD_REV21:
        tx_equalizer_enable = 0x00;
        tx_equalizer_setting = TX_EQUALIZER_SETTINGS_REV21[extio_num];
        break;
    default:
        pr_err("Illegal Board Revision %02x\n", board_revision);
        return 0;
    }

    value[0] = tx_equalizer_enable;
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xf1, value, 1) < 0) {
        pr_err("tx equalizer enable error %d\n", qsfp_number);
        return 0;
    }
    // TXイコライザ設定
    value[0] = tx_equalizer_setting;
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xea, value, 1) < 0) {
        pr_err("tx equalizer setting error %d\n", qsfp_number);
        return 0;
    }
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xeb, value, 1) < 0) {
        pr_err("tx equalizer setting error %d\n", qsfp_number);
        return 0;
    }
    // RXエンファシス設定
    value[0] = 0x00;
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xec, value, 1) < 0) {
        pr_err("rx emphasis setting error %d\n", qsfp_number);
        return 0;
    }
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xed, value, 1) < 0) {
        pr_err("rx emphasis setting error %d\n", qsfp_number);
        return 0;
    }
    // RX振幅値設定
    value[0] = 0x22;
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xee, value, 1) < 0) {
        pr_err("rx freq setting error %d\n", qsfp_number);
        return 0;
    }
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0xef, value, 1) < 0) {
        pr_err("rx freq setting error %d\n", qsfp_number);
        return 0;
    }
    value[0] = 0x00;
    if (i2c_tx(bar0_addr + QSFP_SETTINGS[setting_num][2], &dev_info, 0x7f, value, 1) < 0) {
        pr_err("page reset error %d\n", qsfp_number);
        return 0;
    }
    msleep(1);
    pr_info("qsfp initialized %d\n", qsfp_number);
    qsfp_status->initialized = true;
    return 0;
}

int sony_fpga_xpt_qsfp_cdr_reset(struct sony_fpga_ctrl* ctrl_data, u32 qsfp_number)
{
    u32 ctrl_num = 0;
    u32 extio_num = 0;
    u32 setting_num = 0;
    u32 i;

    void __iomem* bar0_addr;
    struct i2c_dev_info dev_info;
    dev_info.addr_size = 1;

    if (qsfp_number > 23) {
        return -EINVAL;
    }
    if (BOARD_REVISION(ctrl_data->local_id) >= XPT_BOARD_REV21) {
        return 0;
    }

    ctrl_num  = qsfp_number_resolve[qsfp_number][0];
    extio_num = qsfp_number_resolve[qsfp_number][1];
    setting_num = ctrl_num * 8 + extio_num;

    if (ctrl_data->qsfp_ctrl[ctrl_num].status[extio_num].mod_prs_l == 0) {
        pr_info("[%d] qsfp[%d][%d] is not present\n", setting_num, ctrl_num, extio_num);
        return 0;
    }

    bar0_addr = ctrl_data->bar[FPGA_CTRL_BAR];

    // setting
    dev_info.slave_addr = RTM_CDR_RESET_ADDRS[setting_num][1];

    for (i = 0; i < 6; i++) {
        u32 addr = RETIMER_CDR_RESET_SETTINGS[RTM_CDR_RESET_ADDRS[setting_num][2]][i][0];
        u32 mask = RETIMER_CDR_RESET_SETTINGS[RTM_CDR_RESET_ADDRS[setting_num][2]][i][2];
        u32 data = RETIMER_CDR_RESET_SETTINGS[RTM_CDR_RESET_ADDRS[setting_num][2]][i][1];
        u32 wait = RETIMER_CDR_RESET_SETTINGS[RTM_CDR_RESET_ADDRS[setting_num][2]][i][3];
        u8 value = 0;

        if (mask != 0) {
            if (i2c_rx(bar0_addr + RTM_BASE_ADDR, &dev_info, addr, &value, 1) < 0) {
                pr_err("cdr_reset rx error\n");
                return -EFAULT;
            }
            value &= ~mask;
        }
        value |= data;

        if (i2c_tx(bar0_addr + RTM_BASE_ADDR, &dev_info, addr, &value, 1) < 0) {
            pr_err("cdr_reset tx error\n");
            return -EFAULT;
        }
        if (wait > 0) {
            msleep(wait);
        }
    }
    return 0;
}
int sony_fpga_xpt_fpga_probe(struct sony_fpga_ctrl* ctrl)
{
    void __iomem *bar0_addr;
    uint i = 0;
    struct i2c_dev_info dev_info = {0};
    u32 revision;
    u32 board_revision = 0;
    uint8_t fpga_setting_index = 0;
    void __iomem* addr;
    uint i2c_count = I2C_MAX;

    if (ctrl == NULL) {
        pr_err("ctrl is null\n");
        return -EFAULT;
    }

    bar0_addr = ctrl->bar[FPGA_CTRL_BAR];

    board_revision = BOARD_REVISION(ctrl->local_id);
    pr_info("XPT Borad Revision is %d\n", board_revision);
    switch (board_revision) {
    case XPT_BOARD_REV11:
    case XPT_BOARD_REV12:
        qsfp_detect_function = qsfp_detect_ioexpander;
        revision = 0;
        fpga_setting_index = 1;
        break;
    case XPT_BOARD_REV13:
        qsfp_detect_function = qsfp_detect_gpio;
        revision = 1;
        fpga_setting_index = 1;
        break;
    default:
        if (board_revision >= XPT_BOARD_REV21) {
            qsfp_detect_function = qsfp_detect_gpio;
            revision = 2;
            fpga_setting_index = 0;
            i2c_count = I2C_RTM;
        } else {
            pr_err("Illegal XPT Board Revision");
            return -EFAULT;
        }
        break;
    }

    ctrl->i2c_index = i2c_count - 1;

    ctrl->qsfp_ctrl = kzalloc(sizeof(struct qsfp_control) * i2c_count, GFP_KERNEL);
    for (i = 0; i < i2c_count; i++) {
        ctrl->qsfp_ctrl[i].fpga_ctrl_addr = ctrl;
        ctrl->qsfp_ctrl[i].ctrl_addr = qsfp_addrs[i][0];
        ctrl->qsfp_ctrl[i].io_expander_addr = qsfp_addrs[i][1];
        ctrl->qsfp_ctrl[i].ctrl_index = i;
        ctrl->qsfp_ctrl[i].poll_thread = NULL;
        mutex_init(&(ctrl->qsfp_ctrl[i].qsfp_mutex));

        // I2Cドライバ初期化
        i2c_driver_init(ctrl->qsfp_ctrl[i].ctrl_addr + bar0_addr);
        if (ctrl->qsfp_ctrl[i].io_expander_addr != 0) {
            i2c_driver_init(ctrl->qsfp_ctrl[i].io_expander_addr + bar0_addr);
        }
        ctrl->qsfp_ctrl[i].counter = 0;
        ctrl->qsfp_ctrl[i].pause = false;
    }

    dev_info.addr_size = 1;
    // I/O Expanderの初期化
    ARRAY_FOREACH(IO_EXPANDER_SETTINGS, i) {
        // 末尾21基板以降はRetimer非搭載のため設定しない
        if (revision >= 2 && IO_EXPANDER_SETTINGS[i].pci_address == RTM_BASE_ADDR) {
            break;
        }
        dev_info.slave_addr = IO_EXPANDER_SETTINGS[i].slave_address;
        if (i2c_tx(bar0_addr + IO_EXPANDER_SETTINGS[i].pci_address,
               &dev_info,
               IO_EXPANDER_SETTINGS[i].i2c_address,
               (u8*)&IO_EXPANDER_SETTINGS[i].setting,
               1) < 0) {
            return -EFAULT;
        }
    }

    // QSFP Reset解除
    ARRAY_FOREACH(QSFP_RESET_RELEASE, i) {
        dev_info.slave_addr = QSFP_RESET_RELEASE[i].slave_address;
        if (i2c_tx(bar0_addr + QSFP_RESET_RELEASE[i].pci_address,
               &dev_info,
               QSFP_RESET_RELEASE[i].i2c_address,
               (u8*)&QSFP_RESET_RELEASE[i].setting,
               1) < 0) {;
            return -EFAULT;
        }
    }

    // QSFP検出
    dev_info.slave_addr = I2C_SLAVE_ADDR_IOEXPANDER3;
    for (i = 0; i < I2C_RTM; i++) {
        (*qsfp_detect_function)(&ctrl->qsfp_ctrl[i]);
    }

    // QSFP 設定
    for (i = 0; i < 24; i++) {
        sony_fpga_xpt_qsfp_setting(ctrl, i);
    }

    if (revision < 2) {
        // Retimer設定
        ARRAY_FOREACH(RTM_SLAVE_ADDRS, i) {
            u32 j = 0;
            u32 array_size;
            const struct i2c_settings* retimer_settings;
            retimer_settings = (revision == 0) ? RETIMER_SETTINGS_REV12 : RETIMER_SETTINGS_REV13;
            array_size = (revision == 0) ? sizeof(RETIMER_SETTINGS_REV12) / sizeof(struct i2c_settings) : sizeof(RETIMER_SETTINGS_REV13) / sizeof(struct i2c_settings);
            for (j = 0; j < array_size; j++) {
                u8 value = 0;
                dev_info.slave_addr = RTM_SLAVE_ADDRS[i];
                if (retimer_settings[j].mask != 0) {
                    if (i2c_rx(bar0_addr + retimer_settings[j].pci_address, &dev_info, retimer_settings[j].i2c_address, &value, 1) < 0) {
                        return -EFAULT;
                    }
                    value &= ~retimer_settings[j].mask;
                }
                value |= retimer_settings[j].setting;
                if (i2c_tx(bar0_addr + retimer_settings[j].pci_address, &dev_info, retimer_settings[j].i2c_address, &value, 1) < 0) {
                    return -EFAULT;
                }
            }
        }
    }

    // Aurora GT TX Polarity
    ARRAY_FOREACH(TX_POLARITY_SETTING[fpga_setting_index], i) {
        addr = (void __iomem*)(bar0_addr + TX_POLARITY_SETTING[fpga_setting_index][i][0]);
        IO_WRITE_32(TX_POLARITY_SETTING[fpga_setting_index][i][1], addr);
    }
    // Aurora GT TX Diffctrlの設定
    ARRAY_FOREACH(TX_DIFFCTRL_SETTING[fpga_setting_index], i) {
        addr = (void __iomem*)(bar0_addr + TX_DIFFCTRL_SETTING[fpga_setting_index][i][0]);
        IO_WRITE_32(TX_DIFFCTRL_SETTING[fpga_setting_index][i][1], addr);
    }
    // Aurora GT TX Precursorの設定
    ARRAY_FOREACH(TX_PRECURSOR_SETTING[fpga_setting_index], i) {
        addr = (void __iomem*)(bar0_addr + TX_PRECURSOR_SETTING[fpga_setting_index][i][0]);
        IO_WRITE_32(TX_PRECURSOR_SETTING[fpga_setting_index][i][1], addr);
    }

    for (i = 0; i < 3; i++) {
        char thread_name[] = "qsfp_poll_n";
        thread_name[strlen(thread_name)-1] = 0x31 + i;
        ctrl->qsfp_ctrl[i].poll_thread = kthread_create(qsfp_poll_thread, &ctrl->qsfp_ctrl[i], thread_name);
        if (IS_ERR(ctrl->qsfp_ctrl[i].poll_thread)) {
            pr_err("XPT Poll Thread %d is Error!!", i + 1);
            ctrl->qsfp_ctrl[i].poll_thread = NULL;
            return -EFAULT;
        }
    }

    kthread_bind(ctrl->qsfp_ctrl[0].poll_thread, 7);
    kthread_bind(ctrl->qsfp_ctrl[1].poll_thread, 8);
    kthread_bind(ctrl->qsfp_ctrl[2].poll_thread, 9);

    wake_up_process(ctrl->qsfp_ctrl[0].poll_thread);
    wake_up_process(ctrl->qsfp_ctrl[1].poll_thread);
    wake_up_process(ctrl->qsfp_ctrl[2].poll_thread);
    return 0;
}

int sony_fpga_xpt_i2c_request(struct sony_fpga_ctrl* ctrl, struct i2c_param* param, bool is_read)
{
    int ret;
    struct i2c_dev_info dev_info;
    dev_info.slave_addr = param->slave_addr;
    dev_info.addr_size = 1;

    ret = mutex_lock_interruptible(&(ctrl->qsfp_ctrl[param->i2c_bus].qsfp_mutex));
    if (ret != 0) {
        return ret;
    }
    if (is_read) {
        ret = i2c_rx(ctrl->bar[FPGA_CTRL_BAR] + param->pci_addr, &dev_info, param->i2c_addr, param->buff, param->size);
    } else {
        ret = i2c_tx(ctrl->bar[FPGA_CTRL_BAR] + param->pci_addr, &dev_info, param->i2c_addr, param->buff, param->size);
    }
    mutex_unlock(&(ctrl->qsfp_ctrl[param->i2c_bus].qsfp_mutex));
    return ret;
}

int sony_fpga_pause_qsfp_thread(struct sony_fpga_ctrl* ctrl, u32 qsfp_control)
{
    int ret;

    ret = mutex_lock_interruptible(&(ctrl->qsfp_ctrl[qsfp_control].qsfp_mutex));
    if (ret != 0) {
        return ret;
    }
    ctrl->qsfp_ctrl[qsfp_control].pause = true;
    mutex_unlock(&(ctrl->qsfp_ctrl[qsfp_control].qsfp_mutex));
    return ret;
}

int sony_fpga_resume_qsfp_thread(struct sony_fpga_ctrl* ctrl, u32 qsfp_control)
{
    int ret;

    ret = mutex_lock_interruptible(&(ctrl->qsfp_ctrl[qsfp_control].qsfp_mutex));
    if (ret != 0) {
        return ret;
    }
    ctrl->qsfp_ctrl[qsfp_control].pause = false;
    mutex_unlock(&(ctrl->qsfp_ctrl[qsfp_control].qsfp_mutex));
    return ret;
}
MODULE_LICENSE("Dual BSD/GPL");
