18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Nuvoton NPCM7xx I2C Controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Nuvoton Technologies tali.perry@nuvoton.com 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 148c2ecf20Sopenharmony_ci#include <linux/irq.h> 158c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/of.h> 208c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 218c2ecf20Sopenharmony_ci#include <linux/regmap.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cienum i2c_mode { 248c2ecf20Sopenharmony_ci I2C_MASTER, 258c2ecf20Sopenharmony_ci I2C_SLAVE, 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * External I2C Interface driver xfer indication values, which indicate status 308c2ecf20Sopenharmony_ci * of the bus. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cienum i2c_state_ind { 338c2ecf20Sopenharmony_ci I2C_NO_STATUS_IND = 0, 348c2ecf20Sopenharmony_ci I2C_SLAVE_RCV_IND, 358c2ecf20Sopenharmony_ci I2C_SLAVE_XMIT_IND, 368c2ecf20Sopenharmony_ci I2C_SLAVE_XMIT_MISSING_DATA_IND, 378c2ecf20Sopenharmony_ci I2C_SLAVE_RESTART_IND, 388c2ecf20Sopenharmony_ci I2C_SLAVE_DONE_IND, 398c2ecf20Sopenharmony_ci I2C_MASTER_DONE_IND, 408c2ecf20Sopenharmony_ci I2C_NACK_IND, 418c2ecf20Sopenharmony_ci I2C_BUS_ERR_IND, 428c2ecf20Sopenharmony_ci I2C_WAKE_UP_IND, 438c2ecf20Sopenharmony_ci I2C_BLOCK_BYTES_ERR_IND, 448c2ecf20Sopenharmony_ci I2C_SLAVE_RCV_MISSING_DATA_IND, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Operation type values (used to define the operation currently running) 498c2ecf20Sopenharmony_ci * module is interrupt driven, on each interrupt the current operation is 508c2ecf20Sopenharmony_ci * checked to see if the module is currently reading or writing. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cienum i2c_oper { 538c2ecf20Sopenharmony_ci I2C_NO_OPER = 0, 548c2ecf20Sopenharmony_ci I2C_WRITE_OPER, 558c2ecf20Sopenharmony_ci I2C_READ_OPER, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* I2C Bank (module had 2 banks of registers) */ 598c2ecf20Sopenharmony_cienum i2c_bank { 608c2ecf20Sopenharmony_ci I2C_BANK_0 = 0, 618c2ecf20Sopenharmony_ci I2C_BANK_1, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Internal I2C states values (for the I2C module state machine). */ 658c2ecf20Sopenharmony_cienum i2c_state { 668c2ecf20Sopenharmony_ci I2C_DISABLE = 0, 678c2ecf20Sopenharmony_ci I2C_IDLE, 688c2ecf20Sopenharmony_ci I2C_MASTER_START, 698c2ecf20Sopenharmony_ci I2C_SLAVE_MATCH, 708c2ecf20Sopenharmony_ci I2C_OPER_STARTED, 718c2ecf20Sopenharmony_ci I2C_STOP_PENDING, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 758c2ecf20Sopenharmony_ci/* Module supports setting multiple own slave addresses */ 768c2ecf20Sopenharmony_cienum i2c_addr { 778c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR1 = 0, 788c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR2, 798c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR3, 808c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR4, 818c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR5, 828c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR6, 838c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR7, 848c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR8, 858c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR9, 868c2ecf20Sopenharmony_ci I2C_SLAVE_ADDR10, 878c2ecf20Sopenharmony_ci I2C_GC_ADDR, 888c2ecf20Sopenharmony_ci I2C_ARP_ADDR, 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci#endif 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* init register and default value required to enable module */ 938c2ecf20Sopenharmony_ci#define NPCM_I2CSEGCTL 0xE4 948c2ecf20Sopenharmony_ci#define NPCM_I2CSEGCTL_INIT_VAL 0x0333F000 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Common regs */ 978c2ecf20Sopenharmony_ci#define NPCM_I2CSDA 0x00 988c2ecf20Sopenharmony_ci#define NPCM_I2CST 0x02 998c2ecf20Sopenharmony_ci#define NPCM_I2CCST 0x04 1008c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1 0x06 1018c2ecf20Sopenharmony_ci#define NPCM_I2CADDR1 0x08 1028c2ecf20Sopenharmony_ci#define NPCM_I2CCTL2 0x0A 1038c2ecf20Sopenharmony_ci#define NPCM_I2CADDR2 0x0C 1048c2ecf20Sopenharmony_ci#define NPCM_I2CCTL3 0x0E 1058c2ecf20Sopenharmony_ci#define NPCM_I2CCST2 0x18 1068c2ecf20Sopenharmony_ci#define NPCM_I2CCST3 0x19 1078c2ecf20Sopenharmony_ci#define I2C_VER 0x1F 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/*BANK0 regs*/ 1108c2ecf20Sopenharmony_ci#define NPCM_I2CADDR3 0x10 1118c2ecf20Sopenharmony_ci#define NPCM_I2CADDR7 0x11 1128c2ecf20Sopenharmony_ci#define NPCM_I2CADDR4 0x12 1138c2ecf20Sopenharmony_ci#define NPCM_I2CADDR8 0x13 1148c2ecf20Sopenharmony_ci#define NPCM_I2CADDR5 0x14 1158c2ecf20Sopenharmony_ci#define NPCM_I2CADDR9 0x15 1168c2ecf20Sopenharmony_ci#define NPCM_I2CADDR6 0x16 1178c2ecf20Sopenharmony_ci#define NPCM_I2CADDR10 0x17 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 1208c2ecf20Sopenharmony_ci/* 1218c2ecf20Sopenharmony_ci * npcm_i2caddr array: 1228c2ecf20Sopenharmony_ci * The module supports having multiple own slave addresses. 1238c2ecf20Sopenharmony_ci * Since the addr regs are sprinkled all over the address space, 1248c2ecf20Sopenharmony_ci * use this array to get the address or each register. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci#define I2C_NUM_OWN_ADDR 2 1278c2ecf20Sopenharmony_ci#define I2C_NUM_OWN_ADDR_SUPPORTED 2 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { 1308c2ecf20Sopenharmony_ci NPCM_I2CADDR1, NPCM_I2CADDR2, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci#endif 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define NPCM_I2CCTL4 0x1A 1358c2ecf20Sopenharmony_ci#define NPCM_I2CCTL5 0x1B 1368c2ecf20Sopenharmony_ci#define NPCM_I2CSCLLT 0x1C /* SCL Low Time */ 1378c2ecf20Sopenharmony_ci#define NPCM_I2CFIF_CTL 0x1D /* FIFO Control */ 1388c2ecf20Sopenharmony_ci#define NPCM_I2CSCLHT 0x1E /* SCL High Time */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* BANK 1 regs */ 1418c2ecf20Sopenharmony_ci#define NPCM_I2CFIF_CTS 0x10 /* Both FIFOs Control and Status */ 1428c2ecf20Sopenharmony_ci#define NPCM_I2CTXF_CTL 0x12 /* Tx-FIFO Control */ 1438c2ecf20Sopenharmony_ci#define NPCM_I2CT_OUT 0x14 /* Bus T.O. */ 1448c2ecf20Sopenharmony_ci#define NPCM_I2CPEC 0x16 /* PEC Data */ 1458c2ecf20Sopenharmony_ci#define NPCM_I2CTXF_STS 0x1A /* Tx-FIFO Status */ 1468c2ecf20Sopenharmony_ci#define NPCM_I2CRXF_STS 0x1C /* Rx-FIFO Status */ 1478c2ecf20Sopenharmony_ci#define NPCM_I2CRXF_CTL 0x1E /* Rx-FIFO Control */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/* NPCM_I2CST reg fields */ 1508c2ecf20Sopenharmony_ci#define NPCM_I2CST_XMIT BIT(0) 1518c2ecf20Sopenharmony_ci#define NPCM_I2CST_MASTER BIT(1) 1528c2ecf20Sopenharmony_ci#define NPCM_I2CST_NMATCH BIT(2) 1538c2ecf20Sopenharmony_ci#define NPCM_I2CST_STASTR BIT(3) 1548c2ecf20Sopenharmony_ci#define NPCM_I2CST_NEGACK BIT(4) 1558c2ecf20Sopenharmony_ci#define NPCM_I2CST_BER BIT(5) 1568c2ecf20Sopenharmony_ci#define NPCM_I2CST_SDAST BIT(6) 1578c2ecf20Sopenharmony_ci#define NPCM_I2CST_SLVSTP BIT(7) 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* NPCM_I2CCST reg fields */ 1608c2ecf20Sopenharmony_ci#define NPCM_I2CCST_BUSY BIT(0) 1618c2ecf20Sopenharmony_ci#define NPCM_I2CCST_BB BIT(1) 1628c2ecf20Sopenharmony_ci#define NPCM_I2CCST_MATCH BIT(2) 1638c2ecf20Sopenharmony_ci#define NPCM_I2CCST_GCMATCH BIT(3) 1648c2ecf20Sopenharmony_ci#define NPCM_I2CCST_TSDA BIT(4) 1658c2ecf20Sopenharmony_ci#define NPCM_I2CCST_TGSCL BIT(5) 1668c2ecf20Sopenharmony_ci#define NPCM_I2CCST_MATCHAF BIT(6) 1678c2ecf20Sopenharmony_ci#define NPCM_I2CCST_ARPMATCH BIT(7) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* NPCM_I2CCTL1 reg fields */ 1708c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_START BIT(0) 1718c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_STOP BIT(1) 1728c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_INTEN BIT(2) 1738c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_EOBINTE BIT(3) 1748c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_ACK BIT(4) 1758c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_GCMEN BIT(5) 1768c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_NMINTE BIT(6) 1778c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_STASTRE BIT(7) 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* RW1S fields (inside a RW reg): */ 1808c2ecf20Sopenharmony_ci#define NPCM_I2CCTL1_RWS \ 1818c2ecf20Sopenharmony_ci (NPCM_I2CCTL1_START | NPCM_I2CCTL1_STOP | NPCM_I2CCTL1_ACK) 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* npcm_i2caddr reg fields */ 1848c2ecf20Sopenharmony_ci#define NPCM_I2CADDR_A GENMASK(6, 0) 1858c2ecf20Sopenharmony_ci#define NPCM_I2CADDR_SAEN BIT(7) 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* NPCM_I2CCTL2 reg fields */ 1888c2ecf20Sopenharmony_ci#define I2CCTL2_ENABLE BIT(0) 1898c2ecf20Sopenharmony_ci#define I2CCTL2_SCLFRQ6_0 GENMASK(7, 1) 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* NPCM_I2CCTL3 reg fields */ 1928c2ecf20Sopenharmony_ci#define I2CCTL3_SCLFRQ8_7 GENMASK(1, 0) 1938c2ecf20Sopenharmony_ci#define I2CCTL3_ARPMEN BIT(2) 1948c2ecf20Sopenharmony_ci#define I2CCTL3_IDL_START BIT(3) 1958c2ecf20Sopenharmony_ci#define I2CCTL3_400K_MODE BIT(4) 1968c2ecf20Sopenharmony_ci#define I2CCTL3_BNK_SEL BIT(5) 1978c2ecf20Sopenharmony_ci#define I2CCTL3_SDA_LVL BIT(6) 1988c2ecf20Sopenharmony_ci#define I2CCTL3_SCL_LVL BIT(7) 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci/* NPCM_I2CCST2 reg fields */ 2018c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_MATCHA1F BIT(0) 2028c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_MATCHA2F BIT(1) 2038c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_MATCHA3F BIT(2) 2048c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_MATCHA4F BIT(3) 2058c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_MATCHA5F BIT(4) 2068c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_MATCHA6F BIT(5) 2078c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_MATCHA7F BIT(5) 2088c2ecf20Sopenharmony_ci#define NPCM_I2CCST2_INTSTS BIT(7) 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* NPCM_I2CCST3 reg fields */ 2118c2ecf20Sopenharmony_ci#define NPCM_I2CCST3_MATCHA8F BIT(0) 2128c2ecf20Sopenharmony_ci#define NPCM_I2CCST3_MATCHA9F BIT(1) 2138c2ecf20Sopenharmony_ci#define NPCM_I2CCST3_MATCHA10F BIT(2) 2148c2ecf20Sopenharmony_ci#define NPCM_I2CCST3_EO_BUSY BIT(7) 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* NPCM_I2CCTL4 reg fields */ 2178c2ecf20Sopenharmony_ci#define I2CCTL4_HLDT GENMASK(5, 0) 2188c2ecf20Sopenharmony_ci#define I2CCTL4_LVL_WE BIT(7) 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* NPCM_I2CCTL5 reg fields */ 2218c2ecf20Sopenharmony_ci#define I2CCTL5_DBNCT GENMASK(3, 0) 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* NPCM_I2CFIF_CTS reg fields */ 2248c2ecf20Sopenharmony_ci#define NPCM_I2CFIF_CTS_RXF_TXE BIT(1) 2258c2ecf20Sopenharmony_ci#define NPCM_I2CFIF_CTS_RFTE_IE BIT(3) 2268c2ecf20Sopenharmony_ci#define NPCM_I2CFIF_CTS_CLR_FIFO BIT(6) 2278c2ecf20Sopenharmony_ci#define NPCM_I2CFIF_CTS_SLVRSTR BIT(7) 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* NPCM_I2CTXF_CTL reg fields */ 2308c2ecf20Sopenharmony_ci#define NPCM_I2CTXF_CTL_TX_THR GENMASK(4, 0) 2318c2ecf20Sopenharmony_ci#define NPCM_I2CTXF_CTL_THR_TXIE BIT(6) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/* NPCM_I2CT_OUT reg fields */ 2348c2ecf20Sopenharmony_ci#define NPCM_I2CT_OUT_TO_CKDIV GENMASK(5, 0) 2358c2ecf20Sopenharmony_ci#define NPCM_I2CT_OUT_T_OUTIE BIT(6) 2368c2ecf20Sopenharmony_ci#define NPCM_I2CT_OUT_T_OUTST BIT(7) 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* NPCM_I2CTXF_STS reg fields */ 2398c2ecf20Sopenharmony_ci#define NPCM_I2CTXF_STS_TX_BYTES GENMASK(4, 0) 2408c2ecf20Sopenharmony_ci#define NPCM_I2CTXF_STS_TX_THST BIT(6) 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* NPCM_I2CRXF_STS reg fields */ 2438c2ecf20Sopenharmony_ci#define NPCM_I2CRXF_STS_RX_BYTES GENMASK(4, 0) 2448c2ecf20Sopenharmony_ci#define NPCM_I2CRXF_STS_RX_THST BIT(6) 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* NPCM_I2CFIF_CTL reg fields */ 2478c2ecf20Sopenharmony_ci#define NPCM_I2CFIF_CTL_FIFO_EN BIT(4) 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* NPCM_I2CRXF_CTL reg fields */ 2508c2ecf20Sopenharmony_ci#define NPCM_I2CRXF_CTL_RX_THR GENMASK(4, 0) 2518c2ecf20Sopenharmony_ci#define NPCM_I2CRXF_CTL_LAST_PEC BIT(5) 2528c2ecf20Sopenharmony_ci#define NPCM_I2CRXF_CTL_THR_RXIE BIT(6) 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#define I2C_HW_FIFO_SIZE 16 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* I2C_VER reg fields */ 2578c2ecf20Sopenharmony_ci#define I2C_VER_VERSION GENMASK(6, 0) 2588c2ecf20Sopenharmony_ci#define I2C_VER_FIFO_EN BIT(7) 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/* stall/stuck timeout in us */ 2618c2ecf20Sopenharmony_ci#define DEFAULT_STALL_COUNT 25 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* SCLFRQ field position */ 2648c2ecf20Sopenharmony_ci#define SCLFRQ_0_TO_6 GENMASK(6, 0) 2658c2ecf20Sopenharmony_ci#define SCLFRQ_7_TO_8 GENMASK(8, 7) 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* supported clk settings. values in Hz. */ 2688c2ecf20Sopenharmony_ci#define I2C_FREQ_MIN_HZ 10000 2698c2ecf20Sopenharmony_ci#define I2C_FREQ_MAX_HZ I2C_MAX_FAST_MODE_PLUS_FREQ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* Status of one I2C module */ 2728c2ecf20Sopenharmony_cistruct npcm_i2c { 2738c2ecf20Sopenharmony_ci struct i2c_adapter adap; 2748c2ecf20Sopenharmony_ci struct device *dev; 2758c2ecf20Sopenharmony_ci unsigned char __iomem *reg; 2768c2ecf20Sopenharmony_ci spinlock_t lock; /* IRQ synchronization */ 2778c2ecf20Sopenharmony_ci struct completion cmd_complete; 2788c2ecf20Sopenharmony_ci int cmd_err; 2798c2ecf20Sopenharmony_ci struct i2c_msg *msgs; 2808c2ecf20Sopenharmony_ci int msgs_num; 2818c2ecf20Sopenharmony_ci int num; 2828c2ecf20Sopenharmony_ci u32 apb_clk; 2838c2ecf20Sopenharmony_ci struct i2c_bus_recovery_info rinfo; 2848c2ecf20Sopenharmony_ci enum i2c_state state; 2858c2ecf20Sopenharmony_ci enum i2c_oper operation; 2868c2ecf20Sopenharmony_ci enum i2c_mode master_or_slave; 2878c2ecf20Sopenharmony_ci enum i2c_state_ind stop_ind; 2888c2ecf20Sopenharmony_ci u8 dest_addr; 2898c2ecf20Sopenharmony_ci u8 *rd_buf; 2908c2ecf20Sopenharmony_ci u16 rd_size; 2918c2ecf20Sopenharmony_ci u16 rd_ind; 2928c2ecf20Sopenharmony_ci u8 *wr_buf; 2938c2ecf20Sopenharmony_ci u16 wr_size; 2948c2ecf20Sopenharmony_ci u16 wr_ind; 2958c2ecf20Sopenharmony_ci bool fifo_use; 2968c2ecf20Sopenharmony_ci u16 PEC_mask; /* PEC bit mask per slave address */ 2978c2ecf20Sopenharmony_ci bool PEC_use; 2988c2ecf20Sopenharmony_ci bool read_block_use; 2998c2ecf20Sopenharmony_ci unsigned long int_time_stamp; 3008c2ecf20Sopenharmony_ci unsigned long bus_freq; /* in Hz */ 3018c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 3028c2ecf20Sopenharmony_ci u8 own_slave_addr; 3038c2ecf20Sopenharmony_ci struct i2c_client *slave; 3048c2ecf20Sopenharmony_ci int slv_rd_size; 3058c2ecf20Sopenharmony_ci int slv_rd_ind; 3068c2ecf20Sopenharmony_ci int slv_wr_size; 3078c2ecf20Sopenharmony_ci int slv_wr_ind; 3088c2ecf20Sopenharmony_ci u8 slv_rd_buf[I2C_HW_FIFO_SIZE]; 3098c2ecf20Sopenharmony_ci u8 slv_wr_buf[I2C_HW_FIFO_SIZE]; 3108c2ecf20Sopenharmony_ci#endif 3118c2ecf20Sopenharmony_ci struct dentry *debugfs; /* debugfs device directory */ 3128c2ecf20Sopenharmony_ci u64 ber_cnt; 3138c2ecf20Sopenharmony_ci u64 rec_succ_cnt; 3148c2ecf20Sopenharmony_ci u64 rec_fail_cnt; 3158c2ecf20Sopenharmony_ci u64 nack_cnt; 3168c2ecf20Sopenharmony_ci u64 timeout_cnt; 3178c2ecf20Sopenharmony_ci}; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic inline void npcm_i2c_select_bank(struct npcm_i2c *bus, 3208c2ecf20Sopenharmony_ci enum i2c_bank bank) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci u8 i2cctl3 = ioread8(bus->reg + NPCM_I2CCTL3); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (bank == I2C_BANK_0) 3258c2ecf20Sopenharmony_ci i2cctl3 = i2cctl3 & ~I2CCTL3_BNK_SEL; 3268c2ecf20Sopenharmony_ci else 3278c2ecf20Sopenharmony_ci i2cctl3 = i2cctl3 | I2CCTL3_BNK_SEL; 3288c2ecf20Sopenharmony_ci iowrite8(i2cctl3, bus->reg + NPCM_I2CCTL3); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic void npcm_i2c_init_params(struct npcm_i2c *bus) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci bus->stop_ind = I2C_NO_STATUS_IND; 3348c2ecf20Sopenharmony_ci bus->rd_size = 0; 3358c2ecf20Sopenharmony_ci bus->wr_size = 0; 3368c2ecf20Sopenharmony_ci bus->rd_ind = 0; 3378c2ecf20Sopenharmony_ci bus->wr_ind = 0; 3388c2ecf20Sopenharmony_ci bus->read_block_use = false; 3398c2ecf20Sopenharmony_ci bus->int_time_stamp = 0; 3408c2ecf20Sopenharmony_ci bus->PEC_use = false; 3418c2ecf20Sopenharmony_ci bus->PEC_mask = 0; 3428c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 3438c2ecf20Sopenharmony_ci if (bus->slave) 3448c2ecf20Sopenharmony_ci bus->master_or_slave = I2C_SLAVE; 3458c2ecf20Sopenharmony_ci#endif 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic inline void npcm_i2c_wr_byte(struct npcm_i2c *bus, u8 data) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci iowrite8(data, bus->reg + NPCM_I2CSDA); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic inline u8 npcm_i2c_rd_byte(struct npcm_i2c *bus) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci return ioread8(bus->reg + NPCM_I2CSDA); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int npcm_i2c_get_SCL(struct i2c_adapter *_adap) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return !!(I2CCTL3_SCL_LVL & ioread8(bus->reg + NPCM_I2CCTL3)); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int npcm_i2c_get_SDA(struct i2c_adapter *_adap) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return !!(I2CCTL3_SDA_LVL & ioread8(bus->reg + NPCM_I2CCTL3)); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic inline u16 npcm_i2c_get_index(struct npcm_i2c *bus) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci if (bus->operation == I2C_READ_OPER) 3758c2ecf20Sopenharmony_ci return bus->rd_ind; 3768c2ecf20Sopenharmony_ci if (bus->operation == I2C_WRITE_OPER) 3778c2ecf20Sopenharmony_ci return bus->wr_ind; 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci/* quick protocol (just address) */ 3828c2ecf20Sopenharmony_cistatic inline bool npcm_i2c_is_quick(struct npcm_i2c *bus) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci return bus->wr_size == 0 && bus->rd_size == 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void npcm_i2c_disable(struct npcm_i2c *bus) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci u8 i2cctl2; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 3928c2ecf20Sopenharmony_ci int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* Slave addresses removal */ 3958c2ecf20Sopenharmony_ci for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++) 3968c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + npcm_i2caddr[i]); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci#endif 3998c2ecf20Sopenharmony_ci /* Disable module */ 4008c2ecf20Sopenharmony_ci i2cctl2 = ioread8(bus->reg + NPCM_I2CCTL2); 4018c2ecf20Sopenharmony_ci i2cctl2 = i2cctl2 & ~I2CCTL2_ENABLE; 4028c2ecf20Sopenharmony_ci iowrite8(i2cctl2, bus->reg + NPCM_I2CCTL2); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci bus->state = I2C_DISABLE; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic void npcm_i2c_enable(struct npcm_i2c *bus) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci u8 i2cctl2 = ioread8(bus->reg + NPCM_I2CCTL2); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci i2cctl2 = i2cctl2 | I2CCTL2_ENABLE; 4128c2ecf20Sopenharmony_ci iowrite8(i2cctl2, bus->reg + NPCM_I2CCTL2); 4138c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* enable\disable end of busy (EOB) interrupts */ 4178c2ecf20Sopenharmony_cistatic inline void npcm_i2c_eob_int(struct npcm_i2c *bus, bool enable) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci u8 val; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Clear EO_BUSY pending bit: */ 4228c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCST3); 4238c2ecf20Sopenharmony_ci val = val | NPCM_I2CCST3_EO_BUSY; 4248c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCST3); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCTL1); 4278c2ecf20Sopenharmony_ci val &= ~NPCM_I2CCTL1_RWS; 4288c2ecf20Sopenharmony_ci if (enable) 4298c2ecf20Sopenharmony_ci val |= NPCM_I2CCTL1_EOBINTE; 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci val &= ~NPCM_I2CCTL1_EOBINTE; 4328c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCTL1); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic inline bool npcm_i2c_tx_fifo_empty(struct npcm_i2c *bus) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci u8 tx_fifo_sts; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci tx_fifo_sts = ioread8(bus->reg + NPCM_I2CTXF_STS); 4408c2ecf20Sopenharmony_ci /* check if TX FIFO is not empty */ 4418c2ecf20Sopenharmony_ci if ((tx_fifo_sts & NPCM_I2CTXF_STS_TX_BYTES) == 0) 4428c2ecf20Sopenharmony_ci return false; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* check if TX FIFO status bit is set: */ 4458c2ecf20Sopenharmony_ci return !!FIELD_GET(NPCM_I2CTXF_STS_TX_THST, tx_fifo_sts); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic inline bool npcm_i2c_rx_fifo_full(struct npcm_i2c *bus) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci u8 rx_fifo_sts; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci rx_fifo_sts = ioread8(bus->reg + NPCM_I2CRXF_STS); 4538c2ecf20Sopenharmony_ci /* check if RX FIFO is not empty: */ 4548c2ecf20Sopenharmony_ci if ((rx_fifo_sts & NPCM_I2CRXF_STS_RX_BYTES) == 0) 4558c2ecf20Sopenharmony_ci return false; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* check if rx fifo full status is set: */ 4588c2ecf20Sopenharmony_ci return !!FIELD_GET(NPCM_I2CRXF_STS_RX_THST, rx_fifo_sts); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic inline void npcm_i2c_clear_fifo_int(struct npcm_i2c *bus) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci u8 val; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CFIF_CTS); 4668c2ecf20Sopenharmony_ci val = (val & NPCM_I2CFIF_CTS_SLVRSTR) | NPCM_I2CFIF_CTS_RXF_TXE; 4678c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CFIF_CTS); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic inline void npcm_i2c_clear_tx_fifo(struct npcm_i2c *bus) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci u8 val; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CTXF_STS); 4758c2ecf20Sopenharmony_ci val = val | NPCM_I2CTXF_STS_TX_THST; 4768c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CTXF_STS); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic inline void npcm_i2c_clear_rx_fifo(struct npcm_i2c *bus) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci u8 val; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CRXF_STS); 4848c2ecf20Sopenharmony_ci val = val | NPCM_I2CRXF_STS_RX_THST; 4858c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CRXF_STS); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void npcm_i2c_int_enable(struct npcm_i2c *bus, bool enable) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci u8 val; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCTL1); 4938c2ecf20Sopenharmony_ci val &= ~NPCM_I2CCTL1_RWS; 4948c2ecf20Sopenharmony_ci if (enable) 4958c2ecf20Sopenharmony_ci val |= NPCM_I2CCTL1_INTEN; 4968c2ecf20Sopenharmony_ci else 4978c2ecf20Sopenharmony_ci val &= ~NPCM_I2CCTL1_INTEN; 4988c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCTL1); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic inline void npcm_i2c_master_start(struct npcm_i2c *bus) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci u8 val; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCTL1); 5068c2ecf20Sopenharmony_ci val &= ~(NPCM_I2CCTL1_STOP | NPCM_I2CCTL1_ACK); 5078c2ecf20Sopenharmony_ci val |= NPCM_I2CCTL1_START; 5088c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCTL1); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic inline void npcm_i2c_master_stop(struct npcm_i2c *bus) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci u8 val; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * override HW issue: I2C may fail to supply stop condition in Master 5178c2ecf20Sopenharmony_ci * Write operation. 5188c2ecf20Sopenharmony_ci * Need to delay at least 5 us from the last int, before issueing a stop 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_ci udelay(10); /* function called from interrupt, can't sleep */ 5218c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCTL1); 5228c2ecf20Sopenharmony_ci val &= ~(NPCM_I2CCTL1_START | NPCM_I2CCTL1_ACK); 5238c2ecf20Sopenharmony_ci val |= NPCM_I2CCTL1_STOP; 5248c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCTL1); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (!bus->fifo_use) 5278c2ecf20Sopenharmony_ci return; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_1); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (bus->operation == I2C_READ_OPER) 5328c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 5338c2ecf20Sopenharmony_ci else 5348c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 5358c2ecf20Sopenharmony_ci npcm_i2c_clear_fifo_int(bus); 5368c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic inline void npcm_i2c_stall_after_start(struct npcm_i2c *bus, bool stall) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci u8 val; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCTL1); 5448c2ecf20Sopenharmony_ci val &= ~NPCM_I2CCTL1_RWS; 5458c2ecf20Sopenharmony_ci if (stall) 5468c2ecf20Sopenharmony_ci val |= NPCM_I2CCTL1_STASTRE; 5478c2ecf20Sopenharmony_ci else 5488c2ecf20Sopenharmony_ci val &= ~NPCM_I2CCTL1_STASTRE; 5498c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCTL1); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic inline void npcm_i2c_nack(struct npcm_i2c *bus) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci u8 val; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCTL1); 5578c2ecf20Sopenharmony_ci val &= ~(NPCM_I2CCTL1_STOP | NPCM_I2CCTL1_START); 5588c2ecf20Sopenharmony_ci val |= NPCM_I2CCTL1_ACK; 5598c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCTL1); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic inline void npcm_i2c_clear_master_status(struct npcm_i2c *bus) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci u8 val; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* Clear NEGACK, STASTR and BER bits */ 5678c2ecf20Sopenharmony_ci val = NPCM_I2CST_BER | NPCM_I2CST_NEGACK | NPCM_I2CST_STASTR; 5688c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CST); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 5728c2ecf20Sopenharmony_cistatic void npcm_i2c_slave_int_enable(struct npcm_i2c *bus, bool enable) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci u8 i2cctl1; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* enable interrupt on slave match: */ 5778c2ecf20Sopenharmony_ci i2cctl1 = ioread8(bus->reg + NPCM_I2CCTL1); 5788c2ecf20Sopenharmony_ci i2cctl1 &= ~NPCM_I2CCTL1_RWS; 5798c2ecf20Sopenharmony_ci if (enable) 5808c2ecf20Sopenharmony_ci i2cctl1 |= NPCM_I2CCTL1_NMINTE; 5818c2ecf20Sopenharmony_ci else 5828c2ecf20Sopenharmony_ci i2cctl1 &= ~NPCM_I2CCTL1_NMINTE; 5838c2ecf20Sopenharmony_ci iowrite8(i2cctl1, bus->reg + NPCM_I2CCTL1); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int npcm_i2c_slave_enable(struct npcm_i2c *bus, enum i2c_addr addr_type, 5878c2ecf20Sopenharmony_ci u8 addr, bool enable) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci u8 i2cctl1; 5908c2ecf20Sopenharmony_ci u8 i2cctl3; 5918c2ecf20Sopenharmony_ci u8 sa_reg; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci sa_reg = (addr & 0x7F) | FIELD_PREP(NPCM_I2CADDR_SAEN, enable); 5948c2ecf20Sopenharmony_ci if (addr_type == I2C_GC_ADDR) { 5958c2ecf20Sopenharmony_ci i2cctl1 = ioread8(bus->reg + NPCM_I2CCTL1); 5968c2ecf20Sopenharmony_ci if (enable) 5978c2ecf20Sopenharmony_ci i2cctl1 |= NPCM_I2CCTL1_GCMEN; 5988c2ecf20Sopenharmony_ci else 5998c2ecf20Sopenharmony_ci i2cctl1 &= ~NPCM_I2CCTL1_GCMEN; 6008c2ecf20Sopenharmony_ci iowrite8(i2cctl1, bus->reg + NPCM_I2CCTL1); 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci } else if (addr_type == I2C_ARP_ADDR) { 6038c2ecf20Sopenharmony_ci i2cctl3 = ioread8(bus->reg + NPCM_I2CCTL3); 6048c2ecf20Sopenharmony_ci if (enable) 6058c2ecf20Sopenharmony_ci i2cctl3 |= I2CCTL3_ARPMEN; 6068c2ecf20Sopenharmony_ci else 6078c2ecf20Sopenharmony_ci i2cctl3 &= ~I2CCTL3_ARPMEN; 6088c2ecf20Sopenharmony_ci iowrite8(i2cctl3, bus->reg + NPCM_I2CCTL3); 6098c2ecf20Sopenharmony_ci return 0; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10) 6128c2ecf20Sopenharmony_ci dev_err(bus->dev, "try to enable more than 2 SA not supported\n"); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (addr_type >= I2C_ARP_ADDR) 6158c2ecf20Sopenharmony_ci return -EFAULT; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Set and enable the address */ 6188c2ecf20Sopenharmony_ci iowrite8(sa_reg, bus->reg + npcm_i2caddr[addr_type]); 6198c2ecf20Sopenharmony_ci npcm_i2c_slave_int_enable(bus, enable); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci#endif 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic void npcm_i2c_reset(struct npcm_i2c *bus) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci /* 6288c2ecf20Sopenharmony_ci * Save I2CCTL1 relevant bits. It is being cleared when the module 6298c2ecf20Sopenharmony_ci * is disabled. 6308c2ecf20Sopenharmony_ci */ 6318c2ecf20Sopenharmony_ci u8 i2cctl1; 6328c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 6338c2ecf20Sopenharmony_ci u8 addr; 6348c2ecf20Sopenharmony_ci#endif 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci i2cctl1 = ioread8(bus->reg + NPCM_I2CCTL1); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci npcm_i2c_disable(bus); 6398c2ecf20Sopenharmony_ci npcm_i2c_enable(bus); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* Restore NPCM_I2CCTL1 Status */ 6428c2ecf20Sopenharmony_ci i2cctl1 &= ~NPCM_I2CCTL1_RWS; 6438c2ecf20Sopenharmony_ci iowrite8(i2cctl1, bus->reg + NPCM_I2CCTL1); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Clear BB (BUS BUSY) bit */ 6468c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); 6478c2ecf20Sopenharmony_ci iowrite8(0xFF, bus->reg + NPCM_I2CST); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Clear and disable EOB */ 6508c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, false); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* Clear all fifo bits: */ 6538c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 6568c2ecf20Sopenharmony_ci if (bus->slave) { 6578c2ecf20Sopenharmony_ci addr = bus->slave->addr; 6588c2ecf20Sopenharmony_ci npcm_i2c_slave_enable(bus, I2C_SLAVE_ADDR1, addr, true); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci#endif 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* clear status bits for spurious interrupts */ 6638c2ecf20Sopenharmony_ci npcm_i2c_clear_master_status(bus); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic inline bool npcm_i2c_is_master(struct npcm_i2c *bus) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci return !!FIELD_GET(NPCM_I2CST_MASTER, ioread8(bus->reg + NPCM_I2CST)); 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void npcm_i2c_callback(struct npcm_i2c *bus, 6748c2ecf20Sopenharmony_ci enum i2c_state_ind op_status, u16 info) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct i2c_msg *msgs; 6778c2ecf20Sopenharmony_ci int msgs_num; 6788c2ecf20Sopenharmony_ci bool do_complete = false; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci msgs = bus->msgs; 6818c2ecf20Sopenharmony_ci msgs_num = bus->msgs_num; 6828c2ecf20Sopenharmony_ci /* 6838c2ecf20Sopenharmony_ci * check that transaction was not timed-out, and msgs still 6848c2ecf20Sopenharmony_ci * holds a valid value. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci if (!msgs) 6878c2ecf20Sopenharmony_ci return; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (completion_done(&bus->cmd_complete)) 6908c2ecf20Sopenharmony_ci return; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci switch (op_status) { 6938c2ecf20Sopenharmony_ci case I2C_MASTER_DONE_IND: 6948c2ecf20Sopenharmony_ci bus->cmd_err = bus->msgs_num; 6958c2ecf20Sopenharmony_ci fallthrough; 6968c2ecf20Sopenharmony_ci case I2C_BLOCK_BYTES_ERR_IND: 6978c2ecf20Sopenharmony_ci /* Master tx finished and all transmit bytes were sent */ 6988c2ecf20Sopenharmony_ci if (bus->msgs) { 6998c2ecf20Sopenharmony_ci if (msgs[0].flags & I2C_M_RD) 7008c2ecf20Sopenharmony_ci msgs[0].len = info; 7018c2ecf20Sopenharmony_ci else if (msgs_num == 2 && 7028c2ecf20Sopenharmony_ci msgs[1].flags & I2C_M_RD) 7038c2ecf20Sopenharmony_ci msgs[1].len = info; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci do_complete = true; 7068c2ecf20Sopenharmony_ci break; 7078c2ecf20Sopenharmony_ci case I2C_NACK_IND: 7088c2ecf20Sopenharmony_ci /* MASTER transmit got a NACK before tx all bytes */ 7098c2ecf20Sopenharmony_ci bus->cmd_err = -ENXIO; 7108c2ecf20Sopenharmony_ci do_complete = true; 7118c2ecf20Sopenharmony_ci break; 7128c2ecf20Sopenharmony_ci case I2C_BUS_ERR_IND: 7138c2ecf20Sopenharmony_ci /* Bus error */ 7148c2ecf20Sopenharmony_ci bus->cmd_err = -EAGAIN; 7158c2ecf20Sopenharmony_ci do_complete = true; 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci case I2C_WAKE_UP_IND: 7188c2ecf20Sopenharmony_ci /* I2C wake up */ 7198c2ecf20Sopenharmony_ci break; 7208c2ecf20Sopenharmony_ci default: 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci bus->operation = I2C_NO_OPER; 7258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 7268c2ecf20Sopenharmony_ci if (bus->slave) 7278c2ecf20Sopenharmony_ci bus->master_or_slave = I2C_SLAVE; 7288c2ecf20Sopenharmony_ci#endif 7298c2ecf20Sopenharmony_ci if (do_complete) 7308c2ecf20Sopenharmony_ci complete(&bus->cmd_complete); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic u8 npcm_i2c_fifo_usage(struct npcm_i2c *bus) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci if (bus->operation == I2C_WRITE_OPER) 7368c2ecf20Sopenharmony_ci return FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES, 7378c2ecf20Sopenharmony_ci ioread8(bus->reg + NPCM_I2CTXF_STS)); 7388c2ecf20Sopenharmony_ci if (bus->operation == I2C_READ_OPER) 7398c2ecf20Sopenharmony_ci return FIELD_GET(NPCM_I2CRXF_STS_RX_BYTES, 7408c2ecf20Sopenharmony_ci ioread8(bus->reg + NPCM_I2CRXF_STS)); 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void npcm_i2c_write_to_fifo_master(struct npcm_i2c *bus, u16 max_bytes) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci u8 size_free_fifo; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* 7498c2ecf20Sopenharmony_ci * Fill the FIFO, while the FIFO is not full and there are more bytes 7508c2ecf20Sopenharmony_ci * to write 7518c2ecf20Sopenharmony_ci */ 7528c2ecf20Sopenharmony_ci size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus); 7538c2ecf20Sopenharmony_ci while (max_bytes-- && size_free_fifo) { 7548c2ecf20Sopenharmony_ci if (bus->wr_ind < bus->wr_size) 7558c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, bus->wr_buf[bus->wr_ind++]); 7568c2ecf20Sopenharmony_ci else 7578c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, 0xFF); 7588c2ecf20Sopenharmony_ci size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci/* 7638c2ecf20Sopenharmony_ci * npcm_i2c_set_fifo: 7648c2ecf20Sopenharmony_ci * configure the FIFO before using it. If nread is -1 RX FIFO will not be 7658c2ecf20Sopenharmony_ci * configured. same for nwrite 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_cistatic void npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci u8 rxf_ctl = 0; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (!bus->fifo_use) 7728c2ecf20Sopenharmony_ci return; 7738c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_1); 7748c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 7758c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* configure RX FIFO */ 7788c2ecf20Sopenharmony_ci if (nread > 0) { 7798c2ecf20Sopenharmony_ci rxf_ctl = min_t(int, nread, I2C_HW_FIFO_SIZE); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* set LAST bit. if LAST is set next FIFO packet is nacked */ 7828c2ecf20Sopenharmony_ci if (nread <= I2C_HW_FIFO_SIZE) 7838c2ecf20Sopenharmony_ci rxf_ctl |= NPCM_I2CRXF_CTL_LAST_PEC; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* 7868c2ecf20Sopenharmony_ci * if we are about to read the first byte in blk rd mode, 7878c2ecf20Sopenharmony_ci * don't NACK it. If slave returns zero size HW can't NACK 7888c2ecf20Sopenharmony_ci * it immidiattly, it will read extra byte and then NACK. 7898c2ecf20Sopenharmony_ci */ 7908c2ecf20Sopenharmony_ci if (bus->rd_ind == 0 && bus->read_block_use) { 7918c2ecf20Sopenharmony_ci /* set fifo to read one byte, no last: */ 7928c2ecf20Sopenharmony_ci rxf_ctl = 1; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* set fifo size: */ 7968c2ecf20Sopenharmony_ci iowrite8(rxf_ctl, bus->reg + NPCM_I2CRXF_CTL); 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* configure TX FIFO */ 8008c2ecf20Sopenharmony_ci if (nwrite > 0) { 8018c2ecf20Sopenharmony_ci if (nwrite > I2C_HW_FIFO_SIZE) 8028c2ecf20Sopenharmony_ci /* data to send is more then FIFO size. */ 8038c2ecf20Sopenharmony_ci iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CTXF_CTL); 8048c2ecf20Sopenharmony_ci else 8058c2ecf20Sopenharmony_ci iowrite8(nwrite, bus->reg + NPCM_I2CTXF_CTL); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic void npcm_i2c_read_fifo(struct npcm_i2c *bus, u8 bytes_in_fifo) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci u8 data; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci while (bytes_in_fifo--) { 8168c2ecf20Sopenharmony_ci data = npcm_i2c_rd_byte(bus); 8178c2ecf20Sopenharmony_ci if (bus->rd_ind < bus->rd_size) 8188c2ecf20Sopenharmony_ci bus->rd_buf[bus->rd_ind++] = data; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic void npcm_i2c_master_abort(struct npcm_i2c *bus) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci /* Only current master is allowed to issue a stop condition */ 8258c2ecf20Sopenharmony_ci if (!npcm_i2c_is_master(bus)) 8268c2ecf20Sopenharmony_ci return; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, true); 8298c2ecf20Sopenharmony_ci npcm_i2c_master_stop(bus); 8308c2ecf20Sopenharmony_ci npcm_i2c_clear_master_status(bus); 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 8348c2ecf20Sopenharmony_cistatic u8 npcm_i2c_get_slave_addr(struct npcm_i2c *bus, enum i2c_addr addr_type) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci u8 slave_add; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10) 8398c2ecf20Sopenharmony_ci dev_err(bus->dev, "get slave: try to use more than 2 SA not supported\n"); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci slave_add = ioread8(bus->reg + npcm_i2caddr[(int)addr_type]); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return slave_add; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic int npcm_i2c_remove_slave_addr(struct npcm_i2c *bus, u8 slave_add) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci int i; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Set the enable bit */ 8518c2ecf20Sopenharmony_ci slave_add |= 0x80; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++) { 8548c2ecf20Sopenharmony_ci if (ioread8(bus->reg + npcm_i2caddr[i]) == slave_add) 8558c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + npcm_i2caddr[i]); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void npcm_i2c_write_fifo_slave(struct npcm_i2c *bus, u16 max_bytes) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci /* 8648c2ecf20Sopenharmony_ci * Fill the FIFO, while the FIFO is not full and there are more bytes 8658c2ecf20Sopenharmony_ci * to write 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci npcm_i2c_clear_fifo_int(bus); 8688c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 8698c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); 8708c2ecf20Sopenharmony_ci while (max_bytes-- && I2C_HW_FIFO_SIZE != npcm_i2c_fifo_usage(bus)) { 8718c2ecf20Sopenharmony_ci if (bus->slv_wr_size <= 0) 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE; 8748c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, bus->slv_wr_buf[bus->slv_wr_ind]); 8758c2ecf20Sopenharmony_ci bus->slv_wr_ind++; 8768c2ecf20Sopenharmony_ci bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE; 8778c2ecf20Sopenharmony_ci bus->slv_wr_size--; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic void npcm_i2c_read_fifo_slave(struct npcm_i2c *bus, u8 bytes_in_fifo) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci u8 data; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!bus->slave) 8868c2ecf20Sopenharmony_ci return; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci while (bytes_in_fifo--) { 8898c2ecf20Sopenharmony_ci data = npcm_i2c_rd_byte(bus); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci bus->slv_rd_ind = bus->slv_rd_ind % I2C_HW_FIFO_SIZE; 8928c2ecf20Sopenharmony_ci bus->slv_rd_buf[bus->slv_rd_ind] = data; 8938c2ecf20Sopenharmony_ci bus->slv_rd_ind++; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* 1st byte is length in block protocol: */ 8968c2ecf20Sopenharmony_ci if (bus->slv_rd_ind == 1 && bus->read_block_use) 8978c2ecf20Sopenharmony_ci bus->slv_rd_size = data + bus->PEC_use + 1; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic int npcm_i2c_slave_get_wr_buf(struct npcm_i2c *bus) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci int i; 9048c2ecf20Sopenharmony_ci u8 value; 9058c2ecf20Sopenharmony_ci int ind; 9068c2ecf20Sopenharmony_ci int ret = bus->slv_wr_ind; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* fill a cyclic buffer */ 9098c2ecf20Sopenharmony_ci for (i = 0; i < I2C_HW_FIFO_SIZE; i++) { 9108c2ecf20Sopenharmony_ci if (bus->slv_wr_size >= I2C_HW_FIFO_SIZE) 9118c2ecf20Sopenharmony_ci break; 9128c2ecf20Sopenharmony_ci if (bus->state == I2C_SLAVE_MATCH) { 9138c2ecf20Sopenharmony_ci i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value); 9148c2ecf20Sopenharmony_ci bus->state = I2C_OPER_STARTED; 9158c2ecf20Sopenharmony_ci } else { 9168c2ecf20Sopenharmony_ci i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci ind = (bus->slv_wr_ind + bus->slv_wr_size) % I2C_HW_FIFO_SIZE; 9198c2ecf20Sopenharmony_ci bus->slv_wr_buf[ind] = value; 9208c2ecf20Sopenharmony_ci bus->slv_wr_size++; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci return I2C_HW_FIFO_SIZE - ret; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic void npcm_i2c_slave_send_rd_buf(struct npcm_i2c *bus) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci int i; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci for (i = 0; i < bus->slv_rd_ind; i++) 9308c2ecf20Sopenharmony_ci i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED, 9318c2ecf20Sopenharmony_ci &bus->slv_rd_buf[i]); 9328c2ecf20Sopenharmony_ci /* 9338c2ecf20Sopenharmony_ci * once we send bytes up, need to reset the counter of the wr buf 9348c2ecf20Sopenharmony_ci * got data from master (new offset in device), ignore wr fifo: 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci if (bus->slv_rd_ind) { 9378c2ecf20Sopenharmony_ci bus->slv_wr_size = 0; 9388c2ecf20Sopenharmony_ci bus->slv_wr_ind = 0; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci bus->slv_rd_ind = 0; 9428c2ecf20Sopenharmony_ci bus->slv_rd_size = bus->adap.quirks->max_read_len; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci npcm_i2c_clear_fifo_int(bus); 9458c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic void npcm_i2c_slave_receive(struct npcm_i2c *bus, u16 nread, 9498c2ecf20Sopenharmony_ci u8 *read_data) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci bus->state = I2C_OPER_STARTED; 9528c2ecf20Sopenharmony_ci bus->operation = I2C_READ_OPER; 9538c2ecf20Sopenharmony_ci bus->slv_rd_size = nread; 9548c2ecf20Sopenharmony_ci bus->slv_rd_ind = 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); 9578c2ecf20Sopenharmony_ci iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL); 9588c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 9598c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic void npcm_i2c_slave_xmit(struct npcm_i2c *bus, u16 nwrite, 9638c2ecf20Sopenharmony_ci u8 *write_data) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci if (nwrite == 0) 9668c2ecf20Sopenharmony_ci return; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci bus->operation = I2C_WRITE_OPER; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* get the next buffer */ 9718c2ecf20Sopenharmony_ci npcm_i2c_slave_get_wr_buf(bus); 9728c2ecf20Sopenharmony_ci npcm_i2c_write_fifo_slave(bus, nwrite); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci/* 9768c2ecf20Sopenharmony_ci * npcm_i2c_slave_wr_buf_sync: 9778c2ecf20Sopenharmony_ci * currently slave IF only supports single byte operations. 9788c2ecf20Sopenharmony_ci * in order to utilyze the npcm HW FIFO, the driver will ask for 16 bytes 9798c2ecf20Sopenharmony_ci * at a time, pack them in buffer, and then transmit them all together 9808c2ecf20Sopenharmony_ci * to the FIFO and onward to the bus. 9818c2ecf20Sopenharmony_ci * NACK on read will be once reached to bus->adap->quirks->max_read_len. 9828c2ecf20Sopenharmony_ci * sending a NACK wherever the backend requests for it is not supported. 9838c2ecf20Sopenharmony_ci * the next two functions allow reading to local buffer before writing it all 9848c2ecf20Sopenharmony_ci * to the HW FIFO. 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_cistatic void npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci int left_in_fifo; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci left_in_fifo = FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES, 9918c2ecf20Sopenharmony_ci ioread8(bus->reg + NPCM_I2CTXF_STS)); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* fifo already full: */ 9948c2ecf20Sopenharmony_ci if (left_in_fifo >= I2C_HW_FIFO_SIZE || 9958c2ecf20Sopenharmony_ci bus->slv_wr_size >= I2C_HW_FIFO_SIZE) 9968c2ecf20Sopenharmony_ci return; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* update the wr fifo index back to the untransmitted bytes: */ 9998c2ecf20Sopenharmony_ci bus->slv_wr_ind = bus->slv_wr_ind - left_in_fifo; 10008c2ecf20Sopenharmony_ci bus->slv_wr_size = bus->slv_wr_size + left_in_fifo; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (bus->slv_wr_ind < 0) 10038c2ecf20Sopenharmony_ci bus->slv_wr_ind += I2C_HW_FIFO_SIZE; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic void npcm_i2c_slave_rd_wr(struct npcm_i2c *bus) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci if (NPCM_I2CST_XMIT & ioread8(bus->reg + NPCM_I2CST)) { 10098c2ecf20Sopenharmony_ci /* 10108c2ecf20Sopenharmony_ci * Slave got an address match with direction bit 1 so it should 10118c2ecf20Sopenharmony_ci * transmit data. Write till the master will NACK 10128c2ecf20Sopenharmony_ci */ 10138c2ecf20Sopenharmony_ci bus->operation = I2C_WRITE_OPER; 10148c2ecf20Sopenharmony_ci npcm_i2c_slave_xmit(bus, bus->adap.quirks->max_write_len, 10158c2ecf20Sopenharmony_ci bus->slv_wr_buf); 10168c2ecf20Sopenharmony_ci } else { 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * Slave got an address match with direction bit 0 so it should 10198c2ecf20Sopenharmony_ci * receive data. 10208c2ecf20Sopenharmony_ci * this module does not support saying no to bytes. 10218c2ecf20Sopenharmony_ci * it will always ACK. 10228c2ecf20Sopenharmony_ci */ 10238c2ecf20Sopenharmony_ci bus->operation = I2C_READ_OPER; 10248c2ecf20Sopenharmony_ci npcm_i2c_read_fifo_slave(bus, npcm_i2c_fifo_usage(bus)); 10258c2ecf20Sopenharmony_ci bus->stop_ind = I2C_SLAVE_RCV_IND; 10268c2ecf20Sopenharmony_ci npcm_i2c_slave_send_rd_buf(bus); 10278c2ecf20Sopenharmony_ci npcm_i2c_slave_receive(bus, bus->adap.quirks->max_read_len, 10288c2ecf20Sopenharmony_ci bus->slv_rd_buf); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci u8 val; 10358c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 10368c2ecf20Sopenharmony_ci u8 i2cst = ioread8(bus->reg + NPCM_I2CST); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Slave: A NACK has occurred */ 10398c2ecf20Sopenharmony_ci if (NPCM_I2CST_NEGACK & i2cst) { 10408c2ecf20Sopenharmony_ci bus->stop_ind = I2C_NACK_IND; 10418c2ecf20Sopenharmony_ci npcm_i2c_slave_wr_buf_sync(bus); 10428c2ecf20Sopenharmony_ci if (bus->fifo_use) 10438c2ecf20Sopenharmony_ci /* clear the FIFO */ 10448c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, 10458c2ecf20Sopenharmony_ci bus->reg + NPCM_I2CFIF_CTS); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* In slave write, NACK is OK, otherwise it is a problem */ 10488c2ecf20Sopenharmony_ci bus->stop_ind = I2C_NO_STATUS_IND; 10498c2ecf20Sopenharmony_ci bus->operation = I2C_NO_OPER; 10508c2ecf20Sopenharmony_ci bus->own_slave_addr = 0xFF; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* 10538c2ecf20Sopenharmony_ci * Slave has to wait for STOP to decide this is the end 10548c2ecf20Sopenharmony_ci * of the transaction. tx is not yet considered as done 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CST_NEGACK, bus->reg + NPCM_I2CST); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci /* Slave mode: a Bus Error (BER) has been identified */ 10628c2ecf20Sopenharmony_ci if (NPCM_I2CST_BER & i2cst) { 10638c2ecf20Sopenharmony_ci /* 10648c2ecf20Sopenharmony_ci * Check whether bus arbitration or Start or Stop during data 10658c2ecf20Sopenharmony_ci * xfer bus arbitration problem should not result in recovery 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ci bus->stop_ind = I2C_BUS_ERR_IND; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* wait for bus busy before clear fifo */ 10708c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* 10758c2ecf20Sopenharmony_ci * in BER case we might get 2 interrupts: one for slave one for 10768c2ecf20Sopenharmony_ci * master ( for a channel which is master\slave switching) 10778c2ecf20Sopenharmony_ci */ 10788c2ecf20Sopenharmony_ci if (completion_done(&bus->cmd_complete) == false) { 10798c2ecf20Sopenharmony_ci bus->cmd_err = -EIO; 10808c2ecf20Sopenharmony_ci complete(&bus->cmd_complete); 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci bus->own_slave_addr = 0xFF; 10838c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CST_BER, bus->reg + NPCM_I2CST); 10848c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* A Slave Stop Condition has been identified */ 10888c2ecf20Sopenharmony_ci if (NPCM_I2CST_SLVSTP & i2cst) { 10898c2ecf20Sopenharmony_ci u8 bytes_in_fifo = npcm_i2c_fifo_usage(bus); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci bus->stop_ind = I2C_SLAVE_DONE_IND; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (bus->operation == I2C_READ_OPER) 10948c2ecf20Sopenharmony_ci npcm_i2c_read_fifo_slave(bus, bytes_in_fifo); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* if the buffer is empty nothing will be sent */ 10978c2ecf20Sopenharmony_ci npcm_i2c_slave_send_rd_buf(bus); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci /* Slave done transmitting or receiving */ 11008c2ecf20Sopenharmony_ci bus->stop_ind = I2C_NO_STATUS_IND; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* 11038c2ecf20Sopenharmony_ci * Note, just because we got here, it doesn't mean we through 11048c2ecf20Sopenharmony_ci * away the wr buffer. 11058c2ecf20Sopenharmony_ci * we keep it until the next received offset. 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_ci bus->operation = I2C_NO_OPER; 11088c2ecf20Sopenharmony_ci bus->own_slave_addr = 0xFF; 11098c2ecf20Sopenharmony_ci i2c_slave_event(bus->slave, I2C_SLAVE_STOP, 0); 11108c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CST_SLVSTP, bus->reg + NPCM_I2CST); 11118c2ecf20Sopenharmony_ci if (bus->fifo_use) { 11128c2ecf20Sopenharmony_ci npcm_i2c_clear_fifo_int(bus); 11138c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 11148c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, 11178c2ecf20Sopenharmony_ci bus->reg + NPCM_I2CFIF_CTS); 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 11208c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* restart condition occurred and Rx-FIFO was not empty */ 11248c2ecf20Sopenharmony_ci if (bus->fifo_use && FIELD_GET(NPCM_I2CFIF_CTS_SLVRSTR, 11258c2ecf20Sopenharmony_ci ioread8(bus->reg + NPCM_I2CFIF_CTS))) { 11268c2ecf20Sopenharmony_ci bus->stop_ind = I2C_SLAVE_RESTART_IND; 11278c2ecf20Sopenharmony_ci bus->master_or_slave = I2C_SLAVE; 11288c2ecf20Sopenharmony_ci if (bus->operation == I2C_READ_OPER) 11298c2ecf20Sopenharmony_ci npcm_i2c_read_fifo_slave(bus, npcm_i2c_fifo_usage(bus)); 11308c2ecf20Sopenharmony_ci bus->operation = I2C_WRITE_OPER; 11318c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + NPCM_I2CRXF_CTL); 11328c2ecf20Sopenharmony_ci val = NPCM_I2CFIF_CTS_CLR_FIFO | NPCM_I2CFIF_CTS_SLVRSTR | 11338c2ecf20Sopenharmony_ci NPCM_I2CFIF_CTS_RXF_TXE; 11348c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CFIF_CTS); 11358c2ecf20Sopenharmony_ci npcm_i2c_slave_rd_wr(bus); 11368c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* A Slave Address Match has been identified */ 11408c2ecf20Sopenharmony_ci if (NPCM_I2CST_NMATCH & i2cst) { 11418c2ecf20Sopenharmony_ci u8 info = 0; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* Address match automatically implies slave mode */ 11448c2ecf20Sopenharmony_ci bus->master_or_slave = I2C_SLAVE; 11458c2ecf20Sopenharmony_ci npcm_i2c_clear_fifo_int(bus); 11468c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 11478c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 11488c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); 11498c2ecf20Sopenharmony_ci iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL); 11508c2ecf20Sopenharmony_ci if (NPCM_I2CST_XMIT & i2cst) { 11518c2ecf20Sopenharmony_ci bus->operation = I2C_WRITE_OPER; 11528c2ecf20Sopenharmony_ci } else { 11538c2ecf20Sopenharmony_ci i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_REQUESTED, 11548c2ecf20Sopenharmony_ci &info); 11558c2ecf20Sopenharmony_ci bus->operation = I2C_READ_OPER; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci if (bus->own_slave_addr == 0xFF) { 11588c2ecf20Sopenharmony_ci /* Check which type of address match */ 11598c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCST); 11608c2ecf20Sopenharmony_ci if (NPCM_I2CCST_MATCH & val) { 11618c2ecf20Sopenharmony_ci u16 addr; 11628c2ecf20Sopenharmony_ci enum i2c_addr eaddr; 11638c2ecf20Sopenharmony_ci u8 i2ccst2; 11648c2ecf20Sopenharmony_ci u8 i2ccst3; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci i2ccst3 = ioread8(bus->reg + NPCM_I2CCST3); 11678c2ecf20Sopenharmony_ci i2ccst2 = ioread8(bus->reg + NPCM_I2CCST2); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci /* 11708c2ecf20Sopenharmony_ci * the i2c module can response to 10 own SA. 11718c2ecf20Sopenharmony_ci * check which one was addressed by the master. 11728c2ecf20Sopenharmony_ci * repond to the first one. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci addr = ((i2ccst3 & 0x07) << 7) | 11758c2ecf20Sopenharmony_ci (i2ccst2 & 0x7F); 11768c2ecf20Sopenharmony_ci info = ffs(addr); 11778c2ecf20Sopenharmony_ci eaddr = (enum i2c_addr)info; 11788c2ecf20Sopenharmony_ci addr = npcm_i2c_get_slave_addr(bus, eaddr); 11798c2ecf20Sopenharmony_ci addr &= 0x7F; 11808c2ecf20Sopenharmony_ci bus->own_slave_addr = addr; 11818c2ecf20Sopenharmony_ci if (bus->PEC_mask & BIT(info)) 11828c2ecf20Sopenharmony_ci bus->PEC_use = true; 11838c2ecf20Sopenharmony_ci else 11848c2ecf20Sopenharmony_ci bus->PEC_use = false; 11858c2ecf20Sopenharmony_ci } else { 11868c2ecf20Sopenharmony_ci if (NPCM_I2CCST_GCMATCH & val) 11878c2ecf20Sopenharmony_ci bus->own_slave_addr = 0; 11888c2ecf20Sopenharmony_ci if (NPCM_I2CCST_ARPMATCH & val) 11898c2ecf20Sopenharmony_ci bus->own_slave_addr = 0x61; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci } else { 11928c2ecf20Sopenharmony_ci /* 11938c2ecf20Sopenharmony_ci * Slave match can happen in two options: 11948c2ecf20Sopenharmony_ci * 1. Start, SA, read (slave read without further ado) 11958c2ecf20Sopenharmony_ci * 2. Start, SA, read, data, restart, SA, read, ... 11968c2ecf20Sopenharmony_ci * (slave read in fragmented mode) 11978c2ecf20Sopenharmony_ci * 3. Start, SA, write, data, restart, SA, read, .. 11988c2ecf20Sopenharmony_ci * (regular write-read mode) 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci if ((bus->state == I2C_OPER_STARTED && 12018c2ecf20Sopenharmony_ci bus->operation == I2C_READ_OPER && 12028c2ecf20Sopenharmony_ci bus->stop_ind == I2C_SLAVE_XMIT_IND) || 12038c2ecf20Sopenharmony_ci bus->stop_ind == I2C_SLAVE_RCV_IND) { 12048c2ecf20Sopenharmony_ci /* slave tx after slave rx w/o STOP */ 12058c2ecf20Sopenharmony_ci bus->stop_ind = I2C_SLAVE_RESTART_IND; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (NPCM_I2CST_XMIT & i2cst) 12108c2ecf20Sopenharmony_ci bus->stop_ind = I2C_SLAVE_XMIT_IND; 12118c2ecf20Sopenharmony_ci else 12128c2ecf20Sopenharmony_ci bus->stop_ind = I2C_SLAVE_RCV_IND; 12138c2ecf20Sopenharmony_ci bus->state = I2C_SLAVE_MATCH; 12148c2ecf20Sopenharmony_ci npcm_i2c_slave_rd_wr(bus); 12158c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CST_NMATCH, bus->reg + NPCM_I2CST); 12168c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci /* Slave SDA status is set - tx or rx */ 12208c2ecf20Sopenharmony_ci if ((NPCM_I2CST_SDAST & i2cst) || 12218c2ecf20Sopenharmony_ci (bus->fifo_use && 12228c2ecf20Sopenharmony_ci (npcm_i2c_tx_fifo_empty(bus) || npcm_i2c_rx_fifo_full(bus)))) { 12238c2ecf20Sopenharmony_ci npcm_i2c_slave_rd_wr(bus); 12248c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CST_SDAST, bus->reg + NPCM_I2CST); 12258c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 12268c2ecf20Sopenharmony_ci } /* SDAST */ 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* 12298c2ecf20Sopenharmony_ci * if irq is not one of the above, make sure EOB is disabled and all 12308c2ecf20Sopenharmony_ci * status bits are cleared. 12318c2ecf20Sopenharmony_ci */ 12328c2ecf20Sopenharmony_ci if (ret == IRQ_NONE) { 12338c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, false); 12348c2ecf20Sopenharmony_ci npcm_i2c_clear_master_status(bus); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic int npcm_i2c_reg_slave(struct i2c_client *client) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci unsigned long lock_flags; 12438c2ecf20Sopenharmony_ci struct npcm_i2c *bus = i2c_get_adapdata(client->adapter); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci bus->slave = client; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if (!bus->slave) 12488c2ecf20Sopenharmony_ci return -EINVAL; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (client->flags & I2C_CLIENT_TEN) 12518c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci spin_lock_irqsave(&bus->lock, lock_flags); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci npcm_i2c_init_params(bus); 12568c2ecf20Sopenharmony_ci bus->slv_rd_size = 0; 12578c2ecf20Sopenharmony_ci bus->slv_wr_size = 0; 12588c2ecf20Sopenharmony_ci bus->slv_rd_ind = 0; 12598c2ecf20Sopenharmony_ci bus->slv_wr_ind = 0; 12608c2ecf20Sopenharmony_ci if (client->flags & I2C_CLIENT_PEC) 12618c2ecf20Sopenharmony_ci bus->PEC_use = true; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci dev_info(bus->dev, "i2c%d register slave SA=0x%x, PEC=%d\n", bus->num, 12648c2ecf20Sopenharmony_ci client->addr, bus->PEC_use); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci npcm_i2c_slave_enable(bus, I2C_SLAVE_ADDR1, client->addr, true); 12678c2ecf20Sopenharmony_ci npcm_i2c_clear_fifo_int(bus); 12688c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 12698c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 12708c2ecf20Sopenharmony_ci npcm_i2c_slave_int_enable(bus, true); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bus->lock, lock_flags); 12738c2ecf20Sopenharmony_ci return 0; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cistatic int npcm_i2c_unreg_slave(struct i2c_client *client) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci struct npcm_i2c *bus = client->adapter->algo_data; 12798c2ecf20Sopenharmony_ci unsigned long lock_flags; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci spin_lock_irqsave(&bus->lock, lock_flags); 12828c2ecf20Sopenharmony_ci if (!bus->slave) { 12838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bus->lock, lock_flags); 12848c2ecf20Sopenharmony_ci return -EINVAL; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci npcm_i2c_slave_int_enable(bus, false); 12878c2ecf20Sopenharmony_ci npcm_i2c_remove_slave_addr(bus, client->addr); 12888c2ecf20Sopenharmony_ci bus->slave = NULL; 12898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bus->lock, lock_flags); 12908c2ecf20Sopenharmony_ci return 0; 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci#endif /* CONFIG_I2C_SLAVE */ 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic void npcm_i2c_master_fifo_read(struct npcm_i2c *bus) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci int rcount; 12978c2ecf20Sopenharmony_ci int fifo_bytes; 12988c2ecf20Sopenharmony_ci enum i2c_state_ind ind = I2C_MASTER_DONE_IND; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci fifo_bytes = npcm_i2c_fifo_usage(bus); 13018c2ecf20Sopenharmony_ci rcount = bus->rd_size - bus->rd_ind; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* 13048c2ecf20Sopenharmony_ci * In order not to change the RX_TRH during transaction (we found that 13058c2ecf20Sopenharmony_ci * this might be problematic if it takes too much time to read the FIFO) 13068c2ecf20Sopenharmony_ci * we read the data in the following way. If the number of bytes to 13078c2ecf20Sopenharmony_ci * read == FIFO Size + C (where C < FIFO Size)then first read C bytes 13088c2ecf20Sopenharmony_ci * and in the next int we read rest of the data. 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci if (rcount < (2 * I2C_HW_FIFO_SIZE) && rcount > I2C_HW_FIFO_SIZE) 13118c2ecf20Sopenharmony_ci fifo_bytes = rcount - I2C_HW_FIFO_SIZE; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (rcount <= fifo_bytes) { 13148c2ecf20Sopenharmony_ci /* last bytes are about to be read - end of tx */ 13158c2ecf20Sopenharmony_ci bus->state = I2C_STOP_PENDING; 13168c2ecf20Sopenharmony_ci bus->stop_ind = ind; 13178c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, true); 13188c2ecf20Sopenharmony_ci /* Stop should be set before reading last byte. */ 13198c2ecf20Sopenharmony_ci npcm_i2c_master_stop(bus); 13208c2ecf20Sopenharmony_ci npcm_i2c_read_fifo(bus, fifo_bytes); 13218c2ecf20Sopenharmony_ci } else { 13228c2ecf20Sopenharmony_ci npcm_i2c_read_fifo(bus, fifo_bytes); 13238c2ecf20Sopenharmony_ci rcount = bus->rd_size - bus->rd_ind; 13248c2ecf20Sopenharmony_ci npcm_i2c_set_fifo(bus, rcount, -1); 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_master_handler_write(struct npcm_i2c *bus) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci u16 wcount; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci if (bus->fifo_use) 13338c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); /* clear the TX fifo status bit */ 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* Master write operation - last byte handling */ 13368c2ecf20Sopenharmony_ci if (bus->wr_ind == bus->wr_size) { 13378c2ecf20Sopenharmony_ci if (bus->fifo_use && npcm_i2c_fifo_usage(bus) > 0) 13388c2ecf20Sopenharmony_ci /* 13398c2ecf20Sopenharmony_ci * No more bytes to send (to add to the FIFO), 13408c2ecf20Sopenharmony_ci * however the FIFO is not empty yet. It is 13418c2ecf20Sopenharmony_ci * still in the middle of tx. Currently there's nothing 13428c2ecf20Sopenharmony_ci * to do except for waiting to the end of the tx 13438c2ecf20Sopenharmony_ci * We will get an int when the FIFO will get empty. 13448c2ecf20Sopenharmony_ci */ 13458c2ecf20Sopenharmony_ci return; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (bus->rd_size == 0) { 13488c2ecf20Sopenharmony_ci /* all bytes have been written, in wr only operation */ 13498c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, true); 13508c2ecf20Sopenharmony_ci bus->state = I2C_STOP_PENDING; 13518c2ecf20Sopenharmony_ci bus->stop_ind = I2C_MASTER_DONE_IND; 13528c2ecf20Sopenharmony_ci npcm_i2c_master_stop(bus); 13538c2ecf20Sopenharmony_ci /* Clear SDA Status bit (by writing dummy byte) */ 13548c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, 0xFF); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci } else { 13578c2ecf20Sopenharmony_ci /* last write-byte written on previous int - restart */ 13588c2ecf20Sopenharmony_ci npcm_i2c_set_fifo(bus, bus->rd_size, -1); 13598c2ecf20Sopenharmony_ci /* Generate repeated start upon next write to SDA */ 13608c2ecf20Sopenharmony_ci npcm_i2c_master_start(bus); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci /* 13638c2ecf20Sopenharmony_ci * Receiving one byte only - stall after successful 13648c2ecf20Sopenharmony_ci * completion of send address byte. If we NACK here, and 13658c2ecf20Sopenharmony_ci * slave doesn't ACK the address, we might 13668c2ecf20Sopenharmony_ci * unintentionally NACK the next multi-byte read. 13678c2ecf20Sopenharmony_ci */ 13688c2ecf20Sopenharmony_ci if (bus->rd_size == 1) 13698c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, true); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci /* Next int will occur on read */ 13728c2ecf20Sopenharmony_ci bus->operation = I2C_READ_OPER; 13738c2ecf20Sopenharmony_ci /* send the slave address in read direction */ 13748c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, bus->dest_addr | 0x1); 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci } else { 13778c2ecf20Sopenharmony_ci /* write next byte not last byte and not slave address */ 13788c2ecf20Sopenharmony_ci if (!bus->fifo_use || bus->wr_size == 1) { 13798c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, bus->wr_buf[bus->wr_ind++]); 13808c2ecf20Sopenharmony_ci } else { 13818c2ecf20Sopenharmony_ci wcount = bus->wr_size - bus->wr_ind; 13828c2ecf20Sopenharmony_ci npcm_i2c_set_fifo(bus, -1, wcount); 13838c2ecf20Sopenharmony_ci if (wcount) 13848c2ecf20Sopenharmony_ci npcm_i2c_write_to_fifo_master(bus, wcount); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_master_handler_read(struct npcm_i2c *bus) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci u16 block_extra_bytes_size; 13928c2ecf20Sopenharmony_ci u8 data; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci /* added bytes to the packet: */ 13958c2ecf20Sopenharmony_ci block_extra_bytes_size = bus->read_block_use + bus->PEC_use; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* 13988c2ecf20Sopenharmony_ci * Perform master read, distinguishing between last byte and the rest of 13998c2ecf20Sopenharmony_ci * the bytes. The last byte should be read when the clock is stopped 14008c2ecf20Sopenharmony_ci */ 14018c2ecf20Sopenharmony_ci if (bus->rd_ind == 0) { /* first byte handling: */ 14028c2ecf20Sopenharmony_ci if (bus->read_block_use) { 14038c2ecf20Sopenharmony_ci /* first byte in block protocol is the size: */ 14048c2ecf20Sopenharmony_ci data = npcm_i2c_rd_byte(bus); 14058c2ecf20Sopenharmony_ci data = clamp_val(data, 1, I2C_SMBUS_BLOCK_MAX); 14068c2ecf20Sopenharmony_ci bus->rd_size = data + block_extra_bytes_size; 14078c2ecf20Sopenharmony_ci bus->rd_buf[bus->rd_ind++] = data; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* clear RX FIFO interrupt status: */ 14108c2ecf20Sopenharmony_ci if (bus->fifo_use) { 14118c2ecf20Sopenharmony_ci data = ioread8(bus->reg + NPCM_I2CFIF_CTS); 14128c2ecf20Sopenharmony_ci data = data | NPCM_I2CFIF_CTS_RXF_TXE; 14138c2ecf20Sopenharmony_ci iowrite8(data, bus->reg + NPCM_I2CFIF_CTS); 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci npcm_i2c_set_fifo(bus, bus->rd_size - 1, -1); 14178c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, false); 14188c2ecf20Sopenharmony_ci } else { 14198c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 14208c2ecf20Sopenharmony_ci npcm_i2c_master_fifo_read(bus); 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci } else { 14238c2ecf20Sopenharmony_ci if (bus->rd_size == block_extra_bytes_size && 14248c2ecf20Sopenharmony_ci bus->read_block_use) { 14258c2ecf20Sopenharmony_ci bus->state = I2C_STOP_PENDING; 14268c2ecf20Sopenharmony_ci bus->stop_ind = I2C_BLOCK_BYTES_ERR_IND; 14278c2ecf20Sopenharmony_ci bus->cmd_err = -EIO; 14288c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, true); 14298c2ecf20Sopenharmony_ci npcm_i2c_master_stop(bus); 14308c2ecf20Sopenharmony_ci npcm_i2c_read_fifo(bus, npcm_i2c_fifo_usage(bus)); 14318c2ecf20Sopenharmony_ci } else { 14328c2ecf20Sopenharmony_ci npcm_i2c_master_fifo_read(bus); 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_handle_nmatch(struct npcm_i2c *bus) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CST_NMATCH, bus->reg + NPCM_I2CST); 14408c2ecf20Sopenharmony_ci npcm_i2c_nack(bus); 14418c2ecf20Sopenharmony_ci bus->stop_ind = I2C_BUS_ERR_IND; 14428c2ecf20Sopenharmony_ci npcm_i2c_callback(bus, bus->stop_ind, npcm_i2c_get_index(bus)); 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci/* A NACK has occurred */ 14468c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci u8 val; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (bus->nack_cnt < ULLONG_MAX) 14518c2ecf20Sopenharmony_ci bus->nack_cnt++; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci if (bus->fifo_use) { 14548c2ecf20Sopenharmony_ci /* 14558c2ecf20Sopenharmony_ci * if there are still untransmitted bytes in TX FIFO 14568c2ecf20Sopenharmony_ci * reduce them from wr_ind 14578c2ecf20Sopenharmony_ci */ 14588c2ecf20Sopenharmony_ci if (bus->operation == I2C_WRITE_OPER) 14598c2ecf20Sopenharmony_ci bus->wr_ind -= npcm_i2c_fifo_usage(bus); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci /* clear the FIFO */ 14628c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS); 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* In master write operation, got unexpected NACK */ 14668c2ecf20Sopenharmony_ci bus->stop_ind = I2C_NACK_IND; 14678c2ecf20Sopenharmony_ci /* Only current master is allowed to issue Stop Condition */ 14688c2ecf20Sopenharmony_ci if (npcm_i2c_is_master(bus)) { 14698c2ecf20Sopenharmony_ci /* stopping in the middle */ 14708c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, false); 14718c2ecf20Sopenharmony_ci npcm_i2c_master_stop(bus); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci /* Clear SDA Status bit (by reading dummy byte) */ 14748c2ecf20Sopenharmony_ci npcm_i2c_rd_byte(bus); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* 14778c2ecf20Sopenharmony_ci * The bus is released from stall only after the SW clears 14788c2ecf20Sopenharmony_ci * NEGACK bit. Then a Stop condition is sent. 14798c2ecf20Sopenharmony_ci */ 14808c2ecf20Sopenharmony_ci npcm_i2c_clear_master_status(bus); 14818c2ecf20Sopenharmony_ci readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val, 14828c2ecf20Sopenharmony_ci !(val & NPCM_I2CCST_BUSY), 10, 200); 14838c2ecf20Sopenharmony_ci /* verify no status bits are still set after bus is released */ 14848c2ecf20Sopenharmony_ci npcm_i2c_clear_master_status(bus); 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* 14898c2ecf20Sopenharmony_ci * In Master mode, NACK should be cleared only after STOP. 14908c2ecf20Sopenharmony_ci * In such case, the bus is released from stall only after the 14918c2ecf20Sopenharmony_ci * software clears NACK bit. Then a Stop condition is sent. 14928c2ecf20Sopenharmony_ci */ 14938c2ecf20Sopenharmony_ci npcm_i2c_callback(bus, bus->stop_ind, bus->wr_ind); 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci /* Master mode: a Bus Error has been identified */ 14978c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci if (bus->ber_cnt < ULLONG_MAX) 15008c2ecf20Sopenharmony_ci bus->ber_cnt++; 15018c2ecf20Sopenharmony_ci bus->stop_ind = I2C_BUS_ERR_IND; 15028c2ecf20Sopenharmony_ci if (npcm_i2c_is_master(bus)) { 15038c2ecf20Sopenharmony_ci npcm_i2c_master_abort(bus); 15048c2ecf20Sopenharmony_ci } else { 15058c2ecf20Sopenharmony_ci npcm_i2c_clear_master_status(bus); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* Clear BB (BUS BUSY) bit */ 15088c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci bus->cmd_err = -EAGAIN; 15118c2ecf20Sopenharmony_ci npcm_i2c_callback(bus, bus->stop_ind, npcm_i2c_get_index(bus)); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* EOB: a master End Of Busy (meaning STOP completed) */ 15178c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_handle_eob(struct npcm_i2c *bus) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, false); 15208c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 15218c2ecf20Sopenharmony_ci npcm_i2c_callback(bus, bus->stop_ind, bus->rd_ind); 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci/* Address sent and requested stall occurred (Master mode) */ 15258c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_handle_stall_after_start(struct npcm_i2c *bus) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci if (npcm_i2c_is_quick(bus)) { 15288c2ecf20Sopenharmony_ci bus->state = I2C_STOP_PENDING; 15298c2ecf20Sopenharmony_ci bus->stop_ind = I2C_MASTER_DONE_IND; 15308c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, true); 15318c2ecf20Sopenharmony_ci npcm_i2c_master_stop(bus); 15328c2ecf20Sopenharmony_ci } else if ((bus->rd_size == 1) && !bus->read_block_use) { 15338c2ecf20Sopenharmony_ci /* 15348c2ecf20Sopenharmony_ci * Receiving one byte only - set NACK after ensuring 15358c2ecf20Sopenharmony_ci * slave ACKed the address byte. 15368c2ecf20Sopenharmony_ci */ 15378c2ecf20Sopenharmony_ci npcm_i2c_nack(bus); 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci /* Reset stall-after-address-byte */ 15418c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, false); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci /* Clear stall only after setting STOP */ 15448c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CST_STASTR, bus->reg + NPCM_I2CST); 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci/* SDA status is set - TX or RX, master */ 15488c2ecf20Sopenharmony_cistatic void npcm_i2c_irq_handle_sda(struct npcm_i2c *bus, u8 i2cst) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci u8 fif_cts; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (!npcm_i2c_is_master(bus)) 15538c2ecf20Sopenharmony_ci return; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (bus->state == I2C_IDLE) { 15568c2ecf20Sopenharmony_ci bus->stop_ind = I2C_WAKE_UP_IND; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci if (npcm_i2c_is_quick(bus) || bus->read_block_use) 15598c2ecf20Sopenharmony_ci /* 15608c2ecf20Sopenharmony_ci * Need to stall after successful 15618c2ecf20Sopenharmony_ci * completion of sending address byte 15628c2ecf20Sopenharmony_ci */ 15638c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, true); 15648c2ecf20Sopenharmony_ci else 15658c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, false); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* 15688c2ecf20Sopenharmony_ci * Receiving one byte only - stall after successful completion 15698c2ecf20Sopenharmony_ci * of sending address byte If we NACK here, and slave doesn't 15708c2ecf20Sopenharmony_ci * ACK the address, we might unintentionally NACK the next 15718c2ecf20Sopenharmony_ci * multi-byte read 15728c2ecf20Sopenharmony_ci */ 15738c2ecf20Sopenharmony_ci if (bus->wr_size == 0 && bus->rd_size == 1) 15748c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, true); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci /* Initiate I2C master tx */ 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci /* select bank 1 for FIFO regs */ 15798c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_1); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci fif_cts = ioread8(bus->reg + NPCM_I2CFIF_CTS); 15828c2ecf20Sopenharmony_ci fif_cts = fif_cts & ~NPCM_I2CFIF_CTS_SLVRSTR; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* clear FIFO and relevant status bits. */ 15858c2ecf20Sopenharmony_ci fif_cts = fif_cts | NPCM_I2CFIF_CTS_CLR_FIFO; 15868c2ecf20Sopenharmony_ci iowrite8(fif_cts, bus->reg + NPCM_I2CFIF_CTS); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci /* re-enable */ 15898c2ecf20Sopenharmony_ci fif_cts = fif_cts | NPCM_I2CFIF_CTS_RXF_TXE; 15908c2ecf20Sopenharmony_ci iowrite8(fif_cts, bus->reg + NPCM_I2CFIF_CTS); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* 15938c2ecf20Sopenharmony_ci * Configure the FIFO threshold: 15948c2ecf20Sopenharmony_ci * according to the needed # of bytes to read. 15958c2ecf20Sopenharmony_ci * Note: due to HW limitation can't config the rx fifo before it 15968c2ecf20Sopenharmony_ci * got and ACK on the restart. LAST bit will not be reset unless 15978c2ecf20Sopenharmony_ci * RX completed. It will stay set on the next tx. 15988c2ecf20Sopenharmony_ci */ 15998c2ecf20Sopenharmony_ci if (bus->wr_size) 16008c2ecf20Sopenharmony_ci npcm_i2c_set_fifo(bus, -1, bus->wr_size); 16018c2ecf20Sopenharmony_ci else 16028c2ecf20Sopenharmony_ci npcm_i2c_set_fifo(bus, bus->rd_size, -1); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci bus->state = I2C_OPER_STARTED; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (npcm_i2c_is_quick(bus) || bus->wr_size) 16078c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, bus->dest_addr); 16088c2ecf20Sopenharmony_ci else 16098c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, bus->dest_addr | BIT(0)); 16108c2ecf20Sopenharmony_ci /* SDA interrupt, after start\restart */ 16118c2ecf20Sopenharmony_ci } else { 16128c2ecf20Sopenharmony_ci if (NPCM_I2CST_XMIT & i2cst) { 16138c2ecf20Sopenharmony_ci bus->operation = I2C_WRITE_OPER; 16148c2ecf20Sopenharmony_ci npcm_i2c_irq_master_handler_write(bus); 16158c2ecf20Sopenharmony_ci } else { 16168c2ecf20Sopenharmony_ci bus->operation = I2C_READ_OPER; 16178c2ecf20Sopenharmony_ci npcm_i2c_irq_master_handler_read(bus); 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic int npcm_i2c_int_master_handler(struct npcm_i2c *bus) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci u8 i2cst; 16258c2ecf20Sopenharmony_ci int ret = -EIO; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci i2cst = ioread8(bus->reg + NPCM_I2CST); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci if (FIELD_GET(NPCM_I2CST_NMATCH, i2cst)) { 16308c2ecf20Sopenharmony_ci npcm_i2c_irq_handle_nmatch(bus); 16318c2ecf20Sopenharmony_ci return 0; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci /* A NACK has occurred */ 16348c2ecf20Sopenharmony_ci if (FIELD_GET(NPCM_I2CST_NEGACK, i2cst)) { 16358c2ecf20Sopenharmony_ci npcm_i2c_irq_handle_nack(bus); 16368c2ecf20Sopenharmony_ci return 0; 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* Master mode: a Bus Error has been identified */ 16408c2ecf20Sopenharmony_ci if (FIELD_GET(NPCM_I2CST_BER, i2cst)) { 16418c2ecf20Sopenharmony_ci npcm_i2c_irq_handle_ber(bus); 16428c2ecf20Sopenharmony_ci return 0; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* EOB: a master End Of Busy (meaning STOP completed) */ 16468c2ecf20Sopenharmony_ci if ((FIELD_GET(NPCM_I2CCTL1_EOBINTE, 16478c2ecf20Sopenharmony_ci ioread8(bus->reg + NPCM_I2CCTL1)) == 1) && 16488c2ecf20Sopenharmony_ci (FIELD_GET(NPCM_I2CCST3_EO_BUSY, 16498c2ecf20Sopenharmony_ci ioread8(bus->reg + NPCM_I2CCST3)))) { 16508c2ecf20Sopenharmony_ci npcm_i2c_irq_handle_eob(bus); 16518c2ecf20Sopenharmony_ci return 0; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci /* Address sent and requested stall occurred (Master mode) */ 16558c2ecf20Sopenharmony_ci if (FIELD_GET(NPCM_I2CST_STASTR, i2cst)) { 16568c2ecf20Sopenharmony_ci npcm_i2c_irq_handle_stall_after_start(bus); 16578c2ecf20Sopenharmony_ci ret = 0; 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci /* SDA status is set - TX or RX, master */ 16618c2ecf20Sopenharmony_ci if (FIELD_GET(NPCM_I2CST_SDAST, i2cst) || 16628c2ecf20Sopenharmony_ci (bus->fifo_use && 16638c2ecf20Sopenharmony_ci (npcm_i2c_tx_fifo_empty(bus) || npcm_i2c_rx_fifo_full(bus)))) { 16648c2ecf20Sopenharmony_ci npcm_i2c_irq_handle_sda(bus, i2cst); 16658c2ecf20Sopenharmony_ci ret = 0; 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci return ret; 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci/* recovery using TGCLK functionality of the module */ 16728c2ecf20Sopenharmony_cistatic int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci u8 val; 16758c2ecf20Sopenharmony_ci u8 fif_cts; 16768c2ecf20Sopenharmony_ci bool done = false; 16778c2ecf20Sopenharmony_ci int status = -ENOTRECOVERABLE; 16788c2ecf20Sopenharmony_ci struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); 16798c2ecf20Sopenharmony_ci /* Allow 3 bytes (27 toggles) to be read from the slave: */ 16808c2ecf20Sopenharmony_ci int iter = 27; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) { 16838c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck", 16848c2ecf20Sopenharmony_ci bus->num, bus->dest_addr); 16858c2ecf20Sopenharmony_ci npcm_i2c_reset(bus); 16868c2ecf20Sopenharmony_ci return 0; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci npcm_i2c_int_enable(bus, false); 16908c2ecf20Sopenharmony_ci npcm_i2c_disable(bus); 16918c2ecf20Sopenharmony_ci npcm_i2c_enable(bus); 16928c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); 16938c2ecf20Sopenharmony_ci npcm_i2c_clear_tx_fifo(bus); 16948c2ecf20Sopenharmony_ci npcm_i2c_clear_rx_fifo(bus); 16958c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + NPCM_I2CRXF_CTL); 16968c2ecf20Sopenharmony_ci iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); 16978c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, false); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci /* select bank 1 for FIFO regs */ 17008c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_1); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* clear FIFO and relevant status bits. */ 17038c2ecf20Sopenharmony_ci fif_cts = ioread8(bus->reg + NPCM_I2CFIF_CTS); 17048c2ecf20Sopenharmony_ci fif_cts &= ~NPCM_I2CFIF_CTS_SLVRSTR; 17058c2ecf20Sopenharmony_ci fif_cts |= NPCM_I2CFIF_CTS_CLR_FIFO; 17068c2ecf20Sopenharmony_ci iowrite8(fif_cts, bus->reg + NPCM_I2CFIF_CTS); 17078c2ecf20Sopenharmony_ci npcm_i2c_set_fifo(bus, -1, 0); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci /* Repeat the following sequence until SDA is released */ 17108c2ecf20Sopenharmony_ci do { 17118c2ecf20Sopenharmony_ci /* Issue a single SCL toggle */ 17128c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CCST_TGSCL, bus->reg + NPCM_I2CCST); 17138c2ecf20Sopenharmony_ci usleep_range(20, 30); 17148c2ecf20Sopenharmony_ci /* If SDA line is inactive (high), stop */ 17158c2ecf20Sopenharmony_ci if (npcm_i2c_get_SDA(_adap)) { 17168c2ecf20Sopenharmony_ci done = true; 17178c2ecf20Sopenharmony_ci status = 0; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci } while (!done && iter--); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* If SDA line is released: send start-addr-stop, to re-sync. */ 17228c2ecf20Sopenharmony_ci if (npcm_i2c_get_SDA(_adap)) { 17238c2ecf20Sopenharmony_ci /* Send an address byte in write direction: */ 17248c2ecf20Sopenharmony_ci npcm_i2c_wr_byte(bus, bus->dest_addr); 17258c2ecf20Sopenharmony_ci npcm_i2c_master_start(bus); 17268c2ecf20Sopenharmony_ci /* Wait until START condition is sent */ 17278c2ecf20Sopenharmony_ci status = readx_poll_timeout(npcm_i2c_get_SCL, _adap, val, !val, 17288c2ecf20Sopenharmony_ci 20, 200); 17298c2ecf20Sopenharmony_ci /* If START condition was sent */ 17308c2ecf20Sopenharmony_ci if (npcm_i2c_is_master(bus) > 0) { 17318c2ecf20Sopenharmony_ci usleep_range(20, 30); 17328c2ecf20Sopenharmony_ci npcm_i2c_master_stop(bus); 17338c2ecf20Sopenharmony_ci usleep_range(200, 500); 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci npcm_i2c_reset(bus); 17378c2ecf20Sopenharmony_ci npcm_i2c_int_enable(bus, true); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) 17408c2ecf20Sopenharmony_ci status = 0; 17418c2ecf20Sopenharmony_ci else 17428c2ecf20Sopenharmony_ci status = -ENOTRECOVERABLE; 17438c2ecf20Sopenharmony_ci if (status) { 17448c2ecf20Sopenharmony_ci if (bus->rec_fail_cnt < ULLONG_MAX) 17458c2ecf20Sopenharmony_ci bus->rec_fail_cnt++; 17468c2ecf20Sopenharmony_ci } else { 17478c2ecf20Sopenharmony_ci if (bus->rec_succ_cnt < ULLONG_MAX) 17488c2ecf20Sopenharmony_ci bus->rec_succ_cnt++; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci return status; 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci/* recovery using bit banging functionality of the module */ 17548c2ecf20Sopenharmony_cistatic void npcm_i2c_recovery_init(struct i2c_adapter *_adap) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); 17578c2ecf20Sopenharmony_ci struct i2c_bus_recovery_info *rinfo = &bus->rinfo; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci rinfo->recover_bus = npcm_i2c_recovery_tgclk; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* 17628c2ecf20Sopenharmony_ci * npcm i2c HW allows direct reading of SCL and SDA. 17638c2ecf20Sopenharmony_ci * However, it does not support setting SCL and SDA directly. 17648c2ecf20Sopenharmony_ci * The recovery function can togle SCL when SDA is low (but not set) 17658c2ecf20Sopenharmony_ci * Getter functions used internally, and can be used externaly. 17668c2ecf20Sopenharmony_ci */ 17678c2ecf20Sopenharmony_ci rinfo->get_scl = npcm_i2c_get_SCL; 17688c2ecf20Sopenharmony_ci rinfo->get_sda = npcm_i2c_get_SDA; 17698c2ecf20Sopenharmony_ci _adap->bus_recovery_info = rinfo; 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci/* SCLFRQ min/max field values */ 17738c2ecf20Sopenharmony_ci#define SCLFRQ_MIN 10 17748c2ecf20Sopenharmony_ci#define SCLFRQ_MAX 511 17758c2ecf20Sopenharmony_ci#define clk_coef(freq, mul) DIV_ROUND_UP((freq) * (mul), 1000000) 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci/* 17788c2ecf20Sopenharmony_ci * npcm_i2c_init_clk: init HW timing parameters. 17798c2ecf20Sopenharmony_ci * NPCM7XX i2c module timing parameters are depenent on module core clk (APB) 17808c2ecf20Sopenharmony_ci * and bus frequency. 17818c2ecf20Sopenharmony_ci * 100kHz bus requires tSCL = 4 * SCLFRQ * tCLK. LT and HT are simetric. 17828c2ecf20Sopenharmony_ci * 400kHz bus requires assymetric HT and LT. A different equation is recomended 17838c2ecf20Sopenharmony_ci * by the HW designer, given core clock range (equations in comments below). 17848c2ecf20Sopenharmony_ci * 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_cistatic int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci u32 k1 = 0; 17898c2ecf20Sopenharmony_ci u32 k2 = 0; 17908c2ecf20Sopenharmony_ci u8 dbnct = 0; 17918c2ecf20Sopenharmony_ci u32 sclfrq = 0; 17928c2ecf20Sopenharmony_ci u8 hldt = 7; 17938c2ecf20Sopenharmony_ci u8 fast_mode = 0; 17948c2ecf20Sopenharmony_ci u32 src_clk_khz; 17958c2ecf20Sopenharmony_ci u32 bus_freq_khz; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci src_clk_khz = bus->apb_clk / 1000; 17988c2ecf20Sopenharmony_ci bus_freq_khz = bus_freq_hz / 1000; 17998c2ecf20Sopenharmony_ci bus->bus_freq = bus_freq_hz; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci /* 100KHz and below: */ 18028c2ecf20Sopenharmony_ci if (bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ) { 18038c2ecf20Sopenharmony_ci sclfrq = src_clk_khz / (bus_freq_khz * 4); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (sclfrq < SCLFRQ_MIN || sclfrq > SCLFRQ_MAX) 18068c2ecf20Sopenharmony_ci return -EDOM; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (src_clk_khz >= 40000) 18098c2ecf20Sopenharmony_ci hldt = 17; 18108c2ecf20Sopenharmony_ci else if (src_clk_khz >= 12500) 18118c2ecf20Sopenharmony_ci hldt = 15; 18128c2ecf20Sopenharmony_ci else 18138c2ecf20Sopenharmony_ci hldt = 7; 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* 400KHz: */ 18178c2ecf20Sopenharmony_ci else if (bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ) { 18188c2ecf20Sopenharmony_ci sclfrq = 0; 18198c2ecf20Sopenharmony_ci fast_mode = I2CCTL3_400K_MODE; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci if (src_clk_khz < 7500) 18228c2ecf20Sopenharmony_ci /* 400KHZ cannot be supported for core clock < 7.5MHz */ 18238c2ecf20Sopenharmony_ci return -EDOM; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci else if (src_clk_khz >= 50000) { 18268c2ecf20Sopenharmony_ci k1 = 80; 18278c2ecf20Sopenharmony_ci k2 = 48; 18288c2ecf20Sopenharmony_ci hldt = 12; 18298c2ecf20Sopenharmony_ci dbnct = 7; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* Master or Slave with frequency > 25MHz */ 18338c2ecf20Sopenharmony_ci else if (src_clk_khz > 25000) { 18348c2ecf20Sopenharmony_ci hldt = clk_coef(src_clk_khz, 300) + 7; 18358c2ecf20Sopenharmony_ci k1 = clk_coef(src_clk_khz, 1600); 18368c2ecf20Sopenharmony_ci k2 = clk_coef(src_clk_khz, 900); 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci /* 1MHz: */ 18418c2ecf20Sopenharmony_ci else if (bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ) { 18428c2ecf20Sopenharmony_ci sclfrq = 0; 18438c2ecf20Sopenharmony_ci fast_mode = I2CCTL3_400K_MODE; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci /* 1MHZ cannot be supported for core clock < 24 MHz */ 18468c2ecf20Sopenharmony_ci if (src_clk_khz < 24000) 18478c2ecf20Sopenharmony_ci return -EDOM; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci k1 = clk_coef(src_clk_khz, 620); 18508c2ecf20Sopenharmony_ci k2 = clk_coef(src_clk_khz, 380); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci /* Core clk > 40 MHz */ 18538c2ecf20Sopenharmony_ci if (src_clk_khz > 40000) { 18548c2ecf20Sopenharmony_ci /* 18558c2ecf20Sopenharmony_ci * Set HLDT: 18568c2ecf20Sopenharmony_ci * SDA hold time: (HLDT-7) * T(CLK) >= 120 18578c2ecf20Sopenharmony_ci * HLDT = 120/T(CLK) + 7 = 120 * FREQ(CLK) + 7 18588c2ecf20Sopenharmony_ci */ 18598c2ecf20Sopenharmony_ci hldt = clk_coef(src_clk_khz, 120) + 7; 18608c2ecf20Sopenharmony_ci } else { 18618c2ecf20Sopenharmony_ci hldt = 7; 18628c2ecf20Sopenharmony_ci dbnct = 2; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci /* Frequency larger than 1 MHz is not supported */ 18678c2ecf20Sopenharmony_ci else 18688c2ecf20Sopenharmony_ci return -EINVAL; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (bus_freq_hz >= I2C_MAX_FAST_MODE_FREQ) { 18718c2ecf20Sopenharmony_ci k1 = round_up(k1, 2); 18728c2ecf20Sopenharmony_ci k2 = round_up(k2 + 1, 2); 18738c2ecf20Sopenharmony_ci if (k1 < SCLFRQ_MIN || k1 > SCLFRQ_MAX || 18748c2ecf20Sopenharmony_ci k2 < SCLFRQ_MIN || k2 > SCLFRQ_MAX) 18758c2ecf20Sopenharmony_ci return -EDOM; 18768c2ecf20Sopenharmony_ci } 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci /* write sclfrq value. bits [6:0] are in I2CCTL2 reg */ 18798c2ecf20Sopenharmony_ci iowrite8(FIELD_PREP(I2CCTL2_SCLFRQ6_0, sclfrq & 0x7F), 18808c2ecf20Sopenharmony_ci bus->reg + NPCM_I2CCTL2); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci /* bits [8:7] are in I2CCTL3 reg */ 18838c2ecf20Sopenharmony_ci iowrite8(fast_mode | FIELD_PREP(I2CCTL3_SCLFRQ8_7, (sclfrq >> 7) & 0x3), 18848c2ecf20Sopenharmony_ci bus->reg + NPCM_I2CCTL3); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci /* Select Bank 0 to access NPCM_I2CCTL4/NPCM_I2CCTL5 */ 18878c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_0); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci if (bus_freq_hz >= I2C_MAX_FAST_MODE_FREQ) { 18908c2ecf20Sopenharmony_ci /* 18918c2ecf20Sopenharmony_ci * Set SCL Low/High Time: 18928c2ecf20Sopenharmony_ci * k1 = 2 * SCLLT7-0 -> Low Time = k1 / 2 18938c2ecf20Sopenharmony_ci * k2 = 2 * SCLLT7-0 -> High Time = k2 / 2 18948c2ecf20Sopenharmony_ci */ 18958c2ecf20Sopenharmony_ci iowrite8(k1 / 2, bus->reg + NPCM_I2CSCLLT); 18968c2ecf20Sopenharmony_ci iowrite8(k2 / 2, bus->reg + NPCM_I2CSCLHT); 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci iowrite8(dbnct, bus->reg + NPCM_I2CCTL5); 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci iowrite8(hldt, bus->reg + NPCM_I2CCTL4); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci /* Return to Bank 1, and stay there by default: */ 19048c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_1); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci return 0; 19078c2ecf20Sopenharmony_ci} 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_cistatic int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode, 19108c2ecf20Sopenharmony_ci u32 bus_freq_hz) 19118c2ecf20Sopenharmony_ci{ 19128c2ecf20Sopenharmony_ci u8 val; 19138c2ecf20Sopenharmony_ci int ret; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci /* Check whether module already enabled or frequency is out of bounds */ 19168c2ecf20Sopenharmony_ci if ((bus->state != I2C_DISABLE && bus->state != I2C_IDLE) || 19178c2ecf20Sopenharmony_ci bus_freq_hz < I2C_FREQ_MIN_HZ || bus_freq_hz > I2C_FREQ_MAX_HZ) 19188c2ecf20Sopenharmony_ci return -EINVAL; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci npcm_i2c_int_enable(bus, false); 19218c2ecf20Sopenharmony_ci npcm_i2c_disable(bus); 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci /* Configure FIFO mode : */ 19248c2ecf20Sopenharmony_ci if (FIELD_GET(I2C_VER_FIFO_EN, ioread8(bus->reg + I2C_VER))) { 19258c2ecf20Sopenharmony_ci bus->fifo_use = true; 19268c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_0); 19278c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CFIF_CTL); 19288c2ecf20Sopenharmony_ci val |= NPCM_I2CFIF_CTL_FIFO_EN; 19298c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CFIF_CTL); 19308c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_1); 19318c2ecf20Sopenharmony_ci } else { 19328c2ecf20Sopenharmony_ci bus->fifo_use = false; 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci /* Configure I2C module clock frequency */ 19368c2ecf20Sopenharmony_ci ret = npcm_i2c_init_clk(bus, bus_freq_hz); 19378c2ecf20Sopenharmony_ci if (ret) { 19388c2ecf20Sopenharmony_ci dev_err(bus->dev, "npcm_i2c_init_clk failed\n"); 19398c2ecf20Sopenharmony_ci return ret; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* Enable module (before configuring CTL1) */ 19438c2ecf20Sopenharmony_ci npcm_i2c_enable(bus); 19448c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 19458c2ecf20Sopenharmony_ci val = ioread8(bus->reg + NPCM_I2CCTL1); 19468c2ecf20Sopenharmony_ci val = (val | NPCM_I2CCTL1_NMINTE) & ~NPCM_I2CCTL1_RWS; 19478c2ecf20Sopenharmony_ci iowrite8(val, bus->reg + NPCM_I2CCTL1); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci npcm_i2c_reset(bus); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* check HW is OK: SDA and SCL should be high at this point. */ 19528c2ecf20Sopenharmony_ci if ((npcm_i2c_get_SDA(&bus->adap) == 0) || (npcm_i2c_get_SCL(&bus->adap) == 0)) { 19538c2ecf20Sopenharmony_ci dev_err(bus->dev, "I2C%d init fail: lines are low\n", bus->num); 19548c2ecf20Sopenharmony_ci dev_err(bus->dev, "SDA=%d SCL=%d\n", npcm_i2c_get_SDA(&bus->adap), 19558c2ecf20Sopenharmony_ci npcm_i2c_get_SCL(&bus->adap)); 19568c2ecf20Sopenharmony_ci return -ENXIO; 19578c2ecf20Sopenharmony_ci } 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci npcm_i2c_int_enable(bus, true); 19608c2ecf20Sopenharmony_ci return 0; 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_cistatic int __npcm_i2c_init(struct npcm_i2c *bus, struct platform_device *pdev) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci u32 clk_freq_hz; 19668c2ecf20Sopenharmony_ci int ret; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci /* Initialize the internal data structures */ 19698c2ecf20Sopenharmony_ci bus->state = I2C_DISABLE; 19708c2ecf20Sopenharmony_ci bus->master_or_slave = I2C_SLAVE; 19718c2ecf20Sopenharmony_ci bus->int_time_stamp = 0; 19728c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 19738c2ecf20Sopenharmony_ci bus->slave = NULL; 19748c2ecf20Sopenharmony_ci#endif 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci ret = device_property_read_u32(&pdev->dev, "clock-frequency", 19778c2ecf20Sopenharmony_ci &clk_freq_hz); 19788c2ecf20Sopenharmony_ci if (ret) { 19798c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Could not read clock-frequency property"); 19808c2ecf20Sopenharmony_ci clk_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci ret = npcm_i2c_init_module(bus, I2C_MASTER, clk_freq_hz); 19848c2ecf20Sopenharmony_ci if (ret) { 19858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "npcm_i2c_init_module failed\n"); 19868c2ecf20Sopenharmony_ci return ret; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci return 0; 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cistatic irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id) 19938c2ecf20Sopenharmony_ci{ 19948c2ecf20Sopenharmony_ci struct npcm_i2c *bus = dev_id; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (npcm_i2c_is_master(bus)) 19978c2ecf20Sopenharmony_ci bus->master_or_slave = I2C_MASTER; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci if (bus->master_or_slave == I2C_MASTER) { 20008c2ecf20Sopenharmony_ci bus->int_time_stamp = jiffies; 20018c2ecf20Sopenharmony_ci if (!npcm_i2c_int_master_handler(bus)) 20028c2ecf20Sopenharmony_ci return IRQ_HANDLED; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 20058c2ecf20Sopenharmony_ci if (bus->slave) { 20068c2ecf20Sopenharmony_ci bus->master_or_slave = I2C_SLAVE; 20078c2ecf20Sopenharmony_ci if (npcm_i2c_int_slave_handler(bus)) 20088c2ecf20Sopenharmony_ci return IRQ_HANDLED; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci#endif 20118c2ecf20Sopenharmony_ci /* clear status bits for spurious interrupts */ 20128c2ecf20Sopenharmony_ci npcm_i2c_clear_master_status(bus); 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci return IRQ_HANDLED; 20158c2ecf20Sopenharmony_ci} 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_cistatic bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus, 20188c2ecf20Sopenharmony_ci u8 slave_addr, u16 nwrite, u16 nread, 20198c2ecf20Sopenharmony_ci u8 *write_data, u8 *read_data, 20208c2ecf20Sopenharmony_ci bool use_PEC, bool use_read_block) 20218c2ecf20Sopenharmony_ci{ 20228c2ecf20Sopenharmony_ci if (bus->state != I2C_IDLE) { 20238c2ecf20Sopenharmony_ci bus->cmd_err = -EBUSY; 20248c2ecf20Sopenharmony_ci return false; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci bus->dest_addr = slave_addr << 1; 20278c2ecf20Sopenharmony_ci bus->wr_buf = write_data; 20288c2ecf20Sopenharmony_ci bus->wr_size = nwrite; 20298c2ecf20Sopenharmony_ci bus->wr_ind = 0; 20308c2ecf20Sopenharmony_ci bus->rd_buf = read_data; 20318c2ecf20Sopenharmony_ci bus->rd_size = nread; 20328c2ecf20Sopenharmony_ci bus->rd_ind = 0; 20338c2ecf20Sopenharmony_ci bus->PEC_use = 0; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci /* for tx PEC is appended to buffer from i2c IF. PEC flag is ignored */ 20368c2ecf20Sopenharmony_ci if (nread) 20378c2ecf20Sopenharmony_ci bus->PEC_use = use_PEC; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci bus->read_block_use = use_read_block; 20408c2ecf20Sopenharmony_ci if (nread && !nwrite) 20418c2ecf20Sopenharmony_ci bus->operation = I2C_READ_OPER; 20428c2ecf20Sopenharmony_ci else 20438c2ecf20Sopenharmony_ci bus->operation = I2C_WRITE_OPER; 20448c2ecf20Sopenharmony_ci if (bus->fifo_use) { 20458c2ecf20Sopenharmony_ci u8 i2cfif_cts; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci npcm_i2c_select_bank(bus, I2C_BANK_1); 20488c2ecf20Sopenharmony_ci /* clear FIFO and relevant status bits. */ 20498c2ecf20Sopenharmony_ci i2cfif_cts = ioread8(bus->reg + NPCM_I2CFIF_CTS); 20508c2ecf20Sopenharmony_ci i2cfif_cts &= ~NPCM_I2CFIF_CTS_SLVRSTR; 20518c2ecf20Sopenharmony_ci i2cfif_cts |= NPCM_I2CFIF_CTS_CLR_FIFO; 20528c2ecf20Sopenharmony_ci iowrite8(i2cfif_cts, bus->reg + NPCM_I2CFIF_CTS); 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 20568c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, true); 20578c2ecf20Sopenharmony_ci npcm_i2c_master_start(bus); 20588c2ecf20Sopenharmony_ci return true; 20598c2ecf20Sopenharmony_ci} 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_cistatic int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 20628c2ecf20Sopenharmony_ci int num) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci struct npcm_i2c *bus = container_of(adap, struct npcm_i2c, adap); 20658c2ecf20Sopenharmony_ci struct i2c_msg *msg0, *msg1; 20668c2ecf20Sopenharmony_ci unsigned long time_left, flags; 20678c2ecf20Sopenharmony_ci u16 nwrite, nread; 20688c2ecf20Sopenharmony_ci u8 *write_data, *read_data; 20698c2ecf20Sopenharmony_ci u8 slave_addr; 20708c2ecf20Sopenharmony_ci unsigned long timeout; 20718c2ecf20Sopenharmony_ci bool read_block = false; 20728c2ecf20Sopenharmony_ci bool read_PEC = false; 20738c2ecf20Sopenharmony_ci u8 bus_busy; 20748c2ecf20Sopenharmony_ci unsigned long timeout_usec; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci if (bus->state == I2C_DISABLE) { 20778c2ecf20Sopenharmony_ci dev_err(bus->dev, "I2C%d module is disabled", bus->num); 20788c2ecf20Sopenharmony_ci return -EINVAL; 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci msg0 = &msgs[0]; 20828c2ecf20Sopenharmony_ci slave_addr = msg0->addr; 20838c2ecf20Sopenharmony_ci if (msg0->flags & I2C_M_RD) { /* read */ 20848c2ecf20Sopenharmony_ci nwrite = 0; 20858c2ecf20Sopenharmony_ci write_data = NULL; 20868c2ecf20Sopenharmony_ci read_data = msg0->buf; 20878c2ecf20Sopenharmony_ci if (msg0->flags & I2C_M_RECV_LEN) { 20888c2ecf20Sopenharmony_ci nread = 1; 20898c2ecf20Sopenharmony_ci read_block = true; 20908c2ecf20Sopenharmony_ci if (msg0->flags & I2C_CLIENT_PEC) 20918c2ecf20Sopenharmony_ci read_PEC = true; 20928c2ecf20Sopenharmony_ci } else { 20938c2ecf20Sopenharmony_ci nread = msg0->len; 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci } else { /* write */ 20968c2ecf20Sopenharmony_ci nwrite = msg0->len; 20978c2ecf20Sopenharmony_ci write_data = msg0->buf; 20988c2ecf20Sopenharmony_ci nread = 0; 20998c2ecf20Sopenharmony_ci read_data = NULL; 21008c2ecf20Sopenharmony_ci if (num == 2) { 21018c2ecf20Sopenharmony_ci msg1 = &msgs[1]; 21028c2ecf20Sopenharmony_ci read_data = msg1->buf; 21038c2ecf20Sopenharmony_ci if (msg1->flags & I2C_M_RECV_LEN) { 21048c2ecf20Sopenharmony_ci nread = 1; 21058c2ecf20Sopenharmony_ci read_block = true; 21068c2ecf20Sopenharmony_ci if (msg1->flags & I2C_CLIENT_PEC) 21078c2ecf20Sopenharmony_ci read_PEC = true; 21088c2ecf20Sopenharmony_ci } else { 21098c2ecf20Sopenharmony_ci nread = msg1->len; 21108c2ecf20Sopenharmony_ci read_block = false; 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci } 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci /* 21168c2ecf20Sopenharmony_ci * Adaptive TimeOut: estimated time in usec + 100% margin: 21178c2ecf20Sopenharmony_ci * 2: double the timeout for clock stretching case 21188c2ecf20Sopenharmony_ci * 9: bits per transaction (including the ack/nack) 21198c2ecf20Sopenharmony_ci */ 21208c2ecf20Sopenharmony_ci timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); 21218c2ecf20Sopenharmony_ci timeout = max_t(unsigned long, bus->adap.timeout, usecs_to_jiffies(timeout_usec)); 21228c2ecf20Sopenharmony_ci if (nwrite >= 32 * 1024 || nread >= 32 * 1024) { 21238c2ecf20Sopenharmony_ci dev_err(bus->dev, "i2c%d buffer too big\n", bus->num); 21248c2ecf20Sopenharmony_ci return -EINVAL; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci time_left = jiffies + timeout + 1; 21288c2ecf20Sopenharmony_ci do { 21298c2ecf20Sopenharmony_ci /* 21308c2ecf20Sopenharmony_ci * we must clear slave address immediately when the bus is not 21318c2ecf20Sopenharmony_ci * busy, so we spinlock it, but we don't keep the lock for the 21328c2ecf20Sopenharmony_ci * entire while since it is too long. 21338c2ecf20Sopenharmony_ci */ 21348c2ecf20Sopenharmony_ci spin_lock_irqsave(&bus->lock, flags); 21358c2ecf20Sopenharmony_ci bus_busy = ioread8(bus->reg + NPCM_I2CCST) & NPCM_I2CCST_BB; 21368c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 21378c2ecf20Sopenharmony_ci if (!bus_busy && bus->slave) 21388c2ecf20Sopenharmony_ci iowrite8((bus->slave->addr & 0x7F), 21398c2ecf20Sopenharmony_ci bus->reg + NPCM_I2CADDR1); 21408c2ecf20Sopenharmony_ci#endif 21418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bus->lock, flags); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci } while (time_is_after_jiffies(time_left) && bus_busy); 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci if (bus_busy) { 21468c2ecf20Sopenharmony_ci iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); 21478c2ecf20Sopenharmony_ci npcm_i2c_reset(bus); 21488c2ecf20Sopenharmony_ci i2c_recover_bus(adap); 21498c2ecf20Sopenharmony_ci return -EAGAIN; 21508c2ecf20Sopenharmony_ci } 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci npcm_i2c_init_params(bus); 21538c2ecf20Sopenharmony_ci bus->dest_addr = slave_addr; 21548c2ecf20Sopenharmony_ci bus->msgs = msgs; 21558c2ecf20Sopenharmony_ci bus->msgs_num = num; 21568c2ecf20Sopenharmony_ci bus->cmd_err = 0; 21578c2ecf20Sopenharmony_ci bus->read_block_use = read_block; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci reinit_completion(&bus->cmd_complete); 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci npcm_i2c_int_enable(bus, true); 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci if (npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread, 21648c2ecf20Sopenharmony_ci write_data, read_data, read_PEC, 21658c2ecf20Sopenharmony_ci read_block)) { 21668c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&bus->cmd_complete, 21678c2ecf20Sopenharmony_ci timeout); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (time_left == 0) { 21708c2ecf20Sopenharmony_ci if (bus->timeout_cnt < ULLONG_MAX) 21718c2ecf20Sopenharmony_ci bus->timeout_cnt++; 21728c2ecf20Sopenharmony_ci if (bus->master_or_slave == I2C_MASTER) { 21738c2ecf20Sopenharmony_ci i2c_recover_bus(adap); 21748c2ecf20Sopenharmony_ci bus->cmd_err = -EIO; 21758c2ecf20Sopenharmony_ci bus->state = I2C_IDLE; 21768c2ecf20Sopenharmony_ci } 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* if there was BER, check if need to recover the bus: */ 21818c2ecf20Sopenharmony_ci if (bus->cmd_err == -EAGAIN) 21828c2ecf20Sopenharmony_ci bus->cmd_err = i2c_recover_bus(adap); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci /* 21858c2ecf20Sopenharmony_ci * After any type of error, check if LAST bit is still set, 21868c2ecf20Sopenharmony_ci * due to a HW issue. 21878c2ecf20Sopenharmony_ci * It cannot be cleared without resetting the module. 21888c2ecf20Sopenharmony_ci */ 21898c2ecf20Sopenharmony_ci else if (bus->cmd_err && 21908c2ecf20Sopenharmony_ci (NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL))) 21918c2ecf20Sopenharmony_ci npcm_i2c_reset(bus); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci /* after any xfer, successful or not, stall and EOB must be disabled */ 21948c2ecf20Sopenharmony_ci npcm_i2c_stall_after_start(bus, false); 21958c2ecf20Sopenharmony_ci npcm_i2c_eob_int(bus, false); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 21988c2ecf20Sopenharmony_ci /* reenable slave if it was enabled */ 21998c2ecf20Sopenharmony_ci if (bus->slave) 22008c2ecf20Sopenharmony_ci iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN, 22018c2ecf20Sopenharmony_ci bus->reg + NPCM_I2CADDR1); 22028c2ecf20Sopenharmony_ci#else 22038c2ecf20Sopenharmony_ci npcm_i2c_int_enable(bus, false); 22048c2ecf20Sopenharmony_ci#endif 22058c2ecf20Sopenharmony_ci return bus->cmd_err; 22068c2ecf20Sopenharmony_ci} 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_cistatic u32 npcm_i2c_functionality(struct i2c_adapter *adap) 22098c2ecf20Sopenharmony_ci{ 22108c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | 22118c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_EMUL | 22128c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BLOCK_DATA | 22138c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_PEC | 22148c2ecf20Sopenharmony_ci I2C_FUNC_SLAVE; 22158c2ecf20Sopenharmony_ci} 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_cistatic const struct i2c_adapter_quirks npcm_i2c_quirks = { 22188c2ecf20Sopenharmony_ci .max_read_len = 32768, 22198c2ecf20Sopenharmony_ci .max_write_len = 32768, 22208c2ecf20Sopenharmony_ci .flags = I2C_AQ_COMB_WRITE_THEN_READ, 22218c2ecf20Sopenharmony_ci}; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_cistatic const struct i2c_algorithm npcm_i2c_algo = { 22248c2ecf20Sopenharmony_ci .master_xfer = npcm_i2c_master_xfer, 22258c2ecf20Sopenharmony_ci .functionality = npcm_i2c_functionality, 22268c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 22278c2ecf20Sopenharmony_ci .reg_slave = npcm_i2c_reg_slave, 22288c2ecf20Sopenharmony_ci .unreg_slave = npcm_i2c_unreg_slave, 22298c2ecf20Sopenharmony_ci#endif 22308c2ecf20Sopenharmony_ci}; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci/* i2c debugfs directory: used to keep health monitor of i2c devices */ 22338c2ecf20Sopenharmony_cistatic struct dentry *npcm_i2c_debugfs_dir; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_cistatic void npcm_i2c_init_debugfs(struct platform_device *pdev, 22368c2ecf20Sopenharmony_ci struct npcm_i2c *bus) 22378c2ecf20Sopenharmony_ci{ 22388c2ecf20Sopenharmony_ci struct dentry *d; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci if (!npcm_i2c_debugfs_dir) 22418c2ecf20Sopenharmony_ci return; 22428c2ecf20Sopenharmony_ci d = debugfs_create_dir(dev_name(&pdev->dev), npcm_i2c_debugfs_dir); 22438c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(d)) 22448c2ecf20Sopenharmony_ci return; 22458c2ecf20Sopenharmony_ci debugfs_create_u64("ber_cnt", 0444, d, &bus->ber_cnt); 22468c2ecf20Sopenharmony_ci debugfs_create_u64("nack_cnt", 0444, d, &bus->nack_cnt); 22478c2ecf20Sopenharmony_ci debugfs_create_u64("rec_succ_cnt", 0444, d, &bus->rec_succ_cnt); 22488c2ecf20Sopenharmony_ci debugfs_create_u64("rec_fail_cnt", 0444, d, &bus->rec_fail_cnt); 22498c2ecf20Sopenharmony_ci debugfs_create_u64("timeout_cnt", 0444, d, &bus->timeout_cnt); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci bus->debugfs = d; 22528c2ecf20Sopenharmony_ci} 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_cistatic int npcm_i2c_probe_bus(struct platform_device *pdev) 22558c2ecf20Sopenharmony_ci{ 22568c2ecf20Sopenharmony_ci struct npcm_i2c *bus; 22578c2ecf20Sopenharmony_ci struct i2c_adapter *adap; 22588c2ecf20Sopenharmony_ci struct clk *i2c_clk; 22598c2ecf20Sopenharmony_ci static struct regmap *gcr_regmap; 22608c2ecf20Sopenharmony_ci static struct regmap *clk_regmap; 22618c2ecf20Sopenharmony_ci int irq; 22628c2ecf20Sopenharmony_ci int ret; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); 22658c2ecf20Sopenharmony_ci if (!bus) 22668c2ecf20Sopenharmony_ci return -ENOMEM; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci bus->dev = &pdev->dev; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci bus->num = of_alias_get_id(pdev->dev.of_node, "i2c"); 22718c2ecf20Sopenharmony_ci /* core clk must be acquired to calculate module timing settings */ 22728c2ecf20Sopenharmony_ci i2c_clk = devm_clk_get(&pdev->dev, NULL); 22738c2ecf20Sopenharmony_ci if (IS_ERR(i2c_clk)) 22748c2ecf20Sopenharmony_ci return PTR_ERR(i2c_clk); 22758c2ecf20Sopenharmony_ci bus->apb_clk = clk_get_rate(i2c_clk); 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr"); 22788c2ecf20Sopenharmony_ci if (IS_ERR(gcr_regmap)) 22798c2ecf20Sopenharmony_ci return PTR_ERR(gcr_regmap); 22808c2ecf20Sopenharmony_ci regmap_write(gcr_regmap, NPCM_I2CSEGCTL, NPCM_I2CSEGCTL_INIT_VAL); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci clk_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-clk"); 22838c2ecf20Sopenharmony_ci if (IS_ERR(clk_regmap)) 22848c2ecf20Sopenharmony_ci return PTR_ERR(clk_regmap); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci bus->reg = devm_platform_ioremap_resource(pdev, 0); 22878c2ecf20Sopenharmony_ci if (IS_ERR(bus->reg)) 22888c2ecf20Sopenharmony_ci return PTR_ERR(bus->reg); 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci spin_lock_init(&bus->lock); 22918c2ecf20Sopenharmony_ci init_completion(&bus->cmd_complete); 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci adap = &bus->adap; 22948c2ecf20Sopenharmony_ci adap->owner = THIS_MODULE; 22958c2ecf20Sopenharmony_ci adap->retries = 3; 22968c2ecf20Sopenharmony_ci adap->timeout = msecs_to_jiffies(35); 22978c2ecf20Sopenharmony_ci adap->algo = &npcm_i2c_algo; 22988c2ecf20Sopenharmony_ci adap->quirks = &npcm_i2c_quirks; 22998c2ecf20Sopenharmony_ci adap->algo_data = bus; 23008c2ecf20Sopenharmony_ci adap->dev.parent = &pdev->dev; 23018c2ecf20Sopenharmony_ci adap->dev.of_node = pdev->dev.of_node; 23028c2ecf20Sopenharmony_ci adap->nr = pdev->id; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 23058c2ecf20Sopenharmony_ci if (irq < 0) 23068c2ecf20Sopenharmony_ci return irq; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci ret = devm_request_irq(bus->dev, irq, npcm_i2c_bus_irq, 0, 23098c2ecf20Sopenharmony_ci dev_name(bus->dev), bus); 23108c2ecf20Sopenharmony_ci if (ret) 23118c2ecf20Sopenharmony_ci return ret; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci ret = __npcm_i2c_init(bus, pdev); 23148c2ecf20Sopenharmony_ci if (ret) 23158c2ecf20Sopenharmony_ci return ret; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci npcm_i2c_recovery_init(adap); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci i2c_set_adapdata(adap, bus); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci snprintf(bus->adap.name, sizeof(bus->adap.name), "npcm_i2c_%d", 23228c2ecf20Sopenharmony_ci bus->num); 23238c2ecf20Sopenharmony_ci ret = i2c_add_numbered_adapter(&bus->adap); 23248c2ecf20Sopenharmony_ci if (ret) 23258c2ecf20Sopenharmony_ci return ret; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, bus); 23288c2ecf20Sopenharmony_ci npcm_i2c_init_debugfs(pdev, bus); 23298c2ecf20Sopenharmony_ci return 0; 23308c2ecf20Sopenharmony_ci} 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_cistatic int npcm_i2c_remove_bus(struct platform_device *pdev) 23338c2ecf20Sopenharmony_ci{ 23348c2ecf20Sopenharmony_ci unsigned long lock_flags; 23358c2ecf20Sopenharmony_ci struct npcm_i2c *bus = platform_get_drvdata(pdev); 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci debugfs_remove_recursive(bus->debugfs); 23388c2ecf20Sopenharmony_ci spin_lock_irqsave(&bus->lock, lock_flags); 23398c2ecf20Sopenharmony_ci npcm_i2c_disable(bus); 23408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bus->lock, lock_flags); 23418c2ecf20Sopenharmony_ci i2c_del_adapter(&bus->adap); 23428c2ecf20Sopenharmony_ci return 0; 23438c2ecf20Sopenharmony_ci} 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_cistatic const struct of_device_id npcm_i2c_bus_of_table[] = { 23468c2ecf20Sopenharmony_ci { .compatible = "nuvoton,npcm750-i2c", }, 23478c2ecf20Sopenharmony_ci {} 23488c2ecf20Sopenharmony_ci}; 23498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table); 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_cistatic struct platform_driver npcm_i2c_bus_driver = { 23528c2ecf20Sopenharmony_ci .probe = npcm_i2c_probe_bus, 23538c2ecf20Sopenharmony_ci .remove = npcm_i2c_remove_bus, 23548c2ecf20Sopenharmony_ci .driver = { 23558c2ecf20Sopenharmony_ci .name = "nuvoton-i2c", 23568c2ecf20Sopenharmony_ci .of_match_table = npcm_i2c_bus_of_table, 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci}; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_cistatic int __init npcm_i2c_init(void) 23618c2ecf20Sopenharmony_ci{ 23628c2ecf20Sopenharmony_ci int ret; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci npcm_i2c_debugfs_dir = debugfs_create_dir("npcm_i2c", NULL); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci ret = platform_driver_register(&npcm_i2c_bus_driver); 23678c2ecf20Sopenharmony_ci if (ret) { 23688c2ecf20Sopenharmony_ci debugfs_remove_recursive(npcm_i2c_debugfs_dir); 23698c2ecf20Sopenharmony_ci return ret; 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci return 0; 23738c2ecf20Sopenharmony_ci} 23748c2ecf20Sopenharmony_cimodule_init(npcm_i2c_init); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_cistatic void __exit npcm_i2c_exit(void) 23778c2ecf20Sopenharmony_ci{ 23788c2ecf20Sopenharmony_ci platform_driver_unregister(&npcm_i2c_bus_driver); 23798c2ecf20Sopenharmony_ci debugfs_remove_recursive(npcm_i2c_debugfs_dir); 23808c2ecf20Sopenharmony_ci} 23818c2ecf20Sopenharmony_cimodule_exit(npcm_i2c_exit); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Avi Fishman <avi.fishman@gmail.com>"); 23848c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tali Perry <tali.perry@nuvoton.com>"); 23858c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tyrone Ting <kfting@nuvoton.com>"); 23868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Nuvoton I2C Bus Driver"); 23878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2388