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                schedule();
  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#ifdef I2C5_BASE_ADDR
  74        (void *)I2C5_BASE_ADDR,
  75#endif
  76#ifdef I2C6_BASE_ADDR
  77        (void *)I2C6_BASE_ADDR,
  78#endif
  79};
  80
  81/* i2c_index can be from 0 - 3 */
  82int setup_i2c(unsigned i2c_index, int speed, int slave_addr,
  83              struct i2c_pads_info *p)
  84{
  85        char name[9];
  86        int ret;
  87
  88        if (i2c_index >= ARRAY_SIZE(i2c_bases))
  89                return -EINVAL;
  90
  91        snprintf(name, sizeof(name), "i2c_sda%01d", i2c_index);
  92        ret = gpio_request(p->sda.gp, name);
  93        if (ret)
  94                return ret;
  95
  96        snprintf(name, sizeof(name), "i2c_scl%01d", i2c_index);
  97        ret = gpio_request(p->scl.gp, name);
  98        if (ret)
  99                goto err_req;
 100
 101        /* Enable i2c clock */
 102        ret = enable_i2c_clk(1, i2c_index);
 103        if (ret)
 104                goto err_clk;
 105
 106        /* Make sure bus is idle */
 107        ret = force_idle_bus(p);
 108        if (ret)
 109                goto err_idle;
 110
 111#if !CONFIG_IS_ENABLED(DM_I2C)
 112        bus_i2c_init(i2c_index, speed, slave_addr, force_idle_bus, p);
 113#endif
 114
 115        return 0;
 116
 117err_idle:
 118err_clk:
 119        gpio_free(p->scl.gp);
 120err_req:
 121        gpio_free(p->sda.gp);
 122
 123        return ret;
 124}
 125