diff options
| -rw-r--r-- | arch/arm/cpu/armv7/imx-common/Makefile | 4 | ||||
| -rw-r--r-- | arch/arm/cpu/armv7/imx-common/i2c.c | 99 | ||||
| -rw-r--r-- | arch/arm/cpu/armv7/mx5/clock.c | 20 | ||||
| -rw-r--r-- | arch/arm/cpu/armv7/mx6/clock.c | 20 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-mx5/clock.h | 1 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-mx6/clock.h | 1 | ||||
| -rw-r--r-- | arch/arm/include/asm/imx-common/mxc_i2c.h | 42 | 
7 files changed, 186 insertions, 1 deletions
| diff --git a/arch/arm/cpu/armv7/imx-common/Makefile b/arch/arm/cpu/armv7/imx-common/Makefile index 53296fa23..bf36be576 100644 --- a/arch/arm/cpu/armv7/imx-common/Makefile +++ b/arch/arm/cpu/armv7/imx-common/Makefile @@ -27,7 +27,9 @@ include $(TOPDIR)/config.mk  LIB     = $(obj)libimx-common.o -COBJS	= iomux-v3.o 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)) diff --git a/arch/arm/cpu/armv7/imx-common/i2c.c b/arch/arm/cpu/armv7/imx-common/i2c.c new file mode 100644 index 000000000..da2b26f43 --- /dev/null +++ b/arch/arm/cpu/armv7/imx-common/i2c.c @@ -0,0 +1,99 @@ +/* + * 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); +} diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c index 64862b31f..c67c3cfc4 100644 --- a/arch/arm/cpu/armv7/mx5/clock.c +++ b/arch/arm/cpu/armv7/mx5/clock.c @@ -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; diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 52d5dc4d9..fddb3733a 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.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; diff --git a/arch/arm/include/asm/arch-mx5/clock.h b/arch/arm/include/asm/arch-mx5/clock.h index 35ee8155d..36ea03082 100644 --- a/arch/arm/include/asm/arch-mx5/clock.h +++ b/arch/arm/include/asm/arch-mx5/clock.h @@ -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 */ diff --git a/arch/arm/include/asm/arch-mx6/clock.h b/arch/arm/include/asm/arch-mx6/clock.h index b91d8bf45..c55c18d51 100644 --- a/arch/arm/include/asm/arch-mx6/clock.h +++ b/arch/arm/include/asm/arch-mx6/clock.h @@ -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 */ diff --git a/arch/arm/include/asm/imx-common/mxc_i2c.h b/arch/arm/include/asm/imx-common/mxc_i2c.h new file mode 100644 index 000000000..9a5187d46 --- /dev/null +++ b/arch/arm/include/asm/imx-common/mxc_i2c.h @@ -0,0 +1,42 @@ +/* + * 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 |