On Friday 12 February 2010 23:36:20 Pete Eberlein wrote:
> On Fri, 2010-02-12 at 22:03 +0100, Hans Verkuil wrote:
> > > > > +#include <media/v4l2-i2c-drv.h>
> > > >
> > > > The v4l2-i2c-drv.h is to be used only for drivers that also need to be
> > > > compiled
> > > > for kernels < 2.6.26. If I am not mistaken that is the case for this
> > > > driver,
> > > > right? I remember you mentioning that customers of yours use this on
> > > > such old
> > > > kernels. Just making sure.
> > >
> > > My company, Sensoray, doesn't have any products that use this tuner.
> > > This driver was orignally written by Micronas to support their go7007
> > > chip in the Plextor TV402U models. I don't have the datasheet or know
> > > much about tuners anyway. I used the v4l2-i2c-drv.h since it seems like
> > > a good idea at the time. What should I use instead?
> >
> > We way i2c devices are handled changed massively in kernel 2.6.26. In order
> > to
> > stay backwards compatible with older kernels the v4l2-i2c-drv.h header was
> > introduced. However, this is a bit of a hack and any i2c driver that does
> > not
> > need it shouldn't use it.
> >
> > So only if an i2c driver is *never* used by parent drivers that have to
> > support
> > kernels < 2.6.26, then can it drop the v4l2-i2c-drv.h. An example of such an
> > i2c driver is tvp514x.c.
> >
> > Eventually support for such old kernels will be dropped and the
> > v4l2-i2c-drv.h
> > header will disappear altogether, but that's not going to happen anytime
> > soon.
> >
> > What this means for go7007 is that you have to decide whether you want this
> > go7007 driver to work only for kernels >= 2.6.26, or whether it should also
> > work for older kernels. My understanding is that Sensoray wants to be able
> > to
> > compile go7007 for older kernels. In that case the use of v4l2-i2c-drv.h is
> > correct. Note that this is not about whether any of *Sensoray's* products
> > use
> > a particular i2c device, but whether the *go7007* driver uses it.
> >
> > I hope this clarifies this.
>
> Yes it does, thank you. We do want to allow our customers to use the
> go7007 driver with our products on older kernels, so I would like to
> keep the v4l2-i2c-drv.h for now. I've addressed your other comments in
> the revised patch:
I've two small comments. See below.
I also realized that this is really two drivers in one: one driver for the
actual tuner device and one for the mpx device which seems similar in
functionality to the vp27smpx.c driver.
I will look at it again tomorrow, but I might decide that it is better to
split it up into two drivers: one for the tuner and one for the mpx.
Regards,
Hans
>
>
> From: Pete Eberlein <[email protected]>
>
> This is a subdev conversion of the go7007 wis-sony-tuner i2c driver,
> and places it with the other tuner drivers. This obsoletes the
> wis-sony-tuner driver in the go7007 staging directory.
>
> Priority: normal
>
> Signed-off-by: Pete Eberlein <[email protected]>
>
> diff -r 27ee8e515b18 -r 1cf1bf4e616f
> linux/Documentation/video4linux/CARDLIST.tuner
> --- a/linux/Documentation/video4linux/CARDLIST.tuner Wed Feb 10 11:25:59
> 2010 -0800
> +++ b/linux/Documentation/video4linux/CARDLIST.tuner Fri Feb 12 14:27:39
> 2010 -0800
> @@ -81,3 +81,6 @@
> tuner=81 - Partsnic (Daewoo) PTI-5NF05
> tuner=82 - Philips CU1216L
> tuner=83 - NXP TDA18271
> +tuner=84 - Sony PAL+SECAM (BTF-PG472Z)
> +tuner=85 - Sony NTSC_JP (BTF-PK467Z)
> +tuner=86 - Sony NTSC (BTF-PB463Z)
> diff -r 27ee8e515b18 -r 1cf1bf4e616f linux/drivers/media/common/tuners/Kconfig
> --- a/linux/drivers/media/common/tuners/Kconfig Wed Feb 10 11:25:59
> 2010 -0800
> +++ b/linux/drivers/media/common/tuners/Kconfig Fri Feb 12 14:27:39
> 2010 -0800
> @@ -179,4 +179,12 @@
> help
> A driver for the silicon tuner MAX2165 from Maxim.
>
> +config MEDIA_TUNER_SONY
> + tristate "Sony TV tuner"
> + depends on VIDEO_MEDIA && I2C
> + default m if MEDIA_TUNER_CUSTOMISE
> + help
> + A driver for the Sony tuners BTF-PG472Z, BTF-PK467Z, BTF-PB463Z.
> +
> +
> endif # MEDIA_TUNER_CUSTOMISE
> diff -r 27ee8e515b18 -r 1cf1bf4e616f
> linux/drivers/media/common/tuners/Makefile
> --- a/linux/drivers/media/common/tuners/Makefile Wed Feb 10 11:25:59
> 2010 -0800
> +++ b/linux/drivers/media/common/tuners/Makefile Fri Feb 12 14:27:39
> 2010 -0800
> @@ -24,6 +24,7 @@
> obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
> obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
> obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
> +obj-$(CONFIG_MEDIA_TUNER_SONY) += sony-tuner.o
>
> EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
> EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
> diff -r 27ee8e515b18 -r 1cf1bf4e616f
> linux/drivers/media/common/tuners/sony-tuner.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/linux/drivers/media/common/tuners/sony-tuner.c Fri Feb 12 14:27:39
> 2010 -0800
> @@ -0,0 +1,677 @@
> +/*
> + * Copyright (C) 2005-2006 Micronas USA Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License (Version 2) as
> + * published by the Free Software Foundation.
> + *
> + * 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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/videodev2.h>
> +#include <media/tuner.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-i2c-drv.h>
> +
> +MODULE_DESCRIPTION("Sony TV Tuner driver");
> +MODULE_LICENSE("GPL v2");
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on\n");
> +
> +/* #define MPX_DEBUG */
> +
> +/* AS(IF/MPX) pin: LOW HIGH/OPEN
> + * IF/MPX address: 0x42/0x40 0x43/0x44
> + */
> +#define IF_I2C_ADDR 0x43
> +#define MPX_I2C_ADDR 0x44
> +
> +static v4l2_std_id force_band;
> +static char force_band_str[] = "-";
> +module_param_string(force_band, force_band_str, sizeof(force_band_str),
> 0644);
> +static int force_mpx_mode = -1;
> +module_param(force_mpx_mode, int, 0644);
> +
> +/* Store tuner info in the same format as tuner.c, so maybe we can put the
> + * Sony tuner support in there. */
> +struct sony_tunertype {
> + const char *name;
> + unsigned char Vendor; /* unused here */
> + unsigned char Type; /* unused here */
> +
> + unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */
> + unsigned short thresh2; /* band switch VHF_HI <=> UHF */
> + unsigned char VHF_L;
> + unsigned char VHF_H;
> + unsigned char UHF;
> + unsigned char config;
> + unsigned short IFPCoff;
> +};
> +
> +/* This array is indexed by (tuner_type - TUNER_SONY_BTF_PG472Z) */
> +static const struct sony_tunertype sony_tuners[] = {
> + { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0,
> + 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623},
> + { "Sony NTSC_JP (BTF-PK467Z)", 0, 0,
> + 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940},
> + { "Sony NTSC (BTF-PB463Z)", 0, 0,
> + 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732},
> +};
> +
> +struct sony_tuner {
> + struct v4l2_subdev sd;
> + int type;
> + v4l2_std_id std;
> + unsigned int freq;
> + int mpxmode;
> + u32 audmode;
> +};
> +
> +static inline struct sony_tuner *to_state(struct v4l2_subdev *sd)
> +{
> + return container_of(sd, struct sony_tuner, sd);
> +}
> +
> +/* Basically the same as default_set_tv_freq() in tuner.c */
> +static int set_freq(struct i2c_client *client, int freq)
> +{
> + struct sony_tuner *t = to_state(i2c_get_clientdata(client));
> + const char *band_name;
> + int n;
> + int band_select;
> + const struct sony_tunertype *tun;
> + u8 buffer[4];
> +
> + tun = &sony_tuners[t->type - TUNER_SONY_BTF_PG472Z];
> + if (freq < tun->thresh1) {
> + band_name = "VHF_L";
> + band_select = tun->VHF_L;
> + } else if (freq < tun->thresh2) {
> + band_name = "VHF_H";
> + band_select = tun->VHF_H;
> + } else {
> + band_name = "UHF";
> + band_select = tun->UHF;
> + }
> + v4l2_dbg(1, debug, client, "tuning to frequency %d.%04d (%s)\n",
> + freq / 16, (freq % 16) * 625, band_name);
> + n = freq + tun->IFPCoff;
> +
> + buffer[0] = n >> 8;
> + buffer[1] = n & 0xff;
> + buffer[2] = tun->config;
> + buffer[3] = band_select;
> + i2c_master_send(client, buffer, 4);
> +
> + return 0;
> +}
> +
> +static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
> +{
> + u8 buffer[5];
> + struct i2c_msg msg;
> +
> + buffer[0] = dev;
> + buffer[1] = addr >> 8;
> + buffer[2] = addr & 0xff;
> + buffer[3] = val >> 8;
> + buffer[4] = val & 0xff;
> + msg.addr = MPX_I2C_ADDR;
> + msg.flags = 0;
> + msg.len = 5;
> + msg.buf = buffer;
> + i2c_transfer(client->adapter, &msg, 1);
> + return 0;
> +}
> +
> +/*
> + * MPX register values for the BTF-PG472Z:
> + *
> + * FM_ NICAM_ SCART_
> + * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME
> + * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
> + * ---------------------------------------------------------------
> + * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500
> + *
> + * B/G
> + * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500
> + * A2 1003 0020 0100 2601 5000 XXXX 0003 7500
> + * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500
> + *
> + * I
> + * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500
> + * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500
> + *
> + * D/K
> + * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500
> + * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500
> + * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500
> + * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500
> + * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500
> + *
> + * L/L'
> + * Mono 0003 0200 0100 7C03 5000 2200 0009 7500
> + * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500
> + *
> + * M
> + * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500
> + *
> + * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
> + *
> + * Bilingual selection in A2/NICAM:
> + *
> + * High byte of SOURCE Left chan Right chan
> + * 0x01 MAIN SUB
> + * 0x03 MAIN MAIN
> + * 0x04 SUB SUB
> + *
> + * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
> + * 0x00 (all other bands). Force mono in A2 with FMONO_A2:
> + *
> + * FMONO_A2
> + * 10/0022
> + * --------
> + * Forced mono ON 07F0
> + * Forced mono OFF 0190
> + */
> +
> +static struct {
> + enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
> + u16 modus;
> + u16 source;
> + u16 acb;
> + u16 fm_prescale;
> + u16 nicam_prescale;
> + u16 scart_prescale;
> + u16 system;
> + u16 volume;
> +} mpx_audio_modes[] = {
> + /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
> + 0x5000, 0x0000, 0x0001, 0x7500 },
> + /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
> + 0x5000, 0x0000, 0x0003, 0x7500 },
> + /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
> + 0x5000, 0x0000, 0x0003, 0x7500 },
> + /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
> + 0x5000, 0x0000, 0x0008, 0x7500 },
> + /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
> + 0x7900, 0x0000, 0x000A, 0x7500 },
> + /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
> + 0x7900, 0x0000, 0x000A, 0x7500 },
> + /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
> + 0x5000, 0x0000, 0x0004, 0x7500 },
> + /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
> + 0x5000, 0x0000, 0x0004, 0x7500 },
> + /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
> + 0x5000, 0x0000, 0x0005, 0x7500 },
> + /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
> + 0x5000, 0x0000, 0x0007, 0x7500 },
> + /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
> + 0x5000, 0x0000, 0x000B, 0x7500 },
> + /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
> + 0x5000, 0x2200, 0x0009, 0x7500 },
> + /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03,
> + 0x5000, 0x0000, 0x0009, 0x7500 },
> +};
> +
> +#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
> +
> +static int mpx_setup(struct i2c_client *client)
> +{
> + struct sony_tuner *t = i2c_get_clientdata(client);
> + u16 source = 0;
> + u8 buffer[3];
> + struct i2c_msg msg;
> +
> + /* reset MPX */
> + buffer[0] = 0x00;
> + buffer[1] = 0x80;
> + buffer[2] = 0x00;
> + msg.addr = MPX_I2C_ADDR;
> + msg.flags = 0;
> + msg.len = 3;
> + msg.buf = buffer;
> + i2c_transfer(client->adapter, &msg, 1);
> + buffer[1] = 0x00;
> + i2c_transfer(client->adapter, &msg, 1);
> +
> + if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) {
> + switch (t->audmode) {
> + case V4L2_TUNER_MODE_MONO:
> + switch (mpx_audio_modes[t->mpxmode].audio_mode) {
> + case AUD_A2:
> + source = mpx_audio_modes[t->mpxmode].source;
> + break;
> + case AUD_NICAM:
> + source = 0x0000;
> + break;
> + case AUD_NICAM_L:
> + source = 0x0200;
> + break;
> + default:
> + break;
> + }
> + break;
> + case V4L2_TUNER_MODE_STEREO:
> + source = mpx_audio_modes[t->mpxmode].source;
> + break;
> + case V4L2_TUNER_MODE_LANG1:
> + source = 0x0300;
> + break;
> + case V4L2_TUNER_MODE_LANG2:
> + source = 0x0400;
> + break;
> + }
> + source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
> + } else
> + source = mpx_audio_modes[t->mpxmode].source;
> +
> + mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus);
> + mpx_write(client, 0x12, 0x0008, source);
> + mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb);
> + mpx_write(client, 0x12, 0x000e,
> + mpx_audio_modes[t->mpxmode].fm_prescale);
> + mpx_write(client, 0x12, 0x0010,
> + mpx_audio_modes[t->mpxmode].nicam_prescale);
> + mpx_write(client, 0x12, 0x000d,
> + mpx_audio_modes[t->mpxmode].scart_prescale);
> + mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system);
> + mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume);
> + if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2)
> + mpx_write(client, 0x10, 0x0022,
> + t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
> +
> +#ifdef MPX_DEBUG
> + {
> + u8 buf1[3], buf2[2];
> + struct i2c_msg msgs[2];
> +
> + v4l2_info(client, "MPX registers: %04x %04x "
> + "%04x %04x %04x %04x %04x %04x\n",
> + mpx_audio_modes[t->mpxmode].modus,
> + source,
> + mpx_audio_modes[t->mpxmode].acb,
> + mpx_audio_modes[t->mpxmode].fm_prescale,
> + mpx_audio_modes[t->mpxmode].nicam_prescale,
> + mpx_audio_modes[t->mpxmode].scart_prescale,
> + mpx_audio_modes[t->mpxmode].system,
> + mpx_audio_modes[t->mpxmode].volume);
> + buf1[0] = 0x11;
> + buf1[1] = 0x00;
> + buf1[2] = 0x7e;
> + msgs[0].addr = MPX_I2C_ADDR;
> + msgs[0].flags = 0;
> + msgs[0].len = 3;
> + msgs[0].buf = buf1;
> + msgs[1].addr = MPX_I2C_ADDR;
> + msgs[1].flags = I2C_M_RD;
> + msgs[1].len = 2;
> + msgs[1].buf = buf2;
> + i2c_transfer(client->adapter, msgs, 2);
> + v4l2_info(client, "MPX system: %02x%02x\n",
> + buf2[0], buf2[1]);
> + buf1[0] = 0x11;
> + buf1[1] = 0x02;
> + buf1[2] = 0x00;
> + i2c_transfer(client->adapter, msgs, 2);
> + v4l2_info(client, "MPX status: %02x%02x\n",
> + buf2[0], buf2[1]);
> + }
> +#endif
> + return 0;
> +}
> +
> +/*
> + * IF configuration values for the BTF-PG472Z:
> + *
> + * B/G: 0x94 0x70 0x49
> + * I: 0x14 0x70 0x4a
> + * D/K: 0x14 0x70 0x4b
> + * L: 0x04 0x70 0x4b
> + * L': 0x44 0x70 0x53
> + * M: 0x50 0x30 0x4c
> + */
> +
> +static int set_if(struct i2c_client *client)
> +{
> + struct sony_tuner *t = i2c_get_clientdata(client);
> + u8 buffer[4];
> + struct i2c_msg msg;
> + int default_mpx_mode = 0;
> +
> + /* configure IF */
> + buffer[0] = 0;
> + if (t->std & V4L2_STD_PAL_BG) {
> + buffer[1] = 0x94;
> + buffer[2] = 0x70;
> + buffer[3] = 0x49;
> + default_mpx_mode = 1;
> + } else if (t->std & V4L2_STD_PAL_I) {
> + buffer[1] = 0x14;
> + buffer[2] = 0x70;
> + buffer[3] = 0x4a;
> + default_mpx_mode = 4;
> + } else if (t->std & V4L2_STD_PAL_DK) {
> + buffer[1] = 0x14;
> + buffer[2] = 0x70;
> + buffer[3] = 0x4b;
> + default_mpx_mode = 6;
> + } else if (t->std & V4L2_STD_SECAM_L) {
> + buffer[1] = 0x04;
> + buffer[2] = 0x70;
> + buffer[3] = 0x4b;
> + default_mpx_mode = 11;
> + }
> + msg.addr = IF_I2C_ADDR;
> + msg.flags = 0;
> + msg.len = 4;
> + msg.buf = buffer;
> + i2c_transfer(client->adapter, &msg, 1);
> +
> + /* Select MPX mode if not forced by the user */
> + if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES)
> + t->mpxmode = force_mpx_mode;
> + else
> + t->mpxmode = default_mpx_mode;
> + v4l2_dbg(1, debug, client, "setting MPX to mode %d\n", t->mpxmode);
> + mpx_setup(client);
> +
> + return 0;
> +}
> +
> +static int sony_tuner_s_type_addr(struct v4l2_subdev *sd,
> + struct tuner_setup *setup)
> +{
> + struct sony_tuner *t = to_state(sd);
> +
> + if (!(setup->mode_mask & T_ANALOG_TV))
> + return 0;
> +
> + if (t->type >= 0) {
> + if (t->type != setup->type)
> + v4l2_dbg(1, debug, sd, "type already set to %d, "
> + "ignoring request for %d\n",
> + t->type, setup->type);
> + return 0;
> + }
> + switch (setup->type) {
> + case TUNER_SONY_BTF_PG472Z:
> + switch (force_band_str[0]) {
> + case 'b':
> + case 'B':
> + case 'g':
> + case 'G':
> + v4l2_dbg(1, debug, sd, "forcing tuner to PAL-B/G
> bands\n");
> + force_band = V4L2_STD_PAL_BG;
> + break;
> + case 'i':
> + case 'I':
> + v4l2_dbg(1, debug, sd, "forcing tuner to PAL-I band\n");
> + force_band = V4L2_STD_PAL_I;
> + break;
> + case 'd':
> + case 'D':
> + case 'k':
> + case 'K':
> + v4l2_dbg(1, debug, sd, "forcing tuner to PAL-D/K
> bands\n");
> + force_band = V4L2_STD_PAL_I;
> + break;
> + case 'l':
> + case 'L':
> + v4l2_dbg(1, debug, sd, "forcing tuner to SECAM-L
> band\n");
> + force_band = V4L2_STD_SECAM_L;
> + break;
> + default:
> + force_band = 0;
> + break;
> + }
> + if (force_band)
> + t->std = force_band;
> + else
> + t->std = V4L2_STD_PAL_BG;
> + set_if(v4l2_get_subdevdata(sd));
> + break;
> + case TUNER_SONY_BTF_PK467Z:
> + t->std = V4L2_STD_NTSC_M_JP;
> + break;
> + case TUNER_SONY_BTF_PB463Z:
> + t->std = V4L2_STD_NTSC_M;
> + break;
> + default:
> + v4l2_dbg(1, debug, sd,
> + "tuner type %d is not supported by this module\n",
> + setup->type);
> + return -EINVAL;
> + }
> + t->type = setup->type;
> + if (t->type >= 0)
> + v4l2_dbg(1, debug, sd, "type set to %d (%s)\n",
> + t->type,
> + sony_tuners[t->type - TUNER_SONY_BTF_PG472Z].name);
> + return 0;
> +}
> +
> +static int sony_tuner_g_frequency(struct v4l2_subdev *sd,
> + struct v4l2_frequency *freq)
> +{
> + struct sony_tuner *t = to_state(sd);
> +
> + if (freq->type != V4L2_TUNER_ANALOG_TV)
> + return -EINVAL;
> +
> + freq->frequency = t->freq;
> + return 0;
> +}
> +
> +static int sony_tuner_s_frequency(struct v4l2_subdev *sd,
> + struct v4l2_frequency *freq)
> +{
> + struct sony_tuner *t = to_state(sd);
> +
> + if (freq->type != V4L2_TUNER_ANALOG_TV)
> + return -EINVAL;
> +
> + t->freq = freq->frequency;
> + set_freq(v4l2_get_subdevdata(sd), t->freq);
> + return 0;
> +}
> +
> +
> +
> +static int sony_tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
> +{
> + struct sony_tuner *t = to_state(sd);
> + v4l2_std_id old = t->std;
> +
> + switch (t->type) {
> + case TUNER_SONY_BTF_PG472Z:
> + if (force_band && (norm & force_band) != norm &&
> + norm != V4L2_STD_PAL &&
> + norm != V4L2_STD_SECAM) {
> + v4l2_dbg(1, debug, sd, "ignoring requested TV standard
> in "
> + "favor of force_band value\n");
> + t->std = force_band;
> + } else if (norm & V4L2_STD_PAL_BG) { /* default */
> + t->std = V4L2_STD_PAL_BG;
> + } else if (norm & V4L2_STD_PAL_I) {
> + t->std = V4L2_STD_PAL_I;
> + } else if (norm & V4L2_STD_PAL_DK) {
> + t->std = V4L2_STD_PAL_DK;
> + } else if (norm & V4L2_STD_SECAM_L) {
> + t->std = V4L2_STD_SECAM_L;
> + } else {
> + v4l2_dbg(1, debug, sd, "TV standard not supported\n");
> + return -EINVAL;
> + }
> + if (old != t->std)
> + set_if(v4l2_get_subdevdata(sd));
> + break;
> + case TUNER_SONY_BTF_PK467Z:
> + if (!(norm & V4L2_STD_NTSC_M_JP)) {
> + v4l2_dbg(1, debug, sd, "TV standard not supported\n");
> + return -EINVAL;
> + }
> + break;
> + case TUNER_SONY_BTF_PB463Z:
> + if (!(norm & V4L2_STD_NTSC_M)) {
> + v4l2_dbg(1, debug, sd, "TV standard not supported\n");
> + return -EINVAL;
> + }
> + break;
> + }
> + return 0;
> +}
> +
> +static int sony_tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> +{
> + struct sony_tuner *t = to_state(sd);
> +
> + strlcpy(vt->name, "Television", sizeof(vt->name));
> + vt->type = V4L2_TUNER_ANALOG_TV;
> + vt->rangelow = 16; /* FIXME */
> + vt->rangehigh = 16 * 999.99; /* FIXME */
Instead of just saying 'FIXME' add a comment saying something like this:
'Since we do not have a datasheet for this tuner we just put in
artificial low and high frequency values.'
> + switch (t->type) {
> + case TUNER_SONY_BTF_PG472Z:
> + vt->capability = V4L2_TUNER_CAP_NORM |
> + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
> + V4L2_TUNER_CAP_LANG2;
> + vt->rxsubchans = V4L2_TUNER_SUB_MONO |
> + V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
> + V4L2_TUNER_SUB_LANG2;
> + break;
> + case TUNER_SONY_BTF_PK467Z:
> + case TUNER_SONY_BTF_PB463Z:
> + vt->capability = V4L2_TUNER_CAP_STEREO;
> + vt->rxsubchans = V4L2_TUNER_SUB_MONO |
> + V4L2_TUNER_SUB_STEREO;
> + break;
> + }
> + vt->audmode = t->audmode;
> + return 0;
> +}
> +
> +static int sony_tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> +{
> + struct sony_tuner *t = to_state(sd);
> +
> + if (vt->type != V4L2_TUNER_ANALOG_TV)
> + return -EINVAL;
> +
> + switch (t->type) {
> + case TUNER_SONY_BTF_PG472Z:
> + if (vt->audmode != t->audmode) {
> + t->audmode = vt->audmode;
> + mpx_setup(v4l2_get_subdevdata(sd));
> + }
> + break;
> + case TUNER_SONY_BTF_PK467Z:
> + case TUNER_SONY_BTF_PB463Z:
> + break;
> + }
> + return 0;
> +}
> +
> +static int sony_tuner_log_status(struct v4l2_subdev *sd)
> +{
> + struct sony_tuner *t = to_state(sd);
> +
> + v4l2_info(sd, "Standard: %s\n", t->std == V4L2_STD_NTSC ? "NTSC" :
> + t->std == V4L2_STD_PAL ? "PAL" :
> + t->std == V4L2_STD_SECAM ? "SECAM" :
> + "unknown");
> + v4l2_info(sd, "Frequency: %ud\n", t->freq);
> + return 0;
> +}
> +
> +/*
> --------------------------------------------------------------------------*/
> +
> +static const struct v4l2_subdev_core_ops sony_tuner_core_ops = {
> + .log_status = sony_tuner_log_status,
> + .s_std = sony_tuner_s_std,
> +};
> +
> +static const struct v4l2_subdev_tuner_ops sony_tuner_tuner_ops = {
> + .s_frequency = sony_tuner_s_frequency,
> + .g_frequency = sony_tuner_g_frequency,
> + .s_tuner = sony_tuner_s_tuner,
> + .g_tuner = sony_tuner_g_tuner,
> + .s_type_addr = sony_tuner_s_type_addr,
> +};
> +
> +static const struct v4l2_subdev_ops sony_tuner_ops = {
> + .core = &sony_tuner_core_ops,
> + .tuner = &sony_tuner_tuner_ops,
> +};
> +
> +/*
> --------------------------------------------------------------------------*/
> +
> +static int sony_tuner_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct sony_tuner *t;
> + struct v4l2_subdev *sd;
> +
> + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
> + return -ENODEV;
> +
> + v4l2_info(client, "initializing Sony TV Tuner at address 0x%x on %s\n",
> + client->addr << 1, client->adapter->name);
Please use this for consistency with the other i2c drivers:
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
> +
> + t = kzalloc(sizeof(struct sony_tuner), GFP_KERNEL);
> + if (t == NULL)
> + return -ENOMEM;
> +
> + sd = &t->sd;
> + v4l2_i2c_subdev_init(sd, client, &sony_tuner_ops);
> +
> + /* Initialize sony_tuner */
> + t->type = -1;
> + t->freq = 0;
> + t->mpxmode = 0;
> + t->audmode = V4L2_TUNER_MODE_STEREO;
> +
> + return 0;
> +}
> +
> +static int sony_tuner_remove(struct i2c_client *client)
> +{
> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +
> + v4l2_device_unregister_subdev(sd);
> + kfree(to_state(sd));
> +
> + return 0;
> +}
> +
> +/* ----------------------------------------------------------------------- */
> +
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
> +static const struct i2c_device_id sony_tuner_id[] = {
> + { "sony_tuner", 0 },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, sony_tuner_id);
> +#endif
> +
> +static struct v4l2_i2c_driver_data v4l2_i2c_data = {
> + .name = "sony_tuner",
> + .probe = sony_tuner_probe,
> + .remove = sony_tuner_remove,
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
> + .id_table = sony_tuner_id,
> +#endif
> +};
> diff -r 27ee8e515b18 -r 1cf1bf4e616f
> linux/drivers/media/common/tuners/tuner-types.c
> --- a/linux/drivers/media/common/tuners/tuner-types.c Wed Feb 10 11:25:59
> 2010 -0800
> +++ b/linux/drivers/media/common/tuners/tuner-types.c Fri Feb 12 14:27:39
> 2010 -0800
> @@ -1806,6 +1806,18 @@
> .name = "NXP TDA18271",
> /* see tda18271-fe.c for details */
> },
> + [TUNER_SONY_BTF_PG472Z] = {
> + .name = "Sony PAL+SECAM (BTF-PG472Z)",
> + /* see sony-tuner.c for details */
> + },
> + [TUNER_SONY_BTF_PK467Z] = {
> + .name = "Sony NTSC_JP (BTF-PK467Z)",
> + /* see sony-tuner.c for details */
> + },
> + [TUNER_SONY_BTF_PB463Z] = {
> + .name = "Sony NTSC (BTF-PB463Z)",
> + /* see sony-tuner.c for details */
> + },
> };
> EXPORT_SYMBOL(tuners);
>
> diff -r 27ee8e515b18 -r 1cf1bf4e616f
> linux/drivers/staging/go7007/go7007-driver.c
> --- a/linux/drivers/staging/go7007/go7007-driver.c Wed Feb 10 11:25:59
> 2010 -0800
> +++ b/linux/drivers/staging/go7007/go7007-driver.c Fri Feb 12 14:27:39
> 2010 -0800
> @@ -243,6 +243,16 @@
> init_i2c_module(&go->i2c_adapter,
> go->board_info->i2c_devs[i].type,
> go->board_info->i2c_devs[i].addr);
> +
> + if (go->tuner_type >= 0) {
> + struct tuner_setup setup = {
> + .addr = ADDR_UNSET,
> + .type = go->tuner_type,
> + .mode_mask = T_ANALOG_TV,
> + };
> + v4l2_device_call_all(&go->v4l2_dev, 0, tuner,
> + s_type_addr, &setup);
> + }
> if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
> int channel = go->channel_number;
> struct v4l2_priv_tun_config config = {
> diff -r 27ee8e515b18 -r 1cf1bf4e616f
> linux/drivers/staging/go7007/go7007-priv.h
> --- a/linux/drivers/staging/go7007/go7007-priv.h Wed Feb 10 11:25:59
> 2010 -0800
> +++ b/linux/drivers/staging/go7007/go7007-priv.h Fri Feb 12 14:27:39
> 2010 -0800
> @@ -292,9 +292,3 @@
> /* We re-use the I2C_M_TEN value so the flag passes through the masks in the
> * core I2C code. Major kludge, but the I2C layer ain't exactly flexible. */
> #define I2C_CLIENT_SCCB 0x10
> -
> -/* Sony tuner types */
> -
> -#define TUNER_SONY_BTF_PG472Z 200
> -#define TUNER_SONY_BTF_PK467Z 201
> -#define TUNER_SONY_BTF_PB463Z 202
> diff -r 27ee8e515b18 -r 1cf1bf4e616f linux/drivers/staging/go7007/go7007-usb.c
> --- a/linux/drivers/staging/go7007/go7007-usb.c Wed Feb 10 11:25:59
> 2010 -0800
> +++ b/linux/drivers/staging/go7007/go7007-usb.c Fri Feb 12 14:27:39
> 2010 -0800
> @@ -27,6 +27,7 @@
> #include <linux/i2c.h>
> #include <asm/byteorder.h>
> #include <media/tvaudio.h>
> +#include <media/tuner.h>
>
> #include "go7007-priv.h"
>
> @@ -217,7 +218,7 @@
> .addr = 0x1a,
> },
> {
> - .type = "wis_sony_tuner",
> + .type = "sony_tuner",
> .addr = 0x60,
> },
> },
> diff -r 27ee8e515b18 -r 1cf1bf4e616f linux/include/media/tuner.h
> --- a/linux/include/media/tuner.h Wed Feb 10 11:25:59 2010 -0800
> +++ b/linux/include/media/tuner.h Fri Feb 12 14:27:39 2010 -0800
> @@ -130,6 +130,10 @@
> #define TUNER_PHILIPS_CU1216L 82
> #define TUNER_NXP_TDA18271 83
>
> +#define TUNER_SONY_BTF_PG472Z 84 /* PAL+SECAM */
> +#define TUNER_SONY_BTF_PK467Z 85 /* NTSC_JP */
> +#define TUNER_SONY_BTF_PB463Z 86 /* NTSC */
> +
> /* tv card specific */
> #define TDA9887_PRESENT (1<<0)
> #define TDA9887_PORT1_INACTIVE (1<<1)
>
>
--
Hans Verkuil - video4linux developer - sponsored by TANDBERG
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html