uboot/arch/arm/mach-imx/i2c-mxv7.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2012 Boundary Devices Inc.
   4 */
   5#include <common.h>
   6#include <malloc.h>
   7#include <asm/arch/clock.h>
   8#include <asm/arch/imx-regs.h>
   9#include <linux/delay.h>
  10#include <linux/errno.h>
  11#include <asm/gpio.h>
  12#include <asm/mach-imx/mxc_i2c.h>
  13#include <watchdog.h>
  14
  15int force_idle_bus(void *priv)
  16{
  17        int i;
  18        int sda, scl;
  19        ulong elapsed, start_time;
  20        struct i2c_pads_info *p = (struct i2c_pads_info *)priv;
  21        int ret = 0;
  22
  23        gpio_direction_input(p->sda.gp);
  24        gpio_direction_input(p->scl.gp);
  25
  26        imx_iomux_v3_setup_pad(p->sda.gpio_mode);
  27        imx_iomux_v3_setup_pad(p->scl.gpio_mode);
  28
  29        sda = gpio_get_value(p->sda.gp);
  30        scl = gpio_get_value(p->scl.gp);
  31        if ((sda & scl) == 1)
  32                goto exit;              /* Bus is idle already */
  33
  34        printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__,
  35                sda, scl, p->sda.gp, p->scl.gp);
  36        /* Send high and low on the SCL line */
  37        for (i = 0; i < 9; i++) {
  38                gpio_direction_output(p->scl.gp, 0);
  39                udelay(50);
  40                gpio_direction_input(p->scl.gp);
  41                udelay(50);
  42        }
  43        start_time = get_timer(0);
  44        for (;;) {
  45                sda = gpio_get_value(p->sda.gp);
  46                scl = gpio_get_value(p->scl.gp);
  47                if ((sda & scl) == 1)
  48                        break;
  49                WATCHDOG_RESET();
  50                elapsed = get_timer(start_time);
  51                if (elapsed > (CONFIG_SYS_HZ / 5)) {    /* .2 seconds */
  52                        ret = -EBUSY;
  53                        printf("%s: failed to clear bus, sda=%d scl=%d\n",
  54                                        __func__, sda, scl);
  55                        break;
  56                }
  57        }
  58exit:
  59        imx_iomux_v3_setup_pad(p->sda.i2c_mode);
  60        imx_iomux_v3_setup_pad(p->scl.i2c_mode);
  61        return ret;
  62}
  63
  64static void * const i2c_bases[] = {
  65        (void *)I2C1_BASE_ADDR,
  66        (void *)I2C2_BASE_ADDR,
  67#ifdef I2C3_BASE_ADDR
  68        (void *)I2C3_BASE_ADDR,
  69#endif
  70#ifdef I2C4_BASE_ADDR
  71        (void *)I2C4_BASE_ADDR,
  72#endif
  73};
  74
  75/* i2c_index can be from 0 - 3 */
  76int setup_i2c(unsigned i2c_index, int speed, int slave_addr,
  77              struct i2c_pads_info *p)
  78{
  79        char name[9];
  80        int ret;
  81
  82        if (i2c_index >= ARRAY_SIZE(i2c_bases))
  83                return -EINVAL;
  84
  85        snprintf(name, sizeof(name), "i2c_sda%01d", i2c_index);
  86        ret = gpio_request(p->sda.gp, name);
  87        if (ret)
  88                return ret;
  89
  90        snprintf(name, sizeof(name), "i2c_scl%01d", i2c_index);
  91        ret = gpio_request(p->scl.gp, name);
  92        if (ret)
  93                goto err_req;
  94
  95        /* Enable i2c clock */
  96        ret = enable_i2c_clk(1, i2c_index);
  97        if (ret)
  98                goto err_clk;
  99
 100        /* Make sure bus is idle */
 101        ret = force_idle_bus(p);
 102        if (ret)
 103                goto err_idle;
 104
 105#if !CONFIG_IS_ENABLED(DM_I2C)
 106        bus_i2c_init(i2c_index, speed, slave_addr, force_idle_bus, p);
 107#endif
 108
 109        return 0;
 110
 111err_idle:
 112err_clk:
 113        gpio_free(p->scl.gp);
 114err_req:
 115        gpio_free(p->sda.gp);
 116
 117        return ret;
 118}
 119