18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. 38c2ecf20Sopenharmony_ci// Copyright (c) 2017-20 Linaro Limited. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/clk.h> 68c2ecf20Sopenharmony_ci#include <linux/completion.h> 78c2ecf20Sopenharmony_ci#include <linux/i2c.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define CCI_HW_VERSION 0x0 168c2ecf20Sopenharmony_ci#define CCI_RESET_CMD 0x004 178c2ecf20Sopenharmony_ci#define CCI_RESET_CMD_MASK 0x0f73f3f7 188c2ecf20Sopenharmony_ci#define CCI_RESET_CMD_M0_MASK 0x000003f1 198c2ecf20Sopenharmony_ci#define CCI_RESET_CMD_M1_MASK 0x0003f001 208c2ecf20Sopenharmony_ci#define CCI_QUEUE_START 0x008 218c2ecf20Sopenharmony_ci#define CCI_HALT_REQ 0x034 228c2ecf20Sopenharmony_ci#define CCI_HALT_REQ_I2C_M0_Q0Q1 BIT(0) 238c2ecf20Sopenharmony_ci#define CCI_HALT_REQ_I2C_M1_Q0Q1 BIT(1) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_SCL_CTL(m) (0x100 + 0x100 * (m)) 268c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_SDA_CTL_0(m) (0x104 + 0x100 * (m)) 278c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_SDA_CTL_1(m) (0x108 + 0x100 * (m)) 288c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_SDA_CTL_2(m) (0x10c + 0x100 * (m)) 298c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_MISC_CTL(m) (0x110 + 0x100 * (m)) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_READ_DATA(m) (0x118 + 0x100 * (m)) 328c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_READ_BUF_LEVEL(m) (0x11c + 0x100 * (m)) 338c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_Qn_EXEC_WORD_CNT(m, n) (0x300 + 0x200 * (m) + 0x100 * (n)) 348c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_Qn_CUR_WORD_CNT(m, n) (0x304 + 0x200 * (m) + 0x100 * (n)) 358c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_Qn_CUR_CMD(m, n) (0x308 + 0x200 * (m) + 0x100 * (n)) 368c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_Qn_REPORT_STATUS(m, n) (0x30c + 0x200 * (m) + 0x100 * (n)) 378c2ecf20Sopenharmony_ci#define CCI_I2C_Mm_Qn_LOAD_DATA(m, n) (0x310 + 0x200 * (m) + 0x100 * (n)) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define CCI_IRQ_GLOBAL_CLEAR_CMD 0xc00 408c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0 0xc04 418c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_RD_DONE BIT(0) 428c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT BIT(4) 438c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_Q1_REPORT BIT(8) 448c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_RD_DONE BIT(12) 458c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_Q0_REPORT BIT(16) 468c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_Q1_REPORT BIT(20) 478c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_RST_DONE_ACK BIT(24) 488c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_Q0Q1_HALT_ACK BIT(25) 498c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_Q0Q1_HALT_ACK BIT(26) 508c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_ERROR 0x18000ee6 518c2ecf20Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_ERROR 0x60ee6000 528c2ecf20Sopenharmony_ci#define CCI_IRQ_CLEAR_0 0xc08 538c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0 0xc0c 548c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE BIT(0) 558c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT BIT(4) 568c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT BIT(8) 578c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE BIT(12) 588c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT BIT(16) 598c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT BIT(20) 608c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_RST_DONE_ACK BIT(24) 618c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK BIT(25) 628c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK BIT(26) 638c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR BIT(27) 648c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR BIT(28) 658c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR BIT(29) 668c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR BIT(30) 678c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_ERROR 0x18000ee6 688c2ecf20Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_ERROR 0x60ee6000 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define CCI_TIMEOUT (msecs_to_jiffies(100)) 718c2ecf20Sopenharmony_ci#define NUM_MASTERS 2 728c2ecf20Sopenharmony_ci#define NUM_QUEUES 2 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Max number of resources + 1 for a NULL terminator */ 758c2ecf20Sopenharmony_ci#define CCI_RES_MAX 6 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define CCI_I2C_SET_PARAM 1 788c2ecf20Sopenharmony_ci#define CCI_I2C_REPORT 8 798c2ecf20Sopenharmony_ci#define CCI_I2C_WRITE 9 808c2ecf20Sopenharmony_ci#define CCI_I2C_READ 10 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define CCI_I2C_REPORT_IRQ_EN BIT(8) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cienum { 858c2ecf20Sopenharmony_ci I2C_MODE_STANDARD, 868c2ecf20Sopenharmony_ci I2C_MODE_FAST, 878c2ecf20Sopenharmony_ci I2C_MODE_FAST_PLUS, 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cienum cci_i2c_queue_t { 918c2ecf20Sopenharmony_ci QUEUE_0, 928c2ecf20Sopenharmony_ci QUEUE_1 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct hw_params { 968c2ecf20Sopenharmony_ci u16 thigh; /* HIGH period of the SCL clock in clock ticks */ 978c2ecf20Sopenharmony_ci u16 tlow; /* LOW period of the SCL clock */ 988c2ecf20Sopenharmony_ci u16 tsu_sto; /* set-up time for STOP condition */ 998c2ecf20Sopenharmony_ci u16 tsu_sta; /* set-up time for a repeated START condition */ 1008c2ecf20Sopenharmony_ci u16 thd_dat; /* data hold time */ 1018c2ecf20Sopenharmony_ci u16 thd_sta; /* hold time (repeated) START condition */ 1028c2ecf20Sopenharmony_ci u16 tbuf; /* bus free time between a STOP and START condition */ 1038c2ecf20Sopenharmony_ci u8 scl_stretch_en; 1048c2ecf20Sopenharmony_ci u16 trdhld; 1058c2ecf20Sopenharmony_ci u16 tsp; /* pulse width of spikes suppressed by the input filter */ 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistruct cci; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct cci_master { 1118c2ecf20Sopenharmony_ci struct i2c_adapter adap; 1128c2ecf20Sopenharmony_ci u16 master; 1138c2ecf20Sopenharmony_ci u8 mode; 1148c2ecf20Sopenharmony_ci int status; 1158c2ecf20Sopenharmony_ci struct completion irq_complete; 1168c2ecf20Sopenharmony_ci struct cci *cci; 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistruct cci_data { 1208c2ecf20Sopenharmony_ci unsigned int num_masters; 1218c2ecf20Sopenharmony_ci struct i2c_adapter_quirks quirks; 1228c2ecf20Sopenharmony_ci u16 queue_size[NUM_QUEUES]; 1238c2ecf20Sopenharmony_ci unsigned long cci_clk_rate; 1248c2ecf20Sopenharmony_ci struct hw_params params[3]; 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct cci { 1288c2ecf20Sopenharmony_ci struct device *dev; 1298c2ecf20Sopenharmony_ci void __iomem *base; 1308c2ecf20Sopenharmony_ci unsigned int irq; 1318c2ecf20Sopenharmony_ci const struct cci_data *data; 1328c2ecf20Sopenharmony_ci struct clk_bulk_data *clocks; 1338c2ecf20Sopenharmony_ci int nclocks; 1348c2ecf20Sopenharmony_ci struct cci_master master[NUM_MASTERS]; 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic irqreturn_t cci_isr(int irq, void *dev) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct cci *cci = dev; 1408c2ecf20Sopenharmony_ci u32 val, reset = 0; 1418c2ecf20Sopenharmony_ci int ret = IRQ_NONE; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci val = readl(cci->base + CCI_IRQ_STATUS_0); 1448c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_IRQ_CLEAR_0); 1458c2ecf20Sopenharmony_ci writel(0x1, cci->base + CCI_IRQ_GLOBAL_CLEAR_CMD); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_RST_DONE_ACK) { 1488c2ecf20Sopenharmony_ci complete(&cci->master[0].irq_complete); 1498c2ecf20Sopenharmony_ci if (cci->master[1].master) 1508c2ecf20Sopenharmony_ci complete(&cci->master[1].irq_complete); 1518c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE || 1558c2ecf20Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT || 1568c2ecf20Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT) { 1578c2ecf20Sopenharmony_ci cci->master[0].status = 0; 1588c2ecf20Sopenharmony_ci complete(&cci->master[0].irq_complete); 1598c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE || 1638c2ecf20Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT || 1648c2ecf20Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT) { 1658c2ecf20Sopenharmony_ci cci->master[1].status = 0; 1668c2ecf20Sopenharmony_ci complete(&cci->master[1].irq_complete); 1678c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK)) { 1718c2ecf20Sopenharmony_ci reset = CCI_RESET_CMD_M0_MASK; 1728c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK)) { 1768c2ecf20Sopenharmony_ci reset = CCI_RESET_CMD_M1_MASK; 1778c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (unlikely(reset)) 1818c2ecf20Sopenharmony_ci writel(reset, cci->base + CCI_RESET_CMD); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_ERROR)) { 1848c2ecf20Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR || 1858c2ecf20Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR) 1868c2ecf20Sopenharmony_ci cci->master[0].status = -ENXIO; 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci cci->master[0].status = -EIO; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci writel(CCI_HALT_REQ_I2C_M0_Q0Q1, cci->base + CCI_HALT_REQ); 1918c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_ERROR)) { 1958c2ecf20Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR || 1968c2ecf20Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR) 1978c2ecf20Sopenharmony_ci cci->master[1].status = -ENXIO; 1988c2ecf20Sopenharmony_ci else 1998c2ecf20Sopenharmony_ci cci->master[1].status = -EIO; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci writel(CCI_HALT_REQ_I2C_M1_Q0Q1, cci->base + CCI_HALT_REQ); 2028c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int cci_halt(struct cci *cci, u8 master_num) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct cci_master *master; 2118c2ecf20Sopenharmony_ci u32 val; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (master_num >= cci->data->num_masters) { 2148c2ecf20Sopenharmony_ci dev_err(cci->dev, "Unsupported master idx (%u)\n", master_num); 2158c2ecf20Sopenharmony_ci return -EINVAL; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci val = BIT(master_num); 2198c2ecf20Sopenharmony_ci master = &cci->master[master_num]; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci reinit_completion(&master->irq_complete); 2228c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_HALT_REQ); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&master->irq_complete, CCI_TIMEOUT)) { 2258c2ecf20Sopenharmony_ci dev_err(cci->dev, "CCI halt timeout\n"); 2268c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int cci_reset(struct cci *cci) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * we reset the whole controller, here and for implicity use 2368c2ecf20Sopenharmony_ci * master[0].xxx for waiting on it. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_ci reinit_completion(&cci->master[0].irq_complete); 2398c2ecf20Sopenharmony_ci writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&cci->master[0].irq_complete, 2428c2ecf20Sopenharmony_ci CCI_TIMEOUT)) { 2438c2ecf20Sopenharmony_ci dev_err(cci->dev, "CCI reset timeout\n"); 2448c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int cci_init(struct cci *cci) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci u32 val = CCI_IRQ_MASK_0_I2C_M0_RD_DONE | 2538c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT | 2548c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_Q1_REPORT | 2558c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_RD_DONE | 2568c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_Q0_REPORT | 2578c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_Q1_REPORT | 2588c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_RST_DONE_ACK | 2598c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_Q0Q1_HALT_ACK | 2608c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_Q0Q1_HALT_ACK | 2618c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_ERROR | 2628c2ecf20Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_ERROR; 2638c2ecf20Sopenharmony_ci int i; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_IRQ_MASK_0); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci for (i = 0; i < cci->data->num_masters; i++) { 2688c2ecf20Sopenharmony_ci int mode = cci->master[i].mode; 2698c2ecf20Sopenharmony_ci const struct hw_params *hw; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (!cci->master[i].cci) 2728c2ecf20Sopenharmony_ci continue; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci hw = &cci->data->params[mode]; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci val = hw->thigh << 16 | hw->tlow; 2778c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SCL_CTL(i)); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci val = hw->tsu_sto << 16 | hw->tsu_sta; 2808c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_0(i)); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci val = hw->thd_dat << 16 | hw->thd_sta; 2838c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_1(i)); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci val = hw->tbuf; 2868c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_2(i)); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci val = hw->scl_stretch_en << 8 | hw->trdhld << 4 | hw->tsp; 2898c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_MISC_CTL(i)); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int cci_run_queue(struct cci *cci, u8 master, u8 queue) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci u32 val; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci val = readl(cci->base + CCI_I2C_Mm_Qn_CUR_WORD_CNT(master, queue)); 3008c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_EXEC_WORD_CNT(master, queue)); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci reinit_completion(&cci->master[master].irq_complete); 3038c2ecf20Sopenharmony_ci val = BIT(master * 2 + queue); 3048c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_QUEUE_START); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&cci->master[master].irq_complete, 3078c2ecf20Sopenharmony_ci CCI_TIMEOUT)) { 3088c2ecf20Sopenharmony_ci dev_err(cci->dev, "master %d queue %d timeout\n", 3098c2ecf20Sopenharmony_ci master, queue); 3108c2ecf20Sopenharmony_ci cci_reset(cci); 3118c2ecf20Sopenharmony_ci cci_init(cci); 3128c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return cci->master[master].status; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int cci_validate_queue(struct cci *cci, u8 master, u8 queue) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci u32 val; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci val = readl(cci->base + CCI_I2C_Mm_Qn_CUR_WORD_CNT(master, queue)); 3238c2ecf20Sopenharmony_ci if (val == cci->data->queue_size[queue]) 3248c2ecf20Sopenharmony_ci return -EINVAL; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!val) 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN; 3308c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return cci_run_queue(cci, master, queue); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int cci_i2c_read(struct cci *cci, u16 master, 3368c2ecf20Sopenharmony_ci u16 addr, u8 *buf, u16 len) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci u32 val, words_read, words_exp; 3398c2ecf20Sopenharmony_ci u8 queue = QUEUE_1; 3408c2ecf20Sopenharmony_ci int i, index = 0, ret; 3418c2ecf20Sopenharmony_ci bool first = true; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Call validate queue to make sure queue is empty before starting. 3458c2ecf20Sopenharmony_ci * This is to avoid overflow / underflow of queue. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci ret = cci_validate_queue(cci, master, queue); 3488c2ecf20Sopenharmony_ci if (ret < 0) 3498c2ecf20Sopenharmony_ci return ret; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci val = CCI_I2C_SET_PARAM | (addr & 0x7f) << 4; 3528c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci val = CCI_I2C_READ | len << 4; 3558c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = cci_run_queue(cci, master, queue); 3588c2ecf20Sopenharmony_ci if (ret < 0) 3598c2ecf20Sopenharmony_ci return ret; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci words_read = readl(cci->base + CCI_I2C_Mm_READ_BUF_LEVEL(master)); 3628c2ecf20Sopenharmony_ci words_exp = len / 4 + 1; 3638c2ecf20Sopenharmony_ci if (words_read != words_exp) { 3648c2ecf20Sopenharmony_ci dev_err(cci->dev, "words read = %d, words expected = %d\n", 3658c2ecf20Sopenharmony_ci words_read, words_exp); 3668c2ecf20Sopenharmony_ci return -EIO; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci do { 3708c2ecf20Sopenharmony_ci val = readl(cci->base + CCI_I2C_Mm_READ_DATA(master)); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci for (i = 0; i < 4 && index < len; i++) { 3738c2ecf20Sopenharmony_ci if (first) { 3748c2ecf20Sopenharmony_ci /* The LS byte of this register represents the 3758c2ecf20Sopenharmony_ci * first byte read from the slave during a read 3768c2ecf20Sopenharmony_ci * access. 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci first = false; 3798c2ecf20Sopenharmony_ci continue; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci buf[index++] = (val >> (i * 8)) & 0xff; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci } while (--words_read); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int cci_i2c_write(struct cci *cci, u16 master, 3898c2ecf20Sopenharmony_ci u16 addr, u8 *buf, u16 len) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci u8 queue = QUEUE_0; 3928c2ecf20Sopenharmony_ci u8 load[12] = { 0 }; 3938c2ecf20Sopenharmony_ci int i = 0, j, ret; 3948c2ecf20Sopenharmony_ci u32 val; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* 3978c2ecf20Sopenharmony_ci * Call validate queue to make sure queue is empty before starting. 3988c2ecf20Sopenharmony_ci * This is to avoid overflow / underflow of queue. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ci ret = cci_validate_queue(cci, master, queue); 4018c2ecf20Sopenharmony_ci if (ret < 0) 4028c2ecf20Sopenharmony_ci return ret; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci val = CCI_I2C_SET_PARAM | (addr & 0x7f) << 4; 4058c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci load[i++] = CCI_I2C_WRITE | len << 4; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci for (j = 0; j < len; j++) 4108c2ecf20Sopenharmony_ci load[i++] = buf[j]; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci for (j = 0; j < i; j += 4) { 4138c2ecf20Sopenharmony_ci val = load[j]; 4148c2ecf20Sopenharmony_ci val |= load[j + 1] << 8; 4158c2ecf20Sopenharmony_ci val |= load[j + 2] << 16; 4168c2ecf20Sopenharmony_ci val |= load[j + 3] << 24; 4178c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN; 4218c2ecf20Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return cci_run_queue(cci, master, queue); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int cci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct cci_master *cci_master = i2c_get_adapdata(adap); 4298c2ecf20Sopenharmony_ci struct cci *cci = cci_master->cci; 4308c2ecf20Sopenharmony_ci int i, ret; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(cci->dev); 4338c2ecf20Sopenharmony_ci if (ret < 0) 4348c2ecf20Sopenharmony_ci goto err; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 4378c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 4388c2ecf20Sopenharmony_ci ret = cci_i2c_read(cci, cci_master->master, 4398c2ecf20Sopenharmony_ci msgs[i].addr, msgs[i].buf, 4408c2ecf20Sopenharmony_ci msgs[i].len); 4418c2ecf20Sopenharmony_ci else 4428c2ecf20Sopenharmony_ci ret = cci_i2c_write(cci, cci_master->master, 4438c2ecf20Sopenharmony_ci msgs[i].addr, msgs[i].buf, 4448c2ecf20Sopenharmony_ci msgs[i].len); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (ret < 0) 4478c2ecf20Sopenharmony_ci break; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!ret) 4518c2ecf20Sopenharmony_ci ret = num; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cierr: 4548c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(cci->dev); 4558c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(cci->dev); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return ret; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic u32 cci_func(struct i2c_adapter *adap) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic const struct i2c_algorithm cci_algo = { 4668c2ecf20Sopenharmony_ci .master_xfer = cci_xfer, 4678c2ecf20Sopenharmony_ci .functionality = cci_func, 4688c2ecf20Sopenharmony_ci}; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int cci_enable_clocks(struct cci *cci) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci return clk_bulk_prepare_enable(cci->nclocks, cci->clocks); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic void cci_disable_clocks(struct cci *cci) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci clk_bulk_disable_unprepare(cci->nclocks, cci->clocks); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int __maybe_unused cci_suspend_runtime(struct device *dev) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct cci *cci = dev_get_drvdata(dev); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci cci_disable_clocks(cci); 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int __maybe_unused cci_resume_runtime(struct device *dev) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct cci *cci = dev_get_drvdata(dev); 4918c2ecf20Sopenharmony_ci int ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci ret = cci_enable_clocks(cci); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci return ret; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci cci_init(cci); 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int __maybe_unused cci_suspend(struct device *dev) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(dev)) 5048c2ecf20Sopenharmony_ci return cci_suspend_runtime(dev); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int __maybe_unused cci_resume(struct device *dev) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci cci_resume_runtime(dev); 5128c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 5138c2ecf20Sopenharmony_ci pm_request_autosuspend(dev); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return 0; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic const struct dev_pm_ops qcom_cci_pm = { 5198c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(cci_suspend, cci_resume) 5208c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL) 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int cci_probe(struct platform_device *pdev) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5268c2ecf20Sopenharmony_ci unsigned long cci_clk_rate = 0; 5278c2ecf20Sopenharmony_ci struct device_node *child; 5288c2ecf20Sopenharmony_ci struct resource *r; 5298c2ecf20Sopenharmony_ci struct cci *cci; 5308c2ecf20Sopenharmony_ci int ret, i; 5318c2ecf20Sopenharmony_ci u32 val; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci cci = devm_kzalloc(dev, sizeof(*cci), GFP_KERNEL); 5348c2ecf20Sopenharmony_ci if (!cci) 5358c2ecf20Sopenharmony_ci return -ENOMEM; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci cci->dev = dev; 5388c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, cci); 5398c2ecf20Sopenharmony_ci cci->data = device_get_match_data(dev); 5408c2ecf20Sopenharmony_ci if (!cci->data) 5418c2ecf20Sopenharmony_ci return -ENOENT; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci for_each_available_child_of_node(dev->of_node, child) { 5448c2ecf20Sopenharmony_ci u32 idx; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci ret = of_property_read_u32(child, "reg", &idx); 5478c2ecf20Sopenharmony_ci if (ret) { 5488c2ecf20Sopenharmony_ci dev_err(dev, "%pOF invalid 'reg' property", child); 5498c2ecf20Sopenharmony_ci continue; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (idx >= cci->data->num_masters) { 5538c2ecf20Sopenharmony_ci dev_err(dev, "%pOF invalid 'reg' value: %u (max is %u)", 5548c2ecf20Sopenharmony_ci child, idx, cci->data->num_masters - 1); 5558c2ecf20Sopenharmony_ci continue; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci cci->master[idx].adap.quirks = &cci->data->quirks; 5598c2ecf20Sopenharmony_ci cci->master[idx].adap.algo = &cci_algo; 5608c2ecf20Sopenharmony_ci cci->master[idx].adap.dev.parent = dev; 5618c2ecf20Sopenharmony_ci cci->master[idx].adap.dev.of_node = of_node_get(child); 5628c2ecf20Sopenharmony_ci cci->master[idx].master = idx; 5638c2ecf20Sopenharmony_ci cci->master[idx].cci = cci; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci i2c_set_adapdata(&cci->master[idx].adap, &cci->master[idx]); 5668c2ecf20Sopenharmony_ci snprintf(cci->master[idx].adap.name, 5678c2ecf20Sopenharmony_ci sizeof(cci->master[idx].adap.name), "Qualcomm-CCI"); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci cci->master[idx].mode = I2C_MODE_STANDARD; 5708c2ecf20Sopenharmony_ci ret = of_property_read_u32(child, "clock-frequency", &val); 5718c2ecf20Sopenharmony_ci if (!ret) { 5728c2ecf20Sopenharmony_ci if (val == 400000) 5738c2ecf20Sopenharmony_ci cci->master[idx].mode = I2C_MODE_FAST; 5748c2ecf20Sopenharmony_ci else if (val == 1000000) 5758c2ecf20Sopenharmony_ci cci->master[idx].mode = I2C_MODE_FAST_PLUS; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci init_completion(&cci->master[idx].irq_complete); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* Memory */ 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5848c2ecf20Sopenharmony_ci cci->base = devm_ioremap_resource(dev, r); 5858c2ecf20Sopenharmony_ci if (IS_ERR(cci->base)) 5868c2ecf20Sopenharmony_ci return PTR_ERR(cci->base); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Clocks */ 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci ret = devm_clk_bulk_get_all(dev, &cci->clocks); 5918c2ecf20Sopenharmony_ci if (ret < 1) { 5928c2ecf20Sopenharmony_ci dev_err(dev, "failed to get clocks %d\n", ret); 5938c2ecf20Sopenharmony_ci return ret; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci cci->nclocks = ret; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* Retrieve CCI clock rate */ 5988c2ecf20Sopenharmony_ci for (i = 0; i < cci->nclocks; i++) { 5998c2ecf20Sopenharmony_ci if (!strcmp(cci->clocks[i].id, "cci")) { 6008c2ecf20Sopenharmony_ci cci_clk_rate = clk_get_rate(cci->clocks[i].clk); 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (cci_clk_rate != cci->data->cci_clk_rate) { 6068c2ecf20Sopenharmony_ci /* cci clock set by the bootloader or via assigned clock rate 6078c2ecf20Sopenharmony_ci * in DT. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n", 6108c2ecf20Sopenharmony_ci cci_clk_rate, cci->data->cci_clk_rate); 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ret = cci_enable_clocks(cci); 6148c2ecf20Sopenharmony_ci if (ret < 0) 6158c2ecf20Sopenharmony_ci return ret; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Interrupt */ 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci ret = platform_get_irq(pdev, 0); 6208c2ecf20Sopenharmony_ci if (ret < 0) 6218c2ecf20Sopenharmony_ci goto disable_clocks; 6228c2ecf20Sopenharmony_ci cci->irq = ret; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, cci->irq, cci_isr, 0, dev_name(dev), cci); 6258c2ecf20Sopenharmony_ci if (ret < 0) { 6268c2ecf20Sopenharmony_ci dev_err(dev, "request_irq failed, ret: %d\n", ret); 6278c2ecf20Sopenharmony_ci goto disable_clocks; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci val = readl(cci->base + CCI_HW_VERSION); 6318c2ecf20Sopenharmony_ci dev_dbg(dev, "CCI HW version = 0x%08x", val); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci ret = cci_reset(cci); 6348c2ecf20Sopenharmony_ci if (ret < 0) 6358c2ecf20Sopenharmony_ci goto error; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci ret = cci_init(cci); 6388c2ecf20Sopenharmony_ci if (ret < 0) 6398c2ecf20Sopenharmony_ci goto error; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); 6428c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 6438c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 6448c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci for (i = 0; i < cci->data->num_masters; i++) { 6478c2ecf20Sopenharmony_ci if (!cci->master[i].cci) 6488c2ecf20Sopenharmony_ci continue; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&cci->master[i].adap); 6518c2ecf20Sopenharmony_ci if (ret < 0) { 6528c2ecf20Sopenharmony_ci of_node_put(cci->master[i].adap.dev.of_node); 6538c2ecf20Sopenharmony_ci goto error_i2c; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cierror_i2c: 6608c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 6618c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci for (--i ; i >= 0; i--) { 6648c2ecf20Sopenharmony_ci if (cci->master[i].cci) { 6658c2ecf20Sopenharmony_ci i2c_del_adapter(&cci->master[i].adap); 6668c2ecf20Sopenharmony_ci of_node_put(cci->master[i].adap.dev.of_node); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_cierror: 6708c2ecf20Sopenharmony_ci disable_irq(cci->irq); 6718c2ecf20Sopenharmony_cidisable_clocks: 6728c2ecf20Sopenharmony_ci cci_disable_clocks(cci); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int cci_remove(struct platform_device *pdev) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct cci *cci = platform_get_drvdata(pdev); 6808c2ecf20Sopenharmony_ci int i; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci for (i = 0; i < cci->data->num_masters; i++) { 6838c2ecf20Sopenharmony_ci if (cci->master[i].cci) { 6848c2ecf20Sopenharmony_ci i2c_del_adapter(&cci->master[i].adap); 6858c2ecf20Sopenharmony_ci of_node_put(cci->master[i].adap.dev.of_node); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci cci_halt(cci, i); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci disable_irq(cci->irq); 6918c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 6928c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci return 0; 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic const struct cci_data cci_v1_data = { 6988c2ecf20Sopenharmony_ci .num_masters = 1, 6998c2ecf20Sopenharmony_ci .queue_size = { 64, 16 }, 7008c2ecf20Sopenharmony_ci .quirks = { 7018c2ecf20Sopenharmony_ci .max_write_len = 10, 7028c2ecf20Sopenharmony_ci .max_read_len = 12, 7038c2ecf20Sopenharmony_ci }, 7048c2ecf20Sopenharmony_ci .cci_clk_rate = 19200000, 7058c2ecf20Sopenharmony_ci .params[I2C_MODE_STANDARD] = { 7068c2ecf20Sopenharmony_ci .thigh = 78, 7078c2ecf20Sopenharmony_ci .tlow = 114, 7088c2ecf20Sopenharmony_ci .tsu_sto = 28, 7098c2ecf20Sopenharmony_ci .tsu_sta = 28, 7108c2ecf20Sopenharmony_ci .thd_dat = 10, 7118c2ecf20Sopenharmony_ci .thd_sta = 77, 7128c2ecf20Sopenharmony_ci .tbuf = 118, 7138c2ecf20Sopenharmony_ci .scl_stretch_en = 0, 7148c2ecf20Sopenharmony_ci .trdhld = 6, 7158c2ecf20Sopenharmony_ci .tsp = 1 7168c2ecf20Sopenharmony_ci }, 7178c2ecf20Sopenharmony_ci .params[I2C_MODE_FAST] = { 7188c2ecf20Sopenharmony_ci .thigh = 20, 7198c2ecf20Sopenharmony_ci .tlow = 28, 7208c2ecf20Sopenharmony_ci .tsu_sto = 21, 7218c2ecf20Sopenharmony_ci .tsu_sta = 21, 7228c2ecf20Sopenharmony_ci .thd_dat = 13, 7238c2ecf20Sopenharmony_ci .thd_sta = 18, 7248c2ecf20Sopenharmony_ci .tbuf = 32, 7258c2ecf20Sopenharmony_ci .scl_stretch_en = 0, 7268c2ecf20Sopenharmony_ci .trdhld = 6, 7278c2ecf20Sopenharmony_ci .tsp = 3 7288c2ecf20Sopenharmony_ci }, 7298c2ecf20Sopenharmony_ci}; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic const struct cci_data cci_v2_data = { 7328c2ecf20Sopenharmony_ci .num_masters = 2, 7338c2ecf20Sopenharmony_ci .queue_size = { 64, 16 }, 7348c2ecf20Sopenharmony_ci .quirks = { 7358c2ecf20Sopenharmony_ci .max_write_len = 11, 7368c2ecf20Sopenharmony_ci .max_read_len = 12, 7378c2ecf20Sopenharmony_ci }, 7388c2ecf20Sopenharmony_ci .cci_clk_rate = 37500000, 7398c2ecf20Sopenharmony_ci .params[I2C_MODE_STANDARD] = { 7408c2ecf20Sopenharmony_ci .thigh = 201, 7418c2ecf20Sopenharmony_ci .tlow = 174, 7428c2ecf20Sopenharmony_ci .tsu_sto = 204, 7438c2ecf20Sopenharmony_ci .tsu_sta = 231, 7448c2ecf20Sopenharmony_ci .thd_dat = 22, 7458c2ecf20Sopenharmony_ci .thd_sta = 162, 7468c2ecf20Sopenharmony_ci .tbuf = 227, 7478c2ecf20Sopenharmony_ci .scl_stretch_en = 0, 7488c2ecf20Sopenharmony_ci .trdhld = 6, 7498c2ecf20Sopenharmony_ci .tsp = 3 7508c2ecf20Sopenharmony_ci }, 7518c2ecf20Sopenharmony_ci .params[I2C_MODE_FAST] = { 7528c2ecf20Sopenharmony_ci .thigh = 38, 7538c2ecf20Sopenharmony_ci .tlow = 56, 7548c2ecf20Sopenharmony_ci .tsu_sto = 40, 7558c2ecf20Sopenharmony_ci .tsu_sta = 40, 7568c2ecf20Sopenharmony_ci .thd_dat = 22, 7578c2ecf20Sopenharmony_ci .thd_sta = 35, 7588c2ecf20Sopenharmony_ci .tbuf = 62, 7598c2ecf20Sopenharmony_ci .scl_stretch_en = 0, 7608c2ecf20Sopenharmony_ci .trdhld = 6, 7618c2ecf20Sopenharmony_ci .tsp = 3 7628c2ecf20Sopenharmony_ci }, 7638c2ecf20Sopenharmony_ci .params[I2C_MODE_FAST_PLUS] = { 7648c2ecf20Sopenharmony_ci .thigh = 16, 7658c2ecf20Sopenharmony_ci .tlow = 22, 7668c2ecf20Sopenharmony_ci .tsu_sto = 17, 7678c2ecf20Sopenharmony_ci .tsu_sta = 18, 7688c2ecf20Sopenharmony_ci .thd_dat = 16, 7698c2ecf20Sopenharmony_ci .thd_sta = 15, 7708c2ecf20Sopenharmony_ci .tbuf = 24, 7718c2ecf20Sopenharmony_ci .scl_stretch_en = 0, 7728c2ecf20Sopenharmony_ci .trdhld = 3, 7738c2ecf20Sopenharmony_ci .tsp = 3 7748c2ecf20Sopenharmony_ci }, 7758c2ecf20Sopenharmony_ci}; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic const struct of_device_id cci_dt_match[] = { 7788c2ecf20Sopenharmony_ci { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data}, 7798c2ecf20Sopenharmony_ci { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data}, 7808c2ecf20Sopenharmony_ci { .compatible = "qcom,sdm845-cci", .data = &cci_v2_data}, 7818c2ecf20Sopenharmony_ci {} 7828c2ecf20Sopenharmony_ci}; 7838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cci_dt_match); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic struct platform_driver qcom_cci_driver = { 7868c2ecf20Sopenharmony_ci .probe = cci_probe, 7878c2ecf20Sopenharmony_ci .remove = cci_remove, 7888c2ecf20Sopenharmony_ci .driver = { 7898c2ecf20Sopenharmony_ci .name = "i2c-qcom-cci", 7908c2ecf20Sopenharmony_ci .of_match_table = cci_dt_match, 7918c2ecf20Sopenharmony_ci .pm = &qcom_cci_pm, 7928c2ecf20Sopenharmony_ci }, 7938c2ecf20Sopenharmony_ci}; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cimodule_platform_driver(qcom_cci_driver); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Camera Control Interface driver"); 7988c2ecf20Sopenharmony_ciMODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); 7998c2ecf20Sopenharmony_ciMODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>"); 8008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 801