if (dev->chip_id == CHIP_ID_EM2870 ||
dev->chip_id == CHIP_ID_EM2874 ||
dev->chip_id == CHIP_ID_EM28174 ||
- dev->chip_id == CHIP_ID_EM28178) {
+ dev->chip_id == CHIP_ID_EM28178 ||
+ dev->chip_id == CHIP_ID_EM2828X) {
/* Digital only device - don't load any alsa module */
dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
}
EXPORT_SYMBOL_GPL(em28xx_find_led);
+void em2828X_decoder_vmux(struct em28xx *dev, unsigned int vin)
+{
+ switch (vin) {
+ case EM2828X_TELEVISION:
+ dev_dbg(&dev->intf->dev, "EM2828X_TELEVISION\n");
+ break;
+ case EM2828X_COMPOSITE:
+ dev_dbg(&dev->intf->dev, "EM2828X_COMPOSITE\n");
+ break;
+ default:
+ dev_dbg(&dev->intf->dev, "EM2828X_SVIDEO\n");
+ break;
+ };
+
+ em28xx_write_reg(dev, 0x24, 0x00);
+ em28xx_write_reg(dev, 0x25, 0x02);
+ em28xx_write_reg(dev, 0x2E, 0x00);
+
+ if (vin == EM2828X_TELEVISION) {
+ em28xx_write_reg(dev, 0x7A0B, 0xfc);
+ em28xx_write_reg(dev, 0xB6, 0x8F);
+ em28xx_write_reg(dev, 0xB8, 0x01);
+ } else {
+ em28xx_write_reg(dev, 0x7A0B, 0x00);
+ em28xx_write_reg(dev, 0xB6, 0x8F);
+ em28xx_write_reg(dev, 0xB8, 0x00);
+ }
+
+ em28xx_write_reg(dev, 0x7A1C, 0x1E);
+ em28xx_write_reg(dev, 0x7A1D, 0x99);
+ em28xx_write_reg(dev, 0x7A1E, 0x99);
+ em28xx_write_reg(dev, 0x7A1F, 0x9A);
+ em28xx_write_reg(dev, 0x7A20, 0x3d);
+ em28xx_write_reg(dev, 0x7A21, 0x3e);
+ em28xx_write_reg(dev, 0x7A29, 0x00);
+ em28xx_write_reg(dev, 0x7A2F, 0x52);
+ em28xx_write_reg(dev, 0x7A40, 0x05);
+ em28xx_write_reg(dev, 0x7A51, 0x00);
+ em28xx_write_reg(dev, 0x7AC1, 0x1B);
+
+ if (vin == EM2828X_COMPOSITE || vin == EM2828X_TELEVISION) {
+ em28xx_write_reg(dev, 0x38, 0x01);
+ em28xx_write_reg(dev, 0xB1, 0x70);
+ em28xx_write_reg(dev, 0xB3, 0x00);
+ em28xx_write_reg(dev, 0xB5, 0x00);
+ em28xx_write_reg(dev, 0x7A02, 0x4f);
+ } else { /* EM2828X_SVIDEO */
+ em28xx_write_reg(dev, 0x38, 0x00);
+ em28xx_write_reg(dev, 0xB1, 0x60);
+ em28xx_write_reg(dev, 0xB3, 0x10);
+ em28xx_write_reg(dev, 0xB5, 0x10);
+ em28xx_write_reg(dev, 0x7A02, 0x4e);
+ }
+
+ em28xx_write_reg(dev, 0x7A3F, 0x01);
+ em28xx_write_reg(dev, 0x7A3F, 0x00);
+}
+EXPORT_SYMBOL_GPL(em2828X_decoder_vmux);
+
int em28xx_capture_start(struct em28xx *dev, int start)
{
int rc;
rc = em28xx_write_reg_bits(dev,
EM2874_R5F_TS_ENABLE,
start ? EM2874_TS1_CAPTURE_ENABLE : 0x00,
- EM2874_TS1_CAPTURE_ENABLE | EM2874_TS1_FILTER_ENABLE | EM2874_TS1_NULL_DISCARD);
+ EM2874_TS1_CAPTURE_ENABLE |
+ EM2874_TS1_FILTER_ENABLE |
+ EM2874_TS1_NULL_DISCARD);
else
rc = em28xx_write_reg_bits(dev,
EM2874_R5F_TS_ENABLE,
start ? EM2874_TS2_CAPTURE_ENABLE : 0x00,
- EM2874_TS2_CAPTURE_ENABLE | EM2874_TS2_FILTER_ENABLE | EM2874_TS2_NULL_DISCARD);
+ EM2874_TS2_CAPTURE_ENABLE |
+ EM2874_TS2_FILTER_ENABLE |
+ EM2874_TS2_NULL_DISCARD);
} else {
/* FIXME: which is the best order? */
/* video registers are sampled by VREF */
if (dev->is_webcam)
rc = em28xx_write_reg(dev, 0x13, 0x0c);
- /* Enable video capture */
- rc = em28xx_write_reg(dev, 0x48, 0x00);
- if (rc < 0)
- return rc;
+ if (dev->mode == EM28XX_ANALOG_MODE) {
+ /* Enable video capture */
+ rc = em28xx_write_reg(dev, 0x48, 0x00);
+ if (rc < 0)
+ return rc;
- if (dev->mode == EM28XX_ANALOG_MODE)
rc = em28xx_write_reg(dev,
EM28XX_R12_VINENABLE,
0x67);
- else
- rc = em28xx_write_reg(dev,
- EM28XX_R12_VINENABLE,
- 0x37);
+
+ } else if (dev->chip_id == CHIP_ID_EM2828X) {
+ /* The Transport Stream Enable Register moved in em2874 */
+ if (dev->dvb_xfer_bulk) {
+ /* Max Tx Size = 188 * 256 = 48128 - LCM(188,512) * 2 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ 0xff);
+ } else {
+ /* ISOC Maximum Transfer Size = 188 * 5 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ dev->dvb_max_pkt_size_isoc / 188);
+ }
+
+ if (dev->ts == PRIMARY_TS)
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS1_CAPTURE_ENABLE : 0x00,
+ EM2874_TS1_CAPTURE_ENABLE |
+ EM2874_TS1_FILTER_ENABLE |
+ EM2874_TS1_NULL_DISCARD);
+ else
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS2_CAPTURE_ENABLE : 0x00,
+ EM2874_TS2_CAPTURE_ENABLE |
+ EM2874_TS2_FILTER_ENABLE |
+ EM2874_TS2_NULL_DISCARD);
+ } else {
+ /* Enable video capture */
+ rc = em28xx_write_reg(dev, 0x48, 0x00);
+ if (rc < 0)
+ return rc;
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+ }
+
if (rc < 0)
return rc;
usleep_range(10000, 11000);
} else {
- /* disable video capture */
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
+ if (dev->mode == EM28XX_DIGITAL_MODE && dev->chip_id == CHIP_ID_EM2828X) {
+ /* The Transport Stream Enable Register moved in em2874 */
+ if (dev->dvb_xfer_bulk) {
+ /* Max Tx Size = 188 * 256 = 48128 - LCM(188,512) * 2 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ 0xff);
+ } else {
+ /* ISOC Maximum Transfer Size = 188 * 5 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ dev->dvb_max_pkt_size_isoc / 188);
+ }
+
+ if (dev->ts == PRIMARY_TS)
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS1_CAPTURE_ENABLE : 0x00,
+ EM2874_TS1_CAPTURE_ENABLE |
+ EM2874_TS1_FILTER_ENABLE |
+ EM2874_TS1_NULL_DISCARD);
+ else
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS2_CAPTURE_ENABLE : 0x00,
+ EM2874_TS2_CAPTURE_ENABLE |
+ EM2874_TS2_FILTER_ENABLE |
+ EM2874_TS2_NULL_DISCARD);
+ } else {
+ /* disable video capture */
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
+ }
}
}
/* FIXME: check subdevices for VBI support */
if (dev->chip_id == CHIP_ID_EM2860 ||
- dev->chip_id == CHIP_ID_EM2883)
+ dev->chip_id == CHIP_ID_EM2883 ||
+ dev->board.decoder == EM28XX_BUILTIN)
return 1;
/* Version of em28xx that does not support VBI */
return 0;
}
+static int em28xx_analogtv_supported(struct em28xx *dev)
+{
+ return 0;
+}
+
/*
* em28xx_wake_i2c()
* configure i2c attached devices
return em28xx_scaler_set(dev, v4l2->hscale, v4l2->vscale);
}
+static void em2828X_decoder_set_std(struct em28xx *dev, v4l2_std_id norm)
+{
+ if (norm & V4L2_STD_525_60) {
+ dev_dbg(&dev->intf->dev, "V4L2_STD_525_60");
+ em28xx_write_reg(dev, 0x7A01, 0x0d); // 0x05
+ em28xx_write_reg(dev, 0x7A04, 0xDD);
+ em28xx_write_reg(dev, 0x7A07, 0x60);
+ em28xx_write_reg(dev, 0x7A08, 0x7A);
+ em28xx_write_reg(dev, 0x7A09, 0x02);
+ em28xx_write_reg(dev, 0x7A0A, 0x7C);
+ em28xx_write_reg(dev, 0x7A0C, 0x8A);
+ em28xx_write_reg(dev, 0x7A0F, 0x1C);
+ em28xx_write_reg(dev, 0x7A18, 0x20);
+ em28xx_write_reg(dev, 0x7A19, 0x74);
+ em28xx_write_reg(dev, 0x7A1A, 0x5D);
+ em28xx_write_reg(dev, 0x7A1B, 0x17);
+ em28xx_write_reg(dev, 0x7A2E, 0x85);
+ em28xx_write_reg(dev, 0x7A31, 0x63);
+ em28xx_write_reg(dev, 0x7A82, 0x42);
+ em28xx_write_reg(dev, 0x7AC0, 0xD4);
+
+ if (INPUT(dev->ctl_input)->vmux == EM2828X_COMPOSITE) {
+ em28xx_write_reg(dev, 0x7A00, 0x00);
+ em28xx_write_reg(dev, 0x7A03, 0x00);
+ em28xx_write_reg(dev, 0x7A30, 0x22);
+ em28xx_write_reg(dev, 0x7A80, 0x03);
+ } else if (INPUT(dev->ctl_input)->vmux == EM2828X_TELEVISION) {
+ em28xx_write_reg(dev, 0x7A17, 0xc3);
+ em28xx_write_reg(dev, 0x7A31, 0x62); // BRL 0x63
+ em28xx_write_reg(dev, 0x7A82, 0x42);
+ em28xx_write_reg(dev, 0x7AC0, 0xD4);
+ em28xx_write_reg(dev, 0x7A00, 0x00);
+ em28xx_write_reg(dev, 0x7A03, 0x00);
+ em28xx_write_reg(dev, 0x7A30, 0x20);
+ em28xx_write_reg(dev, 0x7A80, 0x00);
+
+ em28xx_write_reg(dev, 0x7A50, 0xdd);
+ em28xx_write_reg(dev, 0x7A5d, 0x0e);
+ em28xx_write_reg(dev, 0x7A5e, 0xea);
+ em28xx_write_reg(dev, 0x7A60, 0x64);
+ em28xx_write_reg(dev, 0x7A67, 0x5a);
+ } else {
+ em28xx_write_reg(dev, 0x7A00, 0x01);
+ em28xx_write_reg(dev, 0x7A03, 0x03);
+ em28xx_write_reg(dev, 0x7A30, 0x20);
+ em28xx_write_reg(dev, 0x7A80, 0x04);
+ }
+ } else if (norm & V4L2_STD_625_50) {
+ dev_dbg(&dev->intf->dev, "V4L2_STD_625_50");
+ em28xx_write_reg(dev, 0x7A04, 0xDC);
+ em28xx_write_reg(dev, 0x7A0C, 0x67);
+ em28xx_write_reg(dev, 0x7A0F, 0x1C);
+ em28xx_write_reg(dev, 0x7A18, 0x28);
+ em28xx_write_reg(dev, 0x7A19, 0x32);
+ em28xx_write_reg(dev, 0x7A1A, 0xB9);
+ em28xx_write_reg(dev, 0x7A1B, 0x86);
+ em28xx_write_reg(dev, 0x7A31, 0xC3);
+ em28xx_write_reg(dev, 0x7A82, 0x52);
+
+ if (INPUT(dev->ctl_input)->vmux == EM2828X_COMPOSITE) {
+ em28xx_write_reg(dev, 0x7A00, 0x32);
+ em28xx_write_reg(dev, 0x7A01, 0x10);
+ em28xx_write_reg(dev, 0x7A03, 0x06);
+ em28xx_write_reg(dev, 0x7A07, 0x2f);
+ em28xx_write_reg(dev, 0x7A08, 0x77);
+ em28xx_write_reg(dev, 0x7A09, 0x0f);
+ em28xx_write_reg(dev, 0x7A0A, 0x8c);
+ em28xx_write_reg(dev, 0x7A20, 0x3d);
+ em28xx_write_reg(dev, 0x7A2E, 0x88);
+ em28xx_write_reg(dev, 0x7A30, 0x2c);
+ em28xx_write_reg(dev, 0x7A80, 0x07);
+ } else if (INPUT(dev->ctl_input)->vmux == EM2828X_TELEVISION) {
+ em28xx_write_reg(dev, 0x7A00, 0x32);
+ em28xx_write_reg(dev, 0x7A03, 0x09);
+ em28xx_write_reg(dev, 0x7A30, 0x2a);
+ em28xx_write_reg(dev, 0x7A80, 0x03);
+ em28xx_write_reg(dev, 0x7A20, 0x35);
+ em28xx_write_reg(dev, 0x7A2e, 0x88);
+ em28xx_write_reg(dev, 0x7A53, 0xcc);
+ em28xx_write_reg(dev, 0x7A5d, 0x16);
+ em28xx_write_reg(dev, 0x7A5e, 0x50);
+ em28xx_write_reg(dev, 0x7A60, 0xb4);
+ em28xx_write_reg(dev, 0x7A67, 0x64);
+ } else {
+ em28xx_write_reg(dev, 0x7A00, 0x33);
+ em28xx_write_reg(dev, 0x7A01, 0x04);
+ em28xx_write_reg(dev, 0x7A03, 0x04);
+ em28xx_write_reg(dev, 0x7A07, 0x20);
+ em28xx_write_reg(dev, 0x7A08, 0x6a);
+ em28xx_write_reg(dev, 0x7A09, 0x16);
+ em28xx_write_reg(dev, 0x7A0A, 0x80);
+ em28xx_write_reg(dev, 0x7A2E, 0x8a);
+ em28xx_write_reg(dev, 0x7A30, 0x26);
+ em28xx_write_reg(dev, 0x7A80, 0x08);
+ }
+ } else {
+ dev_err(&dev->intf->dev, "%s() Unsupported STD: %X", __func__, (unsigned int)norm);
+ }
+
+ em28xx_write_reg(dev, 0x7A3F, 0x01);
+ em28xx_write_reg(dev, 0x7A3F, 0x00);
+}
+
/* Set USB alternate setting for analog video */
static int em28xx_set_alternate(struct em28xx *dev)
{
#ifdef CONFIG_MEDIA_CONTROLLER
int i;
+ if (dev->board.decoder == EM28XX_BUILTIN) {
+ media_device_unregister_entity(dev->v4l2->decoder);
+ kfree(dev->v4l2->decoder);
+ dev->v4l2->decoder = NULL;
+ }
+
for (i = 0; i < MAX_EM28XX_INPUT; i++) {
if (!INPUT(i)->type)
return;
ent->function = MEDIA_ENT_F_CONN_SVIDEO;
break;
default: /* EM28XX_VMUX_TELEVISION or EM28XX_RADIO */
- if (dev->tuner_type != TUNER_ABSENT)
+ if (dev->tuner_type != TUNER_ABSENT || em28xx_analogtv_supported(dev))
ent->function = MEDIA_ENT_F_CONN_RF;
break;
}
dev_err(&dev->intf->dev,
"failed to register input entity %d!\n", i);
}
+
+ if (dev->board.decoder == EM28XX_BUILTIN) {
+ v4l2->decoder_pads[EM2828X_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
+ v4l2->decoder_pads[EM2828X_PAD_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ v4l2->decoder_pads[EM2828X_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ v4l2->decoder_pads[EM2828X_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
+
+ v4l2->decoder = kzalloc_obj(*v4l2->decoder);
+ v4l2->decoder->name = "em2828x_builtin";
+ v4l2->decoder->function = MEDIA_ENT_F_ATV_DECODER;
+
+ ret = media_entity_pads_init(v4l2->decoder, EM2828X_NUM_PADS,
+ &v4l2->decoder_pads[0]);
+ if (ret < 0)
+ dev_err(&dev->intf->dev, "failed to initialize decoder pads %d!\n", ret);
+
+ ret = media_device_register_entity(dev->media_dev, v4l2->decoder);
+ if (ret < 0)
+ dev_err(&dev->intf->dev, "failed to register decoder entity %d!\n", ret);
+ }
+
#endif
}
MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
}
+ if (dev->board.decoder == EM28XX_BUILTIN) {
+ em2828X_decoder_vmux(dev, INPUT(index)->vmux);
+ em2828X_decoder_set_std(dev, dev->v4l2->norm);
+
+ em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+ }
+
if (dev->board.adecoder != EM28XX_NOADECODER) {
v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
dev->ctl_ainput, dev->ctl_aoutput, 0);
em28xx_resolution_set(dev);
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
+ if (dev->board.decoder == EM28XX_BUILTIN)
+ em2828X_decoder_set_std(dev, v4l2->norm);
+
return 0;
}
strscpy(t->name, "Tuner", sizeof(t->name));
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
+ t->signal = 0xffff; /* LOCKED */
+
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
return 0;
}
V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
cap->capabilities |= V4L2_CAP_AUDIO;
- if (dev->tuner_type != TUNER_ABSENT)
+ if (dev->tuner_type != TUNER_ABSENT || em28xx_analogtv_supported(dev))
cap->capabilities |= V4L2_CAP_TUNER;
if (video_is_registered(&v4l2->vbi_dev))
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
}
hdl = &v4l2->ctrl_handler;
- v4l2_ctrl_handler_init(hdl, 8);
+ v4l2_ctrl_handler_init(hdl, 9);
v4l2->v4l2_dev.ctrl_handler = hdl;
if (dev->is_webcam)
}
/* set default norm */
- v4l2->norm = V4L2_STD_PAL;
+ v4l2->norm = -1;
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
v4l2->interlaced_fieldmode = EM28XX_INTERLACED_DEFAULT;
V4L2_CAP_STREAMING;
if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
v4l2->vdev.device_caps |= V4L2_CAP_AUDIO;
- if (dev->tuner_type != TUNER_ABSENT)
+ if (dev->tuner_type != TUNER_ABSENT || em28xx_analogtv_supported(dev))
v4l2->vdev.device_caps |= V4L2_CAP_TUNER;
-
/* disable inapplicable ioctls */
if (dev->is_webcam) {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD);
} else {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_PARM);
}
- if (dev->tuner_type == TUNER_ABSENT) {
+ if ((v4l2->vdev.device_caps & V4L2_CAP_TUNER) == 0) {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_AUDIO);
}
+ if (dev->chip_id == CHIP_ID_EM2828X || dev->board.decoder == EM28XX_BUILTIN)
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_ENUM_FRAMESIZES);
+
/* register v4l2 video video_device */
ret = video_register_device(&v4l2->vdev, VFL_TYPE_VIDEO,
video_nr[dev->devno]);
v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock;
v4l2->vbi_dev.device_caps = V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
- if (dev->tuner_type != TUNER_ABSENT)
+ if ((v4l2->vdev.device_caps & V4L2_CAP_TUNER) == 0)
v4l2->vbi_dev.device_caps |= V4L2_CAP_TUNER;
/* disable inapplicable ioctls */
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM);
- if (dev->tuner_type == TUNER_ABSENT) {
+ if ((v4l2->vbi_dev.device_caps & V4L2_CAP_TUNER) == 0) {
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_FREQUENCY);