18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * I2C adapter for the IMG Serial Control Bus (SCB) IP block. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009, 2010, 2012, 2014 Imagination Technologies Ltd. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * There are three ways that this I2C controller can be driven: 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * - Raw control of the SDA and SCK signals. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This corresponds to MODE_RAW, which takes control of the signals 128c2ecf20Sopenharmony_ci * directly for a certain number of clock cycles (the INT_TIMING 138c2ecf20Sopenharmony_ci * interrupt can be used for timing). 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * - Atomic commands. A low level I2C symbol (such as generate 168c2ecf20Sopenharmony_ci * start/stop/ack/nack bit, generate byte, receive byte, and receive 178c2ecf20Sopenharmony_ci * ACK) is given to the hardware, with detection of completion by bits 188c2ecf20Sopenharmony_ci * in the LINESTAT register. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * This mode of operation is used by MODE_ATOMIC, which uses an I2C 218c2ecf20Sopenharmony_ci * state machine in the interrupt handler to compose/react to I2C 228c2ecf20Sopenharmony_ci * transactions using atomic mode commands, and also by MODE_SEQUENCE, 238c2ecf20Sopenharmony_ci * which emits a simple fixed sequence of atomic mode commands. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Due to software control, the use of atomic commands usually results 268c2ecf20Sopenharmony_ci * in suboptimal use of the bus, with gaps between the I2C symbols while 278c2ecf20Sopenharmony_ci * the driver decides what to do next. 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * - Automatic mode. A bus address, and whether to read/write is 308c2ecf20Sopenharmony_ci * specified, and the hardware takes care of the I2C state machine, 318c2ecf20Sopenharmony_ci * using a FIFO to send/receive bytes of data to an I2C slave. The 328c2ecf20Sopenharmony_ci * driver just has to keep the FIFO drained or filled in response to the 338c2ecf20Sopenharmony_ci * appropriate FIFO interrupts. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * This corresponds to MODE_AUTOMATIC, which manages the FIFOs and deals 368c2ecf20Sopenharmony_ci * with control of repeated start bits between I2C messages. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Use of automatic mode and the FIFO can make much more efficient use 398c2ecf20Sopenharmony_ci * of the bus compared to individual atomic commands, with potentially 408c2ecf20Sopenharmony_ci * no wasted time between I2C symbols or I2C messages. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * In most cases MODE_AUTOMATIC is used, however if any of the messages in 438c2ecf20Sopenharmony_ci * a transaction are zero byte writes (e.g. used by i2cdetect for probing 448c2ecf20Sopenharmony_ci * the bus), MODE_ATOMIC must be used since automatic mode is normally 458c2ecf20Sopenharmony_ci * started by the writing of data into the FIFO. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * The other modes are used in specific circumstances where MODE_ATOMIC and 488c2ecf20Sopenharmony_ci * MODE_AUTOMATIC aren't appropriate. MODE_RAW is used to implement a bus 498c2ecf20Sopenharmony_ci * recovery routine. MODE_SEQUENCE is used to reset the bus and make sure 508c2ecf20Sopenharmony_ci * it is in a sane state. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * Notice that the driver implements a timer-based timeout mechanism. 538c2ecf20Sopenharmony_ci * The reason for this mechanism is to reduce the number of interrupts 548c2ecf20Sopenharmony_ci * received in automatic mode. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * The driver would get a slave event and transaction done interrupts for 578c2ecf20Sopenharmony_ci * each atomic mode command that gets completed. However, these events are 588c2ecf20Sopenharmony_ci * not needed in automatic mode, becase those atomic mode commands are 598c2ecf20Sopenharmony_ci * managed automatically by the hardware. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * In practice, normal I2C transactions will be complete well before you 628c2ecf20Sopenharmony_ci * get the timer interrupt, as the timer is re-scheduled during FIFO 638c2ecf20Sopenharmony_ci * maintenance and disabled after the transaction is complete. 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * In this way normal automatic mode operation isn't impacted by 668c2ecf20Sopenharmony_ci * unnecessary interrupts, but the exceptional abort condition can still be 678c2ecf20Sopenharmony_ci * detected (with a slight delay). 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#include <linux/bitops.h> 718c2ecf20Sopenharmony_ci#include <linux/clk.h> 728c2ecf20Sopenharmony_ci#include <linux/completion.h> 738c2ecf20Sopenharmony_ci#include <linux/err.h> 748c2ecf20Sopenharmony_ci#include <linux/i2c.h> 758c2ecf20Sopenharmony_ci#include <linux/init.h> 768c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 778c2ecf20Sopenharmony_ci#include <linux/io.h> 788c2ecf20Sopenharmony_ci#include <linux/kernel.h> 798c2ecf20Sopenharmony_ci#include <linux/module.h> 808c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 818c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 828c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 838c2ecf20Sopenharmony_ci#include <linux/slab.h> 848c2ecf20Sopenharmony_ci#include <linux/timer.h> 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Register offsets */ 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define SCB_STATUS_REG 0x00 898c2ecf20Sopenharmony_ci#define SCB_OVERRIDE_REG 0x04 908c2ecf20Sopenharmony_ci#define SCB_READ_ADDR_REG 0x08 918c2ecf20Sopenharmony_ci#define SCB_READ_COUNT_REG 0x0c 928c2ecf20Sopenharmony_ci#define SCB_WRITE_ADDR_REG 0x10 938c2ecf20Sopenharmony_ci#define SCB_READ_DATA_REG 0x14 948c2ecf20Sopenharmony_ci#define SCB_WRITE_DATA_REG 0x18 958c2ecf20Sopenharmony_ci#define SCB_FIFO_STATUS_REG 0x1c 968c2ecf20Sopenharmony_ci#define SCB_CONTROL_SOFT_RESET 0x1f 978c2ecf20Sopenharmony_ci#define SCB_CLK_SET_REG 0x3c 988c2ecf20Sopenharmony_ci#define SCB_INT_STATUS_REG 0x40 998c2ecf20Sopenharmony_ci#define SCB_INT_CLEAR_REG 0x44 1008c2ecf20Sopenharmony_ci#define SCB_INT_MASK_REG 0x48 1018c2ecf20Sopenharmony_ci#define SCB_CONTROL_REG 0x4c 1028c2ecf20Sopenharmony_ci#define SCB_TIME_TPL_REG 0x50 1038c2ecf20Sopenharmony_ci#define SCB_TIME_TPH_REG 0x54 1048c2ecf20Sopenharmony_ci#define SCB_TIME_TP2S_REG 0x58 1058c2ecf20Sopenharmony_ci#define SCB_TIME_TBI_REG 0x60 1068c2ecf20Sopenharmony_ci#define SCB_TIME_TSL_REG 0x64 1078c2ecf20Sopenharmony_ci#define SCB_TIME_TDL_REG 0x68 1088c2ecf20Sopenharmony_ci#define SCB_TIME_TSDL_REG 0x6c 1098c2ecf20Sopenharmony_ci#define SCB_TIME_TSDH_REG 0x70 1108c2ecf20Sopenharmony_ci#define SCB_READ_XADDR_REG 0x74 1118c2ecf20Sopenharmony_ci#define SCB_WRITE_XADDR_REG 0x78 1128c2ecf20Sopenharmony_ci#define SCB_WRITE_COUNT_REG 0x7c 1138c2ecf20Sopenharmony_ci#define SCB_CORE_REV_REG 0x80 1148c2ecf20Sopenharmony_ci#define SCB_TIME_TCKH_REG 0x84 1158c2ecf20Sopenharmony_ci#define SCB_TIME_TCKL_REG 0x88 1168c2ecf20Sopenharmony_ci#define SCB_FIFO_FLUSH_REG 0x8c 1178c2ecf20Sopenharmony_ci#define SCB_READ_FIFO_REG 0x94 1188c2ecf20Sopenharmony_ci#define SCB_CLEAR_REG 0x98 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* SCB_CONTROL_REG bits */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define SCB_CONTROL_CLK_ENABLE 0x1e0 1238c2ecf20Sopenharmony_ci#define SCB_CONTROL_TRANSACTION_HALT 0x200 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define FIFO_READ_FULL BIT(0) 1268c2ecf20Sopenharmony_ci#define FIFO_READ_EMPTY BIT(1) 1278c2ecf20Sopenharmony_ci#define FIFO_WRITE_FULL BIT(2) 1288c2ecf20Sopenharmony_ci#define FIFO_WRITE_EMPTY BIT(3) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* SCB_CLK_SET_REG bits */ 1318c2ecf20Sopenharmony_ci#define SCB_FILT_DISABLE BIT(31) 1328c2ecf20Sopenharmony_ci#define SCB_FILT_BYPASS BIT(30) 1338c2ecf20Sopenharmony_ci#define SCB_FILT_INC_MASK 0x7f 1348c2ecf20Sopenharmony_ci#define SCB_FILT_INC_SHIFT 16 1358c2ecf20Sopenharmony_ci#define SCB_INC_MASK 0x7f 1368c2ecf20Sopenharmony_ci#define SCB_INC_SHIFT 8 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* SCB_INT_*_REG bits */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#define INT_BUS_INACTIVE BIT(0) 1418c2ecf20Sopenharmony_ci#define INT_UNEXPECTED_START BIT(1) 1428c2ecf20Sopenharmony_ci#define INT_SCLK_LOW_TIMEOUT BIT(2) 1438c2ecf20Sopenharmony_ci#define INT_SDAT_LOW_TIMEOUT BIT(3) 1448c2ecf20Sopenharmony_ci#define INT_WRITE_ACK_ERR BIT(4) 1458c2ecf20Sopenharmony_ci#define INT_ADDR_ACK_ERR BIT(5) 1468c2ecf20Sopenharmony_ci#define INT_FIFO_FULL BIT(9) 1478c2ecf20Sopenharmony_ci#define INT_FIFO_FILLING BIT(10) 1488c2ecf20Sopenharmony_ci#define INT_FIFO_EMPTY BIT(11) 1498c2ecf20Sopenharmony_ci#define INT_FIFO_EMPTYING BIT(12) 1508c2ecf20Sopenharmony_ci#define INT_TRANSACTION_DONE BIT(15) 1518c2ecf20Sopenharmony_ci#define INT_SLAVE_EVENT BIT(16) 1528c2ecf20Sopenharmony_ci#define INT_MASTER_HALTED BIT(17) 1538c2ecf20Sopenharmony_ci#define INT_TIMING BIT(18) 1548c2ecf20Sopenharmony_ci#define INT_STOP_DETECTED BIT(19) 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#define INT_FIFO_FULL_FILLING (INT_FIFO_FULL | INT_FIFO_FILLING) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* Level interrupts need clearing after handling instead of before */ 1598c2ecf20Sopenharmony_ci#define INT_LEVEL 0x01e00 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* Don't allow any interrupts while the clock may be off */ 1628c2ecf20Sopenharmony_ci#define INT_ENABLE_MASK_INACTIVE 0x00000 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* Interrupt masks for the different driver modes */ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define INT_ENABLE_MASK_RAW INT_TIMING 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define INT_ENABLE_MASK_ATOMIC (INT_TRANSACTION_DONE | \ 1698c2ecf20Sopenharmony_ci INT_SLAVE_EVENT | \ 1708c2ecf20Sopenharmony_ci INT_ADDR_ACK_ERR | \ 1718c2ecf20Sopenharmony_ci INT_WRITE_ACK_ERR) 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define INT_ENABLE_MASK_AUTOMATIC (INT_SCLK_LOW_TIMEOUT | \ 1748c2ecf20Sopenharmony_ci INT_ADDR_ACK_ERR | \ 1758c2ecf20Sopenharmony_ci INT_WRITE_ACK_ERR | \ 1768c2ecf20Sopenharmony_ci INT_FIFO_FULL | \ 1778c2ecf20Sopenharmony_ci INT_FIFO_FILLING | \ 1788c2ecf20Sopenharmony_ci INT_FIFO_EMPTY | \ 1798c2ecf20Sopenharmony_ci INT_MASTER_HALTED | \ 1808c2ecf20Sopenharmony_ci INT_STOP_DETECTED) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define INT_ENABLE_MASK_WAITSTOP (INT_SLAVE_EVENT | \ 1838c2ecf20Sopenharmony_ci INT_ADDR_ACK_ERR | \ 1848c2ecf20Sopenharmony_ci INT_WRITE_ACK_ERR) 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* SCB_STATUS_REG fields */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define LINESTAT_SCLK_LINE_STATUS BIT(0) 1898c2ecf20Sopenharmony_ci#define LINESTAT_SCLK_EN BIT(1) 1908c2ecf20Sopenharmony_ci#define LINESTAT_SDAT_LINE_STATUS BIT(2) 1918c2ecf20Sopenharmony_ci#define LINESTAT_SDAT_EN BIT(3) 1928c2ecf20Sopenharmony_ci#define LINESTAT_DET_START_STATUS BIT(4) 1938c2ecf20Sopenharmony_ci#define LINESTAT_DET_STOP_STATUS BIT(5) 1948c2ecf20Sopenharmony_ci#define LINESTAT_DET_ACK_STATUS BIT(6) 1958c2ecf20Sopenharmony_ci#define LINESTAT_DET_NACK_STATUS BIT(7) 1968c2ecf20Sopenharmony_ci#define LINESTAT_BUS_IDLE BIT(8) 1978c2ecf20Sopenharmony_ci#define LINESTAT_T_DONE_STATUS BIT(9) 1988c2ecf20Sopenharmony_ci#define LINESTAT_SCLK_OUT_STATUS BIT(10) 1998c2ecf20Sopenharmony_ci#define LINESTAT_SDAT_OUT_STATUS BIT(11) 2008c2ecf20Sopenharmony_ci#define LINESTAT_GEN_LINE_MASK_STATUS BIT(12) 2018c2ecf20Sopenharmony_ci#define LINESTAT_START_BIT_DET BIT(13) 2028c2ecf20Sopenharmony_ci#define LINESTAT_STOP_BIT_DET BIT(14) 2038c2ecf20Sopenharmony_ci#define LINESTAT_ACK_DET BIT(15) 2048c2ecf20Sopenharmony_ci#define LINESTAT_NACK_DET BIT(16) 2058c2ecf20Sopenharmony_ci#define LINESTAT_INPUT_HELD_V BIT(17) 2068c2ecf20Sopenharmony_ci#define LINESTAT_ABORT_DET BIT(18) 2078c2ecf20Sopenharmony_ci#define LINESTAT_ACK_OR_NACK_DET (LINESTAT_ACK_DET | LINESTAT_NACK_DET) 2088c2ecf20Sopenharmony_ci#define LINESTAT_INPUT_DATA 0xff000000 2098c2ecf20Sopenharmony_ci#define LINESTAT_INPUT_DATA_SHIFT 24 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci#define LINESTAT_CLEAR_SHIFT 13 2128c2ecf20Sopenharmony_ci#define LINESTAT_LATCHED (0x3f << LINESTAT_CLEAR_SHIFT) 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* SCB_OVERRIDE_REG fields */ 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#define OVERRIDE_SCLK_OVR BIT(0) 2178c2ecf20Sopenharmony_ci#define OVERRIDE_SCLKEN_OVR BIT(1) 2188c2ecf20Sopenharmony_ci#define OVERRIDE_SDAT_OVR BIT(2) 2198c2ecf20Sopenharmony_ci#define OVERRIDE_SDATEN_OVR BIT(3) 2208c2ecf20Sopenharmony_ci#define OVERRIDE_MASTER BIT(9) 2218c2ecf20Sopenharmony_ci#define OVERRIDE_LINE_OVR_EN BIT(10) 2228c2ecf20Sopenharmony_ci#define OVERRIDE_DIRECT BIT(11) 2238c2ecf20Sopenharmony_ci#define OVERRIDE_CMD_SHIFT 4 2248c2ecf20Sopenharmony_ci#define OVERRIDE_CMD_MASK 0x1f 2258c2ecf20Sopenharmony_ci#define OVERRIDE_DATA_SHIFT 24 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#define OVERRIDE_SCLK_DOWN (OVERRIDE_LINE_OVR_EN | \ 2288c2ecf20Sopenharmony_ci OVERRIDE_SCLKEN_OVR) 2298c2ecf20Sopenharmony_ci#define OVERRIDE_SCLK_UP (OVERRIDE_LINE_OVR_EN | \ 2308c2ecf20Sopenharmony_ci OVERRIDE_SCLKEN_OVR | \ 2318c2ecf20Sopenharmony_ci OVERRIDE_SCLK_OVR) 2328c2ecf20Sopenharmony_ci#define OVERRIDE_SDAT_DOWN (OVERRIDE_LINE_OVR_EN | \ 2338c2ecf20Sopenharmony_ci OVERRIDE_SDATEN_OVR) 2348c2ecf20Sopenharmony_ci#define OVERRIDE_SDAT_UP (OVERRIDE_LINE_OVR_EN | \ 2358c2ecf20Sopenharmony_ci OVERRIDE_SDATEN_OVR | \ 2368c2ecf20Sopenharmony_ci OVERRIDE_SDAT_OVR) 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* OVERRIDE_CMD values */ 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define CMD_PAUSE 0x00 2418c2ecf20Sopenharmony_ci#define CMD_GEN_DATA 0x01 2428c2ecf20Sopenharmony_ci#define CMD_GEN_START 0x02 2438c2ecf20Sopenharmony_ci#define CMD_GEN_STOP 0x03 2448c2ecf20Sopenharmony_ci#define CMD_GEN_ACK 0x04 2458c2ecf20Sopenharmony_ci#define CMD_GEN_NACK 0x05 2468c2ecf20Sopenharmony_ci#define CMD_RET_DATA 0x08 2478c2ecf20Sopenharmony_ci#define CMD_RET_ACK 0x09 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* Fixed timing values */ 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#define TIMEOUT_TBI 0x0 2528c2ecf20Sopenharmony_ci#define TIMEOUT_TSL 0xffff 2538c2ecf20Sopenharmony_ci#define TIMEOUT_TDL 0x0 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* Transaction timeout */ 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define IMG_I2C_TIMEOUT (msecs_to_jiffies(1000)) 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/* 2608c2ecf20Sopenharmony_ci * Worst incs are 1 (innacurate) and 16*256 (irregular). 2618c2ecf20Sopenharmony_ci * So a sensible inc is the logarithmic mean: 64 (2^6), which is 2628c2ecf20Sopenharmony_ci * in the middle of the valid range (0-127). 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci#define SCB_OPT_INC 64 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* Setup the clock enable filtering for 25 ns */ 2678c2ecf20Sopenharmony_ci#define SCB_FILT_GLITCH 25 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* 2708c2ecf20Sopenharmony_ci * Bits to return from interrupt handler functions for different modes. 2718c2ecf20Sopenharmony_ci * This delays completion until we've finished with the registers, so that the 2728c2ecf20Sopenharmony_ci * function waiting for completion can safely disable the clock to save power. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci#define ISR_COMPLETE_M BIT(31) 2758c2ecf20Sopenharmony_ci#define ISR_FATAL_M BIT(30) 2768c2ecf20Sopenharmony_ci#define ISR_WAITSTOP BIT(29) 2778c2ecf20Sopenharmony_ci#define ISR_STATUS_M 0x0000ffff /* contains +ve errno */ 2788c2ecf20Sopenharmony_ci#define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err))) 2798c2ecf20Sopenharmony_ci#define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M) 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#define IMG_I2C_PM_TIMEOUT 1000 /* ms */ 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cienum img_i2c_mode { 2848c2ecf20Sopenharmony_ci MODE_INACTIVE, 2858c2ecf20Sopenharmony_ci MODE_RAW, 2868c2ecf20Sopenharmony_ci MODE_ATOMIC, 2878c2ecf20Sopenharmony_ci MODE_AUTOMATIC, 2888c2ecf20Sopenharmony_ci MODE_SEQUENCE, 2898c2ecf20Sopenharmony_ci MODE_FATAL, 2908c2ecf20Sopenharmony_ci MODE_WAITSTOP, 2918c2ecf20Sopenharmony_ci MODE_SUSPEND, 2928c2ecf20Sopenharmony_ci}; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/* Timing parameters for i2c modes (in ns) */ 2958c2ecf20Sopenharmony_cistruct img_i2c_timings { 2968c2ecf20Sopenharmony_ci const char *name; 2978c2ecf20Sopenharmony_ci unsigned int max_bitrate; 2988c2ecf20Sopenharmony_ci unsigned int tckh, tckl, tsdh, tsdl; 2998c2ecf20Sopenharmony_ci unsigned int tp2s, tpl, tph; 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/* The timings array must be ordered from slower to faster */ 3038c2ecf20Sopenharmony_cistatic struct img_i2c_timings timings[] = { 3048c2ecf20Sopenharmony_ci /* Standard mode */ 3058c2ecf20Sopenharmony_ci { 3068c2ecf20Sopenharmony_ci .name = "standard", 3078c2ecf20Sopenharmony_ci .max_bitrate = I2C_MAX_STANDARD_MODE_FREQ, 3088c2ecf20Sopenharmony_ci .tckh = 4000, 3098c2ecf20Sopenharmony_ci .tckl = 4700, 3108c2ecf20Sopenharmony_ci .tsdh = 4700, 3118c2ecf20Sopenharmony_ci .tsdl = 8700, 3128c2ecf20Sopenharmony_ci .tp2s = 4700, 3138c2ecf20Sopenharmony_ci .tpl = 4700, 3148c2ecf20Sopenharmony_ci .tph = 4000, 3158c2ecf20Sopenharmony_ci }, 3168c2ecf20Sopenharmony_ci /* Fast mode */ 3178c2ecf20Sopenharmony_ci { 3188c2ecf20Sopenharmony_ci .name = "fast", 3198c2ecf20Sopenharmony_ci .max_bitrate = I2C_MAX_FAST_MODE_FREQ, 3208c2ecf20Sopenharmony_ci .tckh = 600, 3218c2ecf20Sopenharmony_ci .tckl = 1300, 3228c2ecf20Sopenharmony_ci .tsdh = 600, 3238c2ecf20Sopenharmony_ci .tsdl = 1200, 3248c2ecf20Sopenharmony_ci .tp2s = 1300, 3258c2ecf20Sopenharmony_ci .tpl = 600, 3268c2ecf20Sopenharmony_ci .tph = 600, 3278c2ecf20Sopenharmony_ci }, 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/* Reset dance */ 3318c2ecf20Sopenharmony_cistatic u8 img_i2c_reset_seq[] = { CMD_GEN_START, 3328c2ecf20Sopenharmony_ci CMD_GEN_DATA, 0xff, 3338c2ecf20Sopenharmony_ci CMD_RET_ACK, 3348c2ecf20Sopenharmony_ci CMD_GEN_START, 3358c2ecf20Sopenharmony_ci CMD_GEN_STOP, 3368c2ecf20Sopenharmony_ci 0 }; 3378c2ecf20Sopenharmony_ci/* Just issue a stop (after an abort condition) */ 3388c2ecf20Sopenharmony_cistatic u8 img_i2c_stop_seq[] = { CMD_GEN_STOP, 3398c2ecf20Sopenharmony_ci 0 }; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/* We're interested in different interrupts depending on the mode */ 3428c2ecf20Sopenharmony_cistatic unsigned int img_i2c_int_enable_by_mode[] = { 3438c2ecf20Sopenharmony_ci [MODE_INACTIVE] = INT_ENABLE_MASK_INACTIVE, 3448c2ecf20Sopenharmony_ci [MODE_RAW] = INT_ENABLE_MASK_RAW, 3458c2ecf20Sopenharmony_ci [MODE_ATOMIC] = INT_ENABLE_MASK_ATOMIC, 3468c2ecf20Sopenharmony_ci [MODE_AUTOMATIC] = INT_ENABLE_MASK_AUTOMATIC, 3478c2ecf20Sopenharmony_ci [MODE_SEQUENCE] = INT_ENABLE_MASK_ATOMIC, 3488c2ecf20Sopenharmony_ci [MODE_FATAL] = 0, 3498c2ecf20Sopenharmony_ci [MODE_WAITSTOP] = INT_ENABLE_MASK_WAITSTOP, 3508c2ecf20Sopenharmony_ci [MODE_SUSPEND] = 0, 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* Atomic command names */ 3548c2ecf20Sopenharmony_cistatic const char * const img_i2c_atomic_cmd_names[] = { 3558c2ecf20Sopenharmony_ci [CMD_PAUSE] = "PAUSE", 3568c2ecf20Sopenharmony_ci [CMD_GEN_DATA] = "GEN_DATA", 3578c2ecf20Sopenharmony_ci [CMD_GEN_START] = "GEN_START", 3588c2ecf20Sopenharmony_ci [CMD_GEN_STOP] = "GEN_STOP", 3598c2ecf20Sopenharmony_ci [CMD_GEN_ACK] = "GEN_ACK", 3608c2ecf20Sopenharmony_ci [CMD_GEN_NACK] = "GEN_NACK", 3618c2ecf20Sopenharmony_ci [CMD_RET_DATA] = "RET_DATA", 3628c2ecf20Sopenharmony_ci [CMD_RET_ACK] = "RET_ACK", 3638c2ecf20Sopenharmony_ci}; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistruct img_i2c { 3668c2ecf20Sopenharmony_ci struct i2c_adapter adap; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci void __iomem *base; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* 3718c2ecf20Sopenharmony_ci * The scb core clock is used to get the input frequency, and to disable 3728c2ecf20Sopenharmony_ci * it after every set of transactions to save some power. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci struct clk *scb_clk, *sys_clk; 3758c2ecf20Sopenharmony_ci unsigned int bitrate; 3768c2ecf20Sopenharmony_ci bool need_wr_rd_fence; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* state */ 3798c2ecf20Sopenharmony_ci struct completion msg_complete; 3808c2ecf20Sopenharmony_ci spinlock_t lock; /* lock before doing anything with the state */ 3818c2ecf20Sopenharmony_ci struct i2c_msg msg; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* After the last transaction, wait for a stop bit */ 3848c2ecf20Sopenharmony_ci bool last_msg; 3858c2ecf20Sopenharmony_ci int msg_status; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci enum img_i2c_mode mode; 3888c2ecf20Sopenharmony_ci u32 int_enable; /* depends on mode */ 3898c2ecf20Sopenharmony_ci u32 line_status; /* line status over command */ 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci * To avoid slave event interrupts in automatic mode, use a timer to 3938c2ecf20Sopenharmony_ci * poll the abort condition if we don't get an interrupt for too long. 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ci struct timer_list check_timer; 3968c2ecf20Sopenharmony_ci bool t_halt; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* atomic mode state */ 3998c2ecf20Sopenharmony_ci bool at_t_done; 4008c2ecf20Sopenharmony_ci bool at_slave_event; 4018c2ecf20Sopenharmony_ci int at_cur_cmd; 4028c2ecf20Sopenharmony_ci u8 at_cur_data; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* Sequence: either reset or stop. See img_i2c_sequence. */ 4058c2ecf20Sopenharmony_ci u8 *seq; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* raw mode */ 4088c2ecf20Sopenharmony_ci unsigned int raw_timeout; 4098c2ecf20Sopenharmony_ci}; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int img_i2c_runtime_suspend(struct device *dev); 4128c2ecf20Sopenharmony_cistatic int img_i2c_runtime_resume(struct device *dev); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci writel(value, i2c->base + offset); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic u32 img_i2c_readl(struct img_i2c *i2c, u32 offset) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci return readl(i2c->base + offset); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci/* 4258c2ecf20Sopenharmony_ci * The code to read from the master read fifo, and write to the master 4268c2ecf20Sopenharmony_ci * write fifo, checks a bit in an SCB register before every byte to 4278c2ecf20Sopenharmony_ci * ensure that the fifo is not full (write fifo) or empty (read fifo). 4288c2ecf20Sopenharmony_ci * Due to clock domain crossing inside the SCB block the updated value 4298c2ecf20Sopenharmony_ci * of this bit is only visible after 2 cycles. 4308c2ecf20Sopenharmony_ci * 4318c2ecf20Sopenharmony_ci * The scb_wr_rd_fence() function does 2 dummy writes (to the read-only 4328c2ecf20Sopenharmony_ci * revision register), and it's called after reading from or writing to the 4338c2ecf20Sopenharmony_ci * fifos to ensure that subsequent reads of the fifo status bits do not read 4348c2ecf20Sopenharmony_ci * stale values. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_cistatic void img_i2c_wr_rd_fence(struct img_i2c *i2c) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci if (i2c->need_wr_rd_fence) { 4398c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CORE_REV_REG, 0); 4408c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CORE_REV_REG, 0); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic void img_i2c_switch_mode(struct img_i2c *i2c, enum img_i2c_mode mode) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci i2c->mode = mode; 4478c2ecf20Sopenharmony_ci i2c->int_enable = img_i2c_int_enable_by_mode[mode]; 4488c2ecf20Sopenharmony_ci i2c->line_status = 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic void img_i2c_raw_op(struct img_i2c *i2c) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci i2c->raw_timeout = 0; 4548c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_OVERRIDE_REG, 4558c2ecf20Sopenharmony_ci OVERRIDE_SCLKEN_OVR | 4568c2ecf20Sopenharmony_ci OVERRIDE_SDATEN_OVR | 4578c2ecf20Sopenharmony_ci OVERRIDE_MASTER | 4588c2ecf20Sopenharmony_ci OVERRIDE_LINE_OVR_EN | 4598c2ecf20Sopenharmony_ci OVERRIDE_DIRECT | 4608c2ecf20Sopenharmony_ci ((i2c->at_cur_cmd & OVERRIDE_CMD_MASK) << OVERRIDE_CMD_SHIFT) | 4618c2ecf20Sopenharmony_ci (i2c->at_cur_data << OVERRIDE_DATA_SHIFT)); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic const char *img_i2c_atomic_op_name(unsigned int cmd) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci if (unlikely(cmd >= ARRAY_SIZE(img_i2c_atomic_cmd_names))) 4678c2ecf20Sopenharmony_ci return "UNKNOWN"; 4688c2ecf20Sopenharmony_ci return img_i2c_atomic_cmd_names[cmd]; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* Send a single atomic mode command to the hardware */ 4728c2ecf20Sopenharmony_cistatic void img_i2c_atomic_op(struct img_i2c *i2c, int cmd, u8 data) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci i2c->at_cur_cmd = cmd; 4758c2ecf20Sopenharmony_ci i2c->at_cur_data = data; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* work around lack of data setup time when generating data */ 4788c2ecf20Sopenharmony_ci if (cmd == CMD_GEN_DATA && i2c->mode == MODE_ATOMIC) { 4798c2ecf20Sopenharmony_ci u32 line_status = img_i2c_readl(i2c, SCB_STATUS_REG); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (line_status & LINESTAT_SDAT_LINE_STATUS && !(data & 0x80)) { 4828c2ecf20Sopenharmony_ci /* hold the data line down for a moment */ 4838c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_RAW); 4848c2ecf20Sopenharmony_ci img_i2c_raw_op(i2c); 4858c2ecf20Sopenharmony_ci return; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci dev_dbg(i2c->adap.dev.parent, 4908c2ecf20Sopenharmony_ci "atomic cmd=%s (%d) data=%#x\n", 4918c2ecf20Sopenharmony_ci img_i2c_atomic_op_name(cmd), cmd, data); 4928c2ecf20Sopenharmony_ci i2c->at_t_done = (cmd == CMD_RET_DATA || cmd == CMD_RET_ACK); 4938c2ecf20Sopenharmony_ci i2c->at_slave_event = false; 4948c2ecf20Sopenharmony_ci i2c->line_status = 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_OVERRIDE_REG, 4978c2ecf20Sopenharmony_ci ((cmd & OVERRIDE_CMD_MASK) << OVERRIDE_CMD_SHIFT) | 4988c2ecf20Sopenharmony_ci OVERRIDE_MASTER | 4998c2ecf20Sopenharmony_ci OVERRIDE_DIRECT | 5008c2ecf20Sopenharmony_ci (data << OVERRIDE_DATA_SHIFT)); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* Start a transaction in atomic mode */ 5048c2ecf20Sopenharmony_cistatic void img_i2c_atomic_start(struct img_i2c *i2c) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_ATOMIC); 5078c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable); 5088c2ecf20Sopenharmony_ci img_i2c_atomic_op(i2c, CMD_GEN_START, 0x00); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic void img_i2c_soft_reset(struct img_i2c *i2c) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci i2c->t_halt = false; 5148c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CONTROL_REG, 0); 5158c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CONTROL_REG, 5168c2ecf20Sopenharmony_ci SCB_CONTROL_CLK_ENABLE | SCB_CONTROL_SOFT_RESET); 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/* 5208c2ecf20Sopenharmony_ci * Enable or release transaction halt for control of repeated starts. 5218c2ecf20Sopenharmony_ci * In version 3.3 of the IP when transaction halt is set, an interrupt 5228c2ecf20Sopenharmony_ci * will be generated after each byte of a transfer instead of after 5238c2ecf20Sopenharmony_ci * every transfer but before the stop bit. 5248c2ecf20Sopenharmony_ci * Due to this behaviour we have to be careful that every time we 5258c2ecf20Sopenharmony_ci * release the transaction halt we have to re-enable it straight away 5268c2ecf20Sopenharmony_ci * so that we only process a single byte, not doing so will result in 5278c2ecf20Sopenharmony_ci * all remaining bytes been processed and a stop bit being issued, 5288c2ecf20Sopenharmony_ci * which will prevent us having a repeated start. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_cistatic void img_i2c_transaction_halt(struct img_i2c *i2c, bool t_halt) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci u32 val; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (i2c->t_halt == t_halt) 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci i2c->t_halt = t_halt; 5378c2ecf20Sopenharmony_ci val = img_i2c_readl(i2c, SCB_CONTROL_REG); 5388c2ecf20Sopenharmony_ci if (t_halt) 5398c2ecf20Sopenharmony_ci val |= SCB_CONTROL_TRANSACTION_HALT; 5408c2ecf20Sopenharmony_ci else 5418c2ecf20Sopenharmony_ci val &= ~SCB_CONTROL_TRANSACTION_HALT; 5428c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CONTROL_REG, val); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/* Drain data from the FIFO into the buffer (automatic mode) */ 5468c2ecf20Sopenharmony_cistatic void img_i2c_read_fifo(struct img_i2c *i2c) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci while (i2c->msg.len) { 5498c2ecf20Sopenharmony_ci u32 fifo_status; 5508c2ecf20Sopenharmony_ci u8 data; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci img_i2c_wr_rd_fence(i2c); 5538c2ecf20Sopenharmony_ci fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG); 5548c2ecf20Sopenharmony_ci if (fifo_status & FIFO_READ_EMPTY) 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci data = img_i2c_readl(i2c, SCB_READ_DATA_REG); 5588c2ecf20Sopenharmony_ci *i2c->msg.buf = data; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_READ_FIFO_REG, 0xff); 5618c2ecf20Sopenharmony_ci i2c->msg.len--; 5628c2ecf20Sopenharmony_ci i2c->msg.buf++; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci/* Fill the FIFO with data from the buffer (automatic mode) */ 5678c2ecf20Sopenharmony_cistatic void img_i2c_write_fifo(struct img_i2c *i2c) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci while (i2c->msg.len) { 5708c2ecf20Sopenharmony_ci u32 fifo_status; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci img_i2c_wr_rd_fence(i2c); 5738c2ecf20Sopenharmony_ci fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG); 5748c2ecf20Sopenharmony_ci if (fifo_status & FIFO_WRITE_FULL) 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_WRITE_DATA_REG, *i2c->msg.buf); 5788c2ecf20Sopenharmony_ci i2c->msg.len--; 5798c2ecf20Sopenharmony_ci i2c->msg.buf++; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Disable fifo emptying interrupt if nothing more to write */ 5838c2ecf20Sopenharmony_ci if (!i2c->msg.len) 5848c2ecf20Sopenharmony_ci i2c->int_enable &= ~INT_FIFO_EMPTYING; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* Start a read transaction in automatic mode */ 5888c2ecf20Sopenharmony_cistatic void img_i2c_read(struct img_i2c *i2c) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_AUTOMATIC); 5918c2ecf20Sopenharmony_ci if (!i2c->last_msg) 5928c2ecf20Sopenharmony_ci i2c->int_enable |= INT_SLAVE_EVENT; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable); 5958c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_READ_ADDR_REG, i2c->msg.addr); 5968c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_READ_COUNT_REG, i2c->msg.len); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1)); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* Start a write transaction in automatic mode */ 6028c2ecf20Sopenharmony_cistatic void img_i2c_write(struct img_i2c *i2c) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_AUTOMATIC); 6058c2ecf20Sopenharmony_ci if (!i2c->last_msg) 6068c2ecf20Sopenharmony_ci i2c->int_enable |= INT_SLAVE_EVENT; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_WRITE_ADDR_REG, i2c->msg.addr); 6098c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_WRITE_COUNT_REG, i2c->msg.len); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1)); 6128c2ecf20Sopenharmony_ci img_i2c_write_fifo(i2c); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* img_i2c_write_fifo() may modify int_enable */ 6158c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* 6198c2ecf20Sopenharmony_ci * Indicate that the transaction is complete. This is called from the 6208c2ecf20Sopenharmony_ci * ISR to wake up the waiting thread, after which the ISR must not 6218c2ecf20Sopenharmony_ci * access any more SCB registers. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_cistatic void img_i2c_complete_transaction(struct img_i2c *i2c, int status) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_INACTIVE); 6268c2ecf20Sopenharmony_ci if (status) { 6278c2ecf20Sopenharmony_ci i2c->msg_status = status; 6288c2ecf20Sopenharmony_ci img_i2c_transaction_halt(i2c, false); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci complete(&i2c->msg_complete); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic unsigned int img_i2c_raw_atomic_delay_handler(struct img_i2c *i2c, 6348c2ecf20Sopenharmony_ci u32 int_status, u32 line_status) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci /* Stay in raw mode for this, so we don't just loop infinitely */ 6378c2ecf20Sopenharmony_ci img_i2c_atomic_op(i2c, i2c->at_cur_cmd, i2c->at_cur_data); 6388c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_ATOMIC); 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic unsigned int img_i2c_raw(struct img_i2c *i2c, u32 int_status, 6438c2ecf20Sopenharmony_ci u32 line_status) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci if (int_status & INT_TIMING) { 6468c2ecf20Sopenharmony_ci if (i2c->raw_timeout == 0) 6478c2ecf20Sopenharmony_ci return img_i2c_raw_atomic_delay_handler(i2c, 6488c2ecf20Sopenharmony_ci int_status, line_status); 6498c2ecf20Sopenharmony_ci --i2c->raw_timeout; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci return 0; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic unsigned int img_i2c_sequence(struct img_i2c *i2c, u32 int_status) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci static const unsigned int continue_bits[] = { 6578c2ecf20Sopenharmony_ci [CMD_GEN_START] = LINESTAT_START_BIT_DET, 6588c2ecf20Sopenharmony_ci [CMD_GEN_DATA] = LINESTAT_INPUT_HELD_V, 6598c2ecf20Sopenharmony_ci [CMD_RET_ACK] = LINESTAT_ACK_DET | LINESTAT_NACK_DET, 6608c2ecf20Sopenharmony_ci [CMD_RET_DATA] = LINESTAT_INPUT_HELD_V, 6618c2ecf20Sopenharmony_ci [CMD_GEN_STOP] = LINESTAT_STOP_BIT_DET, 6628c2ecf20Sopenharmony_ci }; 6638c2ecf20Sopenharmony_ci int next_cmd = -1; 6648c2ecf20Sopenharmony_ci u8 next_data = 0x00; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (int_status & INT_SLAVE_EVENT) 6678c2ecf20Sopenharmony_ci i2c->at_slave_event = true; 6688c2ecf20Sopenharmony_ci if (int_status & INT_TRANSACTION_DONE) 6698c2ecf20Sopenharmony_ci i2c->at_t_done = true; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (!i2c->at_slave_event || !i2c->at_t_done) 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* wait if no continue bits are set */ 6758c2ecf20Sopenharmony_ci if (i2c->at_cur_cmd >= 0 && 6768c2ecf20Sopenharmony_ci i2c->at_cur_cmd < ARRAY_SIZE(continue_bits)) { 6778c2ecf20Sopenharmony_ci unsigned int cont_bits = continue_bits[i2c->at_cur_cmd]; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (cont_bits) { 6808c2ecf20Sopenharmony_ci cont_bits |= LINESTAT_ABORT_DET; 6818c2ecf20Sopenharmony_ci if (!(i2c->line_status & cont_bits)) 6828c2ecf20Sopenharmony_ci return 0; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* follow the sequence of commands in i2c->seq */ 6878c2ecf20Sopenharmony_ci next_cmd = *i2c->seq; 6888c2ecf20Sopenharmony_ci /* stop on a nil */ 6898c2ecf20Sopenharmony_ci if (!next_cmd) { 6908c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_OVERRIDE_REG, 0); 6918c2ecf20Sopenharmony_ci return ISR_COMPLETE(0); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci /* when generating data, the next byte is the data */ 6948c2ecf20Sopenharmony_ci if (next_cmd == CMD_GEN_DATA) { 6958c2ecf20Sopenharmony_ci ++i2c->seq; 6968c2ecf20Sopenharmony_ci next_data = *i2c->seq; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci ++i2c->seq; 6998c2ecf20Sopenharmony_ci img_i2c_atomic_op(i2c, next_cmd, next_data); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci return 0; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void img_i2c_reset_start(struct img_i2c *i2c) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci /* Initiate the magic dance */ 7078c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_SEQUENCE); 7088c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable); 7098c2ecf20Sopenharmony_ci i2c->seq = img_i2c_reset_seq; 7108c2ecf20Sopenharmony_ci i2c->at_slave_event = true; 7118c2ecf20Sopenharmony_ci i2c->at_t_done = true; 7128c2ecf20Sopenharmony_ci i2c->at_cur_cmd = -1; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* img_i2c_reset_seq isn't empty so the following won't fail */ 7158c2ecf20Sopenharmony_ci img_i2c_sequence(i2c, 0); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic void img_i2c_stop_start(struct img_i2c *i2c) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci /* Initiate a stop bit sequence */ 7218c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_SEQUENCE); 7228c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable); 7238c2ecf20Sopenharmony_ci i2c->seq = img_i2c_stop_seq; 7248c2ecf20Sopenharmony_ci i2c->at_slave_event = true; 7258c2ecf20Sopenharmony_ci i2c->at_t_done = true; 7268c2ecf20Sopenharmony_ci i2c->at_cur_cmd = -1; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* img_i2c_stop_seq isn't empty so the following won't fail */ 7298c2ecf20Sopenharmony_ci img_i2c_sequence(i2c, 0); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic unsigned int img_i2c_atomic(struct img_i2c *i2c, 7338c2ecf20Sopenharmony_ci u32 int_status, 7348c2ecf20Sopenharmony_ci u32 line_status) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci int next_cmd = -1; 7378c2ecf20Sopenharmony_ci u8 next_data = 0x00; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (int_status & INT_SLAVE_EVENT) 7408c2ecf20Sopenharmony_ci i2c->at_slave_event = true; 7418c2ecf20Sopenharmony_ci if (int_status & INT_TRANSACTION_DONE) 7428c2ecf20Sopenharmony_ci i2c->at_t_done = true; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (!i2c->at_slave_event || !i2c->at_t_done) 7458c2ecf20Sopenharmony_ci goto next_atomic_cmd; 7468c2ecf20Sopenharmony_ci if (i2c->line_status & LINESTAT_ABORT_DET) { 7478c2ecf20Sopenharmony_ci dev_dbg(i2c->adap.dev.parent, "abort condition detected\n"); 7488c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_STOP; 7498c2ecf20Sopenharmony_ci i2c->msg_status = -EIO; 7508c2ecf20Sopenharmony_ci goto next_atomic_cmd; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* i2c->at_cur_cmd may have completed */ 7548c2ecf20Sopenharmony_ci switch (i2c->at_cur_cmd) { 7558c2ecf20Sopenharmony_ci case CMD_GEN_START: 7568c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_DATA; 7578c2ecf20Sopenharmony_ci next_data = i2c_8bit_addr_from_msg(&i2c->msg); 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci case CMD_GEN_DATA: 7608c2ecf20Sopenharmony_ci if (i2c->line_status & LINESTAT_INPUT_HELD_V) 7618c2ecf20Sopenharmony_ci next_cmd = CMD_RET_ACK; 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci case CMD_RET_ACK: 7648c2ecf20Sopenharmony_ci if (i2c->line_status & LINESTAT_ACK_DET || 7658c2ecf20Sopenharmony_ci (i2c->line_status & LINESTAT_NACK_DET && 7668c2ecf20Sopenharmony_ci i2c->msg.flags & I2C_M_IGNORE_NAK)) { 7678c2ecf20Sopenharmony_ci if (i2c->msg.len == 0) { 7688c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_STOP; 7698c2ecf20Sopenharmony_ci } else if (i2c->msg.flags & I2C_M_RD) { 7708c2ecf20Sopenharmony_ci next_cmd = CMD_RET_DATA; 7718c2ecf20Sopenharmony_ci } else { 7728c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_DATA; 7738c2ecf20Sopenharmony_ci next_data = *i2c->msg.buf; 7748c2ecf20Sopenharmony_ci --i2c->msg.len; 7758c2ecf20Sopenharmony_ci ++i2c->msg.buf; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci } else if (i2c->line_status & LINESTAT_NACK_DET) { 7788c2ecf20Sopenharmony_ci i2c->msg_status = -EIO; 7798c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_STOP; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci case CMD_RET_DATA: 7838c2ecf20Sopenharmony_ci if (i2c->line_status & LINESTAT_INPUT_HELD_V) { 7848c2ecf20Sopenharmony_ci *i2c->msg.buf = (i2c->line_status & 7858c2ecf20Sopenharmony_ci LINESTAT_INPUT_DATA) 7868c2ecf20Sopenharmony_ci >> LINESTAT_INPUT_DATA_SHIFT; 7878c2ecf20Sopenharmony_ci --i2c->msg.len; 7888c2ecf20Sopenharmony_ci ++i2c->msg.buf; 7898c2ecf20Sopenharmony_ci if (i2c->msg.len) 7908c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_ACK; 7918c2ecf20Sopenharmony_ci else 7928c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_NACK; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci case CMD_GEN_ACK: 7968c2ecf20Sopenharmony_ci if (i2c->line_status & LINESTAT_ACK_DET) { 7978c2ecf20Sopenharmony_ci next_cmd = CMD_RET_DATA; 7988c2ecf20Sopenharmony_ci } else { 7998c2ecf20Sopenharmony_ci i2c->msg_status = -EIO; 8008c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_STOP; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci case CMD_GEN_NACK: 8048c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_STOP; 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci case CMD_GEN_STOP: 8078c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_OVERRIDE_REG, 0); 8088c2ecf20Sopenharmony_ci return ISR_COMPLETE(0); 8098c2ecf20Sopenharmony_ci default: 8108c2ecf20Sopenharmony_ci dev_err(i2c->adap.dev.parent, "bad atomic command %d\n", 8118c2ecf20Sopenharmony_ci i2c->at_cur_cmd); 8128c2ecf20Sopenharmony_ci i2c->msg_status = -EIO; 8138c2ecf20Sopenharmony_ci next_cmd = CMD_GEN_STOP; 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cinext_atomic_cmd: 8188c2ecf20Sopenharmony_ci if (next_cmd != -1) { 8198c2ecf20Sopenharmony_ci /* don't actually stop unless we're the last transaction */ 8208c2ecf20Sopenharmony_ci if (next_cmd == CMD_GEN_STOP && !i2c->msg_status && 8218c2ecf20Sopenharmony_ci !i2c->last_msg) 8228c2ecf20Sopenharmony_ci return ISR_COMPLETE(0); 8238c2ecf20Sopenharmony_ci img_i2c_atomic_op(i2c, next_cmd, next_data); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci return 0; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci/* 8298c2ecf20Sopenharmony_ci * Timer function to check if something has gone wrong in automatic mode (so we 8308c2ecf20Sopenharmony_ci * don't have to handle so many interrupts just to catch an exception). 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_cistatic void img_i2c_check_timer(struct timer_list *t) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct img_i2c *i2c = from_timer(i2c, t, check_timer); 8358c2ecf20Sopenharmony_ci unsigned long flags; 8368c2ecf20Sopenharmony_ci unsigned int line_status; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 8398c2ecf20Sopenharmony_ci line_status = img_i2c_readl(i2c, SCB_STATUS_REG); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* check for an abort condition */ 8428c2ecf20Sopenharmony_ci if (line_status & LINESTAT_ABORT_DET) { 8438c2ecf20Sopenharmony_ci dev_dbg(i2c->adap.dev.parent, 8448c2ecf20Sopenharmony_ci "abort condition detected by check timer\n"); 8458c2ecf20Sopenharmony_ci /* enable slave event interrupt mask to trigger irq */ 8468c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, 8478c2ecf20Sopenharmony_ci i2c->int_enable | INT_SLAVE_EVENT); 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic unsigned int img_i2c_auto(struct img_i2c *i2c, 8548c2ecf20Sopenharmony_ci unsigned int int_status, 8558c2ecf20Sopenharmony_ci unsigned int line_status) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci if (int_status & (INT_WRITE_ACK_ERR | INT_ADDR_ACK_ERR)) 8588c2ecf20Sopenharmony_ci return ISR_COMPLETE(EIO); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (line_status & LINESTAT_ABORT_DET) { 8618c2ecf20Sopenharmony_ci dev_dbg(i2c->adap.dev.parent, "abort condition detected\n"); 8628c2ecf20Sopenharmony_ci /* empty the read fifo */ 8638c2ecf20Sopenharmony_ci if ((i2c->msg.flags & I2C_M_RD) && 8648c2ecf20Sopenharmony_ci (int_status & INT_FIFO_FULL_FILLING)) 8658c2ecf20Sopenharmony_ci img_i2c_read_fifo(i2c); 8668c2ecf20Sopenharmony_ci /* use atomic mode and try to force a stop bit */ 8678c2ecf20Sopenharmony_ci i2c->msg_status = -EIO; 8688c2ecf20Sopenharmony_ci img_i2c_stop_start(i2c); 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* Enable transaction halt on start bit */ 8738c2ecf20Sopenharmony_ci if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) { 8748c2ecf20Sopenharmony_ci img_i2c_transaction_halt(i2c, !i2c->last_msg); 8758c2ecf20Sopenharmony_ci /* we're no longer interested in the slave event */ 8768c2ecf20Sopenharmony_ci i2c->int_enable &= ~INT_SLAVE_EVENT; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1)); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (int_status & INT_STOP_DETECTED) { 8828c2ecf20Sopenharmony_ci /* Drain remaining data in FIFO and complete transaction */ 8838c2ecf20Sopenharmony_ci if (i2c->msg.flags & I2C_M_RD) 8848c2ecf20Sopenharmony_ci img_i2c_read_fifo(i2c); 8858c2ecf20Sopenharmony_ci return ISR_COMPLETE(0); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (i2c->msg.flags & I2C_M_RD) { 8898c2ecf20Sopenharmony_ci if (int_status & (INT_FIFO_FULL_FILLING | INT_MASTER_HALTED)) { 8908c2ecf20Sopenharmony_ci img_i2c_read_fifo(i2c); 8918c2ecf20Sopenharmony_ci if (i2c->msg.len == 0) 8928c2ecf20Sopenharmony_ci return ISR_WAITSTOP; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci } else { 8958c2ecf20Sopenharmony_ci if (int_status & (INT_FIFO_EMPTY | INT_MASTER_HALTED)) { 8968c2ecf20Sopenharmony_ci if ((int_status & INT_FIFO_EMPTY) && 8978c2ecf20Sopenharmony_ci i2c->msg.len == 0) 8988c2ecf20Sopenharmony_ci return ISR_WAITSTOP; 8998c2ecf20Sopenharmony_ci img_i2c_write_fifo(i2c); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci if (int_status & INT_MASTER_HALTED) { 9038c2ecf20Sopenharmony_ci /* 9048c2ecf20Sopenharmony_ci * Release and then enable transaction halt, to 9058c2ecf20Sopenharmony_ci * allow only a single byte to proceed. 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_ci img_i2c_transaction_halt(i2c, false); 9088c2ecf20Sopenharmony_ci img_i2c_transaction_halt(i2c, !i2c->last_msg); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return 0; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic irqreturn_t img_i2c_isr(int irq, void *dev_id) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci struct img_i2c *i2c = (struct img_i2c *)dev_id; 9178c2ecf20Sopenharmony_ci u32 int_status, line_status; 9188c2ecf20Sopenharmony_ci /* We handle transaction completion AFTER accessing registers */ 9198c2ecf20Sopenharmony_ci unsigned int hret; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* Read interrupt status register. */ 9228c2ecf20Sopenharmony_ci int_status = img_i2c_readl(i2c, SCB_INT_STATUS_REG); 9238c2ecf20Sopenharmony_ci /* Clear detected interrupts. */ 9248c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_CLEAR_REG, int_status); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* 9278c2ecf20Sopenharmony_ci * Read line status and clear it until it actually is clear. We have 9288c2ecf20Sopenharmony_ci * to be careful not to lose any line status bits that get latched. 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci line_status = img_i2c_readl(i2c, SCB_STATUS_REG); 9318c2ecf20Sopenharmony_ci if (line_status & LINESTAT_LATCHED) { 9328c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CLEAR_REG, 9338c2ecf20Sopenharmony_ci (line_status & LINESTAT_LATCHED) 9348c2ecf20Sopenharmony_ci >> LINESTAT_CLEAR_SHIFT); 9358c2ecf20Sopenharmony_ci img_i2c_wr_rd_fence(i2c); 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci spin_lock(&i2c->lock); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* Keep track of line status bits received */ 9418c2ecf20Sopenharmony_ci i2c->line_status &= ~LINESTAT_INPUT_DATA; 9428c2ecf20Sopenharmony_ci i2c->line_status |= line_status; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* 9458c2ecf20Sopenharmony_ci * Certain interrupts indicate that sclk low timeout is not 9468c2ecf20Sopenharmony_ci * a problem. If any of these are set, just continue. 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_ci if ((int_status & INT_SCLK_LOW_TIMEOUT) && 9498c2ecf20Sopenharmony_ci !(int_status & (INT_SLAVE_EVENT | 9508c2ecf20Sopenharmony_ci INT_FIFO_EMPTY | 9518c2ecf20Sopenharmony_ci INT_FIFO_FULL))) { 9528c2ecf20Sopenharmony_ci dev_crit(i2c->adap.dev.parent, 9538c2ecf20Sopenharmony_ci "fatal: clock low timeout occurred %s addr 0x%02x\n", 9548c2ecf20Sopenharmony_ci (i2c->msg.flags & I2C_M_RD) ? "reading" : "writing", 9558c2ecf20Sopenharmony_ci i2c->msg.addr); 9568c2ecf20Sopenharmony_ci hret = ISR_FATAL(EIO); 9578c2ecf20Sopenharmony_ci goto out; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (i2c->mode == MODE_ATOMIC) 9618c2ecf20Sopenharmony_ci hret = img_i2c_atomic(i2c, int_status, line_status); 9628c2ecf20Sopenharmony_ci else if (i2c->mode == MODE_AUTOMATIC) 9638c2ecf20Sopenharmony_ci hret = img_i2c_auto(i2c, int_status, line_status); 9648c2ecf20Sopenharmony_ci else if (i2c->mode == MODE_SEQUENCE) 9658c2ecf20Sopenharmony_ci hret = img_i2c_sequence(i2c, int_status); 9668c2ecf20Sopenharmony_ci else if (i2c->mode == MODE_WAITSTOP && (int_status & INT_SLAVE_EVENT) && 9678c2ecf20Sopenharmony_ci (line_status & LINESTAT_STOP_BIT_DET)) 9688c2ecf20Sopenharmony_ci hret = ISR_COMPLETE(0); 9698c2ecf20Sopenharmony_ci else if (i2c->mode == MODE_RAW) 9708c2ecf20Sopenharmony_ci hret = img_i2c_raw(i2c, int_status, line_status); 9718c2ecf20Sopenharmony_ci else 9728c2ecf20Sopenharmony_ci hret = 0; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Clear detected level interrupts. */ 9758c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_CLEAR_REG, int_status & INT_LEVEL); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ciout: 9788c2ecf20Sopenharmony_ci if (hret & ISR_WAITSTOP) { 9798c2ecf20Sopenharmony_ci /* 9808c2ecf20Sopenharmony_ci * Only wait for stop on last message. 9818c2ecf20Sopenharmony_ci * Also we may already have detected the stop bit. 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_ci if (!i2c->last_msg || i2c->line_status & LINESTAT_STOP_BIT_DET) 9848c2ecf20Sopenharmony_ci hret = ISR_COMPLETE(0); 9858c2ecf20Sopenharmony_ci else 9868c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_WAITSTOP); 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci /* now we've finished using regs, handle transaction completion */ 9908c2ecf20Sopenharmony_ci if (hret & ISR_COMPLETE_M) { 9918c2ecf20Sopenharmony_ci int status = -(hret & ISR_STATUS_M); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci img_i2c_complete_transaction(i2c, status); 9948c2ecf20Sopenharmony_ci if (hret & ISR_FATAL_M) 9958c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_FATAL); 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* Enable interrupts (int_enable may be altered by changing mode) */ 9998c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci spin_unlock(&i2c->lock); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci/* Force a bus reset sequence and wait for it to complete */ 10078c2ecf20Sopenharmony_cistatic int img_i2c_reset_bus(struct img_i2c *i2c) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci unsigned long flags; 10108c2ecf20Sopenharmony_ci unsigned long time_left; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 10138c2ecf20Sopenharmony_ci reinit_completion(&i2c->msg_complete); 10148c2ecf20Sopenharmony_ci img_i2c_reset_start(i2c); 10158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&i2c->msg_complete, 10188c2ecf20Sopenharmony_ci IMG_I2C_TIMEOUT); 10198c2ecf20Sopenharmony_ci if (time_left == 0) 10208c2ecf20Sopenharmony_ci return -ETIMEDOUT; 10218c2ecf20Sopenharmony_ci return 0; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 10258c2ecf20Sopenharmony_ci int num) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci struct img_i2c *i2c = i2c_get_adapdata(adap); 10288c2ecf20Sopenharmony_ci bool atomic = false; 10298c2ecf20Sopenharmony_ci int i, ret; 10308c2ecf20Sopenharmony_ci unsigned long time_left; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (i2c->mode == MODE_SUSPEND) { 10338c2ecf20Sopenharmony_ci WARN(1, "refusing to service transaction in suspended state\n"); 10348c2ecf20Sopenharmony_ci return -EIO; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (i2c->mode == MODE_FATAL) 10388c2ecf20Sopenharmony_ci return -EIO; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 10418c2ecf20Sopenharmony_ci /* 10428c2ecf20Sopenharmony_ci * 0 byte reads are not possible because the slave could try 10438c2ecf20Sopenharmony_ci * and pull the data line low, preventing a stop bit. 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_ci if (!msgs[i].len && msgs[i].flags & I2C_M_RD) 10468c2ecf20Sopenharmony_ci return -EIO; 10478c2ecf20Sopenharmony_ci /* 10488c2ecf20Sopenharmony_ci * 0 byte writes are possible and used for probing, but we 10498c2ecf20Sopenharmony_ci * cannot do them in automatic mode, so use atomic mode 10508c2ecf20Sopenharmony_ci * instead. 10518c2ecf20Sopenharmony_ci * 10528c2ecf20Sopenharmony_ci * Also, the I2C_M_IGNORE_NAK mode can only be implemented 10538c2ecf20Sopenharmony_ci * in atomic mode. 10548c2ecf20Sopenharmony_ci */ 10558c2ecf20Sopenharmony_ci if (!msgs[i].len || 10568c2ecf20Sopenharmony_ci (msgs[i].flags & I2C_M_IGNORE_NAK)) 10578c2ecf20Sopenharmony_ci atomic = true; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(adap->dev.parent); 10618c2ecf20Sopenharmony_ci if (ret < 0) 10628c2ecf20Sopenharmony_ci return ret; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 10658c2ecf20Sopenharmony_ci struct i2c_msg *msg = &msgs[i]; 10668c2ecf20Sopenharmony_ci unsigned long flags; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* 10718c2ecf20Sopenharmony_ci * Make a copy of the message struct. We mustn't modify the 10728c2ecf20Sopenharmony_ci * original or we'll confuse drivers and i2c-dev. 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci i2c->msg = *msg; 10758c2ecf20Sopenharmony_ci i2c->msg_status = 0; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* 10788c2ecf20Sopenharmony_ci * After the last message we must have waited for a stop bit. 10798c2ecf20Sopenharmony_ci * Not waiting can cause problems when the clock is disabled 10808c2ecf20Sopenharmony_ci * before the stop bit is sent, and the linux I2C interface 10818c2ecf20Sopenharmony_ci * requires separate transfers not to joined with repeated 10828c2ecf20Sopenharmony_ci * start. 10838c2ecf20Sopenharmony_ci */ 10848c2ecf20Sopenharmony_ci i2c->last_msg = (i == num - 1); 10858c2ecf20Sopenharmony_ci reinit_completion(&i2c->msg_complete); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* 10888c2ecf20Sopenharmony_ci * Clear line status and all interrupts before starting a 10898c2ecf20Sopenharmony_ci * transfer, as we may have unserviced interrupts from 10908c2ecf20Sopenharmony_ci * previous transfers that might be handled in the context 10918c2ecf20Sopenharmony_ci * of the new transfer. 10928c2ecf20Sopenharmony_ci */ 10938c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0); 10948c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CLEAR_REG, ~0); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (atomic) { 10978c2ecf20Sopenharmony_ci img_i2c_atomic_start(i2c); 10988c2ecf20Sopenharmony_ci } else { 10998c2ecf20Sopenharmony_ci /* 11008c2ecf20Sopenharmony_ci * Enable transaction halt if not the last message in 11018c2ecf20Sopenharmony_ci * the queue so that we can control repeated starts. 11028c2ecf20Sopenharmony_ci */ 11038c2ecf20Sopenharmony_ci img_i2c_transaction_halt(i2c, !i2c->last_msg); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_RD) 11068c2ecf20Sopenharmony_ci img_i2c_read(i2c); 11078c2ecf20Sopenharmony_ci else 11088c2ecf20Sopenharmony_ci img_i2c_write(i2c); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* 11118c2ecf20Sopenharmony_ci * Release and then enable transaction halt, to 11128c2ecf20Sopenharmony_ci * allow only a single byte to proceed. 11138c2ecf20Sopenharmony_ci * This doesn't have an effect on the initial transfer 11148c2ecf20Sopenharmony_ci * but will allow the following transfers to start 11158c2ecf20Sopenharmony_ci * processing if the previous transfer was marked as 11168c2ecf20Sopenharmony_ci * complete while the i2c block was halted. 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_ci img_i2c_transaction_halt(i2c, false); 11198c2ecf20Sopenharmony_ci img_i2c_transaction_halt(i2c, !i2c->last_msg); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&i2c->msg_complete, 11248c2ecf20Sopenharmony_ci IMG_I2C_TIMEOUT); 11258c2ecf20Sopenharmony_ci del_timer_sync(&i2c->check_timer); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci if (time_left == 0) { 11288c2ecf20Sopenharmony_ci dev_err(adap->dev.parent, "i2c transfer timed out\n"); 11298c2ecf20Sopenharmony_ci i2c->msg_status = -ETIMEDOUT; 11308c2ecf20Sopenharmony_ci break; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (i2c->msg_status) 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(adap->dev.parent); 11388c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(adap->dev.parent); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci return i2c->msg_status ? i2c->msg_status : num; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic u32 img_i2c_func(struct i2c_adapter *adap) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 11468c2ecf20Sopenharmony_ci} 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_cistatic const struct i2c_algorithm img_i2c_algo = { 11498c2ecf20Sopenharmony_ci .master_xfer = img_i2c_xfer, 11508c2ecf20Sopenharmony_ci .functionality = img_i2c_func, 11518c2ecf20Sopenharmony_ci}; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic int img_i2c_init(struct img_i2c *i2c) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh; 11568c2ecf20Sopenharmony_ci unsigned int i, data, prescale, inc, int_bitrate, filt; 11578c2ecf20Sopenharmony_ci struct img_i2c_timings timing; 11588c2ecf20Sopenharmony_ci u32 rev; 11598c2ecf20Sopenharmony_ci int ret; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(i2c->adap.dev.parent); 11628c2ecf20Sopenharmony_ci if (ret < 0) 11638c2ecf20Sopenharmony_ci return ret; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci rev = img_i2c_readl(i2c, SCB_CORE_REV_REG); 11668c2ecf20Sopenharmony_ci if ((rev & 0x00ffffff) < 0x00020200) { 11678c2ecf20Sopenharmony_ci dev_info(i2c->adap.dev.parent, 11688c2ecf20Sopenharmony_ci "Unknown hardware revision (%d.%d.%d.%d)\n", 11698c2ecf20Sopenharmony_ci (rev >> 24) & 0xff, (rev >> 16) & 0xff, 11708c2ecf20Sopenharmony_ci (rev >> 8) & 0xff, rev & 0xff); 11718c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(i2c->adap.dev.parent); 11728c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(i2c->adap.dev.parent); 11738c2ecf20Sopenharmony_ci return -EINVAL; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* Fencing enabled by default. */ 11778c2ecf20Sopenharmony_ci i2c->need_wr_rd_fence = true; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Determine what mode we're in from the bitrate */ 11808c2ecf20Sopenharmony_ci timing = timings[0]; 11818c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(timings); i++) { 11828c2ecf20Sopenharmony_ci if (i2c->bitrate <= timings[i].max_bitrate) { 11838c2ecf20Sopenharmony_ci timing = timings[i]; 11848c2ecf20Sopenharmony_ci break; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci if (i2c->bitrate > timings[ARRAY_SIZE(timings) - 1].max_bitrate) { 11888c2ecf20Sopenharmony_ci dev_warn(i2c->adap.dev.parent, 11898c2ecf20Sopenharmony_ci "requested bitrate (%u) is higher than the max bitrate supported (%u)\n", 11908c2ecf20Sopenharmony_ci i2c->bitrate, 11918c2ecf20Sopenharmony_ci timings[ARRAY_SIZE(timings) - 1].max_bitrate); 11928c2ecf20Sopenharmony_ci timing = timings[ARRAY_SIZE(timings) - 1]; 11938c2ecf20Sopenharmony_ci i2c->bitrate = timing.max_bitrate; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci bitrate_khz = i2c->bitrate / 1000; 11978c2ecf20Sopenharmony_ci clk_khz = clk_get_rate(i2c->scb_clk) / 1000; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Find the prescale that would give us that inc (approx delay = 0) */ 12008c2ecf20Sopenharmony_ci prescale = SCB_OPT_INC * clk_khz / (256 * 16 * bitrate_khz); 12018c2ecf20Sopenharmony_ci prescale = clamp_t(unsigned int, prescale, 1, 8); 12028c2ecf20Sopenharmony_ci clk_khz /= prescale; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* Setup the clock increment value */ 12058c2ecf20Sopenharmony_ci inc = (256 * 16 * bitrate_khz) / clk_khz; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci /* 12088c2ecf20Sopenharmony_ci * The clock generation logic allows to filter glitches on the bus. 12098c2ecf20Sopenharmony_ci * This filter is able to remove bus glitches shorter than 50ns. 12108c2ecf20Sopenharmony_ci * If the clock enable rate is greater than 20 MHz, no filtering 12118c2ecf20Sopenharmony_ci * is required, so we need to disable it. 12128c2ecf20Sopenharmony_ci * If it's between the 20-40 MHz range, there's no need to divide 12138c2ecf20Sopenharmony_ci * the clock to get a filter. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_ci if (clk_khz < 20000) { 12168c2ecf20Sopenharmony_ci filt = SCB_FILT_DISABLE; 12178c2ecf20Sopenharmony_ci } else if (clk_khz < 40000) { 12188c2ecf20Sopenharmony_ci filt = SCB_FILT_BYPASS; 12198c2ecf20Sopenharmony_ci } else { 12208c2ecf20Sopenharmony_ci /* Calculate filter clock */ 12218c2ecf20Sopenharmony_ci filt = (64000 / ((clk_khz / 1000) * SCB_FILT_GLITCH)); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci /* Scale up if needed */ 12248c2ecf20Sopenharmony_ci if (64000 % ((clk_khz / 1000) * SCB_FILT_GLITCH)) 12258c2ecf20Sopenharmony_ci inc++; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (filt > SCB_FILT_INC_MASK) 12288c2ecf20Sopenharmony_ci filt = SCB_FILT_INC_MASK; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci filt = (filt & SCB_FILT_INC_MASK) << SCB_FILT_INC_SHIFT; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci data = filt | ((inc & SCB_INC_MASK) << SCB_INC_SHIFT) | (prescale - 1); 12338c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CLK_SET_REG, data); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* Obtain the clock period of the fx16 clock in ns */ 12368c2ecf20Sopenharmony_ci clk_period = (256 * 1000000) / (clk_khz * inc); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* Calculate the bitrate in terms of internal clock pulses */ 12398c2ecf20Sopenharmony_ci int_bitrate = 1000000 / (bitrate_khz * clk_period); 12408c2ecf20Sopenharmony_ci if ((1000000 % (bitrate_khz * clk_period)) >= 12418c2ecf20Sopenharmony_ci ((bitrate_khz * clk_period) / 2)) 12428c2ecf20Sopenharmony_ci int_bitrate++; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* 12458c2ecf20Sopenharmony_ci * Setup clock duty cycle, start with 50% and adjust TCKH and TCKL 12468c2ecf20Sopenharmony_ci * values from there if they don't meet minimum timing requirements 12478c2ecf20Sopenharmony_ci */ 12488c2ecf20Sopenharmony_ci tckh = int_bitrate / 2; 12498c2ecf20Sopenharmony_ci tckl = int_bitrate - tckh; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* Adjust TCKH and TCKL values */ 12528c2ecf20Sopenharmony_ci data = DIV_ROUND_UP(timing.tckl, clk_period); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (tckl < data) { 12558c2ecf20Sopenharmony_ci tckl = data; 12568c2ecf20Sopenharmony_ci tckh = int_bitrate - tckl; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (tckh > 0) 12608c2ecf20Sopenharmony_ci --tckh; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (tckl > 0) 12638c2ecf20Sopenharmony_ci --tckl; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TCKH_REG, tckh); 12668c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TCKL_REG, tckl); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* Setup TSDH value */ 12698c2ecf20Sopenharmony_ci tsdh = DIV_ROUND_UP(timing.tsdh, clk_period); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci if (tsdh > 1) 12728c2ecf20Sopenharmony_ci data = tsdh - 1; 12738c2ecf20Sopenharmony_ci else 12748c2ecf20Sopenharmony_ci data = 0x01; 12758c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TSDH_REG, data); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci /* This value is used later */ 12788c2ecf20Sopenharmony_ci tsdh = data; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci /* Setup TPL value */ 12818c2ecf20Sopenharmony_ci data = timing.tpl / clk_period; 12828c2ecf20Sopenharmony_ci if (data > 0) 12838c2ecf20Sopenharmony_ci --data; 12848c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TPL_REG, data); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* Setup TPH value */ 12878c2ecf20Sopenharmony_ci data = timing.tph / clk_period; 12888c2ecf20Sopenharmony_ci if (data > 0) 12898c2ecf20Sopenharmony_ci --data; 12908c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TPH_REG, data); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* Setup TSDL value to TPL + TSDH + 2 */ 12938c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TSDL_REG, data + tsdh + 2); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* Setup TP2S value */ 12968c2ecf20Sopenharmony_ci data = timing.tp2s / clk_period; 12978c2ecf20Sopenharmony_ci if (data > 0) 12988c2ecf20Sopenharmony_ci --data; 12998c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TP2S_REG, data); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TBI_REG, TIMEOUT_TBI); 13028c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TSL_REG, TIMEOUT_TSL); 13038c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_TIME_TDL_REG, TIMEOUT_TDL); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* Take module out of soft reset and enable clocks */ 13068c2ecf20Sopenharmony_ci img_i2c_soft_reset(i2c); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* Disable all interrupts */ 13098c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, 0); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* Clear all interrupts */ 13128c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* Clear the scb_line_status events */ 13158c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_CLEAR_REG, ~0); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* Enable interrupts */ 13188c2ecf20Sopenharmony_ci img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* Perform a synchronous sequence to reset the bus */ 13218c2ecf20Sopenharmony_ci ret = img_i2c_reset_bus(i2c); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(i2c->adap.dev.parent); 13248c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(i2c->adap.dev.parent); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci return ret; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic int img_i2c_probe(struct platform_device *pdev) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 13328c2ecf20Sopenharmony_ci struct img_i2c *i2c; 13338c2ecf20Sopenharmony_ci int irq, ret; 13348c2ecf20Sopenharmony_ci u32 val; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci i2c = devm_kzalloc(&pdev->dev, sizeof(struct img_i2c), GFP_KERNEL); 13378c2ecf20Sopenharmony_ci if (!i2c) 13388c2ecf20Sopenharmony_ci return -ENOMEM; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci i2c->base = devm_platform_ioremap_resource(pdev, 0); 13418c2ecf20Sopenharmony_ci if (IS_ERR(i2c->base)) 13428c2ecf20Sopenharmony_ci return PTR_ERR(i2c->base); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 13458c2ecf20Sopenharmony_ci if (irq < 0) 13468c2ecf20Sopenharmony_ci return irq; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci i2c->sys_clk = devm_clk_get(&pdev->dev, "sys"); 13498c2ecf20Sopenharmony_ci if (IS_ERR(i2c->sys_clk)) { 13508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't get system clock\n"); 13518c2ecf20Sopenharmony_ci return PTR_ERR(i2c->sys_clk); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci i2c->scb_clk = devm_clk_get(&pdev->dev, "scb"); 13558c2ecf20Sopenharmony_ci if (IS_ERR(i2c->scb_clk)) { 13568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't get core clock\n"); 13578c2ecf20Sopenharmony_ci return PTR_ERR(i2c->scb_clk); 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, img_i2c_isr, 0, 13618c2ecf20Sopenharmony_ci pdev->name, i2c); 13628c2ecf20Sopenharmony_ci if (ret) { 13638c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't request irq %d\n", irq); 13648c2ecf20Sopenharmony_ci return ret; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci /* Set up the exception check timer */ 13688c2ecf20Sopenharmony_ci timer_setup(&i2c->check_timer, img_i2c_check_timer, 0); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci i2c->bitrate = timings[0].max_bitrate; 13718c2ecf20Sopenharmony_ci if (!of_property_read_u32(node, "clock-frequency", &val)) 13728c2ecf20Sopenharmony_ci i2c->bitrate = val; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci i2c_set_adapdata(&i2c->adap, i2c); 13758c2ecf20Sopenharmony_ci i2c->adap.dev.parent = &pdev->dev; 13768c2ecf20Sopenharmony_ci i2c->adap.dev.of_node = node; 13778c2ecf20Sopenharmony_ci i2c->adap.owner = THIS_MODULE; 13788c2ecf20Sopenharmony_ci i2c->adap.algo = &img_i2c_algo; 13798c2ecf20Sopenharmony_ci i2c->adap.retries = 5; 13808c2ecf20Sopenharmony_ci i2c->adap.nr = pdev->id; 13818c2ecf20Sopenharmony_ci snprintf(i2c->adap.name, sizeof(i2c->adap.name), "IMG SCB I2C"); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_INACTIVE); 13848c2ecf20Sopenharmony_ci spin_lock_init(&i2c->lock); 13858c2ecf20Sopenharmony_ci init_completion(&i2c->msg_complete); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, i2c); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_I2C_PM_TIMEOUT); 13908c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 13918c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 13928c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) { 13938c2ecf20Sopenharmony_ci ret = img_i2c_runtime_resume(&pdev->dev); 13948c2ecf20Sopenharmony_ci if (ret) 13958c2ecf20Sopenharmony_ci return ret; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci ret = img_i2c_init(i2c); 13998c2ecf20Sopenharmony_ci if (ret) 14008c2ecf20Sopenharmony_ci goto rpm_disable; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci ret = i2c_add_numbered_adapter(&i2c->adap); 14038c2ecf20Sopenharmony_ci if (ret < 0) 14048c2ecf20Sopenharmony_ci goto rpm_disable; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci return 0; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cirpm_disable: 14098c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) 14108c2ecf20Sopenharmony_ci img_i2c_runtime_suspend(&pdev->dev); 14118c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 14128c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 14138c2ecf20Sopenharmony_ci return ret; 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic int img_i2c_remove(struct platform_device *dev) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct img_i2c *i2c = platform_get_drvdata(dev); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci i2c_del_adapter(&i2c->adap); 14218c2ecf20Sopenharmony_ci pm_runtime_disable(&dev->dev); 14228c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(&dev->dev)) 14238c2ecf20Sopenharmony_ci img_i2c_runtime_suspend(&dev->dev); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci return 0; 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cistatic int img_i2c_runtime_suspend(struct device *dev) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct img_i2c *i2c = dev_get_drvdata(dev); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->scb_clk); 14338c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->sys_clk); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return 0; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic int img_i2c_runtime_resume(struct device *dev) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci struct img_i2c *i2c = dev_get_drvdata(dev); 14418c2ecf20Sopenharmony_ci int ret; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2c->sys_clk); 14448c2ecf20Sopenharmony_ci if (ret) { 14458c2ecf20Sopenharmony_ci dev_err(dev, "Unable to enable sys clock\n"); 14468c2ecf20Sopenharmony_ci return ret; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2c->scb_clk); 14508c2ecf20Sopenharmony_ci if (ret) { 14518c2ecf20Sopenharmony_ci dev_err(dev, "Unable to enable scb clock\n"); 14528c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->sys_clk); 14538c2ecf20Sopenharmony_ci return ret; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci return 0; 14578c2ecf20Sopenharmony_ci} 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 14608c2ecf20Sopenharmony_cistatic int img_i2c_suspend(struct device *dev) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci struct img_i2c *i2c = dev_get_drvdata(dev); 14638c2ecf20Sopenharmony_ci int ret; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 14668c2ecf20Sopenharmony_ci if (ret) 14678c2ecf20Sopenharmony_ci return ret; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci img_i2c_switch_mode(i2c, MODE_SUSPEND); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci return 0; 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic int img_i2c_resume(struct device *dev) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci struct img_i2c *i2c = dev_get_drvdata(dev); 14778c2ecf20Sopenharmony_ci int ret; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci ret = pm_runtime_force_resume(dev); 14808c2ecf20Sopenharmony_ci if (ret) 14818c2ecf20Sopenharmony_ci return ret; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci img_i2c_init(i2c); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci return 0; 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic const struct dev_pm_ops img_i2c_pm = { 14908c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend, 14918c2ecf20Sopenharmony_ci img_i2c_runtime_resume, 14928c2ecf20Sopenharmony_ci NULL) 14938c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) 14948c2ecf20Sopenharmony_ci}; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic const struct of_device_id img_scb_i2c_match[] = { 14978c2ecf20Sopenharmony_ci { .compatible = "img,scb-i2c" }, 14988c2ecf20Sopenharmony_ci { } 14998c2ecf20Sopenharmony_ci}; 15008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, img_scb_i2c_match); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cistatic struct platform_driver img_scb_i2c_driver = { 15038c2ecf20Sopenharmony_ci .driver = { 15048c2ecf20Sopenharmony_ci .name = "img-i2c-scb", 15058c2ecf20Sopenharmony_ci .of_match_table = img_scb_i2c_match, 15068c2ecf20Sopenharmony_ci .pm = &img_i2c_pm, 15078c2ecf20Sopenharmony_ci }, 15088c2ecf20Sopenharmony_ci .probe = img_i2c_probe, 15098c2ecf20Sopenharmony_ci .remove = img_i2c_remove, 15108c2ecf20Sopenharmony_ci}; 15118c2ecf20Sopenharmony_cimodule_platform_driver(img_scb_i2c_driver); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ciMODULE_AUTHOR("James Hogan <jhogan@kernel.org>"); 15148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IMG host I2C driver"); 15158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1516