Lines Matching +full:num +full:- +full:transfer +full:- +full:bits

1 // SPDX-License-Identifier: GPL-2.0-only
3 * i2c-exynos5.c - Samsung Exynos5 I2C Controller Driver
32 * Special bits are available for both modes of operation to set commands
33 * and for checking transfer status
62 /* I2C_CTL Register bits */
69 /* I2C_FIFO_CTL Register bits */
75 /* I2C_TRAILING_CTL Register bits */
78 /* I2C_INT_EN Register bits */
83 /* I2C_INT_STAT Register bits */
104 /* I2C_FIFO_STAT Register bits */
112 /* I2C_CONF Register bits */
117 /* I2C_AUTO_CONF Register bits */
122 /* I2C_TIMEOUT Register bits */
126 /* I2C_MANUAL_CMD register bits */
130 /* I2C_TRANS_STATUS register bits */
134 /* I2C_TRANS_STATUS register bits for Exynos5 variant */
141 /* I2C_TRANS_STATUS register bits for Exynos7 variant */
159 /* I2C_ADDR register bits */
206 /* Version of HS-I2C Hardware */
211 * struct exynos_hsi2c_variant - platform specific HSI2C driver data
251 .compatible = "samsung,exynos5-hsi2c",
254 .compatible = "samsung,exynos5250-hsi2c",
257 .compatible = "samsung,exynos5260-hsi2c",
260 .compatible = "samsung,exynos7-hsi2c",
263 .compatible = "samsung,exynosautov9-hsi2c",
266 .compatible = "samsung,exynos8895-hsi2c",
274 writel(readl(i2c->regs + HSI2C_INT_STATUS), in exynos5_i2c_clr_pend_irq()
275 i2c->regs + HSI2C_INT_STATUS); in exynos5_i2c_clr_pend_irq()
285 * Returns 0 on success, -EINVAL if the cycle length cannot
300 unsigned int clkin = clk_get_rate(i2c->clk); in exynos5_i2c_set_timing()
301 unsigned int op_clk = hs_timings ? i2c->op_clock : in exynos5_i2c_set_timing()
302 (i2c->op_clock >= I2C_MAX_FAST_MODE_PLUS_FREQ) ? I2C_MAX_STANDARD_MODE_FREQ : in exynos5_i2c_set_timing()
303 i2c->op_clock; in exynos5_i2c_set_timing()
320 if (i2c->variant->hw == I2C_TYPE_EXYNOSAUTOV9) { in exynos5_i2c_set_timing()
321 div = ((clkin / (16 * i2c->op_clock)) - 1); in exynos5_i2c_set_timing()
324 writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); in exynos5_i2c_set_timing()
326 writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3); in exynos5_i2c_set_timing()
346 * 2 * ((FLT_CYCLE + 3) - (FLT_CYCLE + 3) % (CLK_DIV + 1)) in exynos5_i2c_set_timing()
349 * temp := (FPCLK / FI2C) - (FLT_CYCLE + 3) * 2 in exynos5_i2c_set_timing()
357 * ((t_low_min + (scl_clock - t_low_min - t_high_min) / 2) / scl_clock) in exynos5_i2c_set_timing()
368 * Fast-Plus Mode: 0.5us, 0.26us, 1us, 0.62 in exynos5_i2c_set_timing()
371 t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; in exynos5_i2c_set_timing()
372 if (i2c->variant->hw == I2C_TYPE_EXYNOS8895) in exynos5_i2c_set_timing()
373 temp = clkin / op_clk - (t_ftl_cycle + 3) * 2; in exynos5_i2c_set_timing()
374 else if (i2c->variant->hw == I2C_TYPE_EXYNOS7) in exynos5_i2c_set_timing()
375 temp = clkin / op_clk - 8 - t_ftl_cycle; in exynos5_i2c_set_timing()
377 temp = clkin / op_clk - 8 - (t_ftl_cycle * 2); in exynos5_i2c_set_timing()
380 if (i2c->variant->hw == I2C_TYPE_EXYNOS8895) in exynos5_i2c_set_timing()
382 (div + 1) - 2; in exynos5_i2c_set_timing()
384 clk_cycle = temp / (div + 1) - 2; in exynos5_i2c_set_timing()
386 dev_err(i2c->dev, "%s clock set-up failed\n", in exynos5_i2c_set_timing()
388 return -EINVAL; in exynos5_i2c_set_timing()
403 t_scl_h = clk_cycle - t_scl_l; in exynos5_i2c_set_timing()
416 dev_dbg(i2c->dev, "tSTART_SU: %X, tSTART_HD: %X, tSTOP_SU: %X\n", in exynos5_i2c_set_timing()
418 dev_dbg(i2c->dev, "tDATA_SU: %X, tSCL_L: %X, tSCL_H: %X\n", in exynos5_i2c_set_timing()
420 dev_dbg(i2c->dev, "nClkDiv: %X, tSR_RELEASE: %X\n", in exynos5_i2c_set_timing()
422 dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd); in exynos5_i2c_set_timing()
425 writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1); in exynos5_i2c_set_timing()
426 writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2); in exynos5_i2c_set_timing()
427 writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); in exynos5_i2c_set_timing()
429 writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_FS1); in exynos5_i2c_set_timing()
430 writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_FS2); in exynos5_i2c_set_timing()
431 writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3); in exynos5_i2c_set_timing()
433 writel(i2c_timing_sla, i2c->regs + HSI2C_TIMING_SLA); in exynos5_i2c_set_timing()
443 if (ret < 0 || i2c->op_clock < I2C_MAX_FAST_MODE_PLUS_FREQ) in exynos5_hsi2c_clock_setup()
455 u32 i2c_conf = readl(i2c->regs + HSI2C_CONF); in exynos5_i2c_init()
456 u32 i2c_timeout = readl(i2c->regs + HSI2C_TIMEOUT); in exynos5_i2c_init()
460 writel(i2c_timeout, i2c->regs + HSI2C_TIMEOUT); in exynos5_i2c_init()
463 i2c->regs + HSI2C_CTL); in exynos5_i2c_init()
464 writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL); in exynos5_i2c_init()
466 if (i2c->op_clock >= I2C_MAX_FAST_MODE_PLUS_FREQ) { in exynos5_i2c_init()
467 writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)), in exynos5_i2c_init()
468 i2c->regs + HSI2C_ADDR); in exynos5_i2c_init()
472 writel(i2c_conf | HSI2C_AUTO_MODE, i2c->regs + HSI2C_CONF); in exynos5_i2c_init()
480 i2c_ctl = readl(i2c->regs + HSI2C_CTL); in exynos5_i2c_reset()
482 writel(i2c_ctl, i2c->regs + HSI2C_CTL); in exynos5_i2c_reset()
484 i2c_ctl = readl(i2c->regs + HSI2C_CTL); in exynos5_i2c_reset()
486 writel(i2c_ctl, i2c->regs + HSI2C_CTL); in exynos5_i2c_reset()
508 i2c->state = -EINVAL; in exynos5_i2c_irq()
510 spin_lock(&i2c->lock); in exynos5_i2c_irq()
512 int_status = readl(i2c->regs + HSI2C_INT_STATUS); in exynos5_i2c_irq()
513 writel(int_status, i2c->regs + HSI2C_INT_STATUS); in exynos5_i2c_irq()
515 /* handle interrupt related to the transfer status */ in exynos5_i2c_irq()
516 switch (i2c->variant->hw) { in exynos5_i2c_irq()
523 i2c->trans_done = 1; in exynos5_i2c_irq()
524 i2c->state = 0; in exynos5_i2c_irq()
526 dev_dbg(i2c->dev, "Deal with arbitration lose\n"); in exynos5_i2c_irq()
527 i2c->state = -EAGAIN; in exynos5_i2c_irq()
530 dev_dbg(i2c->dev, "No ACK from device\n"); in exynos5_i2c_irq()
531 i2c->state = -ENXIO; in exynos5_i2c_irq()
534 dev_dbg(i2c->dev, "No device\n"); in exynos5_i2c_irq()
535 i2c->state = -ENXIO; in exynos5_i2c_irq()
538 dev_dbg(i2c->dev, "Accessing device timed out\n"); in exynos5_i2c_irq()
539 i2c->state = -ETIMEDOUT; in exynos5_i2c_irq()
548 trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); in exynos5_i2c_irq()
550 dev_dbg(i2c->dev, "No ACK from device\n"); in exynos5_i2c_irq()
551 i2c->state = -ENXIO; in exynos5_i2c_irq()
554 dev_dbg(i2c->dev, "No device\n"); in exynos5_i2c_irq()
555 i2c->state = -ENXIO; in exynos5_i2c_irq()
558 dev_dbg(i2c->dev, "Deal with arbitration lose\n"); in exynos5_i2c_irq()
559 i2c->state = -EAGAIN; in exynos5_i2c_irq()
562 dev_dbg(i2c->dev, "Accessing device timed out\n"); in exynos5_i2c_irq()
563 i2c->state = -ETIMEDOUT; in exynos5_i2c_irq()
566 i2c->trans_done = 1; in exynos5_i2c_irq()
567 i2c->state = 0; in exynos5_i2c_irq()
573 if ((i2c->msg->flags & I2C_M_RD) && (int_status & in exynos5_i2c_irq()
575 fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); in exynos5_i2c_irq()
577 len = min(fifo_level, i2c->msg->len - i2c->msg_ptr); in exynos5_i2c_irq()
581 readl(i2c->regs + HSI2C_RX_DATA); in exynos5_i2c_irq()
582 i2c->msg->buf[i2c->msg_ptr++] = byte; in exynos5_i2c_irq()
583 len--; in exynos5_i2c_irq()
585 i2c->state = 0; in exynos5_i2c_irq()
587 fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); in exynos5_i2c_irq()
590 len = i2c->variant->fifo_depth - fifo_level; in exynos5_i2c_irq()
591 if (len > (i2c->msg->len - i2c->msg_ptr)) { in exynos5_i2c_irq()
592 u32 int_en = readl(i2c->regs + HSI2C_INT_ENABLE); in exynos5_i2c_irq()
595 writel(int_en, i2c->regs + HSI2C_INT_ENABLE); in exynos5_i2c_irq()
596 len = i2c->msg->len - i2c->msg_ptr; in exynos5_i2c_irq()
600 byte = i2c->msg->buf[i2c->msg_ptr++]; in exynos5_i2c_irq()
601 writel(byte, i2c->regs + HSI2C_TX_DATA); in exynos5_i2c_irq()
602 len--; in exynos5_i2c_irq()
604 i2c->state = 0; in exynos5_i2c_irq()
608 if ((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) || in exynos5_i2c_irq()
609 (i2c->state < 0)) { in exynos5_i2c_irq()
610 writel(0, i2c->regs + HSI2C_INT_ENABLE); in exynos5_i2c_irq()
612 complete(&i2c->msg_complete); in exynos5_i2c_irq()
615 spin_unlock(&i2c->lock); in exynos5_i2c_irq()
626 * Returns -EBUSY if the bus cannot be bought to idle
636 trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); in exynos5_i2c_wait_bus_idle()
643 return -EBUSY; in exynos5_i2c_wait_bus_idle()
650 val = readl(i2c->regs + HSI2C_CTL) | HSI2C_RXCHON; in exynos5_i2c_bus_recover()
651 writel(val, i2c->regs + HSI2C_CTL); in exynos5_i2c_bus_recover()
652 val = readl(i2c->regs + HSI2C_CONF) & ~HSI2C_AUTO_MODE; in exynos5_i2c_bus_recover()
653 writel(val, i2c->regs + HSI2C_CONF); in exynos5_i2c_bus_recover()
658 * bits + one pulse for NACK). in exynos5_i2c_bus_recover()
660 writel(HSI2C_CMD_READ_DATA, i2c->regs + HSI2C_MANUAL_CMD); in exynos5_i2c_bus_recover()
662 writel(HSI2C_CMD_SEND_STOP, i2c->regs + HSI2C_MANUAL_CMD); in exynos5_i2c_bus_recover()
665 val = readl(i2c->regs + HSI2C_CTL) & ~HSI2C_RXCHON; in exynos5_i2c_bus_recover()
666 writel(val, i2c->regs + HSI2C_CTL); in exynos5_i2c_bus_recover()
667 val = readl(i2c->regs + HSI2C_CONF) | HSI2C_AUTO_MODE; in exynos5_i2c_bus_recover()
668 writel(val, i2c->regs + HSI2C_CONF); in exynos5_i2c_bus_recover()
675 if (i2c->variant->hw == I2C_TYPE_EXYNOS5) in exynos5_i2c_bus_check()
685 u32 st = readl(i2c->regs + HSI2C_TRANS_STATUS); in exynos5_i2c_bus_check()
700 * stop: Enables stop after transfer if set. Set for last transfer of
717 if (i2c->variant->hw == I2C_TYPE_EXYNOS5) in exynos5_i2c_message_start()
722 i2c_ctl = readl(i2c->regs + HSI2C_CTL); in exynos5_i2c_message_start()
726 if (i2c->msg->flags & I2C_M_RD) { in exynos5_i2c_message_start()
731 trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? in exynos5_i2c_message_start()
732 (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len; in exynos5_i2c_message_start()
740 trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? in exynos5_i2c_message_start()
741 (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len; in exynos5_i2c_message_start()
747 i2c_addr = HSI2C_SLV_ADDR_MAS(i2c->msg->addr); in exynos5_i2c_message_start()
749 if (i2c->op_clock >= I2C_MAX_FAST_MODE_PLUS_FREQ) in exynos5_i2c_message_start()
750 i2c_addr |= HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)); in exynos5_i2c_message_start()
752 writel(i2c_addr, i2c->regs + HSI2C_ADDR); in exynos5_i2c_message_start()
754 writel(fifo_ctl, i2c->regs + HSI2C_FIFO_CTL); in exynos5_i2c_message_start()
755 writel(i2c_ctl, i2c->regs + HSI2C_CTL); in exynos5_i2c_message_start()
760 * Enable interrupts before starting the transfer so that we don't in exynos5_i2c_message_start()
763 spin_lock_irqsave(&i2c->lock, flags); in exynos5_i2c_message_start()
764 writel(int_en, i2c->regs + HSI2C_INT_ENABLE); in exynos5_i2c_message_start()
768 i2c_auto_conf |= i2c->msg->len; in exynos5_i2c_message_start()
770 writel(i2c_auto_conf, i2c->regs + HSI2C_AUTO_CONF); in exynos5_i2c_message_start()
771 spin_unlock_irqrestore(&i2c->lock, flags); in exynos5_i2c_message_start()
780 !((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) || in exynos5_i2c_poll_irqs_timeout()
781 (i2c->state < 0))) { in exynos5_i2c_poll_irqs_timeout()
782 while (readl(i2c->regs + HSI2C_INT_ENABLE) & in exynos5_i2c_poll_irqs_timeout()
783 readl(i2c->regs + HSI2C_INT_STATUS)) in exynos5_i2c_poll_irqs_timeout()
784 exynos5_i2c_irq(i2c->irq, i2c); in exynos5_i2c_poll_irqs_timeout()
796 i2c->msg = msgs; in exynos5_i2c_xfer_msg()
797 i2c->msg_ptr = 0; in exynos5_i2c_xfer_msg()
798 i2c->trans_done = 0; in exynos5_i2c_xfer_msg()
800 reinit_completion(&i2c->msg_complete); in exynos5_i2c_xfer_msg()
804 if (!i2c->atomic) in exynos5_i2c_xfer_msg()
805 time_left = wait_for_completion_timeout(&i2c->msg_complete, in exynos5_i2c_xfer_msg()
812 ret = -ETIMEDOUT; in exynos5_i2c_xfer_msg()
814 ret = i2c->state; in exynos5_i2c_xfer_msg()
825 if (ret == -ETIMEDOUT) in exynos5_i2c_xfer_msg()
826 dev_warn(i2c->dev, "%s timeout\n", in exynos5_i2c_xfer_msg()
827 (msgs->flags & I2C_M_RD) ? "rx" : "tx"); in exynos5_i2c_xfer_msg()
835 struct i2c_msg *msgs, int num) in exynos5_i2c_xfer() argument
837 struct exynos5_i2c *i2c = adap->algo_data; in exynos5_i2c_xfer()
840 ret = clk_enable(i2c->pclk); in exynos5_i2c_xfer()
844 ret = clk_enable(i2c->clk); in exynos5_i2c_xfer()
848 for (i = 0; i < num; ++i) { in exynos5_i2c_xfer()
849 ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num); in exynos5_i2c_xfer()
854 clk_disable(i2c->clk); in exynos5_i2c_xfer()
856 clk_disable(i2c->pclk); in exynos5_i2c_xfer()
858 return ret ?: num; in exynos5_i2c_xfer()
862 struct i2c_msg *msgs, int num) in exynos5_i2c_xfer_atomic() argument
864 struct exynos5_i2c *i2c = adap->algo_data; in exynos5_i2c_xfer_atomic()
867 disable_irq(i2c->irq); in exynos5_i2c_xfer_atomic()
868 i2c->atomic = true; in exynos5_i2c_xfer_atomic()
869 ret = exynos5_i2c_xfer(adap, msgs, num); in exynos5_i2c_xfer_atomic()
870 i2c->atomic = false; in exynos5_i2c_xfer_atomic()
871 enable_irq(i2c->irq); in exynos5_i2c_xfer_atomic()
889 struct device_node *np = pdev->dev.of_node; in exynos5_i2c_probe()
893 i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL); in exynos5_i2c_probe()
895 return -ENOMEM; in exynos5_i2c_probe()
897 if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock)) in exynos5_i2c_probe()
898 i2c->op_clock = I2C_MAX_STANDARD_MODE_FREQ; in exynos5_i2c_probe()
900 strscpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name)); in exynos5_i2c_probe()
901 i2c->adap.owner = THIS_MODULE; in exynos5_i2c_probe()
902 i2c->adap.algo = &exynos5_i2c_algorithm; in exynos5_i2c_probe()
903 i2c->adap.retries = 3; in exynos5_i2c_probe()
905 i2c->dev = &pdev->dev; in exynos5_i2c_probe()
906 i2c->clk = devm_clk_get(&pdev->dev, "hsi2c"); in exynos5_i2c_probe()
907 if (IS_ERR(i2c->clk)) { in exynos5_i2c_probe()
908 dev_err(&pdev->dev, "cannot get clock\n"); in exynos5_i2c_probe()
909 return -ENOENT; in exynos5_i2c_probe()
912 i2c->pclk = devm_clk_get_optional(&pdev->dev, "hsi2c_pclk"); in exynos5_i2c_probe()
913 if (IS_ERR(i2c->pclk)) { in exynos5_i2c_probe()
914 return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), in exynos5_i2c_probe()
918 ret = clk_prepare_enable(i2c->pclk); in exynos5_i2c_probe()
922 ret = clk_prepare_enable(i2c->clk); in exynos5_i2c_probe()
926 i2c->regs = devm_platform_ioremap_resource(pdev, 0); in exynos5_i2c_probe()
927 if (IS_ERR(i2c->regs)) { in exynos5_i2c_probe()
928 ret = PTR_ERR(i2c->regs); in exynos5_i2c_probe()
932 i2c->adap.dev.of_node = np; in exynos5_i2c_probe()
933 i2c->adap.algo_data = i2c; in exynos5_i2c_probe()
934 i2c->adap.dev.parent = &pdev->dev; in exynos5_i2c_probe()
936 /* Clear pending interrupts from u-boot or misc causes */ in exynos5_i2c_probe()
939 spin_lock_init(&i2c->lock); in exynos5_i2c_probe()
940 init_completion(&i2c->msg_complete); in exynos5_i2c_probe()
942 i2c->irq = ret = platform_get_irq(pdev, 0); in exynos5_i2c_probe()
946 ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq, in exynos5_i2c_probe()
947 IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c); in exynos5_i2c_probe()
949 dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", i2c->irq); in exynos5_i2c_probe()
953 i2c->variant = of_device_get_match_data(&pdev->dev); in exynos5_i2c_probe()
961 ret = i2c_add_adapter(&i2c->adap); in exynos5_i2c_probe()
967 clk_disable(i2c->clk); in exynos5_i2c_probe()
968 clk_disable(i2c->pclk); in exynos5_i2c_probe()
973 clk_disable_unprepare(i2c->clk); in exynos5_i2c_probe()
976 clk_disable_unprepare(i2c->pclk); in exynos5_i2c_probe()
984 i2c_del_adapter(&i2c->adap); in exynos5_i2c_remove()
986 clk_unprepare(i2c->clk); in exynos5_i2c_remove()
987 clk_unprepare(i2c->pclk); in exynos5_i2c_remove()
994 i2c_mark_adapter_suspended(&i2c->adap); in exynos5_i2c_suspend_noirq()
995 clk_unprepare(i2c->clk); in exynos5_i2c_suspend_noirq()
996 clk_unprepare(i2c->pclk); in exynos5_i2c_suspend_noirq()
1006 ret = clk_prepare_enable(i2c->pclk); in exynos5_i2c_resume_noirq()
1010 ret = clk_prepare_enable(i2c->clk); in exynos5_i2c_resume_noirq()
1019 clk_disable(i2c->clk); in exynos5_i2c_resume_noirq()
1020 clk_disable(i2c->pclk); in exynos5_i2c_resume_noirq()
1021 i2c_mark_adapter_resumed(&i2c->adap); in exynos5_i2c_resume_noirq()
1026 clk_disable_unprepare(i2c->clk); in exynos5_i2c_resume_noirq()
1028 clk_disable_unprepare(i2c->pclk); in exynos5_i2c_resume_noirq()
1041 .name = "exynos5-hsi2c",
1049 MODULE_DESCRIPTION("Exynos5 HS-I2C Bus driver");