162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. 362306a36Sopenharmony_ci// Copyright (c) 2017-2022 Linaro Limited. 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/clk.h> 662306a36Sopenharmony_ci#include <linux/completion.h> 762306a36Sopenharmony_ci#include <linux/i2c.h> 862306a36Sopenharmony_ci#include <linux/io.h> 962306a36Sopenharmony_ci#include <linux/interrupt.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define CCI_HW_VERSION 0x0 1662306a36Sopenharmony_ci#define CCI_RESET_CMD 0x004 1762306a36Sopenharmony_ci#define CCI_RESET_CMD_MASK 0x0f73f3f7 1862306a36Sopenharmony_ci#define CCI_RESET_CMD_M0_MASK 0x000003f1 1962306a36Sopenharmony_ci#define CCI_RESET_CMD_M1_MASK 0x0003f001 2062306a36Sopenharmony_ci#define CCI_QUEUE_START 0x008 2162306a36Sopenharmony_ci#define CCI_HALT_REQ 0x034 2262306a36Sopenharmony_ci#define CCI_HALT_REQ_I2C_M0_Q0Q1 BIT(0) 2362306a36Sopenharmony_ci#define CCI_HALT_REQ_I2C_M1_Q0Q1 BIT(1) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define CCI_I2C_Mm_SCL_CTL(m) (0x100 + 0x100 * (m)) 2662306a36Sopenharmony_ci#define CCI_I2C_Mm_SDA_CTL_0(m) (0x104 + 0x100 * (m)) 2762306a36Sopenharmony_ci#define CCI_I2C_Mm_SDA_CTL_1(m) (0x108 + 0x100 * (m)) 2862306a36Sopenharmony_ci#define CCI_I2C_Mm_SDA_CTL_2(m) (0x10c + 0x100 * (m)) 2962306a36Sopenharmony_ci#define CCI_I2C_Mm_MISC_CTL(m) (0x110 + 0x100 * (m)) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define CCI_I2C_Mm_READ_DATA(m) (0x118 + 0x100 * (m)) 3262306a36Sopenharmony_ci#define CCI_I2C_Mm_READ_BUF_LEVEL(m) (0x11c + 0x100 * (m)) 3362306a36Sopenharmony_ci#define CCI_I2C_Mm_Qn_EXEC_WORD_CNT(m, n) (0x300 + 0x200 * (m) + 0x100 * (n)) 3462306a36Sopenharmony_ci#define CCI_I2C_Mm_Qn_CUR_WORD_CNT(m, n) (0x304 + 0x200 * (m) + 0x100 * (n)) 3562306a36Sopenharmony_ci#define CCI_I2C_Mm_Qn_CUR_CMD(m, n) (0x308 + 0x200 * (m) + 0x100 * (n)) 3662306a36Sopenharmony_ci#define CCI_I2C_Mm_Qn_REPORT_STATUS(m, n) (0x30c + 0x200 * (m) + 0x100 * (n)) 3762306a36Sopenharmony_ci#define CCI_I2C_Mm_Qn_LOAD_DATA(m, n) (0x310 + 0x200 * (m) + 0x100 * (n)) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define CCI_IRQ_GLOBAL_CLEAR_CMD 0xc00 4062306a36Sopenharmony_ci#define CCI_IRQ_MASK_0 0xc04 4162306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_RD_DONE BIT(0) 4262306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT BIT(4) 4362306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_Q1_REPORT BIT(8) 4462306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_RD_DONE BIT(12) 4562306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_Q0_REPORT BIT(16) 4662306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_Q1_REPORT BIT(20) 4762306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_RST_DONE_ACK BIT(24) 4862306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_Q0Q1_HALT_ACK BIT(25) 4962306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_Q0Q1_HALT_ACK BIT(26) 5062306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M0_ERROR 0x18000ee6 5162306a36Sopenharmony_ci#define CCI_IRQ_MASK_0_I2C_M1_ERROR 0x60ee6000 5262306a36Sopenharmony_ci#define CCI_IRQ_CLEAR_0 0xc08 5362306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0 0xc0c 5462306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE BIT(0) 5562306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT BIT(4) 5662306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT BIT(8) 5762306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE BIT(12) 5862306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT BIT(16) 5962306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT BIT(20) 6062306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_RST_DONE_ACK BIT(24) 6162306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK BIT(25) 6262306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK BIT(26) 6362306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR BIT(27) 6462306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR BIT(28) 6562306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR BIT(29) 6662306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR BIT(30) 6762306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M0_ERROR 0x18000ee6 6862306a36Sopenharmony_ci#define CCI_IRQ_STATUS_0_I2C_M1_ERROR 0x60ee6000 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define CCI_TIMEOUT (msecs_to_jiffies(100)) 7162306a36Sopenharmony_ci#define NUM_MASTERS 2 7262306a36Sopenharmony_ci#define NUM_QUEUES 2 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Max number of resources + 1 for a NULL terminator */ 7562306a36Sopenharmony_ci#define CCI_RES_MAX 6 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define CCI_I2C_SET_PARAM 1 7862306a36Sopenharmony_ci#define CCI_I2C_REPORT 8 7962306a36Sopenharmony_ci#define CCI_I2C_WRITE 9 8062306a36Sopenharmony_ci#define CCI_I2C_READ 10 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define CCI_I2C_REPORT_IRQ_EN BIT(8) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cienum { 8562306a36Sopenharmony_ci I2C_MODE_STANDARD, 8662306a36Sopenharmony_ci I2C_MODE_FAST, 8762306a36Sopenharmony_ci I2C_MODE_FAST_PLUS, 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cienum cci_i2c_queue_t { 9162306a36Sopenharmony_ci QUEUE_0, 9262306a36Sopenharmony_ci QUEUE_1 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct hw_params { 9662306a36Sopenharmony_ci u16 thigh; /* HIGH period of the SCL clock in clock ticks */ 9762306a36Sopenharmony_ci u16 tlow; /* LOW period of the SCL clock */ 9862306a36Sopenharmony_ci u16 tsu_sto; /* set-up time for STOP condition */ 9962306a36Sopenharmony_ci u16 tsu_sta; /* set-up time for a repeated START condition */ 10062306a36Sopenharmony_ci u16 thd_dat; /* data hold time */ 10162306a36Sopenharmony_ci u16 thd_sta; /* hold time (repeated) START condition */ 10262306a36Sopenharmony_ci u16 tbuf; /* bus free time between a STOP and START condition */ 10362306a36Sopenharmony_ci u8 scl_stretch_en; 10462306a36Sopenharmony_ci u16 trdhld; 10562306a36Sopenharmony_ci u16 tsp; /* pulse width of spikes suppressed by the input filter */ 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistruct cci; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistruct cci_master { 11162306a36Sopenharmony_ci struct i2c_adapter adap; 11262306a36Sopenharmony_ci u16 master; 11362306a36Sopenharmony_ci u8 mode; 11462306a36Sopenharmony_ci int status; 11562306a36Sopenharmony_ci struct completion irq_complete; 11662306a36Sopenharmony_ci struct cci *cci; 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistruct cci_data { 12062306a36Sopenharmony_ci unsigned int num_masters; 12162306a36Sopenharmony_ci struct i2c_adapter_quirks quirks; 12262306a36Sopenharmony_ci u16 queue_size[NUM_QUEUES]; 12362306a36Sopenharmony_ci unsigned long cci_clk_rate; 12462306a36Sopenharmony_ci struct hw_params params[3]; 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct cci { 12862306a36Sopenharmony_ci struct device *dev; 12962306a36Sopenharmony_ci void __iomem *base; 13062306a36Sopenharmony_ci unsigned int irq; 13162306a36Sopenharmony_ci const struct cci_data *data; 13262306a36Sopenharmony_ci struct clk_bulk_data *clocks; 13362306a36Sopenharmony_ci int nclocks; 13462306a36Sopenharmony_ci struct cci_master master[NUM_MASTERS]; 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic irqreturn_t cci_isr(int irq, void *dev) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct cci *cci = dev; 14062306a36Sopenharmony_ci u32 val, reset = 0; 14162306a36Sopenharmony_ci int ret = IRQ_NONE; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci val = readl(cci->base + CCI_IRQ_STATUS_0); 14462306a36Sopenharmony_ci writel(val, cci->base + CCI_IRQ_CLEAR_0); 14562306a36Sopenharmony_ci writel(0x1, cci->base + CCI_IRQ_GLOBAL_CLEAR_CMD); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_RST_DONE_ACK) { 14862306a36Sopenharmony_ci complete(&cci->master[0].irq_complete); 14962306a36Sopenharmony_ci if (cci->master[1].master) 15062306a36Sopenharmony_ci complete(&cci->master[1].irq_complete); 15162306a36Sopenharmony_ci ret = IRQ_HANDLED; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE || 15562306a36Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT || 15662306a36Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT) { 15762306a36Sopenharmony_ci cci->master[0].status = 0; 15862306a36Sopenharmony_ci complete(&cci->master[0].irq_complete); 15962306a36Sopenharmony_ci ret = IRQ_HANDLED; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE || 16362306a36Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT || 16462306a36Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT) { 16562306a36Sopenharmony_ci cci->master[1].status = 0; 16662306a36Sopenharmony_ci complete(&cci->master[1].irq_complete); 16762306a36Sopenharmony_ci ret = IRQ_HANDLED; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK)) { 17162306a36Sopenharmony_ci reset = CCI_RESET_CMD_M0_MASK; 17262306a36Sopenharmony_ci ret = IRQ_HANDLED; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK)) { 17662306a36Sopenharmony_ci reset = CCI_RESET_CMD_M1_MASK; 17762306a36Sopenharmony_ci ret = IRQ_HANDLED; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (unlikely(reset)) 18162306a36Sopenharmony_ci writel(reset, cci->base + CCI_RESET_CMD); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_ERROR)) { 18462306a36Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR || 18562306a36Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR) 18662306a36Sopenharmony_ci cci->master[0].status = -ENXIO; 18762306a36Sopenharmony_ci else 18862306a36Sopenharmony_ci cci->master[0].status = -EIO; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci writel(CCI_HALT_REQ_I2C_M0_Q0Q1, cci->base + CCI_HALT_REQ); 19162306a36Sopenharmony_ci ret = IRQ_HANDLED; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_ERROR)) { 19562306a36Sopenharmony_ci if (val & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR || 19662306a36Sopenharmony_ci val & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR) 19762306a36Sopenharmony_ci cci->master[1].status = -ENXIO; 19862306a36Sopenharmony_ci else 19962306a36Sopenharmony_ci cci->master[1].status = -EIO; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci writel(CCI_HALT_REQ_I2C_M1_Q0Q1, cci->base + CCI_HALT_REQ); 20262306a36Sopenharmony_ci ret = IRQ_HANDLED; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return ret; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic int cci_halt(struct cci *cci, u8 master_num) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct cci_master *master; 21162306a36Sopenharmony_ci u32 val; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (master_num >= cci->data->num_masters) { 21462306a36Sopenharmony_ci dev_err(cci->dev, "Unsupported master idx (%u)\n", master_num); 21562306a36Sopenharmony_ci return -EINVAL; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci val = BIT(master_num); 21962306a36Sopenharmony_ci master = &cci->master[master_num]; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci reinit_completion(&master->irq_complete); 22262306a36Sopenharmony_ci writel(val, cci->base + CCI_HALT_REQ); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (!wait_for_completion_timeout(&master->irq_complete, CCI_TIMEOUT)) { 22562306a36Sopenharmony_ci dev_err(cci->dev, "CCI halt timeout\n"); 22662306a36Sopenharmony_ci return -ETIMEDOUT; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int cci_reset(struct cci *cci) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * we reset the whole controller, here and for implicity use 23662306a36Sopenharmony_ci * master[0].xxx for waiting on it. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci reinit_completion(&cci->master[0].irq_complete); 23962306a36Sopenharmony_ci writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (!wait_for_completion_timeout(&cci->master[0].irq_complete, 24262306a36Sopenharmony_ci CCI_TIMEOUT)) { 24362306a36Sopenharmony_ci dev_err(cci->dev, "CCI reset timeout\n"); 24462306a36Sopenharmony_ci return -ETIMEDOUT; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int cci_init(struct cci *cci) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci u32 val = CCI_IRQ_MASK_0_I2C_M0_RD_DONE | 25362306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT | 25462306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_Q1_REPORT | 25562306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_RD_DONE | 25662306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_Q0_REPORT | 25762306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_Q1_REPORT | 25862306a36Sopenharmony_ci CCI_IRQ_MASK_0_RST_DONE_ACK | 25962306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_Q0Q1_HALT_ACK | 26062306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_Q0Q1_HALT_ACK | 26162306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M0_ERROR | 26262306a36Sopenharmony_ci CCI_IRQ_MASK_0_I2C_M1_ERROR; 26362306a36Sopenharmony_ci int i; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci writel(val, cci->base + CCI_IRQ_MASK_0); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci for (i = 0; i < cci->data->num_masters; i++) { 26862306a36Sopenharmony_ci int mode = cci->master[i].mode; 26962306a36Sopenharmony_ci const struct hw_params *hw; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (!cci->master[i].cci) 27262306a36Sopenharmony_ci continue; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci hw = &cci->data->params[mode]; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci val = hw->thigh << 16 | hw->tlow; 27762306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SCL_CTL(i)); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci val = hw->tsu_sto << 16 | hw->tsu_sta; 28062306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_0(i)); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci val = hw->thd_dat << 16 | hw->thd_sta; 28362306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_1(i)); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci val = hw->tbuf; 28662306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_2(i)); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci val = hw->scl_stretch_en << 8 | hw->trdhld << 4 | hw->tsp; 28962306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_MISC_CTL(i)); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int cci_run_queue(struct cci *cci, u8 master, u8 queue) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci u32 val; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci val = readl(cci->base + CCI_I2C_Mm_Qn_CUR_WORD_CNT(master, queue)); 30062306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_EXEC_WORD_CNT(master, queue)); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci reinit_completion(&cci->master[master].irq_complete); 30362306a36Sopenharmony_ci val = BIT(master * 2 + queue); 30462306a36Sopenharmony_ci writel(val, cci->base + CCI_QUEUE_START); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!wait_for_completion_timeout(&cci->master[master].irq_complete, 30762306a36Sopenharmony_ci CCI_TIMEOUT)) { 30862306a36Sopenharmony_ci dev_err(cci->dev, "master %d queue %d timeout\n", 30962306a36Sopenharmony_ci master, queue); 31062306a36Sopenharmony_ci cci_reset(cci); 31162306a36Sopenharmony_ci cci_init(cci); 31262306a36Sopenharmony_ci return -ETIMEDOUT; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return cci->master[master].status; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int cci_validate_queue(struct cci *cci, u8 master, u8 queue) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci u32 val; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci val = readl(cci->base + CCI_I2C_Mm_Qn_CUR_WORD_CNT(master, queue)); 32362306a36Sopenharmony_ci if (val == cci->data->queue_size[queue]) 32462306a36Sopenharmony_ci return -EINVAL; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!val) 32762306a36Sopenharmony_ci return 0; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN; 33062306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return cci_run_queue(cci, master, queue); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int cci_i2c_read(struct cci *cci, u16 master, 33662306a36Sopenharmony_ci u16 addr, u8 *buf, u16 len) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci u32 val, words_read, words_exp; 33962306a36Sopenharmony_ci u8 queue = QUEUE_1; 34062306a36Sopenharmony_ci int i, index = 0, ret; 34162306a36Sopenharmony_ci bool first = true; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * Call validate queue to make sure queue is empty before starting. 34562306a36Sopenharmony_ci * This is to avoid overflow / underflow of queue. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci ret = cci_validate_queue(cci, master, queue); 34862306a36Sopenharmony_ci if (ret < 0) 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci val = CCI_I2C_SET_PARAM | (addr & 0x7f) << 4; 35262306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci val = CCI_I2C_READ | len << 4; 35562306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ret = cci_run_queue(cci, master, queue); 35862306a36Sopenharmony_ci if (ret < 0) 35962306a36Sopenharmony_ci return ret; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci words_read = readl(cci->base + CCI_I2C_Mm_READ_BUF_LEVEL(master)); 36262306a36Sopenharmony_ci words_exp = len / 4 + 1; 36362306a36Sopenharmony_ci if (words_read != words_exp) { 36462306a36Sopenharmony_ci dev_err(cci->dev, "words read = %d, words expected = %d\n", 36562306a36Sopenharmony_ci words_read, words_exp); 36662306a36Sopenharmony_ci return -EIO; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci do { 37062306a36Sopenharmony_ci val = readl(cci->base + CCI_I2C_Mm_READ_DATA(master)); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci for (i = 0; i < 4 && index < len; i++) { 37362306a36Sopenharmony_ci if (first) { 37462306a36Sopenharmony_ci /* The LS byte of this register represents the 37562306a36Sopenharmony_ci * first byte read from the slave during a read 37662306a36Sopenharmony_ci * access. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci first = false; 37962306a36Sopenharmony_ci continue; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci buf[index++] = (val >> (i * 8)) & 0xff; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } while (--words_read); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int cci_i2c_write(struct cci *cci, u16 master, 38962306a36Sopenharmony_ci u16 addr, u8 *buf, u16 len) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci u8 queue = QUEUE_0; 39262306a36Sopenharmony_ci u8 load[12] = { 0 }; 39362306a36Sopenharmony_ci int i = 0, j, ret; 39462306a36Sopenharmony_ci u32 val; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * Call validate queue to make sure queue is empty before starting. 39862306a36Sopenharmony_ci * This is to avoid overflow / underflow of queue. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci ret = cci_validate_queue(cci, master, queue); 40162306a36Sopenharmony_ci if (ret < 0) 40262306a36Sopenharmony_ci return ret; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci val = CCI_I2C_SET_PARAM | (addr & 0x7f) << 4; 40562306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci load[i++] = CCI_I2C_WRITE | len << 4; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci for (j = 0; j < len; j++) 41062306a36Sopenharmony_ci load[i++] = buf[j]; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci for (j = 0; j < i; j += 4) { 41362306a36Sopenharmony_ci val = load[j]; 41462306a36Sopenharmony_ci val |= load[j + 1] << 8; 41562306a36Sopenharmony_ci val |= load[j + 2] << 16; 41662306a36Sopenharmony_ci val |= load[j + 3] << 24; 41762306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN; 42162306a36Sopenharmony_ci writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue)); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return cci_run_queue(cci, master, queue); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int cci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct cci_master *cci_master = i2c_get_adapdata(adap); 42962306a36Sopenharmony_ci struct cci *cci = cci_master->cci; 43062306a36Sopenharmony_ci int i, ret; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci ret = pm_runtime_get_sync(cci->dev); 43362306a36Sopenharmony_ci if (ret < 0) 43462306a36Sopenharmony_ci goto err; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci for (i = 0; i < num; i++) { 43762306a36Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 43862306a36Sopenharmony_ci ret = cci_i2c_read(cci, cci_master->master, 43962306a36Sopenharmony_ci msgs[i].addr, msgs[i].buf, 44062306a36Sopenharmony_ci msgs[i].len); 44162306a36Sopenharmony_ci else 44262306a36Sopenharmony_ci ret = cci_i2c_write(cci, cci_master->master, 44362306a36Sopenharmony_ci msgs[i].addr, msgs[i].buf, 44462306a36Sopenharmony_ci msgs[i].len); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (ret < 0) 44762306a36Sopenharmony_ci break; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (!ret) 45162306a36Sopenharmony_ci ret = num; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cierr: 45462306a36Sopenharmony_ci pm_runtime_mark_last_busy(cci->dev); 45562306a36Sopenharmony_ci pm_runtime_put_autosuspend(cci->dev); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci return ret; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic u32 cci_func(struct i2c_adapter *adap) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic const struct i2c_algorithm cci_algo = { 46662306a36Sopenharmony_ci .master_xfer = cci_xfer, 46762306a36Sopenharmony_ci .functionality = cci_func, 46862306a36Sopenharmony_ci}; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int cci_enable_clocks(struct cci *cci) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci return clk_bulk_prepare_enable(cci->nclocks, cci->clocks); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void cci_disable_clocks(struct cci *cci) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci clk_bulk_disable_unprepare(cci->nclocks, cci->clocks); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int __maybe_unused cci_suspend_runtime(struct device *dev) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct cci *cci = dev_get_drvdata(dev); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci cci_disable_clocks(cci); 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int __maybe_unused cci_resume_runtime(struct device *dev) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct cci *cci = dev_get_drvdata(dev); 49162306a36Sopenharmony_ci int ret; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci ret = cci_enable_clocks(cci); 49462306a36Sopenharmony_ci if (ret) 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci cci_init(cci); 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int __maybe_unused cci_suspend(struct device *dev) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci if (!pm_runtime_suspended(dev)) 50462306a36Sopenharmony_ci return cci_suspend_runtime(dev); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int __maybe_unused cci_resume(struct device *dev) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci cci_resume_runtime(dev); 51262306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 51362306a36Sopenharmony_ci pm_request_autosuspend(dev); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic const struct dev_pm_ops qcom_cci_pm = { 51962306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(cci_suspend, cci_resume) 52062306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL) 52162306a36Sopenharmony_ci}; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int cci_probe(struct platform_device *pdev) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct device *dev = &pdev->dev; 52662306a36Sopenharmony_ci unsigned long cci_clk_rate = 0; 52762306a36Sopenharmony_ci struct device_node *child; 52862306a36Sopenharmony_ci struct resource *r; 52962306a36Sopenharmony_ci struct cci *cci; 53062306a36Sopenharmony_ci int ret, i; 53162306a36Sopenharmony_ci u32 val; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci cci = devm_kzalloc(dev, sizeof(*cci), GFP_KERNEL); 53462306a36Sopenharmony_ci if (!cci) 53562306a36Sopenharmony_ci return -ENOMEM; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci cci->dev = dev; 53862306a36Sopenharmony_ci platform_set_drvdata(pdev, cci); 53962306a36Sopenharmony_ci cci->data = device_get_match_data(dev); 54062306a36Sopenharmony_ci if (!cci->data) 54162306a36Sopenharmony_ci return -ENOENT; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci for_each_available_child_of_node(dev->of_node, child) { 54462306a36Sopenharmony_ci struct cci_master *master; 54562306a36Sopenharmony_ci u32 idx; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ret = of_property_read_u32(child, "reg", &idx); 54862306a36Sopenharmony_ci if (ret) { 54962306a36Sopenharmony_ci dev_err(dev, "%pOF invalid 'reg' property", child); 55062306a36Sopenharmony_ci continue; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (idx >= cci->data->num_masters) { 55462306a36Sopenharmony_ci dev_err(dev, "%pOF invalid 'reg' value: %u (max is %u)", 55562306a36Sopenharmony_ci child, idx, cci->data->num_masters - 1); 55662306a36Sopenharmony_ci continue; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci master = &cci->master[idx]; 56062306a36Sopenharmony_ci master->adap.quirks = &cci->data->quirks; 56162306a36Sopenharmony_ci master->adap.algo = &cci_algo; 56262306a36Sopenharmony_ci master->adap.dev.parent = dev; 56362306a36Sopenharmony_ci master->adap.dev.of_node = of_node_get(child); 56462306a36Sopenharmony_ci master->master = idx; 56562306a36Sopenharmony_ci master->cci = cci; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci i2c_set_adapdata(&master->adap, master); 56862306a36Sopenharmony_ci snprintf(master->adap.name, sizeof(master->adap.name), "Qualcomm-CCI"); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci master->mode = I2C_MODE_STANDARD; 57162306a36Sopenharmony_ci ret = of_property_read_u32(child, "clock-frequency", &val); 57262306a36Sopenharmony_ci if (!ret) { 57362306a36Sopenharmony_ci if (val == I2C_MAX_FAST_MODE_FREQ) 57462306a36Sopenharmony_ci master->mode = I2C_MODE_FAST; 57562306a36Sopenharmony_ci else if (val == I2C_MAX_FAST_MODE_PLUS_FREQ) 57662306a36Sopenharmony_ci master->mode = I2C_MODE_FAST_PLUS; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci init_completion(&master->irq_complete); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* Memory */ 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci cci->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); 58562306a36Sopenharmony_ci if (IS_ERR(cci->base)) 58662306a36Sopenharmony_ci return PTR_ERR(cci->base); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* Clocks */ 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci ret = devm_clk_bulk_get_all(dev, &cci->clocks); 59162306a36Sopenharmony_ci if (ret < 0) 59262306a36Sopenharmony_ci return dev_err_probe(dev, ret, "failed to get clocks\n"); 59362306a36Sopenharmony_ci else if (!ret) 59462306a36Sopenharmony_ci return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); 59562306a36Sopenharmony_ci cci->nclocks = ret; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* Retrieve CCI clock rate */ 59862306a36Sopenharmony_ci for (i = 0; i < cci->nclocks; i++) { 59962306a36Sopenharmony_ci if (!strcmp(cci->clocks[i].id, "cci")) { 60062306a36Sopenharmony_ci cci_clk_rate = clk_get_rate(cci->clocks[i].clk); 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (cci_clk_rate != cci->data->cci_clk_rate) { 60662306a36Sopenharmony_ci /* cci clock set by the bootloader or via assigned clock rate 60762306a36Sopenharmony_ci * in DT. 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_ci dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n", 61062306a36Sopenharmony_ci cci_clk_rate, cci->data->cci_clk_rate); 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ret = cci_enable_clocks(cci); 61462306a36Sopenharmony_ci if (ret < 0) 61562306a36Sopenharmony_ci return ret; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Interrupt */ 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 62062306a36Sopenharmony_ci if (ret < 0) 62162306a36Sopenharmony_ci goto disable_clocks; 62262306a36Sopenharmony_ci cci->irq = ret; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci ret = devm_request_irq(dev, cci->irq, cci_isr, 0, dev_name(dev), cci); 62562306a36Sopenharmony_ci if (ret < 0) { 62662306a36Sopenharmony_ci dev_err(dev, "request_irq failed, ret: %d\n", ret); 62762306a36Sopenharmony_ci goto disable_clocks; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci val = readl(cci->base + CCI_HW_VERSION); 63162306a36Sopenharmony_ci dev_dbg(dev, "CCI HW version = 0x%08x", val); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci ret = cci_reset(cci); 63462306a36Sopenharmony_ci if (ret < 0) 63562306a36Sopenharmony_ci goto error; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci ret = cci_init(cci); 63862306a36Sopenharmony_ci if (ret < 0) 63962306a36Sopenharmony_ci goto error; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); 64262306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 64362306a36Sopenharmony_ci pm_runtime_set_active(dev); 64462306a36Sopenharmony_ci pm_runtime_enable(dev); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci for (i = 0; i < cci->data->num_masters; i++) { 64762306a36Sopenharmony_ci if (!cci->master[i].cci) 64862306a36Sopenharmony_ci continue; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci ret = i2c_add_adapter(&cci->master[i].adap); 65162306a36Sopenharmony_ci if (ret < 0) { 65262306a36Sopenharmony_ci of_node_put(cci->master[i].adap.dev.of_node); 65362306a36Sopenharmony_ci goto error_i2c; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cierror_i2c: 66062306a36Sopenharmony_ci pm_runtime_disable(dev); 66162306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci for (--i ; i >= 0; i--) { 66462306a36Sopenharmony_ci if (cci->master[i].cci) { 66562306a36Sopenharmony_ci i2c_del_adapter(&cci->master[i].adap); 66662306a36Sopenharmony_ci of_node_put(cci->master[i].adap.dev.of_node); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_cierror: 67062306a36Sopenharmony_ci disable_irq(cci->irq); 67162306a36Sopenharmony_cidisable_clocks: 67262306a36Sopenharmony_ci cci_disable_clocks(cci); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return ret; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic void cci_remove(struct platform_device *pdev) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct cci *cci = platform_get_drvdata(pdev); 68062306a36Sopenharmony_ci int i; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci for (i = 0; i < cci->data->num_masters; i++) { 68362306a36Sopenharmony_ci if (cci->master[i].cci) { 68462306a36Sopenharmony_ci i2c_del_adapter(&cci->master[i].adap); 68562306a36Sopenharmony_ci of_node_put(cci->master[i].adap.dev.of_node); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci cci_halt(cci, i); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci disable_irq(cci->irq); 69162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 69262306a36Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic const struct cci_data cci_v1_data = { 69662306a36Sopenharmony_ci .num_masters = 1, 69762306a36Sopenharmony_ci .queue_size = { 64, 16 }, 69862306a36Sopenharmony_ci .quirks = { 69962306a36Sopenharmony_ci .max_write_len = 10, 70062306a36Sopenharmony_ci .max_read_len = 12, 70162306a36Sopenharmony_ci }, 70262306a36Sopenharmony_ci .cci_clk_rate = 19200000, 70362306a36Sopenharmony_ci .params[I2C_MODE_STANDARD] = { 70462306a36Sopenharmony_ci .thigh = 78, 70562306a36Sopenharmony_ci .tlow = 114, 70662306a36Sopenharmony_ci .tsu_sto = 28, 70762306a36Sopenharmony_ci .tsu_sta = 28, 70862306a36Sopenharmony_ci .thd_dat = 10, 70962306a36Sopenharmony_ci .thd_sta = 77, 71062306a36Sopenharmony_ci .tbuf = 118, 71162306a36Sopenharmony_ci .scl_stretch_en = 0, 71262306a36Sopenharmony_ci .trdhld = 6, 71362306a36Sopenharmony_ci .tsp = 1 71462306a36Sopenharmony_ci }, 71562306a36Sopenharmony_ci .params[I2C_MODE_FAST] = { 71662306a36Sopenharmony_ci .thigh = 20, 71762306a36Sopenharmony_ci .tlow = 28, 71862306a36Sopenharmony_ci .tsu_sto = 21, 71962306a36Sopenharmony_ci .tsu_sta = 21, 72062306a36Sopenharmony_ci .thd_dat = 13, 72162306a36Sopenharmony_ci .thd_sta = 18, 72262306a36Sopenharmony_ci .tbuf = 32, 72362306a36Sopenharmony_ci .scl_stretch_en = 0, 72462306a36Sopenharmony_ci .trdhld = 6, 72562306a36Sopenharmony_ci .tsp = 3 72662306a36Sopenharmony_ci }, 72762306a36Sopenharmony_ci}; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic const struct cci_data cci_v1_5_data = { 73062306a36Sopenharmony_ci .num_masters = 2, 73162306a36Sopenharmony_ci .queue_size = { 64, 16 }, 73262306a36Sopenharmony_ci .quirks = { 73362306a36Sopenharmony_ci .max_write_len = 10, 73462306a36Sopenharmony_ci .max_read_len = 12, 73562306a36Sopenharmony_ci }, 73662306a36Sopenharmony_ci .cci_clk_rate = 19200000, 73762306a36Sopenharmony_ci .params[I2C_MODE_STANDARD] = { 73862306a36Sopenharmony_ci .thigh = 78, 73962306a36Sopenharmony_ci .tlow = 114, 74062306a36Sopenharmony_ci .tsu_sto = 28, 74162306a36Sopenharmony_ci .tsu_sta = 28, 74262306a36Sopenharmony_ci .thd_dat = 10, 74362306a36Sopenharmony_ci .thd_sta = 77, 74462306a36Sopenharmony_ci .tbuf = 118, 74562306a36Sopenharmony_ci .scl_stretch_en = 0, 74662306a36Sopenharmony_ci .trdhld = 6, 74762306a36Sopenharmony_ci .tsp = 1 74862306a36Sopenharmony_ci }, 74962306a36Sopenharmony_ci .params[I2C_MODE_FAST] = { 75062306a36Sopenharmony_ci .thigh = 20, 75162306a36Sopenharmony_ci .tlow = 28, 75262306a36Sopenharmony_ci .tsu_sto = 21, 75362306a36Sopenharmony_ci .tsu_sta = 21, 75462306a36Sopenharmony_ci .thd_dat = 13, 75562306a36Sopenharmony_ci .thd_sta = 18, 75662306a36Sopenharmony_ci .tbuf = 32, 75762306a36Sopenharmony_ci .scl_stretch_en = 0, 75862306a36Sopenharmony_ci .trdhld = 6, 75962306a36Sopenharmony_ci .tsp = 3 76062306a36Sopenharmony_ci }, 76162306a36Sopenharmony_ci}; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic const struct cci_data cci_v2_data = { 76462306a36Sopenharmony_ci .num_masters = 2, 76562306a36Sopenharmony_ci .queue_size = { 64, 16 }, 76662306a36Sopenharmony_ci .quirks = { 76762306a36Sopenharmony_ci .max_write_len = 11, 76862306a36Sopenharmony_ci .max_read_len = 12, 76962306a36Sopenharmony_ci }, 77062306a36Sopenharmony_ci .cci_clk_rate = 37500000, 77162306a36Sopenharmony_ci .params[I2C_MODE_STANDARD] = { 77262306a36Sopenharmony_ci .thigh = 201, 77362306a36Sopenharmony_ci .tlow = 174, 77462306a36Sopenharmony_ci .tsu_sto = 204, 77562306a36Sopenharmony_ci .tsu_sta = 231, 77662306a36Sopenharmony_ci .thd_dat = 22, 77762306a36Sopenharmony_ci .thd_sta = 162, 77862306a36Sopenharmony_ci .tbuf = 227, 77962306a36Sopenharmony_ci .scl_stretch_en = 0, 78062306a36Sopenharmony_ci .trdhld = 6, 78162306a36Sopenharmony_ci .tsp = 3 78262306a36Sopenharmony_ci }, 78362306a36Sopenharmony_ci .params[I2C_MODE_FAST] = { 78462306a36Sopenharmony_ci .thigh = 38, 78562306a36Sopenharmony_ci .tlow = 56, 78662306a36Sopenharmony_ci .tsu_sto = 40, 78762306a36Sopenharmony_ci .tsu_sta = 40, 78862306a36Sopenharmony_ci .thd_dat = 22, 78962306a36Sopenharmony_ci .thd_sta = 35, 79062306a36Sopenharmony_ci .tbuf = 62, 79162306a36Sopenharmony_ci .scl_stretch_en = 0, 79262306a36Sopenharmony_ci .trdhld = 6, 79362306a36Sopenharmony_ci .tsp = 3 79462306a36Sopenharmony_ci }, 79562306a36Sopenharmony_ci .params[I2C_MODE_FAST_PLUS] = { 79662306a36Sopenharmony_ci .thigh = 16, 79762306a36Sopenharmony_ci .tlow = 22, 79862306a36Sopenharmony_ci .tsu_sto = 17, 79962306a36Sopenharmony_ci .tsu_sta = 18, 80062306a36Sopenharmony_ci .thd_dat = 16, 80162306a36Sopenharmony_ci .thd_sta = 15, 80262306a36Sopenharmony_ci .tbuf = 24, 80362306a36Sopenharmony_ci .scl_stretch_en = 0, 80462306a36Sopenharmony_ci .trdhld = 3, 80562306a36Sopenharmony_ci .tsp = 3 80662306a36Sopenharmony_ci }, 80762306a36Sopenharmony_ci}; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic const struct of_device_id cci_dt_match[] = { 81062306a36Sopenharmony_ci { .compatible = "qcom,msm8226-cci", .data = &cci_v1_data}, 81162306a36Sopenharmony_ci { .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data}, 81262306a36Sopenharmony_ci { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data}, 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* 81662306a36Sopenharmony_ci * Legacy compatibles kept for backwards compatibility. 81762306a36Sopenharmony_ci * Do not add any new ones unless they introduce a new config 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_ci { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data}, 82062306a36Sopenharmony_ci { .compatible = "qcom,sdm845-cci", .data = &cci_v2_data}, 82162306a36Sopenharmony_ci { .compatible = "qcom,sm8250-cci", .data = &cci_v2_data}, 82262306a36Sopenharmony_ci { .compatible = "qcom,sm8450-cci", .data = &cci_v2_data}, 82362306a36Sopenharmony_ci {} 82462306a36Sopenharmony_ci}; 82562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cci_dt_match); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic struct platform_driver qcom_cci_driver = { 82862306a36Sopenharmony_ci .probe = cci_probe, 82962306a36Sopenharmony_ci .remove_new = cci_remove, 83062306a36Sopenharmony_ci .driver = { 83162306a36Sopenharmony_ci .name = "i2c-qcom-cci", 83262306a36Sopenharmony_ci .of_match_table = cci_dt_match, 83362306a36Sopenharmony_ci .pm = &qcom_cci_pm, 83462306a36Sopenharmony_ci }, 83562306a36Sopenharmony_ci}; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cimodule_platform_driver(qcom_cci_driver); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Camera Control Interface driver"); 84062306a36Sopenharmony_ciMODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); 84162306a36Sopenharmony_ciMODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>"); 84262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 843