18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * TI OMAP I2C master mode driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2003 MontaVista Software, Inc.
68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Nokia Corporation
78c2ecf20Sopenharmony_ci * Copyright (C) 2004 - 2007 Texas Instruments.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Originally written by MontaVista Software, Inc.
108c2ecf20Sopenharmony_ci * Additional contributions by:
118c2ecf20Sopenharmony_ci *	Tony Lindgren <tony@atomide.com>
128c2ecf20Sopenharmony_ci *	Imre Deak <imre.deak@nokia.com>
138c2ecf20Sopenharmony_ci *	Juha Yrjölä <juha.yrjola@solidboot.com>
148c2ecf20Sopenharmony_ci *	Syed Khasim <x0khasim@ti.com>
158c2ecf20Sopenharmony_ci *	Nishant Menon <nm@ti.com>
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/delay.h>
208c2ecf20Sopenharmony_ci#include <linux/i2c.h>
218c2ecf20Sopenharmony_ci#include <linux/err.h>
228c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
238c2ecf20Sopenharmony_ci#include <linux/completion.h>
248c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
258c2ecf20Sopenharmony_ci#include <linux/clk.h>
268c2ecf20Sopenharmony_ci#include <linux/io.h>
278c2ecf20Sopenharmony_ci#include <linux/of.h>
288c2ecf20Sopenharmony_ci#include <linux/of_device.h>
298c2ecf20Sopenharmony_ci#include <linux/slab.h>
308c2ecf20Sopenharmony_ci#include <linux/platform_data/i2c-omap.h>
318c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
328c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* I2C controller revisions */
358c2ecf20Sopenharmony_ci#define OMAP_I2C_OMAP1_REV_2		0x20
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* I2C controller revisions present on specific hardware */
388c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_ON_2430		0x00000036
398c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_ON_3430_3530	0x0000003C
408c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_ON_3630		0x00000040
418c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_ON_4430_PLUS	0x50400002
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* timeout waiting for the controller to respond */
448c2ecf20Sopenharmony_ci#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* timeout for pm runtime autosuspend */
478c2ecf20Sopenharmony_ci#define OMAP_I2C_PM_TIMEOUT		1000	/* ms */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* timeout for making decision on bus free status */
508c2ecf20Sopenharmony_ci#define OMAP_I2C_BUS_FREE_TIMEOUT (msecs_to_jiffies(10))
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
538c2ecf20Sopenharmony_cienum {
548c2ecf20Sopenharmony_ci	OMAP_I2C_REV_REG = 0,
558c2ecf20Sopenharmony_ci	OMAP_I2C_IE_REG,
568c2ecf20Sopenharmony_ci	OMAP_I2C_STAT_REG,
578c2ecf20Sopenharmony_ci	OMAP_I2C_IV_REG,
588c2ecf20Sopenharmony_ci	OMAP_I2C_WE_REG,
598c2ecf20Sopenharmony_ci	OMAP_I2C_SYSS_REG,
608c2ecf20Sopenharmony_ci	OMAP_I2C_BUF_REG,
618c2ecf20Sopenharmony_ci	OMAP_I2C_CNT_REG,
628c2ecf20Sopenharmony_ci	OMAP_I2C_DATA_REG,
638c2ecf20Sopenharmony_ci	OMAP_I2C_SYSC_REG,
648c2ecf20Sopenharmony_ci	OMAP_I2C_CON_REG,
658c2ecf20Sopenharmony_ci	OMAP_I2C_OA_REG,
668c2ecf20Sopenharmony_ci	OMAP_I2C_SA_REG,
678c2ecf20Sopenharmony_ci	OMAP_I2C_PSC_REG,
688c2ecf20Sopenharmony_ci	OMAP_I2C_SCLL_REG,
698c2ecf20Sopenharmony_ci	OMAP_I2C_SCLH_REG,
708c2ecf20Sopenharmony_ci	OMAP_I2C_SYSTEST_REG,
718c2ecf20Sopenharmony_ci	OMAP_I2C_BUFSTAT_REG,
728c2ecf20Sopenharmony_ci	/* only on OMAP4430 */
738c2ecf20Sopenharmony_ci	OMAP_I2C_IP_V2_REVNB_LO,
748c2ecf20Sopenharmony_ci	OMAP_I2C_IP_V2_REVNB_HI,
758c2ecf20Sopenharmony_ci	OMAP_I2C_IP_V2_IRQSTATUS_RAW,
768c2ecf20Sopenharmony_ci	OMAP_I2C_IP_V2_IRQENABLE_SET,
778c2ecf20Sopenharmony_ci	OMAP_I2C_IP_V2_IRQENABLE_CLR,
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
818c2ecf20Sopenharmony_ci#define OMAP_I2C_IE_XDR		(1 << 14)	/* TX Buffer drain int enable */
828c2ecf20Sopenharmony_ci#define OMAP_I2C_IE_RDR		(1 << 13)	/* RX Buffer drain int enable */
838c2ecf20Sopenharmony_ci#define OMAP_I2C_IE_XRDY	(1 << 4)	/* TX data ready int enable */
848c2ecf20Sopenharmony_ci#define OMAP_I2C_IE_RRDY	(1 << 3)	/* RX data ready int enable */
858c2ecf20Sopenharmony_ci#define OMAP_I2C_IE_ARDY	(1 << 2)	/* Access ready int enable */
868c2ecf20Sopenharmony_ci#define OMAP_I2C_IE_NACK	(1 << 1)	/* No ack interrupt enable */
878c2ecf20Sopenharmony_ci#define OMAP_I2C_IE_AL		(1 << 0)	/* Arbitration lost int ena */
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* I2C Status Register (OMAP_I2C_STAT): */
908c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_XDR	(1 << 14)	/* TX Buffer draining */
918c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_RDR	(1 << 13)	/* RX Buffer draining */
928c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_BB	(1 << 12)	/* Bus busy */
938c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_ROVR	(1 << 11)	/* Receive overrun */
948c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_XUDF	(1 << 10)	/* Transmit underflow */
958c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_AAS	(1 << 9)	/* Address as slave */
968c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_BF	(1 << 8)	/* Bus Free */
978c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_XRDY	(1 << 4)	/* Transmit data ready */
988c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_RRDY	(1 << 3)	/* Receive data ready */
998c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_ARDY	(1 << 2)	/* Register access ready */
1008c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_NACK	(1 << 1)	/* No ack interrupt enable */
1018c2ecf20Sopenharmony_ci#define OMAP_I2C_STAT_AL	(1 << 0)	/* Arbitration lost int ena */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/* I2C WE wakeup enable register */
1048c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_XDR_WE	(1 << 14)	/* TX drain wakup */
1058c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_RDR_WE	(1 << 13)	/* RX drain wakeup */
1068c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_AAS_WE	(1 << 9)	/* Address as slave wakeup*/
1078c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_BF_WE	(1 << 8)	/* Bus free wakeup */
1088c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_STC_WE	(1 << 6)	/* Start condition wakeup */
1098c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_GC_WE	(1 << 5)	/* General call wakeup */
1108c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_DRDY_WE	(1 << 3)	/* TX/RX data ready wakeup */
1118c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_ARDY_WE	(1 << 2)	/* Reg access ready wakeup */
1128c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_NACK_WE	(1 << 1)	/* No acknowledgment wakeup */
1138c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_AL_WE	(1 << 0)	/* Arbitration lost wakeup */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define OMAP_I2C_WE_ALL		(OMAP_I2C_WE_XDR_WE | OMAP_I2C_WE_RDR_WE | \
1168c2ecf20Sopenharmony_ci				OMAP_I2C_WE_AAS_WE | OMAP_I2C_WE_BF_WE | \
1178c2ecf20Sopenharmony_ci				OMAP_I2C_WE_STC_WE | OMAP_I2C_WE_GC_WE | \
1188c2ecf20Sopenharmony_ci				OMAP_I2C_WE_DRDY_WE | OMAP_I2C_WE_ARDY_WE | \
1198c2ecf20Sopenharmony_ci				OMAP_I2C_WE_NACK_WE | OMAP_I2C_WE_AL_WE)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
1228c2ecf20Sopenharmony_ci#define OMAP_I2C_BUF_RDMA_EN	(1 << 15)	/* RX DMA channel enable */
1238c2ecf20Sopenharmony_ci#define OMAP_I2C_BUF_RXFIF_CLR	(1 << 14)	/* RX FIFO Clear */
1248c2ecf20Sopenharmony_ci#define OMAP_I2C_BUF_XDMA_EN	(1 << 7)	/* TX DMA channel enable */
1258c2ecf20Sopenharmony_ci#define OMAP_I2C_BUF_TXFIF_CLR	(1 << 6)	/* TX FIFO Clear */
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/* I2C Configuration Register (OMAP_I2C_CON): */
1288c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_EN		(1 << 15)	/* I2C module enable */
1298c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_BE		(1 << 14)	/* Big endian mode */
1308c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_OPMODE_HS	(1 << 12)	/* High Speed support */
1318c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_STB	(1 << 11)	/* Start byte mode (master) */
1328c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_MST	(1 << 10)	/* Master/slave mode */
1338c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_TRX	(1 << 9)	/* TX/RX mode (master only) */
1348c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_XA		(1 << 8)	/* Expand address */
1358c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_RM		(1 << 2)	/* Repeat mode (master only) */
1368c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_STP	(1 << 1)	/* Stop cond (master only) */
1378c2ecf20Sopenharmony_ci#define OMAP_I2C_CON_STT	(1 << 0)	/* Start condition (master) */
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/* I2C SCL time value when Master */
1408c2ecf20Sopenharmony_ci#define OMAP_I2C_SCLL_HSSCLL	8
1418c2ecf20Sopenharmony_ci#define OMAP_I2C_SCLH_HSSCLH	8
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/* I2C System Test Register (OMAP_I2C_SYSTEST): */
1448c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_ST_EN		(1 << 15)	/* System test enable */
1458c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_FREE		(1 << 14)	/* Free running mode */
1468c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_TMODE_MASK	(3 << 12)	/* Test mode select */
1478c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_TMODE_SHIFT	(12)		/* Test mode select */
1488c2ecf20Sopenharmony_ci/* Functional mode */
1498c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_I_FUNC	(1 << 8)	/* SCL line input value */
1508c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_O_FUNC	(1 << 7)	/* SCL line output value */
1518c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_I_FUNC	(1 << 6)	/* SDA line input value */
1528c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_O_FUNC	(1 << 5)	/* SDA line output value */
1538c2ecf20Sopenharmony_ci/* SDA/SCL IO mode */
1548c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_I		(1 << 3)	/* SCL line sense in */
1558c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_O		(1 << 2)	/* SCL line drive out */
1568c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_I		(1 << 1)	/* SDA line sense in */
1578c2ecf20Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_O		(1 << 0)	/* SDA line drive out */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/* OCP_SYSSTATUS bit definitions */
1608c2ecf20Sopenharmony_ci#define SYSS_RESETDONE_MASK		(1 << 0)
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci/* OCP_SYSCONFIG bit definitions */
1638c2ecf20Sopenharmony_ci#define SYSC_CLOCKACTIVITY_MASK		(0x3 << 8)
1648c2ecf20Sopenharmony_ci#define SYSC_SIDLEMODE_MASK		(0x3 << 3)
1658c2ecf20Sopenharmony_ci#define SYSC_ENAWAKEUP_MASK		(1 << 2)
1668c2ecf20Sopenharmony_ci#define SYSC_SOFTRESET_MASK		(1 << 1)
1678c2ecf20Sopenharmony_ci#define SYSC_AUTOIDLE_MASK		(1 << 0)
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci#define SYSC_IDLEMODE_SMART		0x2
1708c2ecf20Sopenharmony_ci#define SYSC_CLOCKACTIVITY_FCLK		0x2
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/* Errata definitions */
1738c2ecf20Sopenharmony_ci#define I2C_OMAP_ERRATA_I207		(1 << 0)
1748c2ecf20Sopenharmony_ci#define I2C_OMAP_ERRATA_I462		(1 << 1)
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#define OMAP_I2C_IP_V2_INTERRUPTS_MASK	0x6FFF
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistruct omap_i2c_dev {
1798c2ecf20Sopenharmony_ci	struct device		*dev;
1808c2ecf20Sopenharmony_ci	void __iomem		*base;		/* virtual */
1818c2ecf20Sopenharmony_ci	int			irq;
1828c2ecf20Sopenharmony_ci	int			reg_shift;      /* bit shift for I2C register addresses */
1838c2ecf20Sopenharmony_ci	struct completion	cmd_complete;
1848c2ecf20Sopenharmony_ci	struct resource		*ioarea;
1858c2ecf20Sopenharmony_ci	u32			latency;	/* maximum mpu wkup latency */
1868c2ecf20Sopenharmony_ci	void			(*set_mpu_wkup_lat)(struct device *dev,
1878c2ecf20Sopenharmony_ci						    long latency);
1888c2ecf20Sopenharmony_ci	u32			speed;		/* Speed of bus in kHz */
1898c2ecf20Sopenharmony_ci	u32			flags;
1908c2ecf20Sopenharmony_ci	u16			scheme;
1918c2ecf20Sopenharmony_ci	u16			cmd_err;
1928c2ecf20Sopenharmony_ci	u8			*buf;
1938c2ecf20Sopenharmony_ci	u8			*regs;
1948c2ecf20Sopenharmony_ci	size_t			buf_len;
1958c2ecf20Sopenharmony_ci	struct i2c_adapter	adapter;
1968c2ecf20Sopenharmony_ci	u8			threshold;
1978c2ecf20Sopenharmony_ci	u8			fifo_size;	/* use as flag and value
1988c2ecf20Sopenharmony_ci						 * fifo_size==0 implies no fifo
1998c2ecf20Sopenharmony_ci						 * if set, should be trsh+1
2008c2ecf20Sopenharmony_ci						 */
2018c2ecf20Sopenharmony_ci	u32			rev;
2028c2ecf20Sopenharmony_ci	unsigned		b_hw:1;		/* bad h/w fixes */
2038c2ecf20Sopenharmony_ci	unsigned		bb_valid:1;	/* true when BB-bit reflects
2048c2ecf20Sopenharmony_ci						 * the I2C bus state
2058c2ecf20Sopenharmony_ci						 */
2068c2ecf20Sopenharmony_ci	unsigned		receiver:1;	/* true when we're in receiver mode */
2078c2ecf20Sopenharmony_ci	u16			iestate;	/* Saved interrupt register */
2088c2ecf20Sopenharmony_ci	u16			pscstate;
2098c2ecf20Sopenharmony_ci	u16			scllstate;
2108c2ecf20Sopenharmony_ci	u16			sclhstate;
2118c2ecf20Sopenharmony_ci	u16			syscstate;
2128c2ecf20Sopenharmony_ci	u16			westate;
2138c2ecf20Sopenharmony_ci	u16			errata;
2148c2ecf20Sopenharmony_ci};
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic const u8 reg_map_ip_v1[] = {
2178c2ecf20Sopenharmony_ci	[OMAP_I2C_REV_REG] = 0x00,
2188c2ecf20Sopenharmony_ci	[OMAP_I2C_IE_REG] = 0x01,
2198c2ecf20Sopenharmony_ci	[OMAP_I2C_STAT_REG] = 0x02,
2208c2ecf20Sopenharmony_ci	[OMAP_I2C_IV_REG] = 0x03,
2218c2ecf20Sopenharmony_ci	[OMAP_I2C_WE_REG] = 0x03,
2228c2ecf20Sopenharmony_ci	[OMAP_I2C_SYSS_REG] = 0x04,
2238c2ecf20Sopenharmony_ci	[OMAP_I2C_BUF_REG] = 0x05,
2248c2ecf20Sopenharmony_ci	[OMAP_I2C_CNT_REG] = 0x06,
2258c2ecf20Sopenharmony_ci	[OMAP_I2C_DATA_REG] = 0x07,
2268c2ecf20Sopenharmony_ci	[OMAP_I2C_SYSC_REG] = 0x08,
2278c2ecf20Sopenharmony_ci	[OMAP_I2C_CON_REG] = 0x09,
2288c2ecf20Sopenharmony_ci	[OMAP_I2C_OA_REG] = 0x0a,
2298c2ecf20Sopenharmony_ci	[OMAP_I2C_SA_REG] = 0x0b,
2308c2ecf20Sopenharmony_ci	[OMAP_I2C_PSC_REG] = 0x0c,
2318c2ecf20Sopenharmony_ci	[OMAP_I2C_SCLL_REG] = 0x0d,
2328c2ecf20Sopenharmony_ci	[OMAP_I2C_SCLH_REG] = 0x0e,
2338c2ecf20Sopenharmony_ci	[OMAP_I2C_SYSTEST_REG] = 0x0f,
2348c2ecf20Sopenharmony_ci	[OMAP_I2C_BUFSTAT_REG] = 0x10,
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic const u8 reg_map_ip_v2[] = {
2388c2ecf20Sopenharmony_ci	[OMAP_I2C_REV_REG] = 0x04,
2398c2ecf20Sopenharmony_ci	[OMAP_I2C_IE_REG] = 0x2c,
2408c2ecf20Sopenharmony_ci	[OMAP_I2C_STAT_REG] = 0x28,
2418c2ecf20Sopenharmony_ci	[OMAP_I2C_IV_REG] = 0x34,
2428c2ecf20Sopenharmony_ci	[OMAP_I2C_WE_REG] = 0x34,
2438c2ecf20Sopenharmony_ci	[OMAP_I2C_SYSS_REG] = 0x90,
2448c2ecf20Sopenharmony_ci	[OMAP_I2C_BUF_REG] = 0x94,
2458c2ecf20Sopenharmony_ci	[OMAP_I2C_CNT_REG] = 0x98,
2468c2ecf20Sopenharmony_ci	[OMAP_I2C_DATA_REG] = 0x9c,
2478c2ecf20Sopenharmony_ci	[OMAP_I2C_SYSC_REG] = 0x10,
2488c2ecf20Sopenharmony_ci	[OMAP_I2C_CON_REG] = 0xa4,
2498c2ecf20Sopenharmony_ci	[OMAP_I2C_OA_REG] = 0xa8,
2508c2ecf20Sopenharmony_ci	[OMAP_I2C_SA_REG] = 0xac,
2518c2ecf20Sopenharmony_ci	[OMAP_I2C_PSC_REG] = 0xb0,
2528c2ecf20Sopenharmony_ci	[OMAP_I2C_SCLL_REG] = 0xb4,
2538c2ecf20Sopenharmony_ci	[OMAP_I2C_SCLH_REG] = 0xb8,
2548c2ecf20Sopenharmony_ci	[OMAP_I2C_SYSTEST_REG] = 0xbC,
2558c2ecf20Sopenharmony_ci	[OMAP_I2C_BUFSTAT_REG] = 0xc0,
2568c2ecf20Sopenharmony_ci	[OMAP_I2C_IP_V2_REVNB_LO] = 0x00,
2578c2ecf20Sopenharmony_ci	[OMAP_I2C_IP_V2_REVNB_HI] = 0x04,
2588c2ecf20Sopenharmony_ci	[OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24,
2598c2ecf20Sopenharmony_ci	[OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c,
2608c2ecf20Sopenharmony_ci	[OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30,
2618c2ecf20Sopenharmony_ci};
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic int omap_i2c_xfer_data(struct omap_i2c_dev *omap);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic inline void omap_i2c_write_reg(struct omap_i2c_dev *omap,
2668c2ecf20Sopenharmony_ci				      int reg, u16 val)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	writew_relaxed(val, omap->base +
2698c2ecf20Sopenharmony_ci			(omap->regs[reg] << omap->reg_shift));
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic inline u16 omap_i2c_read_reg(struct omap_i2c_dev *omap, int reg)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	return readw_relaxed(omap->base +
2758c2ecf20Sopenharmony_ci				(omap->regs[reg] << omap->reg_shift));
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic void __omap_i2c_init(struct omap_i2c_dev *omap)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
2848c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_PSC_REG, omap->pscstate);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/* SCL low and high time values */
2878c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_SCLL_REG, omap->scllstate);
2888c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_SCLH_REG, omap->sclhstate);
2898c2ecf20Sopenharmony_ci	if (omap->rev >= OMAP_I2C_REV_ON_3430_3530)
2908c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_WE_REG, omap->westate);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* Take the I2C module out of reset: */
2938c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/*
2968c2ecf20Sopenharmony_ci	 * NOTE: right after setting CON_EN, STAT_BB could be 0 while the
2978c2ecf20Sopenharmony_ci	 * bus is busy. It will be changed to 1 on the next IP FCLK clock.
2988c2ecf20Sopenharmony_ci	 * udelay(1) will be enough to fix that.
2998c2ecf20Sopenharmony_ci	 */
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/*
3028c2ecf20Sopenharmony_ci	 * Don't write to this register if the IE state is 0 as it can
3038c2ecf20Sopenharmony_ci	 * cause deadlock.
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	if (omap->iestate)
3068c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, omap->iestate);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int omap_i2c_reset(struct omap_i2c_dev *omap)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	unsigned long timeout;
3128c2ecf20Sopenharmony_ci	u16 sysc;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (omap->rev >= OMAP_I2C_OMAP1_REV_2) {
3158c2ecf20Sopenharmony_ci		sysc = omap_i2c_read_reg(omap, OMAP_I2C_SYSC_REG);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		/* Disable I2C controller before soft reset */
3188c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_CON_REG,
3198c2ecf20Sopenharmony_ci			omap_i2c_read_reg(omap, OMAP_I2C_CON_REG) &
3208c2ecf20Sopenharmony_ci				~(OMAP_I2C_CON_EN));
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
3238c2ecf20Sopenharmony_ci		/* For some reason we need to set the EN bit before the
3248c2ecf20Sopenharmony_ci		 * reset done bit gets set. */
3258c2ecf20Sopenharmony_ci		timeout = jiffies + OMAP_I2C_TIMEOUT;
3268c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
3278c2ecf20Sopenharmony_ci		while (!(omap_i2c_read_reg(omap, OMAP_I2C_SYSS_REG) &
3288c2ecf20Sopenharmony_ci			 SYSS_RESETDONE_MASK)) {
3298c2ecf20Sopenharmony_ci			if (time_after(jiffies, timeout)) {
3308c2ecf20Sopenharmony_ci				dev_warn(omap->dev, "timeout waiting "
3318c2ecf20Sopenharmony_ci						"for controller reset\n");
3328c2ecf20Sopenharmony_ci				return -ETIMEDOUT;
3338c2ecf20Sopenharmony_ci			}
3348c2ecf20Sopenharmony_ci			msleep(1);
3358c2ecf20Sopenharmony_ci		}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		/* SYSC register is cleared by the reset; rewrite it */
3388c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, sysc);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		if (omap->rev > OMAP_I2C_REV_ON_3430_3530) {
3418c2ecf20Sopenharmony_ci			/* Schedule I2C-bus monitoring on the next transfer */
3428c2ecf20Sopenharmony_ci			omap->bb_valid = 0;
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int omap_i2c_init(struct omap_i2c_dev *omap)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	u16 psc = 0, scll = 0, sclh = 0;
3528c2ecf20Sopenharmony_ci	u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
3538c2ecf20Sopenharmony_ci	unsigned long fclk_rate = 12000000;
3548c2ecf20Sopenharmony_ci	unsigned long internal_clk = 0;
3558c2ecf20Sopenharmony_ci	struct clk *fclk;
3568c2ecf20Sopenharmony_ci	int error;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (omap->rev >= OMAP_I2C_REV_ON_3430_3530) {
3598c2ecf20Sopenharmony_ci		/*
3608c2ecf20Sopenharmony_ci		 * Enabling all wakup sources to stop I2C freezing on
3618c2ecf20Sopenharmony_ci		 * WFI instruction.
3628c2ecf20Sopenharmony_ci		 * REVISIT: Some wkup sources might not be needed.
3638c2ecf20Sopenharmony_ci		 */
3648c2ecf20Sopenharmony_ci		omap->westate = OMAP_I2C_WE_ALL;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (omap->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
3688c2ecf20Sopenharmony_ci		/*
3698c2ecf20Sopenharmony_ci		 * The I2C functional clock is the armxor_ck, so there's
3708c2ecf20Sopenharmony_ci		 * no need to get "armxor_ck" separately.  Now, if OMAP2420
3718c2ecf20Sopenharmony_ci		 * always returns 12MHz for the functional clock, we can
3728c2ecf20Sopenharmony_ci		 * do this bit unconditionally.
3738c2ecf20Sopenharmony_ci		 */
3748c2ecf20Sopenharmony_ci		fclk = clk_get(omap->dev, "fck");
3758c2ecf20Sopenharmony_ci		if (IS_ERR(fclk)) {
3768c2ecf20Sopenharmony_ci			error = PTR_ERR(fclk);
3778c2ecf20Sopenharmony_ci			dev_err(omap->dev, "could not get fck: %i\n", error);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci			return error;
3808c2ecf20Sopenharmony_ci		}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		fclk_rate = clk_get_rate(fclk);
3838c2ecf20Sopenharmony_ci		clk_put(fclk);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		/* TRM for 5912 says the I2C clock must be prescaled to be
3868c2ecf20Sopenharmony_ci		 * between 7 - 12 MHz. The XOR input clock is typically
3878c2ecf20Sopenharmony_ci		 * 12, 13 or 19.2 MHz. So we should have code that produces:
3888c2ecf20Sopenharmony_ci		 *
3898c2ecf20Sopenharmony_ci		 * XOR MHz	Divider		Prescaler
3908c2ecf20Sopenharmony_ci		 * 12		1		0
3918c2ecf20Sopenharmony_ci		 * 13		2		1
3928c2ecf20Sopenharmony_ci		 * 19.2		2		1
3938c2ecf20Sopenharmony_ci		 */
3948c2ecf20Sopenharmony_ci		if (fclk_rate > 12000000)
3958c2ecf20Sopenharmony_ci			psc = fclk_rate / 12000000;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (!(omap->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		/*
4018c2ecf20Sopenharmony_ci		 * HSI2C controller internal clk rate should be 19.2 Mhz for
4028c2ecf20Sopenharmony_ci		 * HS and for all modes on 2430. On 34xx we can use lower rate
4038c2ecf20Sopenharmony_ci		 * to get longer filter period for better noise suppression.
4048c2ecf20Sopenharmony_ci		 * The filter is iclk (fclk for HS) period.
4058c2ecf20Sopenharmony_ci		 */
4068c2ecf20Sopenharmony_ci		if (omap->speed > 400 ||
4078c2ecf20Sopenharmony_ci			       omap->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
4088c2ecf20Sopenharmony_ci			internal_clk = 19200;
4098c2ecf20Sopenharmony_ci		else if (omap->speed > 100)
4108c2ecf20Sopenharmony_ci			internal_clk = 9600;
4118c2ecf20Sopenharmony_ci		else
4128c2ecf20Sopenharmony_ci			internal_clk = 4000;
4138c2ecf20Sopenharmony_ci		fclk = clk_get(omap->dev, "fck");
4148c2ecf20Sopenharmony_ci		if (IS_ERR(fclk)) {
4158c2ecf20Sopenharmony_ci			error = PTR_ERR(fclk);
4168c2ecf20Sopenharmony_ci			dev_err(omap->dev, "could not get fck: %i\n", error);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci			return error;
4198c2ecf20Sopenharmony_ci		}
4208c2ecf20Sopenharmony_ci		fclk_rate = clk_get_rate(fclk) / 1000;
4218c2ecf20Sopenharmony_ci		clk_put(fclk);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		/* Compute prescaler divisor */
4248c2ecf20Sopenharmony_ci		psc = fclk_rate / internal_clk;
4258c2ecf20Sopenharmony_ci		psc = psc - 1;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		/* If configured for High Speed */
4288c2ecf20Sopenharmony_ci		if (omap->speed > 400) {
4298c2ecf20Sopenharmony_ci			unsigned long scl;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci			/* For first phase of HS mode */
4328c2ecf20Sopenharmony_ci			scl = internal_clk / 400;
4338c2ecf20Sopenharmony_ci			fsscll = scl - (scl / 3) - 7;
4348c2ecf20Sopenharmony_ci			fssclh = (scl / 3) - 5;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci			/* For second phase of HS mode */
4378c2ecf20Sopenharmony_ci			scl = fclk_rate / omap->speed;
4388c2ecf20Sopenharmony_ci			hsscll = scl - (scl / 3) - 7;
4398c2ecf20Sopenharmony_ci			hssclh = (scl / 3) - 5;
4408c2ecf20Sopenharmony_ci		} else if (omap->speed > 100) {
4418c2ecf20Sopenharmony_ci			unsigned long scl;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci			/* Fast mode */
4448c2ecf20Sopenharmony_ci			scl = internal_clk / omap->speed;
4458c2ecf20Sopenharmony_ci			fsscll = scl - (scl / 3) - 7;
4468c2ecf20Sopenharmony_ci			fssclh = (scl / 3) - 5;
4478c2ecf20Sopenharmony_ci		} else {
4488c2ecf20Sopenharmony_ci			/* Standard mode */
4498c2ecf20Sopenharmony_ci			fsscll = internal_clk / (omap->speed * 2) - 7;
4508c2ecf20Sopenharmony_ci			fssclh = internal_clk / (omap->speed * 2) - 5;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci		scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
4538c2ecf20Sopenharmony_ci		sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
4548c2ecf20Sopenharmony_ci	} else {
4558c2ecf20Sopenharmony_ci		/* Program desired operating rate */
4568c2ecf20Sopenharmony_ci		fclk_rate /= (psc + 1) * 1000;
4578c2ecf20Sopenharmony_ci		if (psc > 2)
4588c2ecf20Sopenharmony_ci			psc = 2;
4598c2ecf20Sopenharmony_ci		scll = fclk_rate / (omap->speed * 2) - 7 + psc;
4608c2ecf20Sopenharmony_ci		sclh = fclk_rate / (omap->speed * 2) - 7 + psc;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	omap->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
4648c2ecf20Sopenharmony_ci			OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
4658c2ecf20Sopenharmony_ci			OMAP_I2C_IE_AL)  | ((omap->fifo_size) ?
4668c2ecf20Sopenharmony_ci				(OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	omap->pscstate = psc;
4698c2ecf20Sopenharmony_ci	omap->scllstate = scll;
4708c2ecf20Sopenharmony_ci	omap->sclhstate = sclh;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) {
4738c2ecf20Sopenharmony_ci		/* Not implemented */
4748c2ecf20Sopenharmony_ci		omap->bb_valid = 1;
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	__omap_i2c_init(omap);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci/*
4838c2ecf20Sopenharmony_ci * Try bus recovery, but only if SDA is actually low.
4848c2ecf20Sopenharmony_ci */
4858c2ecf20Sopenharmony_cistatic int omap_i2c_recover_bus(struct omap_i2c_dev *omap)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	u16 systest;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG);
4908c2ecf20Sopenharmony_ci	if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
4918c2ecf20Sopenharmony_ci	    (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC))
4928c2ecf20Sopenharmony_ci		return 0; /* bus seems to already be fine */
4938c2ecf20Sopenharmony_ci	if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC))
4948c2ecf20Sopenharmony_ci		return -EBUSY; /* recovery would not fix SCL */
4958c2ecf20Sopenharmony_ci	return i2c_recover_bus(&omap->adapter);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/*
4998c2ecf20Sopenharmony_ci * Waiting on Bus Busy
5008c2ecf20Sopenharmony_ci */
5018c2ecf20Sopenharmony_cistatic int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	unsigned long timeout;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	timeout = jiffies + OMAP_I2C_TIMEOUT;
5068c2ecf20Sopenharmony_ci	while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
5078c2ecf20Sopenharmony_ci		if (time_after(jiffies, timeout))
5088c2ecf20Sopenharmony_ci			return omap_i2c_recover_bus(omap);
5098c2ecf20Sopenharmony_ci		msleep(1);
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	return 0;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci/*
5168c2ecf20Sopenharmony_ci * Wait while BB-bit doesn't reflect the I2C bus state
5178c2ecf20Sopenharmony_ci *
5188c2ecf20Sopenharmony_ci * In a multimaster environment, after IP software reset, BB-bit value doesn't
5198c2ecf20Sopenharmony_ci * correspond to the current bus state. It may happen what BB-bit will be 0,
5208c2ecf20Sopenharmony_ci * while the bus is busy due to another I2C master activity.
5218c2ecf20Sopenharmony_ci * Here are BB-bit values after reset:
5228c2ecf20Sopenharmony_ci *     SDA   SCL   BB   NOTES
5238c2ecf20Sopenharmony_ci *       0     0    0   1, 2
5248c2ecf20Sopenharmony_ci *       1     0    0   1, 2
5258c2ecf20Sopenharmony_ci *       0     1    1
5268c2ecf20Sopenharmony_ci *       1     1    0   3
5278c2ecf20Sopenharmony_ci * Later, if IP detect SDA=0 and SCL=1 (ACK) or SDA 1->0 while SCL=1 (START)
5288c2ecf20Sopenharmony_ci * combinations on the bus, it set BB-bit to 1.
5298c2ecf20Sopenharmony_ci * If IP detect SDA 0->1 while SCL=1 (STOP) combination on the bus,
5308c2ecf20Sopenharmony_ci * it set BB-bit to 0 and BF to 1.
5318c2ecf20Sopenharmony_ci * BB and BF bits correctly tracks the bus state while IP is suspended
5328c2ecf20Sopenharmony_ci * BB bit became valid on the next FCLK clock after CON_EN bit set
5338c2ecf20Sopenharmony_ci *
5348c2ecf20Sopenharmony_ci * NOTES:
5358c2ecf20Sopenharmony_ci * 1. Any transfer started when BB=0 and bus is busy wouldn't be
5368c2ecf20Sopenharmony_ci *    completed by IP and results in controller timeout.
5378c2ecf20Sopenharmony_ci * 2. Any transfer started when BB=0 and SCL=0 results in IP
5388c2ecf20Sopenharmony_ci *    starting to drive SDA low. In that case IP corrupt data
5398c2ecf20Sopenharmony_ci *    on the bus.
5408c2ecf20Sopenharmony_ci * 3. Any transfer started in the middle of another master's transfer
5418c2ecf20Sopenharmony_ci *    results in unpredictable results and data corruption
5428c2ecf20Sopenharmony_ci */
5438c2ecf20Sopenharmony_cistatic int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	unsigned long bus_free_timeout = 0;
5468c2ecf20Sopenharmony_ci	unsigned long timeout;
5478c2ecf20Sopenharmony_ci	int bus_free = 0;
5488c2ecf20Sopenharmony_ci	u16 stat, systest;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (omap->bb_valid)
5518c2ecf20Sopenharmony_ci		return 0;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	timeout = jiffies + OMAP_I2C_TIMEOUT;
5548c2ecf20Sopenharmony_ci	while (1) {
5558c2ecf20Sopenharmony_ci		stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
5568c2ecf20Sopenharmony_ci		/*
5578c2ecf20Sopenharmony_ci		 * We will see BB or BF event in a case IP had detected any
5588c2ecf20Sopenharmony_ci		 * activity on the I2C bus. Now IP correctly tracks the bus
5598c2ecf20Sopenharmony_ci		 * state. BB-bit value is valid.
5608c2ecf20Sopenharmony_ci		 */
5618c2ecf20Sopenharmony_ci		if (stat & (OMAP_I2C_STAT_BB | OMAP_I2C_STAT_BF))
5628c2ecf20Sopenharmony_ci			break;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		/*
5658c2ecf20Sopenharmony_ci		 * Otherwise, we must look signals on the bus to make
5668c2ecf20Sopenharmony_ci		 * the right decision.
5678c2ecf20Sopenharmony_ci		 */
5688c2ecf20Sopenharmony_ci		systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG);
5698c2ecf20Sopenharmony_ci		if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
5708c2ecf20Sopenharmony_ci		    (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) {
5718c2ecf20Sopenharmony_ci			if (!bus_free) {
5728c2ecf20Sopenharmony_ci				bus_free_timeout = jiffies +
5738c2ecf20Sopenharmony_ci					OMAP_I2C_BUS_FREE_TIMEOUT;
5748c2ecf20Sopenharmony_ci				bus_free = 1;
5758c2ecf20Sopenharmony_ci			}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci			/*
5788c2ecf20Sopenharmony_ci			 * SDA and SCL lines was high for 10 ms without bus
5798c2ecf20Sopenharmony_ci			 * activity detected. The bus is free. Consider
5808c2ecf20Sopenharmony_ci			 * BB-bit value is valid.
5818c2ecf20Sopenharmony_ci			 */
5828c2ecf20Sopenharmony_ci			if (time_after(jiffies, bus_free_timeout))
5838c2ecf20Sopenharmony_ci				break;
5848c2ecf20Sopenharmony_ci		} else {
5858c2ecf20Sopenharmony_ci			bus_free = 0;
5868c2ecf20Sopenharmony_ci		}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci		if (time_after(jiffies, timeout)) {
5898c2ecf20Sopenharmony_ci			/*
5908c2ecf20Sopenharmony_ci			 * SDA or SCL were low for the entire timeout without
5918c2ecf20Sopenharmony_ci			 * any activity detected. Most likely, a slave is
5928c2ecf20Sopenharmony_ci			 * locking up the bus with no master driving the clock.
5938c2ecf20Sopenharmony_ci			 */
5948c2ecf20Sopenharmony_ci			dev_warn(omap->dev, "timeout waiting for bus ready\n");
5958c2ecf20Sopenharmony_ci			return omap_i2c_recover_bus(omap);
5968c2ecf20Sopenharmony_ci		}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		msleep(1);
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	omap->bb_valid = 1;
6028c2ecf20Sopenharmony_ci	return 0;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	u16		buf;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (omap->flags & OMAP_I2C_FLAG_NO_FIFO)
6108c2ecf20Sopenharmony_ci		return;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/*
6138c2ecf20Sopenharmony_ci	 * Set up notification threshold based on message size. We're doing
6148c2ecf20Sopenharmony_ci	 * this to try and avoid draining feature as much as possible. Whenever
6158c2ecf20Sopenharmony_ci	 * we have big messages to transfer (bigger than our total fifo size)
6168c2ecf20Sopenharmony_ci	 * then we might use draining feature to transfer the remaining bytes.
6178c2ecf20Sopenharmony_ci	 */
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	omap->threshold = clamp(size, (u8) 1, omap->fifo_size);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	buf = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (is_rx) {
6248c2ecf20Sopenharmony_ci		/* Clear RX Threshold */
6258c2ecf20Sopenharmony_ci		buf &= ~(0x3f << 8);
6268c2ecf20Sopenharmony_ci		buf |= ((omap->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR;
6278c2ecf20Sopenharmony_ci	} else {
6288c2ecf20Sopenharmony_ci		/* Clear TX Threshold */
6298c2ecf20Sopenharmony_ci		buf &= ~0x3f;
6308c2ecf20Sopenharmony_ci		buf |= (omap->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, buf);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (omap->rev < OMAP_I2C_REV_ON_3630)
6368c2ecf20Sopenharmony_ci		omap->b_hw = 1; /* Enable hardware fixes */
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* calculate wakeup latency constraint for MPU */
6398c2ecf20Sopenharmony_ci	if (omap->set_mpu_wkup_lat != NULL)
6408c2ecf20Sopenharmony_ci		omap->latency = (1000000 * omap->threshold) /
6418c2ecf20Sopenharmony_ci			(1000 * omap->speed / 8);
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic void omap_i2c_wait(struct omap_i2c_dev *omap)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	u16 stat;
6478c2ecf20Sopenharmony_ci	u16 mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
6488c2ecf20Sopenharmony_ci	int count = 0;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	do {
6518c2ecf20Sopenharmony_ci		stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
6528c2ecf20Sopenharmony_ci		count++;
6538c2ecf20Sopenharmony_ci	} while (!(stat & mask) && count < 5);
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci/*
6578c2ecf20Sopenharmony_ci * Low level master read/write transaction.
6588c2ecf20Sopenharmony_ci */
6598c2ecf20Sopenharmony_cistatic int omap_i2c_xfer_msg(struct i2c_adapter *adap,
6608c2ecf20Sopenharmony_ci			     struct i2c_msg *msg, int stop, bool polling)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	struct omap_i2c_dev *omap = i2c_get_adapdata(adap);
6638c2ecf20Sopenharmony_ci	unsigned long timeout;
6648c2ecf20Sopenharmony_ci	u16 w;
6658c2ecf20Sopenharmony_ci	int ret;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
6688c2ecf20Sopenharmony_ci		msg->addr, msg->len, msg->flags, stop);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	omap->receiver = !!(msg->flags & I2C_M_RD);
6718c2ecf20Sopenharmony_ci	omap_i2c_resize_fifo(omap, msg->len, omap->receiver);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_SA_REG, msg->addr);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	/* REVISIT: Could the STB bit of I2C_CON be used with probing? */
6768c2ecf20Sopenharmony_ci	omap->buf = msg->buf;
6778c2ecf20Sopenharmony_ci	omap->buf_len = msg->len;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* make sure writes to omap->buf_len are ordered */
6808c2ecf20Sopenharmony_ci	barrier();
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_CNT_REG, omap->buf_len);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/* Clear the FIFO Buffers */
6858c2ecf20Sopenharmony_ci	w = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG);
6868c2ecf20Sopenharmony_ci	w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
6878c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (!polling)
6908c2ecf20Sopenharmony_ci		reinit_completion(&omap->cmd_complete);
6918c2ecf20Sopenharmony_ci	omap->cmd_err = 0;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	/* High speed configuration */
6968c2ecf20Sopenharmony_ci	if (omap->speed > 400)
6978c2ecf20Sopenharmony_ci		w |= OMAP_I2C_CON_OPMODE_HS;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (msg->flags & I2C_M_STOP)
7008c2ecf20Sopenharmony_ci		stop = 1;
7018c2ecf20Sopenharmony_ci	if (msg->flags & I2C_M_TEN)
7028c2ecf20Sopenharmony_ci		w |= OMAP_I2C_CON_XA;
7038c2ecf20Sopenharmony_ci	if (!(msg->flags & I2C_M_RD))
7048c2ecf20Sopenharmony_ci		w |= OMAP_I2C_CON_TRX;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	if (!omap->b_hw && stop)
7078c2ecf20Sopenharmony_ci		w |= OMAP_I2C_CON_STP;
7088c2ecf20Sopenharmony_ci	/*
7098c2ecf20Sopenharmony_ci	 * NOTE: STAT_BB bit could became 1 here if another master occupy
7108c2ecf20Sopenharmony_ci	 * the bus. IP successfully complete transfer when the bus will be
7118c2ecf20Sopenharmony_ci	 * free again (BB reset to 0).
7128c2ecf20Sopenharmony_ci	 */
7138c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/*
7168c2ecf20Sopenharmony_ci	 * Don't write stt and stp together on some hardware.
7178c2ecf20Sopenharmony_ci	 */
7188c2ecf20Sopenharmony_ci	if (omap->b_hw && stop) {
7198c2ecf20Sopenharmony_ci		unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
7208c2ecf20Sopenharmony_ci		u16 con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
7218c2ecf20Sopenharmony_ci		while (con & OMAP_I2C_CON_STT) {
7228c2ecf20Sopenharmony_ci			con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci			/* Let the user know if i2c is in a bad state */
7258c2ecf20Sopenharmony_ci			if (time_after(jiffies, delay)) {
7268c2ecf20Sopenharmony_ci				dev_err(omap->dev, "controller timed out "
7278c2ecf20Sopenharmony_ci				"waiting for start condition to finish\n");
7288c2ecf20Sopenharmony_ci				return -ETIMEDOUT;
7298c2ecf20Sopenharmony_ci			}
7308c2ecf20Sopenharmony_ci			cpu_relax();
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci		w |= OMAP_I2C_CON_STP;
7348c2ecf20Sopenharmony_ci		w &= ~OMAP_I2C_CON_STT;
7358c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w);
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	/*
7398c2ecf20Sopenharmony_ci	 * REVISIT: We should abort the transfer on signals, but the bus goes
7408c2ecf20Sopenharmony_ci	 * into arbitration and we're currently unable to recover from it.
7418c2ecf20Sopenharmony_ci	 */
7428c2ecf20Sopenharmony_ci	if (!polling) {
7438c2ecf20Sopenharmony_ci		timeout = wait_for_completion_timeout(&omap->cmd_complete,
7448c2ecf20Sopenharmony_ci						      OMAP_I2C_TIMEOUT);
7458c2ecf20Sopenharmony_ci	} else {
7468c2ecf20Sopenharmony_ci		do {
7478c2ecf20Sopenharmony_ci			omap_i2c_wait(omap);
7488c2ecf20Sopenharmony_ci			ret = omap_i2c_xfer_data(omap);
7498c2ecf20Sopenharmony_ci		} while (ret == -EAGAIN);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		timeout = !ret;
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	if (timeout == 0) {
7558c2ecf20Sopenharmony_ci		dev_err(omap->dev, "controller timed out\n");
7568c2ecf20Sopenharmony_ci		omap_i2c_reset(omap);
7578c2ecf20Sopenharmony_ci		__omap_i2c_init(omap);
7588c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (likely(!omap->cmd_err))
7628c2ecf20Sopenharmony_ci		return 0;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	/* We have an error */
7658c2ecf20Sopenharmony_ci	if (omap->cmd_err & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) {
7668c2ecf20Sopenharmony_ci		omap_i2c_reset(omap);
7678c2ecf20Sopenharmony_ci		__omap_i2c_init(omap);
7688c2ecf20Sopenharmony_ci		return -EIO;
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	if (omap->cmd_err & OMAP_I2C_STAT_AL)
7728c2ecf20Sopenharmony_ci		return -EAGAIN;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (omap->cmd_err & OMAP_I2C_STAT_NACK) {
7758c2ecf20Sopenharmony_ci		if (msg->flags & I2C_M_IGNORE_NAK)
7768c2ecf20Sopenharmony_ci			return 0;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		w = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
7798c2ecf20Sopenharmony_ci		w |= OMAP_I2C_CON_STP;
7808c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w);
7818c2ecf20Sopenharmony_ci		return -EREMOTEIO;
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci	return -EIO;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci/*
7888c2ecf20Sopenharmony_ci * Prepare controller for a transaction and call omap_i2c_xfer_msg
7898c2ecf20Sopenharmony_ci * to do the work during IRQ processing.
7908c2ecf20Sopenharmony_ci */
7918c2ecf20Sopenharmony_cistatic int
7928c2ecf20Sopenharmony_ciomap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num,
7938c2ecf20Sopenharmony_ci		     bool polling)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	struct omap_i2c_dev *omap = i2c_get_adapdata(adap);
7968c2ecf20Sopenharmony_ci	int i;
7978c2ecf20Sopenharmony_ci	int r;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	r = pm_runtime_get_sync(omap->dev);
8008c2ecf20Sopenharmony_ci	if (r < 0)
8018c2ecf20Sopenharmony_ci		goto out;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	r = omap_i2c_wait_for_bb_valid(omap);
8048c2ecf20Sopenharmony_ci	if (r < 0)
8058c2ecf20Sopenharmony_ci		goto out;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	r = omap_i2c_wait_for_bb(omap);
8088c2ecf20Sopenharmony_ci	if (r < 0)
8098c2ecf20Sopenharmony_ci		goto out;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (omap->set_mpu_wkup_lat != NULL)
8128c2ecf20Sopenharmony_ci		omap->set_mpu_wkup_lat(omap->dev, omap->latency);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
8158c2ecf20Sopenharmony_ci		r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)),
8168c2ecf20Sopenharmony_ci				      polling);
8178c2ecf20Sopenharmony_ci		if (r != 0)
8188c2ecf20Sopenharmony_ci			break;
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (r == 0)
8228c2ecf20Sopenharmony_ci		r = num;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	omap_i2c_wait_for_bb(omap);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (omap->set_mpu_wkup_lat != NULL)
8278c2ecf20Sopenharmony_ci		omap->set_mpu_wkup_lat(omap->dev, -1);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ciout:
8308c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(omap->dev);
8318c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(omap->dev);
8328c2ecf20Sopenharmony_ci	return r;
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_cistatic int
8368c2ecf20Sopenharmony_ciomap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	return omap_i2c_xfer_common(adap, msgs, num, false);
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic int
8428c2ecf20Sopenharmony_ciomap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	return omap_i2c_xfer_common(adap, msgs, num, true);
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic u32
8488c2ecf20Sopenharmony_ciomap_i2c_func(struct i2c_adapter *adap)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
8518c2ecf20Sopenharmony_ci	       I2C_FUNC_PROTOCOL_MANGLING;
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_cistatic inline void
8558c2ecf20Sopenharmony_ciomap_i2c_complete_cmd(struct omap_i2c_dev *omap, u16 err)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	omap->cmd_err |= err;
8588c2ecf20Sopenharmony_ci	complete(&omap->cmd_complete);
8598c2ecf20Sopenharmony_ci}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_cistatic inline void
8628c2ecf20Sopenharmony_ciomap_i2c_ack_stat(struct omap_i2c_dev *omap, u16 stat)
8638c2ecf20Sopenharmony_ci{
8648c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, stat);
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic inline void i2c_omap_errata_i207(struct omap_i2c_dev *omap, u16 stat)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	/*
8708c2ecf20Sopenharmony_ci	 * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8)
8718c2ecf20Sopenharmony_ci	 * Not applicable for OMAP4.
8728c2ecf20Sopenharmony_ci	 * Under certain rare conditions, RDR could be set again
8738c2ecf20Sopenharmony_ci	 * when the bus is busy, then ignore the interrupt and
8748c2ecf20Sopenharmony_ci	 * clear the interrupt.
8758c2ecf20Sopenharmony_ci	 */
8768c2ecf20Sopenharmony_ci	if (stat & OMAP_I2C_STAT_RDR) {
8778c2ecf20Sopenharmony_ci		/* Step 1: If RDR is set, clear it */
8788c2ecf20Sopenharmony_ci		omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		/* Step 2: */
8818c2ecf20Sopenharmony_ci		if (!(omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG)
8828c2ecf20Sopenharmony_ci						& OMAP_I2C_STAT_BB)) {
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci			/* Step 3: */
8858c2ecf20Sopenharmony_ci			if (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG)
8868c2ecf20Sopenharmony_ci						& OMAP_I2C_STAT_RDR) {
8878c2ecf20Sopenharmony_ci				omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR);
8888c2ecf20Sopenharmony_ci				dev_dbg(omap->dev, "RDR when bus is busy.\n");
8898c2ecf20Sopenharmony_ci			}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci		}
8928c2ecf20Sopenharmony_ci	}
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci/* rev1 devices are apparently only on some 15xx */
8968c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP15XX
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cistatic irqreturn_t
8998c2ecf20Sopenharmony_ciomap_i2c_omap1_isr(int this_irq, void *dev_id)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	struct omap_i2c_dev *omap = dev_id;
9028c2ecf20Sopenharmony_ci	u16 iv, w;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(omap->dev))
9058c2ecf20Sopenharmony_ci		return IRQ_NONE;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	iv = omap_i2c_read_reg(omap, OMAP_I2C_IV_REG);
9088c2ecf20Sopenharmony_ci	switch (iv) {
9098c2ecf20Sopenharmony_ci	case 0x00:	/* None */
9108c2ecf20Sopenharmony_ci		break;
9118c2ecf20Sopenharmony_ci	case 0x01:	/* Arbitration lost */
9128c2ecf20Sopenharmony_ci		dev_err(omap->dev, "Arbitration lost\n");
9138c2ecf20Sopenharmony_ci		omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_AL);
9148c2ecf20Sopenharmony_ci		break;
9158c2ecf20Sopenharmony_ci	case 0x02:	/* No acknowledgement */
9168c2ecf20Sopenharmony_ci		omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_NACK);
9178c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
9188c2ecf20Sopenharmony_ci		break;
9198c2ecf20Sopenharmony_ci	case 0x03:	/* Register access ready */
9208c2ecf20Sopenharmony_ci		omap_i2c_complete_cmd(omap, 0);
9218c2ecf20Sopenharmony_ci		break;
9228c2ecf20Sopenharmony_ci	case 0x04:	/* Receive data ready */
9238c2ecf20Sopenharmony_ci		if (omap->buf_len) {
9248c2ecf20Sopenharmony_ci			w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG);
9258c2ecf20Sopenharmony_ci			*omap->buf++ = w;
9268c2ecf20Sopenharmony_ci			omap->buf_len--;
9278c2ecf20Sopenharmony_ci			if (omap->buf_len) {
9288c2ecf20Sopenharmony_ci				*omap->buf++ = w >> 8;
9298c2ecf20Sopenharmony_ci				omap->buf_len--;
9308c2ecf20Sopenharmony_ci			}
9318c2ecf20Sopenharmony_ci		} else
9328c2ecf20Sopenharmony_ci			dev_err(omap->dev, "RRDY IRQ while no data requested\n");
9338c2ecf20Sopenharmony_ci		break;
9348c2ecf20Sopenharmony_ci	case 0x05:	/* Transmit data ready */
9358c2ecf20Sopenharmony_ci		if (omap->buf_len) {
9368c2ecf20Sopenharmony_ci			w = *omap->buf++;
9378c2ecf20Sopenharmony_ci			omap->buf_len--;
9388c2ecf20Sopenharmony_ci			if (omap->buf_len) {
9398c2ecf20Sopenharmony_ci				w |= *omap->buf++ << 8;
9408c2ecf20Sopenharmony_ci				omap->buf_len--;
9418c2ecf20Sopenharmony_ci			}
9428c2ecf20Sopenharmony_ci			omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w);
9438c2ecf20Sopenharmony_ci		} else
9448c2ecf20Sopenharmony_ci			dev_err(omap->dev, "XRDY IRQ while no data to send\n");
9458c2ecf20Sopenharmony_ci		break;
9468c2ecf20Sopenharmony_ci	default:
9478c2ecf20Sopenharmony_ci		return IRQ_NONE;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci#else
9538c2ecf20Sopenharmony_ci#define omap_i2c_omap1_isr		NULL
9548c2ecf20Sopenharmony_ci#endif
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci/*
9578c2ecf20Sopenharmony_ci * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
9588c2ecf20Sopenharmony_ci * data to DATA_REG. Otherwise some data bytes can be lost while transferring
9598c2ecf20Sopenharmony_ci * them from the memory to the I2C interface.
9608c2ecf20Sopenharmony_ci */
9618c2ecf20Sopenharmony_cistatic int errata_omap3_i462(struct omap_i2c_dev *omap)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	unsigned long timeout = 10000;
9648c2ecf20Sopenharmony_ci	u16 stat;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	do {
9678c2ecf20Sopenharmony_ci		stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
9688c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_XUDF)
9698c2ecf20Sopenharmony_ci			break;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
9728c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_XRDY |
9738c2ecf20Sopenharmony_ci							OMAP_I2C_STAT_XDR));
9748c2ecf20Sopenharmony_ci			if (stat & OMAP_I2C_STAT_NACK) {
9758c2ecf20Sopenharmony_ci				omap->cmd_err |= OMAP_I2C_STAT_NACK;
9768c2ecf20Sopenharmony_ci				omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK);
9778c2ecf20Sopenharmony_ci			}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci			if (stat & OMAP_I2C_STAT_AL) {
9808c2ecf20Sopenharmony_ci				dev_err(omap->dev, "Arbitration lost\n");
9818c2ecf20Sopenharmony_ci				omap->cmd_err |= OMAP_I2C_STAT_AL;
9828c2ecf20Sopenharmony_ci				omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL);
9838c2ecf20Sopenharmony_ci			}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci			return -EIO;
9868c2ecf20Sopenharmony_ci		}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		cpu_relax();
9898c2ecf20Sopenharmony_ci	} while (--timeout);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	if (!timeout) {
9928c2ecf20Sopenharmony_ci		dev_err(omap->dev, "timeout waiting on XUDF bit\n");
9938c2ecf20Sopenharmony_ci		return 0;
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	return 0;
9978c2ecf20Sopenharmony_ci}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_cistatic void omap_i2c_receive_data(struct omap_i2c_dev *omap, u8 num_bytes,
10008c2ecf20Sopenharmony_ci		bool is_rdr)
10018c2ecf20Sopenharmony_ci{
10028c2ecf20Sopenharmony_ci	u16		w;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	while (num_bytes--) {
10058c2ecf20Sopenharmony_ci		w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG);
10068c2ecf20Sopenharmony_ci		*omap->buf++ = w;
10078c2ecf20Sopenharmony_ci		omap->buf_len--;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		/*
10108c2ecf20Sopenharmony_ci		 * Data reg in 2430, omap3 and
10118c2ecf20Sopenharmony_ci		 * omap4 is 8 bit wide
10128c2ecf20Sopenharmony_ci		 */
10138c2ecf20Sopenharmony_ci		if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
10148c2ecf20Sopenharmony_ci			*omap->buf++ = w >> 8;
10158c2ecf20Sopenharmony_ci			omap->buf_len--;
10168c2ecf20Sopenharmony_ci		}
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_cistatic int omap_i2c_transmit_data(struct omap_i2c_dev *omap, u8 num_bytes,
10218c2ecf20Sopenharmony_ci		bool is_xdr)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	u16		w;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	while (num_bytes--) {
10268c2ecf20Sopenharmony_ci		w = *omap->buf++;
10278c2ecf20Sopenharmony_ci		omap->buf_len--;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci		/*
10308c2ecf20Sopenharmony_ci		 * Data reg in 2430, omap3 and
10318c2ecf20Sopenharmony_ci		 * omap4 is 8 bit wide
10328c2ecf20Sopenharmony_ci		 */
10338c2ecf20Sopenharmony_ci		if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
10348c2ecf20Sopenharmony_ci			w |= *omap->buf++ << 8;
10358c2ecf20Sopenharmony_ci			omap->buf_len--;
10368c2ecf20Sopenharmony_ci		}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		if (omap->errata & I2C_OMAP_ERRATA_I462) {
10398c2ecf20Sopenharmony_ci			int ret;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci			ret = errata_omap3_i462(omap);
10428c2ecf20Sopenharmony_ci			if (ret < 0)
10438c2ecf20Sopenharmony_ci				return ret;
10448c2ecf20Sopenharmony_ci		}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w);
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return 0;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_cistatic irqreturn_t
10538c2ecf20Sopenharmony_ciomap_i2c_isr(int irq, void *dev_id)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	struct omap_i2c_dev *omap = dev_id;
10568c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_HANDLED;
10578c2ecf20Sopenharmony_ci	u16 mask;
10588c2ecf20Sopenharmony_ci	u16 stat;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
10618c2ecf20Sopenharmony_ci	mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG) & ~OMAP_I2C_STAT_NACK;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	if (stat & mask)
10648c2ecf20Sopenharmony_ci		ret = IRQ_WAKE_THREAD;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	return ret;
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_cistatic int omap_i2c_xfer_data(struct omap_i2c_dev *omap)
10708c2ecf20Sopenharmony_ci{
10718c2ecf20Sopenharmony_ci	u16 bits;
10728c2ecf20Sopenharmony_ci	u16 stat;
10738c2ecf20Sopenharmony_ci	int err = 0, count = 0;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	do {
10768c2ecf20Sopenharmony_ci		bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
10778c2ecf20Sopenharmony_ci		stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
10788c2ecf20Sopenharmony_ci		stat &= bits;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci		/* If we're in receiver mode, ignore XDR/XRDY */
10818c2ecf20Sopenharmony_ci		if (omap->receiver)
10828c2ecf20Sopenharmony_ci			stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY);
10838c2ecf20Sopenharmony_ci		else
10848c2ecf20Sopenharmony_ci			stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci		if (!stat) {
10878c2ecf20Sopenharmony_ci			/* my work here is done */
10888c2ecf20Sopenharmony_ci			err = -EAGAIN;
10898c2ecf20Sopenharmony_ci			break;
10908c2ecf20Sopenharmony_ci		}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci		dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat);
10938c2ecf20Sopenharmony_ci		if (count++ == 100) {
10948c2ecf20Sopenharmony_ci			dev_warn(omap->dev, "Too much work in one IRQ\n");
10958c2ecf20Sopenharmony_ci			break;
10968c2ecf20Sopenharmony_ci		}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_NACK) {
10998c2ecf20Sopenharmony_ci			err |= OMAP_I2C_STAT_NACK;
11008c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK);
11018c2ecf20Sopenharmony_ci		}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_AL) {
11048c2ecf20Sopenharmony_ci			dev_err(omap->dev, "Arbitration lost\n");
11058c2ecf20Sopenharmony_ci			err |= OMAP_I2C_STAT_AL;
11068c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL);
11078c2ecf20Sopenharmony_ci		}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci		/*
11108c2ecf20Sopenharmony_ci		 * ProDB0017052: Clear ARDY bit twice
11118c2ecf20Sopenharmony_ci		 */
11128c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_ARDY)
11138c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ARDY);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci		if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
11168c2ecf20Sopenharmony_ci					OMAP_I2C_STAT_AL)) {
11178c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_RRDY |
11188c2ecf20Sopenharmony_ci						OMAP_I2C_STAT_RDR |
11198c2ecf20Sopenharmony_ci						OMAP_I2C_STAT_XRDY |
11208c2ecf20Sopenharmony_ci						OMAP_I2C_STAT_XDR |
11218c2ecf20Sopenharmony_ci						OMAP_I2C_STAT_ARDY));
11228c2ecf20Sopenharmony_ci			break;
11238c2ecf20Sopenharmony_ci		}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_RDR) {
11268c2ecf20Sopenharmony_ci			u8 num_bytes = 1;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci			if (omap->fifo_size)
11298c2ecf20Sopenharmony_ci				num_bytes = omap->buf_len;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci			if (omap->errata & I2C_OMAP_ERRATA_I207) {
11328c2ecf20Sopenharmony_ci				i2c_omap_errata_i207(omap, stat);
11338c2ecf20Sopenharmony_ci				num_bytes = (omap_i2c_read_reg(omap,
11348c2ecf20Sopenharmony_ci					OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F;
11358c2ecf20Sopenharmony_ci			}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci			omap_i2c_receive_data(omap, num_bytes, true);
11388c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR);
11398c2ecf20Sopenharmony_ci			continue;
11408c2ecf20Sopenharmony_ci		}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_RRDY) {
11438c2ecf20Sopenharmony_ci			u8 num_bytes = 1;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci			if (omap->threshold)
11468c2ecf20Sopenharmony_ci				num_bytes = omap->threshold;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci			omap_i2c_receive_data(omap, num_bytes, false);
11498c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RRDY);
11508c2ecf20Sopenharmony_ci			continue;
11518c2ecf20Sopenharmony_ci		}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_XDR) {
11548c2ecf20Sopenharmony_ci			u8 num_bytes = 1;
11558c2ecf20Sopenharmony_ci			int ret;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci			if (omap->fifo_size)
11588c2ecf20Sopenharmony_ci				num_bytes = omap->buf_len;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci			ret = omap_i2c_transmit_data(omap, num_bytes, true);
11618c2ecf20Sopenharmony_ci			if (ret < 0)
11628c2ecf20Sopenharmony_ci				break;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XDR);
11658c2ecf20Sopenharmony_ci			continue;
11668c2ecf20Sopenharmony_ci		}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_XRDY) {
11698c2ecf20Sopenharmony_ci			u8 num_bytes = 1;
11708c2ecf20Sopenharmony_ci			int ret;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci			if (omap->threshold)
11738c2ecf20Sopenharmony_ci				num_bytes = omap->threshold;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci			ret = omap_i2c_transmit_data(omap, num_bytes, false);
11768c2ecf20Sopenharmony_ci			if (ret < 0)
11778c2ecf20Sopenharmony_ci				break;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XRDY);
11808c2ecf20Sopenharmony_ci			continue;
11818c2ecf20Sopenharmony_ci		}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_ROVR) {
11848c2ecf20Sopenharmony_ci			dev_err(omap->dev, "Receive overrun\n");
11858c2ecf20Sopenharmony_ci			err |= OMAP_I2C_STAT_ROVR;
11868c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ROVR);
11878c2ecf20Sopenharmony_ci			break;
11888c2ecf20Sopenharmony_ci		}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci		if (stat & OMAP_I2C_STAT_XUDF) {
11918c2ecf20Sopenharmony_ci			dev_err(omap->dev, "Transmit underflow\n");
11928c2ecf20Sopenharmony_ci			err |= OMAP_I2C_STAT_XUDF;
11938c2ecf20Sopenharmony_ci			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XUDF);
11948c2ecf20Sopenharmony_ci			break;
11958c2ecf20Sopenharmony_ci		}
11968c2ecf20Sopenharmony_ci	} while (stat);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	return err;
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_cistatic irqreturn_t
12028c2ecf20Sopenharmony_ciomap_i2c_isr_thread(int this_irq, void *dev_id)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	int ret;
12058c2ecf20Sopenharmony_ci	struct omap_i2c_dev *omap = dev_id;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	ret = omap_i2c_xfer_data(omap);
12088c2ecf20Sopenharmony_ci	if (ret != -EAGAIN)
12098c2ecf20Sopenharmony_ci		omap_i2c_complete_cmd(omap, ret);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistatic const struct i2c_algorithm omap_i2c_algo = {
12158c2ecf20Sopenharmony_ci	.master_xfer	= omap_i2c_xfer_irq,
12168c2ecf20Sopenharmony_ci	.master_xfer_atomic	= omap_i2c_xfer_polling,
12178c2ecf20Sopenharmony_ci	.functionality	= omap_i2c_func,
12188c2ecf20Sopenharmony_ci};
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_cistatic const struct i2c_adapter_quirks omap_i2c_quirks = {
12218c2ecf20Sopenharmony_ci	.flags = I2C_AQ_NO_ZERO_LEN,
12228c2ecf20Sopenharmony_ci};
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
12258c2ecf20Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap2420_pdata = {
12268c2ecf20Sopenharmony_ci	.rev = OMAP_I2C_IP_VERSION_1,
12278c2ecf20Sopenharmony_ci	.flags = OMAP_I2C_FLAG_NO_FIFO |
12288c2ecf20Sopenharmony_ci			OMAP_I2C_FLAG_SIMPLE_CLOCK |
12298c2ecf20Sopenharmony_ci			OMAP_I2C_FLAG_16BIT_DATA_REG |
12308c2ecf20Sopenharmony_ci			OMAP_I2C_FLAG_BUS_SHIFT_2,
12318c2ecf20Sopenharmony_ci};
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap2430_pdata = {
12348c2ecf20Sopenharmony_ci	.rev = OMAP_I2C_IP_VERSION_1,
12358c2ecf20Sopenharmony_ci	.flags = OMAP_I2C_FLAG_BUS_SHIFT_2 |
12368c2ecf20Sopenharmony_ci			OMAP_I2C_FLAG_FORCE_19200_INT_CLK,
12378c2ecf20Sopenharmony_ci};
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap3_pdata = {
12408c2ecf20Sopenharmony_ci	.rev = OMAP_I2C_IP_VERSION_1,
12418c2ecf20Sopenharmony_ci	.flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
12428c2ecf20Sopenharmony_ci};
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap4_pdata = {
12458c2ecf20Sopenharmony_ci	.rev = OMAP_I2C_IP_VERSION_2,
12468c2ecf20Sopenharmony_ci};
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_cistatic const struct of_device_id omap_i2c_of_match[] = {
12498c2ecf20Sopenharmony_ci	{
12508c2ecf20Sopenharmony_ci		.compatible = "ti,omap4-i2c",
12518c2ecf20Sopenharmony_ci		.data = &omap4_pdata,
12528c2ecf20Sopenharmony_ci	},
12538c2ecf20Sopenharmony_ci	{
12548c2ecf20Sopenharmony_ci		.compatible = "ti,omap3-i2c",
12558c2ecf20Sopenharmony_ci		.data = &omap3_pdata,
12568c2ecf20Sopenharmony_ci	},
12578c2ecf20Sopenharmony_ci	{
12588c2ecf20Sopenharmony_ci		.compatible = "ti,omap2430-i2c",
12598c2ecf20Sopenharmony_ci		.data = &omap2430_pdata,
12608c2ecf20Sopenharmony_ci	},
12618c2ecf20Sopenharmony_ci	{
12628c2ecf20Sopenharmony_ci		.compatible = "ti,omap2420-i2c",
12638c2ecf20Sopenharmony_ci		.data = &omap2420_pdata,
12648c2ecf20Sopenharmony_ci	},
12658c2ecf20Sopenharmony_ci	{ },
12668c2ecf20Sopenharmony_ci};
12678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_i2c_of_match);
12688c2ecf20Sopenharmony_ci#endif
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci#define OMAP_I2C_SCHEME(rev)		((rev & 0xc000) >> 14)
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev) (rev >> 4)
12738c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_0_MINOR(rev) (rev & 0xf)
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev) ((rev & 0x0700) >> 7)
12768c2ecf20Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_1_MINOR(rev) (rev & 0x1f)
12778c2ecf20Sopenharmony_ci#define OMAP_I2C_SCHEME_0		0
12788c2ecf20Sopenharmony_ci#define OMAP_I2C_SCHEME_1		1
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cistatic int omap_i2c_get_scl(struct i2c_adapter *adap)
12818c2ecf20Sopenharmony_ci{
12828c2ecf20Sopenharmony_ci	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
12838c2ecf20Sopenharmony_ci	u32 reg;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	return reg & OMAP_I2C_SYSTEST_SCL_I_FUNC;
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_cistatic int omap_i2c_get_sda(struct i2c_adapter *adap)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
12938c2ecf20Sopenharmony_ci	u32 reg;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	return reg & OMAP_I2C_SYSTEST_SDA_I_FUNC;
12988c2ecf20Sopenharmony_ci}
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_cistatic void omap_i2c_set_scl(struct i2c_adapter *adap, int val)
13018c2ecf20Sopenharmony_ci{
13028c2ecf20Sopenharmony_ci	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
13038c2ecf20Sopenharmony_ci	u32 reg;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
13068c2ecf20Sopenharmony_ci	if (val)
13078c2ecf20Sopenharmony_ci		reg |= OMAP_I2C_SYSTEST_SCL_O;
13088c2ecf20Sopenharmony_ci	else
13098c2ecf20Sopenharmony_ci		reg &= ~OMAP_I2C_SYSTEST_SCL_O;
13108c2ecf20Sopenharmony_ci	omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
13118c2ecf20Sopenharmony_ci}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_cistatic void omap_i2c_prepare_recovery(struct i2c_adapter *adap)
13148c2ecf20Sopenharmony_ci{
13158c2ecf20Sopenharmony_ci	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
13168c2ecf20Sopenharmony_ci	u32 reg;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
13198c2ecf20Sopenharmony_ci	/* enable test mode */
13208c2ecf20Sopenharmony_ci	reg |= OMAP_I2C_SYSTEST_ST_EN;
13218c2ecf20Sopenharmony_ci	/* select SDA/SCL IO mode */
13228c2ecf20Sopenharmony_ci	reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT;
13238c2ecf20Sopenharmony_ci	/* set SCL to high-impedance state (reset value is 0) */
13248c2ecf20Sopenharmony_ci	reg |= OMAP_I2C_SYSTEST_SCL_O;
13258c2ecf20Sopenharmony_ci	/* set SDA to high-impedance state (reset value is 0) */
13268c2ecf20Sopenharmony_ci	reg |= OMAP_I2C_SYSTEST_SDA_O;
13278c2ecf20Sopenharmony_ci	omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_cistatic void omap_i2c_unprepare_recovery(struct i2c_adapter *adap)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
13338c2ecf20Sopenharmony_ci	u32 reg;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
13368c2ecf20Sopenharmony_ci	/* restore reset values */
13378c2ecf20Sopenharmony_ci	reg &= ~OMAP_I2C_SYSTEST_ST_EN;
13388c2ecf20Sopenharmony_ci	reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK;
13398c2ecf20Sopenharmony_ci	reg &= ~OMAP_I2C_SYSTEST_SCL_O;
13408c2ecf20Sopenharmony_ci	reg &= ~OMAP_I2C_SYSTEST_SDA_O;
13418c2ecf20Sopenharmony_ci	omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_cistatic struct i2c_bus_recovery_info omap_i2c_bus_recovery_info = {
13458c2ecf20Sopenharmony_ci	.get_scl		= omap_i2c_get_scl,
13468c2ecf20Sopenharmony_ci	.get_sda		= omap_i2c_get_sda,
13478c2ecf20Sopenharmony_ci	.set_scl		= omap_i2c_set_scl,
13488c2ecf20Sopenharmony_ci	.prepare_recovery	= omap_i2c_prepare_recovery,
13498c2ecf20Sopenharmony_ci	.unprepare_recovery	= omap_i2c_unprepare_recovery,
13508c2ecf20Sopenharmony_ci	.recover_bus		= i2c_generic_scl_recovery,
13518c2ecf20Sopenharmony_ci};
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_cistatic int
13548c2ecf20Sopenharmony_ciomap_i2c_probe(struct platform_device *pdev)
13558c2ecf20Sopenharmony_ci{
13568c2ecf20Sopenharmony_ci	struct omap_i2c_dev	*omap;
13578c2ecf20Sopenharmony_ci	struct i2c_adapter	*adap;
13588c2ecf20Sopenharmony_ci	const struct omap_i2c_bus_platform_data *pdata =
13598c2ecf20Sopenharmony_ci		dev_get_platdata(&pdev->dev);
13608c2ecf20Sopenharmony_ci	struct device_node	*node = pdev->dev.of_node;
13618c2ecf20Sopenharmony_ci	const struct of_device_id *match;
13628c2ecf20Sopenharmony_ci	int irq;
13638c2ecf20Sopenharmony_ci	int r;
13648c2ecf20Sopenharmony_ci	u32 rev;
13658c2ecf20Sopenharmony_ci	u16 minor, major;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
13688c2ecf20Sopenharmony_ci	if (irq < 0)
13698c2ecf20Sopenharmony_ci		return irq;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL);
13728c2ecf20Sopenharmony_ci	if (!omap)
13738c2ecf20Sopenharmony_ci		return -ENOMEM;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	omap->base = devm_platform_ioremap_resource(pdev, 0);
13768c2ecf20Sopenharmony_ci	if (IS_ERR(omap->base))
13778c2ecf20Sopenharmony_ci		return PTR_ERR(omap->base);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev);
13808c2ecf20Sopenharmony_ci	if (match) {
13818c2ecf20Sopenharmony_ci		u32 freq = I2C_MAX_STANDARD_MODE_FREQ;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci		pdata = match->data;
13848c2ecf20Sopenharmony_ci		omap->flags = pdata->flags;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		of_property_read_u32(node, "clock-frequency", &freq);
13878c2ecf20Sopenharmony_ci		/* convert DT freq value in Hz into kHz for speed */
13888c2ecf20Sopenharmony_ci		omap->speed = freq / 1000;
13898c2ecf20Sopenharmony_ci	} else if (pdata != NULL) {
13908c2ecf20Sopenharmony_ci		omap->speed = pdata->clkrate;
13918c2ecf20Sopenharmony_ci		omap->flags = pdata->flags;
13928c2ecf20Sopenharmony_ci		omap->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	omap->dev = &pdev->dev;
13968c2ecf20Sopenharmony_ci	omap->irq = irq;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, omap);
13998c2ecf20Sopenharmony_ci	init_completion(&omap->cmd_complete);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	omap->reg_shift = (omap->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	pm_runtime_enable(omap->dev);
14048c2ecf20Sopenharmony_ci	pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT);
14058c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(omap->dev);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	r = pm_runtime_resume_and_get(omap->dev);
14088c2ecf20Sopenharmony_ci	if (r < 0)
14098c2ecf20Sopenharmony_ci		goto err_disable_pm;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	/*
14128c2ecf20Sopenharmony_ci	 * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2.
14138c2ecf20Sopenharmony_ci	 * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset.
14148c2ecf20Sopenharmony_ci	 * Also since the omap_i2c_read_reg uses reg_map_ip_* a
14158c2ecf20Sopenharmony_ci	 * readw_relaxed is done.
14168c2ecf20Sopenharmony_ci	 */
14178c2ecf20Sopenharmony_ci	rev = readw_relaxed(omap->base + 0x04);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	omap->scheme = OMAP_I2C_SCHEME(rev);
14208c2ecf20Sopenharmony_ci	switch (omap->scheme) {
14218c2ecf20Sopenharmony_ci	case OMAP_I2C_SCHEME_0:
14228c2ecf20Sopenharmony_ci		omap->regs = (u8 *)reg_map_ip_v1;
14238c2ecf20Sopenharmony_ci		omap->rev = omap_i2c_read_reg(omap, OMAP_I2C_REV_REG);
14248c2ecf20Sopenharmony_ci		minor = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev);
14258c2ecf20Sopenharmony_ci		major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev);
14268c2ecf20Sopenharmony_ci		break;
14278c2ecf20Sopenharmony_ci	case OMAP_I2C_SCHEME_1:
14288c2ecf20Sopenharmony_ci	default:
14298c2ecf20Sopenharmony_ci		omap->regs = (u8 *)reg_map_ip_v2;
14308c2ecf20Sopenharmony_ci		rev = (rev << 16) |
14318c2ecf20Sopenharmony_ci			omap_i2c_read_reg(omap, OMAP_I2C_IP_V2_REVNB_LO);
14328c2ecf20Sopenharmony_ci		minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev);
14338c2ecf20Sopenharmony_ci		major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev);
14348c2ecf20Sopenharmony_ci		omap->rev = rev;
14358c2ecf20Sopenharmony_ci	}
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	omap->errata = 0;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	if (omap->rev >= OMAP_I2C_REV_ON_2430 &&
14408c2ecf20Sopenharmony_ci			omap->rev < OMAP_I2C_REV_ON_4430_PLUS)
14418c2ecf20Sopenharmony_ci		omap->errata |= I2C_OMAP_ERRATA_I207;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	if (omap->rev <= OMAP_I2C_REV_ON_3430_3530)
14448c2ecf20Sopenharmony_ci		omap->errata |= I2C_OMAP_ERRATA_I462;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	if (!(omap->flags & OMAP_I2C_FLAG_NO_FIFO)) {
14478c2ecf20Sopenharmony_ci		u16 s;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci		/* Set up the fifo size - Get total size */
14508c2ecf20Sopenharmony_ci		s = (omap_i2c_read_reg(omap, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
14518c2ecf20Sopenharmony_ci		omap->fifo_size = 0x8 << s;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci		/*
14548c2ecf20Sopenharmony_ci		 * Set up notification threshold as half the total available
14558c2ecf20Sopenharmony_ci		 * size. This is to ensure that we can handle the status on int
14568c2ecf20Sopenharmony_ci		 * call back latencies.
14578c2ecf20Sopenharmony_ci		 */
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci		omap->fifo_size = (omap->fifo_size / 2);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci		if (omap->rev < OMAP_I2C_REV_ON_3630)
14628c2ecf20Sopenharmony_ci			omap->b_hw = 1; /* Enable hardware fixes */
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci		/* calculate wakeup latency constraint for MPU */
14658c2ecf20Sopenharmony_ci		if (omap->set_mpu_wkup_lat != NULL)
14668c2ecf20Sopenharmony_ci			omap->latency = (1000000 * omap->fifo_size) /
14678c2ecf20Sopenharmony_ci				       (1000 * omap->speed / 8);
14688c2ecf20Sopenharmony_ci	}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	/* reset ASAP, clearing any IRQs */
14718c2ecf20Sopenharmony_ci	omap_i2c_init(omap);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (omap->rev < OMAP_I2C_OMAP1_REV_2)
14748c2ecf20Sopenharmony_ci		r = devm_request_irq(&pdev->dev, omap->irq, omap_i2c_omap1_isr,
14758c2ecf20Sopenharmony_ci				IRQF_NO_SUSPEND, pdev->name, omap);
14768c2ecf20Sopenharmony_ci	else
14778c2ecf20Sopenharmony_ci		r = devm_request_threaded_irq(&pdev->dev, omap->irq,
14788c2ecf20Sopenharmony_ci				omap_i2c_isr, omap_i2c_isr_thread,
14798c2ecf20Sopenharmony_ci				IRQF_NO_SUSPEND | IRQF_ONESHOT,
14808c2ecf20Sopenharmony_ci				pdev->name, omap);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	if (r) {
14838c2ecf20Sopenharmony_ci		dev_err(omap->dev, "failure requesting irq %i\n", omap->irq);
14848c2ecf20Sopenharmony_ci		goto err_unuse_clocks;
14858c2ecf20Sopenharmony_ci	}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	adap = &omap->adapter;
14888c2ecf20Sopenharmony_ci	i2c_set_adapdata(adap, omap);
14898c2ecf20Sopenharmony_ci	adap->owner = THIS_MODULE;
14908c2ecf20Sopenharmony_ci	adap->class = I2C_CLASS_DEPRECATED;
14918c2ecf20Sopenharmony_ci	strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
14928c2ecf20Sopenharmony_ci	adap->algo = &omap_i2c_algo;
14938c2ecf20Sopenharmony_ci	adap->quirks = &omap_i2c_quirks;
14948c2ecf20Sopenharmony_ci	adap->dev.parent = &pdev->dev;
14958c2ecf20Sopenharmony_ci	adap->dev.of_node = pdev->dev.of_node;
14968c2ecf20Sopenharmony_ci	adap->bus_recovery_info = &omap_i2c_bus_recovery_info;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	/* i2c device drivers may be active on return from add_adapter() */
14998c2ecf20Sopenharmony_ci	adap->nr = pdev->id;
15008c2ecf20Sopenharmony_ci	r = i2c_add_numbered_adapter(adap);
15018c2ecf20Sopenharmony_ci	if (r)
15028c2ecf20Sopenharmony_ci		goto err_unuse_clocks;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr,
15058c2ecf20Sopenharmony_ci		 major, minor, omap->speed);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(omap->dev);
15088c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(omap->dev);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	return 0;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_cierr_unuse_clocks:
15138c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
15148c2ecf20Sopenharmony_ci	pm_runtime_dont_use_autosuspend(omap->dev);
15158c2ecf20Sopenharmony_ci	pm_runtime_put_sync(omap->dev);
15168c2ecf20Sopenharmony_cierr_disable_pm:
15178c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	return r;
15208c2ecf20Sopenharmony_ci}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_cistatic int omap_i2c_remove(struct platform_device *pdev)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	struct omap_i2c_dev	*omap = platform_get_drvdata(pdev);
15258c2ecf20Sopenharmony_ci	int ret;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	i2c_del_adapter(&omap->adapter);
15288c2ecf20Sopenharmony_ci	ret = pm_runtime_resume_and_get(&pdev->dev);
15298c2ecf20Sopenharmony_ci	if (ret < 0)
15308c2ecf20Sopenharmony_ci		return ret;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
15338c2ecf20Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
15348c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
15358c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
15368c2ecf20Sopenharmony_ci	return 0;
15378c2ecf20Sopenharmony_ci}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_cistatic int __maybe_unused omap_i2c_runtime_suspend(struct device *dev)
15408c2ecf20Sopenharmony_ci{
15418c2ecf20Sopenharmony_ci	struct omap_i2c_dev *omap = dev_get_drvdata(dev);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	omap->iestate = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	if (omap->scheme == OMAP_I2C_SCHEME_0)
15468c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, 0);
15478c2ecf20Sopenharmony_ci	else
15488c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_IP_V2_IRQENABLE_CLR,
15498c2ecf20Sopenharmony_ci				   OMAP_I2C_IP_V2_INTERRUPTS_MASK);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	if (omap->rev < OMAP_I2C_OMAP1_REV_2) {
15528c2ecf20Sopenharmony_ci		omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); /* Read clears */
15538c2ecf20Sopenharmony_ci	} else {
15548c2ecf20Sopenharmony_ci		omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, omap->iestate);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci		/* Flush posted write */
15578c2ecf20Sopenharmony_ci		omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
15588c2ecf20Sopenharmony_ci	}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	pinctrl_pm_select_sleep_state(dev);
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	return 0;
15638c2ecf20Sopenharmony_ci}
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_cistatic int __maybe_unused omap_i2c_runtime_resume(struct device *dev)
15668c2ecf20Sopenharmony_ci{
15678c2ecf20Sopenharmony_ci	struct omap_i2c_dev *omap = dev_get_drvdata(dev);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	pinctrl_pm_select_default_state(dev);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	if (!omap->regs)
15728c2ecf20Sopenharmony_ci		return 0;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	__omap_i2c_init(omap);
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	return 0;
15778c2ecf20Sopenharmony_ci}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_cistatic const struct dev_pm_ops omap_i2c_pm_ops = {
15808c2ecf20Sopenharmony_ci	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
15818c2ecf20Sopenharmony_ci				      pm_runtime_force_resume)
15828c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
15838c2ecf20Sopenharmony_ci			   omap_i2c_runtime_resume, NULL)
15848c2ecf20Sopenharmony_ci};
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cistatic struct platform_driver omap_i2c_driver = {
15878c2ecf20Sopenharmony_ci	.probe		= omap_i2c_probe,
15888c2ecf20Sopenharmony_ci	.remove		= omap_i2c_remove,
15898c2ecf20Sopenharmony_ci	.driver		= {
15908c2ecf20Sopenharmony_ci		.name	= "omap_i2c",
15918c2ecf20Sopenharmony_ci		.pm	= &omap_i2c_pm_ops,
15928c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(omap_i2c_of_match),
15938c2ecf20Sopenharmony_ci	},
15948c2ecf20Sopenharmony_ci};
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci/* I2C may be needed to bring up other drivers */
15978c2ecf20Sopenharmony_cistatic int __init
15988c2ecf20Sopenharmony_ciomap_i2c_init_driver(void)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	return platform_driver_register(&omap_i2c_driver);
16018c2ecf20Sopenharmony_ci}
16028c2ecf20Sopenharmony_cisubsys_initcall(omap_i2c_init_driver);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_cistatic void __exit omap_i2c_exit_driver(void)
16058c2ecf20Sopenharmony_ci{
16068c2ecf20Sopenharmony_ci	platform_driver_unregister(&omap_i2c_driver);
16078c2ecf20Sopenharmony_ci}
16088c2ecf20Sopenharmony_cimodule_exit(omap_i2c_exit_driver);
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ciMODULE_AUTHOR("MontaVista Software, Inc. (and others)");
16118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI OMAP I2C bus adapter");
16128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
16138c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:omap_i2c");
1614