diff options
Diffstat (limited to 'arch/arm/mach-davinci/board-dm646x-evm.c')
-rw-r--r-- | arch/arm/mach-davinci/board-dm646x-evm.c | 319 |
1 files changed, 318 insertions, 1 deletions
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 20547049b489..24e0e13b1492 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -34,6 +34,8 @@ #include <linux/i2c/pcf857x.h> #include <linux/etherdevice.h> +#include <media/tvp514x.h> + #include <asm/setup.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -62,6 +64,30 @@ #define DM646X_EVM_PHY_MASK (0x2) #define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ +#define VIDCLKCTL_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x38) +#define VSCLKDIS_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x6c) +#define VCH2CLK_MASK (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8)) +#define VCH2CLK_SYSCLK8 (BIT(9)) +#define VCH2CLK_AUXCLK (BIT(9) | BIT(8)) +#define VCH3CLK_MASK (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12)) +#define VCH3CLK_SYSCLK8 (BIT(13)) +#define VCH3CLK_AUXCLK (BIT(14) | BIT(13)) + +#define VIDCH2CLK (BIT(10)) +#define VIDCH3CLK (BIT(11)) +#define VIDCH1CLK (BIT(4)) +#define TVP7002_INPUT (BIT(4)) +#define TVP5147_INPUT (~BIT(4)) +#define VPIF_INPUT_ONE_CHANNEL (BIT(5)) +#define VPIF_INPUT_TWO_CHANNEL (~BIT(5)) +#define TVP5147_CH0 "tvp514x-0" +#define TVP5147_CH1 "tvp514x-1" + +static void __iomem *vpif_vidclkctl_reg; +static void __iomem *vpif_vsclkdis_reg; +/* spin lock for updating above registers */ +static spinlock_t vpif_reg_lock; + static struct davinci_uart_config uart_config __initdata = { .enabled_uarts = (1 << 0), }; @@ -287,6 +313,40 @@ static struct snd_platform_data dm646x_evm_snd_data[] = { }, }; +static struct i2c_client *cpld_client; + +static int cpld_video_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + cpld_client = client; + return 0; +} + +static int __devexit cpld_video_remove(struct i2c_client *client) +{ + cpld_client = NULL; + return 0; +} + +static const struct i2c_device_id cpld_video_id[] = { + { "cpld_video", 0 }, + { } +}; + +static struct i2c_driver cpld_video_driver = { + .driver = { + .name = "cpld_video", + }, + .probe = cpld_video_probe, + .remove = cpld_video_remove, + .id_table = cpld_video_id, +}; + +static void evm_init_cpld(void) +{ + i2c_add_driver(&cpld_video_driver); +} + static struct i2c_board_info __initdata i2c_info[] = { { I2C_BOARD_INFO("24c256", 0x50), @@ -301,7 +361,10 @@ static struct i2c_board_info __initdata i2c_info[] = { }, { I2C_BOARD_INFO("tlv320aic33", 0x18), - } + }, + { + I2C_BOARD_INFO("cpld_video", 0x3b), + }, }; static struct davinci_i2c_platform_data i2c_pdata = { @@ -309,11 +372,265 @@ static struct davinci_i2c_platform_data i2c_pdata = { .bus_delay = 0 /* usec */, }; +static int set_vpif_clock(int mux_mode, int hd) +{ + unsigned long flags; + unsigned int value; + int val = 0; + int err = 0; + + if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg || !cpld_client) + return -ENXIO; + + /* disable the clock */ + spin_lock_irqsave(&vpif_reg_lock, flags); + value = __raw_readl(vpif_vsclkdis_reg); + value |= (VIDCH3CLK | VIDCH2CLK); + __raw_writel(value, vpif_vsclkdis_reg); + spin_unlock_irqrestore(&vpif_reg_lock, flags); + + val = i2c_smbus_read_byte(cpld_client); + if (val < 0) + return val; + + if (mux_mode == 1) + val &= ~0x40; + else + val |= 0x40; + + err = i2c_smbus_write_byte(cpld_client, val); + if (err) + return err; + + value = __raw_readl(vpif_vidclkctl_reg); + value &= ~(VCH2CLK_MASK); + value &= ~(VCH3CLK_MASK); + + if (hd >= 1) + value |= (VCH2CLK_SYSCLK8 | VCH3CLK_SYSCLK8); + else + value |= (VCH2CLK_AUXCLK | VCH3CLK_AUXCLK); + + __raw_writel(value, vpif_vidclkctl_reg); + + spin_lock_irqsave(&vpif_reg_lock, flags); + value = __raw_readl(vpif_vsclkdis_reg); + /* enable the clock */ + value &= ~(VIDCH3CLK | VIDCH2CLK); + __raw_writel(value, vpif_vsclkdis_reg); + spin_unlock_irqrestore(&vpif_reg_lock, flags); + + return 0; +} + +static struct vpif_subdev_info dm646x_vpif_subdev[] = { + { + .name = "adv7343", + .board_info = { + I2C_BOARD_INFO("adv7343", 0x2a), + }, + }, + { + .name = "ths7303", + .board_info = { + I2C_BOARD_INFO("ths7303", 0x2c), + }, + }, +}; + +static const char *output[] = { + "Composite", + "Component", + "S-Video", +}; + +static struct vpif_display_config dm646x_vpif_display_config = { + .set_clock = set_vpif_clock, + .subdevinfo = dm646x_vpif_subdev, + .subdev_count = ARRAY_SIZE(dm646x_vpif_subdev), + .output = output, + .output_count = ARRAY_SIZE(output), + .card_name = "DM646x EVM", +}; + +/** + * setup_vpif_input_path() + * @channel: channel id (0 - CH0, 1 - CH1) + * @sub_dev_name: ptr sub device name + * + * This will set vpif input to capture data from tvp514x or + * tvp7002. + */ +static int setup_vpif_input_path(int channel, const char *sub_dev_name) +{ + int err = 0; + int val; + + /* for channel 1, we don't do anything */ + if (channel != 0) + return 0; + + if (!cpld_client) + return -ENXIO; + + val = i2c_smbus_read_byte(cpld_client); + if (val < 0) + return val; + + if (!strcmp(sub_dev_name, TVP5147_CH0) || + !strcmp(sub_dev_name, TVP5147_CH1)) + val &= TVP5147_INPUT; + else + val |= TVP7002_INPUT; + + err = i2c_smbus_write_byte(cpld_client, val); + if (err) + return err; + return 0; +} + +/** + * setup_vpif_input_channel_mode() + * @mux_mode: mux mode. 0 - 1 channel or (1) - 2 channel + * + * This will setup input mode to one channel (TVP7002) or 2 channel (TVP5147) + */ +static int setup_vpif_input_channel_mode(int mux_mode) +{ + unsigned long flags; + int err = 0; + int val; + u32 value; + + if (!vpif_vsclkdis_reg || !cpld_client) + return -ENXIO; + + val = i2c_smbus_read_byte(cpld_client); + if (val < 0) + return val; + + spin_lock_irqsave(&vpif_reg_lock, flags); + value = __raw_readl(vpif_vsclkdis_reg); + if (mux_mode) { + val &= VPIF_INPUT_TWO_CHANNEL; + value |= VIDCH1CLK; + } else { + val |= VPIF_INPUT_ONE_CHANNEL; + value &= ~VIDCH1CLK; + } + __raw_writel(value, vpif_vsclkdis_reg); + spin_unlock_irqrestore(&vpif_reg_lock, flags); + + err = i2c_smbus_write_byte(cpld_client, val); + if (err) + return err; + + return 0; +} + +static struct tvp514x_platform_data tvp5146_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1 +}; + +#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +static struct vpif_subdev_info vpif_capture_sdev_info[] = { + { + .name = TVP5147_CH0, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5d), + .platform_data = &tvp5146_pdata, + }, + .input = INPUT_CVBS_VI2B, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .can_route = 1, + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + { + .name = TVP5147_CH1, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5c), + .platform_data = &tvp5146_pdata, + }, + .input = INPUT_SVIDEO_VI2C_VI1C, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .can_route = 1, + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, +}; + +static const struct vpif_input dm6467_ch0_inputs[] = { + { + .input = { + .index = 0, + .name = "Composite", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, + .subdev_name = TVP5147_CH0, + }, +}; + +static const struct vpif_input dm6467_ch1_inputs[] = { + { + .input = { + .index = 0, + .name = "S-Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, + .subdev_name = TVP5147_CH1, + }, +}; + +static struct vpif_capture_config dm646x_vpif_capture_cfg = { + .setup_input_path = setup_vpif_input_path, + .setup_input_channel_mode = setup_vpif_input_channel_mode, + .subdev_info = vpif_capture_sdev_info, + .subdev_count = ARRAY_SIZE(vpif_capture_sdev_info), + .chan_config[0] = { + .inputs = dm6467_ch0_inputs, + .input_count = ARRAY_SIZE(dm6467_ch0_inputs), + }, + .chan_config[1] = { + .inputs = dm6467_ch1_inputs, + .input_count = ARRAY_SIZE(dm6467_ch1_inputs), + }, +}; + +static void __init evm_init_video(void) +{ + vpif_vidclkctl_reg = ioremap(VIDCLKCTL_OFFSET, 4); + vpif_vsclkdis_reg = ioremap(VSCLKDIS_OFFSET, 4); + if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg) { + pr_err("Can't map VPIF VIDCLKCTL or VSCLKDIS registers\n"); + return; + } + spin_lock_init(&vpif_reg_lock); + + dm646x_setup_vpif(&dm646x_vpif_display_config, + &dm646x_vpif_capture_cfg); +} + static void __init evm_init_i2c(void) { davinci_init_i2c(&i2c_pdata); i2c_add_driver(&dm6467evm_cpld_driver); i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); + evm_init_cpld(); + evm_init_video(); } static void __init davinci_map_io(void) |