1a1fee7bcSryan_chen // SPDX-License-Identifier: GPL-2.0+
2a1fee7bcSryan_chen /*
3a1fee7bcSryan_chen * Copyright ASPEED Technology Inc.
4a1fee7bcSryan_chen */
5a1fee7bcSryan_chen #include <linux/iopoll.h>
6a1fee7bcSryan_chen #include <common.h>
7a1fee7bcSryan_chen #include <clk.h>
8a1fee7bcSryan_chen #include <dm.h>
9a1fee7bcSryan_chen #include <errno.h>
10a1fee7bcSryan_chen #include <fdtdec.h>
11a1fee7bcSryan_chen #include <i2c.h>
12a1fee7bcSryan_chen #include <asm/io.h>
13a1fee7bcSryan_chen #include <regmap.h>
14a1fee7bcSryan_chen #include "ast2600_i2c_global.h"
15a1fee7bcSryan_chen
16a1fee7bcSryan_chen struct ast2600_i2c_regs {
17a1fee7bcSryan_chen u32 fun_ctrl;
18a1fee7bcSryan_chen u32 ac_timing;
19a1fee7bcSryan_chen u32 trx_buff;
20a1fee7bcSryan_chen u32 icr;
21a1fee7bcSryan_chen u32 ier;
22a1fee7bcSryan_chen u32 isr;
23a1fee7bcSryan_chen u32 cmd_sts;
24a1fee7bcSryan_chen };
25a1fee7bcSryan_chen
26a1fee7bcSryan_chen /* 0x00 : I2CC Master/Slave Function Control Register */
27a1fee7bcSryan_chen #define AST2600_I2CC_SLAVE_ADDR_RX_EN BIT(20)
28a1fee7bcSryan_chen #define AST2600_I2CC_MASTER_RETRY_MASK GENMASK(19, 18)
29a1fee7bcSryan_chen #define AST2600_I2CC_MASTER_RETRY(x) (((x) & GENMASK(1, 0)) << 18)
30a1fee7bcSryan_chen #define AST2600_I2CC_BUS_AUTO_RELEASE BIT(17)
31a1fee7bcSryan_chen #define AST2600_I2CC_M_SDA_LOCK_EN BIT(16)
32a1fee7bcSryan_chen #define AST2600_I2CC_MULTI_MASTER_DIS BIT(15)
33a1fee7bcSryan_chen #define AST2600_I2CC_M_SCL_DRIVE_EN BIT(14)
34a1fee7bcSryan_chen #define AST2600_I2CC_MSB_STS BIT(9)
35a1fee7bcSryan_chen #define AST2600_I2CC_SDA_DRIVE_1T_EN BIT(8)
36a1fee7bcSryan_chen #define AST2600_I2CC_M_SDA_DRIVE_1T_EN BIT(7)
37a1fee7bcSryan_chen #define AST2600_I2CC_M_HIGH_SPEED_EN BIT(6)
38a1fee7bcSryan_chen /* reserver 5 : 2 */
39a1fee7bcSryan_chen #define AST2600_I2CC_SLAVE_EN BIT(1)
40a1fee7bcSryan_chen #define AST2600_I2CC_MASTER_EN BIT(0)
41a1fee7bcSryan_chen
42a1fee7bcSryan_chen /* 0x04 : I2CD Clock and AC Timing Control Register #1 */
43a1fee7bcSryan_chen /* Base register value. These bits are always set by the driver. */
44a1fee7bcSryan_chen #define I2CD_CACTC_BASE 0xfff00300
45a1fee7bcSryan_chen #define I2CD_TCKHIGH_SHIFT 16
46a1fee7bcSryan_chen #define I2CD_TCKLOW_SHIFT 12
47a1fee7bcSryan_chen #define I2CD_THDDAT_SHIFT 10
48a1fee7bcSryan_chen #define I2CD_TO_DIV_SHIFT 8
49a1fee7bcSryan_chen #define I2CD_BASE_DIV_SHIFT 0
50a1fee7bcSryan_chen
51a1fee7bcSryan_chen /* 0x08 : I2CC Master/Slave Transmit/Receive Byte Buffer Register */
52a1fee7bcSryan_chen #define AST2600_I2CC_TX_DIR_MASK GENMASK(31, 29)
53a1fee7bcSryan_chen #define AST2600_I2CC_SDA_OE BIT(28)
54a1fee7bcSryan_chen #define AST2600_I2CC_SDA_O BIT(27)
55a1fee7bcSryan_chen #define AST2600_I2CC_SCL_OE BIT(26)
56a1fee7bcSryan_chen #define AST2600_I2CC_SCL_O BIT(25)
57a1fee7bcSryan_chen
58a1fee7bcSryan_chen #define AST2600_I2CC_SCL_LINE_STS BIT(18)
59a1fee7bcSryan_chen #define AST2600_I2CC_SDA_LINE_STS BIT(17)
60a1fee7bcSryan_chen #define AST2600_I2CC_BUS_BUSY_STS BIT(16)
61a1fee7bcSryan_chen #define AST2600_I2CC_GET_RX_BUFF(x) (((x) >> 8) & GENMASK(7, 0))
62a1fee7bcSryan_chen
63a1fee7bcSryan_chen /* 0x10 : I2CM Master Interrupt Control Register */
64a1fee7bcSryan_chen /* 0x14 : I2CM Master Interrupt Status Register */
65a1fee7bcSryan_chen #define AST2600_I2CM_PKT_TIMEOUT BIT(18)
66a1fee7bcSryan_chen #define AST2600_I2CM_PKT_ERROR BIT(17)
67a1fee7bcSryan_chen #define AST2600_I2CM_PKT_DONE BIT(16)
68a1fee7bcSryan_chen
69a1fee7bcSryan_chen #define AST2600_I2CM_BUS_RECOVER_FAIL BIT(15)
70a1fee7bcSryan_chen #define AST2600_I2CM_SDA_DL_TO BIT(14)
71a1fee7bcSryan_chen #define AST2600_I2CM_BUS_RECOVER BIT(13)
72a1fee7bcSryan_chen #define AST2600_I2CM_SMBUS_ALT BIT(12)
73a1fee7bcSryan_chen
74a1fee7bcSryan_chen #define AST2600_I2CM_SCL_LOW_TO BIT(6)
75a1fee7bcSryan_chen #define AST2600_I2CM_ABNORMAL BIT(5)
76a1fee7bcSryan_chen #define AST2600_I2CM_NORMAL_STOP BIT(4)
77a1fee7bcSryan_chen #define AST2600_I2CM_ARBIT_LOSS BIT(3)
78a1fee7bcSryan_chen #define AST2600_I2CM_RX_DONE BIT(2)
79a1fee7bcSryan_chen #define AST2600_I2CM_TX_NAK BIT(1)
80a1fee7bcSryan_chen #define AST2600_I2CM_TX_ACK BIT(0)
81a1fee7bcSryan_chen
82a1fee7bcSryan_chen /* 0x18 : I2CM Master Command/Status Register */
83a1fee7bcSryan_chen #define AST2600_I2CM_PKT_ADDR(x) (((x) & GENMASK(6, 0)) << 24)
84a1fee7bcSryan_chen #define AST2600_I2CM_PKT_EN BIT(16)
85a1fee7bcSryan_chen #define AST2600_I2CM_SDA_OE_OUT_DIR BIT(15)
86a1fee7bcSryan_chen #define AST2600_I2CM_SDA_O_OUT_DIR BIT(14)
87a1fee7bcSryan_chen #define AST2600_I2CM_SCL_OE_OUT_DIR BIT(13)
88a1fee7bcSryan_chen #define AST2600_I2CM_SCL_O_OUT_DIR BIT(12)
89a1fee7bcSryan_chen #define AST2600_I2CM_RECOVER_CMD_EN BIT(11)
90a1fee7bcSryan_chen
91a1fee7bcSryan_chen #define AST2600_I2CM_RX_DMA_EN BIT(9)
92a1fee7bcSryan_chen #define AST2600_I2CM_TX_DMA_EN BIT(8)
93a1fee7bcSryan_chen /* Command Bit */
94a1fee7bcSryan_chen #define AST2600_I2CM_RX_BUFF_EN BIT(7)
95a1fee7bcSryan_chen #define AST2600_I2CM_TX_BUFF_EN BIT(6)
96a1fee7bcSryan_chen #define AST2600_I2CM_STOP_CMD BIT(5)
97a1fee7bcSryan_chen #define AST2600_I2CM_RX_CMD_LAST BIT(4)
98a1fee7bcSryan_chen #define AST2600_I2CM_RX_CMD BIT(3)
99a1fee7bcSryan_chen
100a1fee7bcSryan_chen #define AST2600_I2CM_TX_CMD BIT(1)
101a1fee7bcSryan_chen #define AST2600_I2CM_START_CMD BIT(0)
102a1fee7bcSryan_chen
103a1fee7bcSryan_chen #define I2C_TIMEOUT_US 100000
104a1fee7bcSryan_chen /*
105a1fee7bcSryan_chen * Device private data
106a1fee7bcSryan_chen */
107a1fee7bcSryan_chen struct ast2600_i2c_priv {
108a1fee7bcSryan_chen struct clk clk;
109a1fee7bcSryan_chen struct ast2600_i2c_regs *regs;
110a1fee7bcSryan_chen void __iomem *global;
111a1fee7bcSryan_chen };
112a1fee7bcSryan_chen
ast2600_i2c_read_data(struct ast2600_i2c_priv * priv,u8 chip_addr,u8 * buffer,size_t len,bool send_stop)113a1fee7bcSryan_chen static int ast2600_i2c_read_data(struct ast2600_i2c_priv *priv, u8 chip_addr,
114a1fee7bcSryan_chen u8 *buffer, size_t len, bool send_stop)
115a1fee7bcSryan_chen {
116a1fee7bcSryan_chen int rx_cnt, ret = 0;
117a1fee7bcSryan_chen u32 cmd, isr;
118a1fee7bcSryan_chen
119a1fee7bcSryan_chen for (rx_cnt = 0; rx_cnt < len; rx_cnt++, buffer++) {
120a1fee7bcSryan_chen cmd = AST2600_I2CM_PKT_EN | AST2600_I2CM_PKT_ADDR(chip_addr) |
121a1fee7bcSryan_chen AST2600_I2CM_RX_CMD;
122a1fee7bcSryan_chen if (!rx_cnt)
123a1fee7bcSryan_chen cmd |= AST2600_I2CM_START_CMD;
124a1fee7bcSryan_chen
125a1fee7bcSryan_chen if ((len - 1) == rx_cnt)
126a1fee7bcSryan_chen cmd |= AST2600_I2CM_RX_CMD_LAST;
127a1fee7bcSryan_chen
128a1fee7bcSryan_chen if (send_stop && ((len - 1) == rx_cnt))
129a1fee7bcSryan_chen cmd |= AST2600_I2CM_STOP_CMD;
130a1fee7bcSryan_chen
131a1fee7bcSryan_chen writel(cmd, &priv->regs->cmd_sts);
132a1fee7bcSryan_chen
133a1fee7bcSryan_chen ret = readl_poll_timeout(&priv->regs->isr, isr,
134a1fee7bcSryan_chen isr & AST2600_I2CM_PKT_DONE,
135a1fee7bcSryan_chen I2C_TIMEOUT_US);
136a1fee7bcSryan_chen if (ret)
137a1fee7bcSryan_chen return -ETIMEDOUT;
138a1fee7bcSryan_chen
139a1fee7bcSryan_chen *buffer =
140a1fee7bcSryan_chen AST2600_I2CC_GET_RX_BUFF(readl(&priv->regs->trx_buff));
141a1fee7bcSryan_chen
142a1fee7bcSryan_chen writel(AST2600_I2CM_PKT_DONE, &priv->regs->isr);
143a1fee7bcSryan_chen
144a1fee7bcSryan_chen if (isr & AST2600_I2CM_TX_NAK)
145a1fee7bcSryan_chen return -EREMOTEIO;
146a1fee7bcSryan_chen }
147a1fee7bcSryan_chen
148a1fee7bcSryan_chen return 0;
149a1fee7bcSryan_chen }
150a1fee7bcSryan_chen
ast2600_i2c_write_data(struct ast2600_i2c_priv * priv,u8 chip_addr,u8 * buffer,size_t len,bool send_stop)151a1fee7bcSryan_chen static int ast2600_i2c_write_data(struct ast2600_i2c_priv *priv, u8 chip_addr,
152a1fee7bcSryan_chen u8 *buffer, size_t len, bool send_stop)
153a1fee7bcSryan_chen {
154a1fee7bcSryan_chen int tx_cnt, ret = 0;
155a1fee7bcSryan_chen u32 cmd, isr;
156a1fee7bcSryan_chen
157a1fee7bcSryan_chen if (!len) {
158a1fee7bcSryan_chen cmd = AST2600_I2CM_PKT_EN | AST2600_I2CM_PKT_ADDR(chip_addr) |
159a1fee7bcSryan_chen AST2600_I2CM_START_CMD;
160a1fee7bcSryan_chen writel(cmd, &priv->regs->cmd_sts);
161a1fee7bcSryan_chen ret = readl_poll_timeout(&priv->regs->isr, isr,
162a1fee7bcSryan_chen isr & AST2600_I2CM_PKT_DONE,
163a1fee7bcSryan_chen I2C_TIMEOUT_US);
164a1fee7bcSryan_chen if (ret)
165a1fee7bcSryan_chen return -ETIMEDOUT;
166a1fee7bcSryan_chen if (isr & AST2600_I2CM_TX_NAK)
167a1fee7bcSryan_chen return -EREMOTEIO;
168a1fee7bcSryan_chen
169a1fee7bcSryan_chen writel(AST2600_I2CM_PKT_DONE, &priv->regs->isr);
170a1fee7bcSryan_chen }
171a1fee7bcSryan_chen
172a1fee7bcSryan_chen for (tx_cnt = 0; tx_cnt < len; tx_cnt++, buffer++) {
173a1fee7bcSryan_chen cmd = AST2600_I2CM_PKT_EN | AST2600_I2CM_PKT_ADDR(chip_addr);
174a1fee7bcSryan_chen cmd |= AST2600_I2CM_TX_CMD;
175a1fee7bcSryan_chen
176a1fee7bcSryan_chen if (!tx_cnt)
177a1fee7bcSryan_chen cmd |= AST2600_I2CM_START_CMD;
178a1fee7bcSryan_chen
179a1fee7bcSryan_chen if (send_stop && ((len - 1) == tx_cnt))
180a1fee7bcSryan_chen cmd |= AST2600_I2CM_STOP_CMD;
181a1fee7bcSryan_chen
182a1fee7bcSryan_chen writel(*buffer, &priv->regs->trx_buff);
183a1fee7bcSryan_chen writel(cmd, &priv->regs->cmd_sts);
184a1fee7bcSryan_chen ret = readl_poll_timeout(&priv->regs->isr, isr,
185a1fee7bcSryan_chen isr & AST2600_I2CM_PKT_DONE,
186a1fee7bcSryan_chen I2C_TIMEOUT_US);
187a1fee7bcSryan_chen if (ret)
188a1fee7bcSryan_chen return -ETIMEDOUT;
189a1fee7bcSryan_chen
190a1fee7bcSryan_chen writel(AST2600_I2CM_PKT_DONE, &priv->regs->isr);
191a1fee7bcSryan_chen
192a1fee7bcSryan_chen if (isr & AST2600_I2CM_TX_NAK)
193a1fee7bcSryan_chen return -EREMOTEIO;
194a1fee7bcSryan_chen }
195a1fee7bcSryan_chen
196a1fee7bcSryan_chen return 0;
197a1fee7bcSryan_chen }
198a1fee7bcSryan_chen
ast2600_i2c_deblock(struct udevice * dev)199a1fee7bcSryan_chen static int ast2600_i2c_deblock(struct udevice *dev)
200a1fee7bcSryan_chen {
201a1fee7bcSryan_chen struct ast2600_i2c_priv *priv = dev_get_priv(dev);
202a1fee7bcSryan_chen u32 csr = readl(&priv->regs->cmd_sts);
203a1fee7bcSryan_chen u32 isr;
204a1fee7bcSryan_chen int ret;
205a1fee7bcSryan_chen
206a1fee7bcSryan_chen //reinit
207a1fee7bcSryan_chen writel(0, &priv->regs->fun_ctrl);
208a1fee7bcSryan_chen /* Enable Master Mode. Assuming single-master */
209a1fee7bcSryan_chen writel(AST2600_I2CC_BUS_AUTO_RELEASE | AST2600_I2CC_MASTER_EN |
210a1fee7bcSryan_chen AST2600_I2CC_MULTI_MASTER_DIS,
211a1fee7bcSryan_chen &priv->regs->fun_ctrl);
212a1fee7bcSryan_chen
213a1fee7bcSryan_chen csr = readl(&priv->regs->cmd_sts);
214a1fee7bcSryan_chen
215a1fee7bcSryan_chen if (!(csr & AST2600_I2CC_SDA_LINE_STS) &&
216a1fee7bcSryan_chen (csr & AST2600_I2CC_SCL_LINE_STS)) {
217a1fee7bcSryan_chen debug("Bus stuck (%x), attempting recovery\n", csr);
218a1fee7bcSryan_chen writel(AST2600_I2CM_RECOVER_CMD_EN, &priv->regs->cmd_sts);
219a1fee7bcSryan_chen ret = readl_poll_timeout(&priv->regs->isr, isr,
220a1fee7bcSryan_chen isr & (AST2600_I2CM_BUS_RECOVER_FAIL |
221a1fee7bcSryan_chen AST2600_I2CM_BUS_RECOVER),
222a1fee7bcSryan_chen I2C_TIMEOUT_US);
223a1fee7bcSryan_chen writel(~0, &priv->regs->isr);
224a1fee7bcSryan_chen if (ret)
225a1fee7bcSryan_chen return -EREMOTEIO;
226a1fee7bcSryan_chen }
227a1fee7bcSryan_chen
228a1fee7bcSryan_chen return 0;
229a1fee7bcSryan_chen }
230a1fee7bcSryan_chen
ast2600_i2c_xfer(struct udevice * dev,struct i2c_msg * msg,int nmsgs)231a1fee7bcSryan_chen static int ast2600_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
232a1fee7bcSryan_chen {
233a1fee7bcSryan_chen struct ast2600_i2c_priv *priv = dev_get_priv(dev);
234a1fee7bcSryan_chen int ret;
235a1fee7bcSryan_chen
236a1fee7bcSryan_chen if (readl(&priv->regs->trx_buff) & AST2600_I2CC_BUS_BUSY_STS)
237a1fee7bcSryan_chen return -EREMOTEIO;
238a1fee7bcSryan_chen
239a1fee7bcSryan_chen for (; nmsgs > 0; nmsgs--, msg++) {
240a1fee7bcSryan_chen if (msg->flags & I2C_M_RD) {
241a1fee7bcSryan_chen debug("i2c_read: chip=0x%x, len=0x%x, flags=0x%x\n",
242a1fee7bcSryan_chen msg->addr, msg->len, msg->flags);
243a1fee7bcSryan_chen ret = ast2600_i2c_read_data(priv, msg->addr, msg->buf,
244a1fee7bcSryan_chen msg->len, (nmsgs == 1));
245a1fee7bcSryan_chen } else {
246a1fee7bcSryan_chen debug("i2c_write: chip=0x%x, len=0x%x, flags=0x%x\n",
247a1fee7bcSryan_chen msg->addr, msg->len, msg->flags);
248a1fee7bcSryan_chen ret = ast2600_i2c_write_data(priv, msg->addr, msg->buf,
249a1fee7bcSryan_chen msg->len, (nmsgs == 1));
250a1fee7bcSryan_chen }
251a1fee7bcSryan_chen if (ret) {
252a1fee7bcSryan_chen debug("%s: error (%d)\n", __func__, ret);
253a1fee7bcSryan_chen return -EREMOTEIO;
254a1fee7bcSryan_chen }
255a1fee7bcSryan_chen }
256a1fee7bcSryan_chen
257a1fee7bcSryan_chen return 0;
258a1fee7bcSryan_chen }
259a1fee7bcSryan_chen
ast2600_i2c_set_speed(struct udevice * dev,unsigned int speed)260a1fee7bcSryan_chen static int ast2600_i2c_set_speed(struct udevice *dev, unsigned int speed)
261a1fee7bcSryan_chen {
262a1fee7bcSryan_chen struct ast2600_i2c_priv *priv = dev_get_priv(dev);
263a1fee7bcSryan_chen unsigned long base_clk1, base_clk2, base_clk3, base_clk4;
264a1fee7bcSryan_chen int baseclk_idx;
265a1fee7bcSryan_chen u32 clk_div_reg;
266a1fee7bcSryan_chen u32 apb_clk;
267a1fee7bcSryan_chen u32 scl_low;
268a1fee7bcSryan_chen u32 scl_high;
269a1fee7bcSryan_chen int divisor;
270a1fee7bcSryan_chen int inc = 0;
271a1fee7bcSryan_chen u32 data;
272a1fee7bcSryan_chen
273a1fee7bcSryan_chen debug("Setting speed for I2C%d to <%u>\n", dev->seq, speed);
274a1fee7bcSryan_chen if (!speed) {
275a1fee7bcSryan_chen debug("No valid speed specified\n");
276a1fee7bcSryan_chen return -EINVAL;
277a1fee7bcSryan_chen }
278a1fee7bcSryan_chen
279a1fee7bcSryan_chen apb_clk = clk_get_rate(&priv->clk);
280a1fee7bcSryan_chen
281a1fee7bcSryan_chen clk_div_reg = readl(priv->global + 0x10);
282a1fee7bcSryan_chen base_clk1 = (apb_clk * 10) / ((((clk_div_reg & 0xff) + 2) * 10) / 2);
283a1fee7bcSryan_chen base_clk2 =
284a1fee7bcSryan_chen (apb_clk * 10) / (((((clk_div_reg >> 8) & 0xff) + 2) * 10) / 2);
285a1fee7bcSryan_chen base_clk3 = (apb_clk * 10) /
286a1fee7bcSryan_chen (((((clk_div_reg >> 16) & 0xff) + 2) * 10) / 2);
287a1fee7bcSryan_chen base_clk4 = (apb_clk * 10) /
288a1fee7bcSryan_chen (((((clk_div_reg >> 24) & 0xff) + 2) * 10) / 2);
289a1fee7bcSryan_chen
290a1fee7bcSryan_chen if ((apb_clk / speed) <= 32) {
291a1fee7bcSryan_chen baseclk_idx = 0;
292a1fee7bcSryan_chen divisor = DIV_ROUND_UP(apb_clk, speed);
293a1fee7bcSryan_chen } else if ((base_clk1 / speed) <= 32) {
294a1fee7bcSryan_chen baseclk_idx = 1;
295a1fee7bcSryan_chen divisor = DIV_ROUND_UP(base_clk1, speed);
296a1fee7bcSryan_chen } else if ((base_clk2 / speed) <= 32) {
297a1fee7bcSryan_chen baseclk_idx = 2;
298a1fee7bcSryan_chen divisor = DIV_ROUND_UP(base_clk2, speed);
299a1fee7bcSryan_chen } else if ((base_clk3 / speed) <= 32) {
300a1fee7bcSryan_chen baseclk_idx = 3;
301a1fee7bcSryan_chen divisor = DIV_ROUND_UP(base_clk3, speed);
302a1fee7bcSryan_chen } else {
303a1fee7bcSryan_chen baseclk_idx = 4;
304a1fee7bcSryan_chen divisor = DIV_ROUND_UP(base_clk4, speed);
305a1fee7bcSryan_chen inc = 0;
306a1fee7bcSryan_chen while ((divisor + inc) > 32) {
307a1fee7bcSryan_chen inc |= divisor & 0x1;
308a1fee7bcSryan_chen divisor >>= 1;
309a1fee7bcSryan_chen baseclk_idx++;
310a1fee7bcSryan_chen }
311a1fee7bcSryan_chen divisor += inc;
312a1fee7bcSryan_chen }
313a1fee7bcSryan_chen divisor = min_t(int, divisor, 32);
314a1fee7bcSryan_chen baseclk_idx &= 0xf;
315a1fee7bcSryan_chen scl_low = ((divisor * 9) / 16) - 1;
316a1fee7bcSryan_chen scl_low = min_t(u32, scl_low, 0xf);
317a1fee7bcSryan_chen scl_high = (divisor - scl_low - 2) & 0xf;
318a1fee7bcSryan_chen /* Divisor : Base Clock : tCKHighMin : tCK High : tCK Low */
319a1fee7bcSryan_chen data = ((scl_high - 1) << 20) | (scl_high << 16) | (scl_low << 12) |
320a1fee7bcSryan_chen (baseclk_idx);
321a1fee7bcSryan_chen /* Set AC Timing */
322a1fee7bcSryan_chen writel(data, &priv->regs->ac_timing);
323a1fee7bcSryan_chen
324a1fee7bcSryan_chen return 0;
325a1fee7bcSryan_chen }
326a1fee7bcSryan_chen
ast2600_i2c_probe(struct udevice * dev)327a1fee7bcSryan_chen static int ast2600_i2c_probe(struct udevice *dev)
328a1fee7bcSryan_chen {
329a1fee7bcSryan_chen struct ast2600_i2c_priv *priv = dev_get_priv(dev);
330a1fee7bcSryan_chen struct udevice *misc_dev;
331a1fee7bcSryan_chen int ret;
332a1fee7bcSryan_chen
333a1fee7bcSryan_chen /* find global base address */
334a1fee7bcSryan_chen ret = uclass_get_device_by_driver(UCLASS_MISC,
335a1fee7bcSryan_chen DM_GET_DRIVER(aspeed_i2c_global),
336a1fee7bcSryan_chen &misc_dev);
337a1fee7bcSryan_chen if (ret) {
338a1fee7bcSryan_chen debug("i2c global not defined\n");
339a1fee7bcSryan_chen return ret;
340a1fee7bcSryan_chen }
341a1fee7bcSryan_chen
342a1fee7bcSryan_chen priv->global = devfdt_get_addr_ptr(misc_dev);
343a1fee7bcSryan_chen if (IS_ERR(priv->global)) {
344a1fee7bcSryan_chen debug("%s(): can't get global\n", __func__);
345a1fee7bcSryan_chen return PTR_ERR(priv->global);
346a1fee7bcSryan_chen }
347a1fee7bcSryan_chen
348a1fee7bcSryan_chen /* Reset device */
349a1fee7bcSryan_chen writel(0, &priv->regs->fun_ctrl);
350a1fee7bcSryan_chen /* Enable Master Mode. Assuming single-master */
351a1fee7bcSryan_chen writel(AST2600_I2CC_BUS_AUTO_RELEASE | AST2600_I2CC_MASTER_EN |
352a1fee7bcSryan_chen AST2600_I2CC_MULTI_MASTER_DIS,
353a1fee7bcSryan_chen &priv->regs->fun_ctrl);
354a1fee7bcSryan_chen
355a1fee7bcSryan_chen writel(0, &priv->regs->ier);
356a1fee7bcSryan_chen /* Clear Interrupt */
357a1fee7bcSryan_chen writel(~0, &priv->regs->isr);
358a1fee7bcSryan_chen
359a1fee7bcSryan_chen return 0;
360a1fee7bcSryan_chen }
361a1fee7bcSryan_chen
ast2600_i2c_ofdata_to_platdata(struct udevice * dev)362a1fee7bcSryan_chen static int ast2600_i2c_ofdata_to_platdata(struct udevice *dev)
363a1fee7bcSryan_chen {
364a1fee7bcSryan_chen struct ast2600_i2c_priv *priv = dev_get_priv(dev);
365a1fee7bcSryan_chen int ret;
366a1fee7bcSryan_chen
367a1fee7bcSryan_chen priv->regs = devfdt_get_addr_ptr(dev);
368a1fee7bcSryan_chen if (IS_ERR(priv->regs))
369a1fee7bcSryan_chen return PTR_ERR(priv->regs);
370a1fee7bcSryan_chen
371a1fee7bcSryan_chen ret = clk_get_by_index(dev, 0, &priv->clk);
372a1fee7bcSryan_chen if (ret < 0) {
373a1fee7bcSryan_chen debug("%s: Can't get clock for %s: %d\n", __func__, dev->name,
374a1fee7bcSryan_chen ret);
375a1fee7bcSryan_chen return ret;
376a1fee7bcSryan_chen }
377a1fee7bcSryan_chen
378a1fee7bcSryan_chen return 0;
379a1fee7bcSryan_chen }
380a1fee7bcSryan_chen
381a1fee7bcSryan_chen static const struct dm_i2c_ops ast2600_i2c_ops = {
382a1fee7bcSryan_chen .xfer = ast2600_i2c_xfer,
383a1fee7bcSryan_chen .deblock = ast2600_i2c_deblock,
384a1fee7bcSryan_chen .set_bus_speed = ast2600_i2c_set_speed,
385a1fee7bcSryan_chen };
386a1fee7bcSryan_chen
387a1fee7bcSryan_chen static const struct udevice_id ast2600_i2c_ids[] = {
388*982f6418SJoel Stanley { .compatible = "aspeed,ast2600-i2c-bus" },
389a1fee7bcSryan_chen {},
390a1fee7bcSryan_chen };
391a1fee7bcSryan_chen
392a1fee7bcSryan_chen U_BOOT_DRIVER(ast2600_i2c) = {
393a1fee7bcSryan_chen .name = "ast2600_i2c",
394a1fee7bcSryan_chen .id = UCLASS_I2C,
395a1fee7bcSryan_chen .of_match = ast2600_i2c_ids,
396a1fee7bcSryan_chen .probe = ast2600_i2c_probe,
397a1fee7bcSryan_chen .ofdata_to_platdata = ast2600_i2c_ofdata_to_platdata,
398a1fee7bcSryan_chen .priv_auto_alloc_size = sizeof(struct ast2600_i2c_priv),
399a1fee7bcSryan_chen .ops = &ast2600_i2c_ops,
400a1fee7bcSryan_chen };
401