// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 MediaTek Inc.
* Author: Xudong Chen <xudong.chen@mediatek.com>
*/
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/sched.h>
#include <linux/slab.h>
#define I2C_RS_TRANSFER (1 << 4)
#define I2C_ARB_LOST (1 << 3)
#define I2C_HS_NACKERR (1 << 2)
#define I2C_ACKERR (1 << 1)
#define I2C_TRANSAC_COMP (1 << 0)
#define I2C_TRANSAC_START (1 << 0)
#define I2C_RS_MUL_CNFG (1 << 15)
#define I2C_RS_MUL_TRIG (1 << 14)
#define I2C_DCM_DISABLE 0x0000
#define I2C_IO_CONFIG_OPEN_DRAIN 0x0003
#define I2C_IO_CONFIG_PUSH_PULL 0x0000
#define I2C_SOFT_RST 0x0001
#define I2C_FIFO_ADDR_CLR 0x0001
#define I2C_DELAY_LEN 0x0002
#define I2C_ST_START_CON 0x8001
#define I2C_FS_START_CON 0x1800
#define I2C_TIME_CLR_VALUE 0x0000
#define I2C_TIME_DEFAULT_VALUE 0x0003
#define I2C_WRRD_TRANAC_VALUE 0x0002
#define I2C_RD_TRANAC_VALUE 0x0001
#define I2C_DMA_CON_TX 0x0000
#define I2C_DMA_CON_RX 0x0001
#define I2C_DMA_START_EN 0x0001
#define I2C_DMA_INT_FLAG_NONE 0x0000
#define I2C_DMA_CLR_FLAG 0x0000
#define I2C_DMA_HARD_RST 0x0002
#define I2C_DMA_4G_MODE 0x0001
#define I2C_DEFAULT_CLK_DIV 5
#define I2C_DEFAULT_SPEED 100000 /* hz */
#define MAX_FS_MODE_SPEED 400000
#define MAX_HS_MODE_SPEED 3400000
#define MAX_SAMPLE_CNT_DIV 8
#define MAX_STEP_CNT_DIV 64
#define MAX_HS_STEP_CNT_DIV 8
#define I2C_CONTROL_RS (0x1 << 1)
#define I2C_CONTROL_DMA_EN (0x1 << 2)
#define I2C_CONTROL_CLK_EXT_EN (0x1 << 3)
#define I2C_CONTROL_DIR_CHANGE (0x1 << 4)
#define I2C_CONTROL_ACKERR_DET_EN (0x1 << 5)
#define I2C_CONTROL_TRANSFER_LEN_CHANGE (0x1 << 6)
#define I2C_CONTROL_DMAACK_EN (0x1 << 8)
#define I2C_CONTROL_ASYNC_MODE (0x1 << 9)
#define I2C_CONTROL_WRAPPER (0x1 << 0)
#define I2C_DRV_NAME "i2c-mt65xx"
enum DMA_REGS_OFFSET {
OFFSET_INT_FLAG = 0x0,
OFFSET_INT_EN = 0x04,
OFFSET_EN = 0x08,
OFFSET_RST = 0x0c,
OFFSET_CON = 0x18,
OFFSET_TX_MEM_ADDR = 0x1c,
OFFSET_RX_MEM_ADDR = 0x20,
OFFSET_TX_LEN = 0x24,
OFFSET_RX_LEN = 0x28,
OFFSET_TX_4G_MODE = 0x54,
OFFSET_RX_4G_MODE = 0x58,
};
enum i2c_trans_st_rs {
I2C_TRANS_STOP = 0,
I2C_TRANS_REPEATED_START,
};
enum mtk_trans_op {
I2C_MASTER_WR = 1,
I2C_MASTER_RD,
I2C_MASTER_WRRD,
};
enum I2C_REGS_OFFSET {
OFFSET_DATA_PORT,
OFFSET_SLAVE_ADDR,
OFFSET_INTR_MASK,
OFFSET_INTR_STAT,
OFFSET_CONTROL,
OFFSET_TRANSFER_LEN,
OFFSET_TRANSAC_LEN,
OFFSET_DELAY_LEN,
OFFSET_TIMING,
OFFSET_START,
OFFSET_EXT_CONF,
OFFSET_FIFO_STAT,
OFFSET_FIFO_THRESH,
OFFSET_FIFO_ADDR_CLR,
OFFSET_IO_CONFIG,
OFFSET_RSV_DEBUG,
OFFSET_HS,
OFFSET_SOFTRESET,
OFFSET_DCM_EN,
OFFSET_PATH_DIR,
OFFSET_DEBUGSTAT,
OFFSET_DEBUGCTRL,
OFFSET_TRANSFER_LEN_AUX,
OFFSET_CLOCK_DIV,
OFFSET_LTIMING,
};
static const u16 mt_i2c_regs_v1[] = {
[OFFSET_DATA_PORT] = 0x0,
[OFFSET_SLAVE_ADDR] = 0x4,
[OFFSET_INTR_MASK] = 0x8,
[OFFSET_INTR_STAT] = 0xc,
[OFFSET_CONTROL] = 0x10,
[OFFSET_TRANSFER_LEN] = 0x14,
[OFFSET_TRANSAC_LEN] = 0x18,
[OFFSET_DELAY_LEN] = 0x1c,
[OFFSET_TIMING] = 0x20,
[OFFSET_START] = 0x24,
[OFFSET_EXT_CONF] = 0x28,
[OFFSET_FIFO_STAT] = 0x30,
[OFFSET_FIFO_THRESH] = 0x34,
[OFFSET_FIFO_ADDR_CLR] = 0x38,
[OFFSET_IO_CONFIG] = 0x40,
[OFFSET_RSV_DEBUG] = 0x44,
[OFFSET_HS] = 0x48,
[OFFSET_SOFTRESET] = 0x50,
[OFFSET_DCM_EN] = 0x54,
[OFFSET_PATH_DIR] = 0x60,
[OFFSET_DEBUGSTAT] = 0x64,
[OFFSET_DEBUGCTRL] = 0x68,
[OFFSET_TRANSFER_LEN_AUX] = 0x6c,
[OFFSET_CLOCK_DIV] = 0x70,
};
static const u16 mt_i2c_regs_v2[] = {
[OFFSET_DATA_PORT] = 0x0,
[OFFSET_SLAVE_ADDR] = 0x4,
[OFFSET_INTR_MASK] = 0x8,
[OFFSET_INTR_STAT] = 0xc,
[OFFSET_CONTROL] = 0x10,
[OFFSET_TRANSFER_LEN] = 0x14,
[OFFSET_TRANSAC_LEN] = 0x18,
[OFFSET_DELAY_LEN] = 0x1c,
[OFFSET_TIMING] = 0x20,
[OFFSET_START] = 0x24,
[OFFSET_EXT_CONF] = 0x28,
[OFFSET_LTIMING] = 0x2c,
[OFFSET_HS]