Skip to content

Commit

Permalink
V4L/DVB (7595): Improve generic support for setting gpio values
Browse files Browse the repository at this point in the history
em28xx based devices with xc3028 may require some specific gpio values.
This patch adds a generic handling for such values.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
  • Loading branch information
Mauro Carvalho Chehab committed Apr 24, 2008
1 parent acaa4b6 commit ee6e3a8
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 77 deletions.
138 changes: 68 additions & 70 deletions drivers/media/video/em28xx/em28xx-cards.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,6 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_SVIDEO,
.amux = 1,
} },

/* gpio's 4, 1, 0 */
.analog_gpio = 0x003d2d,
},
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Hybrid XS",
Expand Down Expand Up @@ -445,73 +442,88 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
};

int em28xx_tuner_callback(void *ptr, int command, int arg)
{
int rc = 0, i;
struct em28xx *dev = ptr;
struct gpio_ctl (*gpio_ctl)[MAX_GPIO];

if (dev->tuner_type != TUNER_XC2028)
return 0;

if (command != XC2028_TUNER_RESET)
return 0;

if (dev->mode == EM28XX_ANALOG_MODE)
gpio_ctl = dev->analog_gpio;
else
gpio_ctl = dev->digital_gpio;

/* Send GPIO reset sequences specified at board entry */
for (i = 0; i < MAX_GPIO; i++) {
if (!gpio_ctl[i]->val)
break;

dev->em28xx_write_regs(dev,
gpio_ctl[i]->reg,
&gpio_ctl[i]->val, 1);
if (gpio_ctl[i]->t1)
msleep(gpio_ctl[i]->t1);

if (!gpio_ctl[i]->rst)
continue;
dev->em28xx_write_regs(dev,
gpio_ctl[i]->reg,
&gpio_ctl[i]->rst, 1);
if (gpio_ctl[i]->t2)
msleep(gpio_ctl[i]->t2);

dev->em28xx_write_regs(dev,
gpio_ctl[i]->reg,
&gpio_ctl[i]->val, 1);
if (gpio_ctl[i]->t3)
msleep(gpio_ctl[i]->t3);
}
return rc;
}
EXPORT_SYMBOL_GPL(em28xx_tuner_callback);

static void em28xx_set_model(struct em28xx *dev)
{
dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
dev->decoder = em28xx_boards[dev->model].decoder;
dev->video_inputs = em28xx_boards[dev->model].vchannels;
dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
dev->has_dvb = em28xx_boards[dev->model].has_dvb;
dev->analog_gpio = &em28xx_boards[dev->model].analog_gpio;
dev->digital_gpio = &em28xx_boards[dev->model].digital_gpio;
}

/* Since em28xx_pre_card_setup() requires a proper dev->model,
* this won't work for boards with generic PCI IDs
*/
void em28xx_pre_card_setup(struct em28xx *dev)
{
em28xx_set_model(dev);

/* request some modules */
switch (dev->model) {
case EM2880_BOARD_TERRATEC_PRODIGY_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_TERRATEC_HYBRID_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
em28xx_write_regs(dev, 0x08, "\xff", 1);
em28xx_write_regs(dev, 0x04, "\x00", 1);
msleep(100);
em28xx_write_regs(dev, 0x04, "\x08", 1);
msleep(100);
em28xx_write_regs(dev, 0x08, "\xff", 1);
msleep(50);
em28xx_write_regs(dev, 0x08, "\x2d", 1);
msleep(50);
em28xx_write_regs(dev, 0x08, "\x3d", 1);
break;
}
}

