Lines Matching full:i2c
2 * I2C bus driver for Amlogic Meson SoCs
14 #include <linux/i2c.h>
24 /* Meson I2C register map */
72 * struct meson_i2c - Meson I2C device private data
74 * @adap: I2C adapter instance
78 * @msg: Pointer to the current I2C message
111 static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, in meson_i2c_set_mask() argument
116 data = readl(i2c->regs + reg); in meson_i2c_set_mask()
119 writel(data, i2c->regs + reg); in meson_i2c_set_mask()
122 static void meson_i2c_reset_tokens(struct meson_i2c *i2c) in meson_i2c_reset_tokens() argument
124 i2c->tokens[0] = 0; in meson_i2c_reset_tokens()
125 i2c->tokens[1] = 0; in meson_i2c_reset_tokens()
126 i2c->num_tokens = 0; in meson_i2c_reset_tokens()
129 static void meson_i2c_add_token(struct meson_i2c *i2c, int token) in meson_i2c_add_token() argument
131 if (i2c->num_tokens < 8) in meson_i2c_add_token()
132 i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4); in meson_i2c_add_token()
134 i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4); in meson_i2c_add_token()
136 i2c->num_tokens++; in meson_i2c_add_token()
139 static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) in meson_i2c_set_clk_div() argument
141 unsigned long clk_rate = clk_get_rate(i2c->clk); in meson_i2c_set_clk_div()
146 div = DIV_ROUND_UP(div, i2c->data->div_factor); in meson_i2c_set_clk_div()
150 dev_err(i2c->dev, "requested bus frequency too low\n"); in meson_i2c_set_clk_div()
154 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV, in meson_i2c_set_clk_div()
157 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT, in meson_i2c_set_clk_div()
161 meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0); in meson_i2c_set_clk_div()
163 dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__, in meson_i2c_set_clk_div()
167 static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len) in meson_i2c_get_data() argument
172 rdata0 = readl(i2c->regs + REG_TOK_RDATA0); in meson_i2c_get_data()
173 rdata1 = readl(i2c->regs + REG_TOK_RDATA1); in meson_i2c_get_data()
175 dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, in meson_i2c_get_data()
185 static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len) in meson_i2c_put_data() argument
196 writel(wdata0, i2c->regs + REG_TOK_WDATA0); in meson_i2c_put_data()
197 writel(wdata1, i2c->regs + REG_TOK_WDATA1); in meson_i2c_put_data()
199 dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, in meson_i2c_put_data()
203 static void meson_i2c_prepare_xfer(struct meson_i2c *i2c) in meson_i2c_prepare_xfer() argument
205 bool write = !(i2c->msg->flags & I2C_M_RD); in meson_i2c_prepare_xfer()
208 i2c->count = min(i2c->msg->len - i2c->pos, 8); in meson_i2c_prepare_xfer()
210 for (i = 0; i < i2c->count - 1; i++) in meson_i2c_prepare_xfer()
211 meson_i2c_add_token(i2c, TOKEN_DATA); in meson_i2c_prepare_xfer()
213 if (i2c->count) { in meson_i2c_prepare_xfer()
214 if (write || i2c->pos + i2c->count < i2c->msg->len) in meson_i2c_prepare_xfer()
215 meson_i2c_add_token(i2c, TOKEN_DATA); in meson_i2c_prepare_xfer()
217 meson_i2c_add_token(i2c, TOKEN_DATA_LAST); in meson_i2c_prepare_xfer()
221 meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); in meson_i2c_prepare_xfer()
223 if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len) in meson_i2c_prepare_xfer()
224 meson_i2c_add_token(i2c, TOKEN_STOP); in meson_i2c_prepare_xfer()
226 writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0); in meson_i2c_prepare_xfer()
227 writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); in meson_i2c_prepare_xfer()
232 struct meson_i2c *i2c = dev_id; in meson_i2c_irq() local
235 spin_lock(&i2c->lock); in meson_i2c_irq()
237 meson_i2c_reset_tokens(i2c); in meson_i2c_irq()
238 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); in meson_i2c_irq()
239 ctrl = readl(i2c->regs + REG_CTRL); in meson_i2c_irq()
241 dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n", in meson_i2c_irq()
242 i2c->state, i2c->pos, i2c->count, ctrl); in meson_i2c_irq()
244 if (i2c->state == STATE_IDLE) { in meson_i2c_irq()
245 spin_unlock(&i2c->lock); in meson_i2c_irq()
253 * I2C controller automatically generates a STOP in meson_i2c_irq()
256 dev_dbg(i2c->dev, "error bit set\n"); in meson_i2c_irq()
257 i2c->error = -ENXIO; in meson_i2c_irq()
258 i2c->state = STATE_IDLE; in meson_i2c_irq()
259 complete(&i2c->done); in meson_i2c_irq()
263 if (i2c->state == STATE_READ && i2c->count) in meson_i2c_irq()
264 meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); in meson_i2c_irq()
266 i2c->pos += i2c->count; in meson_i2c_irq()
268 if (i2c->pos >= i2c->msg->len) { in meson_i2c_irq()
269 i2c->state = STATE_IDLE; in meson_i2c_irq()
270 complete(&i2c->done); in meson_i2c_irq()
275 meson_i2c_prepare_xfer(i2c); in meson_i2c_irq()
276 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); in meson_i2c_irq()
278 spin_unlock(&i2c->lock); in meson_i2c_irq()
283 static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg) in meson_i2c_do_start() argument
291 meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR, in meson_i2c_do_start()
294 meson_i2c_add_token(i2c, TOKEN_START); in meson_i2c_do_start()
295 meson_i2c_add_token(i2c, token); in meson_i2c_do_start()
298 static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg, in meson_i2c_xfer_msg() argument
304 i2c->msg = msg; in meson_i2c_xfer_msg()
305 i2c->last = last; in meson_i2c_xfer_msg()
306 i2c->pos = 0; in meson_i2c_xfer_msg()
307 i2c->count = 0; in meson_i2c_xfer_msg()
308 i2c->error = 0; in meson_i2c_xfer_msg()
310 meson_i2c_reset_tokens(i2c); in meson_i2c_xfer_msg()
313 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_ACK_IGNORE, flags); in meson_i2c_xfer_msg()
316 meson_i2c_do_start(i2c, msg); in meson_i2c_xfer_msg()
318 i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; in meson_i2c_xfer_msg()
319 meson_i2c_prepare_xfer(i2c); in meson_i2c_xfer_msg()
320 reinit_completion(&i2c->done); in meson_i2c_xfer_msg()
323 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); in meson_i2c_xfer_msg()
326 time_left = wait_for_completion_timeout(&i2c->done, time_left); in meson_i2c_xfer_msg()
329 * Protect access to i2c struct and registers from interrupt in meson_i2c_xfer_msg()
333 spin_lock_irqsave(&i2c->lock, flags); in meson_i2c_xfer_msg()
336 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); in meson_i2c_xfer_msg()
339 i2c->state = STATE_IDLE; in meson_i2c_xfer_msg()
343 if (i2c->error) in meson_i2c_xfer_msg()
344 ret = i2c->error; in meson_i2c_xfer_msg()
346 spin_unlock_irqrestore(&i2c->lock, flags); in meson_i2c_xfer_msg()
354 struct meson_i2c *i2c = adap->algo_data; in meson_i2c_xfer() local
357 clk_enable(i2c->clk); in meson_i2c_xfer()
360 ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1); in meson_i2c_xfer()
365 clk_disable(i2c->clk); in meson_i2c_xfer()
383 struct meson_i2c *i2c; in meson_i2c_probe() local
388 i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL); in meson_i2c_probe()
389 if (!i2c) in meson_i2c_probe()
394 i2c->dev = &pdev->dev; in meson_i2c_probe()
395 platform_set_drvdata(pdev, i2c); in meson_i2c_probe()
397 spin_lock_init(&i2c->lock); in meson_i2c_probe()
398 init_completion(&i2c->done); in meson_i2c_probe()
400 i2c->data = (const struct meson_i2c_data *) in meson_i2c_probe()
403 i2c->clk = devm_clk_get(&pdev->dev, NULL); in meson_i2c_probe()
404 if (IS_ERR(i2c->clk)) { in meson_i2c_probe()
406 return PTR_ERR(i2c->clk); in meson_i2c_probe()
410 i2c->regs = devm_ioremap_resource(&pdev->dev, mem); in meson_i2c_probe()
411 if (IS_ERR(i2c->regs)) in meson_i2c_probe()
412 return PTR_ERR(i2c->regs); in meson_i2c_probe()
420 ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c); in meson_i2c_probe()
426 ret = clk_prepare(i2c->clk); in meson_i2c_probe()
432 strlcpy(i2c->adap.name, "Meson I2C adapter", in meson_i2c_probe()
433 sizeof(i2c->adap.name)); in meson_i2c_probe()
434 i2c->adap.owner = THIS_MODULE; in meson_i2c_probe()
435 i2c->adap.algo = &meson_i2c_algorithm; in meson_i2c_probe()
436 i2c->adap.dev.parent = &pdev->dev; in meson_i2c_probe()
437 i2c->adap.dev.of_node = np; in meson_i2c_probe()
438 i2c->adap.algo_data = i2c; in meson_i2c_probe()
444 meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); in meson_i2c_probe()
446 ret = i2c_add_adapter(&i2c->adap); in meson_i2c_probe()
448 clk_unprepare(i2c->clk); in meson_i2c_probe()
453 meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, in meson_i2c_probe()
456 meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); in meson_i2c_probe()
463 struct meson_i2c *i2c = platform_get_drvdata(pdev); in meson_i2c_remove() local
465 i2c_del_adapter(&i2c->adap); in meson_i2c_remove()
466 clk_unprepare(i2c->clk); in meson_i2c_remove()
484 { .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data },
485 { .compatible = "amlogic,meson-gxbb-i2c", .data = &i2c_gxbb_data },
486 { .compatible = "amlogic,meson-axg-i2c", .data = &i2c_axg_data },
496 .name = "meson-i2c",
503 MODULE_DESCRIPTION("Amlogic Meson I2C Bus driver");