aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-02-21 16:42:49 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:01 -0400
commiteefe1010a4657959588afc7fb3551cfa4e8bb4a7 (patch)
treea23ed1195505ce5be7cf9687bfe553ff6fa36dbc /drivers
parentff2a20018094c593a35f4887bbdabf8926ddb6e6 (diff)
V4L/DVB (10759): cx18: Convert GPIO connected functions to act as v4l2_subdevices
Convert GPIO line functions, such a audio routing and device resets, to v4l2_subdevices. This essentially completes the conversion of cx18 to the v4l2_device/v4l2_subdevice framework. No regression testing has taken place as of yet. Also an ivtv legacy bug with GPIO mux routing and going to/from radio mode was commented, but not fixed. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/cx18/cx18-cards.c19
-rw-r--r--drivers/media/video/cx18/cx18-cards.h3
-rw-r--r--drivers/media/video/cx18/cx18-controls.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c22
-rw-r--r--drivers/media/video/cx18/cx18-driver.h4
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c319
-rw-r--r--drivers/media/video/cx18/cx18-gpio.h10
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c16
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c3
-rw-r--r--drivers/media/video/cx18/cx18-streams.c1
-rw-r--r--drivers/media/video/cx18/cx18-vbi.c1
-rw-r--r--drivers/media/video/cx18/cx18-video.c1
12 files changed, 278 insertions, 123 deletions
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 6644534db564..9bc221837847 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -56,7 +56,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
56 .hw_audio_ctrl = CX18_HW_418_AV, 56 .hw_audio_ctrl = CX18_HW_418_AV,
57 .hw_muxer = CX18_HW_CS5345, 57 .hw_muxer = CX18_HW_CS5345,
58 .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | 58 .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
59 CX18_HW_CS5345 | CX18_HW_DVB, 59 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
60 .video_inputs = { 60 .video_inputs = {
61 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, 61 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
62 { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, 62 { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
@@ -102,7 +102,7 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
102 .hw_audio_ctrl = CX18_HW_418_AV, 102 .hw_audio_ctrl = CX18_HW_418_AV,
103 .hw_muxer = CX18_HW_CS5345, 103 .hw_muxer = CX18_HW_CS5345,
104 .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | 104 .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
105 CX18_HW_CS5345 | CX18_HW_DVB, 105 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
106 .video_inputs = { 106 .video_inputs = {
107 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, 107 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
108 { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, 108 { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
@@ -155,7 +155,7 @@ static const struct cx18_card cx18_card_h900 = {
155 .comment = "Analog TV capture supported\n", 155 .comment = "Analog TV capture supported\n",
156 .v4l2_capabilities = CX18_CAP_ENCODER, 156 .v4l2_capabilities = CX18_CAP_ENCODER,
157 .hw_audio_ctrl = CX18_HW_418_AV, 157 .hw_audio_ctrl = CX18_HW_418_AV,
158 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER, 158 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
159 .video_inputs = { 159 .video_inputs = {
160 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, 160 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
161 { CX18_CARD_INPUT_SVIDEO1, 1, 161 { CX18_CARD_INPUT_SVIDEO1, 1,
@@ -202,7 +202,7 @@ static const struct cx18_card cx18_card_mpc718 = {
202 .comment = "Analog video capture works; some audio line in may not.\n", 202 .comment = "Analog video capture works; some audio line in may not.\n",
203 .v4l2_capabilities = CX18_CAP_ENCODER, 203 .v4l2_capabilities = CX18_CAP_ENCODER,
204 .hw_audio_ctrl = CX18_HW_418_AV, 204 .hw_audio_ctrl = CX18_HW_418_AV,
205 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER, 205 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
206 .video_inputs = { 206 .video_inputs = {
207 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, 207 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
208 { CX18_CARD_INPUT_SVIDEO1, 1, 208 { CX18_CARD_INPUT_SVIDEO1, 1,
@@ -252,8 +252,8 @@ static const struct cx18_card cx18_card_cnxt_raptor_pal = {
252 .comment = "Analog TV capture supported\n", 252 .comment = "Analog TV capture supported\n",
253 .v4l2_capabilities = CX18_CAP_ENCODER, 253 .v4l2_capabilities = CX18_CAP_ENCODER,
254 .hw_audio_ctrl = CX18_HW_418_AV, 254 .hw_audio_ctrl = CX18_HW_418_AV,
255 .hw_muxer = CX18_HW_GPIO_AUDIO_MUX, 255 .hw_muxer = CX18_HW_GPIO_MUX,
256 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_AUDIO_MUX, 256 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX,
257 .video_inputs = { 257 .video_inputs = {
258 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, 258 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
259 { CX18_CARD_INPUT_SVIDEO1, 1, 259 { CX18_CARD_INPUT_SVIDEO1, 1,
@@ -307,7 +307,7 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
307 "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", 307 "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
308 .v4l2_capabilities = CX18_CAP_ENCODER, 308 .v4l2_capabilities = CX18_CAP_ENCODER,
309 .hw_audio_ctrl = CX18_HW_418_AV, 309 .hw_audio_ctrl = CX18_HW_418_AV,
310 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER, 310 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
311 .video_inputs = { 311 .video_inputs = {
312 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 }, 312 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 },
313 { CX18_CARD_INPUT_SVIDEO1, 1, 313 { CX18_CARD_INPUT_SVIDEO1, 1,
@@ -351,8 +351,9 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
351 "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", 351 "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
352 .v4l2_capabilities = CX18_CAP_ENCODER, 352 .v4l2_capabilities = CX18_CAP_ENCODER,
353 .hw_audio_ctrl = CX18_HW_418_AV, 353 .hw_audio_ctrl = CX18_HW_418_AV,
354 .hw_muxer = CX18_HW_GPIO_AUDIO_MUX, 354 .hw_muxer = CX18_HW_GPIO_MUX,
355 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_AUDIO_MUX, 355 .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
356 CX18_HW_GPIO_RESET_CTRL,
356 .video_inputs = { 357 .video_inputs = {
357 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, 358 { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
358 { CX18_CARD_INPUT_SVIDEO1, 1, 359 { CX18_CARD_INPUT_SVIDEO1, 1,
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index bd7f9556f18c..3c552b6b7c4d 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -27,7 +27,8 @@
27#define CX18_HW_CS5345 (1 << 2) 27#define CX18_HW_CS5345 (1 << 2)
28#define CX18_HW_DVB (1 << 3) 28#define CX18_HW_DVB (1 << 3)
29#define CX18_HW_418_AV (1 << 4) 29#define CX18_HW_418_AV (1 << 4)
30#define CX18_HW_GPIO_AUDIO_MUX (1 << 5) 30#define CX18_HW_GPIO_MUX (1 << 5)
31#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
31 32
32/* video inputs */ 33/* video inputs */
33#define CX18_CARD_INPUT_VID_TUNER 1 34#define CX18_CARD_INPUT_VID_TUNER 1
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index e5604c2328ad..925e01fdbaa6 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -22,11 +22,9 @@
22 */ 22 */
23 23
24#include "cx18-driver.h" 24#include "cx18-driver.h"
25#include "cx18-av-core.h"
26#include "cx18-cards.h" 25#include "cx18-cards.h"
27#include "cx18-ioctl.h" 26#include "cx18-ioctl.h"
28#include "cx18-audio.h" 27#include "cx18-audio.h"
29#include "cx18-i2c.h"
30#include "cx18-mailbox.h" 28#include "cx18-mailbox.h"
31#include "cx18-controls.h" 29#include "cx18-controls.h"
32 30
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index edbb83c4c564..79b3bf5bcec1 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -684,7 +684,6 @@ static void cx18_init_subdevs(struct cx18 *cx)
684 continue; 684 continue;
685 685
686 switch (device) { 686 switch (device) {
687 case CX18_HW_GPIO_AUDIO_MUX:
688 case CX18_HW_DVB: 687 case CX18_HW_DVB:
689 case CX18_HW_TVEEPROM: 688 case CX18_HW_TVEEPROM:
690 /* These subordinate devices do not use probing */ 689 /* These subordinate devices do not use probing */
@@ -695,6 +694,16 @@ static void cx18_init_subdevs(struct cx18 *cx)
695 /* Just note that the card uses it (i.e. has analog) */ 694 /* Just note that the card uses it (i.e. has analog) */
696 cx->hw_flags |= device; 695 cx->hw_flags |= device;
697 break; 696 break;
697 case CX18_HW_GPIO_RESET_CTRL:
698 /*
699 * The Reset Controller gets probed and added to
700 * hw_flags earlier for i2c adapter/bus initialization
701 */
702 break;
703 case CX18_HW_GPIO_MUX:
704 if (cx18_gpio_register(cx, device) == 0)
705 cx->hw_flags |= device;
706 break;
698 default: 707 default:
699 if (cx18_i2c_register(cx, i) == 0) 708 if (cx18_i2c_register(cx, i) == 0)
700 cx->hw_flags |= device; 709 cx->hw_flags |= device;
@@ -793,7 +802,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
793 cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); 802 cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
794 cx18_init_scb(cx); 803 cx18_init_scb(cx);
795 804
796 /* Initialize GPIO early so I2C device resets can be performed */
797 cx18_gpio_init(cx); 805 cx18_gpio_init(cx);
798 806
799 /* Initialize integrated A/V decoder early to set PLLs, just in case */ 807 /* Initialize integrated A/V decoder early to set PLLs, just in case */
@@ -802,9 +810,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
802 CX18_ERR("Could not register A/V decoder subdevice\n"); 810 CX18_ERR("Could not register A/V decoder subdevice\n");
803 goto free_map; 811 goto free_map;
804 } 812 }
805 /* Initialize the A/V decoder PLLs to sane defaults */
806 cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS); 813 cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS);
807 814
815 /* Initialize GPIO Reset Controller to do chip resets during i2c init */
816 if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
817 if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0)
818 CX18_WARN("Could not register GPIO reset controller"
819 "subdevice; proceeding anyway.\n");
820 else
821 cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL;
822 }
823
808 /* active i2c */ 824 /* active i2c */
809 CX18_DEBUG_INFO("activating i2c...\n"); 825 CX18_DEBUG_INFO("activating i2c...\n");
810 retval = init_cx18_i2c(cx); 826 retval = init_cx18_i2c(cx);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b81106d682ae..9ee608063b49 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -449,7 +449,7 @@ struct cx18 {
449 struct pci_dev *pci_dev; 449 struct pci_dev *pci_dev;
450 struct v4l2_device v4l2_dev; 450 struct v4l2_device v4l2_dev;
451 struct v4l2_subdev *sd_av; /* A/V decoder/digitizer sub-device */ 451 struct v4l2_subdev *sd_av; /* A/V decoder/digitizer sub-device */
452 struct v4l2_subdev *sd_extmux; /* External audio multiplexer sub-dev */ 452 struct v4l2_subdev *sd_extmux; /* External multiplexer sub-dev */
453 453
454 const struct cx18_card *card; /* card information */ 454 const struct cx18_card *card; /* card information */
455 const char *card_name; /* full name of the card */ 455 const char *card_name; /* full name of the card */
@@ -534,6 +534,8 @@ struct cx18 {
534 u32 gpio_dir; 534 u32 gpio_dir;
535 u32 gpio_val; 535 u32 gpio_val;
536 struct mutex gpio_lock; 536 struct mutex gpio_lock;
537 struct v4l2_subdev sd_gpiomux;
538 struct v4l2_subdev sd_resetctrl;
537 539
538 /* v4l2 and User settings */ 540 /* v4l2 and User settings */
539 541
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index 1a99329f33cb..dcc19b1c541d 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -46,6 +46,9 @@
46 * gpio13: cs5345 reset pin 46 * gpio13: cs5345 reset pin
47*/ 47*/
48 48
49/*
50 * File scope utility functions
51 */
49static void gpio_write(struct cx18 *cx) 52static void gpio_write(struct cx18 *cx)
50{ 53{
51 u32 dir_lo = cx->gpio_dir & 0xffff; 54 u32 dir_lo = cx->gpio_dir & 0xffff;
@@ -63,73 +66,201 @@ static void gpio_write(struct cx18 *cx)
63 CX18_REG_GPIO_OUT2, val_hi, dir_hi); 66 CX18_REG_GPIO_OUT2, val_hi, dir_hi);
64} 67}
65 68
66void cx18_reset_i2c_slaves_gpio(struct cx18 *cx) 69static void gpio_update(struct cx18 *cx, u32 mask, u32 data)
67{ 70{
68 const struct cx18_gpio_i2c_slave_reset *p; 71 if (mask == 0)
72 return;
69 73
70 p = &cx->card->gpio_i2c_slave_reset; 74 mutex_lock(&cx->gpio_lock);
75 cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
76 gpio_write(cx);
77 mutex_unlock(&cx->gpio_lock);
78}
79
80static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi,
81 unsigned int assert_msecs,
82 unsigned int recovery_msecs)
83{
84 u32 mask;
71 85
72 if ((p->active_lo_mask | p->active_hi_mask) == 0) 86 mask = active_lo | active_hi;
87 if (mask == 0)
73 return; 88 return;
74 89
75 /* Assuming that the masks are a subset of the bits in gpio_dir */ 90 /*
91 * Assuming that active_hi and active_lo are a subsets of the bits in
92 * gpio_dir. Also assumes that active_lo and active_hi don't overlap
93 * in any bit position
94 */
76 95
77 /* Assert */ 96 /* Assert */
78 mutex_lock(&cx->gpio_lock); 97 gpio_update(cx, mask, ~active_lo);
79 cx->gpio_val = 98 schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs));
80 (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
81 gpio_write(cx);
82 schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
83 99
84 /* Deassert */ 100 /* Deassert */
85 cx->gpio_val = 101 gpio_update(cx, mask, ~active_hi);
86 (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask); 102 schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs));
87 gpio_write(cx); 103}
88 schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery)); 104
105/*
106 * GPIO Multiplexer - logical device
107 */
108static int gpiomux_log_status(struct v4l2_subdev *sd)
109{
110 struct cx18 *cx = v4l2_get_subdevdata(sd);
111
112 mutex_lock(&cx->gpio_lock);
113 CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n",
114 cx->gpio_dir, cx->gpio_val);
89 mutex_unlock(&cx->gpio_lock); 115 mutex_unlock(&cx->gpio_lock);
116 return 0;
90} 117}
91 118
92void cx18_reset_ir_gpio(void *data) 119static int gpiomux_s_radio(struct v4l2_subdev *sd)
93{ 120{
94 struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; 121 struct cx18 *cx = v4l2_get_subdevdata(sd);
95 const struct cx18_gpio_i2c_slave_reset *p;
96 122
97 p = &cx->card->gpio_i2c_slave_reset; 123 /*
124 * FIXME - work out the cx->active/audio_input mess - this is
125 * intended to handle the switch to radio mode and set the
126 * audio routing, but we need to update the state in cx
127 */
128 gpio_update(cx, cx->card->gpio_audio_input.mask,
129 cx->card->gpio_audio_input.radio);
130 return 0;
131}
98 132
99 if (p->ir_reset_mask == 0) 133static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
100 return; 134{
135 struct cx18 *cx = v4l2_get_subdevdata(sd);
136 u32 data;
101 137
102 CX18_DEBUG_INFO("Resetting IR microcontroller\n"); 138 switch (cx->card->audio_inputs[cx->audio_input].muxer_input) {
139 case 1:
140 data = cx->card->gpio_audio_input.linein;
141 break;
142 case 0:
143 data = cx->card->gpio_audio_input.tuner;
144 break;
145 default:
146 /*
147 * FIXME - work out the cx->active/audio_input mess - this is
148 * intended to handle the switch from radio mode and set the
149 * audio routing, but we need to update the state in cx
150 */
151 data = cx->card->gpio_audio_input.tuner;
152 break;
153 }
154 gpio_update(cx, cx->card->gpio_audio_input.mask, data);
155 return 0;
156}
103 157
104 /* 158static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
105 Assert timing for the Z8F0811 on HVR-1600 boards: 159 const struct v4l2_routing *route)
106 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate 160{
107 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles 161 struct cx18 *cx = v4l2_get_subdevdata(sd);
108 (6,601,085 nanoseconds ~= 7 milliseconds) 162 u32 data;
109 3. DBG pin must be high before chip exits reset for normal operation. 163
110 DBG is open drain and hopefully pulled high since we don't 164 switch (route->input) {
111 normally drive it (GPIO 1?) for the HVR-1600 165 case 0:
112 4. Z8F0811 won't exit reset until RESET is deasserted 166 data = cx->card->gpio_audio_input.tuner;
113 */ 167 break;
114 mutex_lock(&cx->gpio_lock); 168 case 1:
115 cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask; 169 data = cx->card->gpio_audio_input.linein;
116 gpio_write(cx); 170 break;
117 mutex_unlock(&cx->gpio_lock); 171 case 2:
118 schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted)); 172 data = cx->card->gpio_audio_input.radio;
173 break;
174 default:
175 return -EINVAL;
176 }
177 gpio_update(cx, cx->card->gpio_audio_input.mask, data);
178 return 0;
179}
180
181static const struct v4l2_subdev_core_ops gpiomux_core_ops = {
182 .log_status = gpiomux_log_status,
183};
184
185static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = {
186 .s_std = gpiomux_s_std,
187 .s_radio = gpiomux_s_radio,
188};
189
190static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = {
191 .s_routing = gpiomux_s_audio_routing,
192};
193
194static const struct v4l2_subdev_ops gpiomux_ops = {
195 .core = &gpiomux_core_ops,
196 .tuner = &gpiomux_tuner_ops,
197 .audio = &gpiomux_audio_ops,
198};
199
200/*
201 * GPIO Reset Controller - logical device
202 */
203static int resetctrl_log_status(struct v4l2_subdev *sd)
204{
205 struct cx18 *cx = v4l2_get_subdevdata(sd);
119 206
120 /*
121 Zilog comes out of reset, loads reset vector address and executes
122 from there. Required recovery delay unknown.
123 */
124 mutex_lock(&cx->gpio_lock); 207 mutex_lock(&cx->gpio_lock);
125 cx->gpio_val = cx->gpio_val | p->ir_reset_mask; 208 CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n",
126 gpio_write(cx); 209 cx->gpio_dir, cx->gpio_val);
127 mutex_unlock(&cx->gpio_lock); 210 mutex_unlock(&cx->gpio_lock);
128 schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery)); 211 return 0;
129} 212}
130EXPORT_SYMBOL(cx18_reset_ir_gpio);
131/* This symbol is exported for use by an infrared module for the IR-blaster */
132 213
214static int resetctrl_reset(struct v4l2_subdev *sd, u32 val)
215{
216 struct cx18 *cx = v4l2_get_subdevdata(sd);
217 const struct cx18_gpio_i2c_slave_reset *p;
218
219 p = &cx->card->gpio_i2c_slave_reset;
220 switch (val) {
221 case CX18_GPIO_RESET_I2C:
222 gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask,
223 p->msecs_asserted, p->msecs_recovery);
224 break;
225 case CX18_GPIO_RESET_Z8F0811:
226 /*
227 * Assert timing for the Z8F0811 on HVR-1600 boards:
228 * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to
229 * initiate
230 * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock
231 * cycles (6,601,085 nanoseconds ~= 7 milliseconds)
232 * 3. DBG pin must be high before chip exits reset for normal
233 * operation. DBG is open drain and hopefully pulled high
234 * since we don't normally drive it (GPIO 1?) for the
235 * HVR-1600
236 * 4. Z8F0811 won't exit reset until RESET is deasserted
237 * 5. Zilog comes out of reset, loads reset vector address and
238 * executes from there. Required recovery delay unknown.
239 */
240 gpio_reset_seq(cx, p->ir_reset_mask, 0,
241 p->msecs_asserted, p->msecs_recovery);
242 break;
243 case CX18_GPIO_RESET_XC2028:
244 if (cx->card->tuners[0].tuner == TUNER_XC2028)
245 gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0,
246 1, 1);
247 break;
248 }
249 return 0;
250}
251
252static const struct v4l2_subdev_core_ops resetctrl_core_ops = {
253 .log_status = resetctrl_log_status,
254 .reset = resetctrl_reset,
255};
256
257static const struct v4l2_subdev_ops resetctrl_ops = {
258 .core = &resetctrl_core_ops,
259};
260
261/*
262 * External entry points
263 */
133void cx18_gpio_init(struct cx18 *cx) 264void cx18_gpio_init(struct cx18 *cx)
134{ 265{
135 mutex_lock(&cx->gpio_lock); 266 mutex_lock(&cx->gpio_lock);
@@ -156,6 +287,49 @@ void cx18_gpio_init(struct cx18 *cx)
156 mutex_unlock(&cx->gpio_lock); 287 mutex_unlock(&cx->gpio_lock);
157} 288}
158 289
290int cx18_gpio_register(struct cx18 *cx, u32 hw)
291{
292 struct v4l2_subdev *sd;
293 const struct v4l2_subdev_ops *ops;
294 char *str;
295
296 switch (hw) {
297 case CX18_HW_GPIO_MUX:
298 sd = &cx->sd_gpiomux;
299 ops = &gpiomux_ops;
300 str = "gpio mux";
301 break;
302 case CX18_HW_GPIO_RESET_CTRL:
303 sd = &cx->sd_resetctrl;
304 ops = &resetctrl_ops;
305 str = "gpio reset ctrl";
306 break;
307 default:
308 return -EINVAL;
309 }
310
311 v4l2_subdev_init(sd, ops);
312 v4l2_set_subdevdata(sd, cx);
313 snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str);
314 sd->grp_id = hw;
315 return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
316}
317
318void cx18_reset_ir_gpio(void *data)
319{
320 struct cx18 *cx = to_cx18((struct v4l2_device *)data);
321
322 if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)
323 return;
324
325 CX18_DEBUG_INFO("Resetting IR microcontroller\n");
326
327 v4l2_subdev_call(&cx->sd_resetctrl,
328 core, reset, CX18_GPIO_RESET_Z8F0811);
329}
330EXPORT_SYMBOL(cx18_reset_ir_gpio);
331/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */
332
159/* Xceive tuner reset function */ 333/* Xceive tuner reset function */
160int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value) 334int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
161{ 335{
@@ -163,56 +337,11 @@ int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
163 struct cx18_i2c_algo_callback_data *cb_data = algo->data; 337 struct cx18_i2c_algo_callback_data *cb_data = algo->data;
164 struct cx18 *cx = cb_data->cx; 338 struct cx18 *cx = cb_data->cx;
165 339
166 if (cmd != XC2028_TUNER_RESET) 340 if (cmd != XC2028_TUNER_RESET ||
341 cx->card->tuners[0].tuner != TUNER_XC2028)
167 return 0; 342 return 0;
168 CX18_DEBUG_INFO("Resetting tuner\n");
169 343
170 mutex_lock(&cx->gpio_lock); 344 CX18_DEBUG_INFO("Resetting XCeive tuner\n");
171 cx->gpio_val &= ~(1 << cx->card->xceive_pin); 345 return v4l2_subdev_call(&cx->sd_resetctrl,
172 gpio_write(cx); 346 core, reset, CX18_GPIO_RESET_XC2028);
173 mutex_unlock(&cx->gpio_lock);
174 schedule_timeout_interruptible(msecs_to_jiffies(1));
175
176 mutex_lock(&cx->gpio_lock);
177 cx->gpio_val |= 1 << cx->card->xceive_pin;
178 gpio_write(cx);
179 mutex_unlock(&cx->gpio_lock);
180 schedule_timeout_interruptible(msecs_to_jiffies(1));
181 return 0;
182}
183
184int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
185{
186 struct v4l2_routing *route = arg;
187 u32 mask, data;
188
189 switch (command) {
190 case VIDIOC_INT_S_AUDIO_ROUTING:
191 if (route->input > 2)
192 return -EINVAL;
193 mask = cx->card->gpio_audio_input.mask;
194 switch (route->input) {
195 case 0:
196 data = cx->card->gpio_audio_input.tuner;
197 break;
198 case 1:
199 data = cx->card->gpio_audio_input.linein;
200 break;
201 case 2:
202 default:
203 data = cx->card->gpio_audio_input.radio;
204 break;
205 }
206 break;
207
208 default:
209 return -EINVAL;
210 }
211 if (mask) {
212 mutex_lock(&cx->gpio_lock);
213 cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
214 gpio_write(cx);
215 mutex_unlock(&cx->gpio_lock);
216 }
217 return 0;
218} 347}
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index 39ffccc19d8a..f9a5ca3566af 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -22,7 +22,13 @@
22 */ 22 */
23 23
24void cx18_gpio_init(struct cx18 *cx); 24void cx18_gpio_init(struct cx18 *cx);
25void cx18_reset_i2c_slaves_gpio(struct cx18 *cx); 25int cx18_gpio_register(struct cx18 *cx, u32 hw);
26
27enum cx18_gpio_reset_type {
28 CX18_GPIO_RESET_I2C = 0,
29 CX18_GPIO_RESET_Z8F0811 = 1,
30 CX18_GPIO_RESET_XC2028 = 2,
31};
32
26void cx18_reset_ir_gpio(void *data); 33void cx18_reset_ir_gpio(void *data);
27int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value); 34int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value);
28int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 6357dc44ab5b..d092643faf46 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -26,7 +26,6 @@
26#include "cx18-io.h" 26#include "cx18-io.h"
27#include "cx18-cards.h" 27#include "cx18-cards.h"
28#include "cx18-gpio.h" 28#include "cx18-gpio.h"
29#include "cx18-av-core.h"
30#include "cx18-i2c.h" 29#include "cx18-i2c.h"
31#include "cx18-irq.h" 30#include "cx18-irq.h"
32 31
@@ -49,7 +48,8 @@ static const u8 hw_addrs[] = {
49 CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */ 48 CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */
50 0, /* CX18_HW_DVB */ 49 0, /* CX18_HW_DVB */
51 0, /* CX18_HW_418_AV */ 50 0, /* CX18_HW_418_AV */
52 0, /* CX18_HW_GPIO_AUDIO_MUX */ 51 0, /* CX18_HW_GPIO_MUX */
52 0, /* CX18_HW_GPIO_RESET_CTRL */
53}; 53};
54 54
55/* This array should match the CX18_HW_ defines */ 55/* This array should match the CX18_HW_ defines */
@@ -60,7 +60,8 @@ static const u8 hw_bus[] = {
60 0, /* CX18_HW_CS5345 */ 60 0, /* CX18_HW_CS5345 */
61 0, /* CX18_HW_DVB */ 61 0, /* CX18_HW_DVB */
62 0, /* CX18_HW_418_AV */ 62 0, /* CX18_HW_418_AV */
63 0, /* CX18_HW_GPIO_AUDIO_MUX */ 63 0, /* CX18_HW_GPIO_MUX */
64 0, /* CX18_HW_GPIO_RESET_CTRL */
64}; 65};
65 66
66/* This array should match the CX18_HW_ defines */ 67/* This array should match the CX18_HW_ defines */
@@ -70,7 +71,8 @@ static const char * const hw_modules[] = {
70 "cs5345", /* CX18_HW_CS5345 */ 71 "cs5345", /* CX18_HW_CS5345 */
71 NULL, /* CX18_HW_DVB */ 72 NULL, /* CX18_HW_DVB */
72 NULL, /* CX18_HW_418_AV */ 73 NULL, /* CX18_HW_418_AV */
73 NULL, /* CX18_HW_GPIO_AUDIO_MUX */ 74 NULL, /* CX18_HW_GPIO_MUX */
75 NULL, /* CX18_HW_GPIO_RESET_CTRL */
74}; 76};
75 77
76/* This array should match the CX18_HW_ defines */ 78/* This array should match the CX18_HW_ defines */
@@ -80,7 +82,8 @@ static const char * const hw_devicenames[] = {
80 "cs5345", 82 "cs5345",
81 "cx23418_DTV", 83 "cx23418_DTV",
82 "cx23418_AV", 84 "cx23418_AV",
83 "gpio_audio_mux", 85 "gpio_mux",
86 "gpio_reset_ctrl",
84}; 87};
85 88
86int cx18_i2c_register(struct cx18 *cx, unsigned idx) 89int cx18_i2c_register(struct cx18 *cx, unsigned idx)
@@ -262,7 +265,8 @@ int init_cx18_i2c(struct cx18 *cx)
262 cx18_setscl(&cx->i2c_algo_cb_data[1], 1); 265 cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
263 cx18_setsda(&cx->i2c_algo_cb_data[1], 1); 266 cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
264 267
265 cx18_reset_i2c_slaves_gpio(cx); 268 cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
269 core, reset, (u32) CX18_GPIO_RESET_I2C);
266 270
267 return i2c_bit_add_bus(&cx->i2c_adap[0]) || 271 return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
268 i2c_bit_add_bus(&cx->i2c_adap[1]); 272 i2c_bit_add_bus(&cx->i2c_adap[1]);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 13ebd4a70f0d..e4c9e3d8bacd 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -940,7 +940,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
940 u32 val = *(u32 *)arg; 940 u32 val = *(u32 *)arg;
941 941
942 if ((val == 0) || (val & 0x01)) 942 if ((val == 0) || (val & 0x01))
943 cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]); 943 cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
944 (u32) CX18_GPIO_RESET_Z8F0811);
944 break; 945 break;
945 } 946 }
946 947
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 1d17884b3b0d..ce65cc6c86e8 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -32,7 +32,6 @@
32#include "cx18-streams.h" 32#include "cx18-streams.h"
33#include "cx18-cards.h" 33#include "cx18-cards.h"
34#include "cx18-scb.h" 34#include "cx18-scb.h"
35#include "cx18-av-core.h"
36#include "cx18-dvb.h" 35#include "cx18-dvb.h"
37 36
38#define CX18_DSP0_INTERRUPT_MASK 0xd0004C 37#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
index 91c21dce607f..a81fe2e985f2 100644
--- a/drivers/media/video/cx18/cx18-vbi.c
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -25,7 +25,6 @@
25#include "cx18-vbi.h" 25#include "cx18-vbi.h"
26#include "cx18-ioctl.h" 26#include "cx18-ioctl.h"
27#include "cx18-queue.h" 27#include "cx18-queue.h"
28#include "cx18-av-core.h"
29 28
30/* 29/*
31 * Raster Reference/Protection (RP) bytes, used in Start/End Active 30 * Raster Reference/Protection (RP) bytes, used in Start/End Active
diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c
index fabacb0f87c6..6fdadedf17a8 100644
--- a/drivers/media/video/cx18/cx18-video.c
+++ b/drivers/media/video/cx18/cx18-video.c
@@ -21,7 +21,6 @@
21 21
22#include "cx18-driver.h" 22#include "cx18-driver.h"
23#include "cx18-video.h" 23#include "cx18-video.h"
24#include "cx18-av-core.h"
25#include "cx18-cards.h" 24#include "cx18-cards.h"
26 25
27void cx18_video_set_io(struct cx18 *cx) 26void cx18_video_set_io(struct cx18 *cx)