Загрузка данных


#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);
}