162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * i2c-exynos5.c - Samsung Exynos5 I2C Controller Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co., Ltd. 662306a36Sopenharmony_ci*/ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/time.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/clk.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/io.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <linux/spinlock.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * HSI2C controller from Samsung supports 2 modes of operation 2662306a36Sopenharmony_ci * 1. Auto mode: Where in master automatically controls the whole transaction 2762306a36Sopenharmony_ci * 2. Manual mode: Software controls the transaction by issuing commands 2862306a36Sopenharmony_ci * START, READ, WRITE, STOP, RESTART in I2C_MANUAL_CMD register. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Operation mode can be selected by setting AUTO_MODE bit in I2C_CONF register 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * Special bits are available for both modes of operation to set commands 3362306a36Sopenharmony_ci * and for checking transfer status 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* Register Map */ 3762306a36Sopenharmony_ci#define HSI2C_CTL 0x00 3862306a36Sopenharmony_ci#define HSI2C_FIFO_CTL 0x04 3962306a36Sopenharmony_ci#define HSI2C_TRAILIG_CTL 0x08 4062306a36Sopenharmony_ci#define HSI2C_CLK_CTL 0x0C 4162306a36Sopenharmony_ci#define HSI2C_CLK_SLOT 0x10 4262306a36Sopenharmony_ci#define HSI2C_INT_ENABLE 0x20 4362306a36Sopenharmony_ci#define HSI2C_INT_STATUS 0x24 4462306a36Sopenharmony_ci#define HSI2C_ERR_STATUS 0x2C 4562306a36Sopenharmony_ci#define HSI2C_FIFO_STATUS 0x30 4662306a36Sopenharmony_ci#define HSI2C_TX_DATA 0x34 4762306a36Sopenharmony_ci#define HSI2C_RX_DATA 0x38 4862306a36Sopenharmony_ci#define HSI2C_CONF 0x40 4962306a36Sopenharmony_ci#define HSI2C_AUTO_CONF 0x44 5062306a36Sopenharmony_ci#define HSI2C_TIMEOUT 0x48 5162306a36Sopenharmony_ci#define HSI2C_MANUAL_CMD 0x4C 5262306a36Sopenharmony_ci#define HSI2C_TRANS_STATUS 0x50 5362306a36Sopenharmony_ci#define HSI2C_TIMING_HS1 0x54 5462306a36Sopenharmony_ci#define HSI2C_TIMING_HS2 0x58 5562306a36Sopenharmony_ci#define HSI2C_TIMING_HS3 0x5C 5662306a36Sopenharmony_ci#define HSI2C_TIMING_FS1 0x60 5762306a36Sopenharmony_ci#define HSI2C_TIMING_FS2 0x64 5862306a36Sopenharmony_ci#define HSI2C_TIMING_FS3 0x68 5962306a36Sopenharmony_ci#define HSI2C_TIMING_SLA 0x6C 6062306a36Sopenharmony_ci#define HSI2C_ADDR 0x70 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* I2C_CTL Register bits */ 6362306a36Sopenharmony_ci#define HSI2C_FUNC_MODE_I2C (1u << 0) 6462306a36Sopenharmony_ci#define HSI2C_MASTER (1u << 3) 6562306a36Sopenharmony_ci#define HSI2C_RXCHON (1u << 6) 6662306a36Sopenharmony_ci#define HSI2C_TXCHON (1u << 7) 6762306a36Sopenharmony_ci#define HSI2C_SW_RST (1u << 31) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* I2C_FIFO_CTL Register bits */ 7062306a36Sopenharmony_ci#define HSI2C_RXFIFO_EN (1u << 0) 7162306a36Sopenharmony_ci#define HSI2C_TXFIFO_EN (1u << 1) 7262306a36Sopenharmony_ci#define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4) 7362306a36Sopenharmony_ci#define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* I2C_TRAILING_CTL Register bits */ 7662306a36Sopenharmony_ci#define HSI2C_TRAILING_COUNT (0xf) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* I2C_INT_EN Register bits */ 7962306a36Sopenharmony_ci#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) 8062306a36Sopenharmony_ci#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) 8162306a36Sopenharmony_ci#define HSI2C_INT_TRAILING_EN (1u << 6) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* I2C_INT_STAT Register bits */ 8462306a36Sopenharmony_ci#define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0) 8562306a36Sopenharmony_ci#define HSI2C_INT_RX_ALMOSTFULL (1u << 1) 8662306a36Sopenharmony_ci#define HSI2C_INT_TX_UNDERRUN (1u << 2) 8762306a36Sopenharmony_ci#define HSI2C_INT_TX_OVERRUN (1u << 3) 8862306a36Sopenharmony_ci#define HSI2C_INT_RX_UNDERRUN (1u << 4) 8962306a36Sopenharmony_ci#define HSI2C_INT_RX_OVERRUN (1u << 5) 9062306a36Sopenharmony_ci#define HSI2C_INT_TRAILING (1u << 6) 9162306a36Sopenharmony_ci#define HSI2C_INT_I2C (1u << 9) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define HSI2C_INT_TRANS_DONE (1u << 7) 9462306a36Sopenharmony_ci#define HSI2C_INT_TRANS_ABORT (1u << 8) 9562306a36Sopenharmony_ci#define HSI2C_INT_NO_DEV_ACK (1u << 9) 9662306a36Sopenharmony_ci#define HSI2C_INT_NO_DEV (1u << 10) 9762306a36Sopenharmony_ci#define HSI2C_INT_TIMEOUT (1u << 11) 9862306a36Sopenharmony_ci#define HSI2C_INT_I2C_TRANS (HSI2C_INT_TRANS_DONE | \ 9962306a36Sopenharmony_ci HSI2C_INT_TRANS_ABORT | \ 10062306a36Sopenharmony_ci HSI2C_INT_NO_DEV_ACK | \ 10162306a36Sopenharmony_ci HSI2C_INT_NO_DEV | \ 10262306a36Sopenharmony_ci HSI2C_INT_TIMEOUT) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* I2C_FIFO_STAT Register bits */ 10562306a36Sopenharmony_ci#define HSI2C_RX_FIFO_EMPTY (1u << 24) 10662306a36Sopenharmony_ci#define HSI2C_RX_FIFO_FULL (1u << 23) 10762306a36Sopenharmony_ci#define HSI2C_RX_FIFO_LVL(x) ((x >> 16) & 0x7f) 10862306a36Sopenharmony_ci#define HSI2C_TX_FIFO_EMPTY (1u << 8) 10962306a36Sopenharmony_ci#define HSI2C_TX_FIFO_FULL (1u << 7) 11062306a36Sopenharmony_ci#define HSI2C_TX_FIFO_LVL(x) ((x >> 0) & 0x7f) 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* I2C_CONF Register bits */ 11362306a36Sopenharmony_ci#define HSI2C_AUTO_MODE (1u << 31) 11462306a36Sopenharmony_ci#define HSI2C_10BIT_ADDR_MODE (1u << 30) 11562306a36Sopenharmony_ci#define HSI2C_HS_MODE (1u << 29) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* I2C_AUTO_CONF Register bits */ 11862306a36Sopenharmony_ci#define HSI2C_READ_WRITE (1u << 16) 11962306a36Sopenharmony_ci#define HSI2C_STOP_AFTER_TRANS (1u << 17) 12062306a36Sopenharmony_ci#define HSI2C_MASTER_RUN (1u << 31) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* I2C_TIMEOUT Register bits */ 12362306a36Sopenharmony_ci#define HSI2C_TIMEOUT_EN (1u << 31) 12462306a36Sopenharmony_ci#define HSI2C_TIMEOUT_MASK 0xff 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* I2C_MANUAL_CMD register bits */ 12762306a36Sopenharmony_ci#define HSI2C_CMD_READ_DATA (1u << 4) 12862306a36Sopenharmony_ci#define HSI2C_CMD_SEND_STOP (1u << 2) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* I2C_TRANS_STATUS register bits */ 13162306a36Sopenharmony_ci#define HSI2C_MASTER_BUSY (1u << 17) 13262306a36Sopenharmony_ci#define HSI2C_SLAVE_BUSY (1u << 16) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* I2C_TRANS_STATUS register bits for Exynos5 variant */ 13562306a36Sopenharmony_ci#define HSI2C_TIMEOUT_AUTO (1u << 4) 13662306a36Sopenharmony_ci#define HSI2C_NO_DEV (1u << 3) 13762306a36Sopenharmony_ci#define HSI2C_NO_DEV_ACK (1u << 2) 13862306a36Sopenharmony_ci#define HSI2C_TRANS_ABORT (1u << 1) 13962306a36Sopenharmony_ci#define HSI2C_TRANS_DONE (1u << 0) 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* I2C_TRANS_STATUS register bits for Exynos7 variant */ 14262306a36Sopenharmony_ci#define HSI2C_MASTER_ST_MASK 0xf 14362306a36Sopenharmony_ci#define HSI2C_MASTER_ST_IDLE 0x0 14462306a36Sopenharmony_ci#define HSI2C_MASTER_ST_START 0x1 14562306a36Sopenharmony_ci#define HSI2C_MASTER_ST_RESTART 0x2 14662306a36Sopenharmony_ci#define HSI2C_MASTER_ST_STOP 0x3 14762306a36Sopenharmony_ci#define HSI2C_MASTER_ST_MASTER_ID 0x4 14862306a36Sopenharmony_ci#define HSI2C_MASTER_ST_ADDR0 0x5 14962306a36Sopenharmony_ci#define HSI2C_MASTER_ST_ADDR1 0x6 15062306a36Sopenharmony_ci#define HSI2C_MASTER_ST_ADDR2 0x7 15162306a36Sopenharmony_ci#define HSI2C_MASTER_ST_ADDR_SR 0x8 15262306a36Sopenharmony_ci#define HSI2C_MASTER_ST_READ 0x9 15362306a36Sopenharmony_ci#define HSI2C_MASTER_ST_WRITE 0xa 15462306a36Sopenharmony_ci#define HSI2C_MASTER_ST_NO_ACK 0xb 15562306a36Sopenharmony_ci#define HSI2C_MASTER_ST_LOSE 0xc 15662306a36Sopenharmony_ci#define HSI2C_MASTER_ST_WAIT 0xd 15762306a36Sopenharmony_ci#define HSI2C_MASTER_ST_WAIT_CMD 0xe 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* I2C_ADDR register bits */ 16062306a36Sopenharmony_ci#define HSI2C_SLV_ADDR_SLV(x) ((x & 0x3ff) << 0) 16162306a36Sopenharmony_ci#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) 16262306a36Sopenharmony_ci#define HSI2C_MASTER_ID(x) ((x & 0xff) << 24) 16362306a36Sopenharmony_ci#define MASTER_ID(x) ((x & 0x7) + 0x08) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100)) 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cienum i2c_type_exynos { 16862306a36Sopenharmony_ci I2C_TYPE_EXYNOS5, 16962306a36Sopenharmony_ci I2C_TYPE_EXYNOS7, 17062306a36Sopenharmony_ci I2C_TYPE_EXYNOSAUTOV9, 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistruct exynos5_i2c { 17462306a36Sopenharmony_ci struct i2c_adapter adap; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci struct i2c_msg *msg; 17762306a36Sopenharmony_ci struct completion msg_complete; 17862306a36Sopenharmony_ci unsigned int msg_ptr; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci unsigned int irq; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci void __iomem *regs; 18362306a36Sopenharmony_ci struct clk *clk; /* operating clock */ 18462306a36Sopenharmony_ci struct clk *pclk; /* bus clock */ 18562306a36Sopenharmony_ci struct device *dev; 18662306a36Sopenharmony_ci int state; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci spinlock_t lock; /* IRQ synchronization */ 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Since the TRANS_DONE bit is cleared on read, and we may read it 19262306a36Sopenharmony_ci * either during an IRQ or after a transaction, keep track of its 19362306a36Sopenharmony_ci * state here. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci int trans_done; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* Controller operating frequency */ 19862306a36Sopenharmony_ci unsigned int op_clock; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Version of HS-I2C Hardware */ 20162306a36Sopenharmony_ci const struct exynos_hsi2c_variant *variant; 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/** 20562306a36Sopenharmony_ci * struct exynos_hsi2c_variant - platform specific HSI2C driver data 20662306a36Sopenharmony_ci * @fifo_depth: the fifo depth supported by the HSI2C module 20762306a36Sopenharmony_ci * @hw: the hardware variant of Exynos I2C controller 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * Specifies platform specific configuration of HSI2C module. 21062306a36Sopenharmony_ci * Note: A structure for driver specific platform data is used for future 21162306a36Sopenharmony_ci * expansion of its usage. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_cistruct exynos_hsi2c_variant { 21462306a36Sopenharmony_ci unsigned int fifo_depth; 21562306a36Sopenharmony_ci enum i2c_type_exynos hw; 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { 21962306a36Sopenharmony_ci .fifo_depth = 64, 22062306a36Sopenharmony_ci .hw = I2C_TYPE_EXYNOS5, 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { 22462306a36Sopenharmony_ci .fifo_depth = 16, 22562306a36Sopenharmony_ci .hw = I2C_TYPE_EXYNOS5, 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic const struct exynos_hsi2c_variant exynos7_hsi2c_data = { 22962306a36Sopenharmony_ci .fifo_depth = 16, 23062306a36Sopenharmony_ci .hw = I2C_TYPE_EXYNOS7, 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic const struct exynos_hsi2c_variant exynosautov9_hsi2c_data = { 23462306a36Sopenharmony_ci .fifo_depth = 64, 23562306a36Sopenharmony_ci .hw = I2C_TYPE_EXYNOSAUTOV9, 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic const struct of_device_id exynos5_i2c_match[] = { 23962306a36Sopenharmony_ci { 24062306a36Sopenharmony_ci .compatible = "samsung,exynos5-hsi2c", 24162306a36Sopenharmony_ci .data = &exynos5250_hsi2c_data 24262306a36Sopenharmony_ci }, { 24362306a36Sopenharmony_ci .compatible = "samsung,exynos5250-hsi2c", 24462306a36Sopenharmony_ci .data = &exynos5250_hsi2c_data 24562306a36Sopenharmony_ci }, { 24662306a36Sopenharmony_ci .compatible = "samsung,exynos5260-hsi2c", 24762306a36Sopenharmony_ci .data = &exynos5260_hsi2c_data 24862306a36Sopenharmony_ci }, { 24962306a36Sopenharmony_ci .compatible = "samsung,exynos7-hsi2c", 25062306a36Sopenharmony_ci .data = &exynos7_hsi2c_data 25162306a36Sopenharmony_ci }, { 25262306a36Sopenharmony_ci .compatible = "samsung,exynosautov9-hsi2c", 25362306a36Sopenharmony_ci .data = &exynosautov9_hsi2c_data 25462306a36Sopenharmony_ci }, {}, 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, exynos5_i2c_match); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci writel(readl(i2c->regs + HSI2C_INT_STATUS), 26162306a36Sopenharmony_ci i2c->regs + HSI2C_INT_STATUS); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * exynos5_i2c_set_timing: updates the registers with appropriate 26662306a36Sopenharmony_ci * timing values calculated 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * Timing values for operation are calculated against either 100kHz 26962306a36Sopenharmony_ci * or 1MHz controller operating frequency. 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * Returns 0 on success, -EINVAL if the cycle length cannot 27262306a36Sopenharmony_ci * be calculated. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_cistatic int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci u32 i2c_timing_s1; 27762306a36Sopenharmony_ci u32 i2c_timing_s2; 27862306a36Sopenharmony_ci u32 i2c_timing_s3; 27962306a36Sopenharmony_ci u32 i2c_timing_sla; 28062306a36Sopenharmony_ci unsigned int t_start_su, t_start_hd; 28162306a36Sopenharmony_ci unsigned int t_stop_su; 28262306a36Sopenharmony_ci unsigned int t_data_su, t_data_hd; 28362306a36Sopenharmony_ci unsigned int t_scl_l, t_scl_h; 28462306a36Sopenharmony_ci unsigned int t_sr_release; 28562306a36Sopenharmony_ci unsigned int t_ftl_cycle; 28662306a36Sopenharmony_ci unsigned int clkin = clk_get_rate(i2c->clk); 28762306a36Sopenharmony_ci unsigned int op_clk = hs_timings ? i2c->op_clock : 28862306a36Sopenharmony_ci (i2c->op_clock >= I2C_MAX_FAST_MODE_PLUS_FREQ) ? I2C_MAX_STANDARD_MODE_FREQ : 28962306a36Sopenharmony_ci i2c->op_clock; 29062306a36Sopenharmony_ci int div, clk_cycle, temp; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * In case of HSI2C controllers in ExynosAutoV9: 29462306a36Sopenharmony_ci * 29562306a36Sopenharmony_ci * FSCL = IPCLK / ((CLK_DIV + 1) * 16) 29662306a36Sopenharmony_ci * T_SCL_LOW = IPCLK * (CLK_DIV + 1) * (N + M) 29762306a36Sopenharmony_ci * [N : number of 0's in the TSCL_H_HS] 29862306a36Sopenharmony_ci * [M : number of 0's in the TSCL_L_HS] 29962306a36Sopenharmony_ci * T_SCL_HIGH = IPCLK * (CLK_DIV + 1) * (N + M) 30062306a36Sopenharmony_ci * [N : number of 1's in the TSCL_H_HS] 30162306a36Sopenharmony_ci * [M : number of 1's in the TSCL_L_HS] 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * Result of (N + M) is always 8. 30462306a36Sopenharmony_ci * In general case, we don't need to control timing_s1 and timing_s2. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci if (i2c->variant->hw == I2C_TYPE_EXYNOSAUTOV9) { 30762306a36Sopenharmony_ci div = ((clkin / (16 * i2c->op_clock)) - 1); 30862306a36Sopenharmony_ci i2c_timing_s3 = div << 16; 30962306a36Sopenharmony_ci if (hs_timings) 31062306a36Sopenharmony_ci writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); 31162306a36Sopenharmony_ci else 31262306a36Sopenharmony_ci writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * In case of HSI2C controller in Exynos5 series 31962306a36Sopenharmony_ci * FPCLK / FI2C = 32062306a36Sopenharmony_ci * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * In case of HSI2C controllers in Exynos7 series 32362306a36Sopenharmony_ci * FPCLK / FI2C = 32462306a36Sopenharmony_ci * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * clk_cycle := TSCLK_L + TSCLK_H 32762306a36Sopenharmony_ci * temp := (CLK_DIV + 1) * (clk_cycle + 2) 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; 33362306a36Sopenharmony_ci temp = clkin / op_clk - 8 - t_ftl_cycle; 33462306a36Sopenharmony_ci if (i2c->variant->hw != I2C_TYPE_EXYNOS7) 33562306a36Sopenharmony_ci temp -= t_ftl_cycle; 33662306a36Sopenharmony_ci div = temp / 512; 33762306a36Sopenharmony_ci clk_cycle = temp / (div + 1) - 2; 33862306a36Sopenharmony_ci if (temp < 4 || div >= 256 || clk_cycle < 2) { 33962306a36Sopenharmony_ci dev_err(i2c->dev, "%s clock set-up failed\n", 34062306a36Sopenharmony_ci hs_timings ? "HS" : "FS"); 34162306a36Sopenharmony_ci return -EINVAL; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci t_scl_l = clk_cycle / 2; 34562306a36Sopenharmony_ci t_scl_h = clk_cycle / 2; 34662306a36Sopenharmony_ci t_start_su = t_scl_l; 34762306a36Sopenharmony_ci t_start_hd = t_scl_l; 34862306a36Sopenharmony_ci t_stop_su = t_scl_l; 34962306a36Sopenharmony_ci t_data_su = t_scl_l / 2; 35062306a36Sopenharmony_ci t_data_hd = t_scl_l / 2; 35162306a36Sopenharmony_ci t_sr_release = clk_cycle; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; 35462306a36Sopenharmony_ci i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; 35562306a36Sopenharmony_ci i2c_timing_s3 = div << 16 | t_sr_release << 0; 35662306a36Sopenharmony_ci i2c_timing_sla = t_data_hd << 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci dev_dbg(i2c->dev, "tSTART_SU: %X, tSTART_HD: %X, tSTOP_SU: %X\n", 35962306a36Sopenharmony_ci t_start_su, t_start_hd, t_stop_su); 36062306a36Sopenharmony_ci dev_dbg(i2c->dev, "tDATA_SU: %X, tSCL_L: %X, tSCL_H: %X\n", 36162306a36Sopenharmony_ci t_data_su, t_scl_l, t_scl_h); 36262306a36Sopenharmony_ci dev_dbg(i2c->dev, "nClkDiv: %X, tSR_RELEASE: %X\n", 36362306a36Sopenharmony_ci div, t_sr_release); 36462306a36Sopenharmony_ci dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (hs_timings) { 36762306a36Sopenharmony_ci writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1); 36862306a36Sopenharmony_ci writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2); 36962306a36Sopenharmony_ci writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); 37062306a36Sopenharmony_ci } else { 37162306a36Sopenharmony_ci writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_FS1); 37262306a36Sopenharmony_ci writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_FS2); 37362306a36Sopenharmony_ci writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci writel(i2c_timing_sla, i2c->regs + HSI2C_TIMING_SLA); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci /* always set Fast Speed timings */ 38362306a36Sopenharmony_ci int ret = exynos5_i2c_set_timing(i2c, false); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (ret < 0 || i2c->op_clock < I2C_MAX_FAST_MODE_PLUS_FREQ) 38662306a36Sopenharmony_ci return ret; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return exynos5_i2c_set_timing(i2c, true); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/* 39262306a36Sopenharmony_ci * exynos5_i2c_init: configures the controller for I2C functionality 39362306a36Sopenharmony_ci * Programs I2C controller for Master mode operation 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_cistatic void exynos5_i2c_init(struct exynos5_i2c *i2c) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci u32 i2c_conf = readl(i2c->regs + HSI2C_CONF); 39862306a36Sopenharmony_ci u32 i2c_timeout = readl(i2c->regs + HSI2C_TIMEOUT); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Clear to disable Timeout */ 40162306a36Sopenharmony_ci i2c_timeout &= ~HSI2C_TIMEOUT_EN; 40262306a36Sopenharmony_ci writel(i2c_timeout, i2c->regs + HSI2C_TIMEOUT); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci writel((HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), 40562306a36Sopenharmony_ci i2c->regs + HSI2C_CTL); 40662306a36Sopenharmony_ci writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (i2c->op_clock >= I2C_MAX_FAST_MODE_PLUS_FREQ) { 40962306a36Sopenharmony_ci writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)), 41062306a36Sopenharmony_ci i2c->regs + HSI2C_ADDR); 41162306a36Sopenharmony_ci i2c_conf |= HSI2C_HS_MODE; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci writel(i2c_conf | HSI2C_AUTO_MODE, i2c->regs + HSI2C_CONF); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void exynos5_i2c_reset(struct exynos5_i2c *i2c) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci u32 i2c_ctl; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Set and clear the bit for reset */ 42262306a36Sopenharmony_ci i2c_ctl = readl(i2c->regs + HSI2C_CTL); 42362306a36Sopenharmony_ci i2c_ctl |= HSI2C_SW_RST; 42462306a36Sopenharmony_ci writel(i2c_ctl, i2c->regs + HSI2C_CTL); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci i2c_ctl = readl(i2c->regs + HSI2C_CTL); 42762306a36Sopenharmony_ci i2c_ctl &= ~HSI2C_SW_RST; 42862306a36Sopenharmony_ci writel(i2c_ctl, i2c->regs + HSI2C_CTL); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* We don't expect calculations to fail during the run */ 43162306a36Sopenharmony_ci exynos5_hsi2c_clock_setup(i2c); 43262306a36Sopenharmony_ci /* Initialize the configure registers */ 43362306a36Sopenharmony_ci exynos5_i2c_init(i2c); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/* 43762306a36Sopenharmony_ci * exynos5_i2c_irq: top level IRQ servicing routine 43862306a36Sopenharmony_ci * 43962306a36Sopenharmony_ci * INT_STATUS registers gives the interrupt details. Further, 44062306a36Sopenharmony_ci * FIFO_STATUS or TRANS_STATUS registers are to be check for detailed 44162306a36Sopenharmony_ci * state of the bus. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_cistatic irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct exynos5_i2c *i2c = dev_id; 44662306a36Sopenharmony_ci u32 fifo_level, int_status, fifo_status, trans_status; 44762306a36Sopenharmony_ci unsigned char byte; 44862306a36Sopenharmony_ci int len = 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci i2c->state = -EINVAL; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci spin_lock(&i2c->lock); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci int_status = readl(i2c->regs + HSI2C_INT_STATUS); 45562306a36Sopenharmony_ci writel(int_status, i2c->regs + HSI2C_INT_STATUS); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* handle interrupt related to the transfer status */ 45862306a36Sopenharmony_ci switch (i2c->variant->hw) { 45962306a36Sopenharmony_ci case I2C_TYPE_EXYNOSAUTOV9: 46062306a36Sopenharmony_ci fallthrough; 46162306a36Sopenharmony_ci case I2C_TYPE_EXYNOS7: 46262306a36Sopenharmony_ci if (int_status & HSI2C_INT_TRANS_DONE) { 46362306a36Sopenharmony_ci i2c->trans_done = 1; 46462306a36Sopenharmony_ci i2c->state = 0; 46562306a36Sopenharmony_ci } else if (int_status & HSI2C_INT_TRANS_ABORT) { 46662306a36Sopenharmony_ci dev_dbg(i2c->dev, "Deal with arbitration lose\n"); 46762306a36Sopenharmony_ci i2c->state = -EAGAIN; 46862306a36Sopenharmony_ci goto stop; 46962306a36Sopenharmony_ci } else if (int_status & HSI2C_INT_NO_DEV_ACK) { 47062306a36Sopenharmony_ci dev_dbg(i2c->dev, "No ACK from device\n"); 47162306a36Sopenharmony_ci i2c->state = -ENXIO; 47262306a36Sopenharmony_ci goto stop; 47362306a36Sopenharmony_ci } else if (int_status & HSI2C_INT_NO_DEV) { 47462306a36Sopenharmony_ci dev_dbg(i2c->dev, "No device\n"); 47562306a36Sopenharmony_ci i2c->state = -ENXIO; 47662306a36Sopenharmony_ci goto stop; 47762306a36Sopenharmony_ci } else if (int_status & HSI2C_INT_TIMEOUT) { 47862306a36Sopenharmony_ci dev_dbg(i2c->dev, "Accessing device timed out\n"); 47962306a36Sopenharmony_ci i2c->state = -ETIMEDOUT; 48062306a36Sopenharmony_ci goto stop; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case I2C_TYPE_EXYNOS5: 48562306a36Sopenharmony_ci if (!(int_status & HSI2C_INT_I2C)) 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); 48962306a36Sopenharmony_ci if (trans_status & HSI2C_NO_DEV_ACK) { 49062306a36Sopenharmony_ci dev_dbg(i2c->dev, "No ACK from device\n"); 49162306a36Sopenharmony_ci i2c->state = -ENXIO; 49262306a36Sopenharmony_ci goto stop; 49362306a36Sopenharmony_ci } else if (trans_status & HSI2C_NO_DEV) { 49462306a36Sopenharmony_ci dev_dbg(i2c->dev, "No device\n"); 49562306a36Sopenharmony_ci i2c->state = -ENXIO; 49662306a36Sopenharmony_ci goto stop; 49762306a36Sopenharmony_ci } else if (trans_status & HSI2C_TRANS_ABORT) { 49862306a36Sopenharmony_ci dev_dbg(i2c->dev, "Deal with arbitration lose\n"); 49962306a36Sopenharmony_ci i2c->state = -EAGAIN; 50062306a36Sopenharmony_ci goto stop; 50162306a36Sopenharmony_ci } else if (trans_status & HSI2C_TIMEOUT_AUTO) { 50262306a36Sopenharmony_ci dev_dbg(i2c->dev, "Accessing device timed out\n"); 50362306a36Sopenharmony_ci i2c->state = -ETIMEDOUT; 50462306a36Sopenharmony_ci goto stop; 50562306a36Sopenharmony_ci } else if (trans_status & HSI2C_TRANS_DONE) { 50662306a36Sopenharmony_ci i2c->trans_done = 1; 50762306a36Sopenharmony_ci i2c->state = 0; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if ((i2c->msg->flags & I2C_M_RD) && (int_status & 51462306a36Sopenharmony_ci (HSI2C_INT_TRAILING | HSI2C_INT_RX_ALMOSTFULL))) { 51562306a36Sopenharmony_ci fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); 51662306a36Sopenharmony_ci fifo_level = HSI2C_RX_FIFO_LVL(fifo_status); 51762306a36Sopenharmony_ci len = min(fifo_level, i2c->msg->len - i2c->msg_ptr); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci while (len > 0) { 52062306a36Sopenharmony_ci byte = (unsigned char) 52162306a36Sopenharmony_ci readl(i2c->regs + HSI2C_RX_DATA); 52262306a36Sopenharmony_ci i2c->msg->buf[i2c->msg_ptr++] = byte; 52362306a36Sopenharmony_ci len--; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci i2c->state = 0; 52662306a36Sopenharmony_ci } else if (int_status & HSI2C_INT_TX_ALMOSTEMPTY) { 52762306a36Sopenharmony_ci fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); 52862306a36Sopenharmony_ci fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci len = i2c->variant->fifo_depth - fifo_level; 53162306a36Sopenharmony_ci if (len > (i2c->msg->len - i2c->msg_ptr)) { 53262306a36Sopenharmony_ci u32 int_en = readl(i2c->regs + HSI2C_INT_ENABLE); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci int_en &= ~HSI2C_INT_TX_ALMOSTEMPTY_EN; 53562306a36Sopenharmony_ci writel(int_en, i2c->regs + HSI2C_INT_ENABLE); 53662306a36Sopenharmony_ci len = i2c->msg->len - i2c->msg_ptr; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci while (len > 0) { 54062306a36Sopenharmony_ci byte = i2c->msg->buf[i2c->msg_ptr++]; 54162306a36Sopenharmony_ci writel(byte, i2c->regs + HSI2C_TX_DATA); 54262306a36Sopenharmony_ci len--; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci i2c->state = 0; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci stop: 54862306a36Sopenharmony_ci if ((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) || 54962306a36Sopenharmony_ci (i2c->state < 0)) { 55062306a36Sopenharmony_ci writel(0, i2c->regs + HSI2C_INT_ENABLE); 55162306a36Sopenharmony_ci exynos5_i2c_clr_pend_irq(i2c); 55262306a36Sopenharmony_ci complete(&i2c->msg_complete); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci spin_unlock(&i2c->lock); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return IRQ_HANDLED; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/* 56162306a36Sopenharmony_ci * exynos5_i2c_wait_bus_idle 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * Wait for the bus to go idle, indicated by the MASTER_BUSY bit being 56462306a36Sopenharmony_ci * cleared. 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci * Returns -EBUSY if the bus cannot be bought to idle 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_cistatic int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci unsigned long stop_time; 57162306a36Sopenharmony_ci u32 trans_status; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* wait for 100 milli seconds for the bus to be idle */ 57462306a36Sopenharmony_ci stop_time = jiffies + msecs_to_jiffies(100) + 1; 57562306a36Sopenharmony_ci do { 57662306a36Sopenharmony_ci trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); 57762306a36Sopenharmony_ci if (!(trans_status & HSI2C_MASTER_BUSY)) 57862306a36Sopenharmony_ci return 0; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci usleep_range(50, 200); 58162306a36Sopenharmony_ci } while (time_before(jiffies, stop_time)); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return -EBUSY; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void exynos5_i2c_bus_recover(struct exynos5_i2c *i2c) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci u32 val; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci val = readl(i2c->regs + HSI2C_CTL) | HSI2C_RXCHON; 59162306a36Sopenharmony_ci writel(val, i2c->regs + HSI2C_CTL); 59262306a36Sopenharmony_ci val = readl(i2c->regs + HSI2C_CONF) & ~HSI2C_AUTO_MODE; 59362306a36Sopenharmony_ci writel(val, i2c->regs + HSI2C_CONF); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* 59662306a36Sopenharmony_ci * Specification says master should send nine clock pulses. It can be 59762306a36Sopenharmony_ci * emulated by sending manual read command (nine pulses for read eight 59862306a36Sopenharmony_ci * bits + one pulse for NACK). 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci writel(HSI2C_CMD_READ_DATA, i2c->regs + HSI2C_MANUAL_CMD); 60162306a36Sopenharmony_ci exynos5_i2c_wait_bus_idle(i2c); 60262306a36Sopenharmony_ci writel(HSI2C_CMD_SEND_STOP, i2c->regs + HSI2C_MANUAL_CMD); 60362306a36Sopenharmony_ci exynos5_i2c_wait_bus_idle(i2c); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci val = readl(i2c->regs + HSI2C_CTL) & ~HSI2C_RXCHON; 60662306a36Sopenharmony_ci writel(val, i2c->regs + HSI2C_CTL); 60762306a36Sopenharmony_ci val = readl(i2c->regs + HSI2C_CONF) | HSI2C_AUTO_MODE; 60862306a36Sopenharmony_ci writel(val, i2c->regs + HSI2C_CONF); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic void exynos5_i2c_bus_check(struct exynos5_i2c *i2c) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci unsigned long timeout; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (i2c->variant->hw == I2C_TYPE_EXYNOS5) 61662306a36Sopenharmony_ci return; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * HSI2C_MASTER_ST_LOSE state (in Exynos7 and ExynosAutoV9 variants) 62062306a36Sopenharmony_ci * before transaction indicates that bus is stuck (SDA is low). 62162306a36Sopenharmony_ci * In such case bus recovery can be performed. 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(100); 62462306a36Sopenharmony_ci for (;;) { 62562306a36Sopenharmony_ci u32 st = readl(i2c->regs + HSI2C_TRANS_STATUS); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if ((st & HSI2C_MASTER_ST_MASK) != HSI2C_MASTER_ST_LOSE) 62862306a36Sopenharmony_ci return; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (time_is_before_jiffies(timeout)) 63162306a36Sopenharmony_ci return; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci exynos5_i2c_bus_recover(i2c); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/* 63862306a36Sopenharmony_ci * exynos5_i2c_message_start: Configures the bus and starts the xfer 63962306a36Sopenharmony_ci * i2c: struct exynos5_i2c pointer for the current bus 64062306a36Sopenharmony_ci * stop: Enables stop after transfer if set. Set for last transfer of 64162306a36Sopenharmony_ci * in the list of messages. 64262306a36Sopenharmony_ci * 64362306a36Sopenharmony_ci * Configures the bus for read/write function 64462306a36Sopenharmony_ci * Sets chip address to talk to, message length to be sent. 64562306a36Sopenharmony_ci * Enables appropriate interrupts and sends start xfer command. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_cistatic void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci u32 i2c_ctl; 65062306a36Sopenharmony_ci u32 int_en = 0; 65162306a36Sopenharmony_ci u32 i2c_auto_conf = 0; 65262306a36Sopenharmony_ci u32 i2c_addr = 0; 65362306a36Sopenharmony_ci u32 fifo_ctl; 65462306a36Sopenharmony_ci unsigned long flags; 65562306a36Sopenharmony_ci unsigned short trig_lvl; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (i2c->variant->hw == I2C_TYPE_EXYNOS5) 65862306a36Sopenharmony_ci int_en |= HSI2C_INT_I2C; 65962306a36Sopenharmony_ci else 66062306a36Sopenharmony_ci int_en |= HSI2C_INT_I2C_TRANS; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci i2c_ctl = readl(i2c->regs + HSI2C_CTL); 66362306a36Sopenharmony_ci i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); 66462306a36Sopenharmony_ci fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (i2c->msg->flags & I2C_M_RD) { 66762306a36Sopenharmony_ci i2c_ctl |= HSI2C_RXCHON; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci i2c_auto_conf |= HSI2C_READ_WRITE; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? 67262306a36Sopenharmony_ci (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len; 67362306a36Sopenharmony_ci fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(trig_lvl); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN | 67662306a36Sopenharmony_ci HSI2C_INT_TRAILING_EN); 67762306a36Sopenharmony_ci } else { 67862306a36Sopenharmony_ci i2c_ctl |= HSI2C_TXCHON; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? 68162306a36Sopenharmony_ci (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len; 68262306a36Sopenharmony_ci fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(trig_lvl); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci i2c_addr = HSI2C_SLV_ADDR_MAS(i2c->msg->addr); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (i2c->op_clock >= I2C_MAX_FAST_MODE_PLUS_FREQ) 69062306a36Sopenharmony_ci i2c_addr |= HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci writel(i2c_addr, i2c->regs + HSI2C_ADDR); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci writel(fifo_ctl, i2c->regs + HSI2C_FIFO_CTL); 69562306a36Sopenharmony_ci writel(i2c_ctl, i2c->regs + HSI2C_CTL); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci exynos5_i2c_bus_check(i2c); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * Enable interrupts before starting the transfer so that we don't 70162306a36Sopenharmony_ci * miss any INT_I2C interrupts. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 70462306a36Sopenharmony_ci writel(int_en, i2c->regs + HSI2C_INT_ENABLE); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (stop == 1) 70762306a36Sopenharmony_ci i2c_auto_conf |= HSI2C_STOP_AFTER_TRANS; 70862306a36Sopenharmony_ci i2c_auto_conf |= i2c->msg->len; 70962306a36Sopenharmony_ci i2c_auto_conf |= HSI2C_MASTER_RUN; 71062306a36Sopenharmony_ci writel(i2c_auto_conf, i2c->regs + HSI2C_AUTO_CONF); 71162306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, 71562306a36Sopenharmony_ci struct i2c_msg *msgs, int stop) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci unsigned long timeout; 71862306a36Sopenharmony_ci int ret; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci i2c->msg = msgs; 72162306a36Sopenharmony_ci i2c->msg_ptr = 0; 72262306a36Sopenharmony_ci i2c->trans_done = 0; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci reinit_completion(&i2c->msg_complete); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci exynos5_i2c_message_start(i2c, stop); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci timeout = wait_for_completion_timeout(&i2c->msg_complete, 72962306a36Sopenharmony_ci EXYNOS5_I2C_TIMEOUT); 73062306a36Sopenharmony_ci if (timeout == 0) 73162306a36Sopenharmony_ci ret = -ETIMEDOUT; 73262306a36Sopenharmony_ci else 73362306a36Sopenharmony_ci ret = i2c->state; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* 73662306a36Sopenharmony_ci * If this is the last message to be transfered (stop == 1) 73762306a36Sopenharmony_ci * Then check if the bus can be brought back to idle. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci if (ret == 0 && stop) 74062306a36Sopenharmony_ci ret = exynos5_i2c_wait_bus_idle(i2c); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (ret < 0) { 74362306a36Sopenharmony_ci exynos5_i2c_reset(i2c); 74462306a36Sopenharmony_ci if (ret == -ETIMEDOUT) 74562306a36Sopenharmony_ci dev_warn(i2c->dev, "%s timeout\n", 74662306a36Sopenharmony_ci (msgs->flags & I2C_M_RD) ? "rx" : "tx"); 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* Return the state as in interrupt routine */ 75062306a36Sopenharmony_ci return ret; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic int exynos5_i2c_xfer(struct i2c_adapter *adap, 75462306a36Sopenharmony_ci struct i2c_msg *msgs, int num) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct exynos5_i2c *i2c = adap->algo_data; 75762306a36Sopenharmony_ci int i, ret; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci ret = clk_enable(i2c->pclk); 76062306a36Sopenharmony_ci if (ret) 76162306a36Sopenharmony_ci return ret; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ret = clk_enable(i2c->clk); 76462306a36Sopenharmony_ci if (ret) 76562306a36Sopenharmony_ci goto err_pclk; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci for (i = 0; i < num; ++i) { 76862306a36Sopenharmony_ci ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num); 76962306a36Sopenharmony_ci if (ret) 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci clk_disable(i2c->clk); 77462306a36Sopenharmony_cierr_pclk: 77562306a36Sopenharmony_ci clk_disable(i2c->pclk); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return ret ?: num; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic u32 exynos5_i2c_func(struct i2c_adapter *adap) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic const struct i2c_algorithm exynos5_i2c_algorithm = { 78662306a36Sopenharmony_ci .master_xfer = exynos5_i2c_xfer, 78762306a36Sopenharmony_ci .functionality = exynos5_i2c_func, 78862306a36Sopenharmony_ci}; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic int exynos5_i2c_probe(struct platform_device *pdev) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 79362306a36Sopenharmony_ci struct exynos5_i2c *i2c; 79462306a36Sopenharmony_ci int ret; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL); 79762306a36Sopenharmony_ci if (!i2c) 79862306a36Sopenharmony_ci return -ENOMEM; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock)) 80162306a36Sopenharmony_ci i2c->op_clock = I2C_MAX_STANDARD_MODE_FREQ; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci strscpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name)); 80462306a36Sopenharmony_ci i2c->adap.owner = THIS_MODULE; 80562306a36Sopenharmony_ci i2c->adap.algo = &exynos5_i2c_algorithm; 80662306a36Sopenharmony_ci i2c->adap.retries = 3; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci i2c->dev = &pdev->dev; 80962306a36Sopenharmony_ci i2c->clk = devm_clk_get(&pdev->dev, "hsi2c"); 81062306a36Sopenharmony_ci if (IS_ERR(i2c->clk)) { 81162306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot get clock\n"); 81262306a36Sopenharmony_ci return -ENOENT; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci i2c->pclk = devm_clk_get_optional(&pdev->dev, "hsi2c_pclk"); 81662306a36Sopenharmony_ci if (IS_ERR(i2c->pclk)) { 81762306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), 81862306a36Sopenharmony_ci "cannot get pclk"); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci ret = clk_prepare_enable(i2c->pclk); 82262306a36Sopenharmony_ci if (ret) 82362306a36Sopenharmony_ci return ret; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci ret = clk_prepare_enable(i2c->clk); 82662306a36Sopenharmony_ci if (ret) 82762306a36Sopenharmony_ci goto err_pclk; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci i2c->regs = devm_platform_ioremap_resource(pdev, 0); 83062306a36Sopenharmony_ci if (IS_ERR(i2c->regs)) { 83162306a36Sopenharmony_ci ret = PTR_ERR(i2c->regs); 83262306a36Sopenharmony_ci goto err_clk; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci i2c->adap.dev.of_node = np; 83662306a36Sopenharmony_ci i2c->adap.algo_data = i2c; 83762306a36Sopenharmony_ci i2c->adap.dev.parent = &pdev->dev; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* Clear pending interrupts from u-boot or misc causes */ 84062306a36Sopenharmony_ci exynos5_i2c_clr_pend_irq(i2c); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci spin_lock_init(&i2c->lock); 84362306a36Sopenharmony_ci init_completion(&i2c->msg_complete); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci i2c->irq = ret = platform_get_irq(pdev, 0); 84662306a36Sopenharmony_ci if (ret < 0) 84762306a36Sopenharmony_ci goto err_clk; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq, 85062306a36Sopenharmony_ci IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c); 85162306a36Sopenharmony_ci if (ret != 0) { 85262306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", i2c->irq); 85362306a36Sopenharmony_ci goto err_clk; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci i2c->variant = of_device_get_match_data(&pdev->dev); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci ret = exynos5_hsi2c_clock_setup(i2c); 85962306a36Sopenharmony_ci if (ret) 86062306a36Sopenharmony_ci goto err_clk; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci exynos5_i2c_reset(i2c); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci ret = i2c_add_adapter(&i2c->adap); 86562306a36Sopenharmony_ci if (ret < 0) 86662306a36Sopenharmony_ci goto err_clk; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci platform_set_drvdata(pdev, i2c); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci clk_disable(i2c->clk); 87162306a36Sopenharmony_ci clk_disable(i2c->pclk); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci return 0; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci err_clk: 87662306a36Sopenharmony_ci clk_disable_unprepare(i2c->clk); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci err_pclk: 87962306a36Sopenharmony_ci clk_disable_unprepare(i2c->pclk); 88062306a36Sopenharmony_ci return ret; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic void exynos5_i2c_remove(struct platform_device *pdev) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct exynos5_i2c *i2c = platform_get_drvdata(pdev); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci i2c_del_adapter(&i2c->adap); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci clk_unprepare(i2c->clk); 89062306a36Sopenharmony_ci clk_unprepare(i2c->pclk); 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic int exynos5_i2c_suspend_noirq(struct device *dev) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct exynos5_i2c *i2c = dev_get_drvdata(dev); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci i2c_mark_adapter_suspended(&i2c->adap); 89862306a36Sopenharmony_ci clk_unprepare(i2c->clk); 89962306a36Sopenharmony_ci clk_unprepare(i2c->pclk); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci return 0; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistatic int exynos5_i2c_resume_noirq(struct device *dev) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct exynos5_i2c *i2c = dev_get_drvdata(dev); 90762306a36Sopenharmony_ci int ret = 0; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ret = clk_prepare_enable(i2c->pclk); 91062306a36Sopenharmony_ci if (ret) 91162306a36Sopenharmony_ci return ret; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci ret = clk_prepare_enable(i2c->clk); 91462306a36Sopenharmony_ci if (ret) 91562306a36Sopenharmony_ci goto err_pclk; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci ret = exynos5_hsi2c_clock_setup(i2c); 91862306a36Sopenharmony_ci if (ret) 91962306a36Sopenharmony_ci goto err_clk; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci exynos5_i2c_init(i2c); 92262306a36Sopenharmony_ci clk_disable(i2c->clk); 92362306a36Sopenharmony_ci clk_disable(i2c->pclk); 92462306a36Sopenharmony_ci i2c_mark_adapter_resumed(&i2c->adap); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cierr_clk: 92962306a36Sopenharmony_ci clk_disable_unprepare(i2c->clk); 93062306a36Sopenharmony_cierr_pclk: 93162306a36Sopenharmony_ci clk_disable_unprepare(i2c->pclk); 93262306a36Sopenharmony_ci return ret; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic const struct dev_pm_ops exynos5_i2c_dev_pm_ops = { 93662306a36Sopenharmony_ci NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq, 93762306a36Sopenharmony_ci exynos5_i2c_resume_noirq) 93862306a36Sopenharmony_ci}; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic struct platform_driver exynos5_i2c_driver = { 94162306a36Sopenharmony_ci .probe = exynos5_i2c_probe, 94262306a36Sopenharmony_ci .remove_new = exynos5_i2c_remove, 94362306a36Sopenharmony_ci .driver = { 94462306a36Sopenharmony_ci .name = "exynos5-hsi2c", 94562306a36Sopenharmony_ci .pm = pm_sleep_ptr(&exynos5_i2c_dev_pm_ops), 94662306a36Sopenharmony_ci .of_match_table = exynos5_i2c_match, 94762306a36Sopenharmony_ci }, 94862306a36Sopenharmony_ci}; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cimodule_platform_driver(exynos5_i2c_driver); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ciMODULE_DESCRIPTION("Exynos5 HS-I2C Bus driver"); 95362306a36Sopenharmony_ciMODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>"); 95462306a36Sopenharmony_ciMODULE_AUTHOR("Taekgyun Ko <taeggyun.ko@samsung.com>"); 95562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 956