aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2012-05-20 10:30:00 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-20 10:31:51 -0400
commit9554d57ebbc78db6d66057bfc12552247a7567da (patch)
tree2411d1ea00be7836bc4260d3f3ea8c2a482e8e5b
parent973848978be863607282391868efd77ace64278d (diff)
Revert "[media] staging: media: go7007: Adlink MPG24 board issues"
This patch were applied by mistake, as it were rejected by Don, who requested it to be broken into per-change patches. This reverts commit 0982db20aba5fd124bb5942d679d8732478e992a. Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: Volokh Konstantin <volokh84@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/staging/media/go7007/README18
-rw-r--r--drivers/staging/media/go7007/go7007-driver.c27
-rw-r--r--drivers/staging/media/go7007/go7007-priv.h2
-rw-r--r--drivers/staging/media/go7007/go7007-usb.c5
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c7
-rw-r--r--drivers/staging/media/go7007/wis-tw2804.c512
6 files changed, 164 insertions, 407 deletions
diff --git a/drivers/staging/media/go7007/README b/drivers/staging/media/go7007/README
index 082a6818c64e..48f447637817 100644
--- a/drivers/staging/media/go7007/README
+++ b/drivers/staging/media/go7007/README
@@ -5,24 +5,6 @@ Todo:
5 and added to the build. 5 and added to the build.
6 - testing? 6 - testing?
7 - handle churn in v4l layer. 7 - handle churn in v4l layer.
8 - Some features for wis-tw2804 subdev control (comb filter,motion detector sensitive & mask,more over...)
9 - go7007-v4l2.c need rewrite with new v4l2 style without nonstandart IO controls (set detector & bitrate)
10
1105/05/2012 3.4.0-rc+:
12Changes:
13 - When go7007 reset device, i2c was not worked (need rewrite GPIO5)
14 - As wis2804 has i2c_addr=0x00/*really*/, so Need set I2C_CLIENT_TEN flag for validity
15 - Some main nonzero initialization, rewrites with kzalloc instead kmalloc
16 - STATUS_SHUTDOWN was placed in incorrect place, so if firmware wasn`t loaded, we
17 failed v4l2_device_unregister with kernel panic (OOPS)
18 - Some new v4l2 style features as call_all(...s_stream...) for using subdev calls
19 - wis-tw2804.ko module code was incompatible with 3.4.x branch in initialization v4l2_subdev parts.
20 now i2c_get_clientdata(...) contains v4l2_subdev struct instead non standart wis_tw2804 struct
21
22Adds:
23 - Additional chipset wis2804 controls with: gain,auto gain,inputs[0,1],color kill,chroma gain,gain balances,
24 for all 4 channels (from tw2804.pdf)
25 - Power control for each 4 ADC up when s_stream(...,1), down otherwise in wis-tw2804 module
26 8
27Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross 9Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross
28Cohen <rcohen@snurgle.org> as well. 10Cohen <rcohen@snurgle.org> as well.
diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c
index 2dff9b5906b9..ece2dd146487 100644
--- a/drivers/staging/media/go7007/go7007-driver.c
+++ b/drivers/staging/media/go7007/go7007-driver.c
@@ -173,11 +173,6 @@ static int go7007_init_encoder(struct go7007 *go)
173 go7007_write_addr(go, 0x3c82, 0x0001); 173 go7007_write_addr(go, 0x3c82, 0x0001);
174 go7007_write_addr(go, 0x3c80, 0x00fe); 174 go7007_write_addr(go, 0x3c80, 0x00fe);
175 } 175 }
176 if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
177 /* set GPIO5 to be an output, currently low */
178 go7007_write_addr(go, 0x3c82, 0x0000);
179 go7007_write_addr(go, 0x3c80, 0x00df);
180 }
181 return 0; 176 return 0;
182} 177}
183 178
@@ -197,23 +192,17 @@ int go7007_reset_encoder(struct go7007 *go)
197/* 192/*
198 * Attempt to instantiate an I2C client by ID, probably loading a module. 193 * Attempt to instantiate an I2C client by ID, probably loading a module.
199 */ 194 */
200static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *const i2c) 195static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
196 int addr)
201{ 197{
202 struct go7007 *go = i2c_get_adapdata(adapter); 198 struct go7007 *go = i2c_get_adapdata(adapter);
203 struct v4l2_device *v4l2_dev = &go->v4l2_dev; 199 struct v4l2_device *v4l2_dev = &go->v4l2_dev;
204 struct i2c_board_info info;
205
206 memset(&info, 0, sizeof(info));
207 strlcpy(info.type, i2c->type, sizeof(info.type));
208 info.addr = i2c->addr;
209 200
210 if (i2c->id == I2C_DRIVERID_WIS_TW2804) 201 if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL))
211 info.flags |= I2C_CLIENT_TEN;
212 if (v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, NULL))
213 return 0; 202 return 0;
214 203
215 printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", i2c->type); 204 printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
216 return -EINVAL; 205 return -1;
217} 206}
218 207
219/* 208/*
@@ -249,7 +238,9 @@ int go7007_register_encoder(struct go7007 *go)
249 } 238 }
250 if (go->i2c_adapter_online) { 239 if (go->i2c_adapter_online) {
251 for (i = 0; i < go->board_info->num_i2c_devs; ++i) 240 for (i = 0; i < go->board_info->num_i2c_devs; ++i)
252 init_i2c_module(&go->i2c_adapter, &go->board_info->i2c_devs[i]); 241 init_i2c_module(&go->i2c_adapter,
242 go->board_info->i2c_devs[i].type,
243 go->board_info->i2c_devs[i].addr);
253 if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) 244 if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
254 i2c_clients_command(&go->i2c_adapter, 245 i2c_clients_command(&go->i2c_adapter,
255 DECODER_SET_CHANNEL, &go->channel_number); 246 DECODER_SET_CHANNEL, &go->channel_number);
@@ -580,7 +571,7 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
580 struct go7007 *go; 571 struct go7007 *go;
581 int i; 572 int i;
582 573
583 go = kzalloc(sizeof(struct go7007), GFP_KERNEL); 574 go = kmalloc(sizeof(struct go7007), GFP_KERNEL);
584 if (go == NULL) 575 if (go == NULL)
585 return NULL; 576 return NULL;
586 go->dev = dev; 577 go->dev = dev;
diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h
index b7b939a1967e..b58c394c6555 100644
--- a/drivers/staging/media/go7007/go7007-priv.h
+++ b/drivers/staging/media/go7007/go7007-priv.h
@@ -88,7 +88,7 @@ struct go7007_board_info {
88 int audio_bclk_div; 88 int audio_bclk_div;
89 int audio_main_div; 89 int audio_main_div;
90 int num_i2c_devs; 90 int num_i2c_devs;
91 struct go_i2c { 91 struct {
92 const char *type; 92 const char *type;
93 int id; 93 int id;
94 int addr; 94 int addr;
diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c
index 9dbf5ecd05a2..5443e25086e9 100644
--- a/drivers/staging/media/go7007/go7007-usb.c
+++ b/drivers/staging/media/go7007/go7007-usb.c
@@ -1110,6 +1110,9 @@ static int go7007_usb_probe(struct usb_interface *intf,
1110 } else { 1110 } else {
1111 u16 channel; 1111 u16 channel;
1112 1112
1113 /* set GPIO5 to be an output, currently low */
1114 go7007_write_addr(go, 0x3c82, 0x0000);
1115 go7007_write_addr(go, 0x3c80, 0x00df);
1113 /* read channel number from GPIO[1:0] */ 1116 /* read channel number from GPIO[1:0] */
1114 go7007_read_addr(go, 0x3c81, &channel); 1117 go7007_read_addr(go, 0x3c81, &channel);
1115 channel &= 0x3; 1118 channel &= 0x3;
@@ -1242,6 +1245,7 @@ static void go7007_usb_disconnect(struct usb_interface *intf)
1242 struct urb *vurb, *aurb; 1245 struct urb *vurb, *aurb;
1243 int i; 1246 int i;
1244 1247
1248 go->status = STATUS_SHUTDOWN;
1245 usb_kill_urb(usb->intr_urb); 1249 usb_kill_urb(usb->intr_urb);
1246 1250
1247 /* Free USB-related structs */ 1251 /* Free USB-related structs */
@@ -1265,7 +1269,6 @@ static void go7007_usb_disconnect(struct usb_interface *intf)
1265 kfree(go->hpi_context); 1269 kfree(go->hpi_context);
1266 1270
1267 go7007_remove(go); 1271 go7007_remove(go);
1268 go->status = STATUS_SHUTDOWN;
1269} 1272}
1270 1273
1271static struct usb_driver go7007_usb_driver = { 1274static struct usb_driver go7007_usb_driver = {
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index b8f2eb6bc3ef..c184ad30fbd8 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -98,7 +98,7 @@ static int go7007_open(struct file *file)
98 98
99 if (go->status != STATUS_ONLINE) 99 if (go->status != STATUS_ONLINE)
100 return -EBUSY; 100 return -EBUSY;
101 gofh = kzalloc(sizeof(struct go7007_file), GFP_KERNEL); 101 gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL);
102 if (gofh == NULL) 102 if (gofh == NULL)
103 return -ENOMEM; 103 return -ENOMEM;
104 ++go->ref_count; 104 ++go->ref_count;
@@ -953,7 +953,6 @@ static int vidioc_streamon(struct file *file, void *priv,
953 } 953 }
954 mutex_unlock(&go->hw_lock); 954 mutex_unlock(&go->hw_lock);
955 mutex_unlock(&gofh->lock); 955 mutex_unlock(&gofh->lock);
956 call_all(&go->v4l2_dev, video, s_stream, 1);
957 956
958 return retval; 957 return retval;
959} 958}
@@ -969,7 +968,6 @@ static int vidioc_streamoff(struct file *file, void *priv,
969 mutex_lock(&gofh->lock); 968 mutex_lock(&gofh->lock);
970 go7007_streamoff(go); 969 go7007_streamoff(go);
971 mutex_unlock(&gofh->lock); 970 mutex_unlock(&gofh->lock);
972 call_all(&go->v4l2_dev, video, s_stream, 0);
973 971
974 return 0; 972 return 0;
975} 973}
@@ -1834,6 +1832,5 @@ void go7007_v4l2_remove(struct go7007 *go)
1834 mutex_unlock(&go->hw_lock); 1832 mutex_unlock(&go->hw_lock);
1835 if (go->video_dev) 1833 if (go->video_dev)
1836 video_unregister_device(go->video_dev); 1834 video_unregister_device(go->video_dev);
1837 if (go->status != STATUS_SHUTDOWN) 1835 v4l2_device_unregister(&go->v4l2_dev);
1838 v4l2_device_unregister(&go->v4l2_dev);
1839} 1836}
diff --git a/drivers/staging/media/go7007/wis-tw2804.c b/drivers/staging/media/go7007/wis-tw2804.c
index 9afc5df5902e..9134f03e3cf0 100644
--- a/drivers/staging/media/go7007/wis-tw2804.c
+++ b/drivers/staging/media/go7007/wis-tw2804.c
@@ -21,27 +21,16 @@
21#include <linux/videodev2.h> 21#include <linux/videodev2.h>
22#include <linux/ioctl.h> 22#include <linux/ioctl.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <media/v4l2-subdev.h>
25#include <media/v4l2-device.h>
26 24
27#include "wis-i2c.h" 25#include "wis-i2c.h"
28 26
29struct wis_tw2804 { 27struct wis_tw2804 {
30 struct v4l2_subdev sd; 28 int channel;
31 u8 channel:2;
32 u8 input:1;
33 u8 update:1;
34 u8 auto_gain:1;
35 u8 ckil:1;
36 int norm; 29 int norm;
37 u8 brightness; 30 int brightness;
38 u8 contrast; 31 int contrast;
39 u8 saturation; 32 int saturation;
40 u8 hue; 33 int hue;
41 u8 gain;
42 u8 cr_gain;
43 u8 r_balance;
44 u8 b_balance;
45}; 34};
46 35
47static u8 global_registers[] = { 36static u8 global_registers[] = {
@@ -52,7 +41,6 @@ static u8 global_registers[] = {
52 0x3d, 0x80, 41 0x3d, 0x80,
53 0x3e, 0x82, 42 0x3e, 0x82,
54 0x3f, 0x82, 43 0x3f, 0x82,
55 0x78, 0x0f,
56 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ 44 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
57}; 45};
58 46
@@ -115,358 +103,29 @@ static u8 channel_registers[] = {
115 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ 103 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
116}; 104};
117 105
118static s32 write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel) 106static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel)
119{ 107{
120 return i2c_smbus_write_byte_data(client, reg | (channel << 6), value); 108 return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
121} 109}
122 110
123static int write_regs(struct i2c_client *client, u8 *regs, u8 channel) 111static int write_regs(struct i2c_client *client, u8 *regs, int channel)
124{ 112{
125 int i; 113 int i;
126 114
127 for (i = 0; regs[i] != 0xff; i += 2) 115 for (i = 0; regs[i] != 0xff; i += 2)
128 if (i2c_smbus_write_byte_data(client, 116 if (i2c_smbus_write_byte_data(client,
129 regs[i] | (channel << 6), regs[i + 1]) < 0) 117 regs[i] | (channel << 6), regs[i + 1]) < 0)
130 return -EINVAL; 118 return -1;
131 return 0; 119 return 0;
132} 120}
133 121
134static s32 read_reg(struct i2c_client *client, u8 reg, u8 channel)
135{
136 return i2c_smbus_read_byte_data(client, (reg) | (channel << 6));
137}
138
139static inline struct wis_tw2804 *to_state(struct v4l2_subdev *sd)
140{
141 return container_of(sd, struct wis_tw2804, sd);
142}
143
144static int tw2804_log_status(struct v4l2_subdev *sd)
145{
146 struct wis_tw2804 *state = to_state(sd);
147 v4l2_info(sd, "Standard: %s\n", state->norm == V4L2_STD_NTSC ? "NTSC" :
148 state->norm == V4L2_STD_PAL ? "PAL" : "unknown");
149 v4l2_info(sd, "Channel: %d\n", state->channel);
150 v4l2_info(sd, "Input: %d\n", state->input);
151 v4l2_info(sd, "Brightness: %d\n", state->brightness);
152 v4l2_info(sd, "Contrast: %d\n", state->contrast);
153 v4l2_info(sd, "Saturation: %d\n", state->saturation);
154 v4l2_info(sd, "Hue: %d\n", state->hue);
155 return 0;
156}
157
158static int tw2804_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *query)
159{
160 static const u32 user_ctrls[] = {
161 V4L2_CID_USER_CLASS,
162 V4L2_CID_BRIGHTNESS,
163 V4L2_CID_CONTRAST,
164 V4L2_CID_SATURATION,
165 V4L2_CID_HUE,
166 V4L2_CID_AUTOGAIN,
167 V4L2_CID_COLOR_KILLER,
168 V4L2_CID_GAIN,
169 V4L2_CID_CHROMA_GAIN,
170 V4L2_CID_BLUE_BALANCE,
171 V4L2_CID_RED_BALANCE,
172 0
173 };
174
175 static const u32 *ctrl_classes[] = {
176 user_ctrls,
177 NULL
178 };
179
180 query->id = v4l2_ctrl_next(ctrl_classes, query->id);
181
182 switch (query->id) {
183 case V4L2_CID_USER_CLASS:
184 return v4l2_ctrl_query_fill(query, 0, 0, 0, 0);
185 case V4L2_CID_BRIGHTNESS:
186 return v4l2_ctrl_query_fill(query, 0, 255, 1, 128);
187 case V4L2_CID_CONTRAST:
188 return v4l2_ctrl_query_fill(query, 0, 255, 1, 128);
189 case V4L2_CID_SATURATION:
190 return v4l2_ctrl_query_fill(query, 0, 255, 1, 128);
191 case V4L2_CID_HUE:
192 return v4l2_ctrl_query_fill(query, 0, 255, 1, 128);
193 case V4L2_CID_AUTOGAIN:
194 return v4l2_ctrl_query_fill(query, 0, 1, 1, 0);
195 case V4L2_CID_COLOR_KILLER:
196 return v4l2_ctrl_query_fill(query, 0, 1, 1, 0);
197 case V4L2_CID_GAIN:
198 return v4l2_ctrl_query_fill(query, 0, 255, 1, 128);
199 case V4L2_CID_CHROMA_GAIN:
200 return v4l2_ctrl_query_fill(query, 0, 255, 1, 128);
201 case V4L2_CID_BLUE_BALANCE:
202 return v4l2_ctrl_query_fill(query, 0, 255, 1, 122);
203 case V4L2_CID_RED_BALANCE:
204 return v4l2_ctrl_query_fill(query, 0, 255, 1, 122);
205 default:
206 return -EINVAL;
207 }
208}
209
210s32 get_ctrl_addr(int ctrl)
211{
212 switch (ctrl) {
213 case V4L2_CID_BRIGHTNESS:
214 return 0x12;
215 case V4L2_CID_CONTRAST:
216 return 0x11;
217 case V4L2_CID_SATURATION:
218 return 0x10;
219 case V4L2_CID_HUE:
220 return 0x0f;
221 case V4L2_CID_AUTOGAIN:
222 return 0x02;
223 case V4L2_CID_COLOR_KILLER:
224 return 0x14;
225 case V4L2_CID_GAIN:
226 return 0x3c;
227 case V4L2_CID_CHROMA_GAIN:
228 return 0x3d;
229 case V4L2_CID_RED_BALANCE:
230 return 0x3f;
231 case V4L2_CID_BLUE_BALANCE:
232 return 0x3e;
233 default:
234 return -EINVAL;
235 }
236}
237
238static int tw2804_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
239{
240 struct wis_tw2804 *state = to_state(sd);
241 struct i2c_client *client = v4l2_get_subdevdata(sd);
242 s32 addr = get_ctrl_addr(ctrl->id);
243 s32 val = 0;
244
245 if (addr == -EINVAL)
246 return -EINVAL;
247
248 if (state->update) {
249 val = read_reg(client, addr, ctrl->id == V4L2_CID_GAIN ||
250 ctrl->id == V4L2_CID_CHROMA_GAIN ||
251 ctrl->id == V4L2_CID_RED_BALANCE ||
252 ctrl->id == V4L2_CID_BLUE_BALANCE ? 0 : state->channel);
253 if (val < 0)
254 return val;
255 }
256
257 switch (ctrl->id) {
258 case V4L2_CID_BRIGHTNESS:
259 if (state->update)
260 state->brightness = val;
261 ctrl->value = state->brightness;
262 break;
263 case V4L2_CID_CONTRAST:
264 if (state->update)
265 state->contrast = val;
266 ctrl->value = state->contrast;
267 break;
268 case V4L2_CID_SATURATION:
269 if (state->update)
270 state->saturation = val;
271 ctrl->value = state->saturation;
272 break;
273 case V4L2_CID_HUE:
274 if (state->update)
275 state->hue = val;
276 ctrl->value = state->hue;
277 break;
278 case V4L2_CID_AUTOGAIN:
279 if (state->update)
280 state->auto_gain = val & (1<<7) ? 1 : 0;
281 ctrl->value = state->auto_gain;
282 break;
283 case V4L2_CID_COLOR_KILLER:
284 if (state->update)
285 state->ckil = (val & 0x03) == 0x03 ? 1 : 0;
286 ctrl->value = state->ckil;
287 break;
288 case V4L2_CID_GAIN:
289 if (state->update)
290 state->gain = val;
291 ctrl->value = state->gain;
292 break;
293 case V4L2_CID_CHROMA_GAIN:
294 if (state->update)
295 state->cr_gain = val;
296 ctrl->value = state->cr_gain;
297 break;
298 case V4L2_CID_RED_BALANCE:
299 if (state->update)
300 state->r_balance = val;
301 ctrl->value = state->r_balance;
302 break;
303 case V4L2_CID_BLUE_BALANCE:
304 if (state->update)
305 state->b_balance = val;
306 ctrl->value = state->b_balance;
307 break;
308 default:
309 return -EINVAL;
310 }
311
312 state->update = 0;
313 return 0;
314}
315
316static int tw2804_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
317{
318 struct wis_tw2804 *dec = to_state(sd);
319 struct i2c_client *client = v4l2_get_subdevdata(sd);
320 s32 reg = 0;
321 s32 addr = get_ctrl_addr(ctrl->id);
322
323 if (addr == -EINVAL)
324 return -EINVAL;
325
326 switch (ctrl->id) {
327 case V4L2_CID_AUTOGAIN:
328 reg = read_reg(client, addr, dec->channel);
329 if (reg > 0) {
330 if (ctrl->value == 0)
331 ctrl->value = reg & ~(1<<7);
332 else
333 ctrl->value = reg | 1<<7;
334 } else
335 return reg;
336 break;
337 case V4L2_CID_COLOR_KILLER:
338 reg = read_reg(client, addr, dec->channel);
339 if (reg > 0)
340 ctrl->value = (reg & ~(0x03)) | (ctrl->value == 0 ? 0x02 : 0x03);
341 else
342 return reg;
343 break;
344 default:
345 break;
346 }
347
348 ctrl->value = ctrl->value > 255 ? 255 : (ctrl->value < 0 ? 0 : ctrl->value);
349 reg = write_reg(client, addr, (u8)ctrl->value, ctrl->id == V4L2_CID_GAIN ||
350 ctrl->id == V4L2_CID_CHROMA_GAIN ||
351 ctrl->id == V4L2_CID_RED_BALANCE ||
352 ctrl->id == V4L2_CID_BLUE_BALANCE ? 0 : dec->channel);
353
354 if (reg < 0) {
355 v4l2_err(&dec->sd, "Can`t set_ctrl value:id=%d;value=%d\n", ctrl->id, ctrl->value);
356 return reg;
357 }
358
359 dec->update = 1;
360 return tw2804_g_ctrl(sd, ctrl);
361}
362
363static int tw2804_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
364{
365 struct wis_tw2804 *dec = to_state(sd);
366 struct i2c_client *client = v4l2_get_subdevdata(sd);
367
368 u8 regs[] = {
369 0x01, norm&V4L2_STD_NTSC ? 0xc4 : 0x84,
370 0x09, norm&V4L2_STD_NTSC ? 0x07 : 0x04,
371 0x0a, norm&V4L2_STD_NTSC ? 0xf0 : 0x20,
372 0x0b, norm&V4L2_STD_NTSC ? 0x07 : 0x04,
373 0x0c, norm&V4L2_STD_NTSC ? 0xf0 : 0x20,
374 0x0d, norm&V4L2_STD_NTSC ? 0x40 : 0x4a,
375 0x16, norm&V4L2_STD_NTSC ? 0x00 : 0x40,
376 0x17, norm&V4L2_STD_NTSC ? 0x00 : 0x40,
377 0x20, norm&V4L2_STD_NTSC ? 0x07 : 0x0f,
378 0x21, norm&V4L2_STD_NTSC ? 0x07 : 0x0f,
379 0xff, 0xff,
380 };
381 write_regs(client, regs, dec->channel);
382 dec->norm = norm;
383 return 0;
384}
385
386static const struct v4l2_subdev_core_ops tw2804_core_ops = {
387 .log_status = tw2804_log_status,
388 .g_ctrl = tw2804_g_ctrl,
389 .s_ctrl = tw2804_s_ctrl,
390 .queryctrl = tw2804_queryctrl,
391 .s_std = tw2804_s_std,
392};
393
394static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
395 u32 config)
396{
397 struct wis_tw2804 *dec = to_state(sd);
398 struct i2c_client *client = v4l2_get_subdevdata(sd);
399 s32 reg = 0;
400
401 if (0 > input || input > 1)
402 return -EINVAL;
403
404 if (input == dec->input && !dec->update)
405 return 0;
406
407 reg = read_reg(client, 0x22, dec->channel);
408
409 if (reg >= 0) {
410 if (input == 0)
411 reg &= ~(1<<2);
412 else
413 reg |= 1<<2;
414 reg = write_reg(client, 0x22, (u8)reg, dec->channel);
415 }
416
417 if (reg >= 0) {
418 dec->input = input;
419 dec->update = 0;
420 } else
421 return reg;
422 return 0;
423}
424
425static int tw2804_s_mbus_fmt(struct v4l2_subdev *sd,
426 struct v4l2_mbus_framefmt *fmt)
427{
428 /*TODO need select between 3fmt:
429 * bt_656,
430 * bt_601_8bit,
431 * bt_656_dual,
432 */
433 return 0;
434}
435
436int tw2804_s_stream(struct v4l2_subdev *sd, int enable)
437{
438 struct wis_tw2804 *dec = to_state(sd);
439 struct i2c_client *client = v4l2_get_subdevdata(sd);
440 u32 reg = read_reg(client, 0x78, 0);
441
442 if (enable == 1)
443 write_reg(client, 0x78, reg & ~(1<<dec->channel), 0);
444 else
445 write_reg(client, 0x78, reg | (1<<dec->channel), 0);
446
447 return 0;
448}
449
450static const struct v4l2_subdev_video_ops tw2804_video_ops = {
451 .s_routing = tw2804_s_video_routing,
452 .s_mbus_fmt = tw2804_s_mbus_fmt,
453 .s_stream = tw2804_s_stream,
454};
455
456static const struct v4l2_subdev_ops tw2804_ops = {
457 .core = &tw2804_core_ops,
458 .video = &tw2804_video_ops,
459};
460
461static int wis_tw2804_command(struct i2c_client *client, 122static int wis_tw2804_command(struct i2c_client *client,
462 unsigned int cmd, void *arg) 123 unsigned int cmd, void *arg)
463{ 124{
464 struct v4l2_subdev *sd = i2c_get_clientdata(client); 125 struct wis_tw2804 *dec = i2c_get_clientdata(client);
465 struct wis_tw2804 *dec = to_state(sd);
466 int *input;
467 126
468 if (cmd == DECODER_SET_CHANNEL) { 127 if (cmd == DECODER_SET_CHANNEL) {
469 input = arg; 128 int *input = arg;
470 129
471 if (*input < 0 || *input > 3) { 130 if (*input < 0 || *input > 3) {
472 printk(KERN_ERR "wis-tw2804: channel %d is not " 131 printk(KERN_ERR "wis-tw2804: channel %d is not "
@@ -495,6 +154,139 @@ static int wis_tw2804_command(struct i2c_client *client,
495 "channel number is set\n", cmd); 154 "channel number is set\n", cmd);
496 return 0; 155 return 0;
497 } 156 }
157
158 switch (cmd) {
159 case VIDIOC_S_STD:
160 {
161 v4l2_std_id *input = arg;
162 u8 regs[] = {
163 0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84,
164 0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
165 0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
166 0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
167 0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
168 0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a,
169 0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
170 0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
171 0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
172 0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
173 0xff, 0xff,
174 };
175 write_regs(client, regs, dec->channel);
176 dec->norm = *input;
177 break;
178 }
179 case VIDIOC_QUERYCTRL:
180 {
181 struct v4l2_queryctrl *ctrl = arg;
182
183 switch (ctrl->id) {
184 case V4L2_CID_BRIGHTNESS:
185 ctrl->type = V4L2_CTRL_TYPE_INTEGER;
186 strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
187 ctrl->minimum = 0;
188 ctrl->maximum = 255;
189 ctrl->step = 1;
190 ctrl->default_value = 128;
191 ctrl->flags = 0;
192 break;
193 case V4L2_CID_CONTRAST:
194 ctrl->type = V4L2_CTRL_TYPE_INTEGER;
195 strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
196 ctrl->minimum = 0;
197 ctrl->maximum = 255;
198 ctrl->step = 1;
199 ctrl->default_value = 128;
200 ctrl->flags = 0;
201 break;
202 case V4L2_CID_SATURATION:
203 ctrl->type = V4L2_CTRL_TYPE_INTEGER;
204 strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
205 ctrl->minimum = 0;
206 ctrl->maximum = 255;
207 ctrl->step = 1;
208 ctrl->default_value = 128;
209 ctrl->flags = 0;
210 break;
211 case V4L2_CID_HUE:
212 ctrl->type = V4L2_CTRL_TYPE_INTEGER;
213 strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
214 ctrl->minimum = 0;
215 ctrl->maximum = 255;
216 ctrl->step = 1;
217 ctrl->default_value = 128;
218 ctrl->flags = 0;
219 break;
220 }
221 break;
222 }
223 case VIDIOC_S_CTRL:
224 {
225 struct v4l2_control *ctrl = arg;
226
227 switch (ctrl->id) {
228 case V4L2_CID_BRIGHTNESS:
229 if (ctrl->value > 255)
230 dec->brightness = 255;
231 else if (ctrl->value < 0)
232 dec->brightness = 0;
233 else
234 dec->brightness = ctrl->value;
235 write_reg(client, 0x12, dec->brightness, dec->channel);
236 break;
237 case V4L2_CID_CONTRAST:
238 if (ctrl->value > 255)
239 dec->contrast = 255;
240 else if (ctrl->value < 0)
241 dec->contrast = 0;
242 else
243 dec->contrast = ctrl->value;
244 write_reg(client, 0x11, dec->contrast, dec->channel);
245 break;
246 case V4L2_CID_SATURATION:
247 if (ctrl->value > 255)
248 dec->saturation = 255;
249 else if (ctrl->value < 0)
250 dec->saturation = 0;
251 else
252 dec->saturation = ctrl->value;
253 write_reg(client, 0x10, dec->saturation, dec->channel);
254 break;
255 case V4L2_CID_HUE:
256 if (ctrl->value > 255)
257 dec->hue = 255;
258 else if (ctrl->value < 0)
259 dec->hue = 0;
260 else
261 dec->hue = ctrl->value;
262 write_reg(client, 0x0f, dec->hue, dec->channel);
263 break;
264 }
265 break;
266 }
267 case VIDIOC_G_CTRL:
268 {
269 struct v4l2_control *ctrl = arg;
270
271 switch (ctrl->id) {
272 case V4L2_CID_BRIGHTNESS:
273 ctrl->value = dec->brightness;
274 break;
275 case V4L2_CID_CONTRAST:
276 ctrl->value = dec->contrast;
277 break;
278 case V4L2_CID_SATURATION:
279 ctrl->value = dec->saturation;
280 break;
281 case V4L2_CID_HUE:
282 ctrl->value = dec->hue;
283 break;
284 }
285 break;
286 }
287 default:
288 break;
289 }
498 return 0; 290 return 0;
499} 291}
500 292
@@ -503,28 +295,21 @@ static int wis_tw2804_probe(struct i2c_client *client,
503{ 295{
504 struct i2c_adapter *adapter = client->adapter; 296 struct i2c_adapter *adapter = client->adapter;
505 struct wis_tw2804 *dec; 297 struct wis_tw2804 *dec;
506 struct v4l2_subdev *sd;
507 298
508 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 299 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
509 return -ENODEV; 300 return -ENODEV;
510 301
511 dec = kzalloc(sizeof(struct wis_tw2804), GFP_KERNEL); 302 dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL);
512
513 if (dec == NULL) 303 if (dec == NULL)
514 return -ENOMEM; 304 return -ENOMEM;
515 sd = &dec->sd; 305
516 dec->update = 1;
517 dec->channel = -1; 306 dec->channel = -1;
518 dec->norm = V4L2_STD_NTSC; 307 dec->norm = V4L2_STD_NTSC;
519 dec->brightness = 128; 308 dec->brightness = 128;
520 dec->contrast = 128; 309 dec->contrast = 128;
521 dec->saturation = 128; 310 dec->saturation = 128;
522 dec->hue = 128; 311 dec->hue = 128;
523 dec->gain = 128; 312 i2c_set_clientdata(client, dec);
524 dec->cr_gain = 128;
525 dec->b_balance = 122;
526 dec->r_balance = 122;
527 v4l2_i2c_subdev_init(sd, client, &tw2804_ops);
528 313
529 printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n", 314 printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n",
530 client->addr, adapter->name); 315 client->addr, adapter->name);
@@ -534,10 +319,9 @@ static int wis_tw2804_probe(struct i2c_client *client,
534 319
535static int wis_tw2804_remove(struct i2c_client *client) 320static int wis_tw2804_remove(struct i2c_client *client)
536{ 321{
537 struct v4l2_subdev *sd = i2c_get_clientdata(client); 322 struct wis_tw2804 *dec = i2c_get_clientdata(client);
538 323
539 v4l2_device_unregister_subdev(sd); 324 kfree(dec);
540 kfree(to_state(sd));
541 return 0; 325 return 0;
542} 326}
543 327