Lines Matching +full:num +full:- +full:transfer +full:- +full:bits
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2024-2025 Troy Mitchell <troymitchell988@gmail.com>
23 #define SPACEMIT_CR_TB BIT(3) /* transfer byte bit */
24 /* Bits 4-7 are reserved */
28 /* Bits 11-12 are reserved */
31 /* Bits 15-17 are reserved */
37 /* Bits 23-24 are reserved */
42 #define SPACEMIT_CR_RXHFIE BIT(29) /* receive FIFO half-full int enable */
53 /* Bits 0-13 are reserved */
69 #define SPACEMIT_SR_RXHF BIT(29) /* RX FIFO half-full */
98 /* i2c-spacemit driver's main struct */
127 val = readl(i2c->base + SPACEMIT_ICR); in spacemit_i2c_enable()
129 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_enable()
136 val = readl(i2c->base + SPACEMIT_ICR); in spacemit_i2c_disable()
138 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_disable()
143 writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR); in spacemit_i2c_reset()
145 writel(0, i2c->base + SPACEMIT_ICR); in spacemit_i2c_reset()
150 dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status); in spacemit_i2c_handle_err()
152 if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) { in spacemit_i2c_handle_err()
154 return -EAGAIN; in spacemit_i2c_handle_err()
157 return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO; in spacemit_i2c_handle_err()
165 status = readl(i2c->base + SPACEMIT_IBMR); in spacemit_i2c_conditionally_reset_bus()
173 status = readl(i2c->base + SPACEMIT_IBMR); in spacemit_i2c_conditionally_reset_bus()
175 dev_warn_ratelimited(i2c->dev, "unit reset failed\n"); in spacemit_i2c_conditionally_reset_bus()
183 val = readl(i2c->base + SPACEMIT_ISR); in spacemit_i2c_wait_bus_idle()
187 ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR, in spacemit_i2c_wait_bus_idle()
198 /* in case bus is not released after transfer completes */ in spacemit_i2c_check_bus_release()
199 if (readl(i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) { in spacemit_i2c_check_bus_release()
210 * Unmask interrupt bits for all xfer mode: in spacemit_i2c_init()
218 * Unmask interrupt bits for interrupt xfer mode: in spacemit_i2c_init()
227 if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ) in spacemit_i2c_init()
239 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_init()
245 writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); in spacemit_i2c_clear_int_status()
251 struct i2c_msg *cur_msg = i2c->msgs + i2c->msg_idx; in spacemit_i2c_start()
253 i2c->read = !!(cur_msg->flags & I2C_M_RD); in spacemit_i2c_start()
255 i2c->state = SPACEMIT_STATE_START; in spacemit_i2c_start()
257 target_addr_rw = (cur_msg->addr & 0x7f) << 1; in spacemit_i2c_start()
258 if (cur_msg->flags & I2C_M_RD) in spacemit_i2c_start()
261 writel(target_addr_rw, i2c->base + SPACEMIT_IDBR); in spacemit_i2c_start()
264 val = readl(i2c->base + SPACEMIT_ICR); in spacemit_i2c_start()
267 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_start()
274 val = readl(i2c->base + SPACEMIT_ICR); in spacemit_i2c_stop()
277 if (i2c->read) in spacemit_i2c_stop()
280 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_stop()
288 for (i2c->msg_idx = 0; i2c->msg_idx < i2c->msg_num; i2c->msg_idx++) { in spacemit_i2c_xfer_msg()
289 msg = &i2c->msgs[i2c->msg_idx]; in spacemit_i2c_xfer_msg()
290 i2c->msg_buf = msg->buf; in spacemit_i2c_xfer_msg()
291 i2c->unprocessed = msg->len; in spacemit_i2c_xfer_msg()
292 i2c->status = 0; in spacemit_i2c_xfer_msg()
294 reinit_completion(&i2c->complete); in spacemit_i2c_xfer_msg()
298 time_left = wait_for_completion_timeout(&i2c->complete, in spacemit_i2c_xfer_msg()
299 i2c->adapt.timeout); in spacemit_i2c_xfer_msg()
301 dev_err(i2c->dev, "msg completion timeout\n"); in spacemit_i2c_xfer_msg()
304 return -ETIMEDOUT; in spacemit_i2c_xfer_msg()
307 if (i2c->status & SPACEMIT_SR_ERR) in spacemit_i2c_xfer_msg()
316 if (i2c->msg_idx != i2c->msg_num - 1) in spacemit_i2c_is_last_msg()
319 if (i2c->read) in spacemit_i2c_is_last_msg()
320 return i2c->unprocessed == 1; in spacemit_i2c_is_last_msg()
322 return !i2c->unprocessed; in spacemit_i2c_is_last_msg()
327 /* if transfer completes, SPACEMIT_ISR will handle it */ in spacemit_i2c_handle_write()
328 if (i2c->status & SPACEMIT_SR_MSD) in spacemit_i2c_handle_write()
331 if (i2c->unprocessed) { in spacemit_i2c_handle_write()
332 writel(*i2c->msg_buf++, i2c->base + SPACEMIT_IDBR); in spacemit_i2c_handle_write()
333 i2c->unprocessed--; in spacemit_i2c_handle_write()
338 i2c->state = SPACEMIT_STATE_IDLE; in spacemit_i2c_handle_write()
339 complete(&i2c->complete); in spacemit_i2c_handle_write()
344 if (i2c->unprocessed) { in spacemit_i2c_handle_read()
345 *i2c->msg_buf++ = readl(i2c->base + SPACEMIT_IDBR); in spacemit_i2c_handle_read()
346 i2c->unprocessed--; in spacemit_i2c_handle_read()
349 /* if transfer completes, SPACEMIT_ISR will handle it */ in spacemit_i2c_handle_read()
350 if (i2c->status & (SPACEMIT_SR_MSD | SPACEMIT_SR_ACKNAK)) in spacemit_i2c_handle_read()
354 if (i2c->unprocessed) in spacemit_i2c_handle_read()
358 i2c->state = SPACEMIT_STATE_IDLE; in spacemit_i2c_handle_read()
359 complete(&i2c->complete); in spacemit_i2c_handle_read()
364 i2c->state = i2c->read ? SPACEMIT_STATE_READ : SPACEMIT_STATE_WRITE; in spacemit_i2c_handle_start()
365 if (i2c->state == SPACEMIT_STATE_WRITE) in spacemit_i2c_handle_start()
377 if (!(i2c->status & (SPACEMIT_SR_ERR | SPACEMIT_SR_MSD))) in spacemit_i2c_err_check()
387 val = readl(i2c->base + SPACEMIT_ICR); in spacemit_i2c_err_check()
389 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_err_check()
393 i2c->state = SPACEMIT_STATE_IDLE; in spacemit_i2c_err_check()
394 complete(&i2c->complete); in spacemit_i2c_err_check()
402 status = readl(i2c->base + SPACEMIT_ISR); in spacemit_i2c_irq_handler()
406 i2c->status = status; in spacemit_i2c_irq_handler()
410 if (i2c->status & SPACEMIT_SR_ERR) in spacemit_i2c_irq_handler()
413 val = readl(i2c->base + SPACEMIT_ICR); in spacemit_i2c_irq_handler()
415 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_irq_handler()
417 switch (i2c->state) { in spacemit_i2c_irq_handler()
431 if (i2c->state != SPACEMIT_STATE_IDLE) { in spacemit_i2c_irq_handler()
438 writel(val, i2c->base + SPACEMIT_ICR); in spacemit_i2c_irq_handler()
452 for (; idx < i2c->msg_num; idx++) in spacemit_i2c_calc_timeout()
453 cnt += (i2c->msgs + idx)->len + 1; in spacemit_i2c_calc_timeout()
457 * 9 clock cycles: 8 bits of data plus 1 ACK/NACK bit. in spacemit_i2c_calc_timeout()
459 timeout = cnt * 9 * USEC_PER_SEC / i2c->clock_freq; in spacemit_i2c_calc_timeout()
461 i2c->adapt.timeout = usecs_to_jiffies(timeout + USEC_PER_SEC / 10) / i2c->msg_num; in spacemit_i2c_calc_timeout()
464 static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num) in spacemit_i2c_xfer() argument
469 i2c->msgs = msgs; in spacemit_i2c_xfer()
470 i2c->msg_num = num; in spacemit_i2c_xfer()
482 dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret); in spacemit_i2c_xfer()
488 if (ret == -ETIMEDOUT || ret == -EAGAIN) in spacemit_i2c_xfer()
489 dev_err(i2c->dev, "i2c transfer failed, ret %d err 0x%lx\n", in spacemit_i2c_xfer()
490 ret, i2c->status & SPACEMIT_SR_ERR); in spacemit_i2c_xfer()
492 return ret < 0 ? ret : num; in spacemit_i2c_xfer()
508 struct device *dev = &pdev->dev; in spacemit_i2c_probe()
509 struct device_node *of_node = pdev->dev.of_node; in spacemit_i2c_probe()
515 return -ENOMEM; in spacemit_i2c_probe()
517 ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq); in spacemit_i2c_probe()
518 if (ret && ret != -EINVAL) in spacemit_i2c_probe()
519 dev_warn(dev, "failed to read clock-frequency property: %d\n", ret); in spacemit_i2c_probe()
521 /* For now, this driver doesn't support high-speed. */ in spacemit_i2c_probe()
522 if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) { in spacemit_i2c_probe()
524 i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ); in spacemit_i2c_probe()
525 i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ; in spacemit_i2c_probe()
526 } else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) { in spacemit_i2c_probe()
528 i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ); in spacemit_i2c_probe()
529 i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ; in spacemit_i2c_probe()
532 i2c->dev = &pdev->dev; in spacemit_i2c_probe()
534 i2c->base = devm_platform_ioremap_resource(pdev, 0); in spacemit_i2c_probe()
535 if (IS_ERR(i2c->base)) in spacemit_i2c_probe()
536 return dev_err_probe(dev, PTR_ERR(i2c->base), "failed to do ioremap"); in spacemit_i2c_probe()
538 i2c->irq = platform_get_irq(pdev, 0); in spacemit_i2c_probe()
539 if (i2c->irq < 0) in spacemit_i2c_probe()
540 return dev_err_probe(dev, i2c->irq, "failed to get irq resource"); in spacemit_i2c_probe()
542 ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler, in spacemit_i2c_probe()
543 IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(i2c->dev), i2c); in spacemit_i2c_probe()
557 i2c_set_adapdata(&i2c->adapt, i2c); in spacemit_i2c_probe()
558 i2c->adapt.owner = THIS_MODULE; in spacemit_i2c_probe()
559 i2c->adapt.algo = &spacemit_i2c_algo; in spacemit_i2c_probe()
560 i2c->adapt.dev.parent = i2c->dev; in spacemit_i2c_probe()
561 i2c->adapt.nr = pdev->id; in spacemit_i2c_probe()
563 i2c->adapt.dev.of_node = of_node; in spacemit_i2c_probe()
565 strscpy(i2c->adapt.name, "spacemit-i2c-adapter", sizeof(i2c->adapt.name)); in spacemit_i2c_probe()
567 init_completion(&i2c->complete); in spacemit_i2c_probe()
571 ret = i2c_add_numbered_adapter(&i2c->adapt); in spacemit_i2c_probe()
573 return dev_err_probe(&pdev->dev, ret, "failed to add i2c adapter"); in spacemit_i2c_probe()
582 i2c_del_adapter(&i2c->adapt); in spacemit_i2c_remove()
586 { .compatible = "spacemit,k1-i2c", },
595 .name = "i2c-k1",