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

Commit 1f09e8a2 authored by Andy Walls's avatar Andy Walls Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (8068): cx18: Add I2C slave reset via GPIO upon initialization



cx18: Add I2C slave reset via GPIO upon initialization.  One user,
Michael <msd4824@yahoo.com>, has reported this allows his HVR-1600 EEPROM to
be consistently recognized when using (long,) 100 msec delays.   The delays in
this commit are nominal (10 & 40 msec) and need testing/tuning on boards with
I2C problems to find the right values.

Signed-off-by: default avatarAndy Walls <awalls@radix.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 08cf7b2e
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -82,6 +82,11 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
	},
	.gpio_init.initial_value = 0x3001,
	.gpio_init.direction = 0x3001,
	.gpio_i2c_slave_reset = {
		.active_lo_mask = 0x3001,
		.msecs_asserted = 10,
		.msecs_recovery = 40,
	},
	.i2c = &cx18_i2c_std,
};

@@ -122,6 +127,11 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
	},
	.gpio_init.initial_value = 0x3001,
	.gpio_init.direction = 0x3001,
	.gpio_i2c_slave_reset = {
		.active_lo_mask = 0x3001,
		.msecs_asserted = 10,
		.msecs_recovery = 40,
	},
	.i2c = &cx18_i2c_std,
};

+9 −1
Original line number Diff line number Diff line
@@ -78,6 +78,13 @@ struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
	u32 initial_value;
};

struct cx18_gpio_i2c_slave_reset {
	u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */
	u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
	int msecs_asserted; /* time period reset must remain asserted */
	int msecs_recovery; /* time after deassert for chips to be ready */
};

struct cx18_card_tuner {
	v4l2_std_id std; 	/* standard for which the tuner is suitable */
	int 	    tuner; 	/* tuner ID (from tuner.h) */
@@ -115,6 +122,7 @@ struct cx18_card {
	/* GPIO card-specific settings */
	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
	struct cx18_gpio_init 		 gpio_init;
	struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;

	struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
	struct cx18_card_tuner_i2c *i2c;
+25 −1
Original line number Diff line number Diff line
@@ -53,10 +53,34 @@ static void gpio_write(struct cx18 *cx)
	write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
			CX18_REG_GPIO_OUT1);
	write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
	write_reg((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
	write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
			CX18_REG_GPIO_OUT2);
}

void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
{
	const struct cx18_gpio_i2c_slave_reset *p;

	p = &cx->card->gpio_i2c_slave_reset;

	if ((p->active_lo_mask | p->active_hi_mask) == 0)
		return;

	/* Assuming that the masks are a subset of the bits in gpio_dir */

	/* Assert */
	cx->gpio_val =
		(cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
	gpio_write(cx);
	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));

	/* Deassert */
	cx->gpio_val =
		(cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
	gpio_write(cx);
	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
}

void cx18_gpio_init(struct cx18 *cx)
{
	cx->gpio_dir = cx->card->gpio_init.direction;
+1 −0
Original line number Diff line number Diff line
@@ -21,4 +21,5 @@
 */

void cx18_gpio_init(struct cx18 *cx);
void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
+2 −0
Original line number Diff line number Diff line
@@ -405,6 +405,8 @@ int init_cx18_i2c(struct cx18 *cx)
	cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
	cx18_setsda(&cx->i2c_algo_cb_data[1], 1);

	cx18_reset_i2c_slaves_gpio(cx);

	return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
		i2c_bit_add_bus(&cx->i2c_adap[1]);
}