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