Commit 8b2f0795 authored by Devin Heitmueller's avatar Devin Heitmueller Committed by Mauro Carvalho Chehab

V4L/DVB (11066): au0828: add support for analog functionality in bridge

Add support for the analog functionality found in the au0828 bridge

Thanks to Michael Krufky <mkrufky@linuxtv.org> and Steven Toth
<stoth@linuxtv.org> for providing sample hardware, engineering level support,
and testing.
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@linuxtv.org>
Signed-off-by: default avatarMichael Krufky <mkrufky@linuxtv.org>
[mchehab@redhat.com: fix compilation by adding linux/version.h]
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 968cf782
au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
......
......@@ -21,6 +21,18 @@
#include "au0828.h"
#include "au0828-cards.h"
#include "au8522.h"
void hvr950q_cs5340_audio(void *priv, int enable)
{
/* Because the HVR-950q shares an i2s bus between the cs5340 and the
au8522, we need to hold cs5340 in reset when using the au8522 */
struct au0828_dev *dev = priv;
if (enable == 1)
au0828_set(dev, REG_000, 0x10);
else
au0828_clear(dev, REG_000, 0x10);
}
struct au0828_board au0828_boards[] = {
[AU0828_BOARD_UNKNOWN] = {
......@@ -31,6 +43,25 @@ struct au0828_board au0828_boards[] = {
},
[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
.name = "Hauppauge HVR950Q",
.input = {
{
.type = AU0828_VMUX_TELEVISION,
.vmux = AU8522_COMPOSITE_CH4_SIF,
.amux = AU8522_AUDIO_SIF,
},
{
.type = AU0828_VMUX_COMPOSITE,
.vmux = AU8522_COMPOSITE_CH1,
.amux = AU8522_AUDIO_NONE,
.audio_setup = hvr950q_cs5340_audio,
},
{
.type = AU0828_VMUX_SVIDEO,
.vmux = AU8522_SVIDEO_CH13,
.amux = AU8522_AUDIO_NONE,
.audio_setup = hvr950q_cs5340_audio,
},
},
},
[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
.name = "Hauppauge HVR950Q rev xxF8",
......@@ -144,21 +175,23 @@ void au0828_gpio_setup(struct au0828_dev *dev)
* 4 - CS5340
* 5 - AU8522 Demodulator
* 6 - eeprom W/P
* 7 - power supply
* 9 - XC5000 Tuner
*/
/* Into reset */
au0828_write(dev, REG_003, 0x02);
au0828_write(dev, REG_002, 0x88 | 0x20);
au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
au0828_write(dev, REG_001, 0x0);
au0828_write(dev, REG_000, 0x0);
msleep(100);
/* Out of reset */
/* Out of reset (leave the cs5340 in reset until needed) */
au0828_write(dev, REG_003, 0x02);
au0828_write(dev, REG_001, 0x02);
au0828_write(dev, REG_002, 0x88 | 0x20);
au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
msleep(250);
break;
case AU0828_BOARD_DVICO_FUSIONHDTV7:
......
......@@ -146,6 +146,8 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
/* Digital TV */
au0828_dvb_unregister(dev);
au0828_analog_unregister(dev);
/* I2C */
au0828_i2c_unregister(dev);
......@@ -162,9 +164,11 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
static int au0828_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
int ifnum;
int ifnum, i;
struct au0828_dev *dev;
struct usb_device *usbdev = interface_to_usbdev(interface);
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
ifnum = interface->altsetting->desc.bInterfaceNumber;
......@@ -189,6 +193,30 @@ static int au0828_usb_probe(struct usb_interface *interface,
usb_set_intfdata(interface, dev);
/* set au0828 usb interface0 to as5 */
usb_set_interface(usbdev,
interface->cur_altsetting->desc.bInterfaceNumber, 5);
/* Figure out which endpoint has the isoc interface */
iface_desc = interface->cur_altsetting;
for(i = 0; i < iface_desc->desc.bNumEndpoints; i++){
endpoint = &iface_desc->endpoint[i].desc;
if(((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)){
/* we find our isoc in endpoint */
u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
dev->max_pkt_size = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
}
}
if(!(dev->isoc_in_endpointaddr)) {
printk("Could not locate isoc endpoint\n");
kfree(dev);
return -ENODEV;
}
/* Power Up the bridge */
au0828_write(dev, REG_600, 1 << 4);
......@@ -201,6 +229,9 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Setup */
au0828_card_setup(dev);
/* Analog TV */
au0828_analog_register(dev);
/* Digital TV */
au0828_dvb_register(dev);
......
......@@ -27,6 +27,9 @@
#define REG_002 0x002
#define REG_003 0x003
#define AU0828_SENSORCTRL_100 0x100
#define AU0828_SENSORCTRL_VBI_103 0x103
#define REG_200 0x200
#define REG_201 0x201
#define REG_202 0x202
......@@ -35,4 +38,7 @@
#define REG_209 0x209
#define REG_2FF 0x2ff
/* Audio registers */
#define AU0828_AUDIOCTRL_50C 0x50C
#define REG_600 0x600
This diff is collapsed.
......@@ -24,6 +24,10 @@
#include <linux/i2c-algo-bit.h>
#include <media/tveeprom.h>
/* Analog */
#include <linux/videodev2.h>
#include <media/videobuf-vmalloc.h>
/* DVB */
#include "demux.h"
#include "dmxdev.h"
......@@ -39,8 +43,48 @@
#define URB_COUNT 16
#define URB_BUFSIZE (0xe522)
/* Analog constants */
#define NTSC_STD_W 720
#define NTSC_STD_H 480
#define AU0828_INTERLACED_DEFAULT 1
#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
/* Defination for AU0828 USB transfer */
#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
#define AU0828_ISO_PACKETS_PER_URB 10
#define AU0828_ISO_MAX_FRAME_SIZE (3 * 1024)
#define AU0828_ISO_BUFFER_SIZE (AU0828_ISO_PACKETS_PER_URB * AU0828_ISO_MAX_FRAME_SIZE)
#define AU0828_MIN_BUF 4
#define AU0828_DEF_BUF 8
#define AU0828_MAX_IMAGES 10
#define AU0828_FRAME_SIZE (1028 * 1024 * 4)
#define AU0828_URB_TIMEOUT msecs_to_jiffies(AU0828_MAX_ISO_BUFS * AU0828_ISO_PACKETS_PER_URB)
#define AU0828_MAX_INPUT 4
enum au0828_itype {
AU0828_VMUX_COMPOSITE = 1,
AU0828_VMUX_SVIDEO,
AU0828_VMUX_CABLE,
AU0828_VMUX_TELEVISION,
AU0828_VMUX_DVB,
AU0828_VMUX_DEBUG
};
struct au0828_input {
enum au0828_itype type;
unsigned int vmux;
unsigned int amux;
void (*audio_setup) (void *priv, int enable);
};
struct au0828_board {
char *name;
struct au0828_input input[AU0828_MAX_INPUT];
};
struct au0828_dvb {
......@@ -55,6 +99,83 @@ struct au0828_dvb {
int feeding;
};
enum au0828_stream_state {
STREAM_OFF,
STREAM_INTERRUPT,
STREAM_ON
};
#define AUVI_INPUT(nr) (&au0828_boards[dev->board].input[nr])
/* device state */
enum au0828_dev_state {
DEV_INITIALIZED = 0x01,
DEV_DISCONNECTED = 0x02,
DEV_MISCONFIGURED = 0x04
};
struct au0828_fh {
struct au0828_dev *dev;
unsigned int stream_on:1; /* Locks streams */
struct videobuf_queue vb_vidq;
enum v4l2_buf_type type;
};
struct au0828_usb_isoc_ctl {
/* max packet size of isoc transaction */
int max_pkt_size;
/* number of allocated urbs */
int num_bufs;
/* urb for isoc transfers */
struct urb **urb;
/* transfer buffers for isoc transfer */
char **transfer_buffer;
/* Last buffer command and region */
u8 cmd;
int pos, size, pktsize;
/* Last field: ODD or EVEN? */
int field;
/* Stores incomplete commands */
u32 tmp_buf;
int tmp_buf_len;
/* Stores already requested buffers */
struct au0828_buffer *buf;
/* Stores the number of received fields */
int nfields;
/* isoc urb callback */
int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
};
/* buffer for one video frame */
struct au0828_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
struct list_head frame;
int top_field;
int receiving;
};
struct au0828_dmaqueue {
struct list_head active;
struct list_head queued;
wait_queue_head_t wq;
/* Counters to control buffer fill */
int pos;
};
struct au0828_dev {
struct mutex mutex;
struct usb_device *usbdev;
......@@ -70,16 +191,49 @@ struct au0828_dev {
/* Digital */
struct au0828_dvb dvb;
/* Analog */
struct list_head au0828list;
int users;
unsigned int stream_on:1; /* Locks streams */
struct video_device *vdev;
struct video_device *vbi_dev;
int width;
int height;
u32 field_size;
u32 frame_size;
u32 bytesperline;
int type;
u8 ctrl_ainput;
__u8 isoc_in_endpointaddr;
u8 isoc_init_ok;
int greenscreen_detected;
unsigned int frame_count;
int ctrl_freq;
int input_type;
unsigned int ctrl_input;
enum au0828_dev_state dev_state;
enum au0828_stream_state stream_state;
wait_queue_head_t open;
struct mutex lock;
/* Isoc control struct */
struct au0828_dmaqueue vidq;
struct au0828_usb_isoc_ctl isoc_ctl;
spinlock_t slock;
/* usb transfer */
int alt; /* alternate */
int max_pkt_size; /* max packet size of isoc transaction */
int num_alt; /* Number of alternative settings */
unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
struct urb *urb[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */
char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
transfer */
/* USB / URB Related */
int urb_streaming;
struct urb *urbs[URB_COUNT];
};
struct au0828_buff {
struct au0828_dev *dev;
struct urb *purb;
struct list_head buff_list;
};
/* ----------------------------------------------------------- */
......@@ -114,6 +268,12 @@ extern int au0828_i2c_unregister(struct au0828_dev *dev);
extern void au0828_call_i2c_clients(struct au0828_dev *dev,
unsigned int cmd, void *arg);
/* ----------------------------------------------------------- */
/* au0828-video.c */
int au0828_analog_register(struct au0828_dev *dev);
int au0828_analog_stream_disable(struct au0828_dev *d);
void au0828_analog_unregister(struct au0828_dev *dev);
/* ----------------------------------------------------------- */
/* au0828-dvb.c */
extern int au0828_dvb_register(struct au0828_dev *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment