162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI OMAP I2C master mode driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2003 MontaVista Software, Inc. 662306a36Sopenharmony_ci * Copyright (C) 2005 Nokia Corporation 762306a36Sopenharmony_ci * Copyright (C) 2004 - 2007 Texas Instruments. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Originally written by MontaVista Software, Inc. 1062306a36Sopenharmony_ci * Additional contributions by: 1162306a36Sopenharmony_ci * Tony Lindgren <tony@atomide.com> 1262306a36Sopenharmony_ci * Imre Deak <imre.deak@nokia.com> 1362306a36Sopenharmony_ci * Juha Yrjölä <juha.yrjola@solidboot.com> 1462306a36Sopenharmony_ci * Syed Khasim <x0khasim@ti.com> 1562306a36Sopenharmony_ci * Nishant Menon <nm@ti.com> 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/i2c.h> 2162306a36Sopenharmony_ci#include <linux/err.h> 2262306a36Sopenharmony_ci#include <linux/interrupt.h> 2362306a36Sopenharmony_ci#include <linux/completion.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/clk.h> 2662306a36Sopenharmony_ci#include <linux/io.h> 2762306a36Sopenharmony_ci#include <linux/of.h> 2862306a36Sopenharmony_ci#include <linux/of_device.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/platform_data/i2c-omap.h> 3162306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3262306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* I2C controller revisions */ 3562306a36Sopenharmony_ci#define OMAP_I2C_OMAP1_REV_2 0x20 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* I2C controller revisions present on specific hardware */ 3862306a36Sopenharmony_ci#define OMAP_I2C_REV_ON_2430 0x00000036 3962306a36Sopenharmony_ci#define OMAP_I2C_REV_ON_3430_3530 0x0000003C 4062306a36Sopenharmony_ci#define OMAP_I2C_REV_ON_3630 0x00000040 4162306a36Sopenharmony_ci#define OMAP_I2C_REV_ON_4430_PLUS 0x50400002 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* timeout waiting for the controller to respond */ 4462306a36Sopenharmony_ci#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* timeout for pm runtime autosuspend */ 4762306a36Sopenharmony_ci#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* timeout for making decision on bus free status */ 5062306a36Sopenharmony_ci#define OMAP_I2C_BUS_FREE_TIMEOUT (msecs_to_jiffies(10)) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ 5362306a36Sopenharmony_cienum { 5462306a36Sopenharmony_ci OMAP_I2C_REV_REG = 0, 5562306a36Sopenharmony_ci OMAP_I2C_IE_REG, 5662306a36Sopenharmony_ci OMAP_I2C_STAT_REG, 5762306a36Sopenharmony_ci OMAP_I2C_IV_REG, 5862306a36Sopenharmony_ci OMAP_I2C_WE_REG, 5962306a36Sopenharmony_ci OMAP_I2C_SYSS_REG, 6062306a36Sopenharmony_ci OMAP_I2C_BUF_REG, 6162306a36Sopenharmony_ci OMAP_I2C_CNT_REG, 6262306a36Sopenharmony_ci OMAP_I2C_DATA_REG, 6362306a36Sopenharmony_ci OMAP_I2C_SYSC_REG, 6462306a36Sopenharmony_ci OMAP_I2C_CON_REG, 6562306a36Sopenharmony_ci OMAP_I2C_OA_REG, 6662306a36Sopenharmony_ci OMAP_I2C_SA_REG, 6762306a36Sopenharmony_ci OMAP_I2C_PSC_REG, 6862306a36Sopenharmony_ci OMAP_I2C_SCLL_REG, 6962306a36Sopenharmony_ci OMAP_I2C_SCLH_REG, 7062306a36Sopenharmony_ci OMAP_I2C_SYSTEST_REG, 7162306a36Sopenharmony_ci OMAP_I2C_BUFSTAT_REG, 7262306a36Sopenharmony_ci /* only on OMAP4430 */ 7362306a36Sopenharmony_ci OMAP_I2C_IP_V2_REVNB_LO, 7462306a36Sopenharmony_ci OMAP_I2C_IP_V2_REVNB_HI, 7562306a36Sopenharmony_ci OMAP_I2C_IP_V2_IRQSTATUS_RAW, 7662306a36Sopenharmony_ci OMAP_I2C_IP_V2_IRQENABLE_SET, 7762306a36Sopenharmony_ci OMAP_I2C_IP_V2_IRQENABLE_CLR, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* I2C Interrupt Enable Register (OMAP_I2C_IE): */ 8162306a36Sopenharmony_ci#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ 8262306a36Sopenharmony_ci#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */ 8362306a36Sopenharmony_ci#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */ 8462306a36Sopenharmony_ci#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */ 8562306a36Sopenharmony_ci#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */ 8662306a36Sopenharmony_ci#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */ 8762306a36Sopenharmony_ci#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* I2C Status Register (OMAP_I2C_STAT): */ 9062306a36Sopenharmony_ci#define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */ 9162306a36Sopenharmony_ci#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */ 9262306a36Sopenharmony_ci#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */ 9362306a36Sopenharmony_ci#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */ 9462306a36Sopenharmony_ci#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ 9562306a36Sopenharmony_ci#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */ 9662306a36Sopenharmony_ci#define OMAP_I2C_STAT_BF (1 << 8) /* Bus Free */ 9762306a36Sopenharmony_ci#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */ 9862306a36Sopenharmony_ci#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */ 9962306a36Sopenharmony_ci#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */ 10062306a36Sopenharmony_ci#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */ 10162306a36Sopenharmony_ci#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* I2C WE wakeup enable register */ 10462306a36Sopenharmony_ci#define OMAP_I2C_WE_XDR_WE (1 << 14) /* TX drain wakup */ 10562306a36Sopenharmony_ci#define OMAP_I2C_WE_RDR_WE (1 << 13) /* RX drain wakeup */ 10662306a36Sopenharmony_ci#define OMAP_I2C_WE_AAS_WE (1 << 9) /* Address as slave wakeup*/ 10762306a36Sopenharmony_ci#define OMAP_I2C_WE_BF_WE (1 << 8) /* Bus free wakeup */ 10862306a36Sopenharmony_ci#define OMAP_I2C_WE_STC_WE (1 << 6) /* Start condition wakeup */ 10962306a36Sopenharmony_ci#define OMAP_I2C_WE_GC_WE (1 << 5) /* General call wakeup */ 11062306a36Sopenharmony_ci#define OMAP_I2C_WE_DRDY_WE (1 << 3) /* TX/RX data ready wakeup */ 11162306a36Sopenharmony_ci#define OMAP_I2C_WE_ARDY_WE (1 << 2) /* Reg access ready wakeup */ 11262306a36Sopenharmony_ci#define OMAP_I2C_WE_NACK_WE (1 << 1) /* No acknowledgment wakeup */ 11362306a36Sopenharmony_ci#define OMAP_I2C_WE_AL_WE (1 << 0) /* Arbitration lost wakeup */ 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define OMAP_I2C_WE_ALL (OMAP_I2C_WE_XDR_WE | OMAP_I2C_WE_RDR_WE | \ 11662306a36Sopenharmony_ci OMAP_I2C_WE_AAS_WE | OMAP_I2C_WE_BF_WE | \ 11762306a36Sopenharmony_ci OMAP_I2C_WE_STC_WE | OMAP_I2C_WE_GC_WE | \ 11862306a36Sopenharmony_ci OMAP_I2C_WE_DRDY_WE | OMAP_I2C_WE_ARDY_WE | \ 11962306a36Sopenharmony_ci OMAP_I2C_WE_NACK_WE | OMAP_I2C_WE_AL_WE) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */ 12262306a36Sopenharmony_ci#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */ 12362306a36Sopenharmony_ci#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */ 12462306a36Sopenharmony_ci#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */ 12562306a36Sopenharmony_ci#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* I2C Configuration Register (OMAP_I2C_CON): */ 12862306a36Sopenharmony_ci#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */ 12962306a36Sopenharmony_ci#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */ 13062306a36Sopenharmony_ci#define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */ 13162306a36Sopenharmony_ci#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */ 13262306a36Sopenharmony_ci#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */ 13362306a36Sopenharmony_ci#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */ 13462306a36Sopenharmony_ci#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */ 13562306a36Sopenharmony_ci#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */ 13662306a36Sopenharmony_ci#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */ 13762306a36Sopenharmony_ci#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* I2C SCL time value when Master */ 14062306a36Sopenharmony_ci#define OMAP_I2C_SCLL_HSSCLL 8 14162306a36Sopenharmony_ci#define OMAP_I2C_SCLH_HSSCLH 8 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* I2C System Test Register (OMAP_I2C_SYSTEST): */ 14462306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ 14562306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */ 14662306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */ 14762306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */ 14862306a36Sopenharmony_ci/* Functional mode */ 14962306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_I_FUNC (1 << 8) /* SCL line input value */ 15062306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_O_FUNC (1 << 7) /* SCL line output value */ 15162306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_I_FUNC (1 << 6) /* SDA line input value */ 15262306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_O_FUNC (1 << 5) /* SDA line output value */ 15362306a36Sopenharmony_ci/* SDA/SCL IO mode */ 15462306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */ 15562306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */ 15662306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */ 15762306a36Sopenharmony_ci#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */ 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* OCP_SYSSTATUS bit definitions */ 16062306a36Sopenharmony_ci#define SYSS_RESETDONE_MASK (1 << 0) 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* OCP_SYSCONFIG bit definitions */ 16362306a36Sopenharmony_ci#define SYSC_CLOCKACTIVITY_MASK (0x3 << 8) 16462306a36Sopenharmony_ci#define SYSC_SIDLEMODE_MASK (0x3 << 3) 16562306a36Sopenharmony_ci#define SYSC_ENAWAKEUP_MASK (1 << 2) 16662306a36Sopenharmony_ci#define SYSC_SOFTRESET_MASK (1 << 1) 16762306a36Sopenharmony_ci#define SYSC_AUTOIDLE_MASK (1 << 0) 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#define SYSC_IDLEMODE_SMART 0x2 17062306a36Sopenharmony_ci#define SYSC_CLOCKACTIVITY_FCLK 0x2 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* Errata definitions */ 17362306a36Sopenharmony_ci#define I2C_OMAP_ERRATA_I207 (1 << 0) 17462306a36Sopenharmony_ci#define I2C_OMAP_ERRATA_I462 (1 << 1) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistruct omap_i2c_dev { 17962306a36Sopenharmony_ci struct device *dev; 18062306a36Sopenharmony_ci void __iomem *base; /* virtual */ 18162306a36Sopenharmony_ci int irq; 18262306a36Sopenharmony_ci int reg_shift; /* bit shift for I2C register addresses */ 18362306a36Sopenharmony_ci struct completion cmd_complete; 18462306a36Sopenharmony_ci struct resource *ioarea; 18562306a36Sopenharmony_ci u32 latency; /* maximum mpu wkup latency */ 18662306a36Sopenharmony_ci void (*set_mpu_wkup_lat)(struct device *dev, 18762306a36Sopenharmony_ci long latency); 18862306a36Sopenharmony_ci u32 speed; /* Speed of bus in kHz */ 18962306a36Sopenharmony_ci u32 flags; 19062306a36Sopenharmony_ci u16 scheme; 19162306a36Sopenharmony_ci u16 cmd_err; 19262306a36Sopenharmony_ci u8 *buf; 19362306a36Sopenharmony_ci u8 *regs; 19462306a36Sopenharmony_ci size_t buf_len; 19562306a36Sopenharmony_ci struct i2c_adapter adapter; 19662306a36Sopenharmony_ci u8 threshold; 19762306a36Sopenharmony_ci u8 fifo_size; /* use as flag and value 19862306a36Sopenharmony_ci * fifo_size==0 implies no fifo 19962306a36Sopenharmony_ci * if set, should be trsh+1 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci u32 rev; 20262306a36Sopenharmony_ci unsigned b_hw:1; /* bad h/w fixes */ 20362306a36Sopenharmony_ci unsigned bb_valid:1; /* true when BB-bit reflects 20462306a36Sopenharmony_ci * the I2C bus state 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci unsigned receiver:1; /* true when we're in receiver mode */ 20762306a36Sopenharmony_ci u16 iestate; /* Saved interrupt register */ 20862306a36Sopenharmony_ci u16 pscstate; 20962306a36Sopenharmony_ci u16 scllstate; 21062306a36Sopenharmony_ci u16 sclhstate; 21162306a36Sopenharmony_ci u16 syscstate; 21262306a36Sopenharmony_ci u16 westate; 21362306a36Sopenharmony_ci u16 errata; 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic const u8 reg_map_ip_v1[] = { 21762306a36Sopenharmony_ci [OMAP_I2C_REV_REG] = 0x00, 21862306a36Sopenharmony_ci [OMAP_I2C_IE_REG] = 0x01, 21962306a36Sopenharmony_ci [OMAP_I2C_STAT_REG] = 0x02, 22062306a36Sopenharmony_ci [OMAP_I2C_IV_REG] = 0x03, 22162306a36Sopenharmony_ci [OMAP_I2C_WE_REG] = 0x03, 22262306a36Sopenharmony_ci [OMAP_I2C_SYSS_REG] = 0x04, 22362306a36Sopenharmony_ci [OMAP_I2C_BUF_REG] = 0x05, 22462306a36Sopenharmony_ci [OMAP_I2C_CNT_REG] = 0x06, 22562306a36Sopenharmony_ci [OMAP_I2C_DATA_REG] = 0x07, 22662306a36Sopenharmony_ci [OMAP_I2C_SYSC_REG] = 0x08, 22762306a36Sopenharmony_ci [OMAP_I2C_CON_REG] = 0x09, 22862306a36Sopenharmony_ci [OMAP_I2C_OA_REG] = 0x0a, 22962306a36Sopenharmony_ci [OMAP_I2C_SA_REG] = 0x0b, 23062306a36Sopenharmony_ci [OMAP_I2C_PSC_REG] = 0x0c, 23162306a36Sopenharmony_ci [OMAP_I2C_SCLL_REG] = 0x0d, 23262306a36Sopenharmony_ci [OMAP_I2C_SCLH_REG] = 0x0e, 23362306a36Sopenharmony_ci [OMAP_I2C_SYSTEST_REG] = 0x0f, 23462306a36Sopenharmony_ci [OMAP_I2C_BUFSTAT_REG] = 0x10, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic const u8 reg_map_ip_v2[] = { 23862306a36Sopenharmony_ci [OMAP_I2C_REV_REG] = 0x04, 23962306a36Sopenharmony_ci [OMAP_I2C_IE_REG] = 0x2c, 24062306a36Sopenharmony_ci [OMAP_I2C_STAT_REG] = 0x28, 24162306a36Sopenharmony_ci [OMAP_I2C_IV_REG] = 0x34, 24262306a36Sopenharmony_ci [OMAP_I2C_WE_REG] = 0x34, 24362306a36Sopenharmony_ci [OMAP_I2C_SYSS_REG] = 0x90, 24462306a36Sopenharmony_ci [OMAP_I2C_BUF_REG] = 0x94, 24562306a36Sopenharmony_ci [OMAP_I2C_CNT_REG] = 0x98, 24662306a36Sopenharmony_ci [OMAP_I2C_DATA_REG] = 0x9c, 24762306a36Sopenharmony_ci [OMAP_I2C_SYSC_REG] = 0x10, 24862306a36Sopenharmony_ci [OMAP_I2C_CON_REG] = 0xa4, 24962306a36Sopenharmony_ci [OMAP_I2C_OA_REG] = 0xa8, 25062306a36Sopenharmony_ci [OMAP_I2C_SA_REG] = 0xac, 25162306a36Sopenharmony_ci [OMAP_I2C_PSC_REG] = 0xb0, 25262306a36Sopenharmony_ci [OMAP_I2C_SCLL_REG] = 0xb4, 25362306a36Sopenharmony_ci [OMAP_I2C_SCLH_REG] = 0xb8, 25462306a36Sopenharmony_ci [OMAP_I2C_SYSTEST_REG] = 0xbC, 25562306a36Sopenharmony_ci [OMAP_I2C_BUFSTAT_REG] = 0xc0, 25662306a36Sopenharmony_ci [OMAP_I2C_IP_V2_REVNB_LO] = 0x00, 25762306a36Sopenharmony_ci [OMAP_I2C_IP_V2_REVNB_HI] = 0x04, 25862306a36Sopenharmony_ci [OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24, 25962306a36Sopenharmony_ci [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c, 26062306a36Sopenharmony_ci [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int omap_i2c_xfer_data(struct omap_i2c_dev *omap); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline void omap_i2c_write_reg(struct omap_i2c_dev *omap, 26662306a36Sopenharmony_ci int reg, u16 val) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci writew_relaxed(val, omap->base + 26962306a36Sopenharmony_ci (omap->regs[reg] << omap->reg_shift)); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic inline u16 omap_i2c_read_reg(struct omap_i2c_dev *omap, int reg) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci return readw_relaxed(omap->base + 27562306a36Sopenharmony_ci (omap->regs[reg] << omap->reg_shift)); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void __omap_i2c_init(struct omap_i2c_dev *omap) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ 28462306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_PSC_REG, omap->pscstate); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* SCL low and high time values */ 28762306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_SCLL_REG, omap->scllstate); 28862306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_SCLH_REG, omap->sclhstate); 28962306a36Sopenharmony_ci if (omap->rev >= OMAP_I2C_REV_ON_3430_3530) 29062306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_WE_REG, omap->westate); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Take the I2C module out of reset: */ 29362306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* 29662306a36Sopenharmony_ci * NOTE: right after setting CON_EN, STAT_BB could be 0 while the 29762306a36Sopenharmony_ci * bus is busy. It will be changed to 1 on the next IP FCLK clock. 29862306a36Sopenharmony_ci * udelay(1) will be enough to fix that. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * Don't write to this register if the IE state is 0 as it can 30362306a36Sopenharmony_ci * cause deadlock. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci if (omap->iestate) 30662306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, omap->iestate); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int omap_i2c_reset(struct omap_i2c_dev *omap) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci unsigned long timeout; 31262306a36Sopenharmony_ci u16 sysc; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (omap->rev >= OMAP_I2C_OMAP1_REV_2) { 31562306a36Sopenharmony_ci sysc = omap_i2c_read_reg(omap, OMAP_I2C_SYSC_REG); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Disable I2C controller before soft reset */ 31862306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 31962306a36Sopenharmony_ci omap_i2c_read_reg(omap, OMAP_I2C_CON_REG) & 32062306a36Sopenharmony_ci ~(OMAP_I2C_CON_EN)); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); 32362306a36Sopenharmony_ci /* For some reason we need to set the EN bit before the 32462306a36Sopenharmony_ci * reset done bit gets set. */ 32562306a36Sopenharmony_ci timeout = jiffies + OMAP_I2C_TIMEOUT; 32662306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); 32762306a36Sopenharmony_ci while (!(omap_i2c_read_reg(omap, OMAP_I2C_SYSS_REG) & 32862306a36Sopenharmony_ci SYSS_RESETDONE_MASK)) { 32962306a36Sopenharmony_ci if (time_after(jiffies, timeout)) { 33062306a36Sopenharmony_ci dev_warn(omap->dev, "timeout waiting " 33162306a36Sopenharmony_ci "for controller reset\n"); 33262306a36Sopenharmony_ci return -ETIMEDOUT; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci msleep(1); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* SYSC register is cleared by the reset; rewrite it */ 33862306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, sysc); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (omap->rev > OMAP_I2C_REV_ON_3430_3530) { 34162306a36Sopenharmony_ci /* Schedule I2C-bus monitoring on the next transfer */ 34262306a36Sopenharmony_ci omap->bb_valid = 0; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int omap_i2c_init(struct omap_i2c_dev *omap) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci u16 psc = 0, scll = 0, sclh = 0; 35262306a36Sopenharmony_ci u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; 35362306a36Sopenharmony_ci unsigned long fclk_rate = 12000000; 35462306a36Sopenharmony_ci unsigned long internal_clk = 0; 35562306a36Sopenharmony_ci struct clk *fclk; 35662306a36Sopenharmony_ci int error; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (omap->rev >= OMAP_I2C_REV_ON_3430_3530) { 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * Enabling all wakup sources to stop I2C freezing on 36162306a36Sopenharmony_ci * WFI instruction. 36262306a36Sopenharmony_ci * REVISIT: Some wkup sources might not be needed. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci omap->westate = OMAP_I2C_WE_ALL; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (omap->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { 36862306a36Sopenharmony_ci /* 36962306a36Sopenharmony_ci * The I2C functional clock is the armxor_ck, so there's 37062306a36Sopenharmony_ci * no need to get "armxor_ck" separately. Now, if OMAP2420 37162306a36Sopenharmony_ci * always returns 12MHz for the functional clock, we can 37262306a36Sopenharmony_ci * do this bit unconditionally. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci fclk = clk_get(omap->dev, "fck"); 37562306a36Sopenharmony_ci if (IS_ERR(fclk)) { 37662306a36Sopenharmony_ci error = PTR_ERR(fclk); 37762306a36Sopenharmony_ci dev_err(omap->dev, "could not get fck: %i\n", error); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return error; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci fclk_rate = clk_get_rate(fclk); 38362306a36Sopenharmony_ci clk_put(fclk); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* TRM for 5912 says the I2C clock must be prescaled to be 38662306a36Sopenharmony_ci * between 7 - 12 MHz. The XOR input clock is typically 38762306a36Sopenharmony_ci * 12, 13 or 19.2 MHz. So we should have code that produces: 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * XOR MHz Divider Prescaler 39062306a36Sopenharmony_ci * 12 1 0 39162306a36Sopenharmony_ci * 13 2 1 39262306a36Sopenharmony_ci * 19.2 2 1 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci if (fclk_rate > 12000000) 39562306a36Sopenharmony_ci psc = fclk_rate / 12000000; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (!(omap->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* 40162306a36Sopenharmony_ci * HSI2C controller internal clk rate should be 19.2 Mhz for 40262306a36Sopenharmony_ci * HS and for all modes on 2430. On 34xx we can use lower rate 40362306a36Sopenharmony_ci * to get longer filter period for better noise suppression. 40462306a36Sopenharmony_ci * The filter is iclk (fclk for HS) period. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci if (omap->speed > 400 || 40762306a36Sopenharmony_ci omap->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) 40862306a36Sopenharmony_ci internal_clk = 19200; 40962306a36Sopenharmony_ci else if (omap->speed > 100) 41062306a36Sopenharmony_ci internal_clk = 9600; 41162306a36Sopenharmony_ci else 41262306a36Sopenharmony_ci internal_clk = 4000; 41362306a36Sopenharmony_ci fclk = clk_get(omap->dev, "fck"); 41462306a36Sopenharmony_ci if (IS_ERR(fclk)) { 41562306a36Sopenharmony_ci error = PTR_ERR(fclk); 41662306a36Sopenharmony_ci dev_err(omap->dev, "could not get fck: %i\n", error); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return error; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci fclk_rate = clk_get_rate(fclk) / 1000; 42162306a36Sopenharmony_ci clk_put(fclk); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* Compute prescaler divisor */ 42462306a36Sopenharmony_ci psc = fclk_rate / internal_clk; 42562306a36Sopenharmony_ci psc = psc - 1; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* If configured for High Speed */ 42862306a36Sopenharmony_ci if (omap->speed > 400) { 42962306a36Sopenharmony_ci unsigned long scl; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* For first phase of HS mode */ 43262306a36Sopenharmony_ci scl = internal_clk / 400; 43362306a36Sopenharmony_ci fsscll = scl - (scl / 3) - 7; 43462306a36Sopenharmony_ci fssclh = (scl / 3) - 5; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* For second phase of HS mode */ 43762306a36Sopenharmony_ci scl = fclk_rate / omap->speed; 43862306a36Sopenharmony_ci hsscll = scl - (scl / 3) - 7; 43962306a36Sopenharmony_ci hssclh = (scl / 3) - 5; 44062306a36Sopenharmony_ci } else if (omap->speed > 100) { 44162306a36Sopenharmony_ci unsigned long scl; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Fast mode */ 44462306a36Sopenharmony_ci scl = internal_clk / omap->speed; 44562306a36Sopenharmony_ci fsscll = scl - (scl / 3) - 7; 44662306a36Sopenharmony_ci fssclh = (scl / 3) - 5; 44762306a36Sopenharmony_ci } else { 44862306a36Sopenharmony_ci /* Standard mode */ 44962306a36Sopenharmony_ci fsscll = internal_clk / (omap->speed * 2) - 7; 45062306a36Sopenharmony_ci fssclh = internal_clk / (omap->speed * 2) - 5; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; 45362306a36Sopenharmony_ci sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; 45462306a36Sopenharmony_ci } else { 45562306a36Sopenharmony_ci /* Program desired operating rate */ 45662306a36Sopenharmony_ci fclk_rate /= (psc + 1) * 1000; 45762306a36Sopenharmony_ci if (psc > 2) 45862306a36Sopenharmony_ci psc = 2; 45962306a36Sopenharmony_ci scll = fclk_rate / (omap->speed * 2) - 7 + psc; 46062306a36Sopenharmony_ci sclh = fclk_rate / (omap->speed * 2) - 7 + psc; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci omap->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | 46462306a36Sopenharmony_ci OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | 46562306a36Sopenharmony_ci OMAP_I2C_IE_AL) | ((omap->fifo_size) ? 46662306a36Sopenharmony_ci (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci omap->pscstate = psc; 46962306a36Sopenharmony_ci omap->scllstate = scll; 47062306a36Sopenharmony_ci omap->sclhstate = sclh; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) { 47362306a36Sopenharmony_ci /* Not implemented */ 47462306a36Sopenharmony_ci omap->bb_valid = 1; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci __omap_i2c_init(omap); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci/* 48362306a36Sopenharmony_ci * Try bus recovery, but only if SDA is actually low. 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_cistatic int omap_i2c_recover_bus(struct omap_i2c_dev *omap) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci u16 systest; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); 49062306a36Sopenharmony_ci if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && 49162306a36Sopenharmony_ci (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) 49262306a36Sopenharmony_ci return 0; /* bus seems to already be fine */ 49362306a36Sopenharmony_ci if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC)) 49462306a36Sopenharmony_ci return -EBUSY; /* recovery would not fix SCL */ 49562306a36Sopenharmony_ci return i2c_recover_bus(&omap->adapter); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/* 49962306a36Sopenharmony_ci * Waiting on Bus Busy 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_cistatic int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci unsigned long timeout; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci timeout = jiffies + OMAP_I2C_TIMEOUT; 50662306a36Sopenharmony_ci while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { 50762306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 50862306a36Sopenharmony_ci return omap_i2c_recover_bus(omap); 50962306a36Sopenharmony_ci msleep(1); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/* 51662306a36Sopenharmony_ci * Wait while BB-bit doesn't reflect the I2C bus state 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * In a multimaster environment, after IP software reset, BB-bit value doesn't 51962306a36Sopenharmony_ci * correspond to the current bus state. It may happen what BB-bit will be 0, 52062306a36Sopenharmony_ci * while the bus is busy due to another I2C master activity. 52162306a36Sopenharmony_ci * Here are BB-bit values after reset: 52262306a36Sopenharmony_ci * SDA SCL BB NOTES 52362306a36Sopenharmony_ci * 0 0 0 1, 2 52462306a36Sopenharmony_ci * 1 0 0 1, 2 52562306a36Sopenharmony_ci * 0 1 1 52662306a36Sopenharmony_ci * 1 1 0 3 52762306a36Sopenharmony_ci * Later, if IP detect SDA=0 and SCL=1 (ACK) or SDA 1->0 while SCL=1 (START) 52862306a36Sopenharmony_ci * combinations on the bus, it set BB-bit to 1. 52962306a36Sopenharmony_ci * If IP detect SDA 0->1 while SCL=1 (STOP) combination on the bus, 53062306a36Sopenharmony_ci * it set BB-bit to 0 and BF to 1. 53162306a36Sopenharmony_ci * BB and BF bits correctly tracks the bus state while IP is suspended 53262306a36Sopenharmony_ci * BB bit became valid on the next FCLK clock after CON_EN bit set 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * NOTES: 53562306a36Sopenharmony_ci * 1. Any transfer started when BB=0 and bus is busy wouldn't be 53662306a36Sopenharmony_ci * completed by IP and results in controller timeout. 53762306a36Sopenharmony_ci * 2. Any transfer started when BB=0 and SCL=0 results in IP 53862306a36Sopenharmony_ci * starting to drive SDA low. In that case IP corrupt data 53962306a36Sopenharmony_ci * on the bus. 54062306a36Sopenharmony_ci * 3. Any transfer started in the middle of another master's transfer 54162306a36Sopenharmony_ci * results in unpredictable results and data corruption 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_cistatic int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci unsigned long bus_free_timeout = 0; 54662306a36Sopenharmony_ci unsigned long timeout; 54762306a36Sopenharmony_ci int bus_free = 0; 54862306a36Sopenharmony_ci u16 stat, systest; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (omap->bb_valid) 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci timeout = jiffies + OMAP_I2C_TIMEOUT; 55462306a36Sopenharmony_ci while (1) { 55562306a36Sopenharmony_ci stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * We will see BB or BF event in a case IP had detected any 55862306a36Sopenharmony_ci * activity on the I2C bus. Now IP correctly tracks the bus 55962306a36Sopenharmony_ci * state. BB-bit value is valid. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci if (stat & (OMAP_I2C_STAT_BB | OMAP_I2C_STAT_BF)) 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* 56562306a36Sopenharmony_ci * Otherwise, we must look signals on the bus to make 56662306a36Sopenharmony_ci * the right decision. 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_ci systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); 56962306a36Sopenharmony_ci if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && 57062306a36Sopenharmony_ci (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) { 57162306a36Sopenharmony_ci if (!bus_free) { 57262306a36Sopenharmony_ci bus_free_timeout = jiffies + 57362306a36Sopenharmony_ci OMAP_I2C_BUS_FREE_TIMEOUT; 57462306a36Sopenharmony_ci bus_free = 1; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* 57862306a36Sopenharmony_ci * SDA and SCL lines was high for 10 ms without bus 57962306a36Sopenharmony_ci * activity detected. The bus is free. Consider 58062306a36Sopenharmony_ci * BB-bit value is valid. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci if (time_after(jiffies, bus_free_timeout)) 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci } else { 58562306a36Sopenharmony_ci bus_free = 0; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (time_after(jiffies, timeout)) { 58962306a36Sopenharmony_ci /* 59062306a36Sopenharmony_ci * SDA or SCL were low for the entire timeout without 59162306a36Sopenharmony_ci * any activity detected. Most likely, a slave is 59262306a36Sopenharmony_ci * locking up the bus with no master driving the clock. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci dev_warn(omap->dev, "timeout waiting for bus ready\n"); 59562306a36Sopenharmony_ci return omap_i2c_recover_bus(omap); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci msleep(1); 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci omap->bb_valid = 1; 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci u16 buf; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (omap->flags & OMAP_I2C_FLAG_NO_FIFO) 61062306a36Sopenharmony_ci return; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* 61362306a36Sopenharmony_ci * Set up notification threshold based on message size. We're doing 61462306a36Sopenharmony_ci * this to try and avoid draining feature as much as possible. Whenever 61562306a36Sopenharmony_ci * we have big messages to transfer (bigger than our total fifo size) 61662306a36Sopenharmony_ci * then we might use draining feature to transfer the remaining bytes. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci omap->threshold = clamp(size, (u8) 1, omap->fifo_size); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci buf = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (is_rx) { 62462306a36Sopenharmony_ci /* Clear RX Threshold */ 62562306a36Sopenharmony_ci buf &= ~(0x3f << 8); 62662306a36Sopenharmony_ci buf |= ((omap->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; 62762306a36Sopenharmony_ci } else { 62862306a36Sopenharmony_ci /* Clear TX Threshold */ 62962306a36Sopenharmony_ci buf &= ~0x3f; 63062306a36Sopenharmony_ci buf |= (omap->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, buf); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (omap->rev < OMAP_I2C_REV_ON_3630) 63662306a36Sopenharmony_ci omap->b_hw = 1; /* Enable hardware fixes */ 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* calculate wakeup latency constraint for MPU */ 63962306a36Sopenharmony_ci if (omap->set_mpu_wkup_lat != NULL) 64062306a36Sopenharmony_ci omap->latency = (1000000 * omap->threshold) / 64162306a36Sopenharmony_ci (1000 * omap->speed / 8); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic void omap_i2c_wait(struct omap_i2c_dev *omap) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci u16 stat; 64762306a36Sopenharmony_ci u16 mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); 64862306a36Sopenharmony_ci int count = 0; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci do { 65162306a36Sopenharmony_ci stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); 65262306a36Sopenharmony_ci count++; 65362306a36Sopenharmony_ci } while (!(stat & mask) && count < 5); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci/* 65762306a36Sopenharmony_ci * Low level master read/write transaction. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_cistatic int omap_i2c_xfer_msg(struct i2c_adapter *adap, 66062306a36Sopenharmony_ci struct i2c_msg *msg, int stop, bool polling) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct omap_i2c_dev *omap = i2c_get_adapdata(adap); 66362306a36Sopenharmony_ci unsigned long timeout; 66462306a36Sopenharmony_ci u16 w; 66562306a36Sopenharmony_ci int ret; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", 66862306a36Sopenharmony_ci msg->addr, msg->len, msg->flags, stop); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci omap->receiver = !!(msg->flags & I2C_M_RD); 67162306a36Sopenharmony_ci omap_i2c_resize_fifo(omap, msg->len, omap->receiver); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_SA_REG, msg->addr); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ 67662306a36Sopenharmony_ci omap->buf = msg->buf; 67762306a36Sopenharmony_ci omap->buf_len = msg->len; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* make sure writes to omap->buf_len are ordered */ 68062306a36Sopenharmony_ci barrier(); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CNT_REG, omap->buf_len); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* Clear the FIFO Buffers */ 68562306a36Sopenharmony_ci w = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG); 68662306a36Sopenharmony_ci w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; 68762306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (!polling) 69062306a36Sopenharmony_ci reinit_completion(&omap->cmd_complete); 69162306a36Sopenharmony_ci omap->cmd_err = 0; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* High speed configuration */ 69662306a36Sopenharmony_ci if (omap->speed > 400) 69762306a36Sopenharmony_ci w |= OMAP_I2C_CON_OPMODE_HS; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (msg->flags & I2C_M_STOP) 70062306a36Sopenharmony_ci stop = 1; 70162306a36Sopenharmony_ci if (msg->flags & I2C_M_TEN) 70262306a36Sopenharmony_ci w |= OMAP_I2C_CON_XA; 70362306a36Sopenharmony_ci if (!(msg->flags & I2C_M_RD)) 70462306a36Sopenharmony_ci w |= OMAP_I2C_CON_TRX; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (!omap->b_hw && stop) 70762306a36Sopenharmony_ci w |= OMAP_I2C_CON_STP; 70862306a36Sopenharmony_ci /* 70962306a36Sopenharmony_ci * NOTE: STAT_BB bit could became 1 here if another master occupy 71062306a36Sopenharmony_ci * the bus. IP successfully complete transfer when the bus will be 71162306a36Sopenharmony_ci * free again (BB reset to 0). 71262306a36Sopenharmony_ci */ 71362306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* 71662306a36Sopenharmony_ci * Don't write stt and stp together on some hardware. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_ci if (omap->b_hw && stop) { 71962306a36Sopenharmony_ci unsigned long delay = jiffies + OMAP_I2C_TIMEOUT; 72062306a36Sopenharmony_ci u16 con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); 72162306a36Sopenharmony_ci while (con & OMAP_I2C_CON_STT) { 72262306a36Sopenharmony_ci con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Let the user know if i2c is in a bad state */ 72562306a36Sopenharmony_ci if (time_after(jiffies, delay)) { 72662306a36Sopenharmony_ci dev_err(omap->dev, "controller timed out " 72762306a36Sopenharmony_ci "waiting for start condition to finish\n"); 72862306a36Sopenharmony_ci return -ETIMEDOUT; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci cpu_relax(); 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci w |= OMAP_I2C_CON_STP; 73462306a36Sopenharmony_ci w &= ~OMAP_I2C_CON_STT; 73562306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * REVISIT: We should abort the transfer on signals, but the bus goes 74062306a36Sopenharmony_ci * into arbitration and we're currently unable to recover from it. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci if (!polling) { 74362306a36Sopenharmony_ci timeout = wait_for_completion_timeout(&omap->cmd_complete, 74462306a36Sopenharmony_ci OMAP_I2C_TIMEOUT); 74562306a36Sopenharmony_ci } else { 74662306a36Sopenharmony_ci do { 74762306a36Sopenharmony_ci omap_i2c_wait(omap); 74862306a36Sopenharmony_ci ret = omap_i2c_xfer_data(omap); 74962306a36Sopenharmony_ci } while (ret == -EAGAIN); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci timeout = !ret; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (timeout == 0) { 75562306a36Sopenharmony_ci dev_err(omap->dev, "controller timed out\n"); 75662306a36Sopenharmony_ci omap_i2c_reset(omap); 75762306a36Sopenharmony_ci __omap_i2c_init(omap); 75862306a36Sopenharmony_ci return -ETIMEDOUT; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (likely(!omap->cmd_err)) 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* We have an error */ 76562306a36Sopenharmony_ci if (omap->cmd_err & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { 76662306a36Sopenharmony_ci omap_i2c_reset(omap); 76762306a36Sopenharmony_ci __omap_i2c_init(omap); 76862306a36Sopenharmony_ci return -EIO; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (omap->cmd_err & OMAP_I2C_STAT_AL) 77262306a36Sopenharmony_ci return -EAGAIN; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (omap->cmd_err & OMAP_I2C_STAT_NACK) { 77562306a36Sopenharmony_ci if (msg->flags & I2C_M_IGNORE_NAK) 77662306a36Sopenharmony_ci return 0; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci w = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); 77962306a36Sopenharmony_ci w |= OMAP_I2C_CON_STP; 78062306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); 78162306a36Sopenharmony_ci return -EREMOTEIO; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci return -EIO; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci/* 78862306a36Sopenharmony_ci * Prepare controller for a transaction and call omap_i2c_xfer_msg 78962306a36Sopenharmony_ci * to do the work during IRQ processing. 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_cistatic int 79262306a36Sopenharmony_ciomap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num, 79362306a36Sopenharmony_ci bool polling) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct omap_i2c_dev *omap = i2c_get_adapdata(adap); 79662306a36Sopenharmony_ci int i; 79762306a36Sopenharmony_ci int r; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci r = pm_runtime_get_sync(omap->dev); 80062306a36Sopenharmony_ci if (r < 0) 80162306a36Sopenharmony_ci goto out; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci r = omap_i2c_wait_for_bb_valid(omap); 80462306a36Sopenharmony_ci if (r < 0) 80562306a36Sopenharmony_ci goto out; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci r = omap_i2c_wait_for_bb(omap); 80862306a36Sopenharmony_ci if (r < 0) 80962306a36Sopenharmony_ci goto out; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (omap->set_mpu_wkup_lat != NULL) 81262306a36Sopenharmony_ci omap->set_mpu_wkup_lat(omap->dev, omap->latency); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci for (i = 0; i < num; i++) { 81562306a36Sopenharmony_ci r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)), 81662306a36Sopenharmony_ci polling); 81762306a36Sopenharmony_ci if (r != 0) 81862306a36Sopenharmony_ci break; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (r == 0) 82262306a36Sopenharmony_ci r = num; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci omap_i2c_wait_for_bb(omap); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (omap->set_mpu_wkup_lat != NULL) 82762306a36Sopenharmony_ci omap->set_mpu_wkup_lat(omap->dev, -1); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ciout: 83062306a36Sopenharmony_ci pm_runtime_mark_last_busy(omap->dev); 83162306a36Sopenharmony_ci pm_runtime_put_autosuspend(omap->dev); 83262306a36Sopenharmony_ci return r; 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic int 83662306a36Sopenharmony_ciomap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci return omap_i2c_xfer_common(adap, msgs, num, false); 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic int 84262306a36Sopenharmony_ciomap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci return omap_i2c_xfer_common(adap, msgs, num, true); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic u32 84862306a36Sopenharmony_ciomap_i2c_func(struct i2c_adapter *adap) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | 85162306a36Sopenharmony_ci I2C_FUNC_PROTOCOL_MANGLING; 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic inline void 85562306a36Sopenharmony_ciomap_i2c_complete_cmd(struct omap_i2c_dev *omap, u16 err) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci omap->cmd_err |= err; 85862306a36Sopenharmony_ci complete(&omap->cmd_complete); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic inline void 86262306a36Sopenharmony_ciomap_i2c_ack_stat(struct omap_i2c_dev *omap, u16 stat) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, stat); 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic inline void i2c_omap_errata_i207(struct omap_i2c_dev *omap, u16 stat) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci /* 87062306a36Sopenharmony_ci * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8) 87162306a36Sopenharmony_ci * Not applicable for OMAP4. 87262306a36Sopenharmony_ci * Under certain rare conditions, RDR could be set again 87362306a36Sopenharmony_ci * when the bus is busy, then ignore the interrupt and 87462306a36Sopenharmony_ci * clear the interrupt. 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_RDR) { 87762306a36Sopenharmony_ci /* Step 1: If RDR is set, clear it */ 87862306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* Step 2: */ 88162306a36Sopenharmony_ci if (!(omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) 88262306a36Sopenharmony_ci & OMAP_I2C_STAT_BB)) { 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* Step 3: */ 88562306a36Sopenharmony_ci if (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) 88662306a36Sopenharmony_ci & OMAP_I2C_STAT_RDR) { 88762306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); 88862306a36Sopenharmony_ci dev_dbg(omap->dev, "RDR when bus is busy.\n"); 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci/* rev1 devices are apparently only on some 15xx */ 89662306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP15XX 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic irqreturn_t 89962306a36Sopenharmony_ciomap_i2c_omap1_isr(int this_irq, void *dev_id) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci struct omap_i2c_dev *omap = dev_id; 90262306a36Sopenharmony_ci u16 iv, w; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (pm_runtime_suspended(omap->dev)) 90562306a36Sopenharmony_ci return IRQ_NONE; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci iv = omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); 90862306a36Sopenharmony_ci switch (iv) { 90962306a36Sopenharmony_ci case 0x00: /* None */ 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci case 0x01: /* Arbitration lost */ 91262306a36Sopenharmony_ci dev_err(omap->dev, "Arbitration lost\n"); 91362306a36Sopenharmony_ci omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_AL); 91462306a36Sopenharmony_ci break; 91562306a36Sopenharmony_ci case 0x02: /* No acknowledgement */ 91662306a36Sopenharmony_ci omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_NACK); 91762306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP); 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci case 0x03: /* Register access ready */ 92062306a36Sopenharmony_ci omap_i2c_complete_cmd(omap, 0); 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci case 0x04: /* Receive data ready */ 92362306a36Sopenharmony_ci if (omap->buf_len) { 92462306a36Sopenharmony_ci w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG); 92562306a36Sopenharmony_ci *omap->buf++ = w; 92662306a36Sopenharmony_ci omap->buf_len--; 92762306a36Sopenharmony_ci if (omap->buf_len) { 92862306a36Sopenharmony_ci *omap->buf++ = w >> 8; 92962306a36Sopenharmony_ci omap->buf_len--; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci } else 93262306a36Sopenharmony_ci dev_err(omap->dev, "RRDY IRQ while no data requested\n"); 93362306a36Sopenharmony_ci break; 93462306a36Sopenharmony_ci case 0x05: /* Transmit data ready */ 93562306a36Sopenharmony_ci if (omap->buf_len) { 93662306a36Sopenharmony_ci w = *omap->buf++; 93762306a36Sopenharmony_ci omap->buf_len--; 93862306a36Sopenharmony_ci if (omap->buf_len) { 93962306a36Sopenharmony_ci w |= *omap->buf++ << 8; 94062306a36Sopenharmony_ci omap->buf_len--; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w); 94362306a36Sopenharmony_ci } else 94462306a36Sopenharmony_ci dev_err(omap->dev, "XRDY IRQ while no data to send\n"); 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci default: 94762306a36Sopenharmony_ci return IRQ_NONE; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci return IRQ_HANDLED; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci#else 95362306a36Sopenharmony_ci#define omap_i2c_omap1_isr NULL 95462306a36Sopenharmony_ci#endif 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci/* 95762306a36Sopenharmony_ci * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing 95862306a36Sopenharmony_ci * data to DATA_REG. Otherwise some data bytes can be lost while transferring 95962306a36Sopenharmony_ci * them from the memory to the I2C interface. 96062306a36Sopenharmony_ci */ 96162306a36Sopenharmony_cistatic int errata_omap3_i462(struct omap_i2c_dev *omap) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci unsigned long timeout = 10000; 96462306a36Sopenharmony_ci u16 stat; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci do { 96762306a36Sopenharmony_ci stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); 96862306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_XUDF) 96962306a36Sopenharmony_ci break; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { 97262306a36Sopenharmony_ci omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_XRDY | 97362306a36Sopenharmony_ci OMAP_I2C_STAT_XDR)); 97462306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_NACK) { 97562306a36Sopenharmony_ci omap->cmd_err |= OMAP_I2C_STAT_NACK; 97662306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_AL) { 98062306a36Sopenharmony_ci dev_err(omap->dev, "Arbitration lost\n"); 98162306a36Sopenharmony_ci omap->cmd_err |= OMAP_I2C_STAT_AL; 98262306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL); 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci return -EIO; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci cpu_relax(); 98962306a36Sopenharmony_ci } while (--timeout); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (!timeout) { 99262306a36Sopenharmony_ci dev_err(omap->dev, "timeout waiting on XUDF bit\n"); 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return 0; 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic void omap_i2c_receive_data(struct omap_i2c_dev *omap, u8 num_bytes, 100062306a36Sopenharmony_ci bool is_rdr) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci u16 w; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci while (num_bytes--) { 100562306a36Sopenharmony_ci w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG); 100662306a36Sopenharmony_ci *omap->buf++ = w; 100762306a36Sopenharmony_ci omap->buf_len--; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* 101062306a36Sopenharmony_ci * Data reg in 2430, omap3 and 101162306a36Sopenharmony_ci * omap4 is 8 bit wide 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ci if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { 101462306a36Sopenharmony_ci *omap->buf++ = w >> 8; 101562306a36Sopenharmony_ci omap->buf_len--; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_cistatic int omap_i2c_transmit_data(struct omap_i2c_dev *omap, u8 num_bytes, 102162306a36Sopenharmony_ci bool is_xdr) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci u16 w; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci while (num_bytes--) { 102662306a36Sopenharmony_ci w = *omap->buf++; 102762306a36Sopenharmony_ci omap->buf_len--; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* 103062306a36Sopenharmony_ci * Data reg in 2430, omap3 and 103162306a36Sopenharmony_ci * omap4 is 8 bit wide 103262306a36Sopenharmony_ci */ 103362306a36Sopenharmony_ci if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { 103462306a36Sopenharmony_ci w |= *omap->buf++ << 8; 103562306a36Sopenharmony_ci omap->buf_len--; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (omap->errata & I2C_OMAP_ERRATA_I462) { 103962306a36Sopenharmony_ci int ret; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci ret = errata_omap3_i462(omap); 104262306a36Sopenharmony_ci if (ret < 0) 104362306a36Sopenharmony_ci return ret; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w); 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic irqreturn_t 105362306a36Sopenharmony_ciomap_i2c_isr(int irq, void *dev_id) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct omap_i2c_dev *omap = dev_id; 105662306a36Sopenharmony_ci irqreturn_t ret = IRQ_HANDLED; 105762306a36Sopenharmony_ci u16 mask; 105862306a36Sopenharmony_ci u16 stat; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); 106162306a36Sopenharmony_ci mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG) & ~OMAP_I2C_STAT_NACK; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (stat & mask) 106462306a36Sopenharmony_ci ret = IRQ_WAKE_THREAD; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return ret; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic int omap_i2c_xfer_data(struct omap_i2c_dev *omap) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci u16 bits; 107262306a36Sopenharmony_ci u16 stat; 107362306a36Sopenharmony_ci int err = 0, count = 0; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci do { 107662306a36Sopenharmony_ci bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); 107762306a36Sopenharmony_ci stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); 107862306a36Sopenharmony_ci stat &= bits; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* If we're in receiver mode, ignore XDR/XRDY */ 108162306a36Sopenharmony_ci if (omap->receiver) 108262306a36Sopenharmony_ci stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); 108362306a36Sopenharmony_ci else 108462306a36Sopenharmony_ci stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (!stat) { 108762306a36Sopenharmony_ci /* my work here is done */ 108862306a36Sopenharmony_ci err = -EAGAIN; 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat); 109362306a36Sopenharmony_ci if (count++ == 100) { 109462306a36Sopenharmony_ci dev_warn(omap->dev, "Too much work in one IRQ\n"); 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_NACK) { 109962306a36Sopenharmony_ci err |= OMAP_I2C_STAT_NACK; 110062306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_AL) { 110462306a36Sopenharmony_ci dev_err(omap->dev, "Arbitration lost\n"); 110562306a36Sopenharmony_ci err |= OMAP_I2C_STAT_AL; 110662306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL); 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* 111062306a36Sopenharmony_ci * ProDB0017052: Clear ARDY bit twice 111162306a36Sopenharmony_ci */ 111262306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_ARDY) 111362306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ARDY); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | 111662306a36Sopenharmony_ci OMAP_I2C_STAT_AL)) { 111762306a36Sopenharmony_ci omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_RRDY | 111862306a36Sopenharmony_ci OMAP_I2C_STAT_RDR | 111962306a36Sopenharmony_ci OMAP_I2C_STAT_XRDY | 112062306a36Sopenharmony_ci OMAP_I2C_STAT_XDR | 112162306a36Sopenharmony_ci OMAP_I2C_STAT_ARDY)); 112262306a36Sopenharmony_ci break; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_RDR) { 112662306a36Sopenharmony_ci u8 num_bytes = 1; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (omap->fifo_size) 112962306a36Sopenharmony_ci num_bytes = omap->buf_len; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (omap->errata & I2C_OMAP_ERRATA_I207) { 113262306a36Sopenharmony_ci i2c_omap_errata_i207(omap, stat); 113362306a36Sopenharmony_ci num_bytes = (omap_i2c_read_reg(omap, 113462306a36Sopenharmony_ci OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci omap_i2c_receive_data(omap, num_bytes, true); 113862306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); 113962306a36Sopenharmony_ci continue; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_RRDY) { 114362306a36Sopenharmony_ci u8 num_bytes = 1; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (omap->threshold) 114662306a36Sopenharmony_ci num_bytes = omap->threshold; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci omap_i2c_receive_data(omap, num_bytes, false); 114962306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RRDY); 115062306a36Sopenharmony_ci continue; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_XDR) { 115462306a36Sopenharmony_ci u8 num_bytes = 1; 115562306a36Sopenharmony_ci int ret; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (omap->fifo_size) 115862306a36Sopenharmony_ci num_bytes = omap->buf_len; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci ret = omap_i2c_transmit_data(omap, num_bytes, true); 116162306a36Sopenharmony_ci if (ret < 0) 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XDR); 116562306a36Sopenharmony_ci continue; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_XRDY) { 116962306a36Sopenharmony_ci u8 num_bytes = 1; 117062306a36Sopenharmony_ci int ret; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (omap->threshold) 117362306a36Sopenharmony_ci num_bytes = omap->threshold; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci ret = omap_i2c_transmit_data(omap, num_bytes, false); 117662306a36Sopenharmony_ci if (ret < 0) 117762306a36Sopenharmony_ci break; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XRDY); 118062306a36Sopenharmony_ci continue; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_ROVR) { 118462306a36Sopenharmony_ci dev_err(omap->dev, "Receive overrun\n"); 118562306a36Sopenharmony_ci err |= OMAP_I2C_STAT_ROVR; 118662306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ROVR); 118762306a36Sopenharmony_ci break; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (stat & OMAP_I2C_STAT_XUDF) { 119162306a36Sopenharmony_ci dev_err(omap->dev, "Transmit underflow\n"); 119262306a36Sopenharmony_ci err |= OMAP_I2C_STAT_XUDF; 119362306a36Sopenharmony_ci omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XUDF); 119462306a36Sopenharmony_ci break; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci } while (stat); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci return err; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic irqreturn_t 120262306a36Sopenharmony_ciomap_i2c_isr_thread(int this_irq, void *dev_id) 120362306a36Sopenharmony_ci{ 120462306a36Sopenharmony_ci int ret; 120562306a36Sopenharmony_ci struct omap_i2c_dev *omap = dev_id; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci ret = omap_i2c_xfer_data(omap); 120862306a36Sopenharmony_ci if (ret != -EAGAIN) 120962306a36Sopenharmony_ci omap_i2c_complete_cmd(omap, ret); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci return IRQ_HANDLED; 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic const struct i2c_algorithm omap_i2c_algo = { 121562306a36Sopenharmony_ci .master_xfer = omap_i2c_xfer_irq, 121662306a36Sopenharmony_ci .master_xfer_atomic = omap_i2c_xfer_polling, 121762306a36Sopenharmony_ci .functionality = omap_i2c_func, 121862306a36Sopenharmony_ci}; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic const struct i2c_adapter_quirks omap_i2c_quirks = { 122162306a36Sopenharmony_ci .flags = I2C_AQ_NO_ZERO_LEN, 122262306a36Sopenharmony_ci}; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci#ifdef CONFIG_OF 122562306a36Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap2420_pdata = { 122662306a36Sopenharmony_ci .rev = OMAP_I2C_IP_VERSION_1, 122762306a36Sopenharmony_ci .flags = OMAP_I2C_FLAG_NO_FIFO | 122862306a36Sopenharmony_ci OMAP_I2C_FLAG_SIMPLE_CLOCK | 122962306a36Sopenharmony_ci OMAP_I2C_FLAG_16BIT_DATA_REG | 123062306a36Sopenharmony_ci OMAP_I2C_FLAG_BUS_SHIFT_2, 123162306a36Sopenharmony_ci}; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap2430_pdata = { 123462306a36Sopenharmony_ci .rev = OMAP_I2C_IP_VERSION_1, 123562306a36Sopenharmony_ci .flags = OMAP_I2C_FLAG_BUS_SHIFT_2 | 123662306a36Sopenharmony_ci OMAP_I2C_FLAG_FORCE_19200_INT_CLK, 123762306a36Sopenharmony_ci}; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap3_pdata = { 124062306a36Sopenharmony_ci .rev = OMAP_I2C_IP_VERSION_1, 124162306a36Sopenharmony_ci .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, 124262306a36Sopenharmony_ci}; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic struct omap_i2c_bus_platform_data omap4_pdata = { 124562306a36Sopenharmony_ci .rev = OMAP_I2C_IP_VERSION_2, 124662306a36Sopenharmony_ci}; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cistatic const struct of_device_id omap_i2c_of_match[] = { 124962306a36Sopenharmony_ci { 125062306a36Sopenharmony_ci .compatible = "ti,omap4-i2c", 125162306a36Sopenharmony_ci .data = &omap4_pdata, 125262306a36Sopenharmony_ci }, 125362306a36Sopenharmony_ci { 125462306a36Sopenharmony_ci .compatible = "ti,omap3-i2c", 125562306a36Sopenharmony_ci .data = &omap3_pdata, 125662306a36Sopenharmony_ci }, 125762306a36Sopenharmony_ci { 125862306a36Sopenharmony_ci .compatible = "ti,omap2430-i2c", 125962306a36Sopenharmony_ci .data = &omap2430_pdata, 126062306a36Sopenharmony_ci }, 126162306a36Sopenharmony_ci { 126262306a36Sopenharmony_ci .compatible = "ti,omap2420-i2c", 126362306a36Sopenharmony_ci .data = &omap2420_pdata, 126462306a36Sopenharmony_ci }, 126562306a36Sopenharmony_ci { }, 126662306a36Sopenharmony_ci}; 126762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_i2c_of_match); 126862306a36Sopenharmony_ci#endif 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci#define OMAP_I2C_SCHEME(rev) ((rev & 0xc000) >> 14) 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev) (rev >> 4) 127362306a36Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_0_MINOR(rev) (rev & 0xf) 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev) ((rev & 0x0700) >> 7) 127662306a36Sopenharmony_ci#define OMAP_I2C_REV_SCHEME_1_MINOR(rev) (rev & 0x1f) 127762306a36Sopenharmony_ci#define OMAP_I2C_SCHEME_0 0 127862306a36Sopenharmony_ci#define OMAP_I2C_SCHEME_1 1 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic int omap_i2c_get_scl(struct i2c_adapter *adap) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 128362306a36Sopenharmony_ci u32 reg; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci return reg & OMAP_I2C_SYSTEST_SCL_I_FUNC; 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_cistatic int omap_i2c_get_sda(struct i2c_adapter *adap) 129162306a36Sopenharmony_ci{ 129262306a36Sopenharmony_ci struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 129362306a36Sopenharmony_ci u32 reg; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci return reg & OMAP_I2C_SYSTEST_SDA_I_FUNC; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic void omap_i2c_set_scl(struct i2c_adapter *adap, int val) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 130362306a36Sopenharmony_ci u32 reg; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 130662306a36Sopenharmony_ci if (val) 130762306a36Sopenharmony_ci reg |= OMAP_I2C_SYSTEST_SCL_O; 130862306a36Sopenharmony_ci else 130962306a36Sopenharmony_ci reg &= ~OMAP_I2C_SYSTEST_SCL_O; 131062306a36Sopenharmony_ci omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic void omap_i2c_prepare_recovery(struct i2c_adapter *adap) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 131662306a36Sopenharmony_ci u32 reg; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 131962306a36Sopenharmony_ci /* enable test mode */ 132062306a36Sopenharmony_ci reg |= OMAP_I2C_SYSTEST_ST_EN; 132162306a36Sopenharmony_ci /* select SDA/SCL IO mode */ 132262306a36Sopenharmony_ci reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT; 132362306a36Sopenharmony_ci /* set SCL to high-impedance state (reset value is 0) */ 132462306a36Sopenharmony_ci reg |= OMAP_I2C_SYSTEST_SCL_O; 132562306a36Sopenharmony_ci /* set SDA to high-impedance state (reset value is 0) */ 132662306a36Sopenharmony_ci reg |= OMAP_I2C_SYSTEST_SDA_O; 132762306a36Sopenharmony_ci omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic void omap_i2c_unprepare_recovery(struct i2c_adapter *adap) 133162306a36Sopenharmony_ci{ 133262306a36Sopenharmony_ci struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 133362306a36Sopenharmony_ci u32 reg; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 133662306a36Sopenharmony_ci /* restore reset values */ 133762306a36Sopenharmony_ci reg &= ~OMAP_I2C_SYSTEST_ST_EN; 133862306a36Sopenharmony_ci reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK; 133962306a36Sopenharmony_ci reg &= ~OMAP_I2C_SYSTEST_SCL_O; 134062306a36Sopenharmony_ci reg &= ~OMAP_I2C_SYSTEST_SDA_O; 134162306a36Sopenharmony_ci omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic struct i2c_bus_recovery_info omap_i2c_bus_recovery_info = { 134562306a36Sopenharmony_ci .get_scl = omap_i2c_get_scl, 134662306a36Sopenharmony_ci .get_sda = omap_i2c_get_sda, 134762306a36Sopenharmony_ci .set_scl = omap_i2c_set_scl, 134862306a36Sopenharmony_ci .prepare_recovery = omap_i2c_prepare_recovery, 134962306a36Sopenharmony_ci .unprepare_recovery = omap_i2c_unprepare_recovery, 135062306a36Sopenharmony_ci .recover_bus = i2c_generic_scl_recovery, 135162306a36Sopenharmony_ci}; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int 135462306a36Sopenharmony_ciomap_i2c_probe(struct platform_device *pdev) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct omap_i2c_dev *omap; 135762306a36Sopenharmony_ci struct i2c_adapter *adap; 135862306a36Sopenharmony_ci const struct omap_i2c_bus_platform_data *pdata = 135962306a36Sopenharmony_ci dev_get_platdata(&pdev->dev); 136062306a36Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 136162306a36Sopenharmony_ci const struct of_device_id *match; 136262306a36Sopenharmony_ci int irq; 136362306a36Sopenharmony_ci int r; 136462306a36Sopenharmony_ci u32 rev; 136562306a36Sopenharmony_ci u16 minor, major; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 136862306a36Sopenharmony_ci if (irq < 0) 136962306a36Sopenharmony_ci return irq; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); 137262306a36Sopenharmony_ci if (!omap) 137362306a36Sopenharmony_ci return -ENOMEM; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci omap->base = devm_platform_ioremap_resource(pdev, 0); 137662306a36Sopenharmony_ci if (IS_ERR(omap->base)) 137762306a36Sopenharmony_ci return PTR_ERR(omap->base); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); 138062306a36Sopenharmony_ci if (match) { 138162306a36Sopenharmony_ci u32 freq = I2C_MAX_STANDARD_MODE_FREQ; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci pdata = match->data; 138462306a36Sopenharmony_ci omap->flags = pdata->flags; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci of_property_read_u32(node, "clock-frequency", &freq); 138762306a36Sopenharmony_ci /* convert DT freq value in Hz into kHz for speed */ 138862306a36Sopenharmony_ci omap->speed = freq / 1000; 138962306a36Sopenharmony_ci } else if (pdata != NULL) { 139062306a36Sopenharmony_ci omap->speed = pdata->clkrate; 139162306a36Sopenharmony_ci omap->flags = pdata->flags; 139262306a36Sopenharmony_ci omap->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci omap->dev = &pdev->dev; 139662306a36Sopenharmony_ci omap->irq = irq; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci platform_set_drvdata(pdev, omap); 139962306a36Sopenharmony_ci init_completion(&omap->cmd_complete); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci omap->reg_shift = (omap->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci pm_runtime_enable(omap->dev); 140462306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT); 140562306a36Sopenharmony_ci pm_runtime_use_autosuspend(omap->dev); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci r = pm_runtime_resume_and_get(omap->dev); 140862306a36Sopenharmony_ci if (r < 0) 140962306a36Sopenharmony_ci goto err_disable_pm; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* 141262306a36Sopenharmony_ci * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2. 141362306a36Sopenharmony_ci * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset. 141462306a36Sopenharmony_ci * Also since the omap_i2c_read_reg uses reg_map_ip_* a 141562306a36Sopenharmony_ci * readw_relaxed is done. 141662306a36Sopenharmony_ci */ 141762306a36Sopenharmony_ci rev = readw_relaxed(omap->base + 0x04); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci omap->scheme = OMAP_I2C_SCHEME(rev); 142062306a36Sopenharmony_ci switch (omap->scheme) { 142162306a36Sopenharmony_ci case OMAP_I2C_SCHEME_0: 142262306a36Sopenharmony_ci omap->regs = (u8 *)reg_map_ip_v1; 142362306a36Sopenharmony_ci omap->rev = omap_i2c_read_reg(omap, OMAP_I2C_REV_REG); 142462306a36Sopenharmony_ci minor = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); 142562306a36Sopenharmony_ci major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); 142662306a36Sopenharmony_ci break; 142762306a36Sopenharmony_ci case OMAP_I2C_SCHEME_1: 142862306a36Sopenharmony_ci default: 142962306a36Sopenharmony_ci omap->regs = (u8 *)reg_map_ip_v2; 143062306a36Sopenharmony_ci rev = (rev << 16) | 143162306a36Sopenharmony_ci omap_i2c_read_reg(omap, OMAP_I2C_IP_V2_REVNB_LO); 143262306a36Sopenharmony_ci minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev); 143362306a36Sopenharmony_ci major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev); 143462306a36Sopenharmony_ci omap->rev = rev; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci omap->errata = 0; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (omap->rev >= OMAP_I2C_REV_ON_2430 && 144062306a36Sopenharmony_ci omap->rev < OMAP_I2C_REV_ON_4430_PLUS) 144162306a36Sopenharmony_ci omap->errata |= I2C_OMAP_ERRATA_I207; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) 144462306a36Sopenharmony_ci omap->errata |= I2C_OMAP_ERRATA_I462; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci if (!(omap->flags & OMAP_I2C_FLAG_NO_FIFO)) { 144762306a36Sopenharmony_ci u16 s; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* Set up the fifo size - Get total size */ 145062306a36Sopenharmony_ci s = (omap_i2c_read_reg(omap, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3; 145162306a36Sopenharmony_ci omap->fifo_size = 0x8 << s; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci /* 145462306a36Sopenharmony_ci * Set up notification threshold as half the total available 145562306a36Sopenharmony_ci * size. This is to ensure that we can handle the status on int 145662306a36Sopenharmony_ci * call back latencies. 145762306a36Sopenharmony_ci */ 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci omap->fifo_size = (omap->fifo_size / 2); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (omap->rev < OMAP_I2C_REV_ON_3630) 146262306a36Sopenharmony_ci omap->b_hw = 1; /* Enable hardware fixes */ 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci /* calculate wakeup latency constraint for MPU */ 146562306a36Sopenharmony_ci if (omap->set_mpu_wkup_lat != NULL) 146662306a36Sopenharmony_ci omap->latency = (1000000 * omap->fifo_size) / 146762306a36Sopenharmony_ci (1000 * omap->speed / 8); 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci /* reset ASAP, clearing any IRQs */ 147162306a36Sopenharmony_ci omap_i2c_init(omap); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci if (omap->rev < OMAP_I2C_OMAP1_REV_2) 147462306a36Sopenharmony_ci r = devm_request_irq(&pdev->dev, omap->irq, omap_i2c_omap1_isr, 147562306a36Sopenharmony_ci IRQF_NO_SUSPEND, pdev->name, omap); 147662306a36Sopenharmony_ci else 147762306a36Sopenharmony_ci r = devm_request_threaded_irq(&pdev->dev, omap->irq, 147862306a36Sopenharmony_ci omap_i2c_isr, omap_i2c_isr_thread, 147962306a36Sopenharmony_ci IRQF_NO_SUSPEND | IRQF_ONESHOT, 148062306a36Sopenharmony_ci pdev->name, omap); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci if (r) { 148362306a36Sopenharmony_ci dev_err(omap->dev, "failure requesting irq %i\n", omap->irq); 148462306a36Sopenharmony_ci goto err_unuse_clocks; 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci adap = &omap->adapter; 148862306a36Sopenharmony_ci i2c_set_adapdata(adap, omap); 148962306a36Sopenharmony_ci adap->owner = THIS_MODULE; 149062306a36Sopenharmony_ci adap->class = I2C_CLASS_DEPRECATED; 149162306a36Sopenharmony_ci strscpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); 149262306a36Sopenharmony_ci adap->algo = &omap_i2c_algo; 149362306a36Sopenharmony_ci adap->quirks = &omap_i2c_quirks; 149462306a36Sopenharmony_ci adap->dev.parent = &pdev->dev; 149562306a36Sopenharmony_ci adap->dev.of_node = pdev->dev.of_node; 149662306a36Sopenharmony_ci adap->bus_recovery_info = &omap_i2c_bus_recovery_info; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* i2c device drivers may be active on return from add_adapter() */ 149962306a36Sopenharmony_ci adap->nr = pdev->id; 150062306a36Sopenharmony_ci r = i2c_add_numbered_adapter(adap); 150162306a36Sopenharmony_ci if (r) 150262306a36Sopenharmony_ci goto err_unuse_clocks; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, 150562306a36Sopenharmony_ci major, minor, omap->speed); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci pm_runtime_mark_last_busy(omap->dev); 150862306a36Sopenharmony_ci pm_runtime_put_autosuspend(omap->dev); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci return 0; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_cierr_unuse_clocks: 151362306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); 151462306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(omap->dev); 151562306a36Sopenharmony_ci pm_runtime_put_sync(omap->dev); 151662306a36Sopenharmony_cierr_disable_pm: 151762306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci return r; 152062306a36Sopenharmony_ci} 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_cistatic void omap_i2c_remove(struct platform_device *pdev) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci struct omap_i2c_dev *omap = platform_get_drvdata(pdev); 152562306a36Sopenharmony_ci int ret; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci i2c_del_adapter(&omap->adapter); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci ret = pm_runtime_get_sync(&pdev->dev); 153062306a36Sopenharmony_ci if (ret < 0) 153162306a36Sopenharmony_ci dev_err(omap->dev, "Failed to resume hardware, skip disable\n"); 153262306a36Sopenharmony_ci else 153362306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 153662306a36Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 153762306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 153862306a36Sopenharmony_ci} 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cistatic int __maybe_unused omap_i2c_runtime_suspend(struct device *dev) 154162306a36Sopenharmony_ci{ 154262306a36Sopenharmony_ci struct omap_i2c_dev *omap = dev_get_drvdata(dev); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci omap->iestate = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (omap->scheme == OMAP_I2C_SCHEME_0) 154762306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, 0); 154862306a36Sopenharmony_ci else 154962306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_IP_V2_IRQENABLE_CLR, 155062306a36Sopenharmony_ci OMAP_I2C_IP_V2_INTERRUPTS_MASK); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (omap->rev < OMAP_I2C_OMAP1_REV_2) { 155362306a36Sopenharmony_ci omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); /* Read clears */ 155462306a36Sopenharmony_ci } else { 155562306a36Sopenharmony_ci omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, omap->iestate); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci /* Flush posted write */ 155862306a36Sopenharmony_ci omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci return 0; 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic int __maybe_unused omap_i2c_runtime_resume(struct device *dev) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci struct omap_i2c_dev *omap = dev_get_drvdata(dev); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (!omap->regs) 157362306a36Sopenharmony_ci return 0; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci __omap_i2c_init(omap); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci return 0; 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_cistatic const struct dev_pm_ops omap_i2c_pm_ops = { 158162306a36Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 158262306a36Sopenharmony_ci pm_runtime_force_resume) 158362306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, 158462306a36Sopenharmony_ci omap_i2c_runtime_resume, NULL) 158562306a36Sopenharmony_ci}; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_cistatic struct platform_driver omap_i2c_driver = { 158862306a36Sopenharmony_ci .probe = omap_i2c_probe, 158962306a36Sopenharmony_ci .remove_new = omap_i2c_remove, 159062306a36Sopenharmony_ci .driver = { 159162306a36Sopenharmony_ci .name = "omap_i2c", 159262306a36Sopenharmony_ci .pm = &omap_i2c_pm_ops, 159362306a36Sopenharmony_ci .of_match_table = of_match_ptr(omap_i2c_of_match), 159462306a36Sopenharmony_ci }, 159562306a36Sopenharmony_ci}; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci/* I2C may be needed to bring up other drivers */ 159862306a36Sopenharmony_cistatic int __init 159962306a36Sopenharmony_ciomap_i2c_init_driver(void) 160062306a36Sopenharmony_ci{ 160162306a36Sopenharmony_ci return platform_driver_register(&omap_i2c_driver); 160262306a36Sopenharmony_ci} 160362306a36Sopenharmony_cisubsys_initcall(omap_i2c_init_driver); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic void __exit omap_i2c_exit_driver(void) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci platform_driver_unregister(&omap_i2c_driver); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_cimodule_exit(omap_i2c_exit_driver); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ciMODULE_AUTHOR("MontaVista Software, Inc. (and others)"); 161262306a36Sopenharmony_ciMODULE_DESCRIPTION("TI OMAP I2C bus adapter"); 161362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 161462306a36Sopenharmony_ciMODULE_ALIAS("platform:omap_i2c"); 1615