18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * I2C bus driver for the Cadence I2C controller. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 - 2014 Xilinx, Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* Register offsets for the I2C device. */ 198c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */ 208c2ecf20Sopenharmony_ci#define CDNS_I2C_SR_OFFSET 0x04 /* Status Register, RO */ 218c2ecf20Sopenharmony_ci#define CDNS_I2C_ADDR_OFFSET 0x08 /* I2C Address Register, RW */ 228c2ecf20Sopenharmony_ci#define CDNS_I2C_DATA_OFFSET 0x0C /* I2C Data Register, RW */ 238c2ecf20Sopenharmony_ci#define CDNS_I2C_ISR_OFFSET 0x10 /* IRQ Status Register, RW */ 248c2ecf20Sopenharmony_ci#define CDNS_I2C_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */ 258c2ecf20Sopenharmony_ci#define CDNS_I2C_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */ 268c2ecf20Sopenharmony_ci#define CDNS_I2C_IMR_OFFSET 0x20 /* IRQ Mask Register, RO */ 278c2ecf20Sopenharmony_ci#define CDNS_I2C_IER_OFFSET 0x24 /* IRQ Enable Register, WO */ 288c2ecf20Sopenharmony_ci#define CDNS_I2C_IDR_OFFSET 0x28 /* IRQ Disable Register, WO */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Control Register Bit mask definitions */ 318c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_HOLD BIT(4) /* Hold Bus bit */ 328c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_ACK_EN BIT(3) 338c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_NEA BIT(2) 348c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_MS BIT(1) 358c2ecf20Sopenharmony_ci/* Read or Write Master transfer 0 = Transmitter, 1 = Receiver */ 368c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_RW BIT(0) 378c2ecf20Sopenharmony_ci/* 1 = Auto init FIFO to zeroes */ 388c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_CLR_FIFO BIT(6) 398c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_DIVA_SHIFT 14 408c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_DIVA_MASK (3 << CDNS_I2C_CR_DIVA_SHIFT) 418c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_DIVB_SHIFT 8 428c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_DIVB_MASK (0x3f << CDNS_I2C_CR_DIVB_SHIFT) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_MASTER_EN_MASK (CDNS_I2C_CR_NEA | \ 458c2ecf20Sopenharmony_ci CDNS_I2C_CR_ACK_EN | \ 468c2ecf20Sopenharmony_ci CDNS_I2C_CR_MS) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define CDNS_I2C_CR_SLAVE_EN_MASK ~CDNS_I2C_CR_MASTER_EN_MASK 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* Status Register Bit mask definitions */ 518c2ecf20Sopenharmony_ci#define CDNS_I2C_SR_BA BIT(8) 528c2ecf20Sopenharmony_ci#define CDNS_I2C_SR_TXDV BIT(6) 538c2ecf20Sopenharmony_ci#define CDNS_I2C_SR_RXDV BIT(5) 548c2ecf20Sopenharmony_ci#define CDNS_I2C_SR_RXRW BIT(3) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * I2C Address Register Bit mask definitions 588c2ecf20Sopenharmony_ci * Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0] 598c2ecf20Sopenharmony_ci * bits. A write access to this register always initiates a transfer if the I2C 608c2ecf20Sopenharmony_ci * is in master mode. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci#define CDNS_I2C_ADDR_MASK 0x000003FF /* I2C Address Mask */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * I2C Interrupt Registers Bit mask definitions 668c2ecf20Sopenharmony_ci * All the four interrupt registers (Status/Mask/Enable/Disable) have the same 678c2ecf20Sopenharmony_ci * bit definitions. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_ARB_LOST BIT(9) 708c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_RX_UNF BIT(7) 718c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_TX_OVF BIT(6) 728c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_RX_OVF BIT(5) 738c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_SLV_RDY BIT(4) 748c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_TO BIT(3) 758c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_NACK BIT(2) 768c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_DATA BIT(1) 778c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_COMP BIT(0) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_ALL_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \ 808c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_UNF | \ 818c2ecf20Sopenharmony_ci CDNS_I2C_IXR_TX_OVF | \ 828c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_OVF | \ 838c2ecf20Sopenharmony_ci CDNS_I2C_IXR_SLV_RDY | \ 848c2ecf20Sopenharmony_ci CDNS_I2C_IXR_TO | \ 858c2ecf20Sopenharmony_ci CDNS_I2C_IXR_NACK | \ 868c2ecf20Sopenharmony_ci CDNS_I2C_IXR_DATA | \ 878c2ecf20Sopenharmony_ci CDNS_I2C_IXR_COMP) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_ERR_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \ 908c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_UNF | \ 918c2ecf20Sopenharmony_ci CDNS_I2C_IXR_TX_OVF | \ 928c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_OVF | \ 938c2ecf20Sopenharmony_ci CDNS_I2C_IXR_NACK) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define CDNS_I2C_ENABLED_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \ 968c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_UNF | \ 978c2ecf20Sopenharmony_ci CDNS_I2C_IXR_TX_OVF | \ 988c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_OVF | \ 998c2ecf20Sopenharmony_ci CDNS_I2C_IXR_NACK | \ 1008c2ecf20Sopenharmony_ci CDNS_I2C_IXR_DATA | \ 1018c2ecf20Sopenharmony_ci CDNS_I2C_IXR_COMP) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define CDNS_I2C_IXR_SLAVE_INTR_MASK (CDNS_I2C_IXR_RX_UNF | \ 1048c2ecf20Sopenharmony_ci CDNS_I2C_IXR_TX_OVF | \ 1058c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_OVF | \ 1068c2ecf20Sopenharmony_ci CDNS_I2C_IXR_TO | \ 1078c2ecf20Sopenharmony_ci CDNS_I2C_IXR_NACK | \ 1088c2ecf20Sopenharmony_ci CDNS_I2C_IXR_DATA | \ 1098c2ecf20Sopenharmony_ci CDNS_I2C_IXR_COMP) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000) 1128c2ecf20Sopenharmony_ci/* timeout for pm runtime autosuspend */ 1138c2ecf20Sopenharmony_ci#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define CDNS_I2C_FIFO_DEPTH 16 1168c2ecf20Sopenharmony_ci/* FIFO depth at which the DATA interrupt occurs */ 1178c2ecf20Sopenharmony_ci#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2) 1188c2ecf20Sopenharmony_ci#define CDNS_I2C_MAX_TRANSFER_SIZE 255 1198c2ecf20Sopenharmony_ci/* Transfer size in multiples of data interrupt depth */ 1208c2ecf20Sopenharmony_ci#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define DRIVER_NAME "cdns-i2c" 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define CDNS_I2C_DIVA_MAX 4 1258c2ecf20Sopenharmony_ci#define CDNS_I2C_DIVB_MAX 64 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#define CDNS_I2C_TIMEOUT_MAX 0xFF 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) 1328c2ecf20Sopenharmony_ci#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 1358c2ecf20Sopenharmony_ci/** 1368c2ecf20Sopenharmony_ci * enum cdns_i2c_mode - I2C Controller current operating mode 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * @CDNS_I2C_MODE_SLAVE: I2C controller operating in slave mode 1398c2ecf20Sopenharmony_ci * @CDNS_I2C_MODE_MASTER: I2C Controller operating in master mode 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cienum cdns_i2c_mode { 1428c2ecf20Sopenharmony_ci CDNS_I2C_MODE_SLAVE, 1438c2ecf20Sopenharmony_ci CDNS_I2C_MODE_MASTER, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/** 1478c2ecf20Sopenharmony_ci * enum cdns_i2c_slave_mode - Slave state when I2C is operating in slave mode 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * @CDNS_I2C_SLAVE_STATE_IDLE: I2C slave idle 1508c2ecf20Sopenharmony_ci * @CDNS_I2C_SLAVE_STATE_SEND: I2C slave sending data to master 1518c2ecf20Sopenharmony_ci * @CDNS_I2C_SLAVE_STATE_RECV: I2C slave receiving data from master 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_cienum cdns_i2c_slave_state { 1548c2ecf20Sopenharmony_ci CDNS_I2C_SLAVE_STATE_IDLE, 1558c2ecf20Sopenharmony_ci CDNS_I2C_SLAVE_STATE_SEND, 1568c2ecf20Sopenharmony_ci CDNS_I2C_SLAVE_STATE_RECV, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci#endif 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * struct cdns_i2c - I2C device private data structure 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * @dev: Pointer to device structure 1648c2ecf20Sopenharmony_ci * @membase: Base address of the I2C device 1658c2ecf20Sopenharmony_ci * @adap: I2C adapter instance 1668c2ecf20Sopenharmony_ci * @p_msg: Message pointer 1678c2ecf20Sopenharmony_ci * @err_status: Error status in Interrupt Status Register 1688c2ecf20Sopenharmony_ci * @xfer_done: Transfer complete status 1698c2ecf20Sopenharmony_ci * @p_send_buf: Pointer to transmit buffer 1708c2ecf20Sopenharmony_ci * @p_recv_buf: Pointer to receive buffer 1718c2ecf20Sopenharmony_ci * @send_count: Number of bytes still expected to send 1728c2ecf20Sopenharmony_ci * @recv_count: Number of bytes still expected to receive 1738c2ecf20Sopenharmony_ci * @curr_recv_count: Number of bytes to be received in current transfer 1748c2ecf20Sopenharmony_ci * @irq: IRQ number 1758c2ecf20Sopenharmony_ci * @input_clk: Input clock to I2C controller 1768c2ecf20Sopenharmony_ci * @i2c_clk: Maximum I2C clock speed 1778c2ecf20Sopenharmony_ci * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit 1788c2ecf20Sopenharmony_ci * @clk: Pointer to struct clk 1798c2ecf20Sopenharmony_ci * @clk_rate_change_nb: Notifier block for clock rate changes 1808c2ecf20Sopenharmony_ci * @quirks: flag for broken hold bit usage in r1p10 1818c2ecf20Sopenharmony_ci * @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register 1828c2ecf20Sopenharmony_ci * @slave: Registered slave instance. 1838c2ecf20Sopenharmony_ci * @dev_mode: I2C operating role(master/slave). 1848c2ecf20Sopenharmony_ci * @slave_state: I2C Slave state(idle/read/write). 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistruct cdns_i2c { 1878c2ecf20Sopenharmony_ci struct device *dev; 1888c2ecf20Sopenharmony_ci void __iomem *membase; 1898c2ecf20Sopenharmony_ci struct i2c_adapter adap; 1908c2ecf20Sopenharmony_ci struct i2c_msg *p_msg; 1918c2ecf20Sopenharmony_ci int err_status; 1928c2ecf20Sopenharmony_ci struct completion xfer_done; 1938c2ecf20Sopenharmony_ci unsigned char *p_send_buf; 1948c2ecf20Sopenharmony_ci unsigned char *p_recv_buf; 1958c2ecf20Sopenharmony_ci unsigned int send_count; 1968c2ecf20Sopenharmony_ci unsigned int recv_count; 1978c2ecf20Sopenharmony_ci unsigned int curr_recv_count; 1988c2ecf20Sopenharmony_ci int irq; 1998c2ecf20Sopenharmony_ci unsigned long input_clk; 2008c2ecf20Sopenharmony_ci unsigned int i2c_clk; 2018c2ecf20Sopenharmony_ci unsigned int bus_hold_flag; 2028c2ecf20Sopenharmony_ci struct clk *clk; 2038c2ecf20Sopenharmony_ci struct notifier_block clk_rate_change_nb; 2048c2ecf20Sopenharmony_ci u32 quirks; 2058c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 2068c2ecf20Sopenharmony_ci u16 ctrl_reg_diva_divb; 2078c2ecf20Sopenharmony_ci struct i2c_client *slave; 2088c2ecf20Sopenharmony_ci enum cdns_i2c_mode dev_mode; 2098c2ecf20Sopenharmony_ci enum cdns_i2c_slave_state slave_state; 2108c2ecf20Sopenharmony_ci#endif 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistruct cdns_platform_data { 2148c2ecf20Sopenharmony_ci u32 quirks; 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \ 2188c2ecf20Sopenharmony_ci clk_rate_change_nb) 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/** 2218c2ecf20Sopenharmony_ci * cdns_i2c_clear_bus_hold - Clear bus hold bit 2228c2ecf20Sopenharmony_ci * @id: Pointer to driver data struct 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * Helper to clear the controller's bus hold bit. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_cistatic void cdns_i2c_clear_bus_hold(struct cdns_i2c *id) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci u32 reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); 2298c2ecf20Sopenharmony_ci if (reg & CDNS_I2C_CR_HOLD) 2308c2ecf20Sopenharmony_ci cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return (hold_wrkaround && 2368c2ecf20Sopenharmony_ci (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 2408c2ecf20Sopenharmony_cistatic void cdns_i2c_set_mode(enum cdns_i2c_mode mode, struct cdns_i2c *id) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci /* Disable all interrupts */ 2438c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Clear FIFO and transfer size */ 2468c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Update device mode and state */ 2498c2ecf20Sopenharmony_ci id->dev_mode = mode; 2508c2ecf20Sopenharmony_ci id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci switch (mode) { 2538c2ecf20Sopenharmony_ci case CDNS_I2C_MODE_MASTER: 2548c2ecf20Sopenharmony_ci /* Enable i2c master */ 2558c2ecf20Sopenharmony_ci cdns_i2c_writereg(id->ctrl_reg_diva_divb | 2568c2ecf20Sopenharmony_ci CDNS_I2C_CR_MASTER_EN_MASK, 2578c2ecf20Sopenharmony_ci CDNS_I2C_CR_OFFSET); 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * This delay is needed to give the IP some time to switch to 2608c2ecf20Sopenharmony_ci * the master mode. With lower values(like 110 us) i2cdetect 2618c2ecf20Sopenharmony_ci * will not detect any slave and without this delay, the IP will 2628c2ecf20Sopenharmony_ci * trigger a timeout interrupt. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci usleep_range(115, 125); 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci case CDNS_I2C_MODE_SLAVE: 2678c2ecf20Sopenharmony_ci /* Enable i2c slave */ 2688c2ecf20Sopenharmony_ci cdns_i2c_writereg(id->ctrl_reg_diva_divb & 2698c2ecf20Sopenharmony_ci CDNS_I2C_CR_SLAVE_EN_MASK, 2708c2ecf20Sopenharmony_ci CDNS_I2C_CR_OFFSET); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Setting slave address */ 2738c2ecf20Sopenharmony_ci cdns_i2c_writereg(id->slave->addr & CDNS_I2C_ADDR_MASK, 2748c2ecf20Sopenharmony_ci CDNS_I2C_ADDR_OFFSET); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Enable slave send/receive interrupts */ 2778c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_IXR_SLAVE_INTR_MASK, 2788c2ecf20Sopenharmony_ci CDNS_I2C_IER_OFFSET); 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void cdns_i2c_slave_rcv_data(struct cdns_i2c *id) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci u8 bytes; 2868c2ecf20Sopenharmony_ci unsigned char data; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Prepare backend for data reception */ 2898c2ecf20Sopenharmony_ci if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) { 2908c2ecf20Sopenharmony_ci id->slave_state = CDNS_I2C_SLAVE_STATE_RECV; 2918c2ecf20Sopenharmony_ci i2c_slave_event(id->slave, I2C_SLAVE_WRITE_REQUESTED, NULL); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Fetch number of bytes to receive */ 2958c2ecf20Sopenharmony_ci bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Read data and send to backend */ 2988c2ecf20Sopenharmony_ci while (bytes--) { 2998c2ecf20Sopenharmony_ci data = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); 3008c2ecf20Sopenharmony_ci i2c_slave_event(id->slave, I2C_SLAVE_WRITE_RECEIVED, &data); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void cdns_i2c_slave_send_data(struct cdns_i2c *id) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci u8 data; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Prepare backend for data transmission */ 3098c2ecf20Sopenharmony_ci if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) { 3108c2ecf20Sopenharmony_ci id->slave_state = CDNS_I2C_SLAVE_STATE_SEND; 3118c2ecf20Sopenharmony_ci i2c_slave_event(id->slave, I2C_SLAVE_READ_REQUESTED, &data); 3128c2ecf20Sopenharmony_ci } else { 3138c2ecf20Sopenharmony_ci i2c_slave_event(id->slave, I2C_SLAVE_READ_PROCESSED, &data); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Send data over bus */ 3178c2ecf20Sopenharmony_ci cdns_i2c_writereg(data, CDNS_I2C_DATA_OFFSET); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/** 3218c2ecf20Sopenharmony_ci * cdns_i2c_slave_isr - Interrupt handler for the I2C device in slave role 3228c2ecf20Sopenharmony_ci * @ptr: Pointer to I2C device private data 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * This function handles the data interrupt and transfer complete interrupt of 3258c2ecf20Sopenharmony_ci * the I2C device in slave role. 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * Return: IRQ_HANDLED always 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_cistatic irqreturn_t cdns_i2c_slave_isr(void *ptr) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct cdns_i2c *id = ptr; 3328c2ecf20Sopenharmony_ci unsigned int isr_status, i2c_status; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Fetch the interrupt status */ 3358c2ecf20Sopenharmony_ci isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); 3368c2ecf20Sopenharmony_ci cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Ignore masked interrupts */ 3398c2ecf20Sopenharmony_ci isr_status &= ~cdns_i2c_readreg(CDNS_I2C_IMR_OFFSET); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Fetch transfer mode (send/receive) */ 3428c2ecf20Sopenharmony_ci i2c_status = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Handle data send/receive */ 3458c2ecf20Sopenharmony_ci if (i2c_status & CDNS_I2C_SR_RXRW) { 3468c2ecf20Sopenharmony_ci /* Send data to master */ 3478c2ecf20Sopenharmony_ci if (isr_status & CDNS_I2C_IXR_DATA) 3488c2ecf20Sopenharmony_ci cdns_i2c_slave_send_data(id); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (isr_status & CDNS_I2C_IXR_COMP) { 3518c2ecf20Sopenharmony_ci id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; 3528c2ecf20Sopenharmony_ci i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci } else { 3558c2ecf20Sopenharmony_ci /* Receive data from master */ 3568c2ecf20Sopenharmony_ci if (isr_status & CDNS_I2C_IXR_DATA) 3578c2ecf20Sopenharmony_ci cdns_i2c_slave_rcv_data(id); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (isr_status & CDNS_I2C_IXR_COMP) { 3608c2ecf20Sopenharmony_ci cdns_i2c_slave_rcv_data(id); 3618c2ecf20Sopenharmony_ci id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; 3628c2ecf20Sopenharmony_ci i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Master indicated xfer stop or fifo underflow/overflow */ 3678c2ecf20Sopenharmony_ci if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_RX_OVF | 3688c2ecf20Sopenharmony_ci CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF)) { 3698c2ecf20Sopenharmony_ci id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; 3708c2ecf20Sopenharmony_ci i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL); 3718c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci#endif 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/** 3798c2ecf20Sopenharmony_ci * cdns_i2c_master_isr - Interrupt handler for the I2C device in master role 3808c2ecf20Sopenharmony_ci * @ptr: Pointer to I2C device private data 3818c2ecf20Sopenharmony_ci * 3828c2ecf20Sopenharmony_ci * This function handles the data interrupt, transfer complete interrupt and 3838c2ecf20Sopenharmony_ci * the error interrupts of the I2C device in master role. 3848c2ecf20Sopenharmony_ci * 3858c2ecf20Sopenharmony_ci * Return: IRQ_HANDLED always 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_cistatic irqreturn_t cdns_i2c_master_isr(void *ptr) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci unsigned int isr_status, avail_bytes; 3908c2ecf20Sopenharmony_ci unsigned int bytes_to_send; 3918c2ecf20Sopenharmony_ci bool updatetx; 3928c2ecf20Sopenharmony_ci struct cdns_i2c *id = ptr; 3938c2ecf20Sopenharmony_ci /* Signal completion only after everything is updated */ 3948c2ecf20Sopenharmony_ci int done_flag = 0; 3958c2ecf20Sopenharmony_ci irqreturn_t status = IRQ_NONE; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); 3988c2ecf20Sopenharmony_ci cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET); 3998c2ecf20Sopenharmony_ci id->err_status = 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Handling nack and arbitration lost interrupt */ 4028c2ecf20Sopenharmony_ci if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) { 4038c2ecf20Sopenharmony_ci done_flag = 1; 4048c2ecf20Sopenharmony_ci status = IRQ_HANDLED; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * Check if transfer size register needs to be updated again for a 4098c2ecf20Sopenharmony_ci * large data receive operation. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci updatetx = id->recv_count > id->curr_recv_count; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* When receiving, handle data interrupt and completion interrupt */ 4148c2ecf20Sopenharmony_ci if (id->p_recv_buf && 4158c2ecf20Sopenharmony_ci ((isr_status & CDNS_I2C_IXR_COMP) || 4168c2ecf20Sopenharmony_ci (isr_status & CDNS_I2C_IXR_DATA))) { 4178c2ecf20Sopenharmony_ci /* Read data if receive data valid is set */ 4188c2ecf20Sopenharmony_ci while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & 4198c2ecf20Sopenharmony_ci CDNS_I2C_SR_RXDV) { 4208c2ecf20Sopenharmony_ci if (id->recv_count > 0) { 4218c2ecf20Sopenharmony_ci *(id->p_recv_buf)++ = 4228c2ecf20Sopenharmony_ci cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); 4238c2ecf20Sopenharmony_ci id->recv_count--; 4248c2ecf20Sopenharmony_ci id->curr_recv_count--; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * Clear hold bit that was set for FIFO control 4288c2ecf20Sopenharmony_ci * if RX data left is less than or equal to 4298c2ecf20Sopenharmony_ci * FIFO DEPTH unless repeated start is selected 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ci if (id->recv_count <= CDNS_I2C_FIFO_DEPTH && 4328c2ecf20Sopenharmony_ci !id->bus_hold_flag) 4338c2ecf20Sopenharmony_ci cdns_i2c_clear_bus_hold(id); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci } else { 4368c2ecf20Sopenharmony_ci dev_err(id->adap.dev.parent, 4378c2ecf20Sopenharmony_ci "xfer_size reg rollover. xfer aborted!\n"); 4388c2ecf20Sopenharmony_ci id->err_status |= CDNS_I2C_IXR_TO; 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (cdns_is_holdquirk(id, updatetx)) 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* 4478c2ecf20Sopenharmony_ci * The controller sends NACK to the slave when transfer size 4488c2ecf20Sopenharmony_ci * register reaches zero without considering the HOLD bit. 4498c2ecf20Sopenharmony_ci * This workaround is implemented for large data transfers to 4508c2ecf20Sopenharmony_ci * maintain transfer size non-zero while performing a large 4518c2ecf20Sopenharmony_ci * receive operation. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci if (cdns_is_holdquirk(id, updatetx)) { 4548c2ecf20Sopenharmony_ci /* wait while fifo is full */ 4558c2ecf20Sopenharmony_ci while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != 4568c2ecf20Sopenharmony_ci (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH)) 4578c2ecf20Sopenharmony_ci ; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* 4608c2ecf20Sopenharmony_ci * Check number of bytes to be received against maximum 4618c2ecf20Sopenharmony_ci * transfer size and update register accordingly. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) > 4648c2ecf20Sopenharmony_ci CDNS_I2C_TRANSFER_SIZE) { 4658c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, 4668c2ecf20Sopenharmony_ci CDNS_I2C_XFER_SIZE_OFFSET); 4678c2ecf20Sopenharmony_ci id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE + 4688c2ecf20Sopenharmony_ci CDNS_I2C_FIFO_DEPTH; 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci cdns_i2c_writereg(id->recv_count - 4718c2ecf20Sopenharmony_ci CDNS_I2C_FIFO_DEPTH, 4728c2ecf20Sopenharmony_ci CDNS_I2C_XFER_SIZE_OFFSET); 4738c2ecf20Sopenharmony_ci id->curr_recv_count = id->recv_count; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Clear hold (if not repeated start) and signal completion */ 4788c2ecf20Sopenharmony_ci if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) { 4798c2ecf20Sopenharmony_ci if (!id->bus_hold_flag) 4808c2ecf20Sopenharmony_ci cdns_i2c_clear_bus_hold(id); 4818c2ecf20Sopenharmony_ci done_flag = 1; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci status = IRQ_HANDLED; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* When sending, handle transfer complete interrupt */ 4888c2ecf20Sopenharmony_ci if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) { 4898c2ecf20Sopenharmony_ci /* 4908c2ecf20Sopenharmony_ci * If there is more data to be sent, calculate the 4918c2ecf20Sopenharmony_ci * space available in FIFO and fill with that many bytes. 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci if (id->send_count) { 4948c2ecf20Sopenharmony_ci avail_bytes = CDNS_I2C_FIFO_DEPTH - 4958c2ecf20Sopenharmony_ci cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); 4968c2ecf20Sopenharmony_ci if (id->send_count > avail_bytes) 4978c2ecf20Sopenharmony_ci bytes_to_send = avail_bytes; 4988c2ecf20Sopenharmony_ci else 4998c2ecf20Sopenharmony_ci bytes_to_send = id->send_count; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci while (bytes_to_send--) { 5028c2ecf20Sopenharmony_ci cdns_i2c_writereg( 5038c2ecf20Sopenharmony_ci (*(id->p_send_buf)++), 5048c2ecf20Sopenharmony_ci CDNS_I2C_DATA_OFFSET); 5058c2ecf20Sopenharmony_ci id->send_count--; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci /* 5098c2ecf20Sopenharmony_ci * Signal the completion of transaction and 5108c2ecf20Sopenharmony_ci * clear the hold bus bit if there are no 5118c2ecf20Sopenharmony_ci * further messages to be processed. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci done_flag = 1; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci if (!id->send_count && !id->bus_hold_flag) 5168c2ecf20Sopenharmony_ci cdns_i2c_clear_bus_hold(id); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci status = IRQ_HANDLED; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* Update the status for errors */ 5228c2ecf20Sopenharmony_ci id->err_status |= isr_status & CDNS_I2C_IXR_ERR_INTR_MASK; 5238c2ecf20Sopenharmony_ci if (id->err_status) 5248c2ecf20Sopenharmony_ci status = IRQ_HANDLED; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (done_flag) 5278c2ecf20Sopenharmony_ci complete(&id->xfer_done); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return status; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/** 5338c2ecf20Sopenharmony_ci * cdns_i2c_isr - Interrupt handler for the I2C device 5348c2ecf20Sopenharmony_ci * @irq: irq number for the I2C device 5358c2ecf20Sopenharmony_ci * @ptr: void pointer to cdns_i2c structure 5368c2ecf20Sopenharmony_ci * 5378c2ecf20Sopenharmony_ci * This function passes the control to slave/master based on current role of 5388c2ecf20Sopenharmony_ci * i2c controller. 5398c2ecf20Sopenharmony_ci * 5408c2ecf20Sopenharmony_ci * Return: IRQ_HANDLED always 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_cistatic irqreturn_t cdns_i2c_isr(int irq, void *ptr) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 5458c2ecf20Sopenharmony_ci struct cdns_i2c *id = ptr; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (id->dev_mode == CDNS_I2C_MODE_SLAVE) 5488c2ecf20Sopenharmony_ci return cdns_i2c_slave_isr(ptr); 5498c2ecf20Sopenharmony_ci#endif 5508c2ecf20Sopenharmony_ci return cdns_i2c_master_isr(ptr); 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci/** 5548c2ecf20Sopenharmony_ci * cdns_i2c_mrecv - Prepare and start a master receive operation 5558c2ecf20Sopenharmony_ci * @id: pointer to the i2c device structure 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_cistatic void cdns_i2c_mrecv(struct cdns_i2c *id) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci unsigned int ctrl_reg; 5608c2ecf20Sopenharmony_ci unsigned int isr_status; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci id->p_recv_buf = id->p_msg->buf; 5638c2ecf20Sopenharmony_ci id->recv_count = id->p_msg->len; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Put the controller in master receive mode and clear the FIFO */ 5668c2ecf20Sopenharmony_ci ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); 5678c2ecf20Sopenharmony_ci ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* 5708c2ecf20Sopenharmony_ci * Receive up to I2C_SMBUS_BLOCK_MAX data bytes, plus one message length 5718c2ecf20Sopenharmony_ci * byte, plus one checksum byte if PEC is enabled. p_msg->len will be 2 if 5728c2ecf20Sopenharmony_ci * PEC is enabled, otherwise 1. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_ci if (id->p_msg->flags & I2C_M_RECV_LEN) 5758c2ecf20Sopenharmony_ci id->recv_count = I2C_SMBUS_BLOCK_MAX + id->p_msg->len; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci id->curr_recv_count = id->recv_count; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * Check for the message size against FIFO depth and set the 5818c2ecf20Sopenharmony_ci * 'hold bus' bit if it is greater than FIFO depth. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci if (id->recv_count > CDNS_I2C_FIFO_DEPTH) 5848c2ecf20Sopenharmony_ci ctrl_reg |= CDNS_I2C_CR_HOLD; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Clear the interrupts in interrupt status register */ 5898c2ecf20Sopenharmony_ci isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); 5908c2ecf20Sopenharmony_ci cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * The no. of bytes to receive is checked against the limit of 5948c2ecf20Sopenharmony_ci * max transfer size. Set transfer size register with no of bytes 5958c2ecf20Sopenharmony_ci * receive if it is less than transfer size and transfer size if 5968c2ecf20Sopenharmony_ci * it is more. Enable the interrupts. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_ci if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) { 5998c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, 6008c2ecf20Sopenharmony_ci CDNS_I2C_XFER_SIZE_OFFSET); 6018c2ecf20Sopenharmony_ci id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE; 6028c2ecf20Sopenharmony_ci } else { 6038c2ecf20Sopenharmony_ci cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Set the slave address in address register - triggers operation */ 6078c2ecf20Sopenharmony_ci cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, 6088c2ecf20Sopenharmony_ci CDNS_I2C_ADDR_OFFSET); 6098c2ecf20Sopenharmony_ci /* Clear the bus hold flag if bytes to receive is less than FIFO size */ 6108c2ecf20Sopenharmony_ci if (!id->bus_hold_flag && 6118c2ecf20Sopenharmony_ci ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && 6128c2ecf20Sopenharmony_ci (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) 6138c2ecf20Sopenharmony_ci cdns_i2c_clear_bus_hold(id); 6148c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci/** 6188c2ecf20Sopenharmony_ci * cdns_i2c_msend - Prepare and start a master send operation 6198c2ecf20Sopenharmony_ci * @id: pointer to the i2c device 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_cistatic void cdns_i2c_msend(struct cdns_i2c *id) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci unsigned int avail_bytes; 6248c2ecf20Sopenharmony_ci unsigned int bytes_to_send; 6258c2ecf20Sopenharmony_ci unsigned int ctrl_reg; 6268c2ecf20Sopenharmony_ci unsigned int isr_status; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci id->p_recv_buf = NULL; 6298c2ecf20Sopenharmony_ci id->p_send_buf = id->p_msg->buf; 6308c2ecf20Sopenharmony_ci id->send_count = id->p_msg->len; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* Set the controller in Master transmit mode and clear the FIFO. */ 6338c2ecf20Sopenharmony_ci ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); 6348c2ecf20Sopenharmony_ci ctrl_reg &= ~CDNS_I2C_CR_RW; 6358c2ecf20Sopenharmony_ci ctrl_reg |= CDNS_I2C_CR_CLR_FIFO; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* 6388c2ecf20Sopenharmony_ci * Check for the message size against FIFO depth and set the 6398c2ecf20Sopenharmony_ci * 'hold bus' bit if it is greater than FIFO depth. 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_ci if (id->send_count > CDNS_I2C_FIFO_DEPTH) 6428c2ecf20Sopenharmony_ci ctrl_reg |= CDNS_I2C_CR_HOLD; 6438c2ecf20Sopenharmony_ci cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Clear the interrupts in interrupt status register. */ 6468c2ecf20Sopenharmony_ci isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); 6478c2ecf20Sopenharmony_ci cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* 6508c2ecf20Sopenharmony_ci * Calculate the space available in FIFO. Check the message length 6518c2ecf20Sopenharmony_ci * against the space available, and fill the FIFO accordingly. 6528c2ecf20Sopenharmony_ci * Enable the interrupts. 6538c2ecf20Sopenharmony_ci */ 6548c2ecf20Sopenharmony_ci avail_bytes = CDNS_I2C_FIFO_DEPTH - 6558c2ecf20Sopenharmony_ci cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (id->send_count > avail_bytes) 6588c2ecf20Sopenharmony_ci bytes_to_send = avail_bytes; 6598c2ecf20Sopenharmony_ci else 6608c2ecf20Sopenharmony_ci bytes_to_send = id->send_count; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci while (bytes_to_send--) { 6638c2ecf20Sopenharmony_ci cdns_i2c_writereg((*(id->p_send_buf)++), CDNS_I2C_DATA_OFFSET); 6648c2ecf20Sopenharmony_ci id->send_count--; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* 6688c2ecf20Sopenharmony_ci * Clear the bus hold flag if there is no more data 6698c2ecf20Sopenharmony_ci * and if it is the last message. 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_ci if (!id->bus_hold_flag && !id->send_count) 6728c2ecf20Sopenharmony_ci cdns_i2c_clear_bus_hold(id); 6738c2ecf20Sopenharmony_ci /* Set the slave address in address register - triggers operation. */ 6748c2ecf20Sopenharmony_ci cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, 6758c2ecf20Sopenharmony_ci CDNS_I2C_ADDR_OFFSET); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/** 6818c2ecf20Sopenharmony_ci * cdns_i2c_master_reset - Reset the interface 6828c2ecf20Sopenharmony_ci * @adap: pointer to the i2c adapter driver instance 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * This function cleanup the fifos, clear the hold bit and status 6858c2ecf20Sopenharmony_ci * and disable the interrupts. 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_cistatic void cdns_i2c_master_reset(struct i2c_adapter *adap) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct cdns_i2c *id = adap->algo_data; 6908c2ecf20Sopenharmony_ci u32 regval; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* Disable the interrupts */ 6938c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET); 6948c2ecf20Sopenharmony_ci /* Clear the hold bit and fifos */ 6958c2ecf20Sopenharmony_ci regval = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); 6968c2ecf20Sopenharmony_ci regval &= ~CDNS_I2C_CR_HOLD; 6978c2ecf20Sopenharmony_ci regval |= CDNS_I2C_CR_CLR_FIFO; 6988c2ecf20Sopenharmony_ci cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET); 6998c2ecf20Sopenharmony_ci /* Update the transfercount register to zero */ 7008c2ecf20Sopenharmony_ci cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET); 7018c2ecf20Sopenharmony_ci /* Clear the interrupt status register */ 7028c2ecf20Sopenharmony_ci regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); 7038c2ecf20Sopenharmony_ci cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET); 7048c2ecf20Sopenharmony_ci /* Clear the status register */ 7058c2ecf20Sopenharmony_ci regval = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET); 7068c2ecf20Sopenharmony_ci cdns_i2c_writereg(regval, CDNS_I2C_SR_OFFSET); 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, 7108c2ecf20Sopenharmony_ci struct i2c_adapter *adap) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci unsigned long time_left, msg_timeout; 7138c2ecf20Sopenharmony_ci u32 reg; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci id->p_msg = msg; 7168c2ecf20Sopenharmony_ci id->err_status = 0; 7178c2ecf20Sopenharmony_ci reinit_completion(&id->xfer_done); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* Check for the TEN Bit mode on each msg */ 7208c2ecf20Sopenharmony_ci reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); 7218c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_TEN) { 7228c2ecf20Sopenharmony_ci if (reg & CDNS_I2C_CR_NEA) 7238c2ecf20Sopenharmony_ci cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA, 7248c2ecf20Sopenharmony_ci CDNS_I2C_CR_OFFSET); 7258c2ecf20Sopenharmony_ci } else { 7268c2ecf20Sopenharmony_ci if (!(reg & CDNS_I2C_CR_NEA)) 7278c2ecf20Sopenharmony_ci cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA, 7288c2ecf20Sopenharmony_ci CDNS_I2C_CR_OFFSET); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Check for the R/W flag on each msg */ 7328c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_RD) 7338c2ecf20Sopenharmony_ci cdns_i2c_mrecv(id); 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci cdns_i2c_msend(id); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Minimal time to execute this message */ 7388c2ecf20Sopenharmony_ci msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk); 7398c2ecf20Sopenharmony_ci /* Plus some wiggle room */ 7408c2ecf20Sopenharmony_ci msg_timeout += msecs_to_jiffies(500); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (msg_timeout < adap->timeout) 7438c2ecf20Sopenharmony_ci msg_timeout = adap->timeout; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Wait for the signal of completion */ 7468c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); 7478c2ecf20Sopenharmony_ci if (time_left == 0) { 7488c2ecf20Sopenharmony_ci cdns_i2c_master_reset(adap); 7498c2ecf20Sopenharmony_ci dev_err(id->adap.dev.parent, 7508c2ecf20Sopenharmony_ci "timeout waiting on completion\n"); 7518c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, 7558c2ecf20Sopenharmony_ci CDNS_I2C_IDR_OFFSET); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* If it is bus arbitration error, try again */ 7588c2ecf20Sopenharmony_ci if (id->err_status & CDNS_I2C_IXR_ARB_LOST) 7598c2ecf20Sopenharmony_ci return -EAGAIN; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_RECV_LEN) 7628c2ecf20Sopenharmony_ci msg->len += min_t(unsigned int, msg->buf[0], I2C_SMBUS_BLOCK_MAX); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci/** 7688c2ecf20Sopenharmony_ci * cdns_i2c_master_xfer - The main i2c transfer function 7698c2ecf20Sopenharmony_ci * @adap: pointer to the i2c adapter driver instance 7708c2ecf20Sopenharmony_ci * @msgs: pointer to the i2c message structure 7718c2ecf20Sopenharmony_ci * @num: the number of messages to transfer 7728c2ecf20Sopenharmony_ci * 7738c2ecf20Sopenharmony_ci * Initiates the send/recv activity based on the transfer message received. 7748c2ecf20Sopenharmony_ci * 7758c2ecf20Sopenharmony_ci * Return: number of msgs processed on success, negative error otherwise 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_cistatic int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 7788c2ecf20Sopenharmony_ci int num) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci int ret, count; 7818c2ecf20Sopenharmony_ci u32 reg; 7828c2ecf20Sopenharmony_ci struct cdns_i2c *id = adap->algo_data; 7838c2ecf20Sopenharmony_ci bool hold_quirk; 7848c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 7858c2ecf20Sopenharmony_ci bool change_role = false; 7868c2ecf20Sopenharmony_ci#endif 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(id->dev); 7898c2ecf20Sopenharmony_ci if (ret < 0) 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 7938c2ecf20Sopenharmony_ci /* Check i2c operating mode and switch if possible */ 7948c2ecf20Sopenharmony_ci if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { 7958c2ecf20Sopenharmony_ci if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) { 7968c2ecf20Sopenharmony_ci ret = -EAGAIN; 7978c2ecf20Sopenharmony_ci goto out; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* Set mode to master */ 8018c2ecf20Sopenharmony_ci cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* Mark flag to change role once xfer is completed */ 8048c2ecf20Sopenharmony_ci change_role = true; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci#endif 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Check if the bus is free */ 8098c2ecf20Sopenharmony_ci if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) { 8108c2ecf20Sopenharmony_ci ret = -EAGAIN; 8118c2ecf20Sopenharmony_ci goto out; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); 8158c2ecf20Sopenharmony_ci /* 8168c2ecf20Sopenharmony_ci * Set the flag to one when multiple messages are to be 8178c2ecf20Sopenharmony_ci * processed with a repeated start. 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_ci if (num > 1) { 8208c2ecf20Sopenharmony_ci /* 8218c2ecf20Sopenharmony_ci * This controller does not give completion interrupt after a 8228c2ecf20Sopenharmony_ci * master receive message if HOLD bit is set (repeated start), 8238c2ecf20Sopenharmony_ci * resulting in SW timeout. Hence, if a receive message is 8248c2ecf20Sopenharmony_ci * followed by any other message, an error is returned 8258c2ecf20Sopenharmony_ci * indicating that this sequence is not supported. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci for (count = 0; (count < num - 1 && hold_quirk); count++) { 8288c2ecf20Sopenharmony_ci if (msgs[count].flags & I2C_M_RD) { 8298c2ecf20Sopenharmony_ci dev_warn(adap->dev.parent, 8308c2ecf20Sopenharmony_ci "Can't do repeated start after a receive message\n"); 8318c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 8328c2ecf20Sopenharmony_ci goto out; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci id->bus_hold_flag = 1; 8368c2ecf20Sopenharmony_ci reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); 8378c2ecf20Sopenharmony_ci reg |= CDNS_I2C_CR_HOLD; 8388c2ecf20Sopenharmony_ci cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET); 8398c2ecf20Sopenharmony_ci } else { 8408c2ecf20Sopenharmony_ci id->bus_hold_flag = 0; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* Process the msg one by one */ 8448c2ecf20Sopenharmony_ci for (count = 0; count < num; count++, msgs++) { 8458c2ecf20Sopenharmony_ci if (count == (num - 1)) 8468c2ecf20Sopenharmony_ci id->bus_hold_flag = 0; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci ret = cdns_i2c_process_msg(id, msgs, adap); 8498c2ecf20Sopenharmony_ci if (ret) 8508c2ecf20Sopenharmony_ci goto out; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* Report the other error interrupts to application */ 8538c2ecf20Sopenharmony_ci if (id->err_status) { 8548c2ecf20Sopenharmony_ci cdns_i2c_master_reset(adap); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (id->err_status & CDNS_I2C_IXR_NACK) { 8578c2ecf20Sopenharmony_ci ret = -ENXIO; 8588c2ecf20Sopenharmony_ci goto out; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci ret = -EIO; 8618c2ecf20Sopenharmony_ci goto out; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci ret = num; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ciout: 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 8708c2ecf20Sopenharmony_ci /* Switch i2c mode to slave */ 8718c2ecf20Sopenharmony_ci if (change_role) 8728c2ecf20Sopenharmony_ci cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id); 8738c2ecf20Sopenharmony_ci#endif 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(id->dev); 8768c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(id->dev); 8778c2ecf20Sopenharmony_ci return ret; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci/** 8818c2ecf20Sopenharmony_ci * cdns_i2c_func - Returns the supported features of the I2C driver 8828c2ecf20Sopenharmony_ci * @adap: pointer to the i2c adapter structure 8838c2ecf20Sopenharmony_ci * 8848c2ecf20Sopenharmony_ci * Return: 32 bit value, each bit corresponding to a feature 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_cistatic u32 cdns_i2c_func(struct i2c_adapter *adap) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | 8898c2ecf20Sopenharmony_ci (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | 8908c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BLOCK_DATA; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 8938c2ecf20Sopenharmony_ci func |= I2C_FUNC_SLAVE; 8948c2ecf20Sopenharmony_ci#endif 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci return func; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 9008c2ecf20Sopenharmony_cistatic int cdns_reg_slave(struct i2c_client *slave) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci int ret; 9038c2ecf20Sopenharmony_ci struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c, 9048c2ecf20Sopenharmony_ci adap); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (id->slave) 9078c2ecf20Sopenharmony_ci return -EBUSY; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (slave->flags & I2C_CLIENT_TEN) 9108c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(id->dev); 9138c2ecf20Sopenharmony_ci if (ret < 0) 9148c2ecf20Sopenharmony_ci return ret; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* Store slave information */ 9178c2ecf20Sopenharmony_ci id->slave = slave; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* Enable I2C slave */ 9208c2ecf20Sopenharmony_ci cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci return 0; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic int cdns_unreg_slave(struct i2c_client *slave) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c, 9288c2ecf20Sopenharmony_ci adap); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci pm_runtime_put(id->dev); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* Remove slave information */ 9338c2ecf20Sopenharmony_ci id->slave = NULL; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Enable I2C master */ 9368c2ecf20Sopenharmony_ci cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci#endif 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic const struct i2c_algorithm cdns_i2c_algo = { 9438c2ecf20Sopenharmony_ci .master_xfer = cdns_i2c_master_xfer, 9448c2ecf20Sopenharmony_ci .functionality = cdns_i2c_func, 9458c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 9468c2ecf20Sopenharmony_ci .reg_slave = cdns_reg_slave, 9478c2ecf20Sopenharmony_ci .unreg_slave = cdns_unreg_slave, 9488c2ecf20Sopenharmony_ci#endif 9498c2ecf20Sopenharmony_ci}; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci/** 9528c2ecf20Sopenharmony_ci * cdns_i2c_calc_divs - Calculate clock dividers 9538c2ecf20Sopenharmony_ci * @f: I2C clock frequency 9548c2ecf20Sopenharmony_ci * @input_clk: Input clock frequency 9558c2ecf20Sopenharmony_ci * @a: First divider (return value) 9568c2ecf20Sopenharmony_ci * @b: Second divider (return value) 9578c2ecf20Sopenharmony_ci * 9588c2ecf20Sopenharmony_ci * f is used as input and output variable. As input it is used as target I2C 9598c2ecf20Sopenharmony_ci * frequency. On function exit f holds the actually resulting I2C frequency. 9608c2ecf20Sopenharmony_ci * 9618c2ecf20Sopenharmony_ci * Return: 0 on success, negative errno otherwise. 9628c2ecf20Sopenharmony_ci */ 9638c2ecf20Sopenharmony_cistatic int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk, 9648c2ecf20Sopenharmony_ci unsigned int *a, unsigned int *b) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp; 9678c2ecf20Sopenharmony_ci unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0; 9688c2ecf20Sopenharmony_ci unsigned int last_error, current_error; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* calculate (divisor_a+1) x (divisor_b+1) */ 9718c2ecf20Sopenharmony_ci temp = input_clk / (22 * fscl); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* 9748c2ecf20Sopenharmony_ci * If the calculated value is negative or 0, the fscl input is out of 9758c2ecf20Sopenharmony_ci * range. Return error. 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX))) 9788c2ecf20Sopenharmony_ci return -EINVAL; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci last_error = -1; 9818c2ecf20Sopenharmony_ci for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) { 9828c2ecf20Sopenharmony_ci div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1)); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX)) 9858c2ecf20Sopenharmony_ci continue; 9868c2ecf20Sopenharmony_ci div_b--; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1)); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (actual_fscl > fscl) 9918c2ecf20Sopenharmony_ci continue; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) : 9948c2ecf20Sopenharmony_ci (fscl - actual_fscl)); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (last_error > current_error) { 9978c2ecf20Sopenharmony_ci calc_div_a = div_a; 9988c2ecf20Sopenharmony_ci calc_div_b = div_b; 9998c2ecf20Sopenharmony_ci best_fscl = actual_fscl; 10008c2ecf20Sopenharmony_ci last_error = current_error; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci *a = calc_div_a; 10058c2ecf20Sopenharmony_ci *b = calc_div_b; 10068c2ecf20Sopenharmony_ci *f = best_fscl; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci return 0; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci/** 10128c2ecf20Sopenharmony_ci * cdns_i2c_setclk - This function sets the serial clock rate for the I2C device 10138c2ecf20Sopenharmony_ci * @clk_in: I2C clock input frequency in Hz 10148c2ecf20Sopenharmony_ci * @id: Pointer to the I2C device structure 10158c2ecf20Sopenharmony_ci * 10168c2ecf20Sopenharmony_ci * The device must be idle rather than busy transferring data before setting 10178c2ecf20Sopenharmony_ci * these device options. 10188c2ecf20Sopenharmony_ci * The data rate is set by values in the control register. 10198c2ecf20Sopenharmony_ci * The formula for determining the correct register values is 10208c2ecf20Sopenharmony_ci * Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1)) 10218c2ecf20Sopenharmony_ci * See the hardware data sheet for a full explanation of setting the serial 10228c2ecf20Sopenharmony_ci * clock rate. The clock can not be faster than the input clock divide by 22. 10238c2ecf20Sopenharmony_ci * The two most common clock rates are 100KHz and 400KHz. 10248c2ecf20Sopenharmony_ci * 10258c2ecf20Sopenharmony_ci * Return: 0 on success, negative error otherwise 10268c2ecf20Sopenharmony_ci */ 10278c2ecf20Sopenharmony_cistatic int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci unsigned int div_a, div_b; 10308c2ecf20Sopenharmony_ci unsigned int ctrl_reg; 10318c2ecf20Sopenharmony_ci int ret = 0; 10328c2ecf20Sopenharmony_ci unsigned long fscl = id->i2c_clk; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b); 10358c2ecf20Sopenharmony_ci if (ret) 10368c2ecf20Sopenharmony_ci return ret; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); 10398c2ecf20Sopenharmony_ci ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK); 10408c2ecf20Sopenharmony_ci ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) | 10418c2ecf20Sopenharmony_ci (div_b << CDNS_I2C_CR_DIVB_SHIFT)); 10428c2ecf20Sopenharmony_ci cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); 10438c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 10448c2ecf20Sopenharmony_ci id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK | 10458c2ecf20Sopenharmony_ci CDNS_I2C_CR_DIVB_MASK); 10468c2ecf20Sopenharmony_ci#endif 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci/** 10518c2ecf20Sopenharmony_ci * cdns_i2c_clk_notifier_cb - Clock rate change callback 10528c2ecf20Sopenharmony_ci * @nb: Pointer to notifier block 10538c2ecf20Sopenharmony_ci * @event: Notification reason 10548c2ecf20Sopenharmony_ci * @data: Pointer to notification data object 10558c2ecf20Sopenharmony_ci * 10568c2ecf20Sopenharmony_ci * This function is called when the cdns_i2c input clock frequency changes. 10578c2ecf20Sopenharmony_ci * The callback checks whether a valid bus frequency can be generated after the 10588c2ecf20Sopenharmony_ci * change. If so, the change is acknowledged, otherwise the change is aborted. 10598c2ecf20Sopenharmony_ci * New dividers are written to the HW in the pre- or post change notification 10608c2ecf20Sopenharmony_ci * depending on the scaling direction. 10618c2ecf20Sopenharmony_ci * 10628c2ecf20Sopenharmony_ci * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK 10638c2ecf20Sopenharmony_ci * to acknowledge the change, NOTIFY_DONE if the notification is 10648c2ecf20Sopenharmony_ci * considered irrelevant. 10658c2ecf20Sopenharmony_ci */ 10668c2ecf20Sopenharmony_cistatic int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long 10678c2ecf20Sopenharmony_ci event, void *data) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct clk_notifier_data *ndata = data; 10708c2ecf20Sopenharmony_ci struct cdns_i2c *id = to_cdns_i2c(nb); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (pm_runtime_suspended(id->dev)) 10738c2ecf20Sopenharmony_ci return NOTIFY_OK; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci switch (event) { 10768c2ecf20Sopenharmony_ci case PRE_RATE_CHANGE: 10778c2ecf20Sopenharmony_ci { 10788c2ecf20Sopenharmony_ci unsigned long input_clk = ndata->new_rate; 10798c2ecf20Sopenharmony_ci unsigned long fscl = id->i2c_clk; 10808c2ecf20Sopenharmony_ci unsigned int div_a, div_b; 10818c2ecf20Sopenharmony_ci int ret; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci ret = cdns_i2c_calc_divs(&fscl, input_clk, &div_a, &div_b); 10848c2ecf20Sopenharmony_ci if (ret) { 10858c2ecf20Sopenharmony_ci dev_warn(id->adap.dev.parent, 10868c2ecf20Sopenharmony_ci "clock rate change rejected\n"); 10878c2ecf20Sopenharmony_ci return NOTIFY_STOP; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci /* scale up */ 10918c2ecf20Sopenharmony_ci if (ndata->new_rate > ndata->old_rate) 10928c2ecf20Sopenharmony_ci cdns_i2c_setclk(ndata->new_rate, id); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci return NOTIFY_OK; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci case POST_RATE_CHANGE: 10978c2ecf20Sopenharmony_ci id->input_clk = ndata->new_rate; 10988c2ecf20Sopenharmony_ci /* scale down */ 10998c2ecf20Sopenharmony_ci if (ndata->new_rate < ndata->old_rate) 11008c2ecf20Sopenharmony_ci cdns_i2c_setclk(ndata->new_rate, id); 11018c2ecf20Sopenharmony_ci return NOTIFY_OK; 11028c2ecf20Sopenharmony_ci case ABORT_RATE_CHANGE: 11038c2ecf20Sopenharmony_ci /* scale up */ 11048c2ecf20Sopenharmony_ci if (ndata->new_rate > ndata->old_rate) 11058c2ecf20Sopenharmony_ci cdns_i2c_setclk(ndata->old_rate, id); 11068c2ecf20Sopenharmony_ci return NOTIFY_OK; 11078c2ecf20Sopenharmony_ci default: 11088c2ecf20Sopenharmony_ci return NOTIFY_DONE; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci/** 11138c2ecf20Sopenharmony_ci * cdns_i2c_runtime_suspend - Runtime suspend method for the driver 11148c2ecf20Sopenharmony_ci * @dev: Address of the platform_device structure 11158c2ecf20Sopenharmony_ci * 11168c2ecf20Sopenharmony_ci * Put the driver into low power mode. 11178c2ecf20Sopenharmony_ci * 11188c2ecf20Sopenharmony_ci * Return: 0 always 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_cistatic int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct cdns_i2c *xi2c = dev_get_drvdata(dev); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci clk_disable(xi2c->clk); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci return 0; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci/** 11308c2ecf20Sopenharmony_ci * cdns_i2c_runtime_resume - Runtime resume 11318c2ecf20Sopenharmony_ci * @dev: Address of the platform_device structure 11328c2ecf20Sopenharmony_ci * 11338c2ecf20Sopenharmony_ci * Runtime resume callback. 11348c2ecf20Sopenharmony_ci * 11358c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 11368c2ecf20Sopenharmony_ci */ 11378c2ecf20Sopenharmony_cistatic int __maybe_unused cdns_i2c_runtime_resume(struct device *dev) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct cdns_i2c *xi2c = dev_get_drvdata(dev); 11408c2ecf20Sopenharmony_ci int ret; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci ret = clk_enable(xi2c->clk); 11438c2ecf20Sopenharmony_ci if (ret) { 11448c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable clock.\n"); 11458c2ecf20Sopenharmony_ci return ret; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci return 0; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic const struct dev_pm_ops cdns_i2c_dev_pm_ops = { 11528c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend, 11538c2ecf20Sopenharmony_ci cdns_i2c_runtime_resume, NULL) 11548c2ecf20Sopenharmony_ci}; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic const struct cdns_platform_data r1p10_i2c_def = { 11578c2ecf20Sopenharmony_ci .quirks = CDNS_I2C_BROKEN_HOLD_BIT, 11588c2ecf20Sopenharmony_ci}; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cistatic const struct of_device_id cdns_i2c_of_match[] = { 11618c2ecf20Sopenharmony_ci { .compatible = "cdns,i2c-r1p10", .data = &r1p10_i2c_def }, 11628c2ecf20Sopenharmony_ci { .compatible = "cdns,i2c-r1p14",}, 11638c2ecf20Sopenharmony_ci { /* end of table */ } 11648c2ecf20Sopenharmony_ci}; 11658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cdns_i2c_of_match); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci/** 11688c2ecf20Sopenharmony_ci * cdns_i2c_probe - Platform registration call 11698c2ecf20Sopenharmony_ci * @pdev: Handle to the platform device structure 11708c2ecf20Sopenharmony_ci * 11718c2ecf20Sopenharmony_ci * This function does all the memory allocation and registration for the i2c 11728c2ecf20Sopenharmony_ci * device. User can modify the address mode to 10 bit address mode using the 11738c2ecf20Sopenharmony_ci * ioctl call with option I2C_TENBIT. 11748c2ecf20Sopenharmony_ci * 11758c2ecf20Sopenharmony_ci * Return: 0 on success, negative error otherwise 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_cistatic int cdns_i2c_probe(struct platform_device *pdev) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct resource *r_mem; 11808c2ecf20Sopenharmony_ci struct cdns_i2c *id; 11818c2ecf20Sopenharmony_ci int ret; 11828c2ecf20Sopenharmony_ci const struct of_device_id *match; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL); 11858c2ecf20Sopenharmony_ci if (!id) 11868c2ecf20Sopenharmony_ci return -ENOMEM; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci id->dev = &pdev->dev; 11898c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, id); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node); 11928c2ecf20Sopenharmony_ci if (match && match->data) { 11938c2ecf20Sopenharmony_ci const struct cdns_platform_data *data = match->data; 11948c2ecf20Sopenharmony_ci id->quirks = data->quirks; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci id->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem); 11988c2ecf20Sopenharmony_ci if (IS_ERR(id->membase)) 11998c2ecf20Sopenharmony_ci return PTR_ERR(id->membase); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci ret = platform_get_irq(pdev, 0); 12028c2ecf20Sopenharmony_ci if (ret < 0) 12038c2ecf20Sopenharmony_ci return ret; 12048c2ecf20Sopenharmony_ci id->irq = ret; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci id->adap.owner = THIS_MODULE; 12078c2ecf20Sopenharmony_ci id->adap.dev.of_node = pdev->dev.of_node; 12088c2ecf20Sopenharmony_ci id->adap.algo = &cdns_i2c_algo; 12098c2ecf20Sopenharmony_ci id->adap.timeout = CDNS_I2C_TIMEOUT; 12108c2ecf20Sopenharmony_ci id->adap.retries = 3; /* Default retry value. */ 12118c2ecf20Sopenharmony_ci id->adap.algo_data = id; 12128c2ecf20Sopenharmony_ci id->adap.dev.parent = &pdev->dev; 12138c2ecf20Sopenharmony_ci init_completion(&id->xfer_done); 12148c2ecf20Sopenharmony_ci snprintf(id->adap.name, sizeof(id->adap.name), 12158c2ecf20Sopenharmony_ci "Cadence I2C at %08lx", (unsigned long)r_mem->start); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci id->clk = devm_clk_get(&pdev->dev, NULL); 12188c2ecf20Sopenharmony_ci if (IS_ERR(id->clk)) { 12198c2ecf20Sopenharmony_ci if (PTR_ERR(id->clk) != -EPROBE_DEFER) 12208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "input clock not found.\n"); 12218c2ecf20Sopenharmony_ci return PTR_ERR(id->clk); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci ret = clk_prepare_enable(id->clk); 12248c2ecf20Sopenharmony_ci if (ret) 12258c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to enable clock.\n"); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT); 12288c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(id->dev); 12298c2ecf20Sopenharmony_ci pm_runtime_set_active(id->dev); 12308c2ecf20Sopenharmony_ci pm_runtime_enable(id->dev); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb; 12338c2ecf20Sopenharmony_ci if (clk_notifier_register(id->clk, &id->clk_rate_change_nb)) 12348c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); 12358c2ecf20Sopenharmony_ci id->input_clk = clk_get_rate(id->clk); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", 12388c2ecf20Sopenharmony_ci &id->i2c_clk); 12398c2ecf20Sopenharmony_ci if (ret || (id->i2c_clk > I2C_MAX_FAST_MODE_FREQ)) 12408c2ecf20Sopenharmony_ci id->i2c_clk = I2C_MAX_STANDARD_MODE_FREQ; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE) 12438c2ecf20Sopenharmony_ci /* Set initial mode to master */ 12448c2ecf20Sopenharmony_ci id->dev_mode = CDNS_I2C_MODE_MASTER; 12458c2ecf20Sopenharmony_ci id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; 12468c2ecf20Sopenharmony_ci#endif 12478c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_CR_MASTER_EN_MASK, CDNS_I2C_CR_OFFSET); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci ret = cdns_i2c_setclk(id->input_clk, id); 12508c2ecf20Sopenharmony_ci if (ret) { 12518c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk); 12528c2ecf20Sopenharmony_ci ret = -EINVAL; 12538c2ecf20Sopenharmony_ci goto err_clk_dis; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0, 12578c2ecf20Sopenharmony_ci DRIVER_NAME, id); 12588c2ecf20Sopenharmony_ci if (ret) { 12598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot get irq %d\n", id->irq); 12608c2ecf20Sopenharmony_ci goto err_clk_dis; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* 12648c2ecf20Sopenharmony_ci * Cadence I2C controller has a bug wherein it generates 12658c2ecf20Sopenharmony_ci * invalid read transaction after HW timeout in master receiver mode. 12668c2ecf20Sopenharmony_ci * HW timeout is not used by this driver and the interrupt is disabled. 12678c2ecf20Sopenharmony_ci * But the feature itself cannot be disabled. Hence maximum value 12688c2ecf20Sopenharmony_ci * is written to this register to reduce the chances of error. 12698c2ecf20Sopenharmony_ci */ 12708c2ecf20Sopenharmony_ci cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&id->adap); 12738c2ecf20Sopenharmony_ci if (ret < 0) 12748c2ecf20Sopenharmony_ci goto err_clk_dis; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n", 12778c2ecf20Sopenharmony_ci id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cierr_clk_dis: 12828c2ecf20Sopenharmony_ci clk_notifier_unregister(id->clk, &id->clk_rate_change_nb); 12838c2ecf20Sopenharmony_ci clk_disable_unprepare(id->clk); 12848c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 12858c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 12868c2ecf20Sopenharmony_ci return ret; 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci/** 12908c2ecf20Sopenharmony_ci * cdns_i2c_remove - Unregister the device after releasing the resources 12918c2ecf20Sopenharmony_ci * @pdev: Handle to the platform device structure 12928c2ecf20Sopenharmony_ci * 12938c2ecf20Sopenharmony_ci * This function frees all the resources allocated to the device. 12948c2ecf20Sopenharmony_ci * 12958c2ecf20Sopenharmony_ci * Return: 0 always 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_cistatic int cdns_i2c_remove(struct platform_device *pdev) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct cdns_i2c *id = platform_get_drvdata(pdev); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 13028c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 13038c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci i2c_del_adapter(&id->adap); 13068c2ecf20Sopenharmony_ci clk_notifier_unregister(id->clk, &id->clk_rate_change_nb); 13078c2ecf20Sopenharmony_ci clk_disable_unprepare(id->clk); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return 0; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic struct platform_driver cdns_i2c_drv = { 13138c2ecf20Sopenharmony_ci .driver = { 13148c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 13158c2ecf20Sopenharmony_ci .of_match_table = cdns_i2c_of_match, 13168c2ecf20Sopenharmony_ci .pm = &cdns_i2c_dev_pm_ops, 13178c2ecf20Sopenharmony_ci }, 13188c2ecf20Sopenharmony_ci .probe = cdns_i2c_probe, 13198c2ecf20Sopenharmony_ci .remove = cdns_i2c_remove, 13208c2ecf20Sopenharmony_ci}; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_cimodule_platform_driver(cdns_i2c_drv); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xilinx Inc."); 13258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cadence I2C bus driver"); 13268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1327