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