📄 tvp7000.c
字号:
{ /* Video standard: 720*480p resolution,60HZ refresh rate,
31.468kHZ Horizontal frequency,27MHZ pixel rate.
*/
.plldiv_msb = 0x6B,
.plldiv_lsb = 0x40,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x01,
.pre_coast = 0x03,
.post_coast = 0x0c,
.clamp_start = 0x06,
.clamp_width = 0x10,
.alc_placement = 0x18,
},
{ /* Video standard: 720*576p resolution,50HZ refresh rate,
31.25kHZ Horizontal frequency,27MHZ pixel rate.
*/
.plldiv_msb = 0x6C,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x01,
.pre_coast = 0x03,
.post_coast = 0x0c,
.clamp_start = 0x06,
.clamp_width = 0x10,
.alc_placement = 0x18,
},
{ /* Video standard: 1280*720p resolution,60HZ refresh rate,
45kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0x67,
.plldiv_lsb = 0x20,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
},
{ /* Video standard: 1280*720p resolution,50HZ refresh rate,
37.5kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0x7B,
.plldiv_lsb = 0xC0,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
},
{ /* Video standard: 1920*1080i resolution,60HZ refresh rate,
33.75kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0x89,
.plldiv_lsb = 0x80,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x03,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
},
{ /* Video standard: 1920*1080i resolution,50HZ refresh rate,
28.125kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0xA5,
.plldiv_lsb = 0x00,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x03,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
},
{ /* Video standard: 1920*1080p resolution,60HZ refresh rate,
67.5kHZ Horizontal frequency,148.5MHZ pixel rate.
*/
.plldiv_msb = 0x89,
.plldiv_lsb = 0x80,
.pll_ctrl = 0xD8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
},
{ /* Video standard: 1920*1080p resolution,50HZ refresh rate,
56.25kHZ Horizontal frequency,148.5MHZ pixel rate.
*/
.plldiv_msb = 0xA5,
.plldiv_lsb = 0x00,
.pll_ctrl = 0xD8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
},
};
static int tvp7000_attach_adapter(struct i2c_adapter *adapter);
static int tvp7000_detach_client(struct i2c_client *client);
static int tvp7000_detect_client(struct i2c_adapter *adapter,
int addr, int kind);
static inline int tvp7000_read_reg(u8 reg);
static inline int tvp7000_write_reg(u8 reg, u8 value);
static int tvp7000_setup_video_standard(const struct tvp7000_video_std *std);
static int tvp7000_device_init(struct vpfe_capture_params *params);
static int tvp7000_device_cmd(u32 cmd, void *arg);
static struct i2c_driver tvp7000_driver = {
.driver = {
.name = "TVP7000",
},
.id = I2C_DRIVERID_TVP7000,
.attach_adapter = tvp7000_attach_adapter,
.detach_client = tvp7000_detach_client,
};
static inline int tvp7000_read_reg(u8 reg)
{
return i2c_smbus_read_byte_data(tvp7000_client, reg);
}
static inline int tvp7000_write_reg(u8 reg, u8 value)
{
int ret;
ret = i2c_smbus_write_byte_data(tvp7000_client,
reg, value);
if (ret != 0)
DPRINTK("Write Error Address = %x\n", reg);
return ret;
}
static int tvp7000_write_inittab(const struct i2c_reg_value *regs, int num)
{
int err = 0;
int i = 0;
if (regs == NULL)
return -EINVAL;
for (i=0; i<num; i++)
err |= tvp7000_write_reg(regs[i].reg, regs[i].value);
return err;
}
static int tvp7000_detect_client(struct i2c_adapter *adapter,
int addr, int kind)
{
int err = 0;
const char *client_name = "TVP7000 Video Capture";
FN_IN;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE))
{
DPRINTK("Functionality check failed for %s\n",
client_name);
return err;
}
tvp7000_client = kmalloc(sizeof(struct i2c_client),
GFP_KERNEL);
if (tvp7000_client == NULL)
{
err = -ENOMEM;
DPRINTK("Couldn't allocate memory for %s\n",
client_name);
return err;
}
memset(tvp7000_client, 0x00, sizeof(struct i2c_client));
tvp7000_client->adapter = adapter;
tvp7000_client->addr = addr;
tvp7000_client->driver = &tvp7000_driver;
tvp7000_client->flags = 0;
strlcpy(tvp7000_client->name, client_name, I2C_NAME_SIZE);
err = i2c_attach_client(tvp7000_client);
if (err)
{
DPRINTK("Couldn't attach %s\n", client_name);
kfree(tvp7000_client);
return err;
}
return 0;
}
static int tvp7000_attach_adapter(struct i2c_adapter *adapter)
{
FN_IN;
return i2c_probe(adapter, &addr_data, &tvp7000_detect_client);
}
static int tvp7000_detach_client(struct i2c_client *client)
{
int err = 0;
FN_IN;
err = i2c_detach_client(client);
if (err)
{
DPRINTK("Client deregistration failed, \
client not detached.\n");
return err;
}
kfree(client);
return 0;
}
static void tvp7000_device_power_on(bool on)
{
s8 level = (on == true) ? 0 : 1;
/* enable the GPIO(39) direction mode as output */
gpio_direction_output(HD_CAP_GPIO, level);
/* when on == true */
/* set the Reset pin level as High for 5ms */
gpio_set_value(HD_CAP_GPIO, level);
mdelay(5);
/* pull down the Reset pin level for 5us,
reset the chip(Reset pin active in low) */
gpio_set_value(HD_CAP_GPIO, !level);
udelay(5);
/* pull up the Reset pin and delay for 5us,
now,tvp7000 is power up */
gpio_set_value(HD_CAP_GPIO, level);
udelay(5);
}
static int tvp7000_setup_video_standard(const struct tvp7000_video_std *std)
{
int err = 0;
int val;
if (std == NULL)
return -EINVAL;
err |= tvp7000_write_reg(TVP7000_PLL_DIVIDE_MSB, std->plldiv_msb);
err |= tvp7000_write_reg(TVP7000_PLL_DIVIDE_LSB, std->plldiv_lsb);
err |= tvp7000_write_reg(TVP7000_PLL_CTRL, std->pll_ctrl);
val = tvp7000_read_reg(TVP7000_PHASE_SELECT);
val &= ~0x01;
err |= tvp7000_write_reg(TVP7000_PHASE_SELECT, (std->phase_select_bit0 & 0x01) | val);
err |= tvp7000_write_reg(TVP7000_PRE_COAST, std->pre_coast);
err |= tvp7000_write_reg(TVP7000_POST_COAST, std->post_coast);
err |= tvp7000_write_reg(TVP7000_CLAMP_START, std->clamp_start);
err |= tvp7000_write_reg(TVP7000_CLAMP_WIDTH, std->clamp_width);
err |= tvp7000_write_reg(TVP7000_ALC_PLACEMENT, std->alc_placement);
return err;
}
static int tvp7000_selmux(void)
{
if (tvp7000_write_reg(TVP7000_INPUT_MUX_1, 0)) // set channel 1
return -1;
return 0;
}
static int input_signal_exist(void)
{
int val;
val = tvp7000_read_reg(TVP7000_SYNC_DETECT_STATUS);
if ((val & 0x80) && (val & 0x10))
{
return 0;
}
return -1;
}
static int tvp7000_device_cmd(u32 cmd, void *arg)
{
int ret = 0;
switch (cmd)
{
case 0:
case VIDIOC_INT_RESET:
tvp7000_device_init(NULL);
break;
case VIDIOC_G_INPUT:
{
if (!input_signal_exist())
*(int *)arg = VPFE_AMUX_COMPONENT;
else
ret = -EINVAL;
break;
}
case VIDIOC_S_INPUT:
{
int input = *(int *)arg;
if (input == VPFE_AMUX_COMPONENT)
{
if (tvp7000_device_init(NULL))
ret = -EBUSY;
}
else
ret = -EINVAL;
break;
}
case VPFE_CMD_CONFIG_CAPTURE:
{
struct vpfe_capture_params *params =
(struct vpfe_capture_params *)arg;
switch (params->mode)
{
case V4L2_STD_HD_480P:
ret = tvp7000_setup_video_standard(STD(VIDEO480P60HZ));
break;
case V4L2_STD_HD_576P:
ret = tvp7000_setup_video_standard(STD(VIDEO576P50HZ));
break;
case V4L2_STD_HD_720P:
ret = tvp7000_setup_video_standard(STD(VIDEO720P60HZ));
break;
case V4L2_STD_HD_1080I:
ret = tvp7000_setup_video_standard(STD(VIDEO1080I60HZ));
break;
default:
ret = -1;
}
break;
}
default:
ret = -EINVAL;
break;
}
return ret;
}
static int tvp7000_device_init(struct vpfe_capture_params *params)
{
u8 ver = 0;
FN_IN;
ver = tvp7000_read_reg(TVP7000_CHIP_REVISION);
DPRINTK("TVP7000 detect! Revision: %d\n", ver);
#if INIT_DEFAULT
/* initialize TVP7000 as its default values */
tvp7000_write_inittab(tvp7000_init_default, NUM_OF_REGS(tvp7000_init_default));
#endif
tvp7000_write_inittab(tvp7000_init_component, NUM_OF_REGS(tvp7000_init_component));
if (tvp7000_selmux())
return -1;
return 0;
}
static int tvp7000_device_active(void)
{
tvp7000_device_power_on(true);
return 0;
}
static int tvp7000_device_deactive(void)
{
tvp7000_device_power_on(false);
return 0;
}
static int tvp7000_device_cleanup(void)
{
/* do nothing */
return 0;
}
static struct vpfe_capture_device tvp7000_capture_device = {
.name = "TVP7000",
.id = VPFE_CAPTURE_ID_TVP7000,
.capture_device_init = tvp7000_device_init,
.capture_device_cmd = tvp7000_device_cmd,
.capture_device_active = tvp7000_device_active,
.capture_device_deactive = tvp7000_device_deactive,
.capture_device_cleanup = tvp7000_device_cleanup,
};
static __init int tvp7000_init(void)
{
int i;
int err = 0;
FN_IN;
/* power on the tvp7000 Video decoder*/
tvp7000_device_power_on(true);
mdelay(500);
for (i = 0; i < TVP7000_I2C_RETRY; i++)
{
err = i2c_add_driver(&tvp7000_driver);
if (!err)
{
break;
}
}
if (err)
{
DPRINTK("I2C driver %s add failed\n",
tvp7000_driver.driver.name);
return err;
}
err = vpfe_capture_device_register(&tvp7000_capture_device);
if (err)
{
DPRINTK("VPFE Capture Device %s register failed\n",
tvp7000_capture_device.name);
return err;
}
tvp7000_device_power_on(false);
return 0;
}
static __exit void tvp7000_exit(void)
{
FN_IN;
/* power down the tvp7000 Video decoder*/
tvp7000_device_power_on(false);
vpfe_capture_device_unregister(&tvp7000_capture_device);
i2c_del_driver(&tvp7000_driver);
}
module_init(tvp7000_init);
module_exit(tvp7000_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -