Загрузка данных
#define DRIVER_NAME "imx-lpi2c"
#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */
#define LPI2C_MCR 0x10 /* i2c contrl register */
#define LPI2C_MSR 0x14 /* i2c status register */
#define LPI2C_MIER 0x18 /* i2c interrupt enable */
#define LPI2C_MDER 0x1C /* i2c DMA enable */
#define LPI2C_MCFGR0 0x20 /* i2c master configuration */
#define LPI2C_MCFGR1 0x24 /* i2c master configuration */
#define LPI2C_MCFGR2 0x28 /* i2c master configuration */
#define LPI2C_MCFGR3 0x2C /* i2c master configuration */
#define LPI2C_MCCR0 0x48 /* i2c master clk configuration */
#define LPI2C_MCCR1 0x50 /* i2c master clk configuration */
#define LPI2C_MFCR 0x58 /* i2c master FIFO control */
#define LPI2C_MFSR 0x5C /* i2c master FIFO status */
#define LPI2C_MTDR 0x60 /* i2c master TX data register */
#define LPI2C_MRDR 0x70 /* i2c master RX data register */
#define LPI2C_SCR 0x110 /* i2c target contrl register */
#define LPI2C_SSR 0x114 /* i2c target status register */
#define LPI2C_SIER 0x118 /* i2c target interrupt enable */
#define LPI2C_SDER 0x11C /* i2c target DMA enable */
#define LPI2C_SCFGR0 0x120 /* i2c target configuration */
#define LPI2C_SCFGR1 0x124 /* i2c target configuration */
#define LPI2C_SCFGR2 0x128 /* i2c target configuration */
#define LPI2C_SAMR 0x140 /* i2c target address match */
#define LPI2C_SASR 0x150 /* i2c target address status */
#define LPI2C_STAR 0x154 /* i2c target transmit ACK */
#define LPI2C_STDR 0x160 /* i2c target transmit data */
#define LPI2C_SRDR 0x170 /* i2c target receive data */
#define LPI2C_SRDROR 0x178 /* i2c target receive data read only */
/* i2c command */
#define TRAN_DATA 0X00
#define RECV_DATA 0X01
#define GEN_STOP 0X02
#define RECV_DISCARD 0X03
#define GEN_START 0X04
#define START_NACK 0X05
#define START_HIGH 0X06
#define START_HIGH_NACK 0X07
#define MCR_MEN BIT(0)
#define MCR_RST BIT(1)
#define MCR_DOZEN BIT(2)
#define MCR_DBGEN BIT(3)
#define MCR_RTF BIT(8)
#define MCR_RRF BIT(9)
#define MSR_TDF BIT(0)
#define MSR_RDF BIT(1)
#define MSR_SDF BIT(9)
#define MSR_NDF BIT(10)
#define MSR_ALF BIT(11)
#define MSR_MBF BIT(24)
#define MSR_BBF BIT(25)
#define MIER_TDIE BIT(0)
#define MIER_RDIE BIT(1)
#define MIER_SDIE BIT(9)
#define MIER_NDIE BIT(10)
#define MCFGR1_AUTOSTOP BIT(8)
#define MCFGR1_IGNACK BIT(9)
#define MRDR_RXEMPTY BIT(14)
#define MDER_TDDE BIT(0)
#define MDER_RDDE BIT(1)
#define SCR_SEN BIT(0)
#define SCR_RST BIT(1)
#define SCR_FILTEN BIT(4)
#define SCR_RTF BIT(8)
#define SCR_RRF BIT(9)
#define SCFGR1_RXSTALL BIT(1)
#define SCFGR1_TXDSTALL BIT(2)
#define SCFGR2_FILTSDA_SHIFT 24
#define SCFGR2_FILTSCL_SHIFT 16
#define SCFGR2_CLKHOLD(x) (x)
#define SCFGR2_FILTSDA(x) ((x) << SCFGR2_FILTSDA_SHIFT)
#define SCFGR2_FILTSCL(x) ((x) << SCFGR2_FILTSCL_SHIFT)
#define SSR_TDF BIT(0)
#define SSR_RDF BIT(1)
#define SSR_AVF BIT(2)
#define SSR_TAF BIT(3)
#define SSR_RSF BIT(8)
#define SSR_SDF BIT(9)
#define SSR_BEF BIT(10)
#define SSR_FEF BIT(11)
#define SSR_SBF BIT(24)
#define SSR_BBF BIT(25)
#define SSR_CLEAR_BITS (SSR_RSF | SSR_SDF | SSR_BEF | SSR_FEF)
#define SIER_TDIE BIT(0)
#define SIER_RDIE BIT(1)
#define SIER_AVIE BIT(2)
#define SIER_TAIE BIT(3)
#define SIER_RSIE BIT(8)
#define SIER_SDIE BIT(9)
#define SIER_BEIE BIT(10)
#define SIER_FEIE BIT(11)
#define SIER_AM0F BIT(12)
#define SASR_READ_REQ 0x1
#define SLAVE_INT_FLAG (SIER_TDIE | SIER_RDIE | SIER_AVIE | \
SIER_SDIE | SIER_BEIE)
#define I2C_CLK_RATIO 2
#define I2C_CLK_HIGH 24
#define I2C_CLK_ALL 59
#define CHUNK_DATA 256
#define I2C_PM_TIMEOUT 1000 /* ms */
#define I2C_DMA_THRESHOLD 8 /* bytes */
enum lpi2c_imx_mode {
STANDARD, /* <=100Kbps */
FAST, /* <=400Kbps */
FAST_PLUS, /* <=1.0Mbps */
HS, /* <=3.4Mbps */
ULTRA_FAST, /* <=5.0Mbps */
};
enum lpi2c_imx_pincfg {
TWO_PIN_OD,
TWO_PIN_OO,
TWO_PIN_PP,
FOUR_PIN_PP,
};
struct lpi2c_imx_dma {
bool using_pio_mode;
u8 rx_cmd_buf_len;
u8 *dma_buf;
u16 *rx_cmd_buf;
unsigned int dma_len;
unsigned int tx_burst_num;
unsigned int rx_burst_num;
unsigned long dma_msg_flag;
resource_size_t phy_addr;
dma_addr_t dma_tx_addr;
dma_addr_t dma_addr;
enum dma_data_direction dma_direction;
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
};
struct lpi2c_imx_struct {
struct i2c_adapter adapter;
int num_clks;
struct clk_bulk_data *clks;
int irq;
void __iomem *base;
__u8 *rx_buf;
__u8 *tx_buf;
struct completion complete;
unsigned long rate_per;
unsigned int msglen;
unsigned int delivered;
unsigned int block_data;
unsigned int bitrate;
unsigned int txfifosize;
unsigned int rxfifosize;
enum lpi2c_imx_mode mode;
struct i2c_bus_recovery_info rinfo;
bool can_use_dma;
struct lpi2c_imx_dma *dma;
struct i2c_client *target;
};
static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
unsigned int enable)
{
writel(enable, lpi2c_imx->base + LPI2C_MIER);
}
static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned long orig_jiffies = jiffies;
unsigned int temp;
while (1) {
temp = readl(lpi2c_imx->base + LPI2C_MSR);
/* check for arbitration lost, clear if set */
if (temp & MSR_ALF) {
writel(temp, lpi2c_imx->base + LPI2C_MSR);
return -EAGAIN;
}
if (temp & (MSR_BBF | MSR_MBF))
break;
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
return -ETIMEDOUT;
}
schedule();
}
return 0;
}
static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int bitrate = lpi2c_imx->bitrate;
enum lpi2c_imx_mode mode;
if (bitrate <= I2C_MAX_STANDARD_MODE_FREQ)
mode = STANDARD;
else if (bitrate <= I2C_MAX_FAST_MODE_FREQ)
mode = FAST;
else if (bitrate <= I2C_MAX_FAST_MODE_PLUS_FREQ)
mode = FAST_PLUS;
else if (bitrate <= I2C_MAX_HIGH_SPEED_MODE_FREQ)
mode = HS;
else
mode = ULTRA_FAST;
lpi2c_imx->mode = mode;
}
static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
unsigned int temp;
temp = readl(lpi2c_imx->base + LPI2C_MCR);
temp |= MCR_RRF | MCR_RTF;
writel(temp, lpi2c_imx->base + LPI2C_MCR);
writel(0x7f00, lpi2c_imx->base + LPI2C_MSR);
temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
return lpi2c_imx_bus_busy(lpi2c_imx);
}