18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * I2C bus driver for Amlogic Meson SoCs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/completion.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Meson I2C register map */ 238c2ecf20Sopenharmony_ci#define REG_CTRL 0x00 248c2ecf20Sopenharmony_ci#define REG_SLAVE_ADDR 0x04 258c2ecf20Sopenharmony_ci#define REG_TOK_LIST0 0x08 268c2ecf20Sopenharmony_ci#define REG_TOK_LIST1 0x0c 278c2ecf20Sopenharmony_ci#define REG_TOK_WDATA0 0x10 288c2ecf20Sopenharmony_ci#define REG_TOK_WDATA1 0x14 298c2ecf20Sopenharmony_ci#define REG_TOK_RDATA0 0x18 308c2ecf20Sopenharmony_ci#define REG_TOK_RDATA1 0x1c 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Control register fields */ 338c2ecf20Sopenharmony_ci#define REG_CTRL_START BIT(0) 348c2ecf20Sopenharmony_ci#define REG_CTRL_ACK_IGNORE BIT(1) 358c2ecf20Sopenharmony_ci#define REG_CTRL_STATUS BIT(2) 368c2ecf20Sopenharmony_ci#define REG_CTRL_ERROR BIT(3) 378c2ecf20Sopenharmony_ci#define REG_CTRL_CLKDIV GENMASK(21, 12) 388c2ecf20Sopenharmony_ci#define REG_CTRL_CLKDIVEXT GENMASK(29, 28) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define REG_SLV_ADDR GENMASK(7, 0) 418c2ecf20Sopenharmony_ci#define REG_SLV_SDA_FILTER GENMASK(10, 8) 428c2ecf20Sopenharmony_ci#define REG_SLV_SCL_FILTER GENMASK(13, 11) 438c2ecf20Sopenharmony_ci#define REG_SLV_SCL_LOW GENMASK(27, 16) 448c2ecf20Sopenharmony_ci#define REG_SLV_SCL_LOW_EN BIT(28) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define I2C_TIMEOUT_MS 500 478c2ecf20Sopenharmony_ci#define FILTER_DELAY 15 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cienum { 508c2ecf20Sopenharmony_ci TOKEN_END = 0, 518c2ecf20Sopenharmony_ci TOKEN_START, 528c2ecf20Sopenharmony_ci TOKEN_SLAVE_ADDR_WRITE, 538c2ecf20Sopenharmony_ci TOKEN_SLAVE_ADDR_READ, 548c2ecf20Sopenharmony_ci TOKEN_DATA, 558c2ecf20Sopenharmony_ci TOKEN_DATA_LAST, 568c2ecf20Sopenharmony_ci TOKEN_STOP, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cienum { 608c2ecf20Sopenharmony_ci STATE_IDLE, 618c2ecf20Sopenharmony_ci STATE_READ, 628c2ecf20Sopenharmony_ci STATE_WRITE, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct meson_i2c_data { 668c2ecf20Sopenharmony_ci unsigned char div_factor; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/** 708c2ecf20Sopenharmony_ci * struct meson_i2c - Meson I2C device private data 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * @adap: I2C adapter instance 738c2ecf20Sopenharmony_ci * @dev: Pointer to device structure 748c2ecf20Sopenharmony_ci * @regs: Base address of the device memory mapped registers 758c2ecf20Sopenharmony_ci * @clk: Pointer to clock structure 768c2ecf20Sopenharmony_ci * @msg: Pointer to the current I2C message 778c2ecf20Sopenharmony_ci * @state: Current state in the driver state machine 788c2ecf20Sopenharmony_ci * @last: Flag set for the last message in the transfer 798c2ecf20Sopenharmony_ci * @count: Number of bytes to be sent/received in current transfer 808c2ecf20Sopenharmony_ci * @pos: Current position in the send/receive buffer 818c2ecf20Sopenharmony_ci * @error: Flag set when an error is received 828c2ecf20Sopenharmony_ci * @lock: To avoid race conditions between irq handler and xfer code 838c2ecf20Sopenharmony_ci * @done: Completion used to wait for transfer termination 848c2ecf20Sopenharmony_ci * @tokens: Sequence of tokens to be written to the device 858c2ecf20Sopenharmony_ci * @num_tokens: Number of tokens 868c2ecf20Sopenharmony_ci * @data: Pointer to the controlller's platform data 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_cistruct meson_i2c { 898c2ecf20Sopenharmony_ci struct i2c_adapter adap; 908c2ecf20Sopenharmony_ci struct device *dev; 918c2ecf20Sopenharmony_ci void __iomem *regs; 928c2ecf20Sopenharmony_ci struct clk *clk; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci struct i2c_msg *msg; 958c2ecf20Sopenharmony_ci int state; 968c2ecf20Sopenharmony_ci bool last; 978c2ecf20Sopenharmony_ci int count; 988c2ecf20Sopenharmony_ci int pos; 998c2ecf20Sopenharmony_ci int error; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci spinlock_t lock; 1028c2ecf20Sopenharmony_ci struct completion done; 1038c2ecf20Sopenharmony_ci u32 tokens[2]; 1048c2ecf20Sopenharmony_ci int num_tokens; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci const struct meson_i2c_data *data; 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, 1108c2ecf20Sopenharmony_ci u32 val) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci u32 data; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci data = readl(i2c->regs + reg); 1158c2ecf20Sopenharmony_ci data &= ~mask; 1168c2ecf20Sopenharmony_ci data |= val & mask; 1178c2ecf20Sopenharmony_ci writel(data, i2c->regs + reg); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void meson_i2c_reset_tokens(struct meson_i2c *i2c) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci i2c->tokens[0] = 0; 1238c2ecf20Sopenharmony_ci i2c->tokens[1] = 0; 1248c2ecf20Sopenharmony_ci i2c->num_tokens = 0; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void meson_i2c_add_token(struct meson_i2c *i2c, int token) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci if (i2c->num_tokens < 8) 1308c2ecf20Sopenharmony_ci i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4); 1318c2ecf20Sopenharmony_ci else 1328c2ecf20Sopenharmony_ci i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci i2c->num_tokens++; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci unsigned long clk_rate = clk_get_rate(i2c->clk); 1408c2ecf20Sopenharmony_ci unsigned int div; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci div = DIV_ROUND_UP(clk_rate, freq); 1438c2ecf20Sopenharmony_ci div -= FILTER_DELAY; 1448c2ecf20Sopenharmony_ci div = DIV_ROUND_UP(div, i2c->data->div_factor); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* clock divider has 12 bits */ 1478c2ecf20Sopenharmony_ci if (div > GENMASK(11, 0)) { 1488c2ecf20Sopenharmony_ci dev_err(i2c->dev, "requested bus frequency too low\n"); 1498c2ecf20Sopenharmony_ci div = GENMASK(11, 0); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV, 1538c2ecf20Sopenharmony_ci FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0))); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT, 1568c2ecf20Sopenharmony_ci FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10)); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* Disable HIGH/LOW mode */ 1598c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__, 1628c2ecf20Sopenharmony_ci clk_rate, freq, div); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci u32 rdata0, rdata1; 1688c2ecf20Sopenharmony_ci int i; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci rdata0 = readl(i2c->regs + REG_TOK_RDATA0); 1718c2ecf20Sopenharmony_ci rdata1 = readl(i2c->regs + REG_TOK_RDATA1); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, 1748c2ecf20Sopenharmony_ci rdata0, rdata1, len); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci for (i = 0; i < min(4, len); i++) 1778c2ecf20Sopenharmony_ci *buf++ = (rdata0 >> i * 8) & 0xff; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for (i = 4; i < min(8, len); i++) 1808c2ecf20Sopenharmony_ci *buf++ = (rdata1 >> (i - 4) * 8) & 0xff; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci u32 wdata0 = 0, wdata1 = 0; 1868c2ecf20Sopenharmony_ci int i; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci for (i = 0; i < min(4, len); i++) 1898c2ecf20Sopenharmony_ci wdata0 |= *buf++ << (i * 8); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci for (i = 4; i < min(8, len); i++) 1928c2ecf20Sopenharmony_ci wdata1 |= *buf++ << ((i - 4) * 8); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci writel(wdata0, i2c->regs + REG_TOK_WDATA0); 1958c2ecf20Sopenharmony_ci writel(wdata1, i2c->regs + REG_TOK_WDATA1); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, 1988c2ecf20Sopenharmony_ci wdata0, wdata1, len); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void meson_i2c_prepare_xfer(struct meson_i2c *i2c) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci bool write = !(i2c->msg->flags & I2C_M_RD); 2048c2ecf20Sopenharmony_ci int i; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci i2c->count = min(i2c->msg->len - i2c->pos, 8); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci for (i = 0; i < i2c->count - 1; i++) 2098c2ecf20Sopenharmony_ci meson_i2c_add_token(i2c, TOKEN_DATA); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (i2c->count) { 2128c2ecf20Sopenharmony_ci if (write || i2c->pos + i2c->count < i2c->msg->len) 2138c2ecf20Sopenharmony_ci meson_i2c_add_token(i2c, TOKEN_DATA); 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci meson_i2c_add_token(i2c, TOKEN_DATA_LAST); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (write) 2198c2ecf20Sopenharmony_ci meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len) 2228c2ecf20Sopenharmony_ci meson_i2c_add_token(i2c, TOKEN_STOP); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0); 2258c2ecf20Sopenharmony_ci writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void meson_i2c_transfer_complete(struct meson_i2c *i2c, u32 ctrl) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci if (ctrl & REG_CTRL_ERROR) { 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * The bit is set when the IGNORE_NAK bit is cleared 2338c2ecf20Sopenharmony_ci * and the device didn't respond. In this case, the 2348c2ecf20Sopenharmony_ci * I2C controller automatically generates a STOP 2358c2ecf20Sopenharmony_ci * condition. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "error bit set\n"); 2388c2ecf20Sopenharmony_ci i2c->error = -ENXIO; 2398c2ecf20Sopenharmony_ci i2c->state = STATE_IDLE; 2408c2ecf20Sopenharmony_ci } else { 2418c2ecf20Sopenharmony_ci if (i2c->state == STATE_READ && i2c->count) 2428c2ecf20Sopenharmony_ci meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, 2438c2ecf20Sopenharmony_ci i2c->count); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci i2c->pos += i2c->count; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (i2c->pos >= i2c->msg->len) 2488c2ecf20Sopenharmony_ci i2c->state = STATE_IDLE; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic irqreturn_t meson_i2c_irq(int irqno, void *dev_id) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct meson_i2c *i2c = dev_id; 2558c2ecf20Sopenharmony_ci unsigned int ctrl; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci spin_lock(&i2c->lock); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci meson_i2c_reset_tokens(i2c); 2608c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); 2618c2ecf20Sopenharmony_ci ctrl = readl(i2c->regs + REG_CTRL); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n", 2648c2ecf20Sopenharmony_ci i2c->state, i2c->pos, i2c->count, ctrl); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (i2c->state == STATE_IDLE) { 2678c2ecf20Sopenharmony_ci spin_unlock(&i2c->lock); 2688c2ecf20Sopenharmony_ci return IRQ_NONE; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci meson_i2c_transfer_complete(i2c, ctrl); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (i2c->state == STATE_IDLE) { 2748c2ecf20Sopenharmony_ci complete(&i2c->done); 2758c2ecf20Sopenharmony_ci goto out; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Restart the processing */ 2798c2ecf20Sopenharmony_ci meson_i2c_prepare_xfer(i2c); 2808c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); 2818c2ecf20Sopenharmony_ciout: 2828c2ecf20Sopenharmony_ci spin_unlock(&i2c->lock); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci int token; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ : 2928c2ecf20Sopenharmony_ci TOKEN_SLAVE_ADDR_WRITE; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR, 2968c2ecf20Sopenharmony_ci FIELD_PREP(REG_SLV_ADDR, msg->addr << 1)); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci meson_i2c_add_token(i2c, TOKEN_START); 2998c2ecf20Sopenharmony_ci meson_i2c_add_token(i2c, token); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg, 3038c2ecf20Sopenharmony_ci int last, bool atomic) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci unsigned long time_left, flags; 3068c2ecf20Sopenharmony_ci int ret = 0; 3078c2ecf20Sopenharmony_ci u32 ctrl; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci i2c->msg = msg; 3108c2ecf20Sopenharmony_ci i2c->last = last; 3118c2ecf20Sopenharmony_ci i2c->pos = 0; 3128c2ecf20Sopenharmony_ci i2c->count = 0; 3138c2ecf20Sopenharmony_ci i2c->error = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci meson_i2c_reset_tokens(i2c); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci flags = (msg->flags & I2C_M_IGNORE_NAK) ? REG_CTRL_ACK_IGNORE : 0; 3188c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_ACK_IGNORE, flags); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!(msg->flags & I2C_M_NOSTART)) 3218c2ecf20Sopenharmony_ci meson_i2c_do_start(i2c, msg); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; 3248c2ecf20Sopenharmony_ci meson_i2c_prepare_xfer(i2c); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!atomic) 3278c2ecf20Sopenharmony_ci reinit_completion(&i2c->done); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Start the transfer */ 3308c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (atomic) { 3338c2ecf20Sopenharmony_ci ret = readl_poll_timeout_atomic(i2c->regs + REG_CTRL, ctrl, 3348c2ecf20Sopenharmony_ci !(ctrl & REG_CTRL_STATUS), 3358c2ecf20Sopenharmony_ci 10, I2C_TIMEOUT_MS * 1000); 3368c2ecf20Sopenharmony_ci } else { 3378c2ecf20Sopenharmony_ci time_left = msecs_to_jiffies(I2C_TIMEOUT_MS); 3388c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&i2c->done, time_left); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (!time_left) 3418c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* 3458c2ecf20Sopenharmony_ci * Protect access to i2c struct and registers from interrupt 3468c2ecf20Sopenharmony_ci * handlers triggered by a transfer terminated after the 3478c2ecf20Sopenharmony_ci * timeout period 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (atomic && !ret) 3528c2ecf20Sopenharmony_ci meson_i2c_transfer_complete(i2c, ctrl); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Abort any active operation */ 3558c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (ret) 3588c2ecf20Sopenharmony_ci i2c->state = STATE_IDLE; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (i2c->error) 3618c2ecf20Sopenharmony_ci ret = i2c->error; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int meson_i2c_xfer_messages(struct i2c_adapter *adap, 3698c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num, bool atomic) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct meson_i2c *i2c = adap->algo_data; 3728c2ecf20Sopenharmony_ci int i, ret = 0; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 3758c2ecf20Sopenharmony_ci ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1, atomic); 3768c2ecf20Sopenharmony_ci if (ret) 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return ret ?: i; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 3848c2ecf20Sopenharmony_ci int num) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci return meson_i2c_xfer_messages(adap, msgs, num, false); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int meson_i2c_xfer_atomic(struct i2c_adapter *adap, 3908c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci return meson_i2c_xfer_messages(adap, msgs, num, true); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic u32 meson_i2c_func(struct i2c_adapter *adap) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic const struct i2c_algorithm meson_i2c_algorithm = { 4018c2ecf20Sopenharmony_ci .master_xfer = meson_i2c_xfer, 4028c2ecf20Sopenharmony_ci .master_xfer_atomic = meson_i2c_xfer_atomic, 4038c2ecf20Sopenharmony_ci .functionality = meson_i2c_func, 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int meson_i2c_probe(struct platform_device *pdev) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 4098c2ecf20Sopenharmony_ci struct meson_i2c *i2c; 4108c2ecf20Sopenharmony_ci struct i2c_timings timings; 4118c2ecf20Sopenharmony_ci int irq, ret = 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL); 4148c2ecf20Sopenharmony_ci if (!i2c) 4158c2ecf20Sopenharmony_ci return -ENOMEM; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci i2c_parse_fw_timings(&pdev->dev, &timings, true); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci i2c->dev = &pdev->dev; 4208c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, i2c); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci spin_lock_init(&i2c->lock); 4238c2ecf20Sopenharmony_ci init_completion(&i2c->done); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci i2c->data = (const struct meson_i2c_data *) 4268c2ecf20Sopenharmony_ci of_device_get_match_data(&pdev->dev); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci i2c->clk = devm_clk_get(&pdev->dev, NULL); 4298c2ecf20Sopenharmony_ci if (IS_ERR(i2c->clk)) { 4308c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't get device clock\n"); 4318c2ecf20Sopenharmony_ci return PTR_ERR(i2c->clk); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci i2c->regs = devm_platform_ioremap_resource(pdev, 0); 4358c2ecf20Sopenharmony_ci if (IS_ERR(i2c->regs)) 4368c2ecf20Sopenharmony_ci return PTR_ERR(i2c->regs); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 4398c2ecf20Sopenharmony_ci if (irq < 0) 4408c2ecf20Sopenharmony_ci return irq; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c); 4438c2ecf20Sopenharmony_ci if (ret < 0) { 4448c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't request IRQ\n"); 4458c2ecf20Sopenharmony_ci return ret; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2c->clk); 4498c2ecf20Sopenharmony_ci if (ret < 0) { 4508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't prepare clock\n"); 4518c2ecf20Sopenharmony_ci return ret; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci strlcpy(i2c->adap.name, "Meson I2C adapter", 4558c2ecf20Sopenharmony_ci sizeof(i2c->adap.name)); 4568c2ecf20Sopenharmony_ci i2c->adap.owner = THIS_MODULE; 4578c2ecf20Sopenharmony_ci i2c->adap.algo = &meson_i2c_algorithm; 4588c2ecf20Sopenharmony_ci i2c->adap.dev.parent = &pdev->dev; 4598c2ecf20Sopenharmony_ci i2c->adap.dev.of_node = np; 4608c2ecf20Sopenharmony_ci i2c->adap.algo_data = i2c; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* 4638c2ecf20Sopenharmony_ci * A transfer is triggered when START bit changes from 0 to 1. 4648c2ecf20Sopenharmony_ci * Ensure that the bit is set to 0 after probe 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Disable filtering */ 4698c2ecf20Sopenharmony_ci meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, 4708c2ecf20Sopenharmony_ci REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&i2c->adap); 4758c2ecf20Sopenharmony_ci if (ret < 0) { 4768c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 4778c2ecf20Sopenharmony_ci return ret; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return 0; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int meson_i2c_remove(struct platform_device *pdev) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct meson_i2c *i2c = platform_get_drvdata(pdev); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci i2c_del_adapter(&i2c->adap); 4888c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return 0; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic const struct meson_i2c_data i2c_meson6_data = { 4948c2ecf20Sopenharmony_ci .div_factor = 4, 4958c2ecf20Sopenharmony_ci}; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic const struct meson_i2c_data i2c_gxbb_data = { 4988c2ecf20Sopenharmony_ci .div_factor = 4, 4998c2ecf20Sopenharmony_ci}; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic const struct meson_i2c_data i2c_axg_data = { 5028c2ecf20Sopenharmony_ci .div_factor = 3, 5038c2ecf20Sopenharmony_ci}; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic const struct of_device_id meson_i2c_match[] = { 5068c2ecf20Sopenharmony_ci { .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data }, 5078c2ecf20Sopenharmony_ci { .compatible = "amlogic,meson-gxbb-i2c", .data = &i2c_gxbb_data }, 5088c2ecf20Sopenharmony_ci { .compatible = "amlogic,meson-axg-i2c", .data = &i2c_axg_data }, 5098c2ecf20Sopenharmony_ci {}, 5108c2ecf20Sopenharmony_ci}; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, meson_i2c_match); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic struct platform_driver meson_i2c_driver = { 5158c2ecf20Sopenharmony_ci .probe = meson_i2c_probe, 5168c2ecf20Sopenharmony_ci .remove = meson_i2c_remove, 5178c2ecf20Sopenharmony_ci .driver = { 5188c2ecf20Sopenharmony_ci .name = "meson-i2c", 5198c2ecf20Sopenharmony_ci .of_match_table = meson_i2c_match, 5208c2ecf20Sopenharmony_ci }, 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cimodule_platform_driver(meson_i2c_driver); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic Meson I2C Bus driver"); 5268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); 5278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 528