static int em28xx_tuner_callback(void *ptr, int command, int arg)
{
int rc = 0;
struct em28xx *dev = ptr;

if (dev->tuner_type != TUNER_XC2028)
return 0;

switch (command) {
case XC2028_TUNER_RESET:
{
/* GPIO and initialization codes for analog TV and radio
This code should be complemented for DTV, since reset
codes are different.
*/

dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);

if (dev->analog_gpio) {
char gpio0 = dev->analog_gpio & 0xff;
char gpio1 = (dev->analog_gpio >> 8) & 0xff;
char gpio4 = dev->analog_gpio >> 24;

if (gpio4) {
dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
msleep(140);
}

msleep(6);
dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
msleep(10);
dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
msleep(5);
}

break;
}
}
return rc;
/* Put xc2028 tuners and demods into a sane state */
if (dev->tuner_type == TUNER_XC2028) {
dev->mode = EM28XX_DIGITAL_MODE;
em28xx_tuner_callback(dev, XC2028_TUNER_RESET, 0);
};
}

static void em28xx_config_tuner(struct em28xx *dev)
Expand Down Expand Up @@ -634,20 +646,6 @@ static int em28xx_hint_board(struct em28xx *dev)
return -1;
}


static void em28xx_set_model(struct em28xx *dev)
{
dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
dev->decoder = em28xx_boards[dev->model].decoder;
dev->video_inputs = em28xx_boards[dev->model].vchannels;
dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
dev->has_dvb = em28xx_boards[dev->model].has_dvb;
}

/* ----------------------------------------------------------------------- */
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
{
Expand Down
32 changes: 27 additions & 5 deletions drivers/media/video/em28xx/em28xx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,14 +314,36 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)

int em28xx_capture_start(struct em28xx *dev, int start)
{
int ret;
int rc;
/* FIXME: which is the best order? */
/* video registers are sampled by VREF */
if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
0x10)) < 0)
return ret;
rc = em28xx_write_reg_bits(dev, USBSUSP_REG,
start ? 0x10 : 0x00, 0x10);
if (rc < 0)
return rc;

if (!start) {
/* disable video capture */
rc = em28xx_write_regs(dev, VINENABLE_REG, "\x27", 1);
if (rc < 0)
return rc;
}

/* enable video capture */
return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
if (rc < 0)
return rc;
if (dev->mode == EM28XX_ANALOG_MODE)
rc = em28xx_write_regs(dev, VINENABLE_REG,"\x67", 1);
else
rc = em28xx_write_regs(dev, VINENABLE_REG,"\x37", 1);

if (rc < 0)
return rc;

msleep (6);

return rc;
}

int em28xx_outfmt_set_yuv422(struct em28xx *dev)
Expand Down
23 changes: 21 additions & 2 deletions drivers/media/video/em28xx/em28xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@ enum em28xx_decoder {
EM28XX_SAA7114
};

#define MAX_GPIO 2
struct gpio_ctl {
/* Register to be set */
unsigned char reg;
/* Initial/final value */
unsigned char val;
/* reset value - if set, it will do:
val1 - val2 - val1
*/
unsigned char rst;
/* Sleep times
*/
unsigned int t1, t2, t3;
};

struct em28xx_board {
char *name;
int vchannels;
Expand All @@ -233,7 +248,8 @@ struct em28xx_board {
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;

unsigned int analog_gpio;
struct gpio_ctl analog_gpio[MAX_GPIO];
struct gpio_ctl digital_gpio[MAX_GPIO];

enum em28xx_decoder decoder;

Expand Down Expand Up @@ -293,7 +309,6 @@ struct em28xx {
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
unsigned int analog_gpio;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
unsigned int has_tda9887:1;
Expand All @@ -303,6 +318,9 @@ struct em28xx {
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;

struct gpio_ctl (*analog_gpio)[MAX_GPIO];
struct gpio_ctl (*digital_gpio)[MAX_GPIO];

int video_inputs; /* number of video inputs */
struct list_head devlist;

Expand Down Expand Up @@ -443,6 +461,7 @@ extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
extern const unsigned int em28xx_bcount;
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
int em28xx_tuner_callback(void *ptr, int command, int arg);

/* Provided by em28xx-input.c */
/* TODO: Check if the standard get_key handlers on ir-common can be used */
Expand Down

0 comments on commit ee6e3a8

Please sign in to comment.