Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d3c55fd authored by Avinash.H.M's avatar Avinash.H.M Committed by Paul Walmsley
Browse files

OMAP: hwmod: fix the i2c-reset timeout during bootup



The sequence of _ocp_softreset doesn't work for i2c. The i2c module has a
special sequence to reset the module. The sequence is
 - Disable the I2C.
 - Write to SOFTRESET bit.
 - Enable the I2C.
 - Poll on the RESETDONE bit.
The sequence is implemented as a function and the i2c_class is updated with
the correct 'reset' pointer.  omap_hwmod_softreset function is implemented
which triggers the softreset by writing into sysconfig register. On following
this sequence, i2c module resets properly and timeouts are not seen.

Cc: Rajendra Nayak <rnayak@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Signed-off-by: default avatarAvinash.H.M <avinashhm@ti.com>
[paul@pwsan.com: combined this patch with a patch to remove
 HWMOD_INIT_NO_RESET from the 44xx hwmod flags; change register
 offset conditional code to use the IP block revision; minor code
 cleanup]
Signed-off-by: default avatarPaul Walmsley <paul@pwsan.com>
parent 4d4441a6
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
@@ -21,9 +21,19 @@

#include <plat/cpu.h>
#include <plat/i2c.h>
#include <plat/common.h>
#include <plat/omap_hwmod.h>

#include "mux.h"

/* In register I2C_CON, Bit 15 is the I2C enable bit */
#define I2C_EN					BIT(15)
#define OMAP2_I2C_CON_OFFSET			0x24
#define OMAP4_I2C_CON_OFFSET			0xA4

/* Maximum microseconds to wait for OMAP module to softreset */
#define MAX_MODULE_SOFTRESET_WAIT	10000

void __init omap2_i2c_mux_pins(int bus_id)
{
	char mux_name[sizeof("i2c2_scl.i2c2_scl")];
@@ -37,3 +47,61 @@ void __init omap2_i2c_mux_pins(int bus_id)
	sprintf(mux_name, "i2c%i_sda.i2c%i_sda", bus_id, bus_id);
	omap_mux_init_signal(mux_name, OMAP_PIN_INPUT);
}

/**
 * omap_i2c_reset - reset the omap i2c module.
 * @oh: struct omap_hwmod *
 *
 * The i2c moudle in omap2, omap3 had a special sequence to reset. The
 * sequence is:
 * - Disable the I2C.
 * - Write to SOFTRESET bit.
 * - Enable the I2C.
 * - Poll on the RESETDONE bit.
 * The sequence is implemented in below function. This is called for 2420,
 * 2430 and omap3.
 */
int omap_i2c_reset(struct omap_hwmod *oh)
{
	u32 v;
	u16 i2c_con;
	int c = 0;

	if (oh->class->rev == OMAP_I2C_IP_VERSION_2) {
		i2c_con = OMAP4_I2C_CON_OFFSET;
	} else if (oh->class->rev == OMAP_I2C_IP_VERSION_1) {
		i2c_con = OMAP2_I2C_CON_OFFSET;
	} else {
		WARN(1, "Cannot reset I2C block %s: unsupported revision\n",
		     oh->name);
		return -EINVAL;
	}

	/* Disable I2C */
	v = omap_hwmod_read(oh, i2c_con);
	v &= ~I2C_EN;
	omap_hwmod_write(v, oh, i2c_con);

	/* Write to the SOFTRESET bit */
	omap_hwmod_softreset(oh);

	/* Enable I2C */
	v = omap_hwmod_read(oh, i2c_con);
	v |= I2C_EN;
	omap_hwmod_write(v, oh, i2c_con);

	/* Poll on RESETDONE bit */
	omap_test_timeout((omap_hwmod_read(oh,
				oh->class->sysc->syss_offs)
				& SYSS_RESETDONE_MASK),
				MAX_MODULE_SOFTRESET_WAIT, c);

	if (c == MAX_MODULE_SOFTRESET_WAIT)
		pr_warning("%s: %s: softreset failed (waited %d usec)\n",
			__func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
	else
		pr_debug("%s: %s: softreset in %d usec\n", __func__,
			oh->name, c);

	return 0;
}
+27 −0
Original line number Diff line number Diff line
@@ -1655,6 +1655,33 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
		__raw_writel(v, oh->_mpu_rt_va + reg_offs);
}

/**
 * omap_hwmod_softreset - reset a module via SYSCONFIG.SOFTRESET bit
 * @oh: struct omap_hwmod *
 *
 * This is a public function exposed to drivers. Some drivers may need to do
 * some settings before and after resetting the device.  Those drivers after
 * doing the necessary settings could use this function to start a reset by
 * setting the SYSCONFIG.SOFTRESET bit.
 */
int omap_hwmod_softreset(struct omap_hwmod *oh)
{
	u32 v;
	int ret;

	if (!oh || !(oh->_sysc_cache))
		return -EINVAL;

	v = oh->_sysc_cache;
	ret = _set_softreset(oh, &v);
	if (ret)
		goto error;
	_write_sysconfig(v, oh);

error:
	return ret;
}

/**
 * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode
 * @oh: struct omap_hwmod *
+1 −0
Original line number Diff line number Diff line
@@ -1030,6 +1030,7 @@ static struct omap_hwmod_class i2c_class = {
	.name		= "i2c",
	.sysc		= &i2c_sysc,
	.rev		= OMAP_I2C_IP_VERSION_1,
	.reset		= &omap_i2c_reset,
};

static struct omap_i2c_dev_attr i2c_dev_attr = {
+1 −0
Original line number Diff line number Diff line
@@ -1079,6 +1079,7 @@ static struct omap_hwmod_class i2c_class = {
	.name		= "i2c",
	.sysc		= &i2c_sysc,
	.rev		= OMAP_I2C_IP_VERSION_1,
	.reset		= &omap_i2c_reset,
};

static struct omap_i2c_dev_attr i2c_dev_attr = {
+4 −3
Original line number Diff line number Diff line
@@ -1309,6 +1309,7 @@ static struct omap_hwmod_class i2c_class = {
	.name	= "i2c",
	.sysc	= &i2c_sysc,
	.rev	= OMAP_I2C_IP_VERSION_1,
	.reset	= &omap_i2c_reset,
};

static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
Loading