Commit 3ded3743 authored by Wolfram Sang's avatar Wolfram Sang Committed by Wolfram Sang
Browse files

i2c: sh_mobile: add errata workaround



This used to be in platform init code. We want it to do in the driver
now. This is basically a code move and a new compatible added.

Signed-off-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Acked-by: default avatarSimon Horman <horms+renesas@verge.net.au>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent f30dc520
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -150,6 +150,7 @@ struct sh_mobile_i2c_data {

struct sh_mobile_dt_config {
	int clks_per_count;
	void (*setup)(struct sh_mobile_i2c_data *pd);
};

#define IIC_FLAG_HAS_ICIC67	(1 << 0)
@@ -164,6 +165,7 @@ struct sh_mobile_dt_config {
#define ICIC			0x0c
#define ICCL			0x10
#define ICCH			0x14
#define ICSTART			0x70

/* Register bits */
#define ICCR_ICE		0x80
@@ -190,6 +192,8 @@ struct sh_mobile_dt_config {
#define ICIC_WAITE		0x02
#define ICIC_DTEE		0x01

#define ICSTART_ICSTART		0x10

static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data)
{
	if (offs == ICIC)
@@ -782,6 +786,33 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = {
	.master_xfer	= sh_mobile_i2c_xfer,
};

/*
 * r8a7740 chip has lasting errata on I2C I/O pad reset.
 * this is work-around for it.
 */
static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
{
	iic_set_clr(pd, ICCR, ICCR_ICE, 0);
	iic_rd(pd, ICCR); /* dummy read */

	iic_set_clr(pd, ICSTART, ICSTART_ICSTART, 0);
	iic_rd(pd, ICSTART); /* dummy read */

	udelay(10);

	iic_wr(pd, ICCR, ICCR_SCP);
	iic_wr(pd, ICSTART, 0);

	udelay(10);

	iic_wr(pd, ICCR, ICCR_TRS);
	udelay(10);
	iic_wr(pd, ICCR, 0);
	udelay(10);
	iic_wr(pd, ICCR, ICCR_TRS);
	udelay(10);
}

static const struct sh_mobile_dt_config default_dt_config = {
	.clks_per_count = 1,
};
@@ -790,9 +821,15 @@ static const struct sh_mobile_dt_config fast_clock_dt_config = {
	.clks_per_count = 2,
};

static const struct sh_mobile_dt_config r8a7740_dt_config = {
	.clks_per_count = 1,
	.setup = sh_mobile_i2c_r8a7740_workaround,
};

static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
	{ .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
	{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
	{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
	{ .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config },
	{ .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
	{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
@@ -885,6 +922,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)

			config = match->data;
			pd->clks_per_count = config->clks_per_count;

			if (config->setup)
				config->setup(pd);
		}
	} else {
		if (pdata && pdata->bus_speed)