#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/tuner-types.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
#include "mt20xx.h"
#include "tda8290.h"
#include "tea5761.h"
#include "tuner-simple.h"
#include "tda9887.h"
#include "xc5000.h"
+#include "tda18271.h"
#define UNSET (-1U)
return container_of(sd, struct tuner, sd);
}
-/* standard i2c insmod options */
-static unsigned short normal_i2c[] = {
-#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
- 0x10,
-#endif
- 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- I2C_CLIENT_END
-};
-
-I2C_CLIENT_INSMOD;
/* insmod options used at init time => read/only */
static unsigned int addr;
}
}
-static void tuner_i2c_address_check(struct tuner *t)
-{
- if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
- ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
- return;
-
- /* We already know that the XC5000 can only be located at
- * i2c address 0x61, 0x62, 0x63 or 0x64 */
- if ((t->type == TUNER_XC5000) &&
- ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
- return;
-
- tuner_warn("====================== WARNING! ======================\n");
- tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
- tuner_warn("will soon be dropped. This message indicates that your\n");
- tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
- t->name, t->i2c->addr);
- tuner_warn("To ensure continued support for your device, please\n");
- tuner_warn("send a copy of this message, along with full dmesg\n");
- tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
- tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
- tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
- t->i2c->adapter->name, t->i2c->addr, t->type, t->name);
- tuner_warn("====================== WARNING! ======================\n");
-}
-
static struct xc5000_config xc5000_cfg;
static void set_type(struct i2c_client *c, unsigned int type,
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
unsigned char buffer[4];
+ int tune_now = 1;
if (type == UNSET || type == TUNER_ABSENT) {
tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
t->type = type;
/* prevent invalid config values */
- t->config = ((new_config >= 0) && (new_config < 256)) ? new_config : 0;
+ t->config = new_config < 256 ? new_config : 0;
if (tuner_callback != NULL) {
tuner_dbg("defining GPIO callback\n");
t->fe.callback = tuner_callback;
};
if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
goto attach_failed;
+ tune_now = 0;
break;
}
case TUNER_TDA9887:
break;
case TUNER_XC5000:
{
- struct dvb_tuner_ops *xc_tuner_ops;
-
xc5000_cfg.i2c_address = t->i2c->addr;
/* if_khz will be set when the digital dvb_attach() occurs */
xc5000_cfg.if_khz = 0;
if (!dvb_attach(xc5000_attach,
&t->fe, t->i2c->adapter, &xc5000_cfg))
goto attach_failed;
+ tune_now = 0;
+ break;
+ }
+ case TUNER_NXP_TDA18271:
+ {
+ struct tda18271_config cfg = {
+ .config = t->config,
+ };
- xc_tuner_ops = &t->fe.ops.tuner_ops;
- if (xc_tuner_ops->init)
- xc_tuner_ops->init(&t->fe);
+ if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr,
+ t->i2c->adapter, &cfg))
+ goto attach_failed;
+ tune_now = 0;
break;
}
default:
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
- /* xc2028/3028 and xc5000 requires a firmware to be set-up later
+ /* Some tuners require more initialization setup before use,
+ such as firmware download or device calibration.
trying to set a frequency here will just fail
FIXME: better to move set_freq to the tuner code. This is needed
on analog tuners for PLL to properly work
*/
- if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000)
+ if (tune_now)
set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
t->radio_freq : t->tv_freq);
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
t->mode_mask);
- tuner_i2c_address_check(t);
return;
attach_failed:
return 0;
}
-static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
+static int tuner_s_power(struct v4l2_subdev *sd, int on)
{
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ if (on)
+ return 0;
+
tuner_dbg("Putting tuner to sleep\n");
- if (check_mode(t, "s_standby") == -EINVAL)
+ if (check_mode(t, "s_power") == -EINVAL)
return 0;
t->mode = T_STANDBY;
if (analog_ops->standby)
fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
- (abs_freq * 2 + 125/2) / 125 :
- (abs_freq + 62500/2) / 62500;
+ DIV_ROUND_CLOSEST(abs_freq * 2, 125) :
+ DIV_ROUND_CLOSEST(abs_freq, 62500);
return 0;
}
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
return 0;
}
-static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
static int tuner_suspend(struct i2c_client *c, pm_message_t state)
{
struct tuner *t = to_tuner(i2c_get_clientdata(c));
return 0;
}
+static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ /* TUNER_SET_CONFIG is still called by tuner-simple.c, so we have
+ to handle it here.
+ There must be a better way of doing this... */
+ switch (cmd) {
+ case TUNER_SET_CONFIG:
+ return tuner_s_config(sd, arg);
+ }
+ return -ENOIOCTLCMD;
+}
+
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops tuner_core_ops = {
.log_status = tuner_log_status,
- .s_standby = tuner_s_standby,
+ .s_std = tuner_s_std,
+ .s_power = tuner_s_power,
};
static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
- .s_std = tuner_s_std,
.s_radio = tuner_s_radio,
.g_tuner = tuner_g_tuner,
.s_tuner = tuner_s_tuner,
int mode_mask;
if (pos->i2c->adapter != adap ||
- pos->i2c->driver->id != I2C_DRIVERID_TUNER)
+ strcmp(pos->i2c->driver->driver.name, "tuner"))
continue;
mode_mask = pos->mode_mask & ~T_STANDBY;
goto register_client;
}
+ kfree(t);
return -ENODEV;
case 0x42:
case 0x43:
return 0;
}
-static int tuner_legacy_probe(struct i2c_adapter *adap)
-{
- if (0 != addr) {
- normal_i2c[0] = addr;
- normal_i2c[1] = I2C_CLIENT_END;
- }
-
- if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
- return 0;
-
- /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
- * FusionHDTV5 RT Gold has an ir receiver at 0x6b
- * and an RTC at 0x6f which can get corrupted if probed.
- */
- if ((adap->id == I2C_HW_B_CX2388x) ||
- (adap->id == I2C_HW_B_CX23885)) {
- unsigned int i = 0;
-
- while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
- i += 2;
- if (i + 4 < I2C_CLIENT_MAX_OPTS) {
- ignore[i+0] = adap->nr;
- ignore[i+1] = 0x6b;
- ignore[i+2] = adap->nr;
- ignore[i+3] = 0x6f;
- ignore[i+4] = I2C_CLIENT_END;
- } else
- printk(KERN_WARNING "tuner: "
- "too many options specified "
- "in i2c probe ignore list!\n");
- }
- return 1;
-}
-
static int tuner_remove(struct i2c_client *client)
{
struct tuner *t = to_tuner(i2c_get_clientdata(client));
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tuner",
- .driverid = I2C_DRIVERID_TUNER,
- .command = tuner_command,
.probe = tuner_probe,
.remove = tuner_remove,
+ .command = tuner_command,
.suspend = tuner_suspend,
.resume = tuner_resume,
- .legacy_probe = tuner_legacy_probe,
.id_table = tuner_id,
};