18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/acpi.h> 58c2ecf20Sopenharmony_ci#include <linux/clk.h> 68c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 78c2ecf20Sopenharmony_ci#include <linux/err.h> 88c2ecf20Sopenharmony_ci#include <linux/i2c.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 158c2ecf20Sopenharmony_ci#include <linux/qcom-geni-se.h> 168c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define SE_I2C_TX_TRANS_LEN 0x26c 198c2ecf20Sopenharmony_ci#define SE_I2C_RX_TRANS_LEN 0x270 208c2ecf20Sopenharmony_ci#define SE_I2C_SCL_COUNTERS 0x278 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SE_I2C_ERR (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\ 238c2ecf20Sopenharmony_ci M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN) 248c2ecf20Sopenharmony_ci#define SE_I2C_ABORT BIT(1) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* M_CMD OP codes for I2C */ 278c2ecf20Sopenharmony_ci#define I2C_WRITE 0x1 288c2ecf20Sopenharmony_ci#define I2C_READ 0x2 298c2ecf20Sopenharmony_ci#define I2C_WRITE_READ 0x3 308c2ecf20Sopenharmony_ci#define I2C_ADDR_ONLY 0x4 318c2ecf20Sopenharmony_ci#define I2C_BUS_CLEAR 0x6 328c2ecf20Sopenharmony_ci#define I2C_STOP_ON_BUS 0x7 338c2ecf20Sopenharmony_ci/* M_CMD params for I2C */ 348c2ecf20Sopenharmony_ci#define PRE_CMD_DELAY BIT(0) 358c2ecf20Sopenharmony_ci#define TIMESTAMP_BEFORE BIT(1) 368c2ecf20Sopenharmony_ci#define STOP_STRETCH BIT(2) 378c2ecf20Sopenharmony_ci#define TIMESTAMP_AFTER BIT(3) 388c2ecf20Sopenharmony_ci#define POST_COMMAND_DELAY BIT(4) 398c2ecf20Sopenharmony_ci#define IGNORE_ADD_NACK BIT(6) 408c2ecf20Sopenharmony_ci#define READ_FINISHED_WITH_ACK BIT(7) 418c2ecf20Sopenharmony_ci#define BYPASS_ADDR_PHASE BIT(8) 428c2ecf20Sopenharmony_ci#define SLV_ADDR_MSK GENMASK(15, 9) 438c2ecf20Sopenharmony_ci#define SLV_ADDR_SHFT 9 448c2ecf20Sopenharmony_ci/* I2C SCL COUNTER fields */ 458c2ecf20Sopenharmony_ci#define HIGH_COUNTER_MSK GENMASK(29, 20) 468c2ecf20Sopenharmony_ci#define HIGH_COUNTER_SHFT 20 478c2ecf20Sopenharmony_ci#define LOW_COUNTER_MSK GENMASK(19, 10) 488c2ecf20Sopenharmony_ci#define LOW_COUNTER_SHFT 10 498c2ecf20Sopenharmony_ci#define CYCLE_COUNTER_MSK GENMASK(9, 0) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cienum geni_i2c_err_code { 528c2ecf20Sopenharmony_ci GP_IRQ0, 538c2ecf20Sopenharmony_ci NACK, 548c2ecf20Sopenharmony_ci GP_IRQ2, 558c2ecf20Sopenharmony_ci BUS_PROTO, 568c2ecf20Sopenharmony_ci ARB_LOST, 578c2ecf20Sopenharmony_ci GP_IRQ5, 588c2ecf20Sopenharmony_ci GENI_OVERRUN, 598c2ecf20Sopenharmony_ci GENI_ILLEGAL_CMD, 608c2ecf20Sopenharmony_ci GENI_ABORT_DONE, 618c2ecf20Sopenharmony_ci GENI_TIMEOUT, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \ 658c2ecf20Sopenharmony_ci << 5) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define I2C_AUTO_SUSPEND_DELAY 250 688c2ecf20Sopenharmony_ci#define KHZ(freq) (1000 * freq) 698c2ecf20Sopenharmony_ci#define PACKING_BYTES_PW 4 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define ABORT_TIMEOUT HZ 728c2ecf20Sopenharmony_ci#define XFER_TIMEOUT HZ 738c2ecf20Sopenharmony_ci#define RST_TIMEOUT HZ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct geni_i2c_dev { 768c2ecf20Sopenharmony_ci struct geni_se se; 778c2ecf20Sopenharmony_ci u32 tx_wm; 788c2ecf20Sopenharmony_ci int irq; 798c2ecf20Sopenharmony_ci int err; 808c2ecf20Sopenharmony_ci struct i2c_adapter adap; 818c2ecf20Sopenharmony_ci struct completion done; 828c2ecf20Sopenharmony_ci struct i2c_msg *cur; 838c2ecf20Sopenharmony_ci int cur_wr; 848c2ecf20Sopenharmony_ci int cur_rd; 858c2ecf20Sopenharmony_ci spinlock_t lock; 868c2ecf20Sopenharmony_ci u32 clk_freq_out; 878c2ecf20Sopenharmony_ci const struct geni_i2c_clk_fld *clk_fld; 888c2ecf20Sopenharmony_ci int suspended; 898c2ecf20Sopenharmony_ci void *dma_buf; 908c2ecf20Sopenharmony_ci size_t xfer_len; 918c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct geni_i2c_err_log { 958c2ecf20Sopenharmony_ci int err; 968c2ecf20Sopenharmony_ci const char *msg; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic const struct geni_i2c_err_log gi2c_log[] = { 1008c2ecf20Sopenharmony_ci [GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"}, 1018c2ecf20Sopenharmony_ci [NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"}, 1028c2ecf20Sopenharmony_ci [GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"}, 1038c2ecf20Sopenharmony_ci [BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unepxected start/stop"}, 1048c2ecf20Sopenharmony_ci [ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"}, 1058c2ecf20Sopenharmony_ci [GP_IRQ5] = {-EIO, "Unknown I2C err GP IRQ5"}, 1068c2ecf20Sopenharmony_ci [GENI_OVERRUN] = {-EIO, "Cmd overrun, check GENI cmd-state machine"}, 1078c2ecf20Sopenharmony_ci [GENI_ILLEGAL_CMD] = {-EIO, "Illegal cmd, check GENI cmd-state machine"}, 1088c2ecf20Sopenharmony_ci [GENI_ABORT_DONE] = {-ETIMEDOUT, "Abort after timeout successful"}, 1098c2ecf20Sopenharmony_ci [GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"}, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistruct geni_i2c_clk_fld { 1138c2ecf20Sopenharmony_ci u32 clk_freq_out; 1148c2ecf20Sopenharmony_ci u8 clk_div; 1158c2ecf20Sopenharmony_ci u8 t_high_cnt; 1168c2ecf20Sopenharmony_ci u8 t_low_cnt; 1178c2ecf20Sopenharmony_ci u8 t_cycle_cnt; 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* 1218c2ecf20Sopenharmony_ci * Hardware uses the underlying formula to calculate time periods of 1228c2ecf20Sopenharmony_ci * SCL clock cycle. Firmware uses some additional cycles excluded from the 1238c2ecf20Sopenharmony_ci * below formula and it is confirmed that the time periods are within 1248c2ecf20Sopenharmony_ci * specification limits. 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * time of high period of SCL: t_high = (t_high_cnt * clk_div) / source_clock 1278c2ecf20Sopenharmony_ci * time of low period of SCL: t_low = (t_low_cnt * clk_div) / source_clock 1288c2ecf20Sopenharmony_ci * time of full period of SCL: t_cycle = (t_cycle_cnt * clk_div) / source_clock 1298c2ecf20Sopenharmony_ci * clk_freq_out = t / t_cycle 1308c2ecf20Sopenharmony_ci * source_clock = 19.2 MHz 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cistatic const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { 1338c2ecf20Sopenharmony_ci {KHZ(100), 7, 10, 11, 26}, 1348c2ecf20Sopenharmony_ci {KHZ(400), 2, 5, 12, 24}, 1358c2ecf20Sopenharmony_ci {KHZ(1000), 1, 3, 9, 18}, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int i; 1418c2ecf20Sopenharmony_ci const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { 1448c2ecf20Sopenharmony_ci if (itr->clk_freq_out == gi2c->clk_freq_out) { 1458c2ecf20Sopenharmony_ci gi2c->clk_fld = itr; 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci return -EINVAL; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; 1558c2ecf20Sopenharmony_ci u32 val; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci writel_relaxed(0, gi2c->se.base + SE_GENI_CLK_SEL); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci val = (itr->clk_div << CLK_DIV_SHFT) | SER_CLK_EN; 1608c2ecf20Sopenharmony_ci writel_relaxed(val, gi2c->se.base + GENI_SER_M_CLK_CFG); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci val = itr->t_high_cnt << HIGH_COUNTER_SHFT; 1638c2ecf20Sopenharmony_ci val |= itr->t_low_cnt << LOW_COUNTER_SHFT; 1648c2ecf20Sopenharmony_ci val |= itr->t_cycle_cnt; 1658c2ecf20Sopenharmony_ci writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void geni_i2c_err_misc(struct geni_i2c_dev *gi2c) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci u32 m_cmd = readl_relaxed(gi2c->se.base + SE_GENI_M_CMD0); 1718c2ecf20Sopenharmony_ci u32 m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); 1728c2ecf20Sopenharmony_ci u32 geni_s = readl_relaxed(gi2c->se.base + SE_GENI_STATUS); 1738c2ecf20Sopenharmony_ci u32 geni_ios = readl_relaxed(gi2c->se.base + SE_GENI_IOS); 1748c2ecf20Sopenharmony_ci u32 dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN); 1758c2ecf20Sopenharmony_ci u32 rx_st, tx_st; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (dma) { 1788c2ecf20Sopenharmony_ci rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); 1798c2ecf20Sopenharmony_ci tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); 1808c2ecf20Sopenharmony_ci } else { 1818c2ecf20Sopenharmony_ci rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS); 1828c2ecf20Sopenharmony_ci tx_st = readl_relaxed(gi2c->se.base + SE_GENI_TX_FIFO_STATUS); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci dev_dbg(gi2c->se.dev, "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n", 1858c2ecf20Sopenharmony_ci dma, tx_st, rx_st, m_stat); 1868c2ecf20Sopenharmony_ci dev_dbg(gi2c->se.dev, "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n", 1878c2ecf20Sopenharmony_ci m_cmd, geni_s, geni_ios); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci if (!gi2c->err) 1938c2ecf20Sopenharmony_ci gi2c->err = gi2c_log[err].err; 1948c2ecf20Sopenharmony_ci if (gi2c->cur) 1958c2ecf20Sopenharmony_ci dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n", 1968c2ecf20Sopenharmony_ci gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (err != NACK && err != GENI_ABORT_DONE) { 1998c2ecf20Sopenharmony_ci dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg); 2008c2ecf20Sopenharmony_ci geni_i2c_err_misc(gi2c); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic irqreturn_t geni_i2c_irq(int irq, void *dev) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = dev; 2078c2ecf20Sopenharmony_ci void __iomem *base = gi2c->se.base; 2088c2ecf20Sopenharmony_ci int j, p; 2098c2ecf20Sopenharmony_ci u32 m_stat; 2108c2ecf20Sopenharmony_ci u32 rx_st; 2118c2ecf20Sopenharmony_ci u32 dm_tx_st; 2128c2ecf20Sopenharmony_ci u32 dm_rx_st; 2138c2ecf20Sopenharmony_ci u32 dma; 2148c2ecf20Sopenharmony_ci u32 val; 2158c2ecf20Sopenharmony_ci struct i2c_msg *cur; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci spin_lock(&gi2c->lock); 2188c2ecf20Sopenharmony_ci m_stat = readl_relaxed(base + SE_GENI_M_IRQ_STATUS); 2198c2ecf20Sopenharmony_ci rx_st = readl_relaxed(base + SE_GENI_RX_FIFO_STATUS); 2208c2ecf20Sopenharmony_ci dm_tx_st = readl_relaxed(base + SE_DMA_TX_IRQ_STAT); 2218c2ecf20Sopenharmony_ci dm_rx_st = readl_relaxed(base + SE_DMA_RX_IRQ_STAT); 2228c2ecf20Sopenharmony_ci dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN); 2238c2ecf20Sopenharmony_ci cur = gi2c->cur; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!cur || 2268c2ecf20Sopenharmony_ci m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) || 2278c2ecf20Sopenharmony_ci dm_rx_st & (DM_I2C_CB_ERR)) { 2288c2ecf20Sopenharmony_ci if (m_stat & M_GP_IRQ_1_EN) 2298c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, NACK); 2308c2ecf20Sopenharmony_ci if (m_stat & M_GP_IRQ_3_EN) 2318c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, BUS_PROTO); 2328c2ecf20Sopenharmony_ci if (m_stat & M_GP_IRQ_4_EN) 2338c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, ARB_LOST); 2348c2ecf20Sopenharmony_ci if (m_stat & M_CMD_OVERRUN_EN) 2358c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, GENI_OVERRUN); 2368c2ecf20Sopenharmony_ci if (m_stat & M_ILLEGAL_CMD_EN) 2378c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, GENI_ILLEGAL_CMD); 2388c2ecf20Sopenharmony_ci if (m_stat & M_CMD_ABORT_EN) 2398c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, GENI_ABORT_DONE); 2408c2ecf20Sopenharmony_ci if (m_stat & M_GP_IRQ_0_EN) 2418c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, GP_IRQ0); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Disable the TX Watermark interrupt to stop TX */ 2448c2ecf20Sopenharmony_ci if (!dma) 2458c2ecf20Sopenharmony_ci writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG); 2468c2ecf20Sopenharmony_ci } else if (dma) { 2478c2ecf20Sopenharmony_ci dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n", 2488c2ecf20Sopenharmony_ci dm_tx_st, dm_rx_st); 2498c2ecf20Sopenharmony_ci } else if (cur->flags & I2C_M_RD && 2508c2ecf20Sopenharmony_ci m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) { 2518c2ecf20Sopenharmony_ci u32 rxcnt = rx_st & RX_FIFO_WC_MSK; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for (j = 0; j < rxcnt; j++) { 2548c2ecf20Sopenharmony_ci p = 0; 2558c2ecf20Sopenharmony_ci val = readl_relaxed(base + SE_GENI_RX_FIFOn); 2568c2ecf20Sopenharmony_ci while (gi2c->cur_rd < cur->len && p < sizeof(val)) { 2578c2ecf20Sopenharmony_ci cur->buf[gi2c->cur_rd++] = val & 0xff; 2588c2ecf20Sopenharmony_ci val >>= 8; 2598c2ecf20Sopenharmony_ci p++; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci if (gi2c->cur_rd == cur->len) 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci } else if (!(cur->flags & I2C_M_RD) && 2658c2ecf20Sopenharmony_ci m_stat & M_TX_FIFO_WATERMARK_EN) { 2668c2ecf20Sopenharmony_ci for (j = 0; j < gi2c->tx_wm; j++) { 2678c2ecf20Sopenharmony_ci u32 temp; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci val = 0; 2708c2ecf20Sopenharmony_ci p = 0; 2718c2ecf20Sopenharmony_ci while (gi2c->cur_wr < cur->len && p < sizeof(val)) { 2728c2ecf20Sopenharmony_ci temp = cur->buf[gi2c->cur_wr++]; 2738c2ecf20Sopenharmony_ci val |= temp << (p * 8); 2748c2ecf20Sopenharmony_ci p++; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci writel_relaxed(val, base + SE_GENI_TX_FIFOn); 2778c2ecf20Sopenharmony_ci /* TX Complete, Disable the TX Watermark interrupt */ 2788c2ecf20Sopenharmony_ci if (gi2c->cur_wr == cur->len) { 2798c2ecf20Sopenharmony_ci writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG); 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (m_stat) 2868c2ecf20Sopenharmony_ci writel_relaxed(m_stat, base + SE_GENI_M_IRQ_CLEAR); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (dma && dm_tx_st) 2898c2ecf20Sopenharmony_ci writel_relaxed(dm_tx_st, base + SE_DMA_TX_IRQ_CLR); 2908c2ecf20Sopenharmony_ci if (dma && dm_rx_st) 2918c2ecf20Sopenharmony_ci writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* if this is err with done-bit not set, handle that through timeout. */ 2948c2ecf20Sopenharmony_ci if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN || 2958c2ecf20Sopenharmony_ci dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE || 2968c2ecf20Sopenharmony_ci dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE) 2978c2ecf20Sopenharmony_ci complete(&gi2c->done); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci spin_unlock(&gi2c->lock); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci u32 val; 3078c2ecf20Sopenharmony_ci unsigned long time_left = ABORT_TIMEOUT; 3088c2ecf20Sopenharmony_ci unsigned long flags; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci spin_lock_irqsave(&gi2c->lock, flags); 3118c2ecf20Sopenharmony_ci geni_i2c_err(gi2c, GENI_TIMEOUT); 3128c2ecf20Sopenharmony_ci gi2c->cur = NULL; 3138c2ecf20Sopenharmony_ci geni_se_abort_m_cmd(&gi2c->se); 3148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gi2c->lock, flags); 3158c2ecf20Sopenharmony_ci do { 3168c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&gi2c->done, time_left); 3178c2ecf20Sopenharmony_ci val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); 3188c2ecf20Sopenharmony_ci } while (!(val & M_CMD_ABORT_EN) && time_left); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!(val & M_CMD_ABORT_EN)) 3218c2ecf20Sopenharmony_ci dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n"); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci u32 val; 3278c2ecf20Sopenharmony_ci unsigned long time_left = RST_TIMEOUT; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST); 3308c2ecf20Sopenharmony_ci do { 3318c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&gi2c->done, time_left); 3328c2ecf20Sopenharmony_ci val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); 3338c2ecf20Sopenharmony_ci } while (!(val & RX_RESET_DONE) && time_left); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (!(val & RX_RESET_DONE)) 3368c2ecf20Sopenharmony_ci dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n"); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci u32 val; 3428c2ecf20Sopenharmony_ci unsigned long time_left = RST_TIMEOUT; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST); 3458c2ecf20Sopenharmony_ci do { 3468c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&gi2c->done, time_left); 3478c2ecf20Sopenharmony_ci val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); 3488c2ecf20Sopenharmony_ci } while (!(val & TX_RESET_DONE) && time_left); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (!(val & TX_RESET_DONE)) 3518c2ecf20Sopenharmony_ci dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n"); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c, 3558c2ecf20Sopenharmony_ci struct i2c_msg *cur) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci gi2c->cur_rd = 0; 3588c2ecf20Sopenharmony_ci if (gi2c->dma_buf) { 3598c2ecf20Sopenharmony_ci if (gi2c->err) 3608c2ecf20Sopenharmony_ci geni_i2c_rx_fsm_rst(gi2c); 3618c2ecf20Sopenharmony_ci geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len); 3628c2ecf20Sopenharmony_ci i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c, 3678c2ecf20Sopenharmony_ci struct i2c_msg *cur) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci gi2c->cur_wr = 0; 3708c2ecf20Sopenharmony_ci if (gi2c->dma_buf) { 3718c2ecf20Sopenharmony_ci if (gi2c->err) 3728c2ecf20Sopenharmony_ci geni_i2c_tx_fsm_rst(gi2c); 3738c2ecf20Sopenharmony_ci geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len); 3748c2ecf20Sopenharmony_ci i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, 3798c2ecf20Sopenharmony_ci u32 m_param) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci dma_addr_t rx_dma = 0; 3828c2ecf20Sopenharmony_ci unsigned long time_left; 3838c2ecf20Sopenharmony_ci void *dma_buf = NULL; 3848c2ecf20Sopenharmony_ci struct geni_se *se = &gi2c->se; 3858c2ecf20Sopenharmony_ci size_t len = msg->len; 3868c2ecf20Sopenharmony_ci struct i2c_msg *cur; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (!of_machine_is_compatible("lenovo,yoga-c630")) 3898c2ecf20Sopenharmony_ci dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (dma_buf) 3928c2ecf20Sopenharmony_ci geni_se_select_mode(se, GENI_SE_DMA); 3938c2ecf20Sopenharmony_ci else 3948c2ecf20Sopenharmony_ci geni_se_select_mode(se, GENI_SE_FIFO); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN); 3978c2ecf20Sopenharmony_ci geni_se_setup_m_cmd(se, I2C_READ, m_param); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) { 4008c2ecf20Sopenharmony_ci geni_se_select_mode(se, GENI_SE_FIFO); 4018c2ecf20Sopenharmony_ci i2c_put_dma_safe_msg_buf(dma_buf, msg, false); 4028c2ecf20Sopenharmony_ci dma_buf = NULL; 4038c2ecf20Sopenharmony_ci } else { 4048c2ecf20Sopenharmony_ci gi2c->xfer_len = len; 4058c2ecf20Sopenharmony_ci gi2c->dma_addr = rx_dma; 4068c2ecf20Sopenharmony_ci gi2c->dma_buf = dma_buf; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci cur = gi2c->cur; 4108c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); 4118c2ecf20Sopenharmony_ci if (!time_left) 4128c2ecf20Sopenharmony_ci geni_i2c_abort_xfer(gi2c); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci geni_i2c_rx_msg_cleanup(gi2c, cur); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return gi2c->err; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, 4208c2ecf20Sopenharmony_ci u32 m_param) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci dma_addr_t tx_dma = 0; 4238c2ecf20Sopenharmony_ci unsigned long time_left; 4248c2ecf20Sopenharmony_ci void *dma_buf = NULL; 4258c2ecf20Sopenharmony_ci struct geni_se *se = &gi2c->se; 4268c2ecf20Sopenharmony_ci size_t len = msg->len; 4278c2ecf20Sopenharmony_ci struct i2c_msg *cur; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (!of_machine_is_compatible("lenovo,yoga-c630")) 4308c2ecf20Sopenharmony_ci dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (dma_buf) 4338c2ecf20Sopenharmony_ci geni_se_select_mode(se, GENI_SE_DMA); 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci geni_se_select_mode(se, GENI_SE_FIFO); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN); 4388c2ecf20Sopenharmony_ci geni_se_setup_m_cmd(se, I2C_WRITE, m_param); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) { 4418c2ecf20Sopenharmony_ci geni_se_select_mode(se, GENI_SE_FIFO); 4428c2ecf20Sopenharmony_ci i2c_put_dma_safe_msg_buf(dma_buf, msg, false); 4438c2ecf20Sopenharmony_ci dma_buf = NULL; 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci gi2c->xfer_len = len; 4468c2ecf20Sopenharmony_ci gi2c->dma_addr = tx_dma; 4478c2ecf20Sopenharmony_ci gi2c->dma_buf = dma_buf; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!dma_buf) /* Get FIFO IRQ */ 4518c2ecf20Sopenharmony_ci writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci cur = gi2c->cur; 4548c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); 4558c2ecf20Sopenharmony_ci if (!time_left) 4568c2ecf20Sopenharmony_ci geni_i2c_abort_xfer(gi2c); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci geni_i2c_tx_msg_cleanup(gi2c, cur); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return gi2c->err; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int geni_i2c_xfer(struct i2c_adapter *adap, 4648c2ecf20Sopenharmony_ci struct i2c_msg msgs[], 4658c2ecf20Sopenharmony_ci int num) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap); 4688c2ecf20Sopenharmony_ci int i, ret; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci gi2c->err = 0; 4718c2ecf20Sopenharmony_ci reinit_completion(&gi2c->done); 4728c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(gi2c->se.dev); 4738c2ecf20Sopenharmony_ci if (ret < 0) { 4748c2ecf20Sopenharmony_ci dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret); 4758c2ecf20Sopenharmony_ci pm_runtime_put_noidle(gi2c->se.dev); 4768c2ecf20Sopenharmony_ci /* Set device in suspended since resume failed */ 4778c2ecf20Sopenharmony_ci pm_runtime_set_suspended(gi2c->se.dev); 4788c2ecf20Sopenharmony_ci return ret; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci qcom_geni_i2c_conf(gi2c); 4828c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 4838c2ecf20Sopenharmony_ci u32 m_param = i < (num - 1) ? STOP_STRETCH : 0; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci gi2c->cur = &msgs[i]; 4888c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 4898c2ecf20Sopenharmony_ci ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param); 4908c2ecf20Sopenharmony_ci else 4918c2ecf20Sopenharmony_ci ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (ret) 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci if (ret == 0) 4978c2ecf20Sopenharmony_ci ret = num; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(gi2c->se.dev); 5008c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(gi2c->se.dev); 5018c2ecf20Sopenharmony_ci gi2c->cur = NULL; 5028c2ecf20Sopenharmony_ci gi2c->err = 0; 5038c2ecf20Sopenharmony_ci return ret; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic u32 geni_i2c_func(struct i2c_adapter *adap) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic const struct i2c_algorithm geni_i2c_algo = { 5128c2ecf20Sopenharmony_ci .master_xfer = geni_i2c_xfer, 5138c2ecf20Sopenharmony_ci .functionality = geni_i2c_func, 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 5178c2ecf20Sopenharmony_cistatic const struct acpi_device_id geni_i2c_acpi_match[] = { 5188c2ecf20Sopenharmony_ci { "QCOM0220"}, 5198c2ecf20Sopenharmony_ci { }, 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match); 5228c2ecf20Sopenharmony_ci#endif 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int geni_i2c_probe(struct platform_device *pdev) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c; 5278c2ecf20Sopenharmony_ci struct resource *res; 5288c2ecf20Sopenharmony_ci u32 proto, tx_depth; 5298c2ecf20Sopenharmony_ci int ret; 5308c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci gi2c = devm_kzalloc(dev, sizeof(*gi2c), GFP_KERNEL); 5338c2ecf20Sopenharmony_ci if (!gi2c) 5348c2ecf20Sopenharmony_ci return -ENOMEM; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci gi2c->se.dev = dev; 5378c2ecf20Sopenharmony_ci gi2c->se.wrapper = dev_get_drvdata(dev->parent); 5388c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5398c2ecf20Sopenharmony_ci gi2c->se.base = devm_ioremap_resource(dev, res); 5408c2ecf20Sopenharmony_ci if (IS_ERR(gi2c->se.base)) 5418c2ecf20Sopenharmony_ci return PTR_ERR(gi2c->se.base); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci gi2c->se.clk = devm_clk_get(dev, "se"); 5448c2ecf20Sopenharmony_ci if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(dev)) 5458c2ecf20Sopenharmony_ci return PTR_ERR(gi2c->se.clk); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "clock-frequency", 5488c2ecf20Sopenharmony_ci &gi2c->clk_freq_out); 5498c2ecf20Sopenharmony_ci if (ret) { 5508c2ecf20Sopenharmony_ci dev_info(dev, "Bus frequency not specified, default to 100kHz.\n"); 5518c2ecf20Sopenharmony_ci gi2c->clk_freq_out = KHZ(100); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (has_acpi_companion(dev)) 5558c2ecf20Sopenharmony_ci ACPI_COMPANION_SET(&gi2c->adap.dev, ACPI_COMPANION(dev)); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci gi2c->irq = platform_get_irq(pdev, 0); 5588c2ecf20Sopenharmony_ci if (gi2c->irq < 0) 5598c2ecf20Sopenharmony_ci return gi2c->irq; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ret = geni_i2c_clk_map_idx(gi2c); 5628c2ecf20Sopenharmony_ci if (ret) { 5638c2ecf20Sopenharmony_ci dev_err(dev, "Invalid clk frequency %d Hz: %d\n", 5648c2ecf20Sopenharmony_ci gi2c->clk_freq_out, ret); 5658c2ecf20Sopenharmony_ci return ret; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci gi2c->adap.algo = &geni_i2c_algo; 5698c2ecf20Sopenharmony_ci init_completion(&gi2c->done); 5708c2ecf20Sopenharmony_ci spin_lock_init(&gi2c->lock); 5718c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, gi2c); 5728c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0, 5738c2ecf20Sopenharmony_ci dev_name(dev), gi2c); 5748c2ecf20Sopenharmony_ci if (ret) { 5758c2ecf20Sopenharmony_ci dev_err(dev, "Request_irq failed:%d: err:%d\n", 5768c2ecf20Sopenharmony_ci gi2c->irq, ret); 5778c2ecf20Sopenharmony_ci return ret; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci /* Disable the interrupt so that the system can enter low-power mode */ 5808c2ecf20Sopenharmony_ci disable_irq(gi2c->irq); 5818c2ecf20Sopenharmony_ci i2c_set_adapdata(&gi2c->adap, gi2c); 5828c2ecf20Sopenharmony_ci gi2c->adap.dev.parent = dev; 5838c2ecf20Sopenharmony_ci gi2c->adap.dev.of_node = dev->of_node; 5848c2ecf20Sopenharmony_ci strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name)); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci ret = geni_icc_get(&gi2c->se, "qup-memory"); 5878c2ecf20Sopenharmony_ci if (ret) 5888c2ecf20Sopenharmony_ci return ret; 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * Set the bus quota for core and cpu to a reasonable value for 5918c2ecf20Sopenharmony_ci * register access. 5928c2ecf20Sopenharmony_ci * Set quota for DDR based on bus speed. 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_ci gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW; 5958c2ecf20Sopenharmony_ci gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; 5968c2ecf20Sopenharmony_ci gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ret = geni_icc_set_bw(&gi2c->se); 5998c2ecf20Sopenharmony_ci if (ret) 6008c2ecf20Sopenharmony_ci return ret; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci ret = geni_se_resources_on(&gi2c->se); 6038c2ecf20Sopenharmony_ci if (ret) { 6048c2ecf20Sopenharmony_ci dev_err(dev, "Error turning on resources %d\n", ret); 6058c2ecf20Sopenharmony_ci return ret; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci proto = geni_se_read_proto(&gi2c->se); 6088c2ecf20Sopenharmony_ci tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se); 6098c2ecf20Sopenharmony_ci if (proto != GENI_SE_I2C) { 6108c2ecf20Sopenharmony_ci dev_err(dev, "Invalid proto %d\n", proto); 6118c2ecf20Sopenharmony_ci geni_se_resources_off(&gi2c->se); 6128c2ecf20Sopenharmony_ci return -ENXIO; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci gi2c->tx_wm = tx_depth - 1; 6158c2ecf20Sopenharmony_ci geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth); 6168c2ecf20Sopenharmony_ci geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, PACKING_BYTES_PW, 6178c2ecf20Sopenharmony_ci true, true, true); 6188c2ecf20Sopenharmony_ci ret = geni_se_resources_off(&gi2c->se); 6198c2ecf20Sopenharmony_ci if (ret) { 6208c2ecf20Sopenharmony_ci dev_err(dev, "Error turning off resources %d\n", ret); 6218c2ecf20Sopenharmony_ci return ret; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ret = geni_icc_disable(&gi2c->se); 6258c2ecf20Sopenharmony_ci if (ret) 6268c2ecf20Sopenharmony_ci return ret; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci gi2c->suspended = 1; 6318c2ecf20Sopenharmony_ci pm_runtime_set_suspended(gi2c->se.dev); 6328c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY); 6338c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(gi2c->se.dev); 6348c2ecf20Sopenharmony_ci pm_runtime_enable(gi2c->se.dev); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&gi2c->adap); 6378c2ecf20Sopenharmony_ci if (ret) { 6388c2ecf20Sopenharmony_ci dev_err(dev, "Error adding i2c adapter %d\n", ret); 6398c2ecf20Sopenharmony_ci pm_runtime_disable(gi2c->se.dev); 6408c2ecf20Sopenharmony_ci return ret; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci dev_dbg(dev, "Geni-I2C adaptor successfully added\n"); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic int geni_i2c_remove(struct platform_device *pdev) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci i2c_del_adapter(&gi2c->adap); 6538c2ecf20Sopenharmony_ci pm_runtime_disable(gi2c->se.dev); 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic void geni_i2c_shutdown(struct platform_device *pdev) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Make client i2c transfers start failing */ 6628c2ecf20Sopenharmony_ci i2c_mark_adapter_suspended(&gi2c->adap); 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci int ret; 6688c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci disable_irq(gi2c->irq); 6718c2ecf20Sopenharmony_ci ret = geni_se_resources_off(&gi2c->se); 6728c2ecf20Sopenharmony_ci if (ret) { 6738c2ecf20Sopenharmony_ci enable_irq(gi2c->irq); 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci } else { 6778c2ecf20Sopenharmony_ci gi2c->suspended = 1; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci return geni_icc_disable(&gi2c->se); 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int __maybe_unused geni_i2c_runtime_resume(struct device *dev) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci int ret; 6868c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci ret = geni_icc_enable(&gi2c->se); 6898c2ecf20Sopenharmony_ci if (ret) 6908c2ecf20Sopenharmony_ci return ret; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ret = geni_se_resources_on(&gi2c->se); 6938c2ecf20Sopenharmony_ci if (ret) 6948c2ecf20Sopenharmony_ci return ret; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci enable_irq(gi2c->irq); 6978c2ecf20Sopenharmony_ci gi2c->suspended = 0; 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int __maybe_unused geni_i2c_suspend_noirq(struct device *dev) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci i2c_mark_adapter_suspended(&gi2c->adap); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (!gi2c->suspended) { 7088c2ecf20Sopenharmony_ci geni_i2c_runtime_suspend(dev); 7098c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 7108c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 7118c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci return 0; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int __maybe_unused geni_i2c_resume_noirq(struct device *dev) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci i2c_mark_adapter_resumed(&gi2c->adap); 7218c2ecf20Sopenharmony_ci return 0; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic const struct dev_pm_ops geni_i2c_pm_ops = { 7258c2ecf20Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, geni_i2c_resume_noirq) 7268c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(geni_i2c_runtime_suspend, geni_i2c_runtime_resume, 7278c2ecf20Sopenharmony_ci NULL) 7288c2ecf20Sopenharmony_ci}; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic const struct of_device_id geni_i2c_dt_match[] = { 7318c2ecf20Sopenharmony_ci { .compatible = "qcom,geni-i2c" }, 7328c2ecf20Sopenharmony_ci {} 7338c2ecf20Sopenharmony_ci}; 7348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, geni_i2c_dt_match); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic struct platform_driver geni_i2c_driver = { 7378c2ecf20Sopenharmony_ci .probe = geni_i2c_probe, 7388c2ecf20Sopenharmony_ci .remove = geni_i2c_remove, 7398c2ecf20Sopenharmony_ci .shutdown = geni_i2c_shutdown, 7408c2ecf20Sopenharmony_ci .driver = { 7418c2ecf20Sopenharmony_ci .name = "geni_i2c", 7428c2ecf20Sopenharmony_ci .pm = &geni_i2c_pm_ops, 7438c2ecf20Sopenharmony_ci .of_match_table = geni_i2c_dt_match, 7448c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(geni_i2c_acpi_match), 7458c2ecf20Sopenharmony_ci }, 7468c2ecf20Sopenharmony_ci}; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cimodule_platform_driver(geni_i2c_driver); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("I2C Controller Driver for GENI based QUP cores"); 7518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 752