18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * I2C bus driver for CSR SiRFprimaII 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CLK_CTRL 0x00 198c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STATUS 0x0C 208c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CTRL 0x10 218c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_IO_CTRL 0x14 228c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_SDA_DELAY 0x18 238c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_START 0x1C 248c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_BUF 0x30 258c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_BUF 0x80 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_BUF_MAX 16 288c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_BUF_MAX 16 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD(x) (SIRFSOC_I2C_CMD_BUF + (x)*0x04) 318c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_MASK(x) (0xFF<<(((x)&3)*8)) 328c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_SHIFT(x) (((x)&3)*8) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DIV_MASK (0xFFFF) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* I2C status flags */ 378c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_BUSY BIT(0) 388c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_TIP BIT(1) 398c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_NACK BIT(2) 408c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_TR_INT BIT(4) 418c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_STOP BIT(6) 428c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_CMD_DONE BIT(8) 438c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_ERR BIT(9) 448c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_INDEX (0x1F<<16) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* I2C control flags */ 478c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_RESET BIT(0) 488c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CORE_EN BIT(1) 498c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_MASTER_MODE BIT(2) 508c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_DONE_EN BIT(11) 518c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_ERR_INT_EN BIT(12) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_SDA_DELAY_MASK (0xFF) 548c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_SCLF_FILTER (3<<8) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_START_CMD BIT(0) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_RP(x) ((x)&0x7) 598c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_NACK BIT(3) 608c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_WRITE BIT(4) 618c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_READ BIT(5) 628c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STOP BIT(6) 638c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_START BIT(7) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_ERR_NOACK 1 668c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_ERR_TIMEOUT 2 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistruct sirfsoc_i2c { 698c2ecf20Sopenharmony_ci void __iomem *base; 708c2ecf20Sopenharmony_ci struct clk *clk; 718c2ecf20Sopenharmony_ci u32 cmd_ptr; /* Current position in CMD buffer */ 728c2ecf20Sopenharmony_ci u8 *buf; /* Buffer passed by user */ 738c2ecf20Sopenharmony_ci u32 msg_len; /* Message length */ 748c2ecf20Sopenharmony_ci u32 finished_len; /* number of bytes read/written */ 758c2ecf20Sopenharmony_ci u32 read_cmd_len; /* number of read cmd sent */ 768c2ecf20Sopenharmony_ci int msg_read; /* 1 indicates a read message */ 778c2ecf20Sopenharmony_ci int err_status; /* 1 indicates an error on bus */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci u32 sda_delay; /* For suspend/resume */ 808c2ecf20Sopenharmony_ci u32 clk_div; 818c2ecf20Sopenharmony_ci int last; /* Last message in transfer, STOP cmd can be sent */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci struct completion done; /* indicates completion of message transfer */ 848c2ecf20Sopenharmony_ci struct i2c_adapter adapter; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci u32 data = 0; 908c2ecf20Sopenharmony_ci int i; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci for (i = 0; i < siic->read_cmd_len; i++) { 938c2ecf20Sopenharmony_ci if (!(i & 0x3)) 948c2ecf20Sopenharmony_ci data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i); 958c2ecf20Sopenharmony_ci siic->buf[siic->finished_len++] = 968c2ecf20Sopenharmony_ci (u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >> 978c2ecf20Sopenharmony_ci SIRFSOC_I2C_DATA_SHIFT(i)); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci u32 regval; 1048c2ecf20Sopenharmony_ci int i = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (siic->msg_read) { 1078c2ecf20Sopenharmony_ci while (((siic->finished_len + i) < siic->msg_len) 1088c2ecf20Sopenharmony_ci && (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) { 1098c2ecf20Sopenharmony_ci regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0); 1108c2ecf20Sopenharmony_ci if (((siic->finished_len + i) == 1118c2ecf20Sopenharmony_ci (siic->msg_len - 1)) && siic->last) 1128c2ecf20Sopenharmony_ci regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK; 1138c2ecf20Sopenharmony_ci writel(regval, 1148c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); 1158c2ecf20Sopenharmony_ci i++; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci siic->read_cmd_len = i; 1198c2ecf20Sopenharmony_ci } else { 1208c2ecf20Sopenharmony_ci while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1) 1218c2ecf20Sopenharmony_ci && (siic->finished_len < siic->msg_len)) { 1228c2ecf20Sopenharmony_ci regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0); 1238c2ecf20Sopenharmony_ci if ((siic->finished_len == (siic->msg_len - 1)) 1248c2ecf20Sopenharmony_ci && siic->last) 1258c2ecf20Sopenharmony_ci regval |= SIRFSOC_I2C_STOP; 1268c2ecf20Sopenharmony_ci writel(regval, 1278c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); 1288c2ecf20Sopenharmony_ci writel(siic->buf[siic->finished_len++], 1298c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci siic->cmd_ptr = 0; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Trigger the transfer */ 1358c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id; 1418c2ecf20Sopenharmony_ci u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (i2c_stat & SIRFSOC_I2C_STAT_ERR) { 1448c2ecf20Sopenharmony_ci /* Error conditions */ 1458c2ecf20Sopenharmony_ci siic->err_status = SIRFSOC_I2C_ERR_NOACK; 1468c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (i2c_stat & SIRFSOC_I2C_STAT_NACK) 1498c2ecf20Sopenharmony_ci dev_dbg(&siic->adapter.dev, "ACK not received\n"); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci dev_err(&siic->adapter.dev, "I2C error\n"); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * Due to hardware ANOMALY, we need to reset I2C earlier after 1558c2ecf20Sopenharmony_ci * we get NOACK while accessing non-existing clients, otherwise 1568c2ecf20Sopenharmony_ci * we will get errors even we access existing clients later 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET, 1598c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CTRL); 1608c2ecf20Sopenharmony_ci while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) 1618c2ecf20Sopenharmony_ci cpu_relax(); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci complete(&siic->done); 1648c2ecf20Sopenharmony_ci } else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) { 1658c2ecf20Sopenharmony_ci /* CMD buffer execution complete */ 1668c2ecf20Sopenharmony_ci if (siic->msg_read) 1678c2ecf20Sopenharmony_ci i2c_sirfsoc_read_data(siic); 1688c2ecf20Sopenharmony_ci if (siic->finished_len == siic->msg_len) 1698c2ecf20Sopenharmony_ci complete(&siic->done); 1708c2ecf20Sopenharmony_ci else /* Fill a new CMD buffer for left data */ 1718c2ecf20Sopenharmony_ci i2c_sirfsoc_queue_cmd(siic); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic, 1808c2ecf20Sopenharmony_ci struct i2c_msg *msg) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci unsigned char addr; 1838c2ecf20Sopenharmony_ci u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* no data and last message -> add STOP */ 1868c2ecf20Sopenharmony_ci if (siic->last && (msg->len == 0)) 1878c2ecf20Sopenharmony_ci regval |= SIRFSOC_I2C_STOP; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci addr = i2c_8bit_addr_from_msg(msg); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Reverse direction bit */ 1948c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_REV_DIR_ADDR) 1958c2ecf20Sopenharmony_ci addr ^= 1; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL); 2038c2ecf20Sopenharmony_ci /* timeout waiting for the xfer to finish or fail */ 2048c2ecf20Sopenharmony_ci int timeout = msecs_to_jiffies((msg->len + 1) * 50); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci i2c_sirfsoc_set_address(siic, msg); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN, 2098c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CTRL); 2108c2ecf20Sopenharmony_ci i2c_sirfsoc_queue_cmd(siic); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (wait_for_completion_timeout(&siic->done, timeout) == 0) { 2138c2ecf20Sopenharmony_ci siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT; 2148c2ecf20Sopenharmony_ci dev_err(&siic->adapter.dev, "Transfer timeout\n"); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN), 2188c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CTRL); 2198c2ecf20Sopenharmony_ci writel(0, siic->base + SIRFSOC_I2C_CMD_START); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* i2c control doesn't response, reset it */ 2228c2ecf20Sopenharmony_ci if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) { 2238c2ecf20Sopenharmony_ci writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET, 2248c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CTRL); 2258c2ecf20Sopenharmony_ci while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) 2268c2ecf20Sopenharmony_ci cpu_relax(); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci return siic->err_status ? -EAGAIN : 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic u32 i2c_sirfsoc_func(struct i2c_adapter *adap) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 2378c2ecf20Sopenharmony_ci int num) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct sirfsoc_i2c *siic = adap->algo_data; 2408c2ecf20Sopenharmony_ci int i, ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci clk_enable(siic->clk); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 2458c2ecf20Sopenharmony_ci siic->buf = msgs[i].buf; 2468c2ecf20Sopenharmony_ci siic->msg_len = msgs[i].len; 2478c2ecf20Sopenharmony_ci siic->msg_read = !!(msgs[i].flags & I2C_M_RD); 2488c2ecf20Sopenharmony_ci siic->err_status = 0; 2498c2ecf20Sopenharmony_ci siic->cmd_ptr = 0; 2508c2ecf20Sopenharmony_ci siic->finished_len = 0; 2518c2ecf20Sopenharmony_ci siic->last = (i == (num - 1)); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]); 2548c2ecf20Sopenharmony_ci if (ret) { 2558c2ecf20Sopenharmony_ci clk_disable(siic->clk); 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci clk_disable(siic->clk); 2618c2ecf20Sopenharmony_ci return num; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* I2C algorithms associated with this master controller driver */ 2658c2ecf20Sopenharmony_cistatic const struct i2c_algorithm i2c_sirfsoc_algo = { 2668c2ecf20Sopenharmony_ci .master_xfer = i2c_sirfsoc_xfer, 2678c2ecf20Sopenharmony_ci .functionality = i2c_sirfsoc_func, 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_probe(struct platform_device *pdev) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct sirfsoc_i2c *siic; 2738c2ecf20Sopenharmony_ci struct i2c_adapter *adap; 2748c2ecf20Sopenharmony_ci struct clk *clk; 2758c2ecf20Sopenharmony_ci int bitrate; 2768c2ecf20Sopenharmony_ci int ctrl_speed; 2778c2ecf20Sopenharmony_ci int irq; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci int err; 2808c2ecf20Sopenharmony_ci u32 regval; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci clk = clk_get(&pdev->dev, NULL); 2838c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 2848c2ecf20Sopenharmony_ci err = PTR_ERR(clk); 2858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Clock get failed\n"); 2868c2ecf20Sopenharmony_ci goto err_get_clk; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci err = clk_prepare(clk); 2908c2ecf20Sopenharmony_ci if (err) { 2918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Clock prepare failed\n"); 2928c2ecf20Sopenharmony_ci goto err_clk_prep; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci err = clk_enable(clk); 2968c2ecf20Sopenharmony_ci if (err) { 2978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Clock enable failed\n"); 2988c2ecf20Sopenharmony_ci goto err_clk_en; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci ctrl_speed = clk_get_rate(clk); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL); 3048c2ecf20Sopenharmony_ci if (!siic) { 3058c2ecf20Sopenharmony_ci err = -ENOMEM; 3068c2ecf20Sopenharmony_ci goto out; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci adap = &siic->adapter; 3098c2ecf20Sopenharmony_ci adap->class = I2C_CLASS_DEPRECATED; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci siic->base = devm_platform_ioremap_resource(pdev, 0); 3128c2ecf20Sopenharmony_ci if (IS_ERR(siic->base)) { 3138c2ecf20Sopenharmony_ci err = PTR_ERR(siic->base); 3148c2ecf20Sopenharmony_ci goto out; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 3188c2ecf20Sopenharmony_ci if (irq < 0) { 3198c2ecf20Sopenharmony_ci err = irq; 3208c2ecf20Sopenharmony_ci goto out; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0, 3238c2ecf20Sopenharmony_ci dev_name(&pdev->dev), siic); 3248c2ecf20Sopenharmony_ci if (err) 3258c2ecf20Sopenharmony_ci goto out; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci adap->algo = &i2c_sirfsoc_algo; 3288c2ecf20Sopenharmony_ci adap->algo_data = siic; 3298c2ecf20Sopenharmony_ci adap->retries = 3; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci adap->dev.of_node = pdev->dev.of_node; 3328c2ecf20Sopenharmony_ci adap->dev.parent = &pdev->dev; 3338c2ecf20Sopenharmony_ci adap->nr = pdev->id; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name)); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, adap); 3388c2ecf20Sopenharmony_ci init_completion(&siic->done); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Controller initialisation */ 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); 3438c2ecf20Sopenharmony_ci while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) 3448c2ecf20Sopenharmony_ci cpu_relax(); 3458c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE, 3468c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CTRL); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci siic->clk = clk; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci err = of_property_read_u32(pdev->dev.of_node, 3518c2ecf20Sopenharmony_ci "clock-frequency", &bitrate); 3528c2ecf20Sopenharmony_ci if (err < 0) 3538c2ecf20Sopenharmony_ci bitrate = I2C_MAX_STANDARD_MODE_FREQ; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci * Due to some hardware design issues, we need to tune the formula. 3578c2ecf20Sopenharmony_ci * Since i2c is open drain interface that allows the slave to 3588c2ecf20Sopenharmony_ci * stall the transaction by holding the SCL line at '0', the RTL 3598c2ecf20Sopenharmony_ci * implementation is waiting for SCL feedback from the pin after 3608c2ecf20Sopenharmony_ci * setting it to High-Z ('1'). This wait adds to the high-time 3618c2ecf20Sopenharmony_ci * interval counter few cycles of the input synchronization 3628c2ecf20Sopenharmony_ci * (depending on the SCL_FILTER_REG field), and also the time it 3638c2ecf20Sopenharmony_ci * takes for the board pull-up resistor to rise the SCL line. 3648c2ecf20Sopenharmony_ci * For slow SCL settings these additions are negligible, 3658c2ecf20Sopenharmony_ci * but they start to affect the speed when clock is set to faster 3668c2ecf20Sopenharmony_ci * frequencies. 3678c2ecf20Sopenharmony_ci * Through the actual tests, use the different user_div value(which 3688c2ecf20Sopenharmony_ci * in the divider formula 'Fio / (Fi2c * user_div)') to adapt 3698c2ecf20Sopenharmony_ci * the different ranges of i2c bus clock frequency, to make the SCL 3708c2ecf20Sopenharmony_ci * more accurate. 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci if (bitrate <= 30000) 3738c2ecf20Sopenharmony_ci regval = ctrl_speed / (bitrate * 5); 3748c2ecf20Sopenharmony_ci else if (bitrate > 30000 && bitrate <= 280000) 3758c2ecf20Sopenharmony_ci regval = (2 * ctrl_speed) / (bitrate * 11); 3768c2ecf20Sopenharmony_ci else 3778c2ecf20Sopenharmony_ci regval = ctrl_speed / (bitrate * 6); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL); 3808c2ecf20Sopenharmony_ci if (regval > 0xFF) 3818c2ecf20Sopenharmony_ci writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY); 3828c2ecf20Sopenharmony_ci else 3838c2ecf20Sopenharmony_ci writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci err = i2c_add_numbered_adapter(adap); 3868c2ecf20Sopenharmony_ci if (err < 0) 3878c2ecf20Sopenharmony_ci goto out; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci clk_disable(clk); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci dev_info(&pdev->dev, " I2C adapter ready to operate\n"); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ciout: 3968c2ecf20Sopenharmony_ci clk_disable(clk); 3978c2ecf20Sopenharmony_cierr_clk_en: 3988c2ecf20Sopenharmony_ci clk_unprepare(clk); 3998c2ecf20Sopenharmony_cierr_clk_prep: 4008c2ecf20Sopenharmony_ci clk_put(clk); 4018c2ecf20Sopenharmony_cierr_get_clk: 4028c2ecf20Sopenharmony_ci return err; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_remove(struct platform_device *pdev) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = platform_get_drvdata(pdev); 4088c2ecf20Sopenharmony_ci struct sirfsoc_i2c *siic = adapter->algo_data; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); 4118c2ecf20Sopenharmony_ci i2c_del_adapter(adapter); 4128c2ecf20Sopenharmony_ci clk_unprepare(siic->clk); 4138c2ecf20Sopenharmony_ci clk_put(siic->clk); 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4188c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_suspend(struct device *dev) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = dev_get_drvdata(dev); 4218c2ecf20Sopenharmony_ci struct sirfsoc_i2c *siic = adapter->algo_data; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci clk_enable(siic->clk); 4248c2ecf20Sopenharmony_ci siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY); 4258c2ecf20Sopenharmony_ci siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL); 4268c2ecf20Sopenharmony_ci clk_disable(siic->clk); 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_resume(struct device *dev) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = dev_get_drvdata(dev); 4338c2ecf20Sopenharmony_ci struct sirfsoc_i2c *siic = adapter->algo_data; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci clk_enable(siic->clk); 4368c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); 4378c2ecf20Sopenharmony_ci while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) 4388c2ecf20Sopenharmony_ci cpu_relax(); 4398c2ecf20Sopenharmony_ci writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE, 4408c2ecf20Sopenharmony_ci siic->base + SIRFSOC_I2C_CTRL); 4418c2ecf20Sopenharmony_ci writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL); 4428c2ecf20Sopenharmony_ci writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY); 4438c2ecf20Sopenharmony_ci clk_disable(siic->clk); 4448c2ecf20Sopenharmony_ci return 0; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic const struct dev_pm_ops i2c_sirfsoc_pm_ops = { 4488c2ecf20Sopenharmony_ci .suspend = i2c_sirfsoc_suspend, 4498c2ecf20Sopenharmony_ci .resume = i2c_sirfsoc_resume, 4508c2ecf20Sopenharmony_ci}; 4518c2ecf20Sopenharmony_ci#endif 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic const struct of_device_id sirfsoc_i2c_of_match[] = { 4548c2ecf20Sopenharmony_ci { .compatible = "sirf,prima2-i2c", }, 4558c2ecf20Sopenharmony_ci {}, 4568c2ecf20Sopenharmony_ci}; 4578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic struct platform_driver i2c_sirfsoc_driver = { 4608c2ecf20Sopenharmony_ci .driver = { 4618c2ecf20Sopenharmony_ci .name = "sirfsoc_i2c", 4628c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4638c2ecf20Sopenharmony_ci .pm = &i2c_sirfsoc_pm_ops, 4648c2ecf20Sopenharmony_ci#endif 4658c2ecf20Sopenharmony_ci .of_match_table = sirfsoc_i2c_of_match, 4668c2ecf20Sopenharmony_ci }, 4678c2ecf20Sopenharmony_ci .probe = i2c_sirfsoc_probe, 4688c2ecf20Sopenharmony_ci .remove = i2c_sirfsoc_remove, 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_cimodule_platform_driver(i2c_sirfsoc_driver); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SiRF SoC I2C master controller driver"); 4738c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>"); 4748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xiangzhen Ye <Xiangzhen.Ye@csr.com>"); 4758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 476