mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-16 11:38:11 +00:00
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: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
08cf7b2ed1
commit
1f09e8a25c
5 changed files with 47 additions and 2 deletions
|
@ -82,6 +82,11 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
|
||||||
},
|
},
|
||||||
.gpio_init.initial_value = 0x3001,
|
.gpio_init.initial_value = 0x3001,
|
||||||
.gpio_init.direction = 0x3001,
|
.gpio_init.direction = 0x3001,
|
||||||
|
.gpio_i2c_slave_reset = {
|
||||||
|
.active_lo_mask = 0x3001,
|
||||||
|
.msecs_asserted = 10,
|
||||||
|
.msecs_recovery = 40,
|
||||||
|
},
|
||||||
.i2c = &cx18_i2c_std,
|
.i2c = &cx18_i2c_std,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -122,6 +127,11 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
|
||||||
},
|
},
|
||||||
.gpio_init.initial_value = 0x3001,
|
.gpio_init.initial_value = 0x3001,
|
||||||
.gpio_init.direction = 0x3001,
|
.gpio_init.direction = 0x3001,
|
||||||
|
.gpio_i2c_slave_reset = {
|
||||||
|
.active_lo_mask = 0x3001,
|
||||||
|
.msecs_asserted = 10,
|
||||||
|
.msecs_recovery = 40,
|
||||||
|
},
|
||||||
.i2c = &cx18_i2c_std,
|
.i2c = &cx18_i2c_std,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,13 @@ struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
|
||||||
u32 initial_value;
|
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 {
|
struct cx18_card_tuner {
|
||||||
v4l2_std_id std; /* standard for which the tuner is suitable */
|
v4l2_std_id std; /* standard for which the tuner is suitable */
|
||||||
int tuner; /* tuner ID (from tuner.h) */
|
int tuner; /* tuner ID (from tuner.h) */
|
||||||
|
@ -114,7 +121,8 @@ struct cx18_card {
|
||||||
|
|
||||||
/* GPIO card-specific settings */
|
/* GPIO card-specific settings */
|
||||||
u8 xceive_pin; /* XCeive tuner GPIO reset pin */
|
u8 xceive_pin; /* XCeive tuner GPIO reset pin */
|
||||||
struct cx18_gpio_init gpio_init;
|
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 tuners[CX18_CARD_MAX_TUNERS];
|
||||||
struct cx18_card_tuner_i2c *i2c;
|
struct cx18_card_tuner_i2c *i2c;
|
||||||
|
|
|
@ -53,10 +53,34 @@ static void gpio_write(struct cx18 *cx)
|
||||||
write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
|
write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
|
||||||
CX18_REG_GPIO_OUT1);
|
CX18_REG_GPIO_OUT1);
|
||||||
write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
|
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);
|
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)
|
void cx18_gpio_init(struct cx18 *cx)
|
||||||
{
|
{
|
||||||
cx->gpio_dir = cx->card->gpio_init.direction;
|
cx->gpio_dir = cx->card->gpio_init.direction;
|
||||||
|
|
|
@ -21,4 +21,5 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void cx18_gpio_init(struct cx18 *cx);
|
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);
|
int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
|
||||||
|
|
|
@ -405,6 +405,8 @@ int init_cx18_i2c(struct cx18 *cx)
|
||||||
cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
|
cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
|
||||||
cx18_setsda(&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]) ||
|
return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
|
||||||
i2c_bit_add_bus(&cx->i2c_adap[1]);
|
i2c_bit_add_bus(&cx->i2c_adap[1]);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue