diff options
Diffstat (limited to 'linux/drivers')
-rw-r--r-- | linux/drivers/media/video/Kconfig | 9 | ||||
-rw-r--r-- | linux/drivers/media/video/Makefile | 1 | ||||
-rw-r--r-- | linux/drivers/media/video/cx25840/cx25840-core.c | 4 | ||||
-rw-r--r-- | linux/drivers/media/video/cx25840/cx25840-core.h | 1 | ||||
-rw-r--r-- | linux/drivers/media/video/cx25840/cx25840-vbi.c | 24 | ||||
-rw-r--r-- | linux/drivers/media/video/tlv320aic23b.c | 250 |
6 files changed, 284 insertions, 5 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index e7cc79c6e..134af1cad 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -363,6 +363,15 @@ config VIDEO_CS53L32A To compile this driver as a module, choose M here: the module will be called cs53l32a. +config VIDEO_TLV320AIC23B + tristate "Texas Instruments TLV320AIC23B audio codec" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + ---help--- + Support for the Texas Instruments TLV320AIC23B audio codec. + + To compile this driver as a module, choose M here: the + module will be called tlv320aic23b. + config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" depends on VIDEO_DEV && I2C && EXPERIMENTAL diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index ad54ecdd7..44f84166f 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o +obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index a9cfd098d..f0eab8352 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -10,6 +10,9 @@ * * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. * + * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> + * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -1003,6 +1006,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->audclk_freq = 48000; state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; + state->vbi_line_offset = 8; state->id = id; if (state->is_cx25836) diff --git a/linux/drivers/media/video/cx25840/cx25840-core.h b/linux/drivers/media/video/cx25840/cx25840-core.h index fe3d1ece1..87226a1a3 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.h +++ b/linux/drivers/media/video/cx25840/cx25840-core.h @@ -41,6 +41,7 @@ struct cx25840_state { enum cx25840_audio_input aud_input; u32 audclk_freq; int audmode; + int vbi_line_offset; enum v4l2_chip_ident id; int is_cx25836; }; diff --git a/linux/drivers/media/video/cx25840/cx25840-vbi.c b/linux/drivers/media/video/cx25840/cx25840-vbi.c index 658fcb260..a998760c8 100644 --- a/linux/drivers/media/video/cx25840/cx25840-vbi.c +++ b/linux/drivers/media/video/cx25840/cx25840-vbi.c @@ -85,6 +85,7 @@ static int decode_vps(u8 * dst, u8 * p) void cx25840_vbi_setup(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); v4l2_std_id std = cx25840_get_v4lstd(client); if (std & ~V4L2_STD_NTSC) { @@ -118,6 +119,7 @@ void cx25840_vbi_setup(struct i2c_client *client) cx25840_write(client, 0x47e, 0x0a); cx25840_write(client, 0x47f, 0x01); + state->vbi_line_offset = 5; } else { /* datasheet startup, step 8d */ cx25840_write(client, 0x49f, 0x14); @@ -141,11 +143,13 @@ void cx25840_vbi_setup(struct i2c_client *client) cx25840_write(client, 0x47d, 0x7c); cx25840_write(client, 0x47e, 0x08); cx25840_write(client, 0x47f, 0x00); + state->vbi_line_offset = 8; } } int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) { + struct cx25840_state *state = i2c_get_clientdata(client); struct v4l2_format *fmt; struct v4l2_sliced_vbi_format *svbi; @@ -212,7 +216,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) cx25840_vbi_setup(client); /* Sliced VBI */ - cx25840_write(client, 0x404, 0x36); /* Ancillery data */ + cx25840_write(client, 0x404, 0x32); /* Ancillary data */ cx25840_write(client, 0x406, 0x13); cx25840_write(client, 0x47f, vbi_offset); @@ -249,8 +253,18 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) } } - for (x = 1, i = 0x424; i <= 0x434; i++, x++) { - cx25840_write(client, i, lcr[6 + x]); + if (is_pal) { + for (x = 1, i = 0x424; i <= 0x434; i++, x++) { + cx25840_write(client, i, lcr[6 + x]); + } + } + else { + for (x = 1, i = 0x424; i <= 0x430; i++, x++) { + cx25840_write(client, i, lcr[9 + x]); + } + for (i = 0x431; i <= 0x434; i++) { + cx25840_write(client, i, 0); + } } cx25840_write(client, 0x43c, 0x16); @@ -258,7 +272,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) if (is_pal) { cx25840_write(client, 0x474, 0x2a); } else { - cx25840_write(client, 0x474, 0x1a + 6); + cx25840_write(client, 0x474, 0x22); } break; } @@ -279,7 +293,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) id1 = p[-1]; id2 = p[0] & 0xf; l = p[2] & 0x3f; - l += 5; + l += state->vbi_line_offset; p += 4; switch (id2) { diff --git a/linux/drivers/media/video/tlv320aic23b.c b/linux/drivers/media/video/tlv320aic23b.c new file mode 100644 index 000000000..4721d6f93 --- /dev/null +++ b/linux/drivers/media/video/tlv320aic23b.c @@ -0,0 +1,250 @@ +/* + * tlv320aic23b - driver version 0.0.1 + * + * Copyright (C) 2006 Scott Alfter <salfter@ssai.us> + * + * Based on wm8775 driver + * + * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to> + * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "compat.h" +#include <linux/module.h> +#include <linux/types.h> +#include <linux/ioctl.h> +#include <asm/uaccess.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/videodev.h> +#include <media/v4l2-common.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include "i2c-compat.h" +#include <linux/slab.h> +#endif + +MODULE_DESCRIPTION("tlv320aic23b driver"); +MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END }; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +#endif + +I2C_CLIENT_INSMOD; + +/* ----------------------------------------------------------------------- */ + +struct tlv320aic23b_state { + u8 muted; +}; + +static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val) +{ + int i; + + if ((reg < 0 || reg > 9) && (reg != 15)) { + v4l_err(client, "Invalid register R%d\n", reg); + return -1; + } + + for (i = 0; i < 3; i++) { + if (i2c_smbus_write_byte_data(client, (reg << 1) | + (val >> 8), val & 0xff) == 0) { + return 0; + } + } + v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); + return -1; +} + +static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct tlv320aic23b_state *state = i2c_get_clientdata(client); + struct v4l2_control *ctrl = arg; + u32* freq = arg; + + switch (cmd) { + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + switch (*freq) { + case 32000: /* set sample rate to 32 kHz */ + tlv320aic23b_write(client, 8, 0x018); + break; + case 44100: /* set sample rate to 44.1 kHz */ + tlv320aic23b_write(client, 8, 0x022); + break; + case 48000: /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 8, 0x000); + break; + default: + return -EINVAL; + } + break; + + case VIDIOC_G_CTRL: + if (ctrl->id != V4L2_CID_AUDIO_MUTE) + return -EINVAL; + ctrl->value = state->muted; + break; + + case VIDIOC_S_CTRL: + if (ctrl->id != V4L2_CID_AUDIO_MUTE) + return -EINVAL; + state->muted = ctrl->value; + tlv320aic23b_write(client, 0, 0x180); /* mute both channels */ + /* set gain on both channels to +3.0 dB */ + if (!state->muted) + tlv320aic23b_write(client, 0, 0x119); + break; + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Input: %s\n", + state->muted ? "muted" : "active"); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static struct i2c_driver i2c_driver; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind) +#else +static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +#endif +{ + struct i2c_client *client; + struct tlv320aic23b_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + client->flags = I2C_CLIENT_ALLOW_USE; +#endif + snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + state->muted = 0; + i2c_set_clientdata(client, state); + + /* initialize tlv320aic23b */ + tlv320aic23b_write(client, 15, 0x000); /* RESET */ + tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */ + tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */ + tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */ + tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */ + + i2c_attach_client(client); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + MOD_INC_USE_COUNT; +#endif + return 0; +} + +static int tlv320aic23b_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, tlv320aic23b_attach); + return 0; +} + +static int tlv320aic23b_detach(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(client); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + MOD_DEC_USE_COUNT; +#endif + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)) + .owner = THIS_MODULE, +#endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + .name = "tlv320aic23b", + .flags = I2C_DF_NOTIFY, +#else + .driver = { + .name = "tlv320aic23b", + }, +#endif + .id = I2C_DRIVERID_TLV320AIC23B, + .attach_adapter = tlv320aic23b_probe, + .detach_client = tlv320aic23b_detach, + .command = tlv320aic23b_command, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +EXPORT_NO_SYMBOLS; +#endif + +static int __init tlv320aic23b_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit tlv320aic23b_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(tlv320aic23b_init_module); +module_exit(tlv320aic23b_cleanup_module); |