Skip to content
Snippets Groups Projects
Commit 948fa171 authored by Wolfgang Denk's avatar Wolfgang Denk
Browse files

Merge branch 'master' of git://git.denx.de/u-boot-i2c

* 'master' of git://git.denx.de/u-boot-i2c

:
  km/common: remove printfs for i2c deblocking code
  CONFIG: SMDK5250: I2C: Enable I2C
  I2C: Add support for Multi channel
  I2C: Modify the I2C driver for EXYNOS5
  I2C: Move struct s3c24x0_i2c to a common place.
  EXYNOS: PINMUX: Add pinmux support for I2C
  EXYNOS5: define EXYNOS5_I2C_SPACING
  EXYNOS: Add I2C base address.
  EXYNOS: CLK: Add i2c clock
  mx6qsabrelite: add i2c multi-bus support
  imx-common: add i2c.c for bus recovery support
  i.mx53: add definition for I2C3_BASE_ADDR
  i.mx: iomux-v3.c: move to imx-common directory
  i.mx: iomux-v3.h: move to imx-common include directory
  iomux-v3: remove include of mx6x_pins.h
  mxc_i2c: finish adding CONFIG_I2C_MULTI_BUS support
  mxc_i2c: add bus recovery support
  mxc_i2c: prep work for multiple busses support
  mxc_i2c: add i2c_regs argument to i2c_imx_stop
  mxc_i2c: add retries
  mxc_i2c: check for arbitration lost
  mxc_i2c: change slave addr if conflicts with destination.
  mxc_i2c: don't disable controller after every transaction
  mxc_i2c: place i2c_reset code inline
  mxc_i2c: place imx_start code inline
  mxc_i2c: remove redundant read
  mxc_i2c: combine i2c_imx_bus_busy and i2c_imx_trx_complete into wait_for_sr_state
  mxc_i2c.c: code i2c_probe as a 0 length i2c_write
  mxc_i2c: call i2c_imx_stop on error in i2c_read/i2c_write
  mxc_i2c: create i2c_init_transfer
  mxc_i2c: clear i2sr before waiting for bit
  mxc_i2c: create tx_byte function
  mxc_i2c: remove ifdef of CONFIG_HARD_I2C
  mxc_i2c: fix i2c_imx_stop
  i2c: deblock i2c bus also if accessed before realocation

Signed-off-by: default avatarWolfgang Denk <wd@denx.de>
parents d978780b e69e482b
No related branches found
No related tags found
No related merge requests found
Showing
with 338 additions and 22 deletions
......@@ -578,6 +578,29 @@ void exynos4_set_mipi_clk(void)
writel(cfg, &clk->div_lcd0);
}
/*
* I2C
*
* exynos5: obtaining the I2C clock
*/
static unsigned long exynos5_get_i2c_clk(void)
{
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
unsigned long aclk_66, aclk_66_pre, sclk;
unsigned int ratio;
sclk = get_pll_clk(MPLL);
ratio = (readl(&clk->div_top1)) >> 24;
ratio &= 0x7;
aclk_66_pre = sclk / (ratio + 1);
ratio = readl(&clk->div_top0);
ratio &= 0x7;
aclk_66 = aclk_66_pre / (ratio + 1);
return aclk_66;
}
unsigned long get_pll_clk(int pllreg)
{
if (cpu_is_exynos5())
......@@ -594,6 +617,16 @@ unsigned long get_arm_clk(void)
return exynos4_get_arm_clk();
}
unsigned long get_i2c_clk(void)
{
if (cpu_is_exynos5()) {
return exynos5_get_i2c_clk();
} else {
debug("I2C clock is not set for this CPU\n");
return 0;
}
}
unsigned long get_pwm_clk(void)
{
if (cpu_is_exynos5())
......
......@@ -184,6 +184,48 @@ static void exynos5_sromc_config(int flags)
}
}
static void exynos5_i2c_config(int peripheral, int flags)
{
struct exynos5_gpio_part1 *gpio1 =
(struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1();
switch (peripheral) {
case PERIPH_ID_I2C0:
s5p_gpio_cfg_pin(&gpio1->b3, 0, GPIO_FUNC(0x2));
s5p_gpio_cfg_pin(&gpio1->b3, 1, GPIO_FUNC(0x2));
break;
case PERIPH_ID_I2C1:
s5p_gpio_cfg_pin(&gpio1->b3, 2, GPIO_FUNC(0x2));
s5p_gpio_cfg_pin(&gpio1->b3, 3, GPIO_FUNC(0x2));
break;
case PERIPH_ID_I2C2:
s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3));
s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3));
break;
case PERIPH_ID_I2C3:
s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3));
s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3));
break;
case PERIPH_ID_I2C4:
s5p_gpio_cfg_pin(&gpio1->a2, 0, GPIO_FUNC(0x3));
s5p_gpio_cfg_pin(&gpio1->a2, 1, GPIO_FUNC(0x3));
break;
case PERIPH_ID_I2C5:
s5p_gpio_cfg_pin(&gpio1->a2, 2, GPIO_FUNC(0x3));
s5p_gpio_cfg_pin(&gpio1->a2, 3, GPIO_FUNC(0x3));
break;
case PERIPH_ID_I2C6:
s5p_gpio_cfg_pin(&gpio1->b1, 3, GPIO_FUNC(0x4));
s5p_gpio_cfg_pin(&gpio1->b1, 4, GPIO_FUNC(0x4));
break;
case PERIPH_ID_I2C7:
s5p_gpio_cfg_pin(&gpio1->b2, 2, GPIO_FUNC(0x3));
s5p_gpio_cfg_pin(&gpio1->b2, 3, GPIO_FUNC(0x3));
break;
}
}
static int exynos5_pinmux_config(int peripheral, int flags)
{
switch (peripheral) {
......@@ -201,6 +243,16 @@ static int exynos5_pinmux_config(int peripheral, int flags)
case PERIPH_ID_SROMC:
exynos5_sromc_config(flags);
break;
case PERIPH_ID_I2C0:
case PERIPH_ID_I2C1:
case PERIPH_ID_I2C2:
case PERIPH_ID_I2C3:
case PERIPH_ID_I2C4:
case PERIPH_ID_I2C5:
case PERIPH_ID_I2C6:
case PERIPH_ID_I2C7:
exynos5_i2c_config(peripheral, flags);
break;
default:
debug("%s: invalid peripheral %d", __func__, peripheral);
return -1;
......
......@@ -27,7 +27,9 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libimx-common.o
COBJS = timer.o cpu.o speed.o
COBJS-y = iomux-v3.o timer.o cpu.o speed.o
COBJS-$(CONFIG_I2C_MXC) += i2c.o
COBJS := $(sort $(COBJS-y))
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
......
/*
* Copyright (C) 2012 Boundary Devices Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/errno.h>
#include <asm/gpio.h>
#include <asm/imx-common/mxc_i2c.h>
#include <watchdog.h>
static int force_idle_bus(void *priv)
{
int i;
int sda, scl;
ulong elapsed, start_time;
struct i2c_pads_info *p = (struct i2c_pads_info *)priv;
int ret = 0;
gpio_direction_input(p->sda.gp);
gpio_direction_input(p->scl.gp);
imx_iomux_v3_setup_pad(p->sda.gpio_mode);
imx_iomux_v3_setup_pad(p->scl.gpio_mode);
sda = gpio_get_value(p->sda.gp);
scl = gpio_get_value(p->scl.gp);
if ((sda & scl) == 1)
goto exit; /* Bus is idle already */
printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__,
sda, scl, p->sda.gp, p->scl.gp);
/* Send high and low on the SCL line */
for (i = 0; i < 9; i++) {
gpio_direction_output(p->scl.gp, 0);
udelay(50);
gpio_direction_input(p->scl.gp);
udelay(50);
}
start_time = get_timer(0);
for (;;) {
sda = gpio_get_value(p->sda.gp);
scl = gpio_get_value(p->scl.gp);
if ((sda & scl) == 1)
break;
WATCHDOG_RESET();
elapsed = get_timer(start_time);
if (elapsed > (CONFIG_SYS_HZ / 5)) { /* .2 seconds */
ret = -EBUSY;
printf("%s: failed to clear bus, sda=%d scl=%d\n",
__func__, sda, scl);
break;
}
}
exit:
imx_iomux_v3_setup_pad(p->sda.i2c_mode);
imx_iomux_v3_setup_pad(p->scl.i2c_mode);
return ret;
}
static void * const i2c_bases[] = {
(void *)I2C1_BASE_ADDR,
(void *)I2C2_BASE_ADDR,
#ifdef I2C3_BASE_ADDR
(void *)I2C3_BASE_ADDR,
#endif
};
/* i2c_index can be from 0 - 2 */
void setup_i2c(unsigned i2c_index, int speed, int slave_addr,
struct i2c_pads_info *p)
{
if (i2c_index >= ARRAY_SIZE(i2c_bases))
return;
/* Enable i2c clock */
enable_i2c_clk(1, i2c_index);
/* Make sure bus is idle */
force_idle_bus(p);
bus_i2c_init(i2c_bases[i2c_index], speed, slave_addr,
force_idle_bus, p);
}
......@@ -23,8 +23,7 @@
#include <common.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/mx6x_pins.h>
#include <asm/arch/iomux-v3.h>
#include <asm/imx-common/iomux-v3.h>
static void *base = (void *)IOMUXC_BASE_ADDR;
......
......@@ -117,6 +117,26 @@ void enable_usboh3_clk(unsigned char enable)
writel(reg, &mxc_ccm->CCGR2);
}
#ifdef CONFIG_I2C_MXC
/* i2c_num can be from 0 - 2 */
int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
{
u32 reg;
u32 mask;
if (i2c_num > 2)
return -EINVAL;
mask = MXC_CCM_CCGR_CG_MASK << ((i2c_num + 9) << 1);
reg = __raw_readl(&mxc_ccm->CCGR1);
if (enable)
reg |= mask;
else
reg &= ~mask;
__raw_writel(reg, &mxc_ccm->CCGR1);
return 0;
}
#endif
void set_usb_phy1_clk(void)
{
unsigned int reg;
......
......@@ -27,7 +27,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).o
COBJS = soc.o clock.o iomux-v3.o
COBJS = soc.o clock.o
SOBJS = lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
......
......@@ -50,6 +50,26 @@ void enable_usboh3_clk(unsigned char enable)
}
#ifdef CONFIG_I2C_MXC
/* i2c_num can be from 0 - 2 */
int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
{
u32 reg;
u32 mask;
if (i2c_num > 2)
return -EINVAL;
mask = MXC_CCM_CCGR_CG_MASK << ((i2c_num + 3) << 1);
reg = __raw_readl(&imx_ccm->CCGR2);
if (enable)
reg |= mask;
else
reg &= ~mask;
__raw_writel(reg, &imx_ccm->CCGR2);
return 0;
}
#endif
static u32 decode_pll(enum pll_clocks pll, u32 infreq)
{
u32 div;
......
......@@ -30,6 +30,7 @@
unsigned long get_pll_clk(int pllreg);
unsigned long get_arm_clk(void);
unsigned long get_i2c_clk(void);
unsigned long get_pwm_clk(void);
unsigned long get_uart_clk(int dev_index);
void set_mmc_clk(int dev_index, unsigned int div);
......
......@@ -49,6 +49,7 @@
#define EXYNOS4_USB_HOST_EHCI_BASE 0x12580000
#define EXYNOS4_USBPHY_BASE 0x125B0000
#define EXYNOS4_UART_BASE 0x13800000
#define EXYNOS4_I2C_BASE 0x13860000
#define EXYNOS4_ADC_BASE 0x13910000
#define EXYNOS4_PWMTIMER_BASE 0x139D0000
#define EXYNOS4_MODEM_BASE 0x13A00000
......@@ -57,6 +58,8 @@
#define EXYNOS4_GPIO_PART4_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS5 */
#define EXYNOS5_I2C_SPACING 0x10000
#define EXYNOS5_GPIO_PART4_BASE 0x03860000
#define EXYNOS5_PRO_ID 0x10000000
#define EXYNOS5_CLOCK_BASE 0x10010000
......@@ -76,6 +79,7 @@
#define EXYNOS5_MMC_BASE 0x12200000
#define EXYNOS5_SROMC_BASE 0x12250000
#define EXYNOS5_UART_BASE 0x12C00000
#define EXYNOS5_I2C_BASE 0x12C60000
#define EXYNOS5_PWMTIMER_BASE 0x12DD0000
#define EXYNOS5_GPIO_PART2_BASE 0x13400000
#define EXYNOS5_FIMD_BASE 0x14400000
......@@ -148,6 +152,7 @@ SAMSUNG_BASE(adc, ADC_BASE)
SAMSUNG_BASE(clock, CLOCK_BASE)
SAMSUNG_BASE(sysreg, SYSREG_BASE)
SAMSUNG_BASE(fimd, FIMD_BASE)
SAMSUNG_BASE(i2c, I2C_BASE)
SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE)
SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE)
SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE)
......
......@@ -30,6 +30,14 @@
*
*/
enum periph_id {
PERIPH_ID_I2C0,
PERIPH_ID_I2C1,
PERIPH_ID_I2C2,
PERIPH_ID_I2C3,
PERIPH_ID_I2C4,
PERIPH_ID_I2C5,
PERIPH_ID_I2C6,
PERIPH_ID_I2C7,
PERIPH_ID_SDMMC0,
PERIPH_ID_SDMMC1,
PERIPH_ID_SDMMC2,
......
......@@ -49,5 +49,6 @@ void enable_usb_phy2_clk(unsigned char enable);
void set_usboh3_clk(void);
void enable_usboh3_clk(unsigned char enable);
void mxc_set_sata_internal_clock(void);
int enable_i2c_clk(unsigned char enable, unsigned i2c_num);
#endif /* __ASM_ARCH_CLOCK_H */
......@@ -96,6 +96,7 @@
#define GPIO5_BASE_ADDR (AIPS1_BASE_ADDR + 0x000DC000)
#define GPIO6_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E0000)
#define GPIO7_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E4000)
#define I2C3_BASE_ADDR (AIPS1_BASE_ADDR + 0x000EC000)
#define UART4_BASE_ADDR (AIPS1_BASE_ADDR + 0x000F0000)
#endif
/*
......
......@@ -48,5 +48,6 @@ u32 imx_get_fecclk(void);
unsigned int mxc_get_clock(enum mxc_clock clk);
void enable_usboh3_clk(unsigned char enable);
int enable_sata_clock(void);
int enable_i2c_clk(unsigned char enable, unsigned i2c_num);
#endif /* __ASM_ARCH_CLOCK_H */
......@@ -22,7 +22,7 @@
#ifndef __ASM_ARCH_MX6_MX6X_PINS_H__
#define __ASM_ARCH_MX6_MX6X_PINS_H__
#include <asm/arch/iomux-v3.h>
#include <asm/imx-common/iomux-v3.h>
/* Use to set PAD control */
#define PAD_CTL_HYS (1 << 16)
......
......@@ -343,16 +343,6 @@ struct s3c24x0_watchdog {
u32 wtcnt;
};
/* IIC (see manual chapter 20) */
struct s3c24x0_i2c {
u32 iiccon;
u32 iicstat;
u32 iicadd;
u32 iicds;
};
/* IIS (see manual chapter 21) */
struct s3c24x0_i2s {
#ifdef __BIG_ENDIAN
......
/*
* Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __ASM_ARCH_MXC_MXC_I2C_H__
#define __ASM_ARCH_MXC_MXC_I2C_H__
#include <asm/imx-common/iomux-v3.h>
struct i2c_pin_ctrl {
iomux_v3_cfg_t i2c_mode;
iomux_v3_cfg_t gpio_mode;
unsigned char gp;
unsigned char spare;
};
struct i2c_pads_info {
struct i2c_pin_ctrl scl;
struct i2c_pin_ctrl sda;
};
void setup_i2c(unsigned i2c_index, int speed, int slave_addr,
struct i2c_pads_info *p);
void bus_i2c_init(void *base, int speed, int slave_addr,
int (*idle_bus_fn)(void *p), void *p);
int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf,
int len);
int bus_i2c_write(void *base, uchar chip, uint addr, int alen,
const uchar *buf, int len);
#endif
......@@ -24,9 +24,9 @@
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/mx6x_pins.h>
#include <asm/arch/iomux-v3.h>
#include <asm/errno.h>
#include <asm/gpio.h>
#include <asm/imx-common/iomux-v3.h>
#include <mmc.h>
#include <fsl_esdhc.h>
#include <miiphy.h>
......
......@@ -22,12 +22,13 @@
#include <common.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/mx6x_pins.h>
#include <asm/arch/iomux-v3.h>
#include <asm/arch/clock.h>
#include <asm/errno.h>
#include <asm/gpio.h>
#include <asm/imx-common/iomux-v3.h>
#include <asm/imx-common/mxc_i2c.h>
#include <mmc.h>
#include <fsl_esdhc.h>
#include <micrel.h>
......@@ -77,9 +78,48 @@ iomux_v3_cfg_t uart2_pads[] = {
MX6Q_PAD_EIM_D27__UART2_RXD | MUX_PAD_CTRL(UART_PAD_CTRL),
};
iomux_v3_cfg_t i2c3_pads[] = {
MX6Q_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(I2C_PAD_CTRL),
MX6Q_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(I2C_PAD_CTRL),
#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
/* I2C1, SGTL5000 */
struct i2c_pads_info i2c_pad_info0 = {
.scl = {
.i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6Q_PAD_EIM_D21__GPIO_3_21 | PC,
.gp = GPIO_NUMBER(3, 21)
},
.sda = {
.i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6Q_PAD_EIM_D28__GPIO_3_28 | PC,
.gp = GPIO_NUMBER(3, 28)
}
};
/* I2C2 Camera, MIPI */
struct i2c_pads_info i2c_pad_info1 = {
.scl = {
.i2c_mode = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6Q_PAD_KEY_COL3__GPIO_4_12 | PC,
.gp = GPIO_NUMBER(4, 12)
},
.sda = {
.i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO_4_13 | PC,
.gp = GPIO_NUMBER(4, 13)
}
};
/* I2C3, J15 - RGB connector */
struct i2c_pads_info i2c_pad_info2 = {
.scl = {
.i2c_mode = MX6Q_PAD_GPIO_5__I2C3_SCL | PC,
.gpio_mode = MX6Q_PAD_GPIO_5__GPIO_1_5 | PC,
.gp = GPIO_NUMBER(1, 5)
},
.sda = {
.i2c_mode = MX6Q_PAD_GPIO_16__I2C3_SDA | PC,
.gpio_mode = MX6Q_PAD_GPIO_16__GPIO_7_11 | PC,
.gp = GPIO_NUMBER(7, 11)
}
};
iomux_v3_cfg_t usdhc3_pads[] = {
......@@ -346,7 +386,9 @@ int board_init(void)
#ifdef CONFIG_MXC_SPI
setup_spi();
#endif
imx_iomux_v3_setup_multiple_pads(i2c3_pads, ARRAY_SIZE(i2c3_pads));
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0);
setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2);
#ifdef CONFIG_CMD_SATA
setup_sata();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment