Commit c5ef8f8c authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Mauro Carvalho Chehab

[media] adv7180: Add support for the adv7182

This patch adds support for the adv7182 to the adv7180 driver. The adv7182
is similar to the adv7180, the main difference from the driver's point of
view is how the video input and how the input format are selected.
Signed-off-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Acked-by: default avatarFederico Vaga <federico.vaga@gmail.com>
Acked-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent f5dde49b
...@@ -52,6 +52,8 @@ ...@@ -52,6 +52,8 @@
#define ADV7180_REG_INPUT_CONTROL 0x0000 #define ADV7180_REG_INPUT_CONTROL 0x0000
#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f
#define ADV7182_REG_INPUT_VIDSEL 0x0002
#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004
#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
...@@ -134,6 +136,25 @@ ...@@ -134,6 +136,25 @@
#define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09
#define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a
#define ADV7182_INPUT_CVBS_AIN1 0x00
#define ADV7182_INPUT_CVBS_AIN2 0x01
#define ADV7182_INPUT_CVBS_AIN3 0x02
#define ADV7182_INPUT_CVBS_AIN4 0x03
#define ADV7182_INPUT_CVBS_AIN5 0x04
#define ADV7182_INPUT_CVBS_AIN6 0x05
#define ADV7182_INPUT_CVBS_AIN7 0x06
#define ADV7182_INPUT_CVBS_AIN8 0x07
#define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08
#define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09
#define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a
#define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b
#define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c
#define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d
#define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e
#define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f
#define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10
#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
struct adv7180_state; struct adv7180_state;
#define ADV7180_FLAG_RESET_POWERED BIT(0) #define ADV7180_FLAG_RESET_POWERED BIT(0)
...@@ -614,6 +635,118 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input) ...@@ -614,6 +635,118 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret); return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret);
} }
static int adv7182_init(struct adv7180_state *state)
{
/* ADI required writes */
adv7180_write(state, 0x0003, 0x0c);
adv7180_write(state, 0x0004, 0x07);
adv7180_write(state, 0x0013, 0x00);
adv7180_write(state, 0x001d, 0x40);
return 0;
}
static int adv7182_set_std(struct adv7180_state *state, unsigned int std)
{
return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4);
}
enum adv7182_input_type {
ADV7182_INPUT_TYPE_CVBS,
ADV7182_INPUT_TYPE_DIFF_CVBS,
ADV7182_INPUT_TYPE_SVIDEO,
ADV7182_INPUT_TYPE_YPBPR,
};
static enum adv7182_input_type adv7182_get_input_type(unsigned int input)
{
switch (input) {
case ADV7182_INPUT_CVBS_AIN1:
case ADV7182_INPUT_CVBS_AIN2:
case ADV7182_INPUT_CVBS_AIN3:
case ADV7182_INPUT_CVBS_AIN4:
case ADV7182_INPUT_CVBS_AIN5:
case ADV7182_INPUT_CVBS_AIN6:
case ADV7182_INPUT_CVBS_AIN7:
case ADV7182_INPUT_CVBS_AIN8:
return ADV7182_INPUT_TYPE_CVBS;
case ADV7182_INPUT_SVIDEO_AIN1_AIN2:
case ADV7182_INPUT_SVIDEO_AIN3_AIN4:
case ADV7182_INPUT_SVIDEO_AIN5_AIN6:
case ADV7182_INPUT_SVIDEO_AIN7_AIN8:
return ADV7182_INPUT_TYPE_SVIDEO;
case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3:
case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6:
return ADV7182_INPUT_TYPE_YPBPR;
case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2:
case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4:
case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6:
case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8:
return ADV7182_INPUT_TYPE_DIFF_CVBS;
default: /* Will never happen */
return 0;
}
}
/* ADI recommended writes to registers 0x52, 0x53, 0x54 */
static unsigned int adv7182_lbias_settings[][3] = {
[ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 },
[ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
[ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
[ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
};
static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
{
enum adv7182_input_type input_type;
unsigned int *lbias;
unsigned int i;
int ret;
ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input);
if (ret)
return ret;
/* Reset clamp circuitry - ADI recommended writes */
adv7180_write(state, 0x809c, 0x00);
adv7180_write(state, 0x809c, 0xff);
input_type = adv7182_get_input_type(input);
switch (input_type) {
case ADV7182_INPUT_TYPE_CVBS:
case ADV7182_INPUT_TYPE_DIFF_CVBS:
/* ADI recommends to use the SH1 filter */
adv7180_write(state, 0x0017, 0x41);
break;
default:
adv7180_write(state, 0x0017, 0x01);
break;
}
lbias = adv7182_lbias_settings[input_type];
for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++)
adv7180_write(state, 0x0052 + i, lbias[i]);
if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) {
/* ADI required writes to make differential CVBS work */
adv7180_write(state, 0x005f, 0xa8);
adv7180_write(state, 0x005a, 0x90);
adv7180_write(state, 0x0060, 0xb0);
adv7180_write(state, 0x80b6, 0x08);
adv7180_write(state, 0x80c0, 0xa0);
} else {
adv7180_write(state, 0x005f, 0xf0);
adv7180_write(state, 0x005a, 0xd0);
adv7180_write(state, 0x0060, 0x10);
adv7180_write(state, 0x80b6, 0x9c);
adv7180_write(state, 0x80c0, 0x00);
}
return 0;
}
static const struct adv7180_chip_info adv7180_info = { static const struct adv7180_chip_info adv7180_info = {
.flags = ADV7180_FLAG_RESET_POWERED, .flags = ADV7180_FLAG_RESET_POWERED,
/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
...@@ -635,6 +768,21 @@ static const struct adv7180_chip_info adv7180_info = { ...@@ -635,6 +768,21 @@ static const struct adv7180_chip_info adv7180_info = {
.select_input = adv7180_select_input, .select_input = adv7180_select_input,
}; };
static const struct adv7180_chip_info adv7182_info = {
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN3) |
BIT(ADV7182_INPUT_CVBS_AIN4) |
BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4),
.init = adv7182_init,
.set_std = adv7182_set_std,
.select_input = adv7182_select_input,
};
static int init_device(struct adv7180_state *state) static int init_device(struct adv7180_state *state)
{ {
int ret; int ret;
...@@ -777,6 +925,7 @@ static int adv7180_remove(struct i2c_client *client) ...@@ -777,6 +925,7 @@ static int adv7180_remove(struct i2c_client *client)
static const struct i2c_device_id adv7180_id[] = { static const struct i2c_device_id adv7180_id[] = {
{ "adv7180", (kernel_ulong_t)&adv7180_info }, { "adv7180", (kernel_ulong_t)&adv7180_info },
{ "adv7182", (kernel_ulong_t)&adv7182_info },
{}, {},
}; };
MODULE_DEVICE_TABLE(i2c, adv7180_id); MODULE_DEVICE_TABLE(i2c, adv7180_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment