aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2015-01-23 10:52:28 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-02-02 08:47:19 -0500
commitf5dde49b8f362bdc53dbdbd3a579fac5e66d878d (patch)
tree9b434045d1f0d648c724639f3e11e10b8794f4e2 /drivers/media/i2c
parent3e35e33c086ca81e0576ad1ace22ca058d071b2c (diff)
[media] adv7180: Prepare for multi-chip support
The adv7180 is part of a larger family of device, which have all a very similar register map layout. This patch prepares the adv7180 driver for support for multiple different devices. For now the only difference we care about is the number of input channel configurations. Also the way the input format is configured slightly differs between some devices. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Federico Vaga <federico.vaga@gmail.com> Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r--drivers/media/i2c/adv7180.c187
1 files changed, 130 insertions, 57 deletions
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 363d8d98914c..170c2fcceb00 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -32,23 +32,24 @@
32#include <linux/mutex.h> 32#include <linux/mutex.h>
33#include <linux/delay.h> 33#include <linux/delay.h>
34 34
35#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0
36#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1
37#define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2
38#define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3
39#define ADV7180_STD_NTSC_J 0x4
40#define ADV7180_STD_NTSC_M 0x5
41#define ADV7180_STD_PAL60 0x6
42#define ADV7180_STD_NTSC_443 0x7
43#define ADV7180_STD_PAL_BG 0x8
44#define ADV7180_STD_PAL_N 0x9
45#define ADV7180_STD_PAL_M 0xa
46#define ADV7180_STD_PAL_M_PED 0xb
47#define ADV7180_STD_PAL_COMB_N 0xc
48#define ADV7180_STD_PAL_COMB_N_PED 0xd
49#define ADV7180_STD_PAL_SECAM 0xe
50#define ADV7180_STD_PAL_SECAM_PED 0xf
51
35#define ADV7180_REG_INPUT_CONTROL 0x0000 52#define ADV7180_REG_INPUT_CONTROL 0x0000
36#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
37#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
38#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20
39#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30
40#define ADV7180_INPUT_CONTROL_NTSC_J 0x40
41#define ADV7180_INPUT_CONTROL_NTSC_M 0x50
42#define ADV7180_INPUT_CONTROL_PAL60 0x60
43#define ADV7180_INPUT_CONTROL_NTSC_443 0x70
44#define ADV7180_INPUT_CONTROL_PAL_BG 0x80
45#define ADV7180_INPUT_CONTROL_PAL_N 0x90
46#define ADV7180_INPUT_CONTROL_PAL_M 0xa0
47#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0
48#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0
49#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0
50#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0
51#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0
52#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f 53#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f
53 54
54#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 55#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004
@@ -121,6 +122,30 @@
121#define ADV7180_REG_NTSC_V_BIT_END 0x00E6 122#define ADV7180_REG_NTSC_V_BIT_END 0x00E6
122#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 123#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F
123 124
125#define ADV7180_INPUT_CVBS_AIN1 0x00
126#define ADV7180_INPUT_CVBS_AIN2 0x01
127#define ADV7180_INPUT_CVBS_AIN3 0x02
128#define ADV7180_INPUT_CVBS_AIN4 0x03
129#define ADV7180_INPUT_CVBS_AIN5 0x04
130#define ADV7180_INPUT_CVBS_AIN6 0x05
131#define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06
132#define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07
133#define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08
134#define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09
135#define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a
136
137struct adv7180_state;
138
139#define ADV7180_FLAG_RESET_POWERED BIT(0)
140
141struct adv7180_chip_info {
142 unsigned int flags;
143 unsigned int valid_input_mask;
144 int (*set_std)(struct adv7180_state *st, unsigned int std);
145 int (*select_input)(struct adv7180_state *st, unsigned int input);
146 int (*init)(struct adv7180_state *state);
147};
148
124struct adv7180_state { 149struct adv7180_state {
125 struct v4l2_ctrl_handler ctrl_hdl; 150 struct v4l2_ctrl_handler ctrl_hdl;
126 struct v4l2_subdev sd; 151 struct v4l2_subdev sd;
@@ -134,6 +159,7 @@ struct adv7180_state {
134 159
135 struct i2c_client *client; 160 struct i2c_client *client;
136 unsigned int register_page; 161 unsigned int register_page;
162 const struct adv7180_chip_info *chip_info;
137}; 163};
138#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ 164#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
139 struct adv7180_state, \ 165 struct adv7180_state, \
@@ -165,6 +191,11 @@ static int adv7180_read(struct adv7180_state *state, unsigned int reg)
165 return i2c_smbus_read_byte_data(state->client, reg & 0xff); 191 return i2c_smbus_read_byte_data(state->client, reg & 0xff);
166} 192}
167 193
194static int adv7180_set_video_standard(struct adv7180_state *state,
195 unsigned int std)
196{
197 return state->chip_info->set_std(state, std);
198}
168 199
169static v4l2_std_id adv7180_std_to_v4l2(u8 status1) 200static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
170{ 201{
@@ -197,22 +228,22 @@ static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
197static int v4l2_std_to_adv7180(v4l2_std_id std) 228static int v4l2_std_to_adv7180(v4l2_std_id std)
198{ 229{
199 if (std == V4L2_STD_PAL_60) 230 if (std == V4L2_STD_PAL_60)
200 return ADV7180_INPUT_CONTROL_PAL60; 231 return ADV7180_STD_PAL60;
201 if (std == V4L2_STD_NTSC_443) 232 if (std == V4L2_STD_NTSC_443)
202 return ADV7180_INPUT_CONTROL_NTSC_443; 233 return ADV7180_STD_NTSC_443;
203 if (std == V4L2_STD_PAL_N) 234 if (std == V4L2_STD_PAL_N)
204 return ADV7180_INPUT_CONTROL_PAL_N; 235 return ADV7180_STD_PAL_N;
205 if (std == V4L2_STD_PAL_M) 236 if (std == V4L2_STD_PAL_M)
206 return ADV7180_INPUT_CONTROL_PAL_M; 237 return ADV7180_STD_PAL_M;
207 if (std == V4L2_STD_PAL_Nc) 238 if (std == V4L2_STD_PAL_Nc)
208 return ADV7180_INPUT_CONTROL_PAL_COMB_N; 239 return ADV7180_STD_PAL_COMB_N;
209 240
210 if (std & V4L2_STD_PAL) 241 if (std & V4L2_STD_PAL)
211 return ADV7180_INPUT_CONTROL_PAL_BG; 242 return ADV7180_STD_PAL_BG;
212 if (std & V4L2_STD_NTSC) 243 if (std & V4L2_STD_NTSC)
213 return ADV7180_INPUT_CONTROL_NTSC_M; 244 return ADV7180_STD_NTSC_M;
214 if (std & V4L2_STD_SECAM) 245 if (std & V4L2_STD_SECAM)
215 return ADV7180_INPUT_CONTROL_PAL_SECAM; 246 return ADV7180_STD_PAL_SECAM;
216 247
217 return -EINVAL; 248 return -EINVAL;
218} 249}
@@ -272,19 +303,15 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
272 if (ret) 303 if (ret)
273 return ret; 304 return ret;
274 305
275 /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept 306 if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) {
276 * all inputs and let the card driver take care of validation 307 ret = -EINVAL;
277 */
278 if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
279 goto out; 308 goto out;
309 }
280 310
281 ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL); 311 ret = state->chip_info->select_input(state, input);
282 if (ret < 0)
283 goto out;
284 312
285 ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; 313 if (ret == 0)
286 ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret | input); 314 state->input = input;
287 state->input = input;
288out: 315out:
289 mutex_unlock(&state->mutex); 316 mutex_unlock(&state->mutex);
290 return ret; 317 return ret;
@@ -307,9 +334,8 @@ static int adv7180_program_std(struct adv7180_state *state)
307 int ret; 334 int ret;
308 335
309 if (state->autodetect) { 336 if (state->autodetect) {
310 ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 337 ret = adv7180_set_video_standard(state,
311 ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 338 ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
312 | state->input);
313 if (ret < 0) 339 if (ret < 0)
314 return ret; 340 return ret;
315 341
@@ -319,8 +345,7 @@ static int adv7180_program_std(struct adv7180_state *state)
319 if (ret < 0) 345 if (ret < 0)
320 return ret; 346 return ret;
321 347
322 ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 348 ret = adv7180_set_video_standard(state, ret);
323 ret | state->input);
324 if (ret < 0) 349 if (ret < 0)
325 return ret; 350 return ret;
326 } 351 }
@@ -521,6 +546,7 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
521 .g_mbus_config = adv7180_g_mbus_config, 546 .g_mbus_config = adv7180_g_mbus_config,
522}; 547};
523 548
549
524static const struct v4l2_subdev_core_ops adv7180_core_ops = { 550static const struct v4l2_subdev_core_ops adv7180_core_ops = {
525 .s_power = adv7180_s_power, 551 .s_power = adv7180_s_power,
526}; 552};
@@ -554,33 +580,77 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
554 return IRQ_HANDLED; 580 return IRQ_HANDLED;
555} 581}
556 582
557static int init_device(struct adv7180_state *state) 583static int adv7180_init(struct adv7180_state *state)
558{ 584{
559 int ret; 585 int ret;
560 586
561 mutex_lock(&state->mutex);
562
563 adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
564 usleep_range(2000, 10000);
565
566 ret = adv7180_program_std(state);
567 if (ret)
568 goto out_unlock;
569
570 /* ITU-R BT.656-4 compatible */ 587 /* ITU-R BT.656-4 compatible */
571 ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 588 ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
572 ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); 589 ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
573 if (ret < 0) 590 if (ret < 0)
574 goto out_unlock; 591 return ret;
575 592
576 /* Manually set V bit end position in NTSC mode */ 593 /* Manually set V bit end position in NTSC mode */
577 ret = adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END, 594 return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END,
578 ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); 595 ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
596}
597
598static int adv7180_set_std(struct adv7180_state *state, unsigned int std)
599{
600 return adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
601 (std << 4) | state->input);
602}
603
604static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
605{
606 int ret;
607
608 ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
579 if (ret < 0) 609 if (ret < 0)
610 return ret;
611
612 ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
613 ret |= input;
614 return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret);
615}
616
617static const struct adv7180_chip_info adv7180_info = {
618 .flags = ADV7180_FLAG_RESET_POWERED,
619 /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
620 * all inputs and let the card driver take care of validation
621 */
622 .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) |
623 BIT(ADV7180_INPUT_CVBS_AIN2) |
624 BIT(ADV7180_INPUT_CVBS_AIN3) |
625 BIT(ADV7180_INPUT_CVBS_AIN4) |
626 BIT(ADV7180_INPUT_CVBS_AIN5) |
627 BIT(ADV7180_INPUT_CVBS_AIN6) |
628 BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) |
629 BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) |
630 BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) |
631 BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) |
632 BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6),
633 .init = adv7180_init,
634 .set_std = adv7180_set_std,
635 .select_input = adv7180_select_input,
636};
637
638static int init_device(struct adv7180_state *state)
639{
640 int ret;
641
642 mutex_lock(&state->mutex);
643
644 adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
645 usleep_range(2000, 10000);
646
647 ret = state->chip_info->init(state);
648 if (ret)
580 goto out_unlock; 649 goto out_unlock;
581 650
582 /* read current norm */ 651 ret = adv7180_program_std(state);
583 __adv7180_status(state, NULL, &state->curr_norm); 652 if (ret)
653 goto out_unlock;
584 654
585 /* register for interrupts */ 655 /* register for interrupts */
586 if (state->irq > 0) { 656 if (state->irq > 0) {
@@ -635,11 +705,15 @@ static int adv7180_probe(struct i2c_client *client,
635 return -ENOMEM; 705 return -ENOMEM;
636 706
637 state->client = client; 707 state->client = client;
708 state->chip_info = (struct adv7180_chip_info *)id->driver_data;
638 709
639 state->irq = client->irq; 710 state->irq = client->irq;
640 mutex_init(&state->mutex); 711 mutex_init(&state->mutex);
641 state->autodetect = true; 712 state->autodetect = true;
642 state->powered = true; 713 if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
714 state->powered = true;
715 else
716 state->powered = false;
643 state->input = 0; 717 state->input = 0;
644 sd = &state->sd; 718 sd = &state->sd;
645 v4l2_i2c_subdev_init(sd, client, &adv7180_ops); 719 v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
@@ -702,9 +776,10 @@ static int adv7180_remove(struct i2c_client *client)
702} 776}
703 777
704static const struct i2c_device_id adv7180_id[] = { 778static const struct i2c_device_id adv7180_id[] = {
705 {KBUILD_MODNAME, 0}, 779 { "adv7180", (kernel_ulong_t)&adv7180_info },
706 {}, 780 {},
707}; 781};
782MODULE_DEVICE_TABLE(i2c, adv7180_id);
708 783
709#ifdef CONFIG_PM_SLEEP 784#ifdef CONFIG_PM_SLEEP
710static int adv7180_suspend(struct device *dev) 785static int adv7180_suspend(struct device *dev)
@@ -741,8 +816,6 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
741#define ADV7180_PM_OPS NULL 816#define ADV7180_PM_OPS NULL
742#endif 817#endif
743 818
744MODULE_DEVICE_TABLE(i2c, adv7180_id);
745
746static struct i2c_driver adv7180_driver = { 819static struct i2c_driver adv7180_driver = {
747 .driver = { 820 .driver = {
748 .owner = THIS_MODULE, 821 .owner = THIS_MODULE,