diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 17:39:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 17:39:09 -0400 |
commit | e317234975cb7463b8ca21a93bb6862d9dcf113f (patch) | |
tree | 4446fa3a21364f3cba23a22aa2a94027f169d8df /drivers/media | |
parent | f37ab0fba271e43edab0e3ae9fe644fcda455402 (diff) | |
parent | 7483d45f0aee3afc0646d185cabd4af9f6cab58c (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- V4L2 API additions to better support JPEG compression control
- media API additions to properly support MPEG decoders
- V4L2 API additions for image crop/scaling
- a few other V4L2 API DocBook fixes/improvements
- two new DVB frontend drivers: m88rs2000 and rtl2830
- two new DVB drivers: az6007 and rtl28xxu
- a framework for ISA drivers, that removed lots of common code found
at the ISA radio drivers
- a new FM transmitter driver (radio-keene)
- a GPIO-based IR receiver driver
- a new sensor driver: mt9m032
- some new video drivers: adv7183, blackfin, mx2_emmaprp, sii9234_drv,
vs6624
- several new board additions, driver fixes, improvements and cleanups.
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (295 commits)
[media] update CARDLIST.em28xx
[media] partially reverts changeset fa5527c
[media] stb0899: fix the limits for signal strength values
[media] em28xx: support for 2304:0242 PCTV QuatroStick (510e)
[media] em28xx: support for 2013:0251 PCTV QuatroStick nano (520e)
[media] -EINVAL -> -ENOTTY
[media] gspca - sn9c20x: Cleanup source
[media] gspca - sn9c20x: Simplify register write for capture start/stop
[media] gspca - sn9c20x: Add automatic JPEG compression mechanism
[media] gspca - sn9c20x: Greater delay in case of sensor no response
[media] gspca - sn9c20x: Optimize the code of write sequences
[media] gspca - sn9c20x: Add the JPEG compression quality control
[media] gspca - sn9c20x: Add a delay after Omnivision sensor reset
[media] gspca - sn9c20x: Propagate USB errors to higher level
[media] gspca - sn9c20x: Use the new video control mechanism
[media] gspca - sn9c20x: Fix loss of frame start
[media] gspca - zc3xx: Lack of register 08 value for sensor cs2102k
[media] gspca - ov534_9: Add brightness to OmniVision 5621 sensor
[media] gspca - zc3xx: Add V4L2_CID_JPEG_COMPRESSION_QUALITY control support
[media] pvrusb2: fix 7MHz & 8MHz DVB-T tuner support for HVR1900 rev D1F5
...
Diffstat (limited to 'drivers/media')
249 files changed, 16874 insertions, 6652 deletions
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 8295854ab94b..f80407eb8998 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile | |||
@@ -29,5 +29,5 @@ obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o | |||
29 | obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o | 29 | obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o |
30 | obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o | 30 | obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o |
31 | 31 | ||
32 | ccflags-y += -Idrivers/media/dvb/dvb-core | 32 | ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core |
33 | ccflags-y += -Idrivers/media/dvb/frontends | 33 | ccflags-y += -I$(srctree)/drivers/media/dvb/frontends |
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c index cb2c98fbad1b..ba84936aafd6 100644 --- a/drivers/media/common/tuners/max2165.c +++ b/drivers/media/common/tuners/max2165.c | |||
@@ -168,7 +168,7 @@ int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) | |||
168 | int i; | 168 | int i; |
169 | 169 | ||
170 | if (0 == divisor) | 170 | if (0 == divisor) |
171 | return -1; | 171 | return -EINVAL; |
172 | 172 | ||
173 | q = dividend / divisor; | 173 | q = dividend / divisor; |
174 | remainder = dividend - q * divisor; | 174 | remainder = dividend - q * divisor; |
@@ -194,10 +194,13 @@ static int max2165_set_rf(struct max2165_priv *priv, u32 freq) | |||
194 | u8 tf_ntch; | 194 | u8 tf_ntch; |
195 | u32 t; | 195 | u32 t; |
196 | u32 quotient, fraction; | 196 | u32 quotient, fraction; |
197 | int ret; | ||
197 | 198 | ||
198 | /* Set PLL divider according to RF frequency */ | 199 | /* Set PLL divider according to RF frequency */ |
199 | fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, | 200 | ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, |
200 | "ient, &fraction); | 201 | "ient, &fraction); |
202 | if (ret != 0) | ||
203 | return ret; | ||
201 | 204 | ||
202 | /* 20-bit fraction */ | 205 | /* 20-bit fraction */ |
203 | fraction >>= 12; | 206 | fraction >>= 12; |
diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c index c89af3cd5eba..0ed9091ff48e 100644 --- a/drivers/media/common/tuners/mt2063.c +++ b/drivers/media/common/tuners/mt2063.c | |||
@@ -350,7 +350,7 @@ static int MT2063_Sleep(struct dvb_frontend *fe) | |||
350 | /* | 350 | /* |
351 | * ToDo: Add code here to implement a OS blocking | 351 | * ToDo: Add code here to implement a OS blocking |
352 | */ | 352 | */ |
353 | msleep(10); | 353 | msleep(100); |
354 | 354 | ||
355 | return 0; | 355 | return 0; |
356 | } | 356 | } |
@@ -2226,7 +2226,7 @@ static struct dvb_tuner_ops mt2063_ops = { | |||
2226 | .info = { | 2226 | .info = { |
2227 | .name = "MT2063 Silicon Tuner", | 2227 | .name = "MT2063 Silicon Tuner", |
2228 | .frequency_min = 45000000, | 2228 | .frequency_min = 45000000, |
2229 | .frequency_max = 850000000, | 2229 | .frequency_max = 865000000, |
2230 | .frequency_step = 0, | 2230 | .frequency_step = 0, |
2231 | }, | 2231 | }, |
2232 | 2232 | ||
diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h index 62d0e8ec4e99..3f5cfd93713f 100644 --- a/drivers/media/common/tuners/mt2063.h +++ b/drivers/media/common/tuners/mt2063.h | |||
@@ -23,10 +23,6 @@ static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, | |||
23 | return NULL; | 23 | return NULL; |
24 | } | 24 | } |
25 | 25 | ||
26 | int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, | ||
27 | u32 bw_in, | ||
28 | enum MTTune_atv_standard tv_type); | ||
29 | |||
30 | /* FIXME: Should use the standard DVB attachment interfaces */ | 26 | /* FIXME: Should use the standard DVB attachment interfaces */ |
31 | unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); | 27 | unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); |
32 | unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); | 28 | unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); |
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index e13683bab6b3..2da4440c16ee 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c | |||
@@ -1868,6 +1868,10 @@ struct tunertype tuners[] = { | |||
1868 | .params = tuner_tena_tnf_5337_params, | 1868 | .params = tuner_tena_tnf_5337_params, |
1869 | .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), | 1869 | .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), |
1870 | }, | 1870 | }, |
1871 | [TUNER_XC5000C] = { /* Xceive 5000C */ | ||
1872 | .name = "Xceive 5000C tuner", | ||
1873 | /* see xc5000.c for details */ | ||
1874 | }, | ||
1871 | }; | 1875 | }; |
1872 | EXPORT_SYMBOL(tuners); | 1876 | EXPORT_SYMBOL(tuners); |
1873 | 1877 | ||
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index 296df05b8cda..7f98984e4fad 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c | |||
@@ -49,9 +49,6 @@ static LIST_HEAD(hybrid_tuner_instance_list); | |||
49 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | 49 | #define dprintk(level, fmt, arg...) if (debug >= level) \ |
50 | printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) | 50 | printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) |
51 | 51 | ||
52 | #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" | ||
53 | #define XC5000_DEFAULT_FIRMWARE_SIZE 12401 | ||
54 | |||
55 | struct xc5000_priv { | 52 | struct xc5000_priv { |
56 | struct tuner_i2c_props i2c_props; | 53 | struct tuner_i2c_props i2c_props; |
57 | struct list_head hybrid_tuner_instance_list; | 54 | struct list_head hybrid_tuner_instance_list; |
@@ -62,6 +59,8 @@ struct xc5000_priv { | |||
62 | u8 video_standard; | 59 | u8 video_standard; |
63 | u8 rf_mode; | 60 | u8 rf_mode; |
64 | u8 radio_input; | 61 | u8 radio_input; |
62 | |||
63 | int chip_id; | ||
65 | }; | 64 | }; |
66 | 65 | ||
67 | /* Misc Defines */ | 66 | /* Misc Defines */ |
@@ -204,6 +203,33 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { | |||
204 | {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} | 203 | {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} |
205 | }; | 204 | }; |
206 | 205 | ||
206 | |||
207 | struct xc5000_fw_cfg { | ||
208 | char *name; | ||
209 | u16 size; | ||
210 | }; | ||
211 | |||
212 | static const struct xc5000_fw_cfg xc5000a_1_6_114 = { | ||
213 | .name = "dvb-fe-xc5000-1.6.114.fw", | ||
214 | .size = 12401, | ||
215 | }; | ||
216 | |||
217 | static const struct xc5000_fw_cfg xc5000c_41_024_5_31875 = { | ||
218 | .name = "dvb-fe-xc5000c-41.024.5-31875.fw", | ||
219 | .size = 16503, | ||
220 | }; | ||
221 | |||
222 | static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) | ||
223 | { | ||
224 | switch (chip_id) { | ||
225 | default: | ||
226 | case XC5000A: | ||
227 | return &xc5000a_1_6_114; | ||
228 | case XC5000C: | ||
229 | return &xc5000c_41_024_5_31875; | ||
230 | } | ||
231 | } | ||
232 | |||
207 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); | 233 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); |
208 | static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); | 234 | static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); |
209 | static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); | 235 | static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); |
@@ -552,12 +578,14 @@ static int xc5000_fwupload(struct dvb_frontend *fe) | |||
552 | struct xc5000_priv *priv = fe->tuner_priv; | 578 | struct xc5000_priv *priv = fe->tuner_priv; |
553 | const struct firmware *fw; | 579 | const struct firmware *fw; |
554 | int ret; | 580 | int ret; |
581 | const struct xc5000_fw_cfg *desired_fw = | ||
582 | xc5000_assign_firmware(priv->chip_id); | ||
555 | 583 | ||
556 | /* request the firmware, this will block and timeout */ | 584 | /* request the firmware, this will block and timeout */ |
557 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", | 585 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", |
558 | XC5000_DEFAULT_FIRMWARE); | 586 | desired_fw->name); |
559 | 587 | ||
560 | ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, | 588 | ret = request_firmware(&fw, desired_fw->name, |
561 | priv->i2c_props.adap->dev.parent); | 589 | priv->i2c_props.adap->dev.parent); |
562 | if (ret) { | 590 | if (ret) { |
563 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); | 591 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); |
@@ -569,7 +597,7 @@ static int xc5000_fwupload(struct dvb_frontend *fe) | |||
569 | ret = XC_RESULT_SUCCESS; | 597 | ret = XC_RESULT_SUCCESS; |
570 | } | 598 | } |
571 | 599 | ||
572 | if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { | 600 | if (fw->size != desired_fw->size) { |
573 | printk(KERN_ERR "xc5000: firmware incorrect size\n"); | 601 | printk(KERN_ERR "xc5000: firmware incorrect size\n"); |
574 | ret = XC_RESULT_RESET_FAILURE; | 602 | ret = XC_RESULT_RESET_FAILURE; |
575 | } else { | 603 | } else { |
@@ -1139,6 +1167,13 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | |||
1139 | if (priv->radio_input == 0) | 1167 | if (priv->radio_input == 0) |
1140 | priv->radio_input = cfg->radio_input; | 1168 | priv->radio_input = cfg->radio_input; |
1141 | 1169 | ||
1170 | /* don't override chip id if it's already been set | ||
1171 | unless explicitly specified */ | ||
1172 | if ((priv->chip_id == 0) || (cfg->chip_id)) | ||
1173 | /* use default chip id if none specified, set to 0 so | ||
1174 | it can be overridden if this is a hybrid driver */ | ||
1175 | priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; | ||
1176 | |||
1142 | /* Check if firmware has been loaded. It is possible that another | 1177 | /* Check if firmware has been loaded. It is possible that another |
1143 | instance of the driver has loaded the firmware. | 1178 | instance of the driver has loaded the firmware. |
1144 | */ | 1179 | */ |
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h index e2957451b532..3396f8e02b40 100644 --- a/drivers/media/common/tuners/xc5000.h +++ b/drivers/media/common/tuners/xc5000.h | |||
@@ -27,10 +27,15 @@ | |||
27 | struct dvb_frontend; | 27 | struct dvb_frontend; |
28 | struct i2c_adapter; | 28 | struct i2c_adapter; |
29 | 29 | ||
30 | #define XC5000A 1 | ||
31 | #define XC5000C 2 | ||
32 | |||
30 | struct xc5000_config { | 33 | struct xc5000_config { |
31 | u8 i2c_address; | 34 | u8 i2c_address; |
32 | u32 if_khz; | 35 | u32 if_khz; |
33 | u8 radio_input; | 36 | u8 radio_input; |
37 | |||
38 | int chip_id; | ||
34 | }; | 39 | }; |
35 | 40 | ||
36 | /* xc5000 callback command */ | 41 | /* xc5000 callback command */ |
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c index ce4f85849e7b..d88c4aa7d24d 100644 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c | |||
@@ -578,6 +578,7 @@ static int demod_attach_drxk(struct ddb_input *input) | |||
578 | struct drxk_config config; | 578 | struct drxk_config config; |
579 | 579 | ||
580 | memset(&config, 0, sizeof(config)); | 580 | memset(&config, 0, sizeof(config)); |
581 | config.microcode_name = "drxk_a3.mc"; | ||
581 | config.adr = 0x29 + (input->nr & 1); | 582 | config.adr = 0x29 + (input->nr & 1); |
582 | 583 | ||
583 | fe = input->fe = dvb_attach(drxk_attach, &config, i2c); | 584 | fe = input->fe = dvb_attach(drxk_attach, &config, i2c); |
diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h index 6d14893218f4..8b1b41d2a52d 100644 --- a/drivers/media/dvb/ddbridge/ddbridge.h +++ b/drivers/media/dvb/ddbridge/ddbridge.h | |||
@@ -32,8 +32,6 @@ | |||
32 | #include <asm/dma.h> | 32 | #include <asm/dma.h> |
33 | #include <linux/dvb/frontend.h> | 33 | #include <linux/dvb/frontend.h> |
34 | #include <linux/dvb/ca.h> | 34 | #include <linux/dvb/ca.h> |
35 | #include <linux/dvb/video.h> | ||
36 | #include <linux/dvb/audio.h> | ||
37 | #include <linux/socket.h> | 35 | #include <linux/socket.h> |
38 | 36 | ||
39 | #include "dmxdev.h" | 37 | #include "dmxdev.h" |
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index fbbe545a74cb..4555baa383b2 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
@@ -655,6 +655,8 @@ restart: | |||
655 | dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); | 655 | dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); |
656 | re_tune = true; | 656 | re_tune = true; |
657 | fepriv->state = FESTATE_TUNED; | 657 | fepriv->state = FESTATE_TUNED; |
658 | } else { | ||
659 | re_tune = false; | ||
658 | } | 660 | } |
659 | 661 | ||
660 | if (fe->ops.tune) | 662 | if (fe->ops.tune) |
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 9f203c6767a6..63bf45679f98 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig | |||
@@ -361,6 +361,14 @@ config DVB_USB_EC168 | |||
361 | help | 361 | help |
362 | Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. | 362 | Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. |
363 | 363 | ||
364 | config DVB_USB_AZ6007 | ||
365 | tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" | ||
366 | depends on DVB_USB | ||
367 | select DVB_DRXK if !DVB_FE_CUSTOMISE | ||
368 | select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE | ||
369 | help | ||
370 | Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers. | ||
371 | |||
364 | config DVB_USB_AZ6027 | 372 | config DVB_USB_AZ6027 |
365 | tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" | 373 | tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" |
366 | depends on DVB_USB | 374 | depends on DVB_USB |
@@ -378,6 +386,7 @@ config DVB_USB_LME2510 | |||
378 | select DVB_IX2505V if !DVB_FE_CUSTOMISE | 386 | select DVB_IX2505V if !DVB_FE_CUSTOMISE |
379 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | 387 | select DVB_STV0299 if !DVB_FE_CUSTOMISE |
380 | select DVB_PLL if !DVB_FE_CUSTOMISE | 388 | select DVB_PLL if !DVB_FE_CUSTOMISE |
389 | select DVB_M88RS2000 if !DVB_FE_CUSTOMISE | ||
381 | help | 390 | help |
382 | Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . | 391 | Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . |
383 | 392 | ||
@@ -403,3 +412,13 @@ config DVB_USB_MXL111SF | |||
403 | select VIDEO_TVEEPROM | 412 | select VIDEO_TVEEPROM |
404 | help | 413 | help |
405 | Say Y here to support the MxL111SF USB2.0 DTV receiver. | 414 | Say Y here to support the MxL111SF USB2.0 DTV receiver. |
415 | |||
416 | config DVB_USB_RTL28XXU | ||
417 | tristate "Realtek RTL28xxU DVB USB support" | ||
418 | depends on DVB_USB && EXPERIMENTAL | ||
419 | select DVB_RTL2830 | ||
420 | select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE | ||
421 | select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE | ||
422 | select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE | ||
423 | help | ||
424 | Say Y here to support the Realtek RTL28xxU DVB USB receiver. | ||
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 26c8b9e57050..b76acb5387e6 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile | |||
@@ -54,7 +54,6 @@ obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o | |||
54 | dvb-usb-opera-objs = opera1.o | 54 | dvb-usb-opera-objs = opera1.o |
55 | obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o | 55 | obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o |
56 | 56 | ||
57 | |||
58 | dvb-usb-af9005-objs = af9005.o af9005-fe.o | 57 | dvb-usb-af9005-objs = af9005.o af9005-fe.o |
59 | obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o | 58 | obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o |
60 | 59 | ||
@@ -88,6 +87,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o | |||
88 | dvb-usb-ec168-objs = ec168.o | 87 | dvb-usb-ec168-objs = ec168.o |
89 | obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o | 88 | obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o |
90 | 89 | ||
90 | dvb-usb-az6007-objs = az6007.o | ||
91 | obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o | ||
92 | |||
91 | dvb-usb-az6027-objs = az6027.o | 93 | dvb-usb-az6027-objs = az6027.o |
92 | obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o | 94 | obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o |
93 | 95 | ||
@@ -105,8 +107,12 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o | |||
105 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o | 107 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o |
106 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o | 108 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o |
107 | 109 | ||
108 | ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 110 | dvb-usb-rtl28xxu-objs = rtl28xxu.o |
111 | obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o | ||
112 | |||
113 | ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core | ||
114 | ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ | ||
109 | # due to tuner-xc3028 | 115 | # due to tuner-xc3028 |
110 | ccflags-y += -Idrivers/media/common/tuners | 116 | ccflags-y += -I$(srctree)/drivers/media/common/tuners |
111 | EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci | 117 | ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci |
112 | 118 | ||
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 282a43d648df..7e70ea50ef26 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c | |||
@@ -1164,6 +1164,41 @@ static int af9015_af9013_sleep(struct dvb_frontend *fe) | |||
1164 | return ret; | 1164 | return ret; |
1165 | } | 1165 | } |
1166 | 1166 | ||
1167 | /* override tuner callbacks for resource locking */ | ||
1168 | static int af9015_tuner_init(struct dvb_frontend *fe) | ||
1169 | { | ||
1170 | int ret; | ||
1171 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1172 | struct af9015_state *priv = adap->dev->priv; | ||
1173 | |||
1174 | if (mutex_lock_interruptible(&adap->dev->usb_mutex)) | ||
1175 | return -EAGAIN; | ||
1176 | |||
1177 | ret = priv->tuner_init[adap->id](fe); | ||
1178 | |||
1179 | mutex_unlock(&adap->dev->usb_mutex); | ||
1180 | |||
1181 | return ret; | ||
1182 | } | ||
1183 | |||
1184 | /* override tuner callbacks for resource locking */ | ||
1185 | static int af9015_tuner_sleep(struct dvb_frontend *fe) | ||
1186 | { | ||
1187 | int ret; | ||
1188 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1189 | struct af9015_state *priv = adap->dev->priv; | ||
1190 | |||
1191 | if (mutex_lock_interruptible(&adap->dev->usb_mutex)) | ||
1192 | return -EAGAIN; | ||
1193 | |||
1194 | ret = priv->tuner_sleep[adap->id](fe); | ||
1195 | |||
1196 | mutex_unlock(&adap->dev->usb_mutex); | ||
1197 | |||
1198 | return ret; | ||
1199 | } | ||
1200 | |||
1201 | |||
1167 | static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) | 1202 | static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) |
1168 | { | 1203 | { |
1169 | int ret; | 1204 | int ret; |
@@ -1283,6 +1318,7 @@ static struct mxl5007t_config af9015_mxl5007t_config = { | |||
1283 | static int af9015_tuner_attach(struct dvb_usb_adapter *adap) | 1318 | static int af9015_tuner_attach(struct dvb_usb_adapter *adap) |
1284 | { | 1319 | { |
1285 | int ret; | 1320 | int ret; |
1321 | struct af9015_state *state = adap->dev->priv; | ||
1286 | deb_info("%s:\n", __func__); | 1322 | deb_info("%s:\n", __func__); |
1287 | 1323 | ||
1288 | switch (af9015_af9013_config[adap->id].tuner) { | 1324 | switch (af9015_af9013_config[adap->id].tuner) { |
@@ -1340,6 +1376,19 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) | |||
1340 | err("Unknown tuner id:%d", | 1376 | err("Unknown tuner id:%d", |
1341 | af9015_af9013_config[adap->id].tuner); | 1377 | af9015_af9013_config[adap->id].tuner); |
1342 | } | 1378 | } |
1379 | |||
1380 | if (adap->fe_adap[0].fe->ops.tuner_ops.init) { | ||
1381 | state->tuner_init[adap->id] = | ||
1382 | adap->fe_adap[0].fe->ops.tuner_ops.init; | ||
1383 | adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init; | ||
1384 | } | ||
1385 | |||
1386 | if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) { | ||
1387 | state->tuner_sleep[adap->id] = | ||
1388 | adap->fe_adap[0].fe->ops.tuner_ops.sleep; | ||
1389 | adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep; | ||
1390 | } | ||
1391 | |||
1343 | return ret; | 1392 | return ret; |
1344 | } | 1393 | } |
1345 | 1394 | ||
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h index f619063fa72f..2f68419e899b 100644 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ b/drivers/media/dvb/dvb-usb/af9015.h | |||
@@ -108,6 +108,8 @@ struct af9015_state { | |||
108 | int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); | 108 | int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); |
109 | int (*init[2]) (struct dvb_frontend *fe); | 109 | int (*init[2]) (struct dvb_frontend *fe); |
110 | int (*sleep[2]) (struct dvb_frontend *fe); | 110 | int (*sleep[2]) (struct dvb_frontend *fe); |
111 | int (*tuner_init[2]) (struct dvb_frontend *fe); | ||
112 | int (*tuner_sleep[2]) (struct dvb_frontend *fe); | ||
111 | }; | 113 | }; |
112 | 114 | ||
113 | struct af9015_config { | 115 | struct af9015_config { |
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index cf0c318d6989..03c28655af1b 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c | |||
@@ -58,7 +58,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, | |||
58 | u8 *rbuf, u8 rlen) | 58 | u8 *rbuf, u8 rlen) |
59 | { | 59 | { |
60 | struct anysee_state *state = d->priv; | 60 | struct anysee_state *state = d->priv; |
61 | int act_len, ret; | 61 | int act_len, ret, i; |
62 | u8 buf[64]; | 62 | u8 buf[64]; |
63 | 63 | ||
64 | memcpy(&buf[0], sbuf, slen); | 64 | memcpy(&buf[0], sbuf, slen); |
@@ -73,26 +73,52 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, | |||
73 | /* We need receive one message more after dvb_usb_generic_rw due | 73 | /* We need receive one message more after dvb_usb_generic_rw due |
74 | to weird transaction flow, which is 1 x send + 2 x receive. */ | 74 | to weird transaction flow, which is 1 x send + 2 x receive. */ |
75 | ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); | 75 | ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); |
76 | if (!ret) { | 76 | if (ret) |
77 | goto error_unlock; | ||
78 | |||
79 | /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 | ||
80 | * (EPIPE, Broken pipe). Function supports currently msleep() as a | ||
81 | * parameter but I would not like to use it, since according to | ||
82 | * Documentation/timers/timers-howto.txt it should not be used such | ||
83 | * short, under < 20ms, sleeps. Repeating failed message would be | ||
84 | * better choice as not to add unwanted delays... | ||
85 | * Fixing that correctly is one of those or both; | ||
86 | * 1) use repeat if possible | ||
87 | * 2) add suitable delay | ||
88 | */ | ||
89 | |||
90 | /* get answer, retry few times if error returned */ | ||
91 | for (i = 0; i < 3; i++) { | ||
77 | /* receive 2nd answer */ | 92 | /* receive 2nd answer */ |
78 | ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, | 93 | ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, |
79 | d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), | 94 | d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), |
80 | &act_len, 2000); | 95 | &act_len, 2000); |
81 | if (ret) | 96 | |
82 | err("%s: recv bulk message failed: %d", __func__, ret); | 97 | if (ret) { |
83 | else { | 98 | deb_info("%s: recv bulk message failed: %d", |
99 | __func__, ret); | ||
100 | } else { | ||
84 | deb_xfer("<<< "); | 101 | deb_xfer("<<< "); |
85 | debug_dump(buf, rlen, deb_xfer); | 102 | debug_dump(buf, rlen, deb_xfer); |
86 | 103 | ||
87 | if (buf[63] != 0x4f) | 104 | if (buf[63] != 0x4f) |
88 | deb_info("%s: cmd failed\n", __func__); | 105 | deb_info("%s: cmd failed\n", __func__); |
106 | |||
107 | break; | ||
89 | } | 108 | } |
90 | } | 109 | } |
91 | 110 | ||
111 | if (ret) { | ||
112 | /* all retries failed, it is fatal */ | ||
113 | err("%s: recv bulk message failed: %d", __func__, ret); | ||
114 | goto error_unlock; | ||
115 | } | ||
116 | |||
92 | /* read request, copy returned data to return buf */ | 117 | /* read request, copy returned data to return buf */ |
93 | if (!ret && rbuf && rlen) | 118 | if (rbuf && rlen) |
94 | memcpy(rbuf, buf, rlen); | 119 | memcpy(rbuf, buf, rlen); |
95 | 120 | ||
121 | error_unlock: | ||
96 | mutex_unlock(&anysee_usb_mutex); | 122 | mutex_unlock(&anysee_usb_mutex); |
97 | 123 | ||
98 | return ret; | 124 | return ret; |
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c new file mode 100644 index 000000000000..4008b9c50fbd --- /dev/null +++ b/drivers/media/dvb/dvb-usb/az6007.c | |||
@@ -0,0 +1,957 @@ | |||
1 | /* | ||
2 | * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones | ||
3 | * | ||
4 | * Copyright (c) Henry Wang <Henry.wang@AzureWave.com> | ||
5 | * | ||
6 | * This driver was made publicly available by Terratec, at: | ||
7 | * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz | ||
8 | * The original driver's license is GPL, as declared with MODULE_LICENSE() | ||
9 | * | ||
10 | * Copyright (c) 2010-2011 Mauro Carvalho Chehab <mchehab@redhat.com> | ||
11 | * Driver modified by in order to work with upstream drxk driver, and | ||
12 | * tons of bugs got fixed. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation under version 2 of the License. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | */ | ||
23 | |||
24 | #include "drxk.h" | ||
25 | #include "mt2063.h" | ||
26 | #include "dvb_ca_en50221.h" | ||
27 | |||
28 | #define DVB_USB_LOG_PREFIX "az6007" | ||
29 | #include "dvb-usb.h" | ||
30 | |||
31 | /* debug */ | ||
32 | int dvb_usb_az6007_debug; | ||
33 | module_param_named(debug, dvb_usb_az6007_debug, int, 0644); | ||
34 | MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." | ||
35 | DVB_USB_DEBUG_STATUS); | ||
36 | |||
37 | #define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args) | ||
38 | #define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args) | ||
39 | #define deb_rc(args...) dprintk(dvb_usb_az6007_debug, 0x04, args) | ||
40 | #define deb_fe(args...) dprintk(dvb_usb_az6007_debug, 0x08, args) | ||
41 | |||
42 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
43 | |||
44 | /* Known requests (Cypress FX2 firmware + az6007 "private" ones*/ | ||
45 | |||
46 | #define FX2_OED 0xb5 | ||
47 | #define AZ6007_READ_DATA 0xb7 | ||
48 | #define AZ6007_I2C_RD 0xb9 | ||
49 | #define AZ6007_POWER 0xbc | ||
50 | #define AZ6007_I2C_WR 0xbd | ||
51 | #define FX2_SCON1 0xc0 | ||
52 | #define AZ6007_TS_THROUGH 0xc7 | ||
53 | #define AZ6007_READ_IR 0xb4 | ||
54 | |||
55 | struct az6007_device_state { | ||
56 | struct mutex mutex; | ||
57 | struct mutex ca_mutex; | ||
58 | struct dvb_ca_en50221 ca; | ||
59 | unsigned warm:1; | ||
60 | int (*gate_ctrl) (struct dvb_frontend *, int); | ||
61 | unsigned char data[4096]; | ||
62 | }; | ||
63 | |||
64 | static struct drxk_config terratec_h7_drxk = { | ||
65 | .adr = 0x29, | ||
66 | .parallel_ts = true, | ||
67 | .dynamic_clk = true, | ||
68 | .single_master = true, | ||
69 | .enable_merr_cfg = true, | ||
70 | .no_i2c_bridge = false, | ||
71 | .chunk_size = 64, | ||
72 | .mpeg_out_clk_strength = 0x02, | ||
73 | .microcode_name = "dvb-usb-terratec-h7-drxk.fw", | ||
74 | }; | ||
75 | |||
76 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
77 | { | ||
78 | struct dvb_usb_adapter *adap = fe->sec_priv; | ||
79 | struct az6007_device_state *st; | ||
80 | int status = 0; | ||
81 | |||
82 | deb_info("%s: %s\n", __func__, enable ? "enable" : "disable"); | ||
83 | |||
84 | if (!adap) | ||
85 | return -EINVAL; | ||
86 | |||
87 | st = adap->dev->priv; | ||
88 | |||
89 | if (!st) | ||
90 | return -EINVAL; | ||
91 | |||
92 | if (enable) | ||
93 | status = st->gate_ctrl(fe, 1); | ||
94 | else | ||
95 | status = st->gate_ctrl(fe, 0); | ||
96 | |||
97 | return status; | ||
98 | } | ||
99 | |||
100 | static struct mt2063_config az6007_mt2063_config = { | ||
101 | .tuner_address = 0x60, | ||
102 | .refclock = 36125000, | ||
103 | }; | ||
104 | |||
105 | static int __az6007_read(struct usb_device *udev, u8 req, u16 value, | ||
106 | u16 index, u8 *b, int blen) | ||
107 | { | ||
108 | int ret; | ||
109 | |||
110 | ret = usb_control_msg(udev, | ||
111 | usb_rcvctrlpipe(udev, 0), | ||
112 | req, | ||
113 | USB_TYPE_VENDOR | USB_DIR_IN, | ||
114 | value, index, b, blen, 5000); | ||
115 | if (ret < 0) { | ||
116 | warn("usb read operation failed. (%d)", ret); | ||
117 | return -EIO; | ||
118 | } | ||
119 | |||
120 | deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, | ||
121 | index); | ||
122 | debug_dump(b, blen, deb_xfer); | ||
123 | |||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value, | ||
128 | u16 index, u8 *b, int blen) | ||
129 | { | ||
130 | struct az6007_device_state *st = d->priv; | ||
131 | int ret; | ||
132 | |||
133 | if (mutex_lock_interruptible(&st->mutex) < 0) | ||
134 | return -EAGAIN; | ||
135 | |||
136 | ret = __az6007_read(d->udev, req, value, index, b, blen); | ||
137 | |||
138 | mutex_unlock(&st->mutex); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static int __az6007_write(struct usb_device *udev, u8 req, u16 value, | ||
144 | u16 index, u8 *b, int blen) | ||
145 | { | ||
146 | int ret; | ||
147 | |||
148 | deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, | ||
149 | index); | ||
150 | debug_dump(b, blen, deb_xfer); | ||
151 | |||
152 | if (blen > 64) { | ||
153 | err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n", | ||
154 | blen); | ||
155 | return -EOPNOTSUPP; | ||
156 | } | ||
157 | |||
158 | ret = usb_control_msg(udev, | ||
159 | usb_sndctrlpipe(udev, 0), | ||
160 | req, | ||
161 | USB_TYPE_VENDOR | USB_DIR_OUT, | ||
162 | value, index, b, blen, 5000); | ||
163 | if (ret != blen) { | ||
164 | err("usb write operation failed. (%d)", ret); | ||
165 | return -EIO; | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value, | ||
172 | u16 index, u8 *b, int blen) | ||
173 | { | ||
174 | struct az6007_device_state *st = d->priv; | ||
175 | int ret; | ||
176 | |||
177 | if (mutex_lock_interruptible(&st->mutex) < 0) | ||
178 | return -EAGAIN; | ||
179 | |||
180 | ret = __az6007_write(d->udev, req, value, index, b, blen); | ||
181 | |||
182 | mutex_unlock(&st->mutex); | ||
183 | |||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
188 | { | ||
189 | struct dvb_usb_device *d = adap->dev; | ||
190 | |||
191 | deb_info("%s: %s", __func__, onoff ? "enable" : "disable"); | ||
192 | |||
193 | return az6007_write(d, 0xbc, onoff, 0, NULL, 0); | ||
194 | } | ||
195 | |||
196 | /* remote control stuff (does not work with my box) */ | ||
197 | static int az6007_rc_query(struct dvb_usb_device *d) | ||
198 | { | ||
199 | struct az6007_device_state *st = d->priv; | ||
200 | unsigned code = 0; | ||
201 | |||
202 | az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); | ||
203 | |||
204 | if (st->data[1] == 0x44) | ||
205 | return 0; | ||
206 | |||
207 | if ((st->data[1] ^ st->data[2]) == 0xff) | ||
208 | code = st->data[1]; | ||
209 | else | ||
210 | code = st->data[1] << 8 | st->data[2]; | ||
211 | |||
212 | if ((st->data[3] ^ st->data[4]) == 0xff) | ||
213 | code = code << 8 | st->data[3]; | ||
214 | else | ||
215 | code = code << 16 | st->data[3] << 8 | st->data[4]; | ||
216 | |||
217 | rc_keydown(d->rc_dev, code, st->data[5]); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, | ||
223 | int slot, | ||
224 | int address) | ||
225 | { | ||
226 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
227 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
228 | |||
229 | int ret; | ||
230 | u8 req; | ||
231 | u16 value; | ||
232 | u16 index; | ||
233 | int blen; | ||
234 | u8 *b; | ||
235 | |||
236 | if (slot != 0) | ||
237 | return -EINVAL; | ||
238 | |||
239 | b = kmalloc(12, GFP_KERNEL); | ||
240 | if (!b) | ||
241 | return -ENOMEM; | ||
242 | |||
243 | mutex_lock(&state->ca_mutex); | ||
244 | |||
245 | req = 0xC1; | ||
246 | value = address; | ||
247 | index = 0; | ||
248 | blen = 1; | ||
249 | |||
250 | ret = az6007_read(d, req, value, index, b, blen); | ||
251 | if (ret < 0) { | ||
252 | warn("usb in operation failed. (%d)", ret); | ||
253 | ret = -EINVAL; | ||
254 | } else { | ||
255 | ret = b[0]; | ||
256 | } | ||
257 | |||
258 | mutex_unlock(&state->ca_mutex); | ||
259 | kfree(b); | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, | ||
264 | int slot, | ||
265 | int address, | ||
266 | u8 value) | ||
267 | { | ||
268 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
269 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
270 | |||
271 | int ret; | ||
272 | u8 req; | ||
273 | u16 value1; | ||
274 | u16 index; | ||
275 | int blen; | ||
276 | |||
277 | deb_info("%s %d", __func__, slot); | ||
278 | if (slot != 0) | ||
279 | return -EINVAL; | ||
280 | |||
281 | mutex_lock(&state->ca_mutex); | ||
282 | req = 0xC2; | ||
283 | value1 = address; | ||
284 | index = value; | ||
285 | blen = 0; | ||
286 | |||
287 | ret = az6007_write(d, req, value1, index, NULL, blen); | ||
288 | if (ret != 0) | ||
289 | warn("usb out operation failed. (%d)", ret); | ||
290 | |||
291 | mutex_unlock(&state->ca_mutex); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, | ||
296 | int slot, | ||
297 | u8 address) | ||
298 | { | ||
299 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
300 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
301 | |||
302 | int ret; | ||
303 | u8 req; | ||
304 | u16 value; | ||
305 | u16 index; | ||
306 | int blen; | ||
307 | u8 *b; | ||
308 | |||
309 | if (slot != 0) | ||
310 | return -EINVAL; | ||
311 | |||
312 | b = kmalloc(12, GFP_KERNEL); | ||
313 | if (!b) | ||
314 | return -ENOMEM; | ||
315 | |||
316 | mutex_lock(&state->ca_mutex); | ||
317 | |||
318 | req = 0xC3; | ||
319 | value = address; | ||
320 | index = 0; | ||
321 | blen = 2; | ||
322 | |||
323 | ret = az6007_read(d, req, value, index, b, blen); | ||
324 | if (ret < 0) { | ||
325 | warn("usb in operation failed. (%d)", ret); | ||
326 | ret = -EINVAL; | ||
327 | } else { | ||
328 | if (b[0] == 0) | ||
329 | warn("Read CI IO error"); | ||
330 | |||
331 | ret = b[1]; | ||
332 | deb_info("read cam data = %x from 0x%x", b[1], value); | ||
333 | } | ||
334 | |||
335 | mutex_unlock(&state->ca_mutex); | ||
336 | kfree(b); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, | ||
341 | int slot, | ||
342 | u8 address, | ||
343 | u8 value) | ||
344 | { | ||
345 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
346 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
347 | |||
348 | int ret; | ||
349 | u8 req; | ||
350 | u16 value1; | ||
351 | u16 index; | ||
352 | int blen; | ||
353 | |||
354 | if (slot != 0) | ||
355 | return -EINVAL; | ||
356 | |||
357 | mutex_lock(&state->ca_mutex); | ||
358 | req = 0xC4; | ||
359 | value1 = address; | ||
360 | index = value; | ||
361 | blen = 0; | ||
362 | |||
363 | ret = az6007_write(d, req, value1, index, NULL, blen); | ||
364 | if (ret != 0) { | ||
365 | warn("usb out operation failed. (%d)", ret); | ||
366 | goto failed; | ||
367 | } | ||
368 | |||
369 | failed: | ||
370 | mutex_unlock(&state->ca_mutex); | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) | ||
375 | { | ||
376 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
377 | |||
378 | int ret; | ||
379 | u8 req; | ||
380 | u16 value; | ||
381 | u16 index; | ||
382 | int blen; | ||
383 | u8 *b; | ||
384 | |||
385 | b = kmalloc(12, GFP_KERNEL); | ||
386 | if (!b) | ||
387 | return -ENOMEM; | ||
388 | |||
389 | req = 0xC8; | ||
390 | value = 0; | ||
391 | index = 0; | ||
392 | blen = 1; | ||
393 | |||
394 | ret = az6007_read(d, req, value, index, b, blen); | ||
395 | if (ret < 0) { | ||
396 | warn("usb in operation failed. (%d)", ret); | ||
397 | ret = -EIO; | ||
398 | } else{ | ||
399 | ret = b[0]; | ||
400 | } | ||
401 | kfree(b); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) | ||
406 | { | ||
407 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
408 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
409 | |||
410 | int ret, i; | ||
411 | u8 req; | ||
412 | u16 value; | ||
413 | u16 index; | ||
414 | int blen; | ||
415 | |||
416 | mutex_lock(&state->ca_mutex); | ||
417 | |||
418 | req = 0xC6; | ||
419 | value = 1; | ||
420 | index = 0; | ||
421 | blen = 0; | ||
422 | |||
423 | ret = az6007_write(d, req, value, index, NULL, blen); | ||
424 | if (ret != 0) { | ||
425 | warn("usb out operation failed. (%d)", ret); | ||
426 | goto failed; | ||
427 | } | ||
428 | |||
429 | msleep(500); | ||
430 | req = 0xC6; | ||
431 | value = 0; | ||
432 | index = 0; | ||
433 | blen = 0; | ||
434 | |||
435 | ret = az6007_write(d, req, value, index, NULL, blen); | ||
436 | if (ret != 0) { | ||
437 | warn("usb out operation failed. (%d)", ret); | ||
438 | goto failed; | ||
439 | } | ||
440 | |||
441 | for (i = 0; i < 15; i++) { | ||
442 | msleep(100); | ||
443 | |||
444 | if (CI_CamReady(ca, slot)) { | ||
445 | deb_info("CAM Ready"); | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | msleep(5000); | ||
450 | |||
451 | failed: | ||
452 | mutex_unlock(&state->ca_mutex); | ||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) | ||
457 | { | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) | ||
462 | { | ||
463 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
464 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
465 | |||
466 | int ret; | ||
467 | u8 req; | ||
468 | u16 value; | ||
469 | u16 index; | ||
470 | int blen; | ||
471 | |||
472 | deb_info("%s", __func__); | ||
473 | mutex_lock(&state->ca_mutex); | ||
474 | req = 0xC7; | ||
475 | value = 1; | ||
476 | index = 0; | ||
477 | blen = 0; | ||
478 | |||
479 | ret = az6007_write(d, req, value, index, NULL, blen); | ||
480 | if (ret != 0) { | ||
481 | warn("usb out operation failed. (%d)", ret); | ||
482 | goto failed; | ||
483 | } | ||
484 | |||
485 | failed: | ||
486 | mutex_unlock(&state->ca_mutex); | ||
487 | return ret; | ||
488 | } | ||
489 | |||
490 | static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) | ||
491 | { | ||
492 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
493 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
494 | int ret; | ||
495 | u8 req; | ||
496 | u16 value; | ||
497 | u16 index; | ||
498 | int blen; | ||
499 | u8 *b; | ||
500 | |||
501 | b = kmalloc(12, GFP_KERNEL); | ||
502 | if (!b) | ||
503 | return -ENOMEM; | ||
504 | mutex_lock(&state->ca_mutex); | ||
505 | |||
506 | req = 0xC5; | ||
507 | value = 0; | ||
508 | index = 0; | ||
509 | blen = 1; | ||
510 | |||
511 | ret = az6007_read(d, req, value, index, b, blen); | ||
512 | if (ret < 0) { | ||
513 | warn("usb in operation failed. (%d)", ret); | ||
514 | ret = -EIO; | ||
515 | } else | ||
516 | ret = 0; | ||
517 | |||
518 | if (!ret && b[0] == 1) { | ||
519 | ret = DVB_CA_EN50221_POLL_CAM_PRESENT | | ||
520 | DVB_CA_EN50221_POLL_CAM_READY; | ||
521 | } | ||
522 | |||
523 | mutex_unlock(&state->ca_mutex); | ||
524 | kfree(b); | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | |||
529 | static void az6007_ci_uninit(struct dvb_usb_device *d) | ||
530 | { | ||
531 | struct az6007_device_state *state; | ||
532 | |||
533 | deb_info("%s", __func__); | ||
534 | |||
535 | if (NULL == d) | ||
536 | return; | ||
537 | |||
538 | state = (struct az6007_device_state *)d->priv; | ||
539 | if (NULL == state) | ||
540 | return; | ||
541 | |||
542 | if (NULL == state->ca.data) | ||
543 | return; | ||
544 | |||
545 | dvb_ca_en50221_release(&state->ca); | ||
546 | |||
547 | memset(&state->ca, 0, sizeof(state->ca)); | ||
548 | } | ||
549 | |||
550 | |||
551 | static int az6007_ci_init(struct dvb_usb_adapter *a) | ||
552 | { | ||
553 | struct dvb_usb_device *d = a->dev; | ||
554 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
555 | int ret; | ||
556 | |||
557 | deb_info("%s", __func__); | ||
558 | |||
559 | mutex_init(&state->ca_mutex); | ||
560 | |||
561 | state->ca.owner = THIS_MODULE; | ||
562 | state->ca.read_attribute_mem = az6007_ci_read_attribute_mem; | ||
563 | state->ca.write_attribute_mem = az6007_ci_write_attribute_mem; | ||
564 | state->ca.read_cam_control = az6007_ci_read_cam_control; | ||
565 | state->ca.write_cam_control = az6007_ci_write_cam_control; | ||
566 | state->ca.slot_reset = az6007_ci_slot_reset; | ||
567 | state->ca.slot_shutdown = az6007_ci_slot_shutdown; | ||
568 | state->ca.slot_ts_enable = az6007_ci_slot_ts_enable; | ||
569 | state->ca.poll_slot_status = az6007_ci_poll_slot_status; | ||
570 | state->ca.data = d; | ||
571 | |||
572 | ret = dvb_ca_en50221_init(&a->dvb_adap, | ||
573 | &state->ca, | ||
574 | 0, /* flags */ | ||
575 | 1);/* n_slots */ | ||
576 | if (ret != 0) { | ||
577 | err("Cannot initialize CI: Error %d.", ret); | ||
578 | memset(&state->ca, 0, sizeof(state->ca)); | ||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | deb_info("CI initialized."); | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) | ||
588 | { | ||
589 | struct az6007_device_state *st = d->priv; | ||
590 | int ret; | ||
591 | |||
592 | ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6); | ||
593 | memcpy(mac, st->data, sizeof(mac)); | ||
594 | |||
595 | if (ret > 0) | ||
596 | deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
597 | __func__, mac[0], mac[1], mac[2], | ||
598 | mac[3], mac[4], mac[5]); | ||
599 | |||
600 | return ret; | ||
601 | } | ||
602 | |||
603 | static int az6007_frontend_attach(struct dvb_usb_adapter *adap) | ||
604 | { | ||
605 | struct az6007_device_state *st = adap->dev->priv; | ||
606 | |||
607 | deb_info("attaching demod drxk"); | ||
608 | |||
609 | adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk, | ||
610 | &adap->dev->i2c_adap); | ||
611 | if (!adap->fe_adap[0].fe) | ||
612 | return -EINVAL; | ||
613 | |||
614 | adap->fe_adap[0].fe->sec_priv = adap; | ||
615 | st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl; | ||
616 | adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; | ||
617 | |||
618 | az6007_ci_init(adap); | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int az6007_tuner_attach(struct dvb_usb_adapter *adap) | ||
624 | { | ||
625 | deb_info("attaching tuner mt2063"); | ||
626 | |||
627 | /* Attach mt2063 to DVB-C frontend */ | ||
628 | if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) | ||
629 | adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); | ||
630 | if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe, | ||
631 | &az6007_mt2063_config, | ||
632 | &adap->dev->i2c_adap)) | ||
633 | return -EINVAL; | ||
634 | |||
635 | if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) | ||
636 | adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) | ||
642 | { | ||
643 | struct az6007_device_state *st = d->priv; | ||
644 | int ret; | ||
645 | |||
646 | deb_info("%s()\n", __func__); | ||
647 | |||
648 | if (!st->warm) { | ||
649 | mutex_init(&st->mutex); | ||
650 | |||
651 | ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0); | ||
652 | if (ret < 0) | ||
653 | return ret; | ||
654 | msleep(60); | ||
655 | ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); | ||
656 | if (ret < 0) | ||
657 | return ret; | ||
658 | msleep(100); | ||
659 | ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0); | ||
660 | if (ret < 0) | ||
661 | return ret; | ||
662 | msleep(20); | ||
663 | ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); | ||
664 | if (ret < 0) | ||
665 | return ret; | ||
666 | |||
667 | msleep(400); | ||
668 | ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0); | ||
669 | if (ret < 0) | ||
670 | return ret; | ||
671 | msleep(150); | ||
672 | ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0); | ||
673 | if (ret < 0) | ||
674 | return ret; | ||
675 | msleep(430); | ||
676 | ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); | ||
677 | if (ret < 0) | ||
678 | return ret; | ||
679 | |||
680 | st->warm = true; | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | if (!onoff) | ||
686 | return 0; | ||
687 | |||
688 | az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); | ||
689 | az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0); | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | /* I2C */ | ||
695 | static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | ||
696 | int num) | ||
697 | { | ||
698 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
699 | struct az6007_device_state *st = d->priv; | ||
700 | int i, j, len; | ||
701 | int ret = 0; | ||
702 | u16 index; | ||
703 | u16 value; | ||
704 | int length; | ||
705 | u8 req, addr; | ||
706 | |||
707 | if (mutex_lock_interruptible(&st->mutex) < 0) | ||
708 | return -EAGAIN; | ||
709 | |||
710 | for (i = 0; i < num; i++) { | ||
711 | addr = msgs[i].addr << 1; | ||
712 | if (((i + 1) < num) | ||
713 | && (msgs[i].len == 1) | ||
714 | && (!msgs[i].flags & I2C_M_RD) | ||
715 | && (msgs[i + 1].flags & I2C_M_RD) | ||
716 | && (msgs[i].addr == msgs[i + 1].addr)) { | ||
717 | /* | ||
718 | * A write + read xfer for the same address, where | ||
719 | * the first xfer has just 1 byte length. | ||
720 | * Need to join both into one operation | ||
721 | */ | ||
722 | if (dvb_usb_az6007_debug & 2) | ||
723 | printk(KERN_DEBUG | ||
724 | "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ", | ||
725 | addr, msgs[i].len, msgs[i + 1].len); | ||
726 | req = AZ6007_I2C_RD; | ||
727 | index = msgs[i].buf[0]; | ||
728 | value = addr | (1 << 8); | ||
729 | length = 6 + msgs[i + 1].len; | ||
730 | len = msgs[i + 1].len; | ||
731 | ret = __az6007_read(d->udev, req, value, index, | ||
732 | st->data, length); | ||
733 | if (ret >= len) { | ||
734 | for (j = 0; j < len; j++) { | ||
735 | msgs[i + 1].buf[j] = st->data[j + 5]; | ||
736 | if (dvb_usb_az6007_debug & 2) | ||
737 | printk(KERN_CONT | ||
738 | "0x%02x ", | ||
739 | msgs[i + 1].buf[j]); | ||
740 | } | ||
741 | } else | ||
742 | ret = -EIO; | ||
743 | i++; | ||
744 | } else if (!(msgs[i].flags & I2C_M_RD)) { | ||
745 | /* write bytes */ | ||
746 | if (dvb_usb_az6007_debug & 2) | ||
747 | printk(KERN_DEBUG | ||
748 | "az6007 I2C xfer write addr=0x%x len=%d: ", | ||
749 | addr, msgs[i].len); | ||
750 | req = AZ6007_I2C_WR; | ||
751 | index = msgs[i].buf[0]; | ||
752 | value = addr | (1 << 8); | ||
753 | length = msgs[i].len - 1; | ||
754 | len = msgs[i].len - 1; | ||
755 | if (dvb_usb_az6007_debug & 2) | ||
756 | printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]); | ||
757 | for (j = 0; j < len; j++) { | ||
758 | st->data[j] = msgs[i].buf[j + 1]; | ||
759 | if (dvb_usb_az6007_debug & 2) | ||
760 | printk(KERN_CONT "0x%02x ", | ||
761 | st->data[j]); | ||
762 | } | ||
763 | ret = __az6007_write(d->udev, req, value, index, | ||
764 | st->data, length); | ||
765 | } else { | ||
766 | /* read bytes */ | ||
767 | if (dvb_usb_az6007_debug & 2) | ||
768 | printk(KERN_DEBUG | ||
769 | "az6007 I2C xfer read addr=0x%x len=%d: ", | ||
770 | addr, msgs[i].len); | ||
771 | req = AZ6007_I2C_RD; | ||
772 | index = msgs[i].buf[0]; | ||
773 | value = addr; | ||
774 | length = msgs[i].len + 6; | ||
775 | len = msgs[i].len; | ||
776 | ret = __az6007_read(d->udev, req, value, index, | ||
777 | st->data, length); | ||
778 | for (j = 0; j < len; j++) { | ||
779 | msgs[i].buf[j] = st->data[j + 5]; | ||
780 | if (dvb_usb_az6007_debug & 2) | ||
781 | printk(KERN_CONT | ||
782 | "0x%02x ", st->data[j + 5]); | ||
783 | } | ||
784 | } | ||
785 | if (dvb_usb_az6007_debug & 2) | ||
786 | printk(KERN_CONT "\n"); | ||
787 | if (ret < 0) | ||
788 | goto err; | ||
789 | } | ||
790 | err: | ||
791 | mutex_unlock(&st->mutex); | ||
792 | |||
793 | if (ret < 0) { | ||
794 | info("%s ERROR: %i", __func__, ret); | ||
795 | return ret; | ||
796 | } | ||
797 | return num; | ||
798 | } | ||
799 | |||
800 | static u32 az6007_i2c_func(struct i2c_adapter *adapter) | ||
801 | { | ||
802 | return I2C_FUNC_I2C; | ||
803 | } | ||
804 | |||
805 | static struct i2c_algorithm az6007_i2c_algo = { | ||
806 | .master_xfer = az6007_i2c_xfer, | ||
807 | .functionality = az6007_i2c_func, | ||
808 | }; | ||
809 | |||
810 | int az6007_identify_state(struct usb_device *udev, | ||
811 | struct dvb_usb_device_properties *props, | ||
812 | struct dvb_usb_device_description **desc, int *cold) | ||
813 | { | ||
814 | int ret; | ||
815 | u8 *mac; | ||
816 | |||
817 | mac = kmalloc(6, GFP_ATOMIC); | ||
818 | if (!mac) | ||
819 | return -ENOMEM; | ||
820 | |||
821 | /* Try to read the mac address */ | ||
822 | ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6); | ||
823 | if (ret == 6) | ||
824 | *cold = 0; | ||
825 | else | ||
826 | *cold = 1; | ||
827 | |||
828 | kfree(mac); | ||
829 | |||
830 | if (*cold) { | ||
831 | __az6007_write(udev, 0x09, 1, 0, NULL, 0); | ||
832 | __az6007_write(udev, 0x00, 0, 0, NULL, 0); | ||
833 | __az6007_write(udev, 0x00, 0, 0, NULL, 0); | ||
834 | } | ||
835 | |||
836 | deb_info("Device is on %s state\n", *cold ? "warm" : "cold"); | ||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | static struct dvb_usb_device_properties az6007_properties; | ||
841 | |||
842 | static void az6007_usb_disconnect(struct usb_interface *intf) | ||
843 | { | ||
844 | struct dvb_usb_device *d = usb_get_intfdata(intf); | ||
845 | az6007_ci_uninit(d); | ||
846 | dvb_usb_device_exit(intf); | ||
847 | } | ||
848 | |||
849 | static int az6007_usb_probe(struct usb_interface *intf, | ||
850 | const struct usb_device_id *id) | ||
851 | { | ||
852 | return dvb_usb_device_init(intf, &az6007_properties, | ||
853 | THIS_MODULE, NULL, adapter_nr); | ||
854 | } | ||
855 | |||
856 | static struct usb_device_id az6007_usb_table[] = { | ||
857 | {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)}, | ||
858 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)}, | ||
859 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)}, | ||
860 | {0}, | ||
861 | }; | ||
862 | |||
863 | MODULE_DEVICE_TABLE(usb, az6007_usb_table); | ||
864 | |||
865 | static struct dvb_usb_device_properties az6007_properties = { | ||
866 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
867 | .usb_ctrl = CYPRESS_FX2, | ||
868 | .firmware = "dvb-usb-terratec-h7-az6007.fw", | ||
869 | .no_reconnect = 1, | ||
870 | .size_of_priv = sizeof(struct az6007_device_state), | ||
871 | .identify_state = az6007_identify_state, | ||
872 | .num_adapters = 1, | ||
873 | .adapter = { | ||
874 | { | ||
875 | .num_frontends = 1, | ||
876 | .fe = {{ | ||
877 | .streaming_ctrl = az6007_streaming_ctrl, | ||
878 | .tuner_attach = az6007_tuner_attach, | ||
879 | .frontend_attach = az6007_frontend_attach, | ||
880 | |||
881 | /* parameter for the MPEG2-data transfer */ | ||
882 | .stream = { | ||
883 | .type = USB_BULK, | ||
884 | .count = 10, | ||
885 | .endpoint = 0x02, | ||
886 | .u = { | ||
887 | .bulk = { | ||
888 | .buffersize = 4096, | ||
889 | } | ||
890 | } | ||
891 | }, | ||
892 | } } | ||
893 | } }, | ||
894 | .power_ctrl = az6007_power_ctrl, | ||
895 | .read_mac_address = az6007_read_mac_addr, | ||
896 | |||
897 | .rc.core = { | ||
898 | .rc_interval = 400, | ||
899 | .rc_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, | ||
900 | .module_name = "az6007", | ||
901 | .rc_query = az6007_rc_query, | ||
902 | .allowed_protos = RC_TYPE_NEC, | ||
903 | }, | ||
904 | .i2c_algo = &az6007_i2c_algo, | ||
905 | |||
906 | .num_device_descs = 2, | ||
907 | .devices = { | ||
908 | { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)", | ||
909 | .cold_ids = { &az6007_usb_table[0], NULL }, | ||
910 | .warm_ids = { NULL }, | ||
911 | }, | ||
912 | { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)", | ||
913 | .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL }, | ||
914 | .warm_ids = { NULL }, | ||
915 | }, | ||
916 | { NULL }, | ||
917 | } | ||
918 | }; | ||
919 | |||
920 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
921 | static struct usb_driver az6007_usb_driver = { | ||
922 | .name = "dvb_usb_az6007", | ||
923 | .probe = az6007_usb_probe, | ||
924 | .disconnect = az6007_usb_disconnect, | ||
925 | .id_table = az6007_usb_table, | ||
926 | }; | ||
927 | |||
928 | /* module stuff */ | ||
929 | static int __init az6007_usb_module_init(void) | ||
930 | { | ||
931 | int result; | ||
932 | deb_info("az6007 usb module init\n"); | ||
933 | |||
934 | result = usb_register(&az6007_usb_driver); | ||
935 | if (result) { | ||
936 | err("usb_register failed. (%d)", result); | ||
937 | return result; | ||
938 | } | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static void __exit az6007_usb_module_exit(void) | ||
944 | { | ||
945 | /* deregister this driver from the USB subsystem */ | ||
946 | deb_info("az6007 usb module exit\n"); | ||
947 | usb_deregister(&az6007_usb_driver); | ||
948 | } | ||
949 | |||
950 | module_init(az6007_usb_module_init); | ||
951 | module_exit(az6007_usb_module_exit); | ||
952 | |||
953 | MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>"); | ||
954 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | ||
955 | MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); | ||
956 | MODULE_VERSION("1.1"); | ||
957 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 070e82aa53f5..02290c60f72f 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c | |||
@@ -677,11 +677,9 @@ static void dib0700_rc_urb_completion(struct urb *purb) | |||
677 | u8 toggle; | 677 | u8 toggle; |
678 | 678 | ||
679 | deb_info("%s()\n", __func__); | 679 | deb_info("%s()\n", __func__); |
680 | if (d == NULL) | ||
681 | return; | ||
682 | |||
683 | if (d->rc_dev == NULL) { | 680 | if (d->rc_dev == NULL) { |
684 | /* This will occur if disable_rc_polling=1 */ | 681 | /* This will occur if disable_rc_polling=1 */ |
682 | kfree(purb->transfer_buffer); | ||
685 | usb_free_urb(purb); | 683 | usb_free_urb(purb); |
686 | return; | 684 | return; |
687 | } | 685 | } |
@@ -690,6 +688,7 @@ static void dib0700_rc_urb_completion(struct urb *purb) | |||
690 | 688 | ||
691 | if (purb->status < 0) { | 689 | if (purb->status < 0) { |
692 | deb_info("discontinuing polling\n"); | 690 | deb_info("discontinuing polling\n"); |
691 | kfree(purb->transfer_buffer); | ||
693 | usb_free_urb(purb); | 692 | usb_free_urb(purb); |
694 | return; | 693 | return; |
695 | } | 694 | } |
@@ -784,8 +783,11 @@ int dib0700_rc_setup(struct dvb_usb_device *d) | |||
784 | dib0700_rc_urb_completion, d); | 783 | dib0700_rc_urb_completion, d); |
785 | 784 | ||
786 | ret = usb_submit_urb(purb, GFP_ATOMIC); | 785 | ret = usb_submit_urb(purb, GFP_ATOMIC); |
787 | if (ret) | 786 | if (ret) { |
788 | err("rc submit urb failed\n"); | 787 | err("rc submit urb failed\n"); |
788 | kfree(purb->transfer_buffer); | ||
789 | usb_free_urb(purb); | ||
790 | } | ||
789 | 791 | ||
790 | return ret; | 792 | return ret; |
791 | } | 793 | } |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index d390ddaa5a53..397d8f232731 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
@@ -51,6 +51,7 @@ | |||
51 | #define USB_VID_PINNACLE 0x2304 | 51 | #define USB_VID_PINNACLE 0x2304 |
52 | #define USB_VID_PCTV 0x2013 | 52 | #define USB_VID_PCTV 0x2013 |
53 | #define USB_VID_PIXELVIEW 0x1554 | 53 | #define USB_VID_PIXELVIEW 0x1554 |
54 | #define USB_VID_REALTEK 0x0bda | ||
54 | #define USB_VID_TECHNOTREND 0x0b48 | 55 | #define USB_VID_TECHNOTREND 0x0b48 |
55 | #define USB_VID_TERRATEC 0x0ccd | 56 | #define USB_VID_TERRATEC 0x0ccd |
56 | #define USB_VID_TELESTAR 0x10b9 | 57 | #define USB_VID_TELESTAR 0x10b9 |
@@ -80,6 +81,7 @@ | |||
80 | #define USB_PID_ANSONIC_DVBT_USB 0x6000 | 81 | #define USB_PID_ANSONIC_DVBT_USB 0x6000 |
81 | #define USB_PID_ANYSEE 0x861f | 82 | #define USB_PID_ANYSEE 0x861f |
82 | #define USB_PID_AZUREWAVE_AD_TU700 0x3237 | 83 | #define USB_PID_AZUREWAVE_AD_TU700 0x3237 |
84 | #define USB_PID_AZUREWAVE_6007 0x0ccd | ||
83 | #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 | 85 | #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 |
84 | #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 | 86 | #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 |
85 | #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 | 87 | #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 |
@@ -125,6 +127,8 @@ | |||
125 | #define USB_PID_E3C_EC168_3 0xfffb | 127 | #define USB_PID_E3C_EC168_3 0xfffb |
126 | #define USB_PID_E3C_EC168_4 0x1001 | 128 | #define USB_PID_E3C_EC168_4 0x1001 |
127 | #define USB_PID_E3C_EC168_5 0x1002 | 129 | #define USB_PID_E3C_EC168_5 0x1002 |
130 | #define USB_PID_FREECOM_DVBT 0x0160 | ||
131 | #define USB_PID_FREECOM_DVBT_2 0x0161 | ||
128 | #define USB_PID_UNIWILL_STK7700P 0x6003 | 132 | #define USB_PID_UNIWILL_STK7700P 0x6003 |
129 | #define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 | 133 | #define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 |
130 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 | 134 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 |
@@ -226,6 +230,8 @@ | |||
226 | #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 | 230 | #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 |
227 | #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 | 231 | #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 |
228 | #define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab | 232 | #define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab |
233 | #define USB_PID_TERRATEC_H7 0x10b4 | ||
234 | #define USB_PID_TERRATEC_H7_2 0x10a3 | ||
229 | #define USB_PID_TERRATEC_T3 0x10a0 | 235 | #define USB_PID_TERRATEC_T3 0x10a0 |
230 | #define USB_PID_TERRATEC_T5 0x10a1 | 236 | #define USB_PID_TERRATEC_T5 0x10a1 |
231 | #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e | 237 | #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e |
@@ -249,6 +255,8 @@ | |||
249 | #define USB_PID_PCTV_400E 0x020f | 255 | #define USB_PID_PCTV_400E 0x020f |
250 | #define USB_PID_PCTV_450E 0x0222 | 256 | #define USB_PID_PCTV_450E 0x0222 |
251 | #define USB_PID_PCTV_452E 0x021f | 257 | #define USB_PID_PCTV_452E 0x021f |
258 | #define USB_PID_REALTEK_RTL2831U 0x2831 | ||
259 | #define USB_PID_REALTEK_RTL2832U 0x2832 | ||
252 | #define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007 | 260 | #define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007 |
253 | #define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a | 261 | #define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a |
254 | #define USB_PID_NEBULA_DIGITV 0x0201 | 262 | #define USB_PID_NEBULA_DIGITV 0x0201 |
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index 9f01cd7a6e3f..3b7b102f20ae 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c | |||
@@ -64,6 +64,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |||
64 | struct it913x_state { | 64 | struct it913x_state { |
65 | u8 id; | 65 | u8 id; |
66 | struct ite_config it913x_config; | 66 | struct ite_config it913x_config; |
67 | u8 pid_filter_onoff; | ||
67 | }; | 68 | }; |
68 | 69 | ||
69 | struct ite_config it913x_config; | 70 | struct ite_config it913x_config; |
@@ -259,15 +260,16 @@ static u32 it913x_query(struct usb_device *udev, u8 pro) | |||
259 | 260 | ||
260 | static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) | 261 | static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) |
261 | { | 262 | { |
263 | struct it913x_state *st = adap->dev->priv; | ||
262 | struct usb_device *udev = adap->dev->udev; | 264 | struct usb_device *udev = adap->dev->udev; |
263 | int ret; | 265 | int ret; |
264 | u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; | 266 | u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; |
265 | 267 | ||
266 | if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) | 268 | mutex_lock(&adap->dev->i2c_mutex); |
267 | return -EAGAIN; | 269 | |
268 | deb_info(1, "PID_C (%02x)", onoff); | 270 | deb_info(1, "PID_C (%02x)", onoff); |
269 | 271 | ||
270 | ret = it913x_wr_reg(udev, pro, PID_EN, onoff); | 272 | ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff); |
271 | 273 | ||
272 | mutex_unlock(&adap->dev->i2c_mutex); | 274 | mutex_unlock(&adap->dev->i2c_mutex); |
273 | return ret; | 275 | return ret; |
@@ -276,12 +278,13 @@ static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
276 | static int it913x_pid_filter(struct dvb_usb_adapter *adap, | 278 | static int it913x_pid_filter(struct dvb_usb_adapter *adap, |
277 | int index, u16 pid, int onoff) | 279 | int index, u16 pid, int onoff) |
278 | { | 280 | { |
281 | struct it913x_state *st = adap->dev->priv; | ||
279 | struct usb_device *udev = adap->dev->udev; | 282 | struct usb_device *udev = adap->dev->udev; |
280 | int ret; | 283 | int ret; |
281 | u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; | 284 | u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; |
282 | 285 | ||
283 | if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) | 286 | mutex_lock(&adap->dev->i2c_mutex); |
284 | return -EAGAIN; | 287 | |
285 | deb_info(1, "PID_F (%02x)", onoff); | 288 | deb_info(1, "PID_F (%02x)", onoff); |
286 | 289 | ||
287 | ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); | 290 | ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); |
@@ -292,6 +295,13 @@ static int it913x_pid_filter(struct dvb_usb_adapter *adap, | |||
292 | 295 | ||
293 | ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); | 296 | ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); |
294 | 297 | ||
298 | if (udev->speed == USB_SPEED_HIGH && pid == 0x2000) { | ||
299 | ret |= it913x_wr_reg(udev, pro, PID_EN, !onoff); | ||
300 | st->pid_filter_onoff = !onoff; | ||
301 | } else | ||
302 | st->pid_filter_onoff = | ||
303 | adap->fe_adap[adap->active_fe].pid_filtering; | ||
304 | |||
295 | mutex_unlock(&adap->dev->i2c_mutex); | 305 | mutex_unlock(&adap->dev->i2c_mutex); |
296 | return 0; | 306 | return 0; |
297 | } | 307 | } |
@@ -316,8 +326,8 @@ static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
316 | int ret; | 326 | int ret; |
317 | u32 reg; | 327 | u32 reg; |
318 | u8 pro; | 328 | u8 pro; |
319 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 329 | |
320 | return -EAGAIN; | 330 | mutex_lock(&d->i2c_mutex); |
321 | 331 | ||
322 | debug_data_snipet(1, "Message out", msg[0].buf); | 332 | debug_data_snipet(1, "Message out", msg[0].buf); |
323 | deb_info(2, "num of messages %d address %02x", num, msg[0].addr); | 333 | deb_info(2, "num of messages %d address %02x", num, msg[0].addr); |
@@ -358,8 +368,7 @@ static int it913x_rc_query(struct dvb_usb_device *d) | |||
358 | int ret; | 368 | int ret; |
359 | u32 key; | 369 | u32 key; |
360 | /* Avoid conflict with frontends*/ | 370 | /* Avoid conflict with frontends*/ |
361 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 371 | mutex_lock(&d->i2c_mutex); |
362 | return -EAGAIN; | ||
363 | 372 | ||
364 | ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET, | 373 | ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET, |
365 | 0, 0, &ibuf[0], sizeof(ibuf)); | 374 | 0, 0, &ibuf[0], sizeof(ibuf)); |
@@ -388,19 +397,12 @@ static int ite_firmware_select(struct usb_device *udev, | |||
388 | { | 397 | { |
389 | int sw; | 398 | int sw; |
390 | /* auto switch */ | 399 | /* auto switch */ |
391 | if (le16_to_cpu(udev->descriptor.idProduct) == | 400 | if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_KWORLD_2) |
392 | USB_PID_ITETECH_IT9135) | 401 | sw = IT9137_FW; |
393 | sw = IT9135_V1_FW; | 402 | else if (it913x_config.chip_ver == 1) |
394 | else if (le16_to_cpu(udev->descriptor.idProduct) == | ||
395 | USB_PID_ITETECH_IT9135_9005) | ||
396 | sw = IT9135_V1_FW; | 403 | sw = IT9135_V1_FW; |
397 | else if (le16_to_cpu(udev->descriptor.idProduct) == | 404 | else |
398 | USB_PID_ITETECH_IT9135_9006) { | ||
399 | sw = IT9135_V2_FW; | 405 | sw = IT9135_V2_FW; |
400 | if (it913x_config.tuner_id_0 == 0) | ||
401 | it913x_config.tuner_id_0 = IT9135_60; | ||
402 | } else | ||
403 | sw = IT9137_FW; | ||
404 | 406 | ||
405 | /* force switch */ | 407 | /* force switch */ |
406 | if (dvb_usb_it913x_firmware != IT9135_AUTO) | 408 | if (dvb_usb_it913x_firmware != IT9135_AUTO) |
@@ -410,41 +412,103 @@ static int ite_firmware_select(struct usb_device *udev, | |||
410 | case IT9135_V1_FW: | 412 | case IT9135_V1_FW: |
411 | it913x_config.firmware_ver = 1; | 413 | it913x_config.firmware_ver = 1; |
412 | it913x_config.adc_x2 = 1; | 414 | it913x_config.adc_x2 = 1; |
415 | it913x_config.read_slevel = false; | ||
413 | props->firmware = fw_it9135_v1; | 416 | props->firmware = fw_it9135_v1; |
414 | break; | 417 | break; |
415 | case IT9135_V2_FW: | 418 | case IT9135_V2_FW: |
416 | it913x_config.firmware_ver = 1; | 419 | it913x_config.firmware_ver = 1; |
417 | it913x_config.adc_x2 = 1; | 420 | it913x_config.adc_x2 = 1; |
421 | it913x_config.read_slevel = false; | ||
418 | props->firmware = fw_it9135_v2; | 422 | props->firmware = fw_it9135_v2; |
423 | switch (it913x_config.tuner_id_0) { | ||
424 | case IT9135_61: | ||
425 | case IT9135_62: | ||
426 | break; | ||
427 | default: | ||
428 | info("Unknown tuner ID applying default 0x60"); | ||
429 | case IT9135_60: | ||
430 | it913x_config.tuner_id_0 = IT9135_60; | ||
431 | } | ||
419 | break; | 432 | break; |
420 | case IT9137_FW: | 433 | case IT9137_FW: |
421 | default: | 434 | default: |
422 | it913x_config.firmware_ver = 0; | 435 | it913x_config.firmware_ver = 0; |
423 | it913x_config.adc_x2 = 0; | 436 | it913x_config.adc_x2 = 0; |
437 | it913x_config.read_slevel = true; | ||
424 | props->firmware = fw_it9137; | 438 | props->firmware = fw_it9137; |
425 | } | 439 | } |
426 | 440 | ||
427 | return 0; | 441 | return 0; |
428 | } | 442 | } |
429 | 443 | ||
444 | static void it913x_select_remote(struct usb_device *udev, | ||
445 | struct dvb_usb_device_properties *props) | ||
446 | { | ||
447 | switch (le16_to_cpu(udev->descriptor.idProduct)) { | ||
448 | case USB_PID_ITETECH_IT9135_9005: | ||
449 | props->rc.core.rc_codes = RC_MAP_IT913X_V2; | ||
450 | return; | ||
451 | default: | ||
452 | props->rc.core.rc_codes = RC_MAP_IT913X_V1; | ||
453 | } | ||
454 | return; | ||
455 | } | ||
456 | |||
430 | #define TS_MPEG_PKT_SIZE 188 | 457 | #define TS_MPEG_PKT_SIZE 188 |
431 | #define EP_LOW 21 | 458 | #define EP_LOW 21 |
432 | #define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) | 459 | #define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) |
433 | #define EP_HIGH 348 | 460 | #define EP_HIGH 348 |
434 | #define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) | 461 | #define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) |
435 | 462 | ||
436 | static int it913x_identify_state(struct usb_device *udev, | 463 | static int it913x_select_config(struct usb_device *udev, |
437 | struct dvb_usb_device_properties *props, | 464 | struct dvb_usb_device_properties *props) |
438 | struct dvb_usb_device_description **desc, | ||
439 | int *cold) | ||
440 | { | 465 | { |
441 | int ret = 0, firm_no; | 466 | int ret = 0, reg; |
442 | u8 reg, remote; | 467 | bool proprietary_ir = false; |
443 | 468 | ||
444 | firm_no = it913x_return_status(udev); | 469 | if (it913x_config.chip_ver == 0x02 |
470 | && it913x_config.chip_type == 0x9135) | ||
471 | reg = it913x_read_reg(udev, 0x461d); | ||
472 | else | ||
473 | reg = it913x_read_reg(udev, 0x461b); | ||
445 | 474 | ||
446 | /* checnk for dual mode */ | 475 | if (reg < 0) |
447 | it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); | 476 | return reg; |
477 | |||
478 | if (reg == 0) { | ||
479 | it913x_config.dual_mode = 0; | ||
480 | it913x_config.tuner_id_0 = IT9135_38; | ||
481 | proprietary_ir = true; | ||
482 | } else { | ||
483 | /* TS mode */ | ||
484 | reg = it913x_read_reg(udev, 0x49c5); | ||
485 | if (reg < 0) | ||
486 | return reg; | ||
487 | it913x_config.dual_mode = reg; | ||
488 | |||
489 | /* IR mode type */ | ||
490 | reg = it913x_read_reg(udev, 0x49ac); | ||
491 | if (reg < 0) | ||
492 | return reg; | ||
493 | if (reg == 5) { | ||
494 | info("Remote propriety (raw) mode"); | ||
495 | proprietary_ir = true; | ||
496 | } else if (reg == 1) { | ||
497 | info("Remote HID mode NOT SUPPORTED"); | ||
498 | proprietary_ir = false; | ||
499 | props->rc.core.rc_codes = NULL; | ||
500 | } else | ||
501 | props->rc.core.rc_codes = NULL; | ||
502 | |||
503 | /* Tuner_id */ | ||
504 | reg = it913x_read_reg(udev, 0x49d0); | ||
505 | if (reg < 0) | ||
506 | return reg; | ||
507 | it913x_config.tuner_id_0 = reg; | ||
508 | } | ||
509 | |||
510 | if (proprietary_ir) | ||
511 | it913x_select_remote(udev, props); | ||
448 | 512 | ||
449 | if (udev->speed != USB_SPEED_HIGH) { | 513 | if (udev->speed != USB_SPEED_HIGH) { |
450 | props->adapter[0].fe[0].pid_filter_count = 5; | 514 | props->adapter[0].fe[0].pid_filter_count = 5; |
@@ -459,17 +523,6 @@ static int it913x_identify_state(struct usb_device *udev, | |||
459 | if(props->adapter[0].fe[0].pid_filter_count == 5) | 523 | if(props->adapter[0].fe[0].pid_filter_count == 5) |
460 | props->adapter[0].fe[0].pid_filter_count = 31; | 524 | props->adapter[0].fe[0].pid_filter_count = 31; |
461 | 525 | ||
462 | /* TODO different remotes */ | ||
463 | remote = it913x_read_reg(udev, 0x49ac); /* Remote */ | ||
464 | if (remote == 0) | ||
465 | props->rc.core.rc_codes = NULL; | ||
466 | |||
467 | /* TODO at the moment tuner_id is always assigned to 0x38 */ | ||
468 | it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0); | ||
469 | |||
470 | info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode | ||
471 | , remote, it913x_config.tuner_id_0); | ||
472 | |||
473 | /* Select Stream Buffer Size and pid filter option*/ | 526 | /* Select Stream Buffer Size and pid filter option*/ |
474 | if (pid_filter) { | 527 | if (pid_filter) { |
475 | props->adapter[0].fe[0].stream.u.bulk.buffersize = | 528 | props->adapter[0].fe[0].stream.u.bulk.buffersize = |
@@ -490,8 +543,29 @@ static int it913x_identify_state(struct usb_device *udev, | |||
490 | } else | 543 | } else |
491 | props->num_adapters = 1; | 544 | props->num_adapters = 1; |
492 | 545 | ||
546 | info("Dual mode=%x Tuner Type=%x", it913x_config.dual_mode, | ||
547 | it913x_config.tuner_id_0); | ||
548 | |||
493 | ret = ite_firmware_select(udev, props); | 549 | ret = ite_firmware_select(udev, props); |
494 | 550 | ||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | static int it913x_identify_state(struct usb_device *udev, | ||
555 | struct dvb_usb_device_properties *props, | ||
556 | struct dvb_usb_device_description **desc, | ||
557 | int *cold) | ||
558 | { | ||
559 | int ret = 0, firm_no; | ||
560 | u8 reg; | ||
561 | |||
562 | firm_no = it913x_return_status(udev); | ||
563 | |||
564 | /* Read and select config */ | ||
565 | ret = it913x_select_config(udev, props); | ||
566 | if (ret < 0) | ||
567 | return ret; | ||
568 | |||
495 | if (firm_no > 0) { | 569 | if (firm_no > 0) { |
496 | *cold = 0; | 570 | *cold = 0; |
497 | return 0; | 571 | return 0; |
@@ -538,18 +612,22 @@ static int it913x_identify_state(struct usb_device *udev, | |||
538 | 612 | ||
539 | static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | 613 | static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) |
540 | { | 614 | { |
615 | struct it913x_state *st = adap->dev->priv; | ||
541 | int ret = 0; | 616 | int ret = 0; |
542 | u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; | 617 | u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; |
543 | 618 | ||
544 | if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) | ||
545 | return -EAGAIN; | ||
546 | deb_info(1, "STM (%02x)", onoff); | 619 | deb_info(1, "STM (%02x)", onoff); |
547 | 620 | ||
548 | if (!onoff) | 621 | if (!onoff) { |
622 | mutex_lock(&adap->dev->i2c_mutex); | ||
623 | |||
549 | ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); | 624 | ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); |
550 | 625 | ||
626 | mutex_unlock(&adap->dev->i2c_mutex); | ||
627 | st->pid_filter_onoff = | ||
628 | adap->fe_adap[adap->active_fe].pid_filtering; | ||
551 | 629 | ||
552 | mutex_unlock(&adap->dev->i2c_mutex); | 630 | } |
553 | 631 | ||
554 | return ret; | 632 | return ret; |
555 | } | 633 | } |
@@ -789,7 +867,7 @@ static struct dvb_usb_device_properties it913x_properties = { | |||
789 | .rc_query = it913x_rc_query, | 867 | .rc_query = it913x_rc_query, |
790 | .rc_interval = IT913X_POLL, | 868 | .rc_interval = IT913X_POLL, |
791 | .allowed_protos = RC_TYPE_NEC, | 869 | .allowed_protos = RC_TYPE_NEC, |
792 | .rc_codes = RC_MAP_MSI_DIGIVOX_III, | 870 | .rc_codes = RC_MAP_IT913X_V1, |
793 | }, | 871 | }, |
794 | .i2c_algo = &it913x_i2c_algo, | 872 | .i2c_algo = &it913x_i2c_algo, |
795 | .num_device_descs = 5, | 873 | .num_device_descs = 5, |
@@ -823,5 +901,5 @@ module_usb_driver(it913x_driver); | |||
823 | 901 | ||
824 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); | 902 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); |
825 | MODULE_DESCRIPTION("it913x USB 2 Driver"); | 903 | MODULE_DESCRIPTION("it913x USB 2 Driver"); |
826 | MODULE_VERSION("1.22"); | 904 | MODULE_VERSION("1.27"); |
827 | MODULE_LICENSE("GPL"); | 905 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 291f6b110399..5dde06d066ff 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c | |||
@@ -77,6 +77,7 @@ | |||
77 | #include "stv0299.h" | 77 | #include "stv0299.h" |
78 | #include "dvb-pll.h" | 78 | #include "dvb-pll.h" |
79 | #include "z0194a.h" | 79 | #include "z0194a.h" |
80 | #include "m88rs2000.h" | ||
80 | 81 | ||
81 | 82 | ||
82 | 83 | ||
@@ -104,7 +105,7 @@ MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); | |||
104 | 105 | ||
105 | static int pid_filter; | 106 | static int pid_filter; |
106 | module_param_named(pid, pid_filter, int, 0644); | 107 | module_param_named(pid, pid_filter, int, 0644); |
107 | MODULE_PARM_DESC(pid, "set default 0=on 1=off"); | 108 | MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on"); |
108 | 109 | ||
109 | 110 | ||
110 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 111 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
@@ -113,6 +114,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |||
113 | #define TUNER_LG 0x1 | 114 | #define TUNER_LG 0x1 |
114 | #define TUNER_S7395 0x2 | 115 | #define TUNER_S7395 0x2 |
115 | #define TUNER_S0194 0x3 | 116 | #define TUNER_S0194 0x3 |
117 | #define TUNER_RS2000 0x4 | ||
116 | 118 | ||
117 | struct lme2510_state { | 119 | struct lme2510_state { |
118 | u8 id; | 120 | u8 id; |
@@ -121,6 +123,8 @@ struct lme2510_state { | |||
121 | u8 signal_level; | 123 | u8 signal_level; |
122 | u8 signal_sn; | 124 | u8 signal_sn; |
123 | u8 time_key; | 125 | u8 time_key; |
126 | u8 last_key; | ||
127 | u8 key_timeout; | ||
124 | u8 i2c_talk_onoff; | 128 | u8 i2c_talk_onoff; |
125 | u8 i2c_gate; | 129 | u8 i2c_gate; |
126 | u8 i2c_tuner_gate_w; | 130 | u8 i2c_tuner_gate_w; |
@@ -128,6 +132,7 @@ struct lme2510_state { | |||
128 | u8 i2c_tuner_addr; | 132 | u8 i2c_tuner_addr; |
129 | u8 stream_on; | 133 | u8 stream_on; |
130 | u8 pid_size; | 134 | u8 pid_size; |
135 | u8 pid_off; | ||
131 | void *buffer; | 136 | void *buffer; |
132 | struct urb *lme_urb; | 137 | struct urb *lme_urb; |
133 | void *usb_buffer; | 138 | void *usb_buffer; |
@@ -178,14 +183,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, | |||
178 | /* the read/write capped at 64 */ | 183 | /* the read/write capped at 64 */ |
179 | memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); | 184 | memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); |
180 | 185 | ||
181 | ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01)); | ||
182 | |||
183 | ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); | 186 | ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); |
184 | 187 | ||
185 | msleep(10); | ||
186 | |||
187 | ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01)); | ||
188 | |||
189 | ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? | 188 | ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? |
190 | rlen : 64 , 0x01); | 189 | rlen : 64 , 0x01); |
191 | 190 | ||
@@ -199,9 +198,14 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, | |||
199 | 198 | ||
200 | static int lme2510_stream_restart(struct dvb_usb_device *d) | 199 | static int lme2510_stream_restart(struct dvb_usb_device *d) |
201 | { | 200 | { |
202 | static u8 stream_on[] = LME_ST_ON_W; | 201 | struct lme2510_state *st = d->priv; |
202 | u8 all_pids[] = LME_ALL_PIDS; | ||
203 | u8 stream_on[] = LME_ST_ON_W; | ||
203 | int ret; | 204 | int ret; |
204 | u8 rbuff[10]; | 205 | u8 rbuff[1]; |
206 | if (st->pid_off) | ||
207 | ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids), | ||
208 | rbuff, sizeof(rbuff)); | ||
205 | /*Restart Stream Command*/ | 209 | /*Restart Stream Command*/ |
206 | ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), | 210 | ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), |
207 | rbuff, sizeof(rbuff)); | 211 | rbuff, sizeof(rbuff)); |
@@ -308,6 +312,14 @@ static void lme2510_int_response(struct urb *lme_urb) | |||
308 | ((ibuf[2] & 0x01) << 0x03); | 312 | ((ibuf[2] & 0x01) << 0x03); |
309 | } | 313 | } |
310 | break; | 314 | break; |
315 | case TUNER_RS2000: | ||
316 | if (ibuf[2] > 0) | ||
317 | st->signal_lock = 0xff; | ||
318 | else | ||
319 | st->signal_lock = 0xf0; | ||
320 | st->signal_level = ibuf[4]; | ||
321 | st->signal_sn = ibuf[5]; | ||
322 | st->time_key = ibuf[7]; | ||
311 | default: | 323 | default: |
312 | break; | 324 | break; |
313 | } | 325 | } |
@@ -359,19 +371,20 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) | |||
359 | static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) | 371 | static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) |
360 | { | 372 | { |
361 | struct lme2510_state *st = adap->dev->priv; | 373 | struct lme2510_state *st = adap->dev->priv; |
362 | static u8 clear_pid_reg[] = LME_CLEAR_PID; | 374 | static u8 clear_pid_reg[] = LME_ALL_PIDS; |
363 | static u8 rbuf[1]; | 375 | static u8 rbuf[1]; |
364 | int ret; | 376 | int ret; |
365 | 377 | ||
366 | deb_info(1, "PID Clearing Filter"); | 378 | deb_info(1, "PID Clearing Filter"); |
367 | 379 | ||
368 | ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); | 380 | mutex_lock(&adap->dev->i2c_mutex); |
369 | if (ret < 0) | ||
370 | return -EAGAIN; | ||
371 | 381 | ||
372 | if (!onoff) | 382 | if (!onoff) { |
373 | ret |= lme2510_usb_talk(adap->dev, clear_pid_reg, | 383 | ret |= lme2510_usb_talk(adap->dev, clear_pid_reg, |
374 | sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); | 384 | sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); |
385 | st->pid_off = true; | ||
386 | } else | ||
387 | st->pid_off = false; | ||
375 | 388 | ||
376 | st->pid_size = 0; | 389 | st->pid_size = 0; |
377 | 390 | ||
@@ -389,11 +402,9 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, | |||
389 | pid, index, onoff); | 402 | pid, index, onoff); |
390 | 403 | ||
391 | if (onoff) { | 404 | if (onoff) { |
392 | ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); | 405 | mutex_lock(&adap->dev->i2c_mutex); |
393 | if (ret < 0) | 406 | ret |= lme2510_enable_pid(adap->dev, index, pid); |
394 | return -EAGAIN; | 407 | mutex_unlock(&adap->dev->i2c_mutex); |
395 | ret |= lme2510_enable_pid(adap->dev, index, pid); | ||
396 | mutex_unlock(&adap->dev->i2c_mutex); | ||
397 | } | 408 | } |
398 | 409 | ||
399 | 410 | ||
@@ -425,9 +436,6 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
425 | int ret = 0; | 436 | int ret = 0; |
426 | struct lme2510_state *st = d->priv; | 437 | struct lme2510_state *st = d->priv; |
427 | 438 | ||
428 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
429 | return -EAGAIN; | ||
430 | |||
431 | if (st->i2c_talk_onoff == 1) { | 439 | if (st->i2c_talk_onoff == 1) { |
432 | 440 | ||
433 | ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); | 441 | ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); |
@@ -456,8 +464,6 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
456 | st->i2c_talk_onoff = 0; | 464 | st->i2c_talk_onoff = 0; |
457 | } | 465 | } |
458 | } | 466 | } |
459 | if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) | ||
460 | msleep(5); | ||
461 | } | 467 | } |
462 | break; | 468 | break; |
463 | case TUNER_S0194: | 469 | case TUNER_S0194: |
@@ -472,10 +478,12 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
472 | } | 478 | } |
473 | } | 479 | } |
474 | break; | 480 | break; |
481 | case TUNER_RS2000: | ||
475 | default: | 482 | default: |
476 | break; | 483 | break; |
477 | } | 484 | } |
478 | } else { | 485 | } else { |
486 | /* TODO rewrite this section */ | ||
479 | switch (st->tuner_config) { | 487 | switch (st->tuner_config) { |
480 | case TUNER_LG: | 488 | case TUNER_LG: |
481 | switch (wbuf[3]) { | 489 | switch (wbuf[3]) { |
@@ -559,6 +567,24 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
559 | break; | 567 | break; |
560 | } | 568 | } |
561 | break; | 569 | break; |
570 | case TUNER_RS2000: | ||
571 | switch (wbuf[3]) { | ||
572 | case 0x8c: | ||
573 | rbuf[0] = 0x55; | ||
574 | rbuf[1] = 0xff; | ||
575 | if (st->last_key == st->time_key) { | ||
576 | st->key_timeout++; | ||
577 | if (st->key_timeout > 5) | ||
578 | rbuf[1] = 0; | ||
579 | } else | ||
580 | st->key_timeout = 0; | ||
581 | st->last_key = st->time_key; | ||
582 | break; | ||
583 | default: | ||
584 | lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); | ||
585 | st->i2c_talk_onoff = 1; | ||
586 | break; | ||
587 | } | ||
562 | default: | 588 | default: |
563 | break; | 589 | break; |
564 | } | 590 | } |
@@ -568,8 +594,6 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
568 | 594 | ||
569 | } | 595 | } |
570 | 596 | ||
571 | mutex_unlock(&d->i2c_mutex); | ||
572 | |||
573 | return ret; | 597 | return ret; |
574 | } | 598 | } |
575 | 599 | ||
@@ -584,6 +608,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
584 | u16 len; | 608 | u16 len; |
585 | u8 gate = st->i2c_gate; | 609 | u8 gate = st->i2c_gate; |
586 | 610 | ||
611 | mutex_lock(&d->i2c_mutex); | ||
612 | |||
587 | if (gate == 0) | 613 | if (gate == 0) |
588 | gate = 5; | 614 | gate = 5; |
589 | 615 | ||
@@ -622,6 +648,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
622 | 648 | ||
623 | if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { | 649 | if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { |
624 | deb_info(1, "i2c transfer failed."); | 650 | deb_info(1, "i2c transfer failed."); |
651 | mutex_unlock(&d->i2c_mutex); | ||
625 | return -EAGAIN; | 652 | return -EAGAIN; |
626 | } | 653 | } |
627 | 654 | ||
@@ -634,6 +661,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
634 | } | 661 | } |
635 | } | 662 | } |
636 | } | 663 | } |
664 | |||
665 | mutex_unlock(&d->i2c_mutex); | ||
637 | return i; | 666 | return i; |
638 | } | 667 | } |
639 | 668 | ||
@@ -653,7 +682,7 @@ static int lme2510_identify_state(struct usb_device *udev, | |||
653 | struct dvb_usb_device_description **desc, | 682 | struct dvb_usb_device_description **desc, |
654 | int *cold) | 683 | int *cold) |
655 | { | 684 | { |
656 | if (pid_filter > 0) | 685 | if (pid_filter != 2) |
657 | props->adapter[0].fe[0].caps &= | 686 | props->adapter[0].fe[0].caps &= |
658 | ~DVB_USB_ADAP_NEED_PID_FILTERING; | 687 | ~DVB_USB_ADAP_NEED_PID_FILTERING; |
659 | *cold = 0; | 688 | *cold = 0; |
@@ -663,7 +692,7 @@ static int lme2510_identify_state(struct usb_device *udev, | |||
663 | static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | 692 | static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) |
664 | { | 693 | { |
665 | struct lme2510_state *st = adap->dev->priv; | 694 | struct lme2510_state *st = adap->dev->priv; |
666 | static u8 clear_reg_3[] = LME_CLEAR_PID; | 695 | static u8 clear_reg_3[] = LME_ALL_PIDS; |
667 | static u8 rbuf[1]; | 696 | static u8 rbuf[1]; |
668 | int ret = 0, rlen = sizeof(rbuf); | 697 | int ret = 0, rlen = sizeof(rbuf); |
669 | 698 | ||
@@ -675,8 +704,7 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
675 | else { | 704 | else { |
676 | deb_info(1, "STM Steam Off"); | 705 | deb_info(1, "STM Steam Off"); |
677 | /* mutex is here only to avoid collision with I2C */ | 706 | /* mutex is here only to avoid collision with I2C */ |
678 | if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) | 707 | mutex_lock(&adap->dev->i2c_mutex); |
679 | return -EAGAIN; | ||
680 | 708 | ||
681 | ret = lme2510_usb_talk(adap->dev, clear_reg_3, | 709 | ret = lme2510_usb_talk(adap->dev, clear_reg_3, |
682 | sizeof(clear_reg_3), rbuf, rlen); | 710 | sizeof(clear_reg_3), rbuf, rlen); |
@@ -781,16 +809,18 @@ static int lme_firmware_switch(struct usb_device *udev, int cold) | |||
781 | const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; | 809 | const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; |
782 | const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw"; | 810 | const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw"; |
783 | const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw"; | 811 | const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw"; |
812 | const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw"; | ||
784 | const char fw_lg[] = "dvb-usb-lme2510-lg.fw"; | 813 | const char fw_lg[] = "dvb-usb-lme2510-lg.fw"; |
785 | const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw"; | 814 | const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw"; |
786 | const char *fw_lme; | 815 | const char *fw_lme; |
787 | int ret, cold_fw; | 816 | int ret = 0, cold_fw; |
788 | 817 | ||
789 | cold = (cold > 0) ? (cold & 1) : 0; | 818 | cold = (cold > 0) ? (cold & 1) : 0; |
790 | 819 | ||
791 | cold_fw = !cold; | 820 | cold_fw = !cold; |
792 | 821 | ||
793 | if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) { | 822 | switch (le16_to_cpu(udev->descriptor.idProduct)) { |
823 | case 0x1122: | ||
794 | switch (dvb_usb_lme2510_firmware) { | 824 | switch (dvb_usb_lme2510_firmware) { |
795 | default: | 825 | default: |
796 | dvb_usb_lme2510_firmware = TUNER_S0194; | 826 | dvb_usb_lme2510_firmware = TUNER_S0194; |
@@ -813,7 +843,8 @@ static int lme_firmware_switch(struct usb_device *udev, int cold) | |||
813 | cold_fw = 0; | 843 | cold_fw = 0; |
814 | break; | 844 | break; |
815 | } | 845 | } |
816 | } else { | 846 | break; |
847 | case 0x1120: | ||
817 | switch (dvb_usb_lme2510_firmware) { | 848 | switch (dvb_usb_lme2510_firmware) { |
818 | default: | 849 | default: |
819 | dvb_usb_lme2510_firmware = TUNER_S7395; | 850 | dvb_usb_lme2510_firmware = TUNER_S7395; |
@@ -842,8 +873,17 @@ static int lme_firmware_switch(struct usb_device *udev, int cold) | |||
842 | cold_fw = 0; | 873 | cold_fw = 0; |
843 | break; | 874 | break; |
844 | } | 875 | } |
876 | break; | ||
877 | case 0x22f0: | ||
878 | fw_lme = fw_c_rs2000; | ||
879 | ret = request_firmware(&fw, fw_lme, &udev->dev); | ||
880 | dvb_usb_lme2510_firmware = TUNER_RS2000; | ||
881 | break; | ||
882 | default: | ||
883 | fw_lme = fw_c_s7395; | ||
845 | } | 884 | } |
846 | 885 | ||
886 | |||
847 | if (cold_fw) { | 887 | if (cold_fw) { |
848 | info("FRM Loading %s file", fw_lme); | 888 | info("FRM Loading %s file", fw_lme); |
849 | ret = lme2510_download_firmware(udev, fw); | 889 | ret = lme2510_download_firmware(udev, fw); |
@@ -906,6 +946,29 @@ static struct stv0299_config sharp_z0194_config = { | |||
906 | .set_symbol_rate = sharp_z0194a_set_symbol_rate, | 946 | .set_symbol_rate = sharp_z0194a_set_symbol_rate, |
907 | }; | 947 | }; |
908 | 948 | ||
949 | static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, | ||
950 | int caller) | ||
951 | { | ||
952 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
953 | struct dvb_usb_device *d = adap->dev; | ||
954 | struct lme2510_state *st = d->priv; | ||
955 | |||
956 | mutex_lock(&d->i2c_mutex); | ||
957 | if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { | ||
958 | st->i2c_talk_onoff = 0; | ||
959 | lme2510_stream_restart(d); | ||
960 | } | ||
961 | mutex_unlock(&d->i2c_mutex); | ||
962 | |||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | static struct m88rs2000_config m88rs2000_config = { | ||
967 | .demod_addr = 0xd0, | ||
968 | .tuner_addr = 0xc0, | ||
969 | .set_ts_params = dm04_rs2000_set_ts_param, | ||
970 | }; | ||
971 | |||
909 | static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, | 972 | static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, |
910 | fe_sec_voltage_t voltage) | 973 | fe_sec_voltage_t voltage) |
911 | { | 974 | { |
@@ -915,8 +978,7 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, | |||
915 | static u8 rbuf[1]; | 978 | static u8 rbuf[1]; |
916 | int ret = 0, len = 3, rlen = 1; | 979 | int ret = 0, len = 3, rlen = 1; |
917 | 980 | ||
918 | if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) | 981 | mutex_lock(&adap->dev->i2c_mutex); |
919 | return -EAGAIN; | ||
920 | 982 | ||
921 | switch (voltage) { | 983 | switch (voltage) { |
922 | case SEC_VOLTAGE_18: | 984 | case SEC_VOLTAGE_18: |
@@ -937,12 +999,31 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, | |||
937 | return (ret < 0) ? -ENODEV : 0; | 999 | return (ret < 0) ? -ENODEV : 0; |
938 | } | 1000 | } |
939 | 1001 | ||
1002 | static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, | ||
1003 | u16 *strength) | ||
1004 | { | ||
1005 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1006 | struct lme2510_state *st = adap->dev->priv; | ||
1007 | |||
1008 | *strength = (u16)((u32)st->signal_level * 0xffff / 0x7f); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
1013 | { | ||
1014 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1015 | struct lme2510_state *st = adap->dev->priv; | ||
1016 | |||
1017 | *snr = (u16)((u32)st->signal_sn * 0xffff / 0xff); | ||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
940 | static int lme_name(struct dvb_usb_adapter *adap) | 1021 | static int lme_name(struct dvb_usb_adapter *adap) |
941 | { | 1022 | { |
942 | struct lme2510_state *st = adap->dev->priv; | 1023 | struct lme2510_state *st = adap->dev->priv; |
943 | const char *desc = adap->dev->desc->name; | 1024 | const char *desc = adap->dev->desc->name; |
944 | char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", | 1025 | char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", |
945 | " SHARP:BS2F7HZ0194"}; | 1026 | " SHARP:BS2F7HZ0194", " RS2000"}; |
946 | char *name = adap->fe_adap[0].fe->ops.info.name; | 1027 | char *name = adap->fe_adap[0].fe->ops.info.name; |
947 | 1028 | ||
948 | strlcpy(name, desc, 128); | 1029 | strlcpy(name, desc, 128); |
@@ -958,60 +1039,82 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) | |||
958 | int ret = 0; | 1039 | int ret = 0; |
959 | 1040 | ||
960 | st->i2c_talk_onoff = 1; | 1041 | st->i2c_talk_onoff = 1; |
1042 | switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) { | ||
1043 | case 0x1122: | ||
1044 | case 0x1120: | ||
1045 | st->i2c_gate = 4; | ||
1046 | adap->fe_adap[0].fe = dvb_attach(tda10086_attach, | ||
1047 | &tda10086_config, &adap->dev->i2c_adap); | ||
1048 | if (adap->fe_adap[0].fe) { | ||
1049 | info("TUN Found Frontend TDA10086"); | ||
1050 | st->i2c_tuner_gate_w = 4; | ||
1051 | st->i2c_tuner_gate_r = 4; | ||
1052 | st->i2c_tuner_addr = 0xc0; | ||
1053 | st->tuner_config = TUNER_LG; | ||
1054 | if (dvb_usb_lme2510_firmware != TUNER_LG) { | ||
1055 | dvb_usb_lme2510_firmware = TUNER_LG; | ||
1056 | ret = lme_firmware_switch(adap->dev->udev, 1); | ||
1057 | } | ||
1058 | break; | ||
1059 | } | ||
961 | 1060 | ||
962 | st->i2c_gate = 4; | 1061 | st->i2c_gate = 4; |
963 | adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, | 1062 | adap->fe_adap[0].fe = dvb_attach(stv0299_attach, |
964 | &adap->dev->i2c_adap); | 1063 | &sharp_z0194_config, &adap->dev->i2c_adap); |
965 | 1064 | if (adap->fe_adap[0].fe) { | |
966 | if (adap->fe_adap[0].fe) { | 1065 | info("FE Found Stv0299"); |
967 | info("TUN Found Frontend TDA10086"); | 1066 | st->i2c_tuner_gate_w = 4; |
968 | st->i2c_tuner_gate_w = 4; | 1067 | st->i2c_tuner_gate_r = 5; |
969 | st->i2c_tuner_gate_r = 4; | 1068 | st->i2c_tuner_addr = 0xc0; |
970 | st->i2c_tuner_addr = 0xc0; | 1069 | st->tuner_config = TUNER_S0194; |
971 | st->tuner_config = TUNER_LG; | 1070 | if (dvb_usb_lme2510_firmware != TUNER_S0194) { |
972 | if (dvb_usb_lme2510_firmware != TUNER_LG) { | 1071 | dvb_usb_lme2510_firmware = TUNER_S0194; |
973 | dvb_usb_lme2510_firmware = TUNER_LG; | 1072 | ret = lme_firmware_switch(adap->dev->udev, 1); |
974 | ret = lme_firmware_switch(adap->dev->udev, 1); | 1073 | } |
1074 | break; | ||
975 | } | 1075 | } |
976 | goto end; | ||
977 | } | ||
978 | 1076 | ||
979 | st->i2c_gate = 4; | 1077 | st->i2c_gate = 5; |
980 | adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config, | 1078 | adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config, |
981 | &adap->dev->i2c_adap); | 1079 | &adap->dev->i2c_adap); |
982 | if (adap->fe_adap[0].fe) { | 1080 | |
983 | info("FE Found Stv0299"); | 1081 | if (adap->fe_adap[0].fe) { |
984 | st->i2c_tuner_gate_w = 4; | 1082 | info("FE Found Stv0288"); |
985 | st->i2c_tuner_gate_r = 5; | 1083 | st->i2c_tuner_gate_w = 4; |
986 | st->i2c_tuner_addr = 0xc0; | 1084 | st->i2c_tuner_gate_r = 5; |
987 | st->tuner_config = TUNER_S0194; | 1085 | st->i2c_tuner_addr = 0xc0; |
988 | if (dvb_usb_lme2510_firmware != TUNER_S0194) { | 1086 | st->tuner_config = TUNER_S7395; |
989 | dvb_usb_lme2510_firmware = TUNER_S0194; | 1087 | if (dvb_usb_lme2510_firmware != TUNER_S7395) { |
990 | ret = lme_firmware_switch(adap->dev->udev, 1); | 1088 | dvb_usb_lme2510_firmware = TUNER_S7395; |
1089 | ret = lme_firmware_switch(adap->dev->udev, 1); | ||
1090 | } | ||
1091 | break; | ||
991 | } | 1092 | } |
992 | goto end; | 1093 | case 0x22f0: |
993 | } | 1094 | st->i2c_gate = 5; |
1095 | adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach, | ||
1096 | &m88rs2000_config, &adap->dev->i2c_adap); | ||
994 | 1097 | ||
995 | st->i2c_gate = 5; | 1098 | if (adap->fe_adap[0].fe) { |
996 | adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config, | 1099 | info("FE Found M88RS2000"); |
997 | &adap->dev->i2c_adap); | 1100 | st->i2c_tuner_gate_w = 5; |
998 | if (adap->fe_adap[0].fe) { | 1101 | st->i2c_tuner_gate_r = 5; |
999 | info("FE Found Stv0288"); | 1102 | st->i2c_tuner_addr = 0xc0; |
1000 | st->i2c_tuner_gate_w = 4; | 1103 | st->tuner_config = TUNER_RS2000; |
1001 | st->i2c_tuner_gate_r = 5; | 1104 | adap->fe_adap[0].fe->ops.read_signal_strength = |
1002 | st->i2c_tuner_addr = 0xc0; | 1105 | dm04_rs2000_read_signal_strength; |
1003 | st->tuner_config = TUNER_S7395; | 1106 | adap->fe_adap[0].fe->ops.read_snr = |
1004 | if (dvb_usb_lme2510_firmware != TUNER_S7395) { | 1107 | dm04_rs2000_read_snr; |
1005 | dvb_usb_lme2510_firmware = TUNER_S7395; | ||
1006 | ret = lme_firmware_switch(adap->dev->udev, 1); | ||
1007 | } | 1108 | } |
1008 | } else { | 1109 | break; |
1009 | info("DM04 Not Supported"); | ||
1010 | return -ENODEV; | ||
1011 | } | 1110 | } |
1012 | 1111 | ||
1112 | if (adap->fe_adap[0].fe == NULL) { | ||
1113 | info("DM04/QQBOX Not Powered up or not Supported"); | ||
1114 | return -ENODEV; | ||
1115 | } | ||
1013 | 1116 | ||
1014 | end: if (ret) { | 1117 | if (ret) { |
1015 | if (adap->fe_adap[0].fe) { | 1118 | if (adap->fe_adap[0].fe) { |
1016 | dvb_frontend_detach(adap->fe_adap[0].fe); | 1119 | dvb_frontend_detach(adap->fe_adap[0].fe); |
1017 | adap->fe_adap[0].fe = NULL; | 1120 | adap->fe_adap[0].fe = NULL; |
@@ -1028,7 +1131,7 @@ end: if (ret) { | |||
1028 | static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) | 1131 | static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) |
1029 | { | 1132 | { |
1030 | struct lme2510_state *st = adap->dev->priv; | 1133 | struct lme2510_state *st = adap->dev->priv; |
1031 | char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"}; | 1134 | char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"}; |
1032 | int ret = 0; | 1135 | int ret = 0; |
1033 | 1136 | ||
1034 | switch (st->tuner_config) { | 1137 | switch (st->tuner_config) { |
@@ -1047,6 +1150,9 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) | |||
1047 | &adap->dev->i2c_adap, DVB_PLL_OPERA1)) | 1150 | &adap->dev->i2c_adap, DVB_PLL_OPERA1)) |
1048 | ret = st->tuner_config; | 1151 | ret = st->tuner_config; |
1049 | break; | 1152 | break; |
1153 | case TUNER_RS2000: | ||
1154 | ret = st->tuner_config; | ||
1155 | break; | ||
1050 | default: | 1156 | default: |
1051 | break; | 1157 | break; |
1052 | } | 1158 | } |
@@ -1075,10 +1181,9 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff) | |||
1075 | static u8 lnb_on[] = LNB_ON; | 1181 | static u8 lnb_on[] = LNB_ON; |
1076 | static u8 lnb_off[] = LNB_OFF; | 1182 | static u8 lnb_off[] = LNB_OFF; |
1077 | static u8 rbuf[1]; | 1183 | static u8 rbuf[1]; |
1078 | int ret, len = 3, rlen = 1; | 1184 | int ret = 0, len = 3, rlen = 1; |
1079 | 1185 | ||
1080 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 1186 | mutex_lock(&d->i2c_mutex); |
1081 | return -EAGAIN; | ||
1082 | 1187 | ||
1083 | if (onoff) | 1188 | if (onoff) |
1084 | ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); | 1189 | ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); |
@@ -1136,6 +1241,7 @@ static int lme2510_probe(struct usb_interface *intf, | |||
1136 | static struct usb_device_id lme2510_table[] = { | 1241 | static struct usb_device_id lme2510_table[] = { |
1137 | { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */ | 1242 | { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */ |
1138 | { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */ | 1243 | { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */ |
1244 | { USB_DEVICE(0x3344, 0x22f0) }, /* LME2510C RS2000 */ | ||
1139 | {} /* Terminating entry */ | 1245 | {} /* Terminating entry */ |
1140 | }; | 1246 | }; |
1141 | 1247 | ||
@@ -1153,7 +1259,7 @@ static struct dvb_usb_device_properties lme2510_properties = { | |||
1153 | DVB_USB_ADAP_NEED_PID_FILTERING| | 1259 | DVB_USB_ADAP_NEED_PID_FILTERING| |
1154 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | 1260 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1155 | .streaming_ctrl = lme2510_streaming_ctrl, | 1261 | .streaming_ctrl = lme2510_streaming_ctrl, |
1156 | .pid_filter_count = 15, | 1262 | .pid_filter_count = 32, |
1157 | .pid_filter = lme2510_pid_filter, | 1263 | .pid_filter = lme2510_pid_filter, |
1158 | .pid_filter_ctrl = lme2510_pid_filter_ctrl, | 1264 | .pid_filter_ctrl = lme2510_pid_filter_ctrl, |
1159 | .frontend_attach = dm04_lme2510_frontend_attach, | 1265 | .frontend_attach = dm04_lme2510_frontend_attach, |
@@ -1204,7 +1310,7 @@ static struct dvb_usb_device_properties lme2510c_properties = { | |||
1204 | DVB_USB_ADAP_NEED_PID_FILTERING| | 1310 | DVB_USB_ADAP_NEED_PID_FILTERING| |
1205 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | 1311 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1206 | .streaming_ctrl = lme2510_streaming_ctrl, | 1312 | .streaming_ctrl = lme2510_streaming_ctrl, |
1207 | .pid_filter_count = 15, | 1313 | .pid_filter_count = 32, |
1208 | .pid_filter = lme2510_pid_filter, | 1314 | .pid_filter = lme2510_pid_filter, |
1209 | .pid_filter_ctrl = lme2510_pid_filter_ctrl, | 1315 | .pid_filter_ctrl = lme2510_pid_filter_ctrl, |
1210 | .frontend_attach = dm04_lme2510_frontend_attach, | 1316 | .frontend_attach = dm04_lme2510_frontend_attach, |
@@ -1234,11 +1340,14 @@ static struct dvb_usb_device_properties lme2510c_properties = { | |||
1234 | .identify_state = lme2510_identify_state, | 1340 | .identify_state = lme2510_identify_state, |
1235 | .i2c_algo = &lme2510_i2c_algo, | 1341 | .i2c_algo = &lme2510_i2c_algo, |
1236 | .generic_bulk_ctrl_endpoint = 0, | 1342 | .generic_bulk_ctrl_endpoint = 0, |
1237 | .num_device_descs = 1, | 1343 | .num_device_descs = 2, |
1238 | .devices = { | 1344 | .devices = { |
1239 | { "DM04_LME2510C_DVB-S", | 1345 | { "DM04_LME2510C_DVB-S", |
1240 | { &lme2510_table[1], NULL }, | 1346 | { &lme2510_table[1], NULL }, |
1241 | }, | 1347 | }, |
1348 | { "DM04_LME2510C_DVB-S RS2000", | ||
1349 | { &lme2510_table[2], NULL }, | ||
1350 | }, | ||
1242 | } | 1351 | } |
1243 | }; | 1352 | }; |
1244 | 1353 | ||
@@ -1295,5 +1404,5 @@ module_usb_driver(lme2510_driver); | |||
1295 | 1404 | ||
1296 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); | 1405 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); |
1297 | MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); | 1406 | MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); |
1298 | MODULE_VERSION("1.91"); | 1407 | MODULE_VERSION("1.99"); |
1299 | MODULE_LICENSE("GPL"); | 1408 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h index ab21e2ef53fa..e9c207205c2f 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.h +++ b/drivers/media/dvb/dvb-usb/lmedm04.h | |||
@@ -41,6 +41,7 @@ | |||
41 | #define LME_ST_ON_W {0x06, 0x00} | 41 | #define LME_ST_ON_W {0x06, 0x00} |
42 | #define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} | 42 | #define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} |
43 | #define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} | 43 | #define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} |
44 | #define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81} | ||
44 | 45 | ||
45 | /* LNB Voltage | 46 | /* LNB Voltage |
46 | * 07 XX XX | 47 | * 07 XX XX |
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 38ef0253d3b5..81305de2fea5 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c | |||
@@ -351,15 +351,13 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
351 | adap_state->ep6_clockphase, | 351 | adap_state->ep6_clockphase, |
352 | 0, 0); | 352 | 0, 0); |
353 | mxl_fail(ret); | 353 | mxl_fail(ret); |
354 | #if 0 | ||
354 | } else { | 355 | } else { |
355 | ret = mxl111sf_disable_656_port(state); | 356 | ret = mxl111sf_disable_656_port(state); |
356 | mxl_fail(ret); | 357 | mxl_fail(ret); |
358 | #endif | ||
357 | } | 359 | } |
358 | 360 | ||
359 | mxl111sf_read_reg(state, 0x12, &tmp); | ||
360 | tmp &= ~0x04; | ||
361 | mxl111sf_write_reg(state, 0x12, tmp); | ||
362 | |||
363 | return ret; | 361 | return ret; |
364 | } | 362 | } |
365 | 363 | ||
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c new file mode 100644 index 000000000000..8f4736a10fc8 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c | |||
@@ -0,0 +1,982 @@ | |||
1 | /* | ||
2 | * Realtek RTL28xxU DVB USB driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> | ||
5 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | */ | ||
21 | |||
22 | #include "rtl28xxu.h" | ||
23 | |||
24 | #include "rtl2830.h" | ||
25 | |||
26 | #include "qt1010.h" | ||
27 | #include "mt2060.h" | ||
28 | #include "mxl5005s.h" | ||
29 | |||
30 | /* debug */ | ||
31 | static int dvb_usb_rtl28xxu_debug; | ||
32 | module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644); | ||
33 | MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); | ||
34 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
35 | |||
36 | static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) | ||
37 | { | ||
38 | int ret; | ||
39 | unsigned int pipe; | ||
40 | u8 requesttype; | ||
41 | u8 *buf; | ||
42 | |||
43 | buf = kmalloc(req->size, GFP_KERNEL); | ||
44 | if (!buf) { | ||
45 | ret = -ENOMEM; | ||
46 | goto err; | ||
47 | } | ||
48 | |||
49 | if (req->index & CMD_WR_FLAG) { | ||
50 | /* write */ | ||
51 | memcpy(buf, req->data, req->size); | ||
52 | requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); | ||
53 | pipe = usb_sndctrlpipe(d->udev, 0); | ||
54 | } else { | ||
55 | /* read */ | ||
56 | requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); | ||
57 | pipe = usb_rcvctrlpipe(d->udev, 0); | ||
58 | } | ||
59 | |||
60 | ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, | ||
61 | req->index, buf, req->size, 1000); | ||
62 | if (ret > 0) | ||
63 | ret = 0; | ||
64 | |||
65 | deb_dump(0, requesttype, req->value, req->index, buf, req->size, | ||
66 | deb_xfer); | ||
67 | |||
68 | /* read request, copy returned data to return buf */ | ||
69 | if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) | ||
70 | memcpy(req->data, buf, req->size); | ||
71 | |||
72 | kfree(buf); | ||
73 | |||
74 | if (ret) | ||
75 | goto err; | ||
76 | |||
77 | return ret; | ||
78 | err: | ||
79 | deb_info("%s: failed=%d\n", __func__, ret); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) | ||
84 | { | ||
85 | struct rtl28xxu_req req; | ||
86 | |||
87 | if (reg < 0x3000) | ||
88 | req.index = CMD_USB_WR; | ||
89 | else if (reg < 0x4000) | ||
90 | req.index = CMD_SYS_WR; | ||
91 | else | ||
92 | req.index = CMD_IR_WR; | ||
93 | |||
94 | req.value = reg; | ||
95 | req.size = len; | ||
96 | req.data = val; | ||
97 | |||
98 | return rtl28xxu_ctrl_msg(d, &req); | ||
99 | } | ||
100 | |||
101 | static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) | ||
102 | { | ||
103 | struct rtl28xxu_req req; | ||
104 | |||
105 | if (reg < 0x3000) | ||
106 | req.index = CMD_USB_RD; | ||
107 | else if (reg < 0x4000) | ||
108 | req.index = CMD_SYS_RD; | ||
109 | else | ||
110 | req.index = CMD_IR_RD; | ||
111 | |||
112 | req.value = reg; | ||
113 | req.size = len; | ||
114 | req.data = val; | ||
115 | |||
116 | return rtl28xxu_ctrl_msg(d, &req); | ||
117 | } | ||
118 | |||
119 | static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) | ||
120 | { | ||
121 | return rtl2831_wr_regs(d, reg, &val, 1); | ||
122 | } | ||
123 | |||
124 | static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) | ||
125 | { | ||
126 | return rtl2831_rd_regs(d, reg, val, 1); | ||
127 | } | ||
128 | |||
129 | /* I2C */ | ||
130 | static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | ||
131 | int num) | ||
132 | { | ||
133 | int ret; | ||
134 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
135 | struct rtl28xxu_priv *priv = d->priv; | ||
136 | struct rtl28xxu_req req; | ||
137 | |||
138 | /* | ||
139 | * It is not known which are real I2C bus xfer limits, but testing | ||
140 | * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes. | ||
141 | * TODO: find out RTL2832U lens | ||
142 | */ | ||
143 | |||
144 | /* | ||
145 | * I2C adapter logic looks rather complicated due to fact it handles | ||
146 | * three different access methods. Those methods are; | ||
147 | * 1) integrated demod access | ||
148 | * 2) old I2C access | ||
149 | * 3) new I2C access | ||
150 | * | ||
151 | * Used method is selected in order 1, 2, 3. Method 3 can handle all | ||
152 | * requests but there is two reasons why not use it always; | ||
153 | * 1) It is most expensive, usually two USB messages are needed | ||
154 | * 2) At least RTL2831U does not support it | ||
155 | * | ||
156 | * Method 3 is needed in case of I2C write+read (typical register read) | ||
157 | * where write is more than one byte. | ||
158 | */ | ||
159 | |||
160 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
161 | return -EAGAIN; | ||
162 | |||
163 | if (num == 2 && !(msg[0].flags & I2C_M_RD) && | ||
164 | (msg[1].flags & I2C_M_RD)) { | ||
165 | if (msg[0].len > 24 || msg[1].len > 24) { | ||
166 | /* TODO: check msg[0].len max */ | ||
167 | ret = -EOPNOTSUPP; | ||
168 | goto err_mutex_unlock; | ||
169 | } else if (msg[0].addr == 0x10) { | ||
170 | /* method 1 - integrated demod */ | ||
171 | req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); | ||
172 | req.index = CMD_DEMOD_RD | priv->page; | ||
173 | req.size = msg[1].len; | ||
174 | req.data = &msg[1].buf[0]; | ||
175 | ret = rtl28xxu_ctrl_msg(d, &req); | ||
176 | } else if (msg[0].len < 2) { | ||
177 | /* method 2 - old I2C */ | ||
178 | req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); | ||
179 | req.index = CMD_I2C_RD; | ||
180 | req.size = msg[1].len; | ||
181 | req.data = &msg[1].buf[0]; | ||
182 | ret = rtl28xxu_ctrl_msg(d, &req); | ||
183 | } else { | ||
184 | /* method 3 - new I2C */ | ||
185 | req.value = (msg[0].addr << 1); | ||
186 | req.index = CMD_I2C_DA_WR; | ||
187 | req.size = msg[0].len; | ||
188 | req.data = msg[0].buf; | ||
189 | ret = rtl28xxu_ctrl_msg(d, &req); | ||
190 | if (ret) | ||
191 | goto err_mutex_unlock; | ||
192 | |||
193 | req.value = (msg[0].addr << 1); | ||
194 | req.index = CMD_I2C_DA_RD; | ||
195 | req.size = msg[1].len; | ||
196 | req.data = msg[1].buf; | ||
197 | ret = rtl28xxu_ctrl_msg(d, &req); | ||
198 | } | ||
199 | } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { | ||
200 | if (msg[0].len > 22) { | ||
201 | /* TODO: check msg[0].len max */ | ||
202 | ret = -EOPNOTSUPP; | ||
203 | goto err_mutex_unlock; | ||
204 | } else if (msg[0].addr == 0x10) { | ||
205 | /* method 1 - integrated demod */ | ||
206 | if (msg[0].buf[0] == 0x00) { | ||
207 | /* save demod page for later demod access */ | ||
208 | priv->page = msg[0].buf[1]; | ||
209 | ret = 0; | ||
210 | } else { | ||
211 | req.value = (msg[0].buf[0] << 8) | | ||
212 | (msg[0].addr << 1); | ||
213 | req.index = CMD_DEMOD_WR | priv->page; | ||
214 | req.size = msg[0].len-1; | ||
215 | req.data = &msg[0].buf[1]; | ||
216 | ret = rtl28xxu_ctrl_msg(d, &req); | ||
217 | } | ||
218 | } else if (msg[0].len < 23) { | ||
219 | /* method 2 - old I2C */ | ||
220 | req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); | ||
221 | req.index = CMD_I2C_WR; | ||
222 | req.size = msg[0].len-1; | ||
223 | req.data = &msg[0].buf[1]; | ||
224 | ret = rtl28xxu_ctrl_msg(d, &req); | ||
225 | } else { | ||
226 | /* method 3 - new I2C */ | ||
227 | req.value = (msg[0].addr << 1); | ||
228 | req.index = CMD_I2C_DA_WR; | ||
229 | req.size = msg[0].len; | ||
230 | req.data = msg[0].buf; | ||
231 | ret = rtl28xxu_ctrl_msg(d, &req); | ||
232 | } | ||
233 | } else { | ||
234 | ret = -EINVAL; | ||
235 | } | ||
236 | |||
237 | err_mutex_unlock: | ||
238 | mutex_unlock(&d->i2c_mutex); | ||
239 | |||
240 | return ret ? ret : num; | ||
241 | } | ||
242 | |||
243 | static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter) | ||
244 | { | ||
245 | return I2C_FUNC_I2C; | ||
246 | } | ||
247 | |||
248 | static struct i2c_algorithm rtl28xxu_i2c_algo = { | ||
249 | .master_xfer = rtl28xxu_i2c_xfer, | ||
250 | .functionality = rtl28xxu_i2c_func, | ||
251 | }; | ||
252 | |||
253 | static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { | ||
254 | .i2c_addr = 0x10, /* 0x20 */ | ||
255 | .xtal = 28800000, | ||
256 | .ts_mode = 0, | ||
257 | .spec_inv = 1, | ||
258 | .if_dvbt = 36150000, | ||
259 | .vtop = 0x20, | ||
260 | .krf = 0x04, | ||
261 | .agc_targ_val = 0x2d, | ||
262 | |||
263 | }; | ||
264 | |||
265 | static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { | ||
266 | .i2c_addr = 0x10, /* 0x20 */ | ||
267 | .xtal = 28800000, | ||
268 | .ts_mode = 0, | ||
269 | .spec_inv = 1, | ||
270 | .if_dvbt = 36125000, | ||
271 | .vtop = 0x20, | ||
272 | .krf = 0x04, | ||
273 | .agc_targ_val = 0x2d, | ||
274 | }; | ||
275 | |||
276 | static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { | ||
277 | .i2c_addr = 0x10, /* 0x20 */ | ||
278 | .xtal = 28800000, | ||
279 | .ts_mode = 0, | ||
280 | .spec_inv = 0, | ||
281 | .if_dvbt = 4570000, | ||
282 | .vtop = 0x3f, | ||
283 | .krf = 0x04, | ||
284 | .agc_targ_val = 0x3e, | ||
285 | }; | ||
286 | |||
287 | static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) | ||
288 | { | ||
289 | int ret; | ||
290 | struct rtl28xxu_priv *priv = adap->dev->priv; | ||
291 | u8 buf[1]; | ||
292 | struct rtl2830_config *rtl2830_config; | ||
293 | /* open RTL2831U/RTL2830 I2C gate */ | ||
294 | struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" }; | ||
295 | /* for MT2060 tuner probe */ | ||
296 | struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf }; | ||
297 | /* for QT1010 tuner probe */ | ||
298 | struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf }; | ||
299 | |||
300 | deb_info("%s:\n", __func__); | ||
301 | |||
302 | /* | ||
303 | * RTL2831U GPIOs | ||
304 | * ========================================================= | ||
305 | * GPIO0 | tuner#0 | 0 off | 1 on | MXL5005S (?) | ||
306 | * GPIO2 | LED | 0 off | 1 on | | ||
307 | * GPIO4 | tuner#1 | 0 on | 1 off | MT2060 | ||
308 | */ | ||
309 | |||
310 | /* GPIO direction */ | ||
311 | ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); | ||
312 | if (ret) | ||
313 | goto err; | ||
314 | |||
315 | /* enable as output GPIO0, GPIO2, GPIO4 */ | ||
316 | ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); | ||
317 | if (ret) | ||
318 | goto err; | ||
319 | |||
320 | /* | ||
321 | * Probe used tuner. We need to know used tuner before demod attach | ||
322 | * since there is some demod params needed to set according to tuner. | ||
323 | */ | ||
324 | |||
325 | /* open demod I2C gate */ | ||
326 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate); | ||
327 | if (ret) | ||
328 | goto err; | ||
329 | |||
330 | /* check QT1010 ID(?) register; reg=0f val=2c */ | ||
331 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010); | ||
332 | if (ret == 0 && buf[0] == 0x2c) { | ||
333 | priv->tuner = TUNER_RTL2830_QT1010; | ||
334 | rtl2830_config = &rtl28xxu_rtl2830_qt1010_config; | ||
335 | deb_info("%s: QT1010\n", __func__); | ||
336 | goto found; | ||
337 | } else { | ||
338 | deb_info("%s: QT1010 probe failed=%d - %02x\n", | ||
339 | __func__, ret, buf[0]); | ||
340 | } | ||
341 | |||
342 | /* open demod I2C gate */ | ||
343 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate); | ||
344 | if (ret) | ||
345 | goto err; | ||
346 | |||
347 | /* check MT2060 ID register; reg=00 val=63 */ | ||
348 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060); | ||
349 | if (ret == 0 && buf[0] == 0x63) { | ||
350 | priv->tuner = TUNER_RTL2830_MT2060; | ||
351 | rtl2830_config = &rtl28xxu_rtl2830_mt2060_config; | ||
352 | deb_info("%s: MT2060\n", __func__); | ||
353 | goto found; | ||
354 | } else { | ||
355 | deb_info("%s: MT2060 probe failed=%d - %02x\n", | ||
356 | __func__, ret, buf[0]); | ||
357 | } | ||
358 | |||
359 | /* assume MXL5005S */ | ||
360 | ret = 0; | ||
361 | priv->tuner = TUNER_RTL2830_MXL5005S; | ||
362 | rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config; | ||
363 | deb_info("%s: MXL5005S\n", __func__); | ||
364 | goto found; | ||
365 | |||
366 | found: | ||
367 | /* attach demodulator */ | ||
368 | adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config, | ||
369 | &adap->dev->i2c_adap); | ||
370 | if (adap->fe_adap[0].fe == NULL) { | ||
371 | ret = -ENODEV; | ||
372 | goto err; | ||
373 | } | ||
374 | |||
375 | return ret; | ||
376 | err: | ||
377 | deb_info("%s: failed=%d\n", __func__, ret); | ||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) | ||
382 | { | ||
383 | int ret; | ||
384 | struct rtl28xxu_priv *priv = adap->dev->priv; | ||
385 | u8 buf[1]; | ||
386 | /* open RTL2832U/RTL2832 I2C gate */ | ||
387 | struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"}; | ||
388 | /* close RTL2832U/RTL2832 I2C gate */ | ||
389 | struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"}; | ||
390 | /* for FC2580 tuner probe */ | ||
391 | struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf}; | ||
392 | |||
393 | deb_info("%s:\n", __func__); | ||
394 | |||
395 | /* GPIO direction */ | ||
396 | ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); | ||
397 | if (ret) | ||
398 | goto err; | ||
399 | |||
400 | /* enable as output GPIO0, GPIO2, GPIO4 */ | ||
401 | ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); | ||
402 | if (ret) | ||
403 | goto err; | ||
404 | |||
405 | ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8); | ||
406 | if (ret) | ||
407 | goto err; | ||
408 | |||
409 | /* | ||
410 | * Probe used tuner. We need to know used tuner before demod attach | ||
411 | * since there is some demod params needed to set according to tuner. | ||
412 | */ | ||
413 | |||
414 | /* open demod I2C gate */ | ||
415 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open); | ||
416 | if (ret) | ||
417 | goto err; | ||
418 | |||
419 | /* check FC2580 ID register; reg=01 val=56 */ | ||
420 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580); | ||
421 | if (ret == 0 && buf[0] == 0x56) { | ||
422 | priv->tuner = TUNER_RTL2832_FC2580; | ||
423 | deb_info("%s: FC2580\n", __func__); | ||
424 | goto found; | ||
425 | } else { | ||
426 | deb_info("%s: FC2580 probe failed=%d - %02x\n", | ||
427 | __func__, ret, buf[0]); | ||
428 | } | ||
429 | |||
430 | /* close demod I2C gate */ | ||
431 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close); | ||
432 | if (ret) | ||
433 | goto err; | ||
434 | |||
435 | /* tuner not found */ | ||
436 | ret = -ENODEV; | ||
437 | goto err; | ||
438 | |||
439 | found: | ||
440 | /* close demod I2C gate */ | ||
441 | ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close); | ||
442 | if (ret) | ||
443 | goto err; | ||
444 | |||
445 | /* attach demodulator */ | ||
446 | /* TODO: */ | ||
447 | |||
448 | return ret; | ||
449 | err: | ||
450 | deb_info("%s: failed=%d\n", __func__, ret); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | static struct qt1010_config rtl28xxu_qt1010_config = { | ||
455 | .i2c_address = 0x62, /* 0xc4 */ | ||
456 | }; | ||
457 | |||
458 | static struct mt2060_config rtl28xxu_mt2060_config = { | ||
459 | .i2c_address = 0x60, /* 0xc0 */ | ||
460 | .clock_out = 0, | ||
461 | }; | ||
462 | |||
463 | static struct mxl5005s_config rtl28xxu_mxl5005s_config = { | ||
464 | .i2c_address = 0x63, /* 0xc6 */ | ||
465 | .if_freq = IF_FREQ_4570000HZ, | ||
466 | .xtal_freq = CRYSTAL_FREQ_16000000HZ, | ||
467 | .agc_mode = MXL_SINGLE_AGC, | ||
468 | .tracking_filter = MXL_TF_C_H, | ||
469 | .rssi_enable = MXL_RSSI_ENABLE, | ||
470 | .cap_select = MXL_CAP_SEL_ENABLE, | ||
471 | .div_out = MXL_DIV_OUT_4, | ||
472 | .clock_out = MXL_CLOCK_OUT_DISABLE, | ||
473 | .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, | ||
474 | .top = MXL5005S_TOP_25P2, | ||
475 | .mod_mode = MXL_DIGITAL_MODE, | ||
476 | .if_mode = MXL_ZERO_IF, | ||
477 | .AgcMasterByte = 0x00, | ||
478 | }; | ||
479 | |||
480 | static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) | ||
481 | { | ||
482 | int ret; | ||
483 | struct rtl28xxu_priv *priv = adap->dev->priv; | ||
484 | struct i2c_adapter *rtl2830_tuner_i2c; | ||
485 | struct dvb_frontend *fe; | ||
486 | |||
487 | deb_info("%s:\n", __func__); | ||
488 | |||
489 | /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */ | ||
490 | rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe); | ||
491 | |||
492 | switch (priv->tuner) { | ||
493 | case TUNER_RTL2830_QT1010: | ||
494 | fe = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, | ||
495 | rtl2830_tuner_i2c, &rtl28xxu_qt1010_config); | ||
496 | break; | ||
497 | case TUNER_RTL2830_MT2060: | ||
498 | fe = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, | ||
499 | rtl2830_tuner_i2c, &rtl28xxu_mt2060_config, | ||
500 | 1220); | ||
501 | break; | ||
502 | case TUNER_RTL2830_MXL5005S: | ||
503 | fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, | ||
504 | rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config); | ||
505 | break; | ||
506 | default: | ||
507 | fe = NULL; | ||
508 | err("unknown tuner=%d", priv->tuner); | ||
509 | } | ||
510 | |||
511 | if (fe == NULL) { | ||
512 | ret = -ENODEV; | ||
513 | goto err; | ||
514 | } | ||
515 | |||
516 | return 0; | ||
517 | err: | ||
518 | deb_info("%s: failed=%d\n", __func__, ret); | ||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) | ||
523 | { | ||
524 | int ret; | ||
525 | struct rtl28xxu_priv *priv = adap->dev->priv; | ||
526 | struct dvb_frontend *fe; | ||
527 | |||
528 | deb_info("%s:\n", __func__); | ||
529 | |||
530 | switch (priv->tuner) { | ||
531 | case TUNER_RTL2832_FC2580: | ||
532 | /* TODO: */ | ||
533 | fe = NULL; | ||
534 | break; | ||
535 | default: | ||
536 | fe = NULL; | ||
537 | err("unknown tuner=%d", priv->tuner); | ||
538 | } | ||
539 | |||
540 | if (fe == NULL) { | ||
541 | ret = -ENODEV; | ||
542 | goto err; | ||
543 | } | ||
544 | |||
545 | return 0; | ||
546 | err: | ||
547 | deb_info("%s: failed=%d\n", __func__, ret); | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff) | ||
552 | { | ||
553 | int ret; | ||
554 | u8 buf[2], gpio; | ||
555 | |||
556 | deb_info("%s: onoff=%d\n", __func__, onoff); | ||
557 | |||
558 | ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio); | ||
559 | if (ret) | ||
560 | goto err; | ||
561 | |||
562 | if (onoff) { | ||
563 | buf[0] = 0x00; | ||
564 | buf[1] = 0x00; | ||
565 | gpio |= 0x04; /* LED on */ | ||
566 | } else { | ||
567 | buf[0] = 0x10; /* stall EPA */ | ||
568 | buf[1] = 0x02; /* reset EPA */ | ||
569 | gpio &= (~0x04); /* LED off */ | ||
570 | } | ||
571 | |||
572 | ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio); | ||
573 | if (ret) | ||
574 | goto err; | ||
575 | |||
576 | ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2); | ||
577 | if (ret) | ||
578 | goto err; | ||
579 | |||
580 | return ret; | ||
581 | err: | ||
582 | deb_info("%s: failed=%d\n", __func__, ret); | ||
583 | return ret; | ||
584 | } | ||
585 | |||
586 | static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff) | ||
587 | { | ||
588 | int ret; | ||
589 | u8 gpio, sys0; | ||
590 | |||
591 | deb_info("%s: onoff=%d\n", __func__, onoff); | ||
592 | |||
593 | /* demod adc */ | ||
594 | ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0); | ||
595 | if (ret) | ||
596 | goto err; | ||
597 | |||
598 | /* tuner power, read GPIOs */ | ||
599 | ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); | ||
600 | if (ret) | ||
601 | goto err; | ||
602 | |||
603 | deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio); | ||
604 | |||
605 | if (onoff) { | ||
606 | gpio |= 0x01; /* GPIO0 = 1 */ | ||
607 | gpio &= (~0x10); /* GPIO4 = 0 */ | ||
608 | sys0 = sys0 & 0x0f; | ||
609 | sys0 |= 0xe0; | ||
610 | } else { | ||
611 | gpio &= (~0x01); /* GPIO0 = 0 */ | ||
612 | gpio |= 0x10; /* GPIO4 = 1 */ | ||
613 | sys0 = sys0 & (~0xc0); | ||
614 | } | ||
615 | |||
616 | deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio); | ||
617 | |||
618 | /* demod adc */ | ||
619 | ret = rtl2831_wr_reg(d, SYS_SYS0, sys0); | ||
620 | if (ret) | ||
621 | goto err; | ||
622 | |||
623 | /* tuner power, write GPIOs */ | ||
624 | ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); | ||
625 | if (ret) | ||
626 | goto err; | ||
627 | |||
628 | return ret; | ||
629 | err: | ||
630 | deb_info("%s: failed=%d\n", __func__, ret); | ||
631 | return ret; | ||
632 | } | ||
633 | |||
634 | static int rtl2831u_rc_query(struct dvb_usb_device *d) | ||
635 | { | ||
636 | int ret, i; | ||
637 | struct rtl28xxu_priv *priv = d->priv; | ||
638 | u8 buf[5]; | ||
639 | u32 rc_code; | ||
640 | struct rtl28xxu_reg_val rc_nec_tab[] = { | ||
641 | { 0x3033, 0x80 }, | ||
642 | { 0x3020, 0x43 }, | ||
643 | { 0x3021, 0x16 }, | ||
644 | { 0x3022, 0x16 }, | ||
645 | { 0x3023, 0x5a }, | ||
646 | { 0x3024, 0x2d }, | ||
647 | { 0x3025, 0x16 }, | ||
648 | { 0x3026, 0x01 }, | ||
649 | { 0x3028, 0xb0 }, | ||
650 | { 0x3029, 0x04 }, | ||
651 | { 0x302c, 0x88 }, | ||
652 | { 0x302e, 0x13 }, | ||
653 | { 0x3030, 0xdf }, | ||
654 | { 0x3031, 0x05 }, | ||
655 | }; | ||
656 | |||
657 | /* init remote controller */ | ||
658 | if (!priv->rc_active) { | ||
659 | for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { | ||
660 | ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, | ||
661 | rc_nec_tab[i].val); | ||
662 | if (ret) | ||
663 | goto err; | ||
664 | } | ||
665 | priv->rc_active = true; | ||
666 | } | ||
667 | |||
668 | ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5); | ||
669 | if (ret) | ||
670 | goto err; | ||
671 | |||
672 | if (buf[4] & 0x01) { | ||
673 | if (buf[2] == (u8) ~buf[3]) { | ||
674 | if (buf[0] == (u8) ~buf[1]) { | ||
675 | /* NEC standard (16 bit) */ | ||
676 | rc_code = buf[0] << 8 | buf[2]; | ||
677 | } else { | ||
678 | /* NEC extended (24 bit) */ | ||
679 | rc_code = buf[0] << 16 | | ||
680 | buf[1] << 8 | buf[2]; | ||
681 | } | ||
682 | } else { | ||
683 | /* NEC full (32 bit) */ | ||
684 | rc_code = buf[0] << 24 | buf[1] << 16 | | ||
685 | buf[2] << 8 | buf[3]; | ||
686 | } | ||
687 | |||
688 | rc_keydown(d->rc_dev, rc_code, 0); | ||
689 | |||
690 | ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); | ||
691 | if (ret) | ||
692 | goto err; | ||
693 | |||
694 | /* repeated intentionally to avoid extra keypress */ | ||
695 | ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); | ||
696 | if (ret) | ||
697 | goto err; | ||
698 | } | ||
699 | |||
700 | return ret; | ||
701 | err: | ||
702 | deb_info("%s: failed=%d\n", __func__, ret); | ||
703 | return ret; | ||
704 | } | ||
705 | |||
706 | static int rtl2832u_rc_query(struct dvb_usb_device *d) | ||
707 | { | ||
708 | int ret, i; | ||
709 | struct rtl28xxu_priv *priv = d->priv; | ||
710 | u8 buf[128]; | ||
711 | int len; | ||
712 | struct rtl28xxu_reg_val rc_nec_tab[] = { | ||
713 | { IR_RX_CTRL, 0x20 }, | ||
714 | { IR_RX_BUF_CTRL, 0x80 }, | ||
715 | { IR_RX_IF, 0xff }, | ||
716 | { IR_RX_IE, 0xff }, | ||
717 | { IR_MAX_DURATION0, 0xd0 }, | ||
718 | { IR_MAX_DURATION1, 0x07 }, | ||
719 | { IR_IDLE_LEN0, 0xc0 }, | ||
720 | { IR_IDLE_LEN1, 0x00 }, | ||
721 | { IR_GLITCH_LEN, 0x03 }, | ||
722 | { IR_RX_CLK, 0x09 }, | ||
723 | { IR_RX_CFG, 0x1c }, | ||
724 | { IR_MAX_H_TOL_LEN, 0x1e }, | ||
725 | { IR_MAX_L_TOL_LEN, 0x1e }, | ||
726 | { IR_RX_CTRL, 0x80 }, | ||
727 | }; | ||
728 | |||
729 | /* init remote controller */ | ||
730 | if (!priv->rc_active) { | ||
731 | for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { | ||
732 | ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, | ||
733 | rc_nec_tab[i].val); | ||
734 | if (ret) | ||
735 | goto err; | ||
736 | } | ||
737 | priv->rc_active = true; | ||
738 | } | ||
739 | |||
740 | ret = rtl2831_rd_reg(d, IR_RX_IF, &buf[0]); | ||
741 | if (ret) | ||
742 | goto err; | ||
743 | |||
744 | if (buf[0] != 0x83) | ||
745 | goto exit; | ||
746 | |||
747 | ret = rtl2831_rd_reg(d, IR_RX_BC, &buf[0]); | ||
748 | if (ret) | ||
749 | goto err; | ||
750 | |||
751 | len = buf[0]; | ||
752 | ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len); | ||
753 | |||
754 | /* TODO: pass raw IR to Kernel IR decoder */ | ||
755 | |||
756 | ret = rtl2831_wr_reg(d, IR_RX_IF, 0x03); | ||
757 | ret = rtl2831_wr_reg(d, IR_RX_BUF_CTRL, 0x80); | ||
758 | ret = rtl2831_wr_reg(d, IR_RX_CTRL, 0x80); | ||
759 | |||
760 | exit: | ||
761 | return ret; | ||
762 | err: | ||
763 | deb_info("%s: failed=%d\n", __func__, ret); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | enum rtl28xxu_usb_table_entry { | ||
768 | RTL2831U_0BDA_2831, | ||
769 | RTL2831U_14AA_0160, | ||
770 | RTL2831U_14AA_0161, | ||
771 | }; | ||
772 | |||
773 | static struct usb_device_id rtl28xxu_table[] = { | ||
774 | /* RTL2831U */ | ||
775 | [RTL2831U_0BDA_2831] = { | ||
776 | USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U)}, | ||
777 | [RTL2831U_14AA_0160] = { | ||
778 | USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT)}, | ||
779 | [RTL2831U_14AA_0161] = { | ||
780 | USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)}, | ||
781 | |||
782 | /* RTL2832U */ | ||
783 | {} /* terminating entry */ | ||
784 | }; | ||
785 | |||
786 | MODULE_DEVICE_TABLE(usb, rtl28xxu_table); | ||
787 | |||
788 | static struct dvb_usb_device_properties rtl28xxu_properties[] = { | ||
789 | { | ||
790 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
791 | |||
792 | .usb_ctrl = DEVICE_SPECIFIC, | ||
793 | .no_reconnect = 1, | ||
794 | |||
795 | .size_of_priv = sizeof(struct rtl28xxu_priv), | ||
796 | |||
797 | .num_adapters = 1, | ||
798 | .adapter = { | ||
799 | { | ||
800 | .num_frontends = 1, | ||
801 | .fe = { | ||
802 | { | ||
803 | .frontend_attach = rtl2831u_frontend_attach, | ||
804 | .tuner_attach = rtl2831u_tuner_attach, | ||
805 | .streaming_ctrl = rtl28xxu_streaming_ctrl, | ||
806 | .stream = { | ||
807 | .type = USB_BULK, | ||
808 | .count = 6, | ||
809 | .endpoint = 0x81, | ||
810 | .u = { | ||
811 | .bulk = { | ||
812 | .buffersize = 8*512, | ||
813 | } | ||
814 | } | ||
815 | } | ||
816 | } | ||
817 | } | ||
818 | } | ||
819 | }, | ||
820 | |||
821 | .power_ctrl = rtl28xxu_power_ctrl, | ||
822 | |||
823 | .rc.core = { | ||
824 | .protocol = RC_TYPE_NEC, | ||
825 | .module_name = "rtl28xxu", | ||
826 | .rc_query = rtl2831u_rc_query, | ||
827 | .rc_interval = 400, | ||
828 | .allowed_protos = RC_TYPE_NEC, | ||
829 | .rc_codes = RC_MAP_EMPTY, | ||
830 | }, | ||
831 | |||
832 | .i2c_algo = &rtl28xxu_i2c_algo, | ||
833 | |||
834 | .num_device_descs = 2, | ||
835 | .devices = { | ||
836 | { | ||
837 | .name = "Realtek RTL2831U reference design", | ||
838 | .warm_ids = { | ||
839 | &rtl28xxu_table[RTL2831U_0BDA_2831], | ||
840 | }, | ||
841 | }, | ||
842 | { | ||
843 | .name = "Freecom USB2.0 DVB-T", | ||
844 | .warm_ids = { | ||
845 | &rtl28xxu_table[RTL2831U_14AA_0160], | ||
846 | &rtl28xxu_table[RTL2831U_14AA_0161], | ||
847 | }, | ||
848 | }, | ||
849 | } | ||
850 | }, | ||
851 | { | ||
852 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
853 | |||
854 | .usb_ctrl = DEVICE_SPECIFIC, | ||
855 | .no_reconnect = 1, | ||
856 | |||
857 | .size_of_priv = sizeof(struct rtl28xxu_priv), | ||
858 | |||
859 | .num_adapters = 1, | ||
860 | .adapter = { | ||
861 | { | ||
862 | .num_frontends = 1, | ||
863 | .fe = { | ||
864 | { | ||
865 | .frontend_attach = rtl2832u_frontend_attach, | ||
866 | .tuner_attach = rtl2832u_tuner_attach, | ||
867 | .streaming_ctrl = rtl28xxu_streaming_ctrl, | ||
868 | .stream = { | ||
869 | .type = USB_BULK, | ||
870 | .count = 6, | ||
871 | .endpoint = 0x81, | ||
872 | .u = { | ||
873 | .bulk = { | ||
874 | .buffersize = 8*512, | ||
875 | } | ||
876 | } | ||
877 | } | ||
878 | } | ||
879 | } | ||
880 | } | ||
881 | }, | ||
882 | |||
883 | .power_ctrl = rtl28xxu_power_ctrl, | ||
884 | |||
885 | .rc.core = { | ||
886 | .protocol = RC_TYPE_NEC, | ||
887 | .module_name = "rtl28xxu", | ||
888 | .rc_query = rtl2832u_rc_query, | ||
889 | .rc_interval = 400, | ||
890 | .allowed_protos = RC_TYPE_NEC, | ||
891 | .rc_codes = RC_MAP_EMPTY, | ||
892 | }, | ||
893 | |||
894 | .i2c_algo = &rtl28xxu_i2c_algo, | ||
895 | |||
896 | .num_device_descs = 0, /* disabled as no support for RTL2832 */ | ||
897 | .devices = { | ||
898 | { | ||
899 | .name = "Realtek RTL2832U reference design", | ||
900 | }, | ||
901 | } | ||
902 | }, | ||
903 | |||
904 | }; | ||
905 | |||
906 | static int rtl28xxu_probe(struct usb_interface *intf, | ||
907 | const struct usb_device_id *id) | ||
908 | { | ||
909 | int ret, i; | ||
910 | int properties_count = ARRAY_SIZE(rtl28xxu_properties); | ||
911 | struct dvb_usb_device *d; | ||
912 | |||
913 | deb_info("%s: interface=%d\n", __func__, | ||
914 | intf->cur_altsetting->desc.bInterfaceNumber); | ||
915 | |||
916 | if (intf->cur_altsetting->desc.bInterfaceNumber != 0) | ||
917 | return 0; | ||
918 | |||
919 | for (i = 0; i < properties_count; i++) { | ||
920 | ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i], | ||
921 | THIS_MODULE, &d, adapter_nr); | ||
922 | if (ret == 0 || ret != -ENODEV) | ||
923 | break; | ||
924 | } | ||
925 | |||
926 | if (ret) | ||
927 | goto err; | ||
928 | |||
929 | /* init USB endpoints */ | ||
930 | ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09); | ||
931 | if (ret) | ||
932 | goto err; | ||
933 | |||
934 | ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); | ||
935 | if (ret) | ||
936 | goto err; | ||
937 | |||
938 | ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); | ||
939 | if (ret) | ||
940 | goto err; | ||
941 | |||
942 | return ret; | ||
943 | err: | ||
944 | deb_info("%s: failed=%d\n", __func__, ret); | ||
945 | return ret; | ||
946 | } | ||
947 | |||
948 | static struct usb_driver rtl28xxu_driver = { | ||
949 | .name = "dvb_usb_rtl28xxu", | ||
950 | .probe = rtl28xxu_probe, | ||
951 | .disconnect = dvb_usb_device_exit, | ||
952 | .id_table = rtl28xxu_table, | ||
953 | }; | ||
954 | |||
955 | /* module stuff */ | ||
956 | static int __init rtl28xxu_module_init(void) | ||
957 | { | ||
958 | int ret; | ||
959 | |||
960 | deb_info("%s:\n", __func__); | ||
961 | |||
962 | ret = usb_register(&rtl28xxu_driver); | ||
963 | if (ret) | ||
964 | err("usb_register failed=%d", ret); | ||
965 | |||
966 | return ret; | ||
967 | } | ||
968 | |||
969 | static void __exit rtl28xxu_module_exit(void) | ||
970 | { | ||
971 | deb_info("%s:\n", __func__); | ||
972 | |||
973 | /* deregister this driver from the USB subsystem */ | ||
974 | usb_deregister(&rtl28xxu_driver); | ||
975 | } | ||
976 | |||
977 | module_init(rtl28xxu_module_init); | ||
978 | module_exit(rtl28xxu_module_exit); | ||
979 | |||
980 | MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver"); | ||
981 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
982 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.h b/drivers/media/dvb/dvb-usb/rtl28xxu.h new file mode 100644 index 000000000000..90f3bb4f4c0e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/rtl28xxu.h | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * Realtek RTL28xxU DVB USB driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> | ||
5 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef RTL28XXU_H | ||
23 | #define RTL28XXU_H | ||
24 | |||
25 | #define DVB_USB_LOG_PREFIX "rtl28xxu" | ||
26 | #include "dvb-usb.h" | ||
27 | |||
28 | #define deb_info(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x01, args) | ||
29 | #define deb_rc(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x02, args) | ||
30 | #define deb_xfer(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x04, args) | ||
31 | #define deb_reg(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x08, args) | ||
32 | #define deb_i2c(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x10, args) | ||
33 | #define deb_fw(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x20, args) | ||
34 | |||
35 | #define deb_dump(r, t, v, i, b, l, func) { \ | ||
36 | int loop_; \ | ||
37 | func("%02x %02x %02x %02x %02x %02x %02x %02x", \ | ||
38 | t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ | ||
39 | if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ | ||
40 | func(" >>> "); \ | ||
41 | else \ | ||
42 | func(" <<< "); \ | ||
43 | for (loop_ = 0; loop_ < l; loop_++) \ | ||
44 | func("%02x ", b[loop_]); \ | ||
45 | func("\n");\ | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * USB commands | ||
50 | * (usb_control_msg() index parameter) | ||
51 | */ | ||
52 | |||
53 | #define DEMOD 0x0000 | ||
54 | #define USB 0x0100 | ||
55 | #define SYS 0x0200 | ||
56 | #define I2C 0x0300 | ||
57 | #define I2C_DA 0x0600 | ||
58 | |||
59 | #define CMD_WR_FLAG 0x0010 | ||
60 | #define CMD_DEMOD_RD 0x0000 | ||
61 | #define CMD_DEMOD_WR 0x0010 | ||
62 | #define CMD_USB_RD 0x0100 | ||
63 | #define CMD_USB_WR 0x0110 | ||
64 | #define CMD_SYS_RD 0x0200 | ||
65 | #define CMD_IR_RD 0x0201 | ||
66 | #define CMD_IR_WR 0x0211 | ||
67 | #define CMD_SYS_WR 0x0210 | ||
68 | #define CMD_I2C_RD 0x0300 | ||
69 | #define CMD_I2C_WR 0x0310 | ||
70 | #define CMD_I2C_DA_RD 0x0600 | ||
71 | #define CMD_I2C_DA_WR 0x0610 | ||
72 | |||
73 | |||
74 | struct rtl28xxu_priv { | ||
75 | u8 chip_id; | ||
76 | u8 tuner; | ||
77 | u8 page; /* integrated demod active register page */ | ||
78 | bool rc_active; | ||
79 | }; | ||
80 | |||
81 | enum rtl28xxu_chip_id { | ||
82 | CHIP_ID_NONE, | ||
83 | CHIP_ID_RTL2831U, | ||
84 | CHIP_ID_RTL2832U, | ||
85 | }; | ||
86 | |||
87 | enum rtl28xxu_tuner { | ||
88 | TUNER_NONE, | ||
89 | |||
90 | TUNER_RTL2830_QT1010, | ||
91 | TUNER_RTL2830_MT2060, | ||
92 | TUNER_RTL2830_MXL5005S, | ||
93 | |||
94 | TUNER_RTL2832_MT2266, | ||
95 | TUNER_RTL2832_FC2580, | ||
96 | TUNER_RTL2832_MT2063, | ||
97 | TUNER_RTL2832_MAX3543, | ||
98 | TUNER_RTL2832_TUA9001, | ||
99 | TUNER_RTL2832_MXL5007T, | ||
100 | TUNER_RTL2832_FC0012, | ||
101 | TUNER_RTL2832_E4000, | ||
102 | TUNER_RTL2832_TDA18272, | ||
103 | TUNER_RTL2832_FC0013, | ||
104 | }; | ||
105 | |||
106 | struct rtl28xxu_req { | ||
107 | u16 value; | ||
108 | u16 index; | ||
109 | u16 size; | ||
110 | u8 *data; | ||
111 | }; | ||
112 | |||
113 | struct rtl28xxu_reg_val { | ||
114 | u16 reg; | ||
115 | u8 val; | ||
116 | }; | ||
117 | |||
118 | /* | ||
119 | * memory map | ||
120 | * | ||
121 | * 0x0000 DEMOD : demodulator | ||
122 | * 0x2000 USB : SIE, USB endpoint, debug, DMA | ||
123 | * 0x3000 SYS : system | ||
124 | * 0xfc00 RC : remote controller (not RTL2831U) | ||
125 | */ | ||
126 | |||
127 | /* | ||
128 | * USB registers | ||
129 | */ | ||
130 | /* SIE Control Registers */ | ||
131 | #define USB_SYSCTL 0x2000 /* USB system control */ | ||
132 | #define USB_SYSCTL_0 0x2000 /* USB system control */ | ||
133 | #define USB_SYSCTL_1 0x2001 /* USB system control */ | ||
134 | #define USB_SYSCTL_2 0x2002 /* USB system control */ | ||
135 | #define USB_SYSCTL_3 0x2003 /* USB system control */ | ||
136 | #define USB_IRQSTAT 0x2008 /* SIE interrupt status */ | ||
137 | #define USB_IRQEN 0x200C /* SIE interrupt enable */ | ||
138 | #define USB_CTRL 0x2010 /* USB control */ | ||
139 | #define USB_STAT 0x2014 /* USB status */ | ||
140 | #define USB_DEVADDR 0x2018 /* USB device address */ | ||
141 | #define USB_TEST 0x201C /* USB test mode */ | ||
142 | #define USB_FRAME_NUMBER 0x2020 /* frame number */ | ||
143 | #define USB_FIFO_ADDR 0x2028 /* address of SIE FIFO RAM */ | ||
144 | #define USB_FIFO_CMD 0x202A /* SIE FIFO RAM access command */ | ||
145 | #define USB_FIFO_DATA 0x2030 /* SIE FIFO RAM data */ | ||
146 | /* Endpoint Registers */ | ||
147 | #define EP0_SETUPA 0x20F8 /* EP 0 setup packet lower byte */ | ||
148 | #define EP0_SETUPB 0x20FC /* EP 0 setup packet higher byte */ | ||
149 | #define USB_EP0_CFG 0x2104 /* EP 0 configure */ | ||
150 | #define USB_EP0_CTL 0x2108 /* EP 0 control */ | ||
151 | #define USB_EP0_STAT 0x210C /* EP 0 status */ | ||
152 | #define USB_EP0_IRQSTAT 0x2110 /* EP 0 interrupt status */ | ||
153 | #define USB_EP0_IRQEN 0x2114 /* EP 0 interrupt enable */ | ||
154 | #define USB_EP0_MAXPKT 0x2118 /* EP 0 max packet size */ | ||
155 | #define USB_EP0_BC 0x2120 /* EP 0 FIFO byte counter */ | ||
156 | #define USB_EPA_CFG 0x2144 /* EP A configure */ | ||
157 | #define USB_EPA_CFG_0 0x2144 /* EP A configure */ | ||
158 | #define USB_EPA_CFG_1 0x2145 /* EP A configure */ | ||
159 | #define USB_EPA_CFG_2 0x2146 /* EP A configure */ | ||
160 | #define USB_EPA_CFG_3 0x2147 /* EP A configure */ | ||
161 | #define USB_EPA_CTL 0x2148 /* EP A control */ | ||
162 | #define USB_EPA_CTL_0 0x2148 /* EP A control */ | ||
163 | #define USB_EPA_CTL_1 0x2149 /* EP A control */ | ||
164 | #define USB_EPA_CTL_2 0x214A /* EP A control */ | ||
165 | #define USB_EPA_CTL_3 0x214B /* EP A control */ | ||
166 | #define USB_EPA_STAT 0x214C /* EP A status */ | ||
167 | #define USB_EPA_IRQSTAT 0x2150 /* EP A interrupt status */ | ||
168 | #define USB_EPA_IRQEN 0x2154 /* EP A interrupt enable */ | ||
169 | #define USB_EPA_MAXPKT 0x2158 /* EP A max packet size */ | ||
170 | #define USB_EPA_MAXPKT_0 0x2158 /* EP A max packet size */ | ||
171 | #define USB_EPA_MAXPKT_1 0x2159 /* EP A max packet size */ | ||
172 | #define USB_EPA_MAXPKT_2 0x215A /* EP A max packet size */ | ||
173 | #define USB_EPA_MAXPKT_3 0x215B /* EP A max packet size */ | ||
174 | #define USB_EPA_FIFO_CFG 0x2160 /* EP A FIFO configure */ | ||
175 | #define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */ | ||
176 | #define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */ | ||
177 | #define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */ | ||
178 | #define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */ | ||
179 | /* Debug Registers */ | ||
180 | #define USB_PHYTSTDIS 0x2F04 /* PHY test disable */ | ||
181 | #define USB_TOUT_VAL 0x2F08 /* USB time-out time */ | ||
182 | #define USB_VDRCTRL 0x2F10 /* UTMI vendor signal control */ | ||
183 | #define USB_VSTAIN 0x2F14 /* UTMI vendor signal status in */ | ||
184 | #define USB_VLOADM 0x2F18 /* UTMI load vendor signal status in */ | ||
185 | #define USB_VSTAOUT 0x2F1C /* UTMI vendor signal status out */ | ||
186 | #define USB_UTMI_TST 0x2F80 /* UTMI test */ | ||
187 | #define USB_UTMI_STATUS 0x2F84 /* UTMI status */ | ||
188 | #define USB_TSTCTL 0x2F88 /* test control */ | ||
189 | #define USB_TSTCTL2 0x2F8C /* test control 2 */ | ||
190 | #define USB_PID_FORCE 0x2F90 /* force PID */ | ||
191 | #define USB_PKTERR_CNT 0x2F94 /* packet error counter */ | ||
192 | #define USB_RXERR_CNT 0x2F98 /* RX error counter */ | ||
193 | #define USB_MEM_BIST 0x2F9C /* MEM BIST test */ | ||
194 | #define USB_SLBBIST 0x2FA0 /* self-loop-back BIST */ | ||
195 | #define USB_CNTTEST 0x2FA4 /* counter test */ | ||
196 | #define USB_PHYTST 0x2FC0 /* USB PHY test */ | ||
197 | #define USB_DBGIDX 0x2FF0 /* select individual block debug signal */ | ||
198 | #define USB_DBGMUX 0x2FF4 /* debug signal module mux */ | ||
199 | |||
200 | /* | ||
201 | * SYS registers | ||
202 | */ | ||
203 | /* demod control registers */ | ||
204 | #define SYS_SYS0 0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */ | ||
205 | #define SYS_DEMOD_CTL 0x3000 /* control register for DVB-T demodulator */ | ||
206 | /* GPIO registers */ | ||
207 | #define SYS_GPIO_OUT_VAL 0x3001 /* output value of GPIO */ | ||
208 | #define SYS_GPIO_IN_VAL 0x3002 /* input value of GPIO */ | ||
209 | #define SYS_GPIO_OUT_EN 0x3003 /* output enable of GPIO */ | ||
210 | #define SYS_SYS1 0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */ | ||
211 | #define SYS_GPIO_DIR 0x3004 /* direction control for GPIO */ | ||
212 | #define SYS_SYSINTE 0x3005 /* system interrupt enable */ | ||
213 | #define SYS_SYSINTS 0x3006 /* system interrupt status */ | ||
214 | #define SYS_GPIO_CFG0 0x3007 /* PAD configuration for GPIO0-GPIO3 */ | ||
215 | #define SYS_SYS2 0x3008 /* include GP_CFG1 and 3 reserved bytes */ | ||
216 | #define SYS_GPIO_CFG1 0x3008 /* PAD configuration for GPIO4 */ | ||
217 | #define SYS_DEMOD_CTL1 0x300B | ||
218 | |||
219 | /* IrDA registers */ | ||
220 | #define SYS_IRRC_PSR 0x3020 /* IR protocol selection */ | ||
221 | #define SYS_IRRC_PER 0x3024 /* IR protocol extension */ | ||
222 | #define SYS_IRRC_SF 0x3028 /* IR sampling frequency */ | ||
223 | #define SYS_IRRC_DPIR 0x302C /* IR data package interval */ | ||
224 | #define SYS_IRRC_CR 0x3030 /* IR control */ | ||
225 | #define SYS_IRRC_RP 0x3034 /* IR read port */ | ||
226 | #define SYS_IRRC_SR 0x3038 /* IR status */ | ||
227 | /* I2C master registers */ | ||
228 | #define SYS_I2CCR 0x3040 /* I2C clock */ | ||
229 | #define SYS_I2CMCR 0x3044 /* I2C master control */ | ||
230 | #define SYS_I2CMSTR 0x3048 /* I2C master SCL timing */ | ||
231 | #define SYS_I2CMSR 0x304C /* I2C master status */ | ||
232 | #define SYS_I2CMFR 0x3050 /* I2C master FIFO */ | ||
233 | |||
234 | /* | ||
235 | * IR registers | ||
236 | */ | ||
237 | #define IR_RX_BUF 0xFC00 | ||
238 | #define IR_RX_IE 0xFD00 | ||
239 | #define IR_RX_IF 0xFD01 | ||
240 | #define IR_RX_CTRL 0xFD02 | ||
241 | #define IR_RX_CFG 0xFD03 | ||
242 | #define IR_MAX_DURATION0 0xFD04 | ||
243 | #define IR_MAX_DURATION1 0xFD05 | ||
244 | #define IR_IDLE_LEN0 0xFD06 | ||
245 | #define IR_IDLE_LEN1 0xFD07 | ||
246 | #define IR_GLITCH_LEN 0xFD08 | ||
247 | #define IR_RX_BUF_CTRL 0xFD09 | ||
248 | #define IR_RX_BUF_DATA 0xFD0A | ||
249 | #define IR_RX_BC 0xFD0B | ||
250 | #define IR_RX_CLK 0xFD0C | ||
251 | #define IR_RX_C_COUNT_L 0xFD0D | ||
252 | #define IR_RX_C_COUNT_H 0xFD0E | ||
253 | #define IR_SUSPEND_CTRL 0xFD10 | ||
254 | #define IR_ERR_TOL_CTRL 0xFD11 | ||
255 | #define IR_UNIT_LEN 0xFD12 | ||
256 | #define IR_ERR_TOL_LEN 0xFD13 | ||
257 | #define IR_MAX_H_TOL_LEN 0xFD14 | ||
258 | #define IR_MAX_L_TOL_LEN 0xFD15 | ||
259 | #define IR_MASK_CTRL 0xFD16 | ||
260 | #define IR_MASK_DATA 0xFD17 | ||
261 | #define IR_RES_MASK_ADDR 0xFD18 | ||
262 | #define IR_RES_MASK_T_LEN 0xFD19 | ||
263 | |||
264 | #endif | ||
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ebb5ed7a7783..21246707fbfb 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -425,6 +425,13 @@ config DVB_CXD2820R | |||
425 | help | 425 | help |
426 | Say Y when you want to support this frontend. | 426 | Say Y when you want to support this frontend. |
427 | 427 | ||
428 | config DVB_RTL2830 | ||
429 | tristate "Realtek RTL2830 DVB-T" | ||
430 | depends on DVB_CORE && I2C | ||
431 | default m if DVB_FE_CUSTOMISE | ||
432 | help | ||
433 | Say Y when you want to support this frontend. | ||
434 | |||
428 | comment "DVB-C (cable) frontends" | 435 | comment "DVB-C (cable) frontends" |
429 | depends on DVB_CORE | 436 | depends on DVB_CORE |
430 | 437 | ||
@@ -698,6 +705,14 @@ config DVB_IT913X_FE | |||
698 | A DVB-T tuner module. | 705 | A DVB-T tuner module. |
699 | Say Y when you want to support this frontend. | 706 | Say Y when you want to support this frontend. |
700 | 707 | ||
708 | config DVB_M88RS2000 | ||
709 | tristate "M88RS2000 DVB-S demodulator and tuner" | ||
710 | depends on DVB_CORE && I2C | ||
711 | default m if DVB_FE_CUSTOMISE | ||
712 | help | ||
713 | A DVB-S tuner module. | ||
714 | Say Y when you want to support this frontend. | ||
715 | |||
701 | comment "Tools to develop new frontends" | 716 | comment "Tools to develop new frontends" |
702 | 717 | ||
703 | config DVB_DUMMY_FE | 718 | config DVB_DUMMY_FE |
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 00a20636df62..86fa808bf589 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -2,8 +2,8 @@ | |||
2 | # Makefile for the kernel DVB frontend device drivers. | 2 | # Makefile for the kernel DVB frontend device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | ccflags-y += -Idrivers/media/dvb/dvb-core/ | 5 | ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/ |
6 | ccflags-y += -Idrivers/media/common/tuners/ | 6 | ccflags-y += -I$(srctree)/drivers/media/common/tuners/ |
7 | 7 | ||
8 | stb0899-objs = stb0899_drv.o stb0899_algo.o | 8 | stb0899-objs = stb0899_drv.o stb0899_algo.o |
9 | stv0900-objs = stv0900_core.o stv0900_sw.o | 9 | stv0900-objs = stv0900_core.o stv0900_sw.o |
@@ -96,4 +96,6 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o | |||
96 | obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o | 96 | obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o |
97 | obj-$(CONFIG_DVB_A8293) += a8293.o | 97 | obj-$(CONFIG_DVB_A8293) += a8293.o |
98 | obj-$(CONFIG_DVB_TDA10071) += tda10071.o | 98 | obj-$(CONFIG_DVB_TDA10071) += tda10071.o |
99 | obj-$(CONFIG_DVB_RTL2830) += rtl2830.o | ||
100 | obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o | ||
99 | 101 | ||
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index 2b248c12f404..55b6390198e3 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c | |||
@@ -839,15 +839,4 @@ static struct i2c_driver au8522_driver = { | |||
839 | .id_table = au8522_id, | 839 | .id_table = au8522_id, |
840 | }; | 840 | }; |
841 | 841 | ||
842 | static __init int init_au8522(void) | 842 | module_i2c_driver(au8522_driver); |
843 | { | ||
844 | return i2c_add_driver(&au8522_driver); | ||
845 | } | ||
846 | |||
847 | static __exit void exit_au8522(void) | ||
848 | { | ||
849 | i2c_del_driver(&au8522_driver); | ||
850 | } | ||
851 | |||
852 | module_init(init_au8522); | ||
853 | module_exit(exit_au8522); | ||
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c index c688b95df486..25f650934c73 100644 --- a/drivers/media/dvb/frontends/au8522_dig.c +++ b/drivers/media/dvb/frontends/au8522_dig.c | |||
@@ -588,11 +588,6 @@ static int au8522_set_frontend(struct dvb_frontend *fe) | |||
588 | (state->current_modulation == c->modulation)) | 588 | (state->current_modulation == c->modulation)) |
589 | return 0; | 589 | return 0; |
590 | 590 | ||
591 | au8522_enable_modulation(fe, c->modulation); | ||
592 | |||
593 | /* Allow the demod to settle */ | ||
594 | msleep(100); | ||
595 | |||
596 | if (fe->ops.tuner_ops.set_params) { | 591 | if (fe->ops.tuner_ops.set_params) { |
597 | if (fe->ops.i2c_gate_ctrl) | 592 | if (fe->ops.i2c_gate_ctrl) |
598 | fe->ops.i2c_gate_ctrl(fe, 1); | 593 | fe->ops.i2c_gate_ctrl(fe, 1); |
@@ -604,6 +599,11 @@ static int au8522_set_frontend(struct dvb_frontend *fe) | |||
604 | if (ret < 0) | 599 | if (ret < 0) |
605 | return ret; | 600 | return ret; |
606 | 601 | ||
602 | /* Allow the tuner to settle */ | ||
603 | msleep(100); | ||
604 | |||
605 | au8522_enable_modulation(fe, c->modulation); | ||
606 | |||
607 | state->current_frequency = c->frequency; | 607 | state->current_frequency = c->frequency; |
608 | 608 | ||
609 | return 0; | 609 | return 0; |
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index faba82485086..edc8eafc5c09 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c | |||
@@ -502,10 +502,26 @@ static int cx22702_read_signal_strength(struct dvb_frontend *fe, | |||
502 | u16 *signal_strength) | 502 | u16 *signal_strength) |
503 | { | 503 | { |
504 | struct cx22702_state *state = fe->demodulator_priv; | 504 | struct cx22702_state *state = fe->demodulator_priv; |
505 | u8 reg23; | ||
505 | 506 | ||
506 | u16 rs_ber; | 507 | /* |
507 | rs_ber = cx22702_readreg(state, 0x23); | 508 | * Experience suggests that the strength signal register works as |
508 | *signal_strength = (rs_ber << 8) | rs_ber; | 509 | * follows: |
510 | * - In the absence of signal, value is 0xff. | ||
511 | * - In the presence of a weak signal, bit 7 is set, not sure what | ||
512 | * the lower 7 bits mean. | ||
513 | * - In the presence of a strong signal, the register holds a 7-bit | ||
514 | * value (bit 7 is cleared), with greater values standing for | ||
515 | * weaker signals. | ||
516 | */ | ||
517 | reg23 = cx22702_readreg(state, 0x23); | ||
518 | if (reg23 & 0x80) { | ||
519 | *signal_strength = 0; | ||
520 | } else { | ||
521 | reg23 = ~reg23 & 0x7f; | ||
522 | /* Scale to 16 bit */ | ||
523 | *signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5); | ||
524 | } | ||
509 | 525 | ||
510 | return 0; | 526 | return 0; |
511 | } | 527 | } |
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index 224d81e85091..d9fe60b4be48 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c | |||
@@ -519,7 +519,7 @@ static int dib0090_fw_identify(struct dvb_frontend *fe) | |||
519 | return 0; | 519 | return 0; |
520 | 520 | ||
521 | identification_error: | 521 | identification_error: |
522 | return -EIO;; | 522 | return -EIO; |
523 | } | 523 | } |
524 | 524 | ||
525 | static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) | 525 | static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) |
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index 863ef3cfab9f..80848b4c15d4 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c | |||
@@ -33,7 +33,7 @@ struct i2c_device { | |||
33 | 33 | ||
34 | /* lock */ | 34 | /* lock */ |
35 | #define DIB_LOCK struct mutex | 35 | #define DIB_LOCK struct mutex |
36 | #define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0) | 36 | #define DibAcquireLock(lock) mutex_lock_interruptible(lock) |
37 | #define DibReleaseLock(lock) mutex_unlock(lock) | 37 | #define DibReleaseLock(lock) mutex_unlock(lock) |
38 | #define DibInitLock(lock) mutex_init(lock) | 38 | #define DibInitLock(lock) mutex_init(lock) |
39 | #define DibFreeLock(lock) | 39 | #define DibFreeLock(lock) |
@@ -446,7 +446,10 @@ static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u1 | |||
446 | if (!state->platform.risc.fw_is_running) | 446 | if (!state->platform.risc.fw_is_running) |
447 | return -EIO; | 447 | return -EIO; |
448 | 448 | ||
449 | DibAcquireLock(&state->platform.risc.mem_lock); | 449 | if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { |
450 | dprintk("could not get the lock"); | ||
451 | return -EINTR; | ||
452 | } | ||
450 | dib9000_risc_mem_setup(state, cmd | 0x80); | 453 | dib9000_risc_mem_setup(state, cmd | 0x80); |
451 | dib9000_risc_mem_read_chunks(state, b, len); | 454 | dib9000_risc_mem_read_chunks(state, b, len); |
452 | DibReleaseLock(&state->platform.risc.mem_lock); | 455 | DibReleaseLock(&state->platform.risc.mem_lock); |
@@ -459,7 +462,10 @@ static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 | |||
459 | if (!state->platform.risc.fw_is_running) | 462 | if (!state->platform.risc.fw_is_running) |
460 | return -EIO; | 463 | return -EIO; |
461 | 464 | ||
462 | DibAcquireLock(&state->platform.risc.mem_lock); | 465 | if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { |
466 | dprintk("could not get the lock"); | ||
467 | return -EINTR; | ||
468 | } | ||
463 | dib9000_risc_mem_setup(state, cmd); | 469 | dib9000_risc_mem_setup(state, cmd); |
464 | dib9000_risc_mem_write_chunks(state, b, m->size); | 470 | dib9000_risc_mem_write_chunks(state, b, m->size); |
465 | DibReleaseLock(&state->platform.risc.mem_lock); | 471 | DibReleaseLock(&state->platform.risc.mem_lock); |
@@ -531,7 +537,10 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, | |||
531 | if (!state->platform.risc.fw_is_running) | 537 | if (!state->platform.risc.fw_is_running) |
532 | return -EINVAL; | 538 | return -EINVAL; |
533 | 539 | ||
534 | DibAcquireLock(&state->platform.risc.mbx_if_lock); | 540 | if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { |
541 | dprintk("could not get the lock"); | ||
542 | return -EINTR; | ||
543 | } | ||
535 | tmp = MAX_MAILBOX_TRY; | 544 | tmp = MAX_MAILBOX_TRY; |
536 | do { | 545 | do { |
537 | size = dib9000_read_word_attr(state, 1043, attr) & 0xff; | 546 | size = dib9000_read_word_attr(state, 1043, attr) & 0xff; |
@@ -593,7 +602,10 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, | |||
593 | if (!state->platform.risc.fw_is_running) | 602 | if (!state->platform.risc.fw_is_running) |
594 | return 0; | 603 | return 0; |
595 | 604 | ||
596 | DibAcquireLock(&state->platform.risc.mbx_if_lock); | 605 | if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { |
606 | dprintk("could not get the lock"); | ||
607 | return 0; | ||
608 | } | ||
597 | if (risc_id == 1) | 609 | if (risc_id == 1) |
598 | mc_base = 16; | 610 | mc_base = 16; |
599 | else | 611 | else |
@@ -701,7 +713,10 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) | |||
701 | if (!state->platform.risc.fw_is_running) | 713 | if (!state->platform.risc.fw_is_running) |
702 | return -1; | 714 | return -1; |
703 | 715 | ||
704 | DibAcquireLock(&state->platform.risc.mbx_lock); | 716 | if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) { |
717 | dprintk("could not get the lock"); | ||
718 | return -1; | ||
719 | } | ||
705 | 720 | ||
706 | if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ | 721 | if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ |
707 | ret = dib9000_mbx_fetch_to_cache(state, attr); | 722 | ret = dib9000_mbx_fetch_to_cache(state, attr); |
@@ -1178,7 +1193,10 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe) | |||
1178 | struct dibDVBTChannel *ch; | 1193 | struct dibDVBTChannel *ch; |
1179 | int ret = 0; | 1194 | int ret = 0; |
1180 | 1195 | ||
1181 | DibAcquireLock(&state->platform.risc.mem_mbx_lock); | 1196 | if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { |
1197 | dprintk("could not get the lock"); | ||
1198 | return -EINTR; | ||
1199 | } | ||
1182 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { | 1200 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { |
1183 | ret = -EIO; | 1201 | ret = -EIO; |
1184 | goto error; | 1202 | goto error; |
@@ -1660,7 +1678,10 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 | |||
1660 | p[12] = 0; | 1678 | p[12] = 0; |
1661 | } | 1679 | } |
1662 | 1680 | ||
1663 | DibAcquireLock(&state->platform.risc.mem_mbx_lock); | 1681 | if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { |
1682 | dprintk("could not get the lock"); | ||
1683 | return 0; | ||
1684 | } | ||
1664 | 1685 | ||
1665 | dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); | 1686 | dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); |
1666 | 1687 | ||
@@ -1768,7 +1789,10 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) | |||
1768 | return 0; | 1789 | return 0; |
1769 | } | 1790 | } |
1770 | 1791 | ||
1771 | DibAcquireLock(&state->demod_lock); | 1792 | if (DibAcquireLock(&state->demod_lock) < 0) { |
1793 | dprintk("could not get the lock"); | ||
1794 | return -EINTR; | ||
1795 | } | ||
1772 | 1796 | ||
1773 | val = dib9000_read_word(state, 294 + 1) & 0xffef; | 1797 | val = dib9000_read_word(state, 294 + 1) & 0xffef; |
1774 | val |= (onoff & 0x1) << 4; | 1798 | val |= (onoff & 0x1) << 4; |
@@ -1800,7 +1824,10 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) | |||
1800 | return 0; | 1824 | return 0; |
1801 | } | 1825 | } |
1802 | 1826 | ||
1803 | DibAcquireLock(&state->demod_lock); | 1827 | if (DibAcquireLock(&state->demod_lock) < 0) { |
1828 | dprintk("could not get the lock"); | ||
1829 | return -EINTR; | ||
1830 | } | ||
1804 | dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); | 1831 | dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); |
1805 | ret = dib9000_write_word(state, 300 + 1 + id, | 1832 | ret = dib9000_write_word(state, 300 + 1 + id, |
1806 | onoff ? (1 << 13) | pid : 0); | 1833 | onoff ? (1 << 13) | pid : 0); |
@@ -1848,7 +1875,10 @@ static int dib9000_sleep(struct dvb_frontend *fe) | |||
1848 | u8 index_frontend; | 1875 | u8 index_frontend; |
1849 | int ret = 0; | 1876 | int ret = 0; |
1850 | 1877 | ||
1851 | DibAcquireLock(&state->demod_lock); | 1878 | if (DibAcquireLock(&state->demod_lock) < 0) { |
1879 | dprintk("could not get the lock"); | ||
1880 | return -EINTR; | ||
1881 | } | ||
1852 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { | 1882 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { |
1853 | ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); | 1883 | ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); |
1854 | if (ret < 0) | 1884 | if (ret < 0) |
@@ -1874,8 +1904,12 @@ static int dib9000_get_frontend(struct dvb_frontend *fe) | |||
1874 | fe_status_t stat; | 1904 | fe_status_t stat; |
1875 | int ret = 0; | 1905 | int ret = 0; |
1876 | 1906 | ||
1877 | if (state->get_frontend_internal == 0) | 1907 | if (state->get_frontend_internal == 0) { |
1878 | DibAcquireLock(&state->demod_lock); | 1908 | if (DibAcquireLock(&state->demod_lock) < 0) { |
1909 | dprintk("could not get the lock"); | ||
1910 | return -EINTR; | ||
1911 | } | ||
1912 | } | ||
1879 | 1913 | ||
1880 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { | 1914 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { |
1881 | state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); | 1915 | state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); |
@@ -1978,7 +2012,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) | |||
1978 | } | 2012 | } |
1979 | 2013 | ||
1980 | state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ | 2014 | state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ |
1981 | DibAcquireLock(&state->demod_lock); | 2015 | if (DibAcquireLock(&state->demod_lock) < 0) { |
2016 | dprintk("could not get the lock"); | ||
2017 | return 0; | ||
2018 | } | ||
1982 | 2019 | ||
1983 | fe->dtv_property_cache.delivery_system = SYS_DVBT; | 2020 | fe->dtv_property_cache.delivery_system = SYS_DVBT; |
1984 | 2021 | ||
@@ -2138,7 +2175,10 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) | |||
2138 | u8 index_frontend; | 2175 | u8 index_frontend; |
2139 | u16 lock = 0, lock_slave = 0; | 2176 | u16 lock = 0, lock_slave = 0; |
2140 | 2177 | ||
2141 | DibAcquireLock(&state->demod_lock); | 2178 | if (DibAcquireLock(&state->demod_lock) < 0) { |
2179 | dprintk("could not get the lock"); | ||
2180 | return -EINTR; | ||
2181 | } | ||
2142 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) | 2182 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) |
2143 | lock_slave |= dib9000_read_lock(state->fe[index_frontend]); | 2183 | lock_slave |= dib9000_read_lock(state->fe[index_frontend]); |
2144 | 2184 | ||
@@ -2168,8 +2208,15 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) | |||
2168 | u16 *c; | 2208 | u16 *c; |
2169 | int ret = 0; | 2209 | int ret = 0; |
2170 | 2210 | ||
2171 | DibAcquireLock(&state->demod_lock); | 2211 | if (DibAcquireLock(&state->demod_lock) < 0) { |
2172 | DibAcquireLock(&state->platform.risc.mem_mbx_lock); | 2212 | dprintk("could not get the lock"); |
2213 | return -EINTR; | ||
2214 | } | ||
2215 | if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { | ||
2216 | dprintk("could not get the lock"); | ||
2217 | ret = -EINTR; | ||
2218 | goto error; | ||
2219 | } | ||
2173 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { | 2220 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { |
2174 | DibReleaseLock(&state->platform.risc.mem_mbx_lock); | 2221 | DibReleaseLock(&state->platform.risc.mem_mbx_lock); |
2175 | ret = -EIO; | 2222 | ret = -EIO; |
@@ -2196,7 +2243,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | |||
2196 | u16 val; | 2243 | u16 val; |
2197 | int ret = 0; | 2244 | int ret = 0; |
2198 | 2245 | ||
2199 | DibAcquireLock(&state->demod_lock); | 2246 | if (DibAcquireLock(&state->demod_lock) < 0) { |
2247 | dprintk("could not get the lock"); | ||
2248 | return -EINTR; | ||
2249 | } | ||
2200 | *strength = 0; | 2250 | *strength = 0; |
2201 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { | 2251 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { |
2202 | state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); | 2252 | state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); |
@@ -2206,8 +2256,13 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | |||
2206 | *strength += val; | 2256 | *strength += val; |
2207 | } | 2257 | } |
2208 | 2258 | ||
2209 | DibAcquireLock(&state->platform.risc.mem_mbx_lock); | 2259 | if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { |
2260 | dprintk("could not get the lock"); | ||
2261 | ret = -EINTR; | ||
2262 | goto error; | ||
2263 | } | ||
2210 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { | 2264 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { |
2265 | DibReleaseLock(&state->platform.risc.mem_mbx_lock); | ||
2211 | ret = -EIO; | 2266 | ret = -EIO; |
2212 | goto error; | 2267 | goto error; |
2213 | } | 2268 | } |
@@ -2232,9 +2287,14 @@ static u32 dib9000_get_snr(struct dvb_frontend *fe) | |||
2232 | u32 n, s, exp; | 2287 | u32 n, s, exp; |
2233 | u16 val; | 2288 | u16 val; |
2234 | 2289 | ||
2235 | DibAcquireLock(&state->platform.risc.mem_mbx_lock); | 2290 | if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { |
2236 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) | 2291 | dprintk("could not get the lock"); |
2237 | return -EIO; | 2292 | return 0; |
2293 | } | ||
2294 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { | ||
2295 | DibReleaseLock(&state->platform.risc.mem_mbx_lock); | ||
2296 | return 0; | ||
2297 | } | ||
2238 | dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); | 2298 | dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); |
2239 | DibReleaseLock(&state->platform.risc.mem_mbx_lock); | 2299 | DibReleaseLock(&state->platform.risc.mem_mbx_lock); |
2240 | 2300 | ||
@@ -2266,7 +2326,10 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) | |||
2266 | u8 index_frontend; | 2326 | u8 index_frontend; |
2267 | u32 snr_master; | 2327 | u32 snr_master; |
2268 | 2328 | ||
2269 | DibAcquireLock(&state->demod_lock); | 2329 | if (DibAcquireLock(&state->demod_lock) < 0) { |
2330 | dprintk("could not get the lock"); | ||
2331 | return -EINTR; | ||
2332 | } | ||
2270 | snr_master = dib9000_get_snr(fe); | 2333 | snr_master = dib9000_get_snr(fe); |
2271 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) | 2334 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) |
2272 | snr_master += dib9000_get_snr(state->fe[index_frontend]); | 2335 | snr_master += dib9000_get_snr(state->fe[index_frontend]); |
@@ -2288,9 +2351,17 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) | |||
2288 | u16 *c = (u16 *)state->i2c_read_buffer; | 2351 | u16 *c = (u16 *)state->i2c_read_buffer; |
2289 | int ret = 0; | 2352 | int ret = 0; |
2290 | 2353 | ||
2291 | DibAcquireLock(&state->demod_lock); | 2354 | if (DibAcquireLock(&state->demod_lock) < 0) { |
2292 | DibAcquireLock(&state->platform.risc.mem_mbx_lock); | 2355 | dprintk("could not get the lock"); |
2356 | return -EINTR; | ||
2357 | } | ||
2358 | if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { | ||
2359 | dprintk("could not get the lock"); | ||
2360 | ret = -EINTR; | ||
2361 | goto error; | ||
2362 | } | ||
2293 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { | 2363 | if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { |
2364 | DibReleaseLock(&state->platform.risc.mem_mbx_lock); | ||
2294 | ret = -EIO; | 2365 | ret = -EIO; |
2295 | goto error; | 2366 | goto error; |
2296 | } | 2367 | } |
diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c index 7bf39cda83c5..f380eb43e9d5 100644 --- a/drivers/media/dvb/frontends/drxd_hard.c +++ b/drivers/media/dvb/frontends/drxd_hard.c | |||
@@ -101,9 +101,9 @@ struct SCfgAgc { | |||
101 | 101 | ||
102 | struct SNoiseCal { | 102 | struct SNoiseCal { |
103 | int cpOpt; | 103 | int cpOpt; |
104 | u16 cpNexpOfs; | 104 | short cpNexpOfs; |
105 | u16 tdCal2k; | 105 | short tdCal2k; |
106 | u16 tdCal8k; | 106 | short tdCal8k; |
107 | }; | 107 | }; |
108 | 108 | ||
109 | enum app_env { | 109 | enum app_env { |
diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h index 020981844a86..9d64e4fea066 100644 --- a/drivers/media/dvb/frontends/drxk.h +++ b/drivers/media/dvb/frontends/drxk.h | |||
@@ -7,15 +7,19 @@ | |||
7 | /** | 7 | /** |
8 | * struct drxk_config - Configure the initial parameters for DRX-K | 8 | * struct drxk_config - Configure the initial parameters for DRX-K |
9 | * | 9 | * |
10 | * adr: I2C Address of the DRX-K | 10 | * @adr: I2C Address of the DRX-K |
11 | * parallel_ts: true means that the device uses parallel TS, | 11 | * @parallel_ts: True means that the device uses parallel TS, |
12 | * Serial otherwise. | 12 | * Serial otherwise. |
13 | * single_master: Device is on the single master mode | 13 | * @dynamic_clk: True means that the clock will be dynamically |
14 | * no_i2c_bridge: Don't switch the I2C bridge to talk with tuner | 14 | * adjusted. Static clock otherwise. |
15 | * antenna_gpio: GPIO bit used to control the antenna | 15 | * @enable_merr_cfg: Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG. |
16 | * antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1 | 16 | * @single_master: Device is on the single master mode |
17 | * @no_i2c_bridge: Don't switch the I2C bridge to talk with tuner | ||
18 | * @antenna_gpio: GPIO bit used to control the antenna | ||
19 | * @antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1 | ||
17 | * means that 1=DVBC, 0 = DVBT. Zero means the opposite. | 20 | * means that 1=DVBC, 0 = DVBT. Zero means the opposite. |
18 | * microcode_name: Name of the firmware file with the microcode | 21 | * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength. |
22 | * @microcode_name: Name of the firmware file with the microcode | ||
19 | * | 23 | * |
20 | * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is | 24 | * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is |
21 | * UIO-3. | 25 | * UIO-3. |
@@ -25,11 +29,14 @@ struct drxk_config { | |||
25 | bool single_master; | 29 | bool single_master; |
26 | bool no_i2c_bridge; | 30 | bool no_i2c_bridge; |
27 | bool parallel_ts; | 31 | bool parallel_ts; |
32 | bool dynamic_clk; | ||
33 | bool enable_merr_cfg; | ||
28 | 34 | ||
29 | bool antenna_dvbt; | 35 | bool antenna_dvbt; |
30 | u16 antenna_gpio; | 36 | u16 antenna_gpio; |
31 | 37 | ||
32 | int chunk_size; | 38 | u8 mpeg_out_clk_strength; |
39 | int chunk_size; | ||
33 | 40 | ||
34 | const char *microcode_name; | 41 | const char *microcode_name; |
35 | }; | 42 | }; |
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index 5ab53795bd7a..36d11756492f 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c | |||
@@ -90,10 +90,6 @@ bool IsA1WithRomCode(struct drxk_state *state) | |||
90 | #define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03) | 90 | #define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03) |
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | #ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH | ||
94 | #define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06) | ||
95 | #endif | ||
96 | |||
97 | #define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700 | 93 | #define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700 |
98 | #define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500 | 94 | #define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500 |
99 | 95 | ||
@@ -649,9 +645,6 @@ static int init_state(struct drxk_state *state) | |||
649 | u32 ulQual83 = DEFAULT_MER_83; | 645 | u32 ulQual83 = DEFAULT_MER_83; |
650 | u32 ulQual93 = DEFAULT_MER_93; | 646 | u32 ulQual93 = DEFAULT_MER_93; |
651 | 647 | ||
652 | u32 ulDVBTStaticTSClock = 1; | ||
653 | u32 ulDVBCStaticTSClock = 1; | ||
654 | |||
655 | u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT; | 648 | u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT; |
656 | u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT; | 649 | u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT; |
657 | 650 | ||
@@ -661,7 +654,6 @@ static int init_state(struct drxk_state *state) | |||
661 | u32 ulGPIOCfg = 0x0113; | 654 | u32 ulGPIOCfg = 0x0113; |
662 | u32 ulInvertTSClock = 0; | 655 | u32 ulInvertTSClock = 0; |
663 | u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH; | 656 | u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH; |
664 | u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH; | ||
665 | u32 ulDVBTBitrate = 50000000; | 657 | u32 ulDVBTBitrate = 50000000; |
666 | u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8; | 658 | u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8; |
667 | 659 | ||
@@ -814,8 +806,7 @@ static int init_state(struct drxk_state *state) | |||
814 | state->m_invertSTR = false; /* If TRUE; invert STR signals */ | 806 | state->m_invertSTR = false; /* If TRUE; invert STR signals */ |
815 | state->m_invertVAL = false; /* If TRUE; invert VAL signals */ | 807 | state->m_invertVAL = false; /* If TRUE; invert VAL signals */ |
816 | state->m_invertCLK = (ulInvertTSClock != 0); /* If TRUE; invert CLK signals */ | 808 | state->m_invertCLK = (ulInvertTSClock != 0); /* If TRUE; invert CLK signals */ |
817 | state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0); | 809 | |
818 | state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0); | ||
819 | /* If TRUE; static MPEG clockrate will be used; | 810 | /* If TRUE; static MPEG clockrate will be used; |
820 | otherwise clockrate will adapt to the bitrate of the TS */ | 811 | otherwise clockrate will adapt to the bitrate of the TS */ |
821 | 812 | ||
@@ -823,7 +814,6 @@ static int init_state(struct drxk_state *state) | |||
823 | state->m_DVBCBitrate = ulDVBCBitrate; | 814 | state->m_DVBCBitrate = ulDVBCBitrate; |
824 | 815 | ||
825 | state->m_TSDataStrength = (ulTSDataStrength & 0x07); | 816 | state->m_TSDataStrength = (ulTSDataStrength & 0x07); |
826 | state->m_TSClockkStrength = (ulTSClockkStrength & 0x07); | ||
827 | 817 | ||
828 | /* Maximum bitrate in b/s in case static clockrate is selected */ | 818 | /* Maximum bitrate in b/s in case static clockrate is selected */ |
829 | state->m_mpegTsStaticBitrate = 19392658; | 819 | state->m_mpegTsStaticBitrate = 19392658; |
@@ -1188,6 +1178,7 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable) | |||
1188 | int status = -1; | 1178 | int status = -1; |
1189 | u16 sioPdrMclkCfg = 0; | 1179 | u16 sioPdrMclkCfg = 0; |
1190 | u16 sioPdrMdxCfg = 0; | 1180 | u16 sioPdrMdxCfg = 0; |
1181 | u16 err_cfg = 0; | ||
1191 | 1182 | ||
1192 | dprintk(1, ": mpeg %s, %s mode\n", | 1183 | dprintk(1, ": mpeg %s, %s mode\n", |
1193 | mpegEnable ? "enable" : "disable", | 1184 | mpegEnable ? "enable" : "disable", |
@@ -1253,12 +1244,17 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable) | |||
1253 | status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg); | 1244 | status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg); |
1254 | if (status < 0) | 1245 | if (status < 0) |
1255 | goto error; | 1246 | goto error; |
1256 | status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000); /* Disable */ | 1247 | |
1248 | if (state->enable_merr_cfg) | ||
1249 | err_cfg = sioPdrMdxCfg; | ||
1250 | |||
1251 | status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg); | ||
1257 | if (status < 0) | 1252 | if (status < 0) |
1258 | goto error; | 1253 | goto error; |
1259 | status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000); /* Disable */ | 1254 | status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg); |
1260 | if (status < 0) | 1255 | if (status < 0) |
1261 | goto error; | 1256 | goto error; |
1257 | |||
1262 | if (state->m_enableParallel == true) { | 1258 | if (state->m_enableParallel == true) { |
1263 | /* paralel -> enable MD1 to MD7 */ | 1259 | /* paralel -> enable MD1 to MD7 */ |
1264 | status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg); | 1260 | status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg); |
@@ -6069,9 +6065,7 @@ static int init_drxk(struct drxk_state *state) | |||
6069 | if (status < 0) | 6065 | if (status < 0) |
6070 | goto error; | 6066 | goto error; |
6071 | 6067 | ||
6072 | if (!state->microcode_name) | 6068 | if (state->microcode_name) |
6073 | load_microcode(state, "drxk_a3.mc"); | ||
6074 | else | ||
6075 | load_microcode(state, state->microcode_name); | 6069 | load_microcode(state, state->microcode_name); |
6076 | 6070 | ||
6077 | /* disable token-ring bus through OFDM block for possible ucode upload */ | 6071 | /* disable token-ring bus through OFDM block for possible ucode upload */ |
@@ -6322,15 +6316,12 @@ static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_t | |||
6322 | switch (p->delivery_system) { | 6316 | switch (p->delivery_system) { |
6323 | case SYS_DVBC_ANNEX_A: | 6317 | case SYS_DVBC_ANNEX_A: |
6324 | case SYS_DVBC_ANNEX_C: | 6318 | case SYS_DVBC_ANNEX_C: |
6319 | case SYS_DVBT: | ||
6325 | sets->min_delay_ms = 3000; | 6320 | sets->min_delay_ms = 3000; |
6326 | sets->max_drift = 0; | 6321 | sets->max_drift = 0; |
6327 | sets->step_size = 0; | 6322 | sets->step_size = 0; |
6328 | return 0; | 6323 | return 0; |
6329 | default: | 6324 | default: |
6330 | /* | ||
6331 | * For DVB-T, let it use the default DVB core way, that is: | ||
6332 | * fepriv->step_size = fe->ops.info.frequency_stepsize * 2 | ||
6333 | */ | ||
6334 | return -EINVAL; | 6325 | return -EINVAL; |
6335 | } | 6326 | } |
6336 | } | 6327 | } |
@@ -6390,6 +6381,21 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, | |||
6390 | state->antenna_gpio = config->antenna_gpio; | 6381 | state->antenna_gpio = config->antenna_gpio; |
6391 | state->antenna_dvbt = config->antenna_dvbt; | 6382 | state->antenna_dvbt = config->antenna_dvbt; |
6392 | state->m_ChunkSize = config->chunk_size; | 6383 | state->m_ChunkSize = config->chunk_size; |
6384 | state->enable_merr_cfg = config->enable_merr_cfg; | ||
6385 | |||
6386 | if (config->dynamic_clk) { | ||
6387 | state->m_DVBTStaticCLK = 0; | ||
6388 | state->m_DVBCStaticCLK = 0; | ||
6389 | } else { | ||
6390 | state->m_DVBTStaticCLK = 1; | ||
6391 | state->m_DVBCStaticCLK = 1; | ||
6392 | } | ||
6393 | |||
6394 | |||
6395 | if (config->mpeg_out_clk_strength) | ||
6396 | state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07; | ||
6397 | else | ||
6398 | state->m_TSClockkStrength = 0x06; | ||
6393 | 6399 | ||
6394 | if (config->parallel_ts) | 6400 | if (config->parallel_ts) |
6395 | state->m_enableParallel = true; | 6401 | state->m_enableParallel = true; |
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h index 3a58b73eb9b9..4bbf841de83a 100644 --- a/drivers/media/dvb/frontends/drxk_hard.h +++ b/drivers/media/dvb/frontends/drxk_hard.h | |||
@@ -332,6 +332,7 @@ struct drxk_state { | |||
332 | 332 | ||
333 | u16 UIO_mask; /* Bits used by UIO */ | 333 | u16 UIO_mask; /* Bits used by UIO */ |
334 | 334 | ||
335 | bool enable_merr_cfg; | ||
335 | bool single_master; | 336 | bool single_master; |
336 | bool no_i2c_bridge; | 337 | bool no_i2c_bridge; |
337 | bool antenna_dvbt; | 338 | bool antenna_dvbt; |
diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h index 93b086ea7e1c..eb6fd8aebdb3 100644 --- a/drivers/media/dvb/frontends/it913x-fe-priv.h +++ b/drivers/media/dvb/frontends/it913x-fe-priv.h | |||
@@ -201,6 +201,11 @@ fe_modulation_t fe_con[] = { | |||
201 | QAM_64, | 201 | QAM_64, |
202 | }; | 202 | }; |
203 | 203 | ||
204 | enum { | ||
205 | PRIORITY_HIGH = 0, /* High-priority stream */ | ||
206 | PRIORITY_LOW, /* Low-priority stream */ | ||
207 | }; | ||
208 | |||
204 | /* Standard demodulator functions */ | 209 | /* Standard demodulator functions */ |
205 | static struct it913xset set_solo_fe[] = { | 210 | static struct it913xset set_solo_fe[] = { |
206 | {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, | 211 | {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, |
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c index ccc36bf2deb4..84df03c29179 100644 --- a/drivers/media/dvb/frontends/it913x-fe.c +++ b/drivers/media/dvb/frontends/it913x-fe.c | |||
@@ -57,6 +57,7 @@ struct it913x_fe_state { | |||
57 | u32 frequency; | 57 | u32 frequency; |
58 | fe_modulation_t constellation; | 58 | fe_modulation_t constellation; |
59 | fe_transmit_mode_t transmission_mode; | 59 | fe_transmit_mode_t transmission_mode; |
60 | u8 priority; | ||
60 | u32 crystalFrequency; | 61 | u32 crystalFrequency; |
61 | u32 adcFrequency; | 62 | u32 adcFrequency; |
62 | u8 tuner_type; | 63 | u8 tuner_type; |
@@ -500,19 +501,87 @@ static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) | |||
500 | return 0; | 501 | return 0; |
501 | } | 502 | } |
502 | 503 | ||
504 | /* FEC values based on fe_code_rate_t non supported values 0*/ | ||
505 | int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88}; | ||
506 | int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82}; | ||
507 | int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76}; | ||
508 | |||
509 | static int it913x_get_signal_strength(struct dvb_frontend *fe) | ||
510 | { | ||
511 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
512 | struct it913x_fe_state *state = fe->demodulator_priv; | ||
513 | u8 code_rate; | ||
514 | int ret, temp; | ||
515 | u8 lna_gain_os; | ||
516 | |||
517 | ret = it913x_read_reg_u8(state, VAR_P_INBAND); | ||
518 | if (ret < 0) | ||
519 | return ret; | ||
520 | |||
521 | /* VHF/UHF gain offset */ | ||
522 | if (state->frequency < 300000000) | ||
523 | lna_gain_os = 7; | ||
524 | else | ||
525 | lna_gain_os = 14; | ||
526 | |||
527 | temp = (ret - 100) - lna_gain_os; | ||
528 | |||
529 | if (state->priority == PRIORITY_HIGH) | ||
530 | code_rate = p->code_rate_HP; | ||
531 | else | ||
532 | code_rate = p->code_rate_LP; | ||
533 | |||
534 | if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval)) | ||
535 | return -EINVAL; | ||
536 | |||
537 | deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp); | ||
538 | |||
539 | /* Apply FEC offset values*/ | ||
540 | switch (p->modulation) { | ||
541 | case QPSK: | ||
542 | temp -= it913x_qpsk_pval[code_rate]; | ||
543 | break; | ||
544 | case QAM_16: | ||
545 | temp -= it913x_16qam_pval[code_rate]; | ||
546 | break; | ||
547 | case QAM_64: | ||
548 | temp -= it913x_64qam_pval[code_rate]; | ||
549 | break; | ||
550 | default: | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | |||
554 | if (temp < -15) | ||
555 | ret = 0; | ||
556 | else if ((-15 <= temp) && (temp < 0)) | ||
557 | ret = (2 * (temp + 15)) / 3; | ||
558 | else if ((0 <= temp) && (temp < 20)) | ||
559 | ret = 4 * temp + 10; | ||
560 | else if ((20 <= temp) && (temp < 35)) | ||
561 | ret = (2 * (temp - 20)) / 3 + 90; | ||
562 | else if (temp >= 35) | ||
563 | ret = 100; | ||
564 | |||
565 | deb_info("Signal Strength :%d", ret); | ||
566 | |||
567 | return ret; | ||
568 | } | ||
569 | |||
503 | static int it913x_fe_read_signal_strength(struct dvb_frontend *fe, | 570 | static int it913x_fe_read_signal_strength(struct dvb_frontend *fe, |
504 | u16 *strength) | 571 | u16 *strength) |
505 | { | 572 | { |
506 | struct it913x_fe_state *state = fe->demodulator_priv; | 573 | struct it913x_fe_state *state = fe->demodulator_priv; |
507 | int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL); | 574 | int ret = 0; |
508 | /*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/ | 575 | if (state->config->read_slevel) { |
509 | if (state->it913x_status & FE_HAS_SIGNAL) | 576 | if (state->it913x_status & FE_HAS_SIGNAL) |
510 | ret = (ret * 0xff) / 0x64; | 577 | ret = it913x_read_reg_u8(state, SIGNAL_LEVEL); |
511 | else | 578 | } else |
512 | ret = 0x0; | 579 | ret = it913x_get_signal_strength(fe); |
513 | ret |= ret << 0x8; | 580 | |
514 | *strength = ret; | 581 | if (ret >= 0) |
515 | return 0; | 582 | *strength = (u16)((u32)ret * 0xffff / 0x64); |
583 | |||
584 | return (ret < 0) ? -ENODEV : 0; | ||
516 | } | 585 | } |
517 | 586 | ||
518 | static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) | 587 | static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) |
@@ -606,6 +675,8 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe) | |||
606 | if (reg[2] < 4) | 675 | if (reg[2] < 4) |
607 | p->hierarchy = fe_hi[reg[2]]; | 676 | p->hierarchy = fe_hi[reg[2]]; |
608 | 677 | ||
678 | state->priority = reg[5]; | ||
679 | |||
609 | p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; | 680 | p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; |
610 | p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; | 681 | p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; |
611 | 682 | ||
@@ -972,5 +1043,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = { | |||
972 | 1043 | ||
973 | MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); | 1044 | MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); |
974 | MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); | 1045 | MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); |
975 | MODULE_VERSION("1.13"); | 1046 | MODULE_VERSION("1.15"); |
976 | MODULE_LICENSE("GPL"); | 1047 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h index c4a908e354e0..07fa4594c12b 100644 --- a/drivers/media/dvb/frontends/it913x-fe.h +++ b/drivers/media/dvb/frontends/it913x-fe.h | |||
@@ -34,6 +34,8 @@ struct ite_config { | |||
34 | u8 tuner_id_1; | 34 | u8 tuner_id_1; |
35 | u8 dual_mode; | 35 | u8 dual_mode; |
36 | u8 adf; | 36 | u8 adf; |
37 | /* option to read SIGNAL_LEVEL */ | ||
38 | u8 read_slevel; | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ | 41 | #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ |
@@ -168,6 +170,8 @@ static inline struct dvb_frontend *it913x_fe_attach( | |||
168 | #define EST_SIGNAL_LEVEL 0x004a | 170 | #define EST_SIGNAL_LEVEL 0x004a |
169 | #define FREE_BAND 0x004b | 171 | #define FREE_BAND 0x004b |
170 | #define SUSPEND_FLAG 0x004c | 172 | #define SUSPEND_FLAG 0x004c |
173 | #define VAR_P_INBAND 0x00f7 | ||
174 | |||
171 | /* Build in tuner types */ | 175 | /* Build in tuner types */ |
172 | #define IT9137 0x38 | 176 | #define IT9137 0x38 |
173 | #define IT9135_38 0x38 | 177 | #define IT9135_38 0x38 |
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index c990d35a13dc..e046622df0e4 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c | |||
@@ -104,8 +104,8 @@ static int i2c_write_demod_bytes (struct lgdt330x_state* state, | |||
104 | * then reads the data returned for (len) bytes. | 104 | * then reads the data returned for (len) bytes. |
105 | */ | 105 | */ |
106 | 106 | ||
107 | static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, | 107 | static int i2c_read_demod_bytes(struct lgdt330x_state *state, |
108 | enum I2C_REG reg, u8* buf, int len) | 108 | enum I2C_REG reg, u8 *buf, int len) |
109 | { | 109 | { |
110 | u8 wr [] = { reg }; | 110 | u8 wr [] = { reg }; |
111 | struct i2c_msg msg [] = { | 111 | struct i2c_msg msg [] = { |
@@ -118,6 +118,8 @@ static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, | |||
118 | ret = i2c_transfer(state->i2c, msg, 2); | 118 | ret = i2c_transfer(state->i2c, msg, 2); |
119 | if (ret != 2) { | 119 | if (ret != 2) { |
120 | printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret); | 120 | printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret); |
121 | if (ret >= 0) | ||
122 | ret = -EIO; | ||
121 | } else { | 123 | } else { |
122 | ret = 0; | 124 | ret = 0; |
123 | } | 125 | } |
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c new file mode 100644 index 000000000000..045ee5a6f7ae --- /dev/null +++ b/drivers/media/dvb/frontends/m88rs2000.c | |||
@@ -0,0 +1,904 @@ | |||
1 | /* | ||
2 | Driver for M88RS2000 demodulator and tuner | ||
3 | |||
4 | Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) | ||
5 | Beta Driver | ||
6 | |||
7 | Include various calculation code from DS3000 driver. | ||
8 | Copyright (C) 2009 Konstantin Dimitrov. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | |||
24 | */ | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/types.h> | ||
32 | |||
33 | |||
34 | #include "dvb_frontend.h" | ||
35 | #include "m88rs2000.h" | ||
36 | |||
37 | struct m88rs2000_state { | ||
38 | struct i2c_adapter *i2c; | ||
39 | const struct m88rs2000_config *config; | ||
40 | struct dvb_frontend frontend; | ||
41 | u8 no_lock_count; | ||
42 | u32 tuner_frequency; | ||
43 | u32 symbol_rate; | ||
44 | fe_code_rate_t fec_inner; | ||
45 | u8 tuner_level; | ||
46 | int errmode; | ||
47 | }; | ||
48 | |||
49 | static int m88rs2000_debug; | ||
50 | |||
51 | module_param_named(debug, m88rs2000_debug, int, 0644); | ||
52 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); | ||
53 | |||
54 | #define dprintk(level, args...) do { \ | ||
55 | if (level & m88rs2000_debug) \ | ||
56 | printk(KERN_DEBUG "m88rs2000-fe: " args); \ | ||
57 | } while (0) | ||
58 | |||
59 | #define deb_info(args...) dprintk(0x01, args) | ||
60 | #define info(format, arg...) \ | ||
61 | printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg) | ||
62 | |||
63 | static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner, | ||
64 | u8 reg, u8 data) | ||
65 | { | ||
66 | int ret; | ||
67 | u8 addr = (tuner == 0) ? state->config->tuner_addr : | ||
68 | state->config->demod_addr; | ||
69 | u8 buf[] = { reg, data }; | ||
70 | struct i2c_msg msg = { | ||
71 | .addr = addr, | ||
72 | .flags = 0, | ||
73 | .buf = buf, | ||
74 | .len = 2 | ||
75 | }; | ||
76 | |||
77 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
78 | |||
79 | if (ret != 1) | ||
80 | deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, " | ||
81 | "ret == %i)\n", __func__, reg, data, ret); | ||
82 | |||
83 | return (ret != 1) ? -EREMOTEIO : 0; | ||
84 | } | ||
85 | |||
86 | static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data) | ||
87 | { | ||
88 | return m88rs2000_writereg(state, 1, reg, data); | ||
89 | } | ||
90 | |||
91 | static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data) | ||
92 | { | ||
93 | m88rs2000_demod_write(state, 0x81, 0x84); | ||
94 | udelay(10); | ||
95 | return m88rs2000_writereg(state, 0, reg, data); | ||
96 | |||
97 | } | ||
98 | |||
99 | static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len) | ||
100 | { | ||
101 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
102 | |||
103 | if (len != 2) | ||
104 | return -EINVAL; | ||
105 | |||
106 | return m88rs2000_writereg(state, 1, buf[0], buf[1]); | ||
107 | } | ||
108 | |||
109 | static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg) | ||
110 | { | ||
111 | int ret; | ||
112 | u8 b0[] = { reg }; | ||
113 | u8 b1[] = { 0 }; | ||
114 | u8 addr = (tuner == 0) ? state->config->tuner_addr : | ||
115 | state->config->demod_addr; | ||
116 | struct i2c_msg msg[] = { | ||
117 | { | ||
118 | .addr = addr, | ||
119 | .flags = 0, | ||
120 | .buf = b0, | ||
121 | .len = 1 | ||
122 | }, { | ||
123 | .addr = addr, | ||
124 | .flags = I2C_M_RD, | ||
125 | .buf = b1, | ||
126 | .len = 1 | ||
127 | } | ||
128 | }; | ||
129 | |||
130 | ret = i2c_transfer(state->i2c, msg, 2); | ||
131 | |||
132 | if (ret != 2) | ||
133 | deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n", | ||
134 | __func__, reg, ret); | ||
135 | |||
136 | return b1[0]; | ||
137 | } | ||
138 | |||
139 | static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg) | ||
140 | { | ||
141 | return m88rs2000_readreg(state, 1, reg); | ||
142 | } | ||
143 | |||
144 | static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg) | ||
145 | { | ||
146 | m88rs2000_demod_write(state, 0x81, 0x85); | ||
147 | udelay(10); | ||
148 | return m88rs2000_readreg(state, 0, reg); | ||
149 | } | ||
150 | |||
151 | static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate) | ||
152 | { | ||
153 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
154 | int ret; | ||
155 | u32 temp; | ||
156 | u8 b[3]; | ||
157 | |||
158 | if ((srate < 1000000) || (srate > 45000000)) | ||
159 | return -EINVAL; | ||
160 | |||
161 | temp = srate / 1000; | ||
162 | temp *= 11831; | ||
163 | temp /= 68; | ||
164 | temp -= 3; | ||
165 | |||
166 | b[0] = (u8) (temp >> 16) & 0xff; | ||
167 | b[1] = (u8) (temp >> 8) & 0xff; | ||
168 | b[2] = (u8) temp & 0xff; | ||
169 | ret = m88rs2000_demod_write(state, 0x93, b[2]); | ||
170 | ret |= m88rs2000_demod_write(state, 0x94, b[1]); | ||
171 | ret |= m88rs2000_demod_write(state, 0x95, b[0]); | ||
172 | |||
173 | deb_info("m88rs2000: m88rs2000_set_symbolrate\n"); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe, | ||
178 | struct dvb_diseqc_master_cmd *m) | ||
179 | { | ||
180 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
181 | |||
182 | int i; | ||
183 | u8 reg; | ||
184 | deb_info("%s\n", __func__); | ||
185 | m88rs2000_demod_write(state, 0x9a, 0x30); | ||
186 | reg = m88rs2000_demod_read(state, 0xb2); | ||
187 | reg &= 0x3f; | ||
188 | m88rs2000_demod_write(state, 0xb2, reg); | ||
189 | for (i = 0; i < m->msg_len; i++) | ||
190 | m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]); | ||
191 | |||
192 | reg = m88rs2000_demod_read(state, 0xb1); | ||
193 | reg &= 0x87; | ||
194 | reg |= ((m->msg_len - 1) << 3) | 0x07; | ||
195 | reg &= 0x7f; | ||
196 | m88rs2000_demod_write(state, 0xb1, reg); | ||
197 | |||
198 | for (i = 0; i < 15; i++) { | ||
199 | if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0) | ||
200 | break; | ||
201 | msleep(20); | ||
202 | } | ||
203 | |||
204 | reg = m88rs2000_demod_read(state, 0xb1); | ||
205 | if ((reg & 0x40) > 0x0) { | ||
206 | reg &= 0x7f; | ||
207 | reg |= 0x40; | ||
208 | m88rs2000_demod_write(state, 0xb1, reg); | ||
209 | } | ||
210 | |||
211 | reg = m88rs2000_demod_read(state, 0xb2); | ||
212 | reg &= 0x3f; | ||
213 | reg |= 0x80; | ||
214 | m88rs2000_demod_write(state, 0xb2, reg); | ||
215 | m88rs2000_demod_write(state, 0x9a, 0xb0); | ||
216 | |||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe, | ||
222 | fe_sec_mini_cmd_t burst) | ||
223 | { | ||
224 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
225 | u8 reg0, reg1; | ||
226 | deb_info("%s\n", __func__); | ||
227 | m88rs2000_demod_write(state, 0x9a, 0x30); | ||
228 | msleep(50); | ||
229 | reg0 = m88rs2000_demod_read(state, 0xb1); | ||
230 | reg1 = m88rs2000_demod_read(state, 0xb2); | ||
231 | /* TODO complete this section */ | ||
232 | m88rs2000_demod_write(state, 0xb2, reg1); | ||
233 | m88rs2000_demod_write(state, 0xb1, reg0); | ||
234 | m88rs2000_demod_write(state, 0x9a, 0xb0); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | ||
240 | { | ||
241 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
242 | u8 reg0, reg1; | ||
243 | m88rs2000_demod_write(state, 0x9a, 0x30); | ||
244 | reg0 = m88rs2000_demod_read(state, 0xb1); | ||
245 | reg1 = m88rs2000_demod_read(state, 0xb2); | ||
246 | |||
247 | reg1 &= 0x3f; | ||
248 | |||
249 | switch (tone) { | ||
250 | case SEC_TONE_ON: | ||
251 | reg0 |= 0x4; | ||
252 | reg0 &= 0xbc; | ||
253 | break; | ||
254 | case SEC_TONE_OFF: | ||
255 | reg1 |= 0x80; | ||
256 | break; | ||
257 | default: | ||
258 | break; | ||
259 | } | ||
260 | m88rs2000_demod_write(state, 0xb2, reg1); | ||
261 | m88rs2000_demod_write(state, 0xb1, reg0); | ||
262 | m88rs2000_demod_write(state, 0x9a, 0xb0); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | struct inittab { | ||
267 | u8 cmd; | ||
268 | u8 reg; | ||
269 | u8 val; | ||
270 | }; | ||
271 | |||
272 | struct inittab m88rs2000_setup[] = { | ||
273 | {DEMOD_WRITE, 0x9a, 0x30}, | ||
274 | {DEMOD_WRITE, 0x00, 0x01}, | ||
275 | {WRITE_DELAY, 0x19, 0x00}, | ||
276 | {DEMOD_WRITE, 0x00, 0x00}, | ||
277 | {DEMOD_WRITE, 0x9a, 0xb0}, | ||
278 | {DEMOD_WRITE, 0x81, 0xc1}, | ||
279 | {TUNER_WRITE, 0x42, 0x73}, | ||
280 | {TUNER_WRITE, 0x05, 0x07}, | ||
281 | {TUNER_WRITE, 0x20, 0x27}, | ||
282 | {TUNER_WRITE, 0x07, 0x02}, | ||
283 | {TUNER_WRITE, 0x11, 0xff}, | ||
284 | {TUNER_WRITE, 0x60, 0xf9}, | ||
285 | {TUNER_WRITE, 0x08, 0x01}, | ||
286 | {TUNER_WRITE, 0x00, 0x41}, | ||
287 | {DEMOD_WRITE, 0x81, 0x81}, | ||
288 | {DEMOD_WRITE, 0x86, 0xc6}, | ||
289 | {DEMOD_WRITE, 0x9a, 0x30}, | ||
290 | {DEMOD_WRITE, 0xf0, 0x22}, | ||
291 | {DEMOD_WRITE, 0xf1, 0xbf}, | ||
292 | {DEMOD_WRITE, 0xb0, 0x45}, | ||
293 | {DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/ | ||
294 | {DEMOD_WRITE, 0x9a, 0xb0}, | ||
295 | {0xff, 0xaa, 0xff} | ||
296 | }; | ||
297 | |||
298 | struct inittab m88rs2000_shutdown[] = { | ||
299 | {DEMOD_WRITE, 0x9a, 0x30}, | ||
300 | {DEMOD_WRITE, 0xb0, 0x00}, | ||
301 | {DEMOD_WRITE, 0xf1, 0x89}, | ||
302 | {DEMOD_WRITE, 0x00, 0x01}, | ||
303 | {DEMOD_WRITE, 0x9a, 0xb0}, | ||
304 | {TUNER_WRITE, 0x00, 0x40}, | ||
305 | {DEMOD_WRITE, 0x81, 0x81}, | ||
306 | {0xff, 0xaa, 0xff} | ||
307 | }; | ||
308 | |||
309 | struct inittab tuner_reset[] = { | ||
310 | {TUNER_WRITE, 0x42, 0x73}, | ||
311 | {TUNER_WRITE, 0x05, 0x07}, | ||
312 | {TUNER_WRITE, 0x20, 0x27}, | ||
313 | {TUNER_WRITE, 0x07, 0x02}, | ||
314 | {TUNER_WRITE, 0x11, 0xff}, | ||
315 | {TUNER_WRITE, 0x60, 0xf9}, | ||
316 | {TUNER_WRITE, 0x08, 0x01}, | ||
317 | {TUNER_WRITE, 0x00, 0x41}, | ||
318 | {0xff, 0xaa, 0xff} | ||
319 | }; | ||
320 | |||
321 | struct inittab fe_reset[] = { | ||
322 | {DEMOD_WRITE, 0x00, 0x01}, | ||
323 | {DEMOD_WRITE, 0xf1, 0xbf}, | ||
324 | {DEMOD_WRITE, 0x00, 0x01}, | ||
325 | {DEMOD_WRITE, 0x20, 0x81}, | ||
326 | {DEMOD_WRITE, 0x21, 0x80}, | ||
327 | {DEMOD_WRITE, 0x10, 0x33}, | ||
328 | {DEMOD_WRITE, 0x11, 0x44}, | ||
329 | {DEMOD_WRITE, 0x12, 0x07}, | ||
330 | {DEMOD_WRITE, 0x18, 0x20}, | ||
331 | {DEMOD_WRITE, 0x28, 0x04}, | ||
332 | {DEMOD_WRITE, 0x29, 0x8e}, | ||
333 | {DEMOD_WRITE, 0x3b, 0xff}, | ||
334 | {DEMOD_WRITE, 0x32, 0x10}, | ||
335 | {DEMOD_WRITE, 0x33, 0x02}, | ||
336 | {DEMOD_WRITE, 0x34, 0x30}, | ||
337 | {DEMOD_WRITE, 0x35, 0xff}, | ||
338 | {DEMOD_WRITE, 0x38, 0x50}, | ||
339 | {DEMOD_WRITE, 0x39, 0x68}, | ||
340 | {DEMOD_WRITE, 0x3c, 0x7f}, | ||
341 | {DEMOD_WRITE, 0x3d, 0x0f}, | ||
342 | {DEMOD_WRITE, 0x45, 0x20}, | ||
343 | {DEMOD_WRITE, 0x46, 0x24}, | ||
344 | {DEMOD_WRITE, 0x47, 0x7c}, | ||
345 | {DEMOD_WRITE, 0x48, 0x16}, | ||
346 | {DEMOD_WRITE, 0x49, 0x04}, | ||
347 | {DEMOD_WRITE, 0x4a, 0x01}, | ||
348 | {DEMOD_WRITE, 0x4b, 0x78}, | ||
349 | {DEMOD_WRITE, 0X4d, 0xd2}, | ||
350 | {DEMOD_WRITE, 0x4e, 0x6d}, | ||
351 | {DEMOD_WRITE, 0x50, 0x30}, | ||
352 | {DEMOD_WRITE, 0x51, 0x30}, | ||
353 | {DEMOD_WRITE, 0x54, 0x7b}, | ||
354 | {DEMOD_WRITE, 0x56, 0x09}, | ||
355 | {DEMOD_WRITE, 0x58, 0x59}, | ||
356 | {DEMOD_WRITE, 0x59, 0x37}, | ||
357 | {DEMOD_WRITE, 0x63, 0xfa}, | ||
358 | {0xff, 0xaa, 0xff} | ||
359 | }; | ||
360 | |||
361 | struct inittab fe_trigger[] = { | ||
362 | {DEMOD_WRITE, 0x97, 0x04}, | ||
363 | {DEMOD_WRITE, 0x99, 0x77}, | ||
364 | {DEMOD_WRITE, 0x9b, 0x64}, | ||
365 | {DEMOD_WRITE, 0x9e, 0x00}, | ||
366 | {DEMOD_WRITE, 0x9f, 0xf8}, | ||
367 | {DEMOD_WRITE, 0xa0, 0x20}, | ||
368 | {DEMOD_WRITE, 0xa1, 0xe0}, | ||
369 | {DEMOD_WRITE, 0xa3, 0x38}, | ||
370 | {DEMOD_WRITE, 0x98, 0xff}, | ||
371 | {DEMOD_WRITE, 0xc0, 0x0f}, | ||
372 | {DEMOD_WRITE, 0x89, 0x01}, | ||
373 | {DEMOD_WRITE, 0x00, 0x00}, | ||
374 | {WRITE_DELAY, 0x0a, 0x00}, | ||
375 | {DEMOD_WRITE, 0x00, 0x01}, | ||
376 | {DEMOD_WRITE, 0x00, 0x00}, | ||
377 | {DEMOD_WRITE, 0x9a, 0xb0}, | ||
378 | {0xff, 0xaa, 0xff} | ||
379 | }; | ||
380 | |||
381 | static int m88rs2000_tab_set(struct m88rs2000_state *state, | ||
382 | struct inittab *tab) | ||
383 | { | ||
384 | int ret = 0; | ||
385 | u8 i; | ||
386 | if (tab == NULL) | ||
387 | return -EINVAL; | ||
388 | |||
389 | for (i = 0; i < 255; i++) { | ||
390 | switch (tab[i].cmd) { | ||
391 | case 0x01: | ||
392 | ret = m88rs2000_demod_write(state, tab[i].reg, | ||
393 | tab[i].val); | ||
394 | break; | ||
395 | case 0x02: | ||
396 | ret = m88rs2000_tuner_write(state, tab[i].reg, | ||
397 | tab[i].val); | ||
398 | break; | ||
399 | case 0x10: | ||
400 | if (tab[i].reg > 0) | ||
401 | mdelay(tab[i].reg); | ||
402 | break; | ||
403 | case 0xff: | ||
404 | if (tab[i].reg == 0xaa && tab[i].val == 0xff) | ||
405 | return 0; | ||
406 | case 0x00: | ||
407 | break; | ||
408 | default: | ||
409 | return -EINVAL; | ||
410 | } | ||
411 | if (ret < 0) | ||
412 | return -ENODEV; | ||
413 | } | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) | ||
418 | { | ||
419 | deb_info("%s: %s\n", __func__, | ||
420 | volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : | ||
421 | volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static int m88rs2000_startup(struct m88rs2000_state *state) | ||
427 | { | ||
428 | int ret = 0; | ||
429 | u8 reg; | ||
430 | |||
431 | reg = m88rs2000_tuner_read(state, 0x00); | ||
432 | if ((reg & 0x40) == 0) | ||
433 | ret = -ENODEV; | ||
434 | |||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | static int m88rs2000_init(struct dvb_frontend *fe) | ||
439 | { | ||
440 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
441 | int ret; | ||
442 | |||
443 | deb_info("m88rs2000: init chip\n"); | ||
444 | /* Setup frontend from shutdown/cold */ | ||
445 | ret = m88rs2000_tab_set(state, m88rs2000_setup); | ||
446 | |||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | static int m88rs2000_sleep(struct dvb_frontend *fe) | ||
451 | { | ||
452 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
453 | int ret; | ||
454 | /* Shutdown the frondend */ | ||
455 | ret = m88rs2000_tab_set(state, m88rs2000_shutdown); | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
460 | { | ||
461 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
462 | u8 reg = m88rs2000_demod_read(state, 0x8c); | ||
463 | |||
464 | *status = 0; | ||
465 | |||
466 | if ((reg & 0x7) == 0x7) { | ||
467 | *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI | ||
468 | | FE_HAS_LOCK; | ||
469 | if (state->config->set_ts_params) | ||
470 | state->config->set_ts_params(fe, CALL_IS_READ); | ||
471 | } | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* Extact code for these unknown but lmedm04 driver uses interupt callbacks */ | ||
476 | |||
477 | static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
478 | { | ||
479 | deb_info("m88rs2000_read_ber %d\n", *ber); | ||
480 | *ber = 0; | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int m88rs2000_read_signal_strength(struct dvb_frontend *fe, | ||
485 | u16 *strength) | ||
486 | { | ||
487 | *strength = 0; | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
492 | { | ||
493 | deb_info("m88rs2000_read_snr %d\n", *snr); | ||
494 | *snr = 0; | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
499 | { | ||
500 | deb_info("m88rs2000_read_ber %d\n", *ucblocks); | ||
501 | *ucblocks = 0; | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset) | ||
506 | { | ||
507 | int ret; | ||
508 | ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset); | ||
509 | ret |= m88rs2000_tuner_write(state, 0x51, 0x1f); | ||
510 | ret |= m88rs2000_tuner_write(state, 0x50, offset); | ||
511 | ret |= m88rs2000_tuner_write(state, 0x50, 0x00); | ||
512 | msleep(20); | ||
513 | return ret; | ||
514 | } | ||
515 | |||
516 | static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe) | ||
517 | { | ||
518 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
519 | int reg; | ||
520 | reg = m88rs2000_tuner_read(state, 0x3d); | ||
521 | reg &= 0x7f; | ||
522 | if (reg < 0x16) | ||
523 | reg = 0xa1; | ||
524 | else if (reg == 0x16) | ||
525 | reg = 0x99; | ||
526 | else | ||
527 | reg = 0xf9; | ||
528 | |||
529 | m88rs2000_tuner_write(state, 0x60, reg); | ||
530 | reg = m88rs2000_tuner_gate_ctrl(state, 0x08); | ||
531 | |||
532 | if (fe->ops.i2c_gate_ctrl) | ||
533 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
534 | return reg; | ||
535 | } | ||
536 | |||
537 | static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset) | ||
538 | { | ||
539 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
540 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
541 | int ret; | ||
542 | u32 frequency = c->frequency; | ||
543 | s32 offset_khz; | ||
544 | s32 tmp; | ||
545 | u32 symbol_rate = (c->symbol_rate / 1000); | ||
546 | u32 f3db, gdiv28; | ||
547 | u16 value, ndiv, lpf_coeff; | ||
548 | u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf; | ||
549 | u8 lo = 0x01, div4 = 0x0; | ||
550 | |||
551 | /* Reset Tuner */ | ||
552 | ret = m88rs2000_tab_set(state, tuner_reset); | ||
553 | |||
554 | /* Calculate frequency divider */ | ||
555 | if (frequency < 1060000) { | ||
556 | lo |= 0x10; | ||
557 | div4 = 0x1; | ||
558 | ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ; | ||
559 | } else | ||
560 | ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ; | ||
561 | ndiv = ndiv + ndiv % 2; | ||
562 | ndiv = ndiv - 1024; | ||
563 | |||
564 | ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo); | ||
565 | |||
566 | /* Set frequency divider */ | ||
567 | ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf); | ||
568 | ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff); | ||
569 | |||
570 | ret |= m88rs2000_tuner_write(state, 0x03, 0x06); | ||
571 | ret |= m88rs2000_tuner_gate_ctrl(state, 0x10); | ||
572 | if (ret < 0) | ||
573 | return -ENODEV; | ||
574 | |||
575 | /* Tuner Frequency Range */ | ||
576 | ret = m88rs2000_tuner_write(state, 0x10, lo); | ||
577 | |||
578 | ret |= m88rs2000_tuner_gate_ctrl(state, 0x08); | ||
579 | |||
580 | /* Tuner RF */ | ||
581 | ret |= m88rs2000_set_tuner_rf(fe); | ||
582 | |||
583 | gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000; | ||
584 | ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff); | ||
585 | ret |= m88rs2000_tuner_gate_ctrl(state, 0x04); | ||
586 | if (ret < 0) | ||
587 | return -ENODEV; | ||
588 | |||
589 | value = m88rs2000_tuner_read(state, 0x26); | ||
590 | |||
591 | f3db = (symbol_rate * 135) / 200 + 2000; | ||
592 | f3db += FREQ_OFFSET_LOW_SYM_RATE; | ||
593 | if (f3db < 7000) | ||
594 | f3db = 7000; | ||
595 | if (f3db > 40000) | ||
596 | f3db = 40000; | ||
597 | |||
598 | gdiv28 = gdiv28 * 207 / (value * 2 + 151); | ||
599 | mlpf_max = gdiv28 * 135 / 100; | ||
600 | mlpf_min = gdiv28 * 78 / 100; | ||
601 | if (mlpf_max > 63) | ||
602 | mlpf_max = 63; | ||
603 | |||
604 | lpf_coeff = 2766; | ||
605 | |||
606 | nlpf = (f3db * gdiv28 * 2 / lpf_coeff / | ||
607 | (FE_CRYSTAL_KHZ / 1000) + 1) / 2; | ||
608 | if (nlpf > 23) | ||
609 | nlpf = 23; | ||
610 | if (nlpf < 1) | ||
611 | nlpf = 1; | ||
612 | |||
613 | lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000) | ||
614 | * lpf_coeff * 2 / f3db + 1) / 2; | ||
615 | |||
616 | if (lpf_mxdiv < mlpf_min) { | ||
617 | nlpf++; | ||
618 | lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000) | ||
619 | * lpf_coeff * 2 / f3db + 1) / 2; | ||
620 | } | ||
621 | |||
622 | if (lpf_mxdiv > mlpf_max) | ||
623 | lpf_mxdiv = mlpf_max; | ||
624 | |||
625 | ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv); | ||
626 | ret |= m88rs2000_tuner_write(state, 0x06, nlpf); | ||
627 | |||
628 | ret |= m88rs2000_tuner_gate_ctrl(state, 0x04); | ||
629 | |||
630 | ret |= m88rs2000_tuner_gate_ctrl(state, 0x01); | ||
631 | |||
632 | msleep(80); | ||
633 | /* calculate offset assuming 96000kHz*/ | ||
634 | offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ | ||
635 | / 14 / (div4 + 1) / 2; | ||
636 | |||
637 | offset_khz -= frequency; | ||
638 | |||
639 | tmp = offset_khz; | ||
640 | tmp *= 65536; | ||
641 | |||
642 | tmp = (2 * tmp + 96000) / (2 * 96000); | ||
643 | if (tmp < 0) | ||
644 | tmp += 65536; | ||
645 | |||
646 | *offset = tmp & 0xffff; | ||
647 | |||
648 | if (fe->ops.i2c_gate_ctrl) | ||
649 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
650 | |||
651 | return (ret < 0) ? -EINVAL : 0; | ||
652 | } | ||
653 | |||
654 | static int m88rs2000_set_fec(struct m88rs2000_state *state, | ||
655 | fe_code_rate_t fec) | ||
656 | { | ||
657 | int ret; | ||
658 | u16 fec_set; | ||
659 | switch (fec) { | ||
660 | /* This is not confirmed kept for reference */ | ||
661 | /* case FEC_1_2: | ||
662 | fec_set = 0x88; | ||
663 | break; | ||
664 | case FEC_2_3: | ||
665 | fec_set = 0x68; | ||
666 | break; | ||
667 | case FEC_3_4: | ||
668 | fec_set = 0x48; | ||
669 | break; | ||
670 | case FEC_5_6: | ||
671 | fec_set = 0x28; | ||
672 | break; | ||
673 | case FEC_7_8: | ||
674 | fec_set = 0x18; | ||
675 | break; */ | ||
676 | case FEC_AUTO: | ||
677 | default: | ||
678 | fec_set = 0x08; | ||
679 | } | ||
680 | ret = m88rs2000_demod_write(state, 0x76, fec_set); | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | |||
686 | static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state) | ||
687 | { | ||
688 | u8 reg; | ||
689 | m88rs2000_demod_write(state, 0x9a, 0x30); | ||
690 | reg = m88rs2000_demod_read(state, 0x76); | ||
691 | m88rs2000_demod_write(state, 0x9a, 0xb0); | ||
692 | |||
693 | switch (reg) { | ||
694 | case 0x88: | ||
695 | return FEC_1_2; | ||
696 | case 0x68: | ||
697 | return FEC_2_3; | ||
698 | case 0x48: | ||
699 | return FEC_3_4; | ||
700 | case 0x28: | ||
701 | return FEC_5_6; | ||
702 | case 0x18: | ||
703 | return FEC_7_8; | ||
704 | case 0x08: | ||
705 | default: | ||
706 | break; | ||
707 | } | ||
708 | |||
709 | return FEC_AUTO; | ||
710 | } | ||
711 | |||
712 | static int m88rs2000_set_frontend(struct dvb_frontend *fe) | ||
713 | { | ||
714 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
715 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
716 | fe_status_t status; | ||
717 | int i, ret; | ||
718 | u16 offset = 0; | ||
719 | u8 reg; | ||
720 | |||
721 | state->no_lock_count = 0; | ||
722 | |||
723 | if (c->delivery_system != SYS_DVBS) { | ||
724 | deb_info("%s: unsupported delivery " | ||
725 | "system selected (%d)\n", | ||
726 | __func__, c->delivery_system); | ||
727 | return -EOPNOTSUPP; | ||
728 | } | ||
729 | |||
730 | /* Set Tuner */ | ||
731 | ret = m88rs2000_set_tuner(fe, &offset); | ||
732 | if (ret < 0) | ||
733 | return -ENODEV; | ||
734 | |||
735 | ret = m88rs2000_demod_write(state, 0x9a, 0x30); | ||
736 | /* Unknown usually 0xc6 sometimes 0xc1 */ | ||
737 | reg = m88rs2000_demod_read(state, 0x86); | ||
738 | ret |= m88rs2000_demod_write(state, 0x86, reg); | ||
739 | /* Offset lower nibble always 0 */ | ||
740 | ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8)); | ||
741 | ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0); | ||
742 | |||
743 | |||
744 | /* Reset Demod */ | ||
745 | ret = m88rs2000_tab_set(state, fe_reset); | ||
746 | if (ret < 0) | ||
747 | return -ENODEV; | ||
748 | |||
749 | /* Unknown */ | ||
750 | reg = m88rs2000_demod_read(state, 0x70); | ||
751 | ret = m88rs2000_demod_write(state, 0x70, reg); | ||
752 | |||
753 | /* Set FEC */ | ||
754 | ret |= m88rs2000_set_fec(state, c->fec_inner); | ||
755 | ret |= m88rs2000_demod_write(state, 0x85, 0x1); | ||
756 | ret |= m88rs2000_demod_write(state, 0x8a, 0xbf); | ||
757 | ret |= m88rs2000_demod_write(state, 0x8d, 0x1e); | ||
758 | ret |= m88rs2000_demod_write(state, 0x90, 0xf1); | ||
759 | ret |= m88rs2000_demod_write(state, 0x91, 0x08); | ||
760 | |||
761 | if (ret < 0) | ||
762 | return -ENODEV; | ||
763 | |||
764 | /* Set Symbol Rate */ | ||
765 | ret = m88rs2000_set_symbolrate(fe, c->symbol_rate); | ||
766 | if (ret < 0) | ||
767 | return -ENODEV; | ||
768 | |||
769 | /* Set up Demod */ | ||
770 | ret = m88rs2000_tab_set(state, fe_trigger); | ||
771 | if (ret < 0) | ||
772 | return -ENODEV; | ||
773 | |||
774 | for (i = 0; i < 25; i++) { | ||
775 | u8 reg = m88rs2000_demod_read(state, 0x8c); | ||
776 | if ((reg & 0x7) == 0x7) { | ||
777 | status = FE_HAS_LOCK; | ||
778 | break; | ||
779 | } | ||
780 | state->no_lock_count++; | ||
781 | if (state->no_lock_count > 15) { | ||
782 | reg = m88rs2000_demod_read(state, 0x70); | ||
783 | reg ^= 0x4; | ||
784 | m88rs2000_demod_write(state, 0x70, reg); | ||
785 | state->no_lock_count = 0; | ||
786 | } | ||
787 | if (state->no_lock_count == 20) | ||
788 | m88rs2000_set_tuner_rf(fe); | ||
789 | msleep(20); | ||
790 | } | ||
791 | |||
792 | if (status & FE_HAS_LOCK) { | ||
793 | state->fec_inner = m88rs2000_get_fec(state); | ||
794 | /* Uknown suspect SNR level */ | ||
795 | reg = m88rs2000_demod_read(state, 0x65); | ||
796 | } | ||
797 | |||
798 | state->tuner_frequency = c->frequency; | ||
799 | state->symbol_rate = c->symbol_rate; | ||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static int m88rs2000_get_frontend(struct dvb_frontend *fe) | ||
804 | { | ||
805 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
806 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
807 | c->fec_inner = state->fec_inner; | ||
808 | c->frequency = state->tuner_frequency; | ||
809 | c->symbol_rate = state->symbol_rate; | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
814 | { | ||
815 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
816 | |||
817 | if (enable) | ||
818 | m88rs2000_demod_write(state, 0x81, 0x84); | ||
819 | else | ||
820 | m88rs2000_demod_write(state, 0x81, 0x81); | ||
821 | udelay(10); | ||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | static void m88rs2000_release(struct dvb_frontend *fe) | ||
826 | { | ||
827 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
828 | kfree(state); | ||
829 | } | ||
830 | |||
831 | static struct dvb_frontend_ops m88rs2000_ops = { | ||
832 | .delsys = { SYS_DVBS }, | ||
833 | .info = { | ||
834 | .name = "M88RS2000 DVB-S", | ||
835 | .frequency_min = 950000, | ||
836 | .frequency_max = 2150000, | ||
837 | .frequency_stepsize = 1000, /* kHz for QPSK frontends */ | ||
838 | .frequency_tolerance = 5000, | ||
839 | .symbol_rate_min = 1000000, | ||
840 | .symbol_rate_max = 45000000, | ||
841 | .symbol_rate_tolerance = 500, /* ppm */ | ||
842 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
843 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
844 | FE_CAN_QPSK | | ||
845 | FE_CAN_FEC_AUTO | ||
846 | }, | ||
847 | |||
848 | .release = m88rs2000_release, | ||
849 | .init = m88rs2000_init, | ||
850 | .sleep = m88rs2000_sleep, | ||
851 | .write = m88rs2000_write, | ||
852 | .i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl, | ||
853 | .read_status = m88rs2000_read_status, | ||
854 | .read_ber = m88rs2000_read_ber, | ||
855 | .read_signal_strength = m88rs2000_read_signal_strength, | ||
856 | .read_snr = m88rs2000_read_snr, | ||
857 | .read_ucblocks = m88rs2000_read_ucblocks, | ||
858 | .diseqc_send_master_cmd = m88rs2000_send_diseqc_msg, | ||
859 | .diseqc_send_burst = m88rs2000_send_diseqc_burst, | ||
860 | .set_tone = m88rs2000_set_tone, | ||
861 | .set_voltage = m88rs2000_set_voltage, | ||
862 | |||
863 | .set_frontend = m88rs2000_set_frontend, | ||
864 | .get_frontend = m88rs2000_get_frontend, | ||
865 | }; | ||
866 | |||
867 | struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config, | ||
868 | struct i2c_adapter *i2c) | ||
869 | { | ||
870 | struct m88rs2000_state *state = NULL; | ||
871 | |||
872 | /* allocate memory for the internal state */ | ||
873 | state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL); | ||
874 | if (state == NULL) | ||
875 | goto error; | ||
876 | |||
877 | /* setup the state */ | ||
878 | state->config = config; | ||
879 | state->i2c = i2c; | ||
880 | state->tuner_frequency = 0; | ||
881 | state->symbol_rate = 0; | ||
882 | state->fec_inner = 0; | ||
883 | |||
884 | if (m88rs2000_startup(state) < 0) | ||
885 | goto error; | ||
886 | |||
887 | /* create dvb_frontend */ | ||
888 | memcpy(&state->frontend.ops, &m88rs2000_ops, | ||
889 | sizeof(struct dvb_frontend_ops)); | ||
890 | state->frontend.demodulator_priv = state; | ||
891 | return &state->frontend; | ||
892 | |||
893 | error: | ||
894 | kfree(state); | ||
895 | |||
896 | return NULL; | ||
897 | } | ||
898 | EXPORT_SYMBOL(m88rs2000_attach); | ||
899 | |||
900 | MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver"); | ||
901 | MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); | ||
902 | MODULE_LICENSE("GPL"); | ||
903 | MODULE_VERSION("1.13"); | ||
904 | |||
diff --git a/drivers/media/dvb/frontends/m88rs2000.h b/drivers/media/dvb/frontends/m88rs2000.h new file mode 100644 index 000000000000..59acdb696873 --- /dev/null +++ b/drivers/media/dvb/frontends/m88rs2000.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | Driver for M88RS2000 demodulator | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | */ | ||
19 | |||
20 | #ifndef M88RS2000_H | ||
21 | #define M88RS2000_H | ||
22 | |||
23 | #include <linux/dvb/frontend.h> | ||
24 | #include "dvb_frontend.h" | ||
25 | |||
26 | struct m88rs2000_config { | ||
27 | /* Demodulator i2c address */ | ||
28 | u8 demod_addr; | ||
29 | /* Tuner address */ | ||
30 | u8 tuner_addr; | ||
31 | |||
32 | u8 *inittab; | ||
33 | |||
34 | /* minimum delay before retuning */ | ||
35 | int min_delay_ms; | ||
36 | |||
37 | int (*set_ts_params)(struct dvb_frontend *, int); | ||
38 | }; | ||
39 | |||
40 | enum { | ||
41 | CALL_IS_SET_FRONTEND = 0x0, | ||
42 | CALL_IS_READ, | ||
43 | }; | ||
44 | |||
45 | #if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \ | ||
46 | defined(MODULE)) | ||
47 | extern struct dvb_frontend *m88rs2000_attach( | ||
48 | const struct m88rs2000_config *config, struct i2c_adapter *i2c); | ||
49 | #else | ||
50 | static inline struct dvb_frontend *m88rs2000_attach( | ||
51 | const struct m88rs2000_config *config, struct i2c_adapter *i2c) | ||
52 | { | ||
53 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
54 | return NULL; | ||
55 | } | ||
56 | #endif /* CONFIG_DVB_M88RS2000 */ | ||
57 | |||
58 | #define FE_CRYSTAL_KHZ 27000 | ||
59 | #define FREQ_OFFSET_LOW_SYM_RATE 3000 | ||
60 | |||
61 | enum { | ||
62 | DEMOD_WRITE = 0x1, | ||
63 | TUNER_WRITE, | ||
64 | WRITE_DELAY = 0x10, | ||
65 | }; | ||
66 | #endif /* M88RS2000_H */ | ||
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c new file mode 100644 index 000000000000..45196c5b0736 --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2830.c | |||
@@ -0,0 +1,562 @@ | |||
1 | /* | ||
2 | * Realtek RTL2830 DVB-T demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | |||
22 | /* | ||
23 | * Driver implements own I2C-adapter for tuner I2C access. That's since chip | ||
24 | * have unusual I2C-gate control which closes gate automatically after each | ||
25 | * I2C transfer. Using own I2C adapter we can workaround that. | ||
26 | */ | ||
27 | |||
28 | #include "rtl2830_priv.h" | ||
29 | |||
30 | int rtl2830_debug; | ||
31 | module_param_named(debug, rtl2830_debug, int, 0644); | ||
32 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
33 | |||
34 | /* write multiple hardware registers */ | ||
35 | static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) | ||
36 | { | ||
37 | int ret; | ||
38 | u8 buf[1+len]; | ||
39 | struct i2c_msg msg[1] = { | ||
40 | { | ||
41 | .addr = priv->cfg.i2c_addr, | ||
42 | .flags = 0, | ||
43 | .len = 1+len, | ||
44 | .buf = buf, | ||
45 | } | ||
46 | }; | ||
47 | |||
48 | buf[0] = reg; | ||
49 | memcpy(&buf[1], val, len); | ||
50 | |||
51 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
52 | if (ret == 1) { | ||
53 | ret = 0; | ||
54 | } else { | ||
55 | warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); | ||
56 | ret = -EREMOTEIO; | ||
57 | } | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | /* read multiple hardware registers */ | ||
62 | static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) | ||
63 | { | ||
64 | int ret; | ||
65 | struct i2c_msg msg[2] = { | ||
66 | { | ||
67 | .addr = priv->cfg.i2c_addr, | ||
68 | .flags = 0, | ||
69 | .len = 1, | ||
70 | .buf = ®, | ||
71 | }, { | ||
72 | .addr = priv->cfg.i2c_addr, | ||
73 | .flags = I2C_M_RD, | ||
74 | .len = len, | ||
75 | .buf = val, | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
80 | if (ret == 2) { | ||
81 | ret = 0; | ||
82 | } else { | ||
83 | warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); | ||
84 | ret = -EREMOTEIO; | ||
85 | } | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | /* write multiple registers */ | ||
90 | static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) | ||
91 | { | ||
92 | int ret; | ||
93 | u8 reg2 = (reg >> 0) & 0xff; | ||
94 | u8 page = (reg >> 8) & 0xff; | ||
95 | |||
96 | /* switch bank if needed */ | ||
97 | if (page != priv->page) { | ||
98 | ret = rtl2830_wr(priv, 0x00, &page, 1); | ||
99 | if (ret) | ||
100 | return ret; | ||
101 | |||
102 | priv->page = page; | ||
103 | } | ||
104 | |||
105 | return rtl2830_wr(priv, reg2, val, len); | ||
106 | } | ||
107 | |||
108 | /* read multiple registers */ | ||
109 | static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) | ||
110 | { | ||
111 | int ret; | ||
112 | u8 reg2 = (reg >> 0) & 0xff; | ||
113 | u8 page = (reg >> 8) & 0xff; | ||
114 | |||
115 | /* switch bank if needed */ | ||
116 | if (page != priv->page) { | ||
117 | ret = rtl2830_wr(priv, 0x00, &page, 1); | ||
118 | if (ret) | ||
119 | return ret; | ||
120 | |||
121 | priv->page = page; | ||
122 | } | ||
123 | |||
124 | return rtl2830_rd(priv, reg2, val, len); | ||
125 | } | ||
126 | |||
127 | #if 0 /* currently not used */ | ||
128 | /* write single register */ | ||
129 | static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val) | ||
130 | { | ||
131 | return rtl2830_wr_regs(priv, reg, &val, 1); | ||
132 | } | ||
133 | #endif | ||
134 | |||
135 | /* read single register */ | ||
136 | static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val) | ||
137 | { | ||
138 | return rtl2830_rd_regs(priv, reg, val, 1); | ||
139 | } | ||
140 | |||
141 | /* write single register with mask */ | ||
142 | int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) | ||
143 | { | ||
144 | int ret; | ||
145 | u8 tmp; | ||
146 | |||
147 | /* no need for read if whole reg is written */ | ||
148 | if (mask != 0xff) { | ||
149 | ret = rtl2830_rd_regs(priv, reg, &tmp, 1); | ||
150 | if (ret) | ||
151 | return ret; | ||
152 | |||
153 | val &= mask; | ||
154 | tmp &= ~mask; | ||
155 | val |= tmp; | ||
156 | } | ||
157 | |||
158 | return rtl2830_wr_regs(priv, reg, &val, 1); | ||
159 | } | ||
160 | |||
161 | /* read single register with mask */ | ||
162 | int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) | ||
163 | { | ||
164 | int ret, i; | ||
165 | u8 tmp; | ||
166 | |||
167 | ret = rtl2830_rd_regs(priv, reg, &tmp, 1); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | |||
171 | tmp &= mask; | ||
172 | |||
173 | /* find position of the first bit */ | ||
174 | for (i = 0; i < 8; i++) { | ||
175 | if ((mask >> i) & 0x01) | ||
176 | break; | ||
177 | } | ||
178 | *val = tmp >> i; | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int rtl2830_init(struct dvb_frontend *fe) | ||
184 | { | ||
185 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
186 | int ret, i; | ||
187 | u64 num; | ||
188 | u8 buf[3], tmp; | ||
189 | u32 if_ctl; | ||
190 | struct rtl2830_reg_val_mask tab[] = { | ||
191 | { 0x00d, 0x01, 0x03 }, | ||
192 | { 0x00d, 0x10, 0x10 }, | ||
193 | { 0x104, 0x00, 0x1e }, | ||
194 | { 0x105, 0x80, 0x80 }, | ||
195 | { 0x110, 0x02, 0x03 }, | ||
196 | { 0x110, 0x08, 0x0c }, | ||
197 | { 0x17b, 0x00, 0x40 }, | ||
198 | { 0x17d, 0x05, 0x0f }, | ||
199 | { 0x17d, 0x50, 0xf0 }, | ||
200 | { 0x18c, 0x08, 0x0f }, | ||
201 | { 0x18d, 0x00, 0xc0 }, | ||
202 | { 0x188, 0x05, 0x0f }, | ||
203 | { 0x189, 0x00, 0xfc }, | ||
204 | { 0x2d5, 0x02, 0x02 }, | ||
205 | { 0x2f1, 0x02, 0x06 }, | ||
206 | { 0x2f1, 0x20, 0xf8 }, | ||
207 | { 0x16d, 0x00, 0x01 }, | ||
208 | { 0x1a6, 0x00, 0x80 }, | ||
209 | { 0x106, priv->cfg.vtop, 0x3f }, | ||
210 | { 0x107, priv->cfg.krf, 0x3f }, | ||
211 | { 0x112, 0x28, 0xff }, | ||
212 | { 0x103, priv->cfg.agc_targ_val, 0xff }, | ||
213 | { 0x00a, 0x02, 0x07 }, | ||
214 | { 0x140, 0x0c, 0x3c }, | ||
215 | { 0x140, 0x40, 0xc0 }, | ||
216 | { 0x15b, 0x05, 0x07 }, | ||
217 | { 0x15b, 0x28, 0x38 }, | ||
218 | { 0x15c, 0x05, 0x07 }, | ||
219 | { 0x15c, 0x28, 0x38 }, | ||
220 | { 0x115, priv->cfg.spec_inv, 0x01 }, | ||
221 | { 0x16f, 0x01, 0x07 }, | ||
222 | { 0x170, 0x18, 0x38 }, | ||
223 | { 0x172, 0x0f, 0x0f }, | ||
224 | { 0x173, 0x08, 0x38 }, | ||
225 | { 0x175, 0x01, 0x07 }, | ||
226 | { 0x176, 0x00, 0xc0 }, | ||
227 | }; | ||
228 | |||
229 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | ||
230 | ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val, | ||
231 | tab[i].mask); | ||
232 | if (ret) | ||
233 | goto err; | ||
234 | } | ||
235 | |||
236 | ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2); | ||
237 | if (ret) | ||
238 | goto err; | ||
239 | |||
240 | ret = rtl2830_wr_regs(priv, 0x195, | ||
241 | "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); | ||
242 | if (ret) | ||
243 | goto err; | ||
244 | |||
245 | num = priv->cfg.if_dvbt % priv->cfg.xtal; | ||
246 | num *= 0x400000; | ||
247 | num = div_u64(num, priv->cfg.xtal); | ||
248 | num = -num; | ||
249 | if_ctl = num & 0x3fffff; | ||
250 | dbg("%s: if_ctl=%08x", __func__, if_ctl); | ||
251 | |||
252 | ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */ | ||
253 | if (ret) | ||
254 | goto err; | ||
255 | |||
256 | buf[0] = tmp << 6; | ||
257 | buf[0] = (if_ctl >> 16) & 0x3f; | ||
258 | buf[1] = (if_ctl >> 8) & 0xff; | ||
259 | buf[2] = (if_ctl >> 0) & 0xff; | ||
260 | |||
261 | ret = rtl2830_wr_regs(priv, 0x119, buf, 3); | ||
262 | if (ret) | ||
263 | goto err; | ||
264 | |||
265 | /* TODO: spec init */ | ||
266 | |||
267 | /* soft reset */ | ||
268 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04); | ||
269 | if (ret) | ||
270 | goto err; | ||
271 | |||
272 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04); | ||
273 | if (ret) | ||
274 | goto err; | ||
275 | |||
276 | priv->sleeping = false; | ||
277 | |||
278 | return ret; | ||
279 | err: | ||
280 | dbg("%s: failed=%d", __func__, ret); | ||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static int rtl2830_sleep(struct dvb_frontend *fe) | ||
285 | { | ||
286 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
287 | priv->sleeping = true; | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | int rtl2830_get_tune_settings(struct dvb_frontend *fe, | ||
292 | struct dvb_frontend_tune_settings *s) | ||
293 | { | ||
294 | s->min_delay_ms = 500; | ||
295 | s->step_size = fe->ops.info.frequency_stepsize * 2; | ||
296 | s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int rtl2830_set_frontend(struct dvb_frontend *fe) | ||
302 | { | ||
303 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
304 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
305 | int ret, i; | ||
306 | static u8 bw_params1[3][34] = { | ||
307 | { | ||
308 | 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41, | ||
309 | 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a, | ||
310 | 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82, | ||
311 | 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */ | ||
312 | }, { | ||
313 | 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca, | ||
314 | 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca, | ||
315 | 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e, | ||
316 | 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */ | ||
317 | }, { | ||
318 | 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0, | ||
319 | 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a, | ||
320 | 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f, | ||
321 | 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */ | ||
322 | }, | ||
323 | }; | ||
324 | static u8 bw_params2[3][6] = { | ||
325 | {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */ | ||
326 | {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */ | ||
327 | {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */ | ||
328 | }; | ||
329 | |||
330 | |||
331 | dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__, | ||
332 | c->frequency, c->bandwidth_hz, c->inversion); | ||
333 | |||
334 | /* program tuner */ | ||
335 | if (fe->ops.tuner_ops.set_params) | ||
336 | fe->ops.tuner_ops.set_params(fe); | ||
337 | |||
338 | switch (c->bandwidth_hz) { | ||
339 | case 6000000: | ||
340 | i = 0; | ||
341 | break; | ||
342 | case 7000000: | ||
343 | i = 1; | ||
344 | break; | ||
345 | case 8000000: | ||
346 | i = 2; | ||
347 | break; | ||
348 | default: | ||
349 | dbg("invalid bandwidth"); | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | |||
353 | ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06); | ||
354 | if (ret) | ||
355 | goto err; | ||
356 | |||
357 | /* 1/2 split I2C write */ | ||
358 | ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17); | ||
359 | if (ret) | ||
360 | goto err; | ||
361 | |||
362 | /* 2/2 split I2C write */ | ||
363 | ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17); | ||
364 | if (ret) | ||
365 | goto err; | ||
366 | |||
367 | ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6); | ||
368 | if (ret) | ||
369 | goto err; | ||
370 | |||
371 | return ret; | ||
372 | err: | ||
373 | dbg("%s: failed=%d", __func__, ret); | ||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
378 | { | ||
379 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
380 | int ret; | ||
381 | u8 tmp; | ||
382 | *status = 0; | ||
383 | |||
384 | if (priv->sleeping) | ||
385 | return 0; | ||
386 | |||
387 | ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */ | ||
388 | if (ret) | ||
389 | goto err; | ||
390 | |||
391 | if (tmp == 11) { | ||
392 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
393 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
394 | } else if (tmp == 10) { | ||
395 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
396 | FE_HAS_VITERBI; | ||
397 | } | ||
398 | |||
399 | return ret; | ||
400 | err: | ||
401 | dbg("%s: failed=%d", __func__, ret); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
406 | { | ||
407 | *snr = 0; | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
412 | { | ||
413 | *ber = 0; | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
418 | { | ||
419 | *ucblocks = 0; | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
424 | { | ||
425 | *strength = 0; | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static struct dvb_frontend_ops rtl2830_ops; | ||
430 | |||
431 | static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter) | ||
432 | { | ||
433 | return I2C_FUNC_I2C; | ||
434 | } | ||
435 | |||
436 | static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, | ||
437 | struct i2c_msg msg[], int num) | ||
438 | { | ||
439 | struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap); | ||
440 | int ret; | ||
441 | |||
442 | /* open i2c-gate */ | ||
443 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08); | ||
444 | if (ret) | ||
445 | goto err; | ||
446 | |||
447 | ret = i2c_transfer(priv->i2c, msg, num); | ||
448 | if (ret < 0) | ||
449 | warn("tuner i2c failed=%d", ret); | ||
450 | |||
451 | return ret; | ||
452 | err: | ||
453 | dbg("%s: failed=%d", __func__, ret); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | static struct i2c_algorithm rtl2830_tuner_i2c_algo = { | ||
458 | .master_xfer = rtl2830_tuner_i2c_xfer, | ||
459 | .functionality = rtl2830_tuner_i2c_func, | ||
460 | }; | ||
461 | |||
462 | struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe) | ||
463 | { | ||
464 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
465 | return &priv->tuner_i2c_adapter; | ||
466 | } | ||
467 | EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter); | ||
468 | |||
469 | static void rtl2830_release(struct dvb_frontend *fe) | ||
470 | { | ||
471 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
472 | |||
473 | i2c_del_adapter(&priv->tuner_i2c_adapter); | ||
474 | kfree(priv); | ||
475 | } | ||
476 | |||
477 | struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg, | ||
478 | struct i2c_adapter *i2c) | ||
479 | { | ||
480 | struct rtl2830_priv *priv = NULL; | ||
481 | int ret = 0; | ||
482 | u8 tmp; | ||
483 | |||
484 | /* allocate memory for the internal state */ | ||
485 | priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL); | ||
486 | if (priv == NULL) | ||
487 | goto err; | ||
488 | |||
489 | /* setup the priv */ | ||
490 | priv->i2c = i2c; | ||
491 | memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config)); | ||
492 | |||
493 | /* check if the demod is there */ | ||
494 | ret = rtl2830_rd_reg(priv, 0x000, &tmp); | ||
495 | if (ret) | ||
496 | goto err; | ||
497 | |||
498 | /* create dvb_frontend */ | ||
499 | memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops)); | ||
500 | priv->fe.demodulator_priv = priv; | ||
501 | |||
502 | /* create tuner i2c adapter */ | ||
503 | strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter", | ||
504 | sizeof(priv->tuner_i2c_adapter.name)); | ||
505 | priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo; | ||
506 | priv->tuner_i2c_adapter.algo_data = NULL; | ||
507 | i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); | ||
508 | if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { | ||
509 | err("tuner I2C bus could not be initialized"); | ||
510 | goto err; | ||
511 | } | ||
512 | |||
513 | priv->sleeping = true; | ||
514 | |||
515 | return &priv->fe; | ||
516 | err: | ||
517 | dbg("%s: failed=%d", __func__, ret); | ||
518 | kfree(priv); | ||
519 | return NULL; | ||
520 | } | ||
521 | EXPORT_SYMBOL(rtl2830_attach); | ||
522 | |||
523 | static struct dvb_frontend_ops rtl2830_ops = { | ||
524 | .delsys = { SYS_DVBT }, | ||
525 | .info = { | ||
526 | .name = "Realtek RTL2830 (DVB-T)", | ||
527 | .caps = FE_CAN_FEC_1_2 | | ||
528 | FE_CAN_FEC_2_3 | | ||
529 | FE_CAN_FEC_3_4 | | ||
530 | FE_CAN_FEC_5_6 | | ||
531 | FE_CAN_FEC_7_8 | | ||
532 | FE_CAN_FEC_AUTO | | ||
533 | FE_CAN_QPSK | | ||
534 | FE_CAN_QAM_16 | | ||
535 | FE_CAN_QAM_64 | | ||
536 | FE_CAN_QAM_AUTO | | ||
537 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
538 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
539 | FE_CAN_HIERARCHY_AUTO | | ||
540 | FE_CAN_RECOVER | | ||
541 | FE_CAN_MUTE_TS | ||
542 | }, | ||
543 | |||
544 | .release = rtl2830_release, | ||
545 | |||
546 | .init = rtl2830_init, | ||
547 | .sleep = rtl2830_sleep, | ||
548 | |||
549 | .get_tune_settings = rtl2830_get_tune_settings, | ||
550 | |||
551 | .set_frontend = rtl2830_set_frontend, | ||
552 | |||
553 | .read_status = rtl2830_read_status, | ||
554 | .read_snr = rtl2830_read_snr, | ||
555 | .read_ber = rtl2830_read_ber, | ||
556 | .read_ucblocks = rtl2830_read_ucblocks, | ||
557 | .read_signal_strength = rtl2830_read_signal_strength, | ||
558 | }; | ||
559 | |||
560 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
561 | MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); | ||
562 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/rtl2830.h b/drivers/media/dvb/frontends/rtl2830.h new file mode 100644 index 000000000000..1c6ee91749c2 --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2830.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Realtek RTL2830 DVB-T demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef RTL2830_H | ||
22 | #define RTL2830_H | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | |||
26 | struct rtl2830_config { | ||
27 | /* | ||
28 | * Demodulator I2C address. | ||
29 | */ | ||
30 | u8 i2c_addr; | ||
31 | |||
32 | /* | ||
33 | * Xtal frequency. | ||
34 | * Hz | ||
35 | * 4000000, 16000000, 25000000, 28800000 | ||
36 | */ | ||
37 | u32 xtal; | ||
38 | |||
39 | /* | ||
40 | * TS output mode. | ||
41 | */ | ||
42 | u8 ts_mode; | ||
43 | |||
44 | /* | ||
45 | * Spectrum inversion. | ||
46 | */ | ||
47 | bool spec_inv; | ||
48 | |||
49 | /* | ||
50 | * IFs for all used modes. | ||
51 | * Hz | ||
52 | * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000 | ||
53 | */ | ||
54 | u32 if_dvbt; | ||
55 | |||
56 | /* | ||
57 | */ | ||
58 | u8 vtop; | ||
59 | |||
60 | /* | ||
61 | */ | ||
62 | u8 krf; | ||
63 | |||
64 | /* | ||
65 | */ | ||
66 | u8 agc_targ_val; | ||
67 | }; | ||
68 | |||
69 | #if defined(CONFIG_DVB_RTL2830) || \ | ||
70 | (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE)) | ||
71 | extern struct dvb_frontend *rtl2830_attach( | ||
72 | const struct rtl2830_config *config, | ||
73 | struct i2c_adapter *i2c | ||
74 | ); | ||
75 | |||
76 | extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( | ||
77 | struct dvb_frontend *fe | ||
78 | ); | ||
79 | #else | ||
80 | static inline struct dvb_frontend *rtl2830_attach( | ||
81 | const struct rtl2830_config *config, | ||
82 | struct i2c_adapter *i2c | ||
83 | ) | ||
84 | { | ||
85 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
89 | static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( | ||
90 | struct dvb_frontend *fe | ||
91 | ) | ||
92 | { | ||
93 | return NULL; | ||
94 | } | ||
95 | #endif | ||
96 | |||
97 | #endif /* RTL2830_H */ | ||
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h new file mode 100644 index 000000000000..4a464761b5b8 --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2830_priv.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Realtek RTL2830 DVB-T demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef RTL2830_PRIV_H | ||
22 | #define RTL2830_PRIV_H | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | #include "rtl2830.h" | ||
26 | |||
27 | #define LOG_PREFIX "rtl2830" | ||
28 | |||
29 | #undef dbg | ||
30 | #define dbg(f, arg...) \ | ||
31 | if (rtl2830_debug) \ | ||
32 | printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
33 | #undef err | ||
34 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
35 | #undef info | ||
36 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
37 | #undef warn | ||
38 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
39 | |||
40 | struct rtl2830_priv { | ||
41 | struct i2c_adapter *i2c; | ||
42 | struct dvb_frontend fe; | ||
43 | struct rtl2830_config cfg; | ||
44 | struct i2c_adapter tuner_i2c_adapter; | ||
45 | |||
46 | bool sleeping; | ||
47 | |||
48 | u8 page; /* active register page */ | ||
49 | }; | ||
50 | |||
51 | struct rtl2830_reg_val_mask { | ||
52 | u16 reg; | ||
53 | u8 val; | ||
54 | u8 mask; | ||
55 | }; | ||
56 | |||
57 | #endif /* RTL2830_PRIV_H */ | ||
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index 38565beafe23..dd08f4ac64a8 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c | |||
@@ -67,7 +67,7 @@ static const struct stb0899_tab stb0899_cn_tab[] = { | |||
67 | * Crude linear extrapolation below -84.8dBm and above -8.0dBm. | 67 | * Crude linear extrapolation below -84.8dBm and above -8.0dBm. |
68 | */ | 68 | */ |
69 | static const struct stb0899_tab stb0899_dvbsrf_tab[] = { | 69 | static const struct stb0899_tab stb0899_dvbsrf_tab[] = { |
70 | { -950, -128 }, | 70 | { -750, -128 }, |
71 | { -748, -94 }, | 71 | { -748, -94 }, |
72 | { -745, -92 }, | 72 | { -745, -92 }, |
73 | { -735, -90 }, | 73 | { -735, -90 }, |
@@ -131,7 +131,7 @@ static const struct stb0899_tab stb0899_dvbs2rf_tab[] = { | |||
131 | { -730, 13645 }, | 131 | { -730, 13645 }, |
132 | { -750, 13909 }, | 132 | { -750, 13909 }, |
133 | { -766, 14153 }, | 133 | { -766, 14153 }, |
134 | { -999, 16383 } | 134 | { -950, 16383 } |
135 | }; | 135 | }; |
136 | 136 | ||
137 | /* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ | 137 | /* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ |
@@ -964,6 +964,7 @@ static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | |||
964 | 964 | ||
965 | int val; | 965 | int val; |
966 | u32 reg; | 966 | u32 reg; |
967 | *strength = 0; | ||
967 | switch (state->delsys) { | 968 | switch (state->delsys) { |
968 | case SYS_DVBS: | 969 | case SYS_DVBS: |
969 | case SYS_DSS: | 970 | case SYS_DSS: |
@@ -983,11 +984,11 @@ static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | |||
983 | break; | 984 | break; |
984 | case SYS_DVBS2: | 985 | case SYS_DVBS2: |
985 | if (internal->lock) { | 986 | if (internal->lock) { |
986 | reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN); | 987 | reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN); |
987 | val = STB0899_GETFIELD(IF_AGC_GAIN, reg); | 988 | val = STB0899_GETFIELD(IF_AGC_GAIN, reg); |
988 | 989 | ||
989 | *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); | 990 | *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); |
990 | *strength += 750; | 991 | *strength += 950; |
991 | dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", | 992 | dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", |
992 | val & 0x3fff, *strength); | 993 | val & 0x3fff, *strength); |
993 | } | 994 | } |
@@ -1009,6 +1010,7 @@ static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr) | |||
1009 | u8 buf[2]; | 1010 | u8 buf[2]; |
1010 | u32 reg; | 1011 | u32 reg; |
1011 | 1012 | ||
1013 | *snr = 0; | ||
1012 | reg = stb0899_read_reg(state, STB0899_VSTATUS); | 1014 | reg = stb0899_read_reg(state, STB0899_VSTATUS); |
1013 | switch (state->delsys) { | 1015 | switch (state->delsys) { |
1014 | case SYS_DVBS: | 1016 | case SYS_DVBS: |
@@ -1071,7 +1073,7 @@ static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status) | |||
1071 | reg = stb0899_read_reg(state, STB0899_VSTATUS); | 1073 | reg = stb0899_read_reg(state, STB0899_VSTATUS); |
1072 | if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { | 1074 | if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { |
1073 | dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); | 1075 | dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); |
1074 | *status |= FE_HAS_CARRIER | FE_HAS_LOCK; | 1076 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; |
1075 | 1077 | ||
1076 | reg = stb0899_read_reg(state, STB0899_PLPARM); | 1078 | reg = stb0899_read_reg(state, STB0899_PLPARM); |
1077 | if (STB0899_GETFIELD(VITCURPUN, reg)) { | 1079 | if (STB0899_GETFIELD(VITCURPUN, reg)) { |
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c index fb5548a82208..632b25156e4c 100644 --- a/drivers/media/dvb/frontends/stv0288.c +++ b/drivers/media/dvb/frontends/stv0288.c | |||
@@ -506,7 +506,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe) | |||
506 | tda[1] = (unsigned char)tm; | 506 | tda[1] = (unsigned char)tm; |
507 | stv0288_writeregI(state, 0x2b, tda[1]); | 507 | stv0288_writeregI(state, 0x2b, tda[1]); |
508 | stv0288_writeregI(state, 0x2c, tda[2]); | 508 | stv0288_writeregI(state, 0x2c, tda[2]); |
509 | udelay(30); | 509 | msleep(30); |
510 | } | 510 | } |
511 | state->tuner_frequency = c->frequency; | 511 | state->tuner_frequency = c->frequency; |
512 | state->fec_inner = FEC_AUTO; | 512 | state->fec_inner = FEC_AUTO; |
diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c index a99205026751..c21bc92d2811 100644 --- a/drivers/media/dvb/frontends/tda10071.c +++ b/drivers/media/dvb/frontends/tda10071.c | |||
@@ -1215,7 +1215,7 @@ error: | |||
1215 | EXPORT_SYMBOL(tda10071_attach); | 1215 | EXPORT_SYMBOL(tda10071_attach); |
1216 | 1216 | ||
1217 | static struct dvb_frontend_ops tda10071_ops = { | 1217 | static struct dvb_frontend_ops tda10071_ops = { |
1218 | .delsys = { SYS_DVBT, SYS_DVBT2 }, | 1218 | .delsys = { SYS_DVBS, SYS_DVBS2 }, |
1219 | .info = { | 1219 | .info = { |
1220 | .name = "NXP TDA10071", | 1220 | .name = "NXP TDA10071", |
1221 | .frequency_min = 950000, | 1221 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 8418c02bcefe..7539a5d71029 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c | |||
@@ -216,6 +216,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, | |||
216 | struct drxk_config config; | 216 | struct drxk_config config; |
217 | 217 | ||
218 | memset(&config, 0, sizeof(config)); | 218 | memset(&config, 0, sizeof(config)); |
219 | config.microcode_name = "drxk_a3.mc"; | ||
219 | config.adr = 0x29 + (chan->number ^ 2); | 220 | config.adr = 0x29 + (chan->number ^ 2); |
220 | 221 | ||
221 | chan->fe = dvb_attach(drxk_attach, &config, i2c); | 222 | chan->fe = dvb_attach(drxk_attach, &config, i2c); |
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c index b81df5fafe26..15b35c4725f1 100644 --- a/drivers/media/dvb/pt1/pt1.c +++ b/drivers/media/dvb/pt1/pt1.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/kthread.h> | 29 | #include <linux/kthread.h> |
30 | #include <linux/freezer.h> | 30 | #include <linux/freezer.h> |
31 | #include <linux/ratelimit.h> | ||
31 | 32 | ||
32 | #include "dvbdev.h" | 33 | #include "dvbdev.h" |
33 | #include "dvb_demux.h" | 34 | #include "dvb_demux.h" |
@@ -77,6 +78,8 @@ struct pt1 { | |||
77 | struct pt1_adapter *adaps[PT1_NR_ADAPS]; | 78 | struct pt1_adapter *adaps[PT1_NR_ADAPS]; |
78 | struct pt1_table *tables; | 79 | struct pt1_table *tables; |
79 | struct task_struct *kthread; | 80 | struct task_struct *kthread; |
81 | int table_index; | ||
82 | int buf_index; | ||
80 | 83 | ||
81 | struct mutex lock; | 84 | struct mutex lock; |
82 | int power; | 85 | int power; |
@@ -90,12 +93,12 @@ struct pt1_adapter { | |||
90 | u8 *buf; | 93 | u8 *buf; |
91 | int upacket_count; | 94 | int upacket_count; |
92 | int packet_count; | 95 | int packet_count; |
96 | int st_count; | ||
93 | 97 | ||
94 | struct dvb_adapter adap; | 98 | struct dvb_adapter adap; |
95 | struct dvb_demux demux; | 99 | struct dvb_demux demux; |
96 | int users; | 100 | int users; |
97 | struct dmxdev dmxdev; | 101 | struct dmxdev dmxdev; |
98 | struct dvb_net net; | ||
99 | struct dvb_frontend *fe; | 102 | struct dvb_frontend *fe; |
100 | int (*orig_set_voltage)(struct dvb_frontend *fe, | 103 | int (*orig_set_voltage)(struct dvb_frontend *fe, |
101 | fe_sec_voltage_t voltage); | 104 | fe_sec_voltage_t voltage); |
@@ -119,7 +122,7 @@ static u32 pt1_read_reg(struct pt1 *pt1, int reg) | |||
119 | return readl(pt1->regs + reg * 4); | 122 | return readl(pt1->regs + reg * 4); |
120 | } | 123 | } |
121 | 124 | ||
122 | static int pt1_nr_tables = 64; | 125 | static int pt1_nr_tables = 8; |
123 | module_param_named(nr_tables, pt1_nr_tables, int, 0); | 126 | module_param_named(nr_tables, pt1_nr_tables, int, 0); |
124 | 127 | ||
125 | static void pt1_increment_table_count(struct pt1 *pt1) | 128 | static void pt1_increment_table_count(struct pt1 *pt1) |
@@ -264,6 +267,7 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) | |||
264 | struct pt1_adapter *adap; | 267 | struct pt1_adapter *adap; |
265 | int offset; | 268 | int offset; |
266 | u8 *buf; | 269 | u8 *buf; |
270 | int sc; | ||
267 | 271 | ||
268 | if (!page->upackets[PT1_NR_UPACKETS - 1]) | 272 | if (!page->upackets[PT1_NR_UPACKETS - 1]) |
269 | return 0; | 273 | return 0; |
@@ -280,6 +284,16 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) | |||
280 | else if (!adap->upacket_count) | 284 | else if (!adap->upacket_count) |
281 | continue; | 285 | continue; |
282 | 286 | ||
287 | if (upacket >> 24 & 1) | ||
288 | printk_ratelimited(KERN_INFO "earth-pt1: device " | ||
289 | "buffer overflowing. table[%d] buf[%d]\n", | ||
290 | pt1->table_index, pt1->buf_index); | ||
291 | sc = upacket >> 26 & 0x7; | ||
292 | if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) | ||
293 | printk_ratelimited(KERN_INFO "earth-pt1: data loss" | ||
294 | " in streamID(adapter)[%d]\n", index); | ||
295 | adap->st_count = sc; | ||
296 | |||
283 | buf = adap->buf; | 297 | buf = adap->buf; |
284 | offset = adap->packet_count * 188 + adap->upacket_count * 3; | 298 | offset = adap->packet_count * 188 + adap->upacket_count * 3; |
285 | buf[offset] = upacket >> 16; | 299 | buf[offset] = upacket >> 16; |
@@ -303,30 +317,25 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) | |||
303 | static int pt1_thread(void *data) | 317 | static int pt1_thread(void *data) |
304 | { | 318 | { |
305 | struct pt1 *pt1; | 319 | struct pt1 *pt1; |
306 | int table_index; | ||
307 | int buf_index; | ||
308 | struct pt1_buffer_page *page; | 320 | struct pt1_buffer_page *page; |
309 | 321 | ||
310 | pt1 = data; | 322 | pt1 = data; |
311 | set_freezable(); | 323 | set_freezable(); |
312 | 324 | ||
313 | table_index = 0; | ||
314 | buf_index = 0; | ||
315 | |||
316 | while (!kthread_should_stop()) { | 325 | while (!kthread_should_stop()) { |
317 | try_to_freeze(); | 326 | try_to_freeze(); |
318 | 327 | ||
319 | page = pt1->tables[table_index].bufs[buf_index].page; | 328 | page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; |
320 | if (!pt1_filter(pt1, page)) { | 329 | if (!pt1_filter(pt1, page)) { |
321 | schedule_timeout_interruptible((HZ + 999) / 1000); | 330 | schedule_timeout_interruptible((HZ + 999) / 1000); |
322 | continue; | 331 | continue; |
323 | } | 332 | } |
324 | 333 | ||
325 | if (++buf_index >= PT1_NR_BUFS) { | 334 | if (++pt1->buf_index >= PT1_NR_BUFS) { |
326 | pt1_increment_table_count(pt1); | 335 | pt1_increment_table_count(pt1); |
327 | buf_index = 0; | 336 | pt1->buf_index = 0; |
328 | if (++table_index >= pt1_nr_tables) | 337 | if (++pt1->table_index >= pt1_nr_tables) |
329 | table_index = 0; | 338 | pt1->table_index = 0; |
330 | } | 339 | } |
331 | } | 340 | } |
332 | 341 | ||
@@ -477,21 +486,60 @@ err: | |||
477 | return ret; | 486 | return ret; |
478 | } | 487 | } |
479 | 488 | ||
489 | static int pt1_start_polling(struct pt1 *pt1) | ||
490 | { | ||
491 | int ret = 0; | ||
492 | |||
493 | mutex_lock(&pt1->lock); | ||
494 | if (!pt1->kthread) { | ||
495 | pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1"); | ||
496 | if (IS_ERR(pt1->kthread)) { | ||
497 | ret = PTR_ERR(pt1->kthread); | ||
498 | pt1->kthread = NULL; | ||
499 | } | ||
500 | } | ||
501 | mutex_unlock(&pt1->lock); | ||
502 | return ret; | ||
503 | } | ||
504 | |||
480 | static int pt1_start_feed(struct dvb_demux_feed *feed) | 505 | static int pt1_start_feed(struct dvb_demux_feed *feed) |
481 | { | 506 | { |
482 | struct pt1_adapter *adap; | 507 | struct pt1_adapter *adap; |
483 | adap = container_of(feed->demux, struct pt1_adapter, demux); | 508 | adap = container_of(feed->demux, struct pt1_adapter, demux); |
484 | if (!adap->users++) | 509 | if (!adap->users++) { |
510 | int ret; | ||
511 | |||
512 | ret = pt1_start_polling(adap->pt1); | ||
513 | if (ret) | ||
514 | return ret; | ||
485 | pt1_set_stream(adap->pt1, adap->index, 1); | 515 | pt1_set_stream(adap->pt1, adap->index, 1); |
516 | } | ||
486 | return 0; | 517 | return 0; |
487 | } | 518 | } |
488 | 519 | ||
520 | static void pt1_stop_polling(struct pt1 *pt1) | ||
521 | { | ||
522 | int i, count; | ||
523 | |||
524 | mutex_lock(&pt1->lock); | ||
525 | for (i = 0, count = 0; i < PT1_NR_ADAPS; i++) | ||
526 | count += pt1->adaps[i]->users; | ||
527 | |||
528 | if (count == 0 && pt1->kthread) { | ||
529 | kthread_stop(pt1->kthread); | ||
530 | pt1->kthread = NULL; | ||
531 | } | ||
532 | mutex_unlock(&pt1->lock); | ||
533 | } | ||
534 | |||
489 | static int pt1_stop_feed(struct dvb_demux_feed *feed) | 535 | static int pt1_stop_feed(struct dvb_demux_feed *feed) |
490 | { | 536 | { |
491 | struct pt1_adapter *adap; | 537 | struct pt1_adapter *adap; |
492 | adap = container_of(feed->demux, struct pt1_adapter, demux); | 538 | adap = container_of(feed->demux, struct pt1_adapter, demux); |
493 | if (!--adap->users) | 539 | if (!--adap->users) { |
494 | pt1_set_stream(adap->pt1, adap->index, 0); | 540 | pt1_set_stream(adap->pt1, adap->index, 0); |
541 | pt1_stop_polling(adap->pt1); | ||
542 | } | ||
495 | return 0; | 543 | return 0; |
496 | } | 544 | } |
497 | 545 | ||
@@ -575,7 +623,6 @@ static int pt1_wakeup(struct dvb_frontend *fe) | |||
575 | 623 | ||
576 | static void pt1_free_adapter(struct pt1_adapter *adap) | 624 | static void pt1_free_adapter(struct pt1_adapter *adap) |
577 | { | 625 | { |
578 | dvb_net_release(&adap->net); | ||
579 | adap->demux.dmx.close(&adap->demux.dmx); | 626 | adap->demux.dmx.close(&adap->demux.dmx); |
580 | dvb_dmxdev_release(&adap->dmxdev); | 627 | dvb_dmxdev_release(&adap->dmxdev); |
581 | dvb_dmx_release(&adap->demux); | 628 | dvb_dmx_release(&adap->demux); |
@@ -616,6 +663,7 @@ pt1_alloc_adapter(struct pt1 *pt1) | |||
616 | adap->buf = buf; | 663 | adap->buf = buf; |
617 | adap->upacket_count = 0; | 664 | adap->upacket_count = 0; |
618 | adap->packet_count = 0; | 665 | adap->packet_count = 0; |
666 | adap->st_count = -1; | ||
619 | 667 | ||
620 | dvb_adap = &adap->adap; | 668 | dvb_adap = &adap->adap; |
621 | dvb_adap->priv = adap; | 669 | dvb_adap->priv = adap; |
@@ -644,8 +692,6 @@ pt1_alloc_adapter(struct pt1 *pt1) | |||
644 | if (ret < 0) | 692 | if (ret < 0) |
645 | goto err_dmx_release; | 693 | goto err_dmx_release; |
646 | 694 | ||
647 | dvb_net_init(dvb_adap, &adap->net, &demux->dmx); | ||
648 | |||
649 | return adap; | 695 | return adap; |
650 | 696 | ||
651 | err_dmx_release: | 697 | err_dmx_release: |
@@ -1020,7 +1066,8 @@ static void __devexit pt1_remove(struct pci_dev *pdev) | |||
1020 | pt1 = pci_get_drvdata(pdev); | 1066 | pt1 = pci_get_drvdata(pdev); |
1021 | regs = pt1->regs; | 1067 | regs = pt1->regs; |
1022 | 1068 | ||
1023 | kthread_stop(pt1->kthread); | 1069 | if (pt1->kthread) |
1070 | kthread_stop(pt1->kthread); | ||
1024 | pt1_cleanup_tables(pt1); | 1071 | pt1_cleanup_tables(pt1); |
1025 | pt1_cleanup_frontends(pt1); | 1072 | pt1_cleanup_frontends(pt1); |
1026 | pt1_disable_ram(pt1); | 1073 | pt1_disable_ram(pt1); |
@@ -1043,7 +1090,6 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1043 | void __iomem *regs; | 1090 | void __iomem *regs; |
1044 | struct pt1 *pt1; | 1091 | struct pt1 *pt1; |
1045 | struct i2c_adapter *i2c_adap; | 1092 | struct i2c_adapter *i2c_adap; |
1046 | struct task_struct *kthread; | ||
1047 | 1093 | ||
1048 | ret = pci_enable_device(pdev); | 1094 | ret = pci_enable_device(pdev); |
1049 | if (ret < 0) | 1095 | if (ret < 0) |
@@ -1139,17 +1185,8 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1139 | if (ret < 0) | 1185 | if (ret < 0) |
1140 | goto err_pt1_cleanup_frontends; | 1186 | goto err_pt1_cleanup_frontends; |
1141 | 1187 | ||
1142 | kthread = kthread_run(pt1_thread, pt1, "pt1"); | ||
1143 | if (IS_ERR(kthread)) { | ||
1144 | ret = PTR_ERR(kthread); | ||
1145 | goto err_pt1_cleanup_tables; | ||
1146 | } | ||
1147 | |||
1148 | pt1->kthread = kthread; | ||
1149 | return 0; | 1188 | return 0; |
1150 | 1189 | ||
1151 | err_pt1_cleanup_tables: | ||
1152 | pt1_cleanup_tables(pt1); | ||
1153 | err_pt1_cleanup_frontends: | 1190 | err_pt1_cleanup_frontends: |
1154 | pt1_cleanup_frontends(pt1); | 1191 | pt1_cleanup_frontends(pt1); |
1155 | err_pt1_disable_ram: | 1192 | err_pt1_disable_ram: |
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 7b42ace419d9..421cf73858d3 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c | |||
@@ -312,7 +312,7 @@ static void __exit media_devnode_exit(void) | |||
312 | unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); | 312 | unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); |
313 | } | 313 | } |
314 | 314 | ||
315 | module_init(media_devnode_init) | 315 | subsys_initcall(media_devnode_init); |
316 | module_exit(media_devnode_exit) | 316 | module_exit(media_devnode_exit) |
317 | 317 | ||
318 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | 318 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); |
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index e954781c90bf..8db2d7f4b52a 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig | |||
@@ -43,7 +43,7 @@ config USB_DSBR | |||
43 | 43 | ||
44 | config RADIO_MAXIRADIO | 44 | config RADIO_MAXIRADIO |
45 | tristate "Guillemot MAXI Radio FM 2000 radio" | 45 | tristate "Guillemot MAXI Radio FM 2000 radio" |
46 | depends on VIDEO_V4L2 && PCI | 46 | depends on VIDEO_V4L2 && PCI && SND |
47 | ---help--- | 47 | ---help--- |
48 | Choose Y here if you have this radio card. This card may also be | 48 | Choose Y here if you have this radio card. This card may also be |
49 | found as Gemtek PCI FM. | 49 | found as Gemtek PCI FM. |
@@ -80,6 +80,16 @@ config RADIO_SI4713 | |||
80 | To compile this driver as a module, choose M here: the | 80 | To compile this driver as a module, choose M here: the |
81 | module will be called radio-si4713. | 81 | module will be called radio-si4713. |
82 | 82 | ||
83 | config USB_KEENE | ||
84 | tristate "Keene FM Transmitter USB support" | ||
85 | depends on USB && VIDEO_V4L2 | ||
86 | ---help--- | ||
87 | Say Y here if you want to connect this type of FM transmitter | ||
88 | to your computer's USB port. | ||
89 | |||
90 | To compile this driver as a module, choose M here: the | ||
91 | module will be called radio-keene. | ||
92 | |||
83 | config RADIO_TEA5764 | 93 | config RADIO_TEA5764 |
84 | tristate "TEA5764 I2C FM radio support" | 94 | tristate "TEA5764 I2C FM radio support" |
85 | depends on I2C && VIDEO_V4L2 | 95 | depends on I2C && VIDEO_V4L2 |
@@ -167,6 +177,10 @@ menuconfig V4L_RADIO_ISA_DRIVERS | |||
167 | 177 | ||
168 | if V4L_RADIO_ISA_DRIVERS | 178 | if V4L_RADIO_ISA_DRIVERS |
169 | 179 | ||
180 | config RADIO_ISA | ||
181 | depends on ISA | ||
182 | tristate | ||
183 | |||
170 | config RADIO_CADET | 184 | config RADIO_CADET |
171 | tristate "ADS Cadet AM/FM Tuner" | 185 | tristate "ADS Cadet AM/FM Tuner" |
172 | depends on ISA && VIDEO_V4L2 | 186 | depends on ISA && VIDEO_V4L2 |
@@ -174,20 +188,13 @@ config RADIO_CADET | |||
174 | Choose Y here if you have one of these AM/FM radio cards, and then | 188 | Choose Y here if you have one of these AM/FM radio cards, and then |
175 | fill in the port address below. | 189 | fill in the port address below. |
176 | 190 | ||
177 | In order to control your radio card, you will need to use programs | ||
178 | that are compatible with the Video For Linux API. Information on | ||
179 | this API and pointers to "v4l" programs may be found at | ||
180 | <file:Documentation/video4linux/API.html>. | ||
181 | |||
182 | Further documentation on this driver can be found on the WWW at | ||
183 | <http://linux.blackhawke.net/cadet/>. | ||
184 | |||
185 | To compile this driver as a module, choose M here: the | 191 | To compile this driver as a module, choose M here: the |
186 | module will be called radio-cadet. | 192 | module will be called radio-cadet. |
187 | 193 | ||
188 | config RADIO_RTRACK | 194 | config RADIO_RTRACK |
189 | tristate "AIMSlab RadioTrack (aka RadioReveal) support" | 195 | tristate "AIMSlab RadioTrack (aka RadioReveal) support" |
190 | depends on ISA && VIDEO_V4L2 | 196 | depends on ISA && VIDEO_V4L2 |
197 | select RADIO_ISA | ||
191 | ---help--- | 198 | ---help--- |
192 | Choose Y here if you have one of these FM radio cards, and then fill | 199 | Choose Y here if you have one of these FM radio cards, and then fill |
193 | in the port address below. | 200 | in the port address below. |
@@ -201,11 +208,7 @@ config RADIO_RTRACK | |||
201 | You must also pass the module a suitable io parameter, 0x248 has | 208 | You must also pass the module a suitable io parameter, 0x248 has |
202 | been reported to be used by these cards. | 209 | been reported to be used by these cards. |
203 | 210 | ||
204 | In order to control your radio card, you will need to use programs | 211 | More information is contained in the file |
205 | that are compatible with the Video For Linux API. Information on | ||
206 | this API and pointers to "v4l" programs may be found at | ||
207 | <file:Documentation/video4linux/API.html>. More information is | ||
208 | contained in the file | ||
209 | <file:Documentation/video4linux/radiotrack.txt>. | 212 | <file:Documentation/video4linux/radiotrack.txt>. |
210 | 213 | ||
211 | To compile this driver as a module, choose M here: the | 214 | To compile this driver as a module, choose M here: the |
@@ -214,7 +217,7 @@ config RADIO_RTRACK | |||
214 | config RADIO_RTRACK_PORT | 217 | config RADIO_RTRACK_PORT |
215 | hex "RadioTrack i/o port (0x20f or 0x30f)" | 218 | hex "RadioTrack i/o port (0x20f or 0x30f)" |
216 | depends on RADIO_RTRACK=y | 219 | depends on RADIO_RTRACK=y |
217 | default "20f" | 220 | default "30f" |
218 | help | 221 | help |
219 | Enter either 0x30f or 0x20f here. The card default is 0x30f, if you | 222 | Enter either 0x30f or 0x20f here. The card default is 0x30f, if you |
220 | haven't changed the jumper setting on the card. | 223 | haven't changed the jumper setting on the card. |
@@ -222,14 +225,14 @@ config RADIO_RTRACK_PORT | |||
222 | config RADIO_RTRACK2 | 225 | config RADIO_RTRACK2 |
223 | tristate "AIMSlab RadioTrack II support" | 226 | tristate "AIMSlab RadioTrack II support" |
224 | depends on ISA && VIDEO_V4L2 | 227 | depends on ISA && VIDEO_V4L2 |
228 | select RADIO_ISA | ||
225 | ---help--- | 229 | ---help--- |
226 | Choose Y here if you have this FM radio card, and then fill in the | 230 | Choose Y here if you have this FM radio card, and then fill in the |
227 | port address below. | 231 | port address below. |
228 | 232 | ||
229 | In order to control your radio card, you will need to use programs | 233 | Note: this driver hasn't been tested since a long time due to lack |
230 | that are compatible with the Video For Linux API. Information on | 234 | of hardware. If you have this hardware, then please contact the |
231 | this API and pointers to "v4l" programs may be found at | 235 | linux-media mailinglist. |
232 | <file:Documentation/video4linux/API.html>. | ||
233 | 236 | ||
234 | To compile this driver as a module, choose M here: the | 237 | To compile this driver as a module, choose M here: the |
235 | module will be called radio-rtrack2. | 238 | module will be called radio-rtrack2. |
@@ -245,15 +248,11 @@ config RADIO_RTRACK2_PORT | |||
245 | config RADIO_AZTECH | 248 | config RADIO_AZTECH |
246 | tristate "Aztech/Packard Bell Radio" | 249 | tristate "Aztech/Packard Bell Radio" |
247 | depends on ISA && VIDEO_V4L2 | 250 | depends on ISA && VIDEO_V4L2 |
251 | select RADIO_ISA | ||
248 | ---help--- | 252 | ---help--- |
249 | Choose Y here if you have one of these FM radio cards, and then fill | 253 | Choose Y here if you have one of these FM radio cards, and then fill |
250 | in the port address below. | 254 | in the port address below. |
251 | 255 | ||
252 | In order to control your radio card, you will need to use programs | ||
253 | that are compatible with the Video For Linux API. Information on | ||
254 | this API and pointers to "v4l" programs may be found at | ||
255 | <file:Documentation/video4linux/API.html>. | ||
256 | |||
257 | To compile this driver as a module, choose M here: the | 256 | To compile this driver as a module, choose M here: the |
258 | module will be called radio-aztech. | 257 | module will be called radio-aztech. |
259 | 258 | ||
@@ -269,6 +268,7 @@ config RADIO_AZTECH_PORT | |||
269 | config RADIO_GEMTEK | 268 | config RADIO_GEMTEK |
270 | tristate "GemTek Radio card (or compatible) support" | 269 | tristate "GemTek Radio card (or compatible) support" |
271 | depends on ISA && VIDEO_V4L2 | 270 | depends on ISA && VIDEO_V4L2 |
271 | select RADIO_ISA | ||
272 | ---help--- | 272 | ---help--- |
273 | Choose Y here if you have this FM radio card, and then fill in the | 273 | Choose Y here if you have this FM radio card, and then fill in the |
274 | I/O port address and settings below. The following cards either have | 274 | I/O port address and settings below. The following cards either have |
@@ -278,23 +278,21 @@ config RADIO_GEMTEK | |||
278 | - Typhoon Radio card (some models) | 278 | - Typhoon Radio card (some models) |
279 | - Hama Radio card | 279 | - Hama Radio card |
280 | 280 | ||
281 | In order to control your radio card, you will need to use programs | ||
282 | that are compatible with the Video For Linux API. Information on | ||
283 | this API and pointers to "v4l" programs may be found at | ||
284 | <file:Documentation/video4linux/API.html>. | ||
285 | |||
286 | To compile this driver as a module, choose M here: the | 281 | To compile this driver as a module, choose M here: the |
287 | module will be called radio-gemtek. | 282 | module will be called radio-gemtek. |
288 | 283 | ||
289 | config RADIO_GEMTEK_PORT | 284 | config RADIO_GEMTEK_PORT |
290 | hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" | 285 | hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c)" |
291 | depends on RADIO_GEMTEK=y | 286 | depends on RADIO_GEMTEK=y |
292 | default "34c" | 287 | default "34c" |
293 | help | 288 | help |
294 | Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is | 289 | Enter either 0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c here. The |
295 | 0x34c, if you haven't changed the jumper setting on the card. On | 290 | card default is 0x34c, if you haven't changed the jumper setting |
296 | Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O | 291 | on the card. |
292 | |||
293 | On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O | ||
297 | port is 0x20c, 0x248 or 0x28c. | 294 | port is 0x20c, 0x248 or 0x28c. |
295 | |||
298 | If automatic I/O port probing is enabled this port will be used only | 296 | If automatic I/O port probing is enabled this port will be used only |
299 | in case of automatic probing failure, ie. as a fallback. | 297 | in case of automatic probing failure, ie. as a fallback. |
300 | 298 | ||
@@ -318,11 +316,6 @@ config RADIO_MIROPCM20 | |||
318 | sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this | 316 | sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this |
319 | is required for the radio-miropcm20. | 317 | is required for the radio-miropcm20. |
320 | 318 | ||
321 | In order to control your radio card, you will need to use programs | ||
322 | that are compatible with the Video For Linux API. Information on | ||
323 | this API and pointers to "v4l" programs may be found at | ||
324 | <file:Documentation/video4linux/API.html>. | ||
325 | |||
326 | To compile this driver as a module, choose M here: the | 319 | To compile this driver as a module, choose M here: the |
327 | module will be called radio-miropcm20. | 320 | module will be called radio-miropcm20. |
328 | 321 | ||
@@ -332,11 +325,6 @@ config RADIO_SF16FMI | |||
332 | ---help--- | 325 | ---help--- |
333 | Choose Y here if you have one of these FM radio cards. | 326 | Choose Y here if you have one of these FM radio cards. |
334 | 327 | ||
335 | In order to control your radio card, you will need to use programs | ||
336 | that are compatible with the Video For Linux API. Information on | ||
337 | this API and pointers to "v4l" programs may be found at | ||
338 | <file:Documentation/video4linux/API.html>. | ||
339 | |||
340 | To compile this driver as a module, choose M here: the | 328 | To compile this driver as a module, choose M here: the |
341 | module will be called radio-sf16fmi. | 329 | module will be called radio-sf16fmi. |
342 | 330 | ||
@@ -346,50 +334,35 @@ config RADIO_SF16FMR2 | |||
346 | ---help--- | 334 | ---help--- |
347 | Choose Y here if you have one of these FM radio cards. | 335 | Choose Y here if you have one of these FM radio cards. |
348 | 336 | ||
349 | In order to control your radio card, you will need to use programs | ||
350 | that are compatible with the Video For Linux API. Information on | ||
351 | this API and pointers to "v4l" programs may be found on the WWW at | ||
352 | <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. | ||
353 | |||
354 | To compile this driver as a module, choose M here: the | 337 | To compile this driver as a module, choose M here: the |
355 | module will be called radio-sf16fmr2. | 338 | module will be called radio-sf16fmr2. |
356 | 339 | ||
357 | config RADIO_TERRATEC | 340 | config RADIO_TERRATEC |
358 | tristate "TerraTec ActiveRadio ISA Standalone" | 341 | tristate "TerraTec ActiveRadio ISA Standalone" |
359 | depends on ISA && VIDEO_V4L2 | 342 | depends on ISA && VIDEO_V4L2 |
343 | select RADIO_ISA | ||
360 | ---help--- | 344 | ---help--- |
361 | Choose Y here if you have this FM radio card, and then fill in the | 345 | Choose Y here if you have this FM radio card. |
362 | port address below. (TODO) | ||
363 | 346 | ||
364 | Note: This driver is in its early stages. Right now volume and | 347 | Note: this driver hasn't been tested since a long time due to lack |
365 | frequency control and muting works at least for me, but | 348 | of hardware. If you have this hardware, then please contact the |
366 | unfortunately I have not found anybody who wants to use this card | 349 | linux-media mailinglist. |
367 | with Linux. So if it is this what YOU are trying to do right now, | ||
368 | PLEASE DROP ME A NOTE!! Rolf Offermanns <rolf@offermanns.de>. | ||
369 | |||
370 | In order to control your radio card, you will need to use programs | ||
371 | that are compatible with the Video For Linux API. Information on | ||
372 | this API and pointers to "v4l" programs may be found at | ||
373 | <file:Documentation/video4linux/API.html>. | ||
374 | 350 | ||
375 | To compile this driver as a module, choose M here: the | 351 | To compile this driver as a module, choose M here: the |
376 | module will be called radio-terratec. | 352 | module will be called radio-terratec. |
377 | 353 | ||
378 | config RADIO_TERRATEC_PORT | ||
379 | hex "Terratec i/o port (normally 0x590)" | ||
380 | depends on RADIO_TERRATEC=y | ||
381 | default "590" | ||
382 | help | ||
383 | Fill in the I/O port of your TerraTec FM radio card. If unsure, go | ||
384 | with the default. | ||
385 | |||
386 | config RADIO_TRUST | 354 | config RADIO_TRUST |
387 | tristate "Trust FM radio card" | 355 | tristate "Trust FM radio card" |
388 | depends on ISA && VIDEO_V4L2 | 356 | depends on ISA && VIDEO_V4L2 |
357 | select RADIO_ISA | ||
389 | help | 358 | help |
390 | This is a driver for the Trust FM radio cards. Say Y if you have | 359 | This is a driver for the Trust FM radio cards. Say Y if you have |
391 | such a card and want to use it under Linux. | 360 | such a card and want to use it under Linux. |
392 | 361 | ||
362 | Note: this driver hasn't been tested since a long time due to lack | ||
363 | of hardware. If you have this hardware, then please contact the | ||
364 | linux-media mailinglist. | ||
365 | |||
393 | To compile this driver as a module, choose M here: the | 366 | To compile this driver as a module, choose M here: the |
394 | module will be called radio-trust. | 367 | module will be called radio-trust. |
395 | 368 | ||
@@ -404,14 +377,14 @@ config RADIO_TRUST_PORT | |||
404 | config RADIO_TYPHOON | 377 | config RADIO_TYPHOON |
405 | tristate "Typhoon Radio (a.k.a. EcoRadio)" | 378 | tristate "Typhoon Radio (a.k.a. EcoRadio)" |
406 | depends on ISA && VIDEO_V4L2 | 379 | depends on ISA && VIDEO_V4L2 |
380 | select RADIO_ISA | ||
407 | ---help--- | 381 | ---help--- |
408 | Choose Y here if you have one of these FM radio cards, and then fill | 382 | Choose Y here if you have one of these FM radio cards, and then fill |
409 | in the port address and the frequency used for muting below. | 383 | in the port address and the frequency used for muting below. |
410 | 384 | ||
411 | In order to control your radio card, you will need to use programs | 385 | Note: this driver hasn't been tested since a long time due to lack |
412 | that are compatible with the Video For Linux API. Information on | 386 | of hardware. If you have this hardware, then please contact the |
413 | this API and pointers to "v4l" programs may be found at | 387 | linux-media mailinglist. |
414 | <file:Documentation/video4linux/API.html>. | ||
415 | 388 | ||
416 | To compile this driver as a module, choose M here: the | 389 | To compile this driver as a module, choose M here: the |
417 | module will be called radio-typhoon. | 390 | module will be called radio-typhoon. |
@@ -438,14 +411,14 @@ config RADIO_TYPHOON_MUTEFREQ | |||
438 | config RADIO_ZOLTRIX | 411 | config RADIO_ZOLTRIX |
439 | tristate "Zoltrix Radio" | 412 | tristate "Zoltrix Radio" |
440 | depends on ISA && VIDEO_V4L2 | 413 | depends on ISA && VIDEO_V4L2 |
414 | select RADIO_ISA | ||
441 | ---help--- | 415 | ---help--- |
442 | Choose Y here if you have one of these FM radio cards, and then fill | 416 | Choose Y here if you have one of these FM radio cards, and then fill |
443 | in the port address below. | 417 | in the port address below. |
444 | 418 | ||
445 | In order to control your radio card, you will need to use programs | 419 | Note: this driver hasn't been tested since a long time due to lack |
446 | that are compatible with the Video For Linux API. Information on | 420 | of hardware. If you have this hardware, then please contact the |
447 | this API and pointers to "v4l" programs may be found at | 421 | linux-media mailinglist. |
448 | <file:Documentation/video4linux/API.html>. | ||
449 | 422 | ||
450 | To compile this driver as a module, choose M here: the | 423 | To compile this driver as a module, choose M here: the |
451 | module will be called radio-zoltrix. | 424 | module will be called radio-zoltrix. |
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 390daf94d847..ca8c7d134b95 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile | |||
@@ -2,6 +2,7 @@ | |||
2 | # Makefile for the kernel character device drivers. | 2 | # Makefile for the kernel character device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_RADIO_ISA) += radio-isa.o | ||
5 | obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o | 6 | obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o |
6 | obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o | 7 | obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o |
7 | obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o | 8 | obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o |
@@ -20,6 +21,7 @@ obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o | |||
20 | obj-$(CONFIG_USB_DSBR) += dsbr100.o | 21 | obj-$(CONFIG_USB_DSBR) += dsbr100.o |
21 | obj-$(CONFIG_RADIO_SI470X) += si470x/ | 22 | obj-$(CONFIG_RADIO_SI470X) += si470x/ |
22 | obj-$(CONFIG_USB_MR800) += radio-mr800.o | 23 | obj-$(CONFIG_USB_MR800) += radio-mr800.o |
24 | obj-$(CONFIG_USB_KEENE) += radio-keene.o | ||
23 | obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o | 25 | obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o |
24 | obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o | 26 | obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o |
25 | obj-$(CONFIG_RADIO_TEF6862) += tef6862.o | 27 | obj-$(CONFIG_RADIO_TEF6862) += tef6862.o |
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 1c3f8440a55c..98e0c8c20312 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c | |||
@@ -1,16 +1,13 @@ | |||
1 | /* radiotrack (radioreveal) driver for Linux radio support | 1 | /* |
2 | * (c) 1997 M. Kirkwood | 2 | * AimsLab RadioTrack (aka RadioVeveal) driver |
3 | * | ||
4 | * Copyright 1997 M. Kirkwood | ||
5 | * | ||
6 | * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> | ||
3 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> | 7 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> |
4 | * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> | 8 | * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> |
5 | * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> | 9 | * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> |
6 | * | 10 | * |
7 | * History: | ||
8 | * 1999-02-24 Russell Kroll <rkroll@exploits.org> | ||
9 | * Fine tuning/VIDEO_TUNER_LOW | ||
10 | * Frequency range expanded to start at 87 MHz | ||
11 | * | ||
12 | * TODO: Allow for more than one of these foolish entities :-) | ||
13 | * | ||
14 | * Notes on the hardware (reverse engineered from other peoples' | 11 | * Notes on the hardware (reverse engineered from other peoples' |
15 | * reverse engineering of AIMS' code :-) | 12 | * reverse engineering of AIMS' code :-) |
16 | * | 13 | * |
@@ -26,6 +23,7 @@ | |||
26 | * wait(a_wee_while); | 23 | * wait(a_wee_while); |
27 | * out(port, stop_changing_the_volume); | 24 | * out(port, stop_changing_the_volume); |
28 | * | 25 | * |
26 | * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. | ||
29 | */ | 27 | */ |
30 | 28 | ||
31 | #include <linux/module.h> /* Modules */ | 29 | #include <linux/module.h> /* Modules */ |
@@ -34,401 +32,179 @@ | |||
34 | #include <linux/delay.h> /* msleep */ | 32 | #include <linux/delay.h> /* msleep */ |
35 | #include <linux/videodev2.h> /* kernel radio structs */ | 33 | #include <linux/videodev2.h> /* kernel radio structs */ |
36 | #include <linux/io.h> /* outb, outb_p */ | 34 | #include <linux/io.h> /* outb, outb_p */ |
35 | #include <linux/slab.h> | ||
37 | #include <media/v4l2-device.h> | 36 | #include <media/v4l2-device.h> |
38 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
38 | #include <media/v4l2-ctrls.h> | ||
39 | #include "radio-isa.h" | ||
39 | 40 | ||
40 | MODULE_AUTHOR("M.Kirkwood"); | 41 | MODULE_AUTHOR("M. Kirkwood"); |
41 | MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); | 42 | MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); |
42 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
43 | MODULE_VERSION("0.0.3"); | 44 | MODULE_VERSION("1.0.0"); |
44 | 45 | ||
45 | #ifndef CONFIG_RADIO_RTRACK_PORT | 46 | #ifndef CONFIG_RADIO_RTRACK_PORT |
46 | #define CONFIG_RADIO_RTRACK_PORT -1 | 47 | #define CONFIG_RADIO_RTRACK_PORT -1 |
47 | #endif | 48 | #endif |
48 | 49 | ||
49 | static int io = CONFIG_RADIO_RTRACK_PORT; | 50 | #define RTRACK_MAX 2 |
50 | static int radio_nr = -1; | ||
51 | 51 | ||
52 | module_param(io, int, 0); | 52 | static int io[RTRACK_MAX] = { [0] = CONFIG_RADIO_RTRACK_PORT, |
53 | MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); | 53 | [1 ... (RTRACK_MAX - 1)] = -1 }; |
54 | module_param(radio_nr, int, 0); | 54 | static int radio_nr[RTRACK_MAX] = { [0 ... (RTRACK_MAX - 1)] = -1 }; |
55 | 55 | ||
56 | struct rtrack | 56 | module_param_array(io, int, NULL, 0444); |
57 | { | 57 | MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)"); |
58 | struct v4l2_device v4l2_dev; | 58 | module_param_array(radio_nr, int, NULL, 0444); |
59 | struct video_device vdev; | 59 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); |
60 | int port; | 60 | |
61 | struct rtrack { | ||
62 | struct radio_isa_card isa; | ||
61 | int curvol; | 63 | int curvol; |
62 | unsigned long curfreq; | ||
63 | int muted; | ||
64 | int io; | ||
65 | struct mutex lock; | ||
66 | }; | 64 | }; |
67 | 65 | ||
68 | static struct rtrack rtrack_card; | 66 | static struct radio_isa_card *rtrack_alloc(void) |
69 | |||
70 | /* local things */ | ||
71 | |||
72 | static void rt_decvol(struct rtrack *rt) | ||
73 | { | ||
74 | outb(0x58, rt->io); /* volume down + sigstr + on */ | ||
75 | msleep(100); | ||
76 | outb(0xd8, rt->io); /* volume steady + sigstr + on */ | ||
77 | } | ||
78 | |||
79 | static void rt_incvol(struct rtrack *rt) | ||
80 | { | ||
81 | outb(0x98, rt->io); /* volume up + sigstr + on */ | ||
82 | msleep(100); | ||
83 | outb(0xd8, rt->io); /* volume steady + sigstr + on */ | ||
84 | } | ||
85 | |||
86 | static void rt_mute(struct rtrack *rt) | ||
87 | { | ||
88 | rt->muted = 1; | ||
89 | mutex_lock(&rt->lock); | ||
90 | outb(0xd0, rt->io); /* volume steady, off */ | ||
91 | mutex_unlock(&rt->lock); | ||
92 | } | ||
93 | |||
94 | static int rt_setvol(struct rtrack *rt, int vol) | ||
95 | { | 67 | { |
96 | int i; | 68 | struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL); |
97 | |||
98 | mutex_lock(&rt->lock); | ||
99 | |||
100 | if (vol == rt->curvol) { /* requested volume = current */ | ||
101 | if (rt->muted) { /* user is unmuting the card */ | ||
102 | rt->muted = 0; | ||
103 | outb(0xd8, rt->io); /* enable card */ | ||
104 | } | ||
105 | mutex_unlock(&rt->lock); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | if (vol == 0) { /* volume = 0 means mute the card */ | ||
110 | outb(0x48, rt->io); /* volume down but still "on" */ | ||
111 | msleep(2000); /* make sure it's totally down */ | ||
112 | outb(0xd0, rt->io); /* volume steady, off */ | ||
113 | rt->curvol = 0; /* track the volume state! */ | ||
114 | mutex_unlock(&rt->lock); | ||
115 | return 0; | ||
116 | } | ||
117 | 69 | ||
118 | rt->muted = 0; | 70 | if (rt) |
119 | if (vol > rt->curvol) | 71 | rt->curvol = 0xff; |
120 | for (i = rt->curvol; i < vol; i++) | 72 | return rt ? &rt->isa : NULL; |
121 | rt_incvol(rt); | ||
122 | else | ||
123 | for (i = rt->curvol; i > vol; i--) | ||
124 | rt_decvol(rt); | ||
125 | |||
126 | rt->curvol = vol; | ||
127 | mutex_unlock(&rt->lock); | ||
128 | return 0; | ||
129 | } | 73 | } |
130 | 74 | ||
131 | /* the 128+64 on these outb's is to keep the volume stable while tuning | 75 | /* The 128+64 on these outb's is to keep the volume stable while tuning. |
132 | * without them, the volume _will_ creep up with each frequency change | 76 | * Without them, the volume _will_ creep up with each frequency change |
133 | * and bit 4 (+16) is to keep the signal strength meter enabled | 77 | * and bit 4 (+16) is to keep the signal strength meter enabled. |
134 | */ | 78 | */ |
135 | 79 | ||
136 | static void send_0_byte(struct rtrack *rt) | 80 | static void send_0_byte(struct radio_isa_card *isa, int on) |
137 | { | 81 | { |
138 | if (rt->curvol == 0 || rt->muted) { | 82 | outb_p(128+64+16+on+1, isa->io); /* wr-enable + data low */ |
139 | outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */ | 83 | outb_p(128+64+16+on+2+1, isa->io); /* clock */ |
140 | outb_p(128+64+16+2+1, rt->io); /* clock */ | ||
141 | } | ||
142 | else { | ||
143 | outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */ | ||
144 | outb_p(128+64+16+8+2+1, rt->io); /* clock */ | ||
145 | } | ||
146 | msleep(1); | 84 | msleep(1); |
147 | } | 85 | } |
148 | 86 | ||
149 | static void send_1_byte(struct rtrack *rt) | 87 | static void send_1_byte(struct radio_isa_card *isa, int on) |
150 | { | 88 | { |
151 | if (rt->curvol == 0 || rt->muted) { | 89 | outb_p(128+64+16+on+4+1, isa->io); /* wr-enable+data high */ |
152 | outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */ | 90 | outb_p(128+64+16+on+4+2+1, isa->io); /* clock */ |
153 | outb_p(128+64+16+4+2+1, rt->io); /* clock */ | ||
154 | } | ||
155 | else { | ||
156 | outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */ | ||
157 | outb_p(128+64+16+8+4+2+1, rt->io); /* clock */ | ||
158 | } | ||
159 | |||
160 | msleep(1); | 91 | msleep(1); |
161 | } | 92 | } |
162 | 93 | ||
163 | static int rt_setfreq(struct rtrack *rt, unsigned long freq) | 94 | static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq) |
164 | { | 95 | { |
96 | int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8; | ||
165 | int i; | 97 | int i; |
166 | 98 | ||
167 | mutex_lock(&rt->lock); /* Stop other ops interfering */ | ||
168 | |||
169 | rt->curfreq = freq; | ||
170 | |||
171 | /* now uses VIDEO_TUNER_LOW for fine tuning */ | ||
172 | |||
173 | freq += 171200; /* Add 10.7 MHz IF */ | 99 | freq += 171200; /* Add 10.7 MHz IF */ |
174 | freq /= 800; /* Convert to 50 kHz units */ | 100 | freq /= 800; /* Convert to 50 kHz units */ |
175 | 101 | ||
176 | send_0_byte(rt); /* 0: LSB of frequency */ | 102 | send_0_byte(isa, on); /* 0: LSB of frequency */ |
177 | 103 | ||
178 | for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ | 104 | for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ |
179 | if (freq & (1 << i)) | 105 | if (freq & (1 << i)) |
180 | send_1_byte(rt); | 106 | send_1_byte(isa, on); |
181 | else | 107 | else |
182 | send_0_byte(rt); | 108 | send_0_byte(isa, on); |
183 | |||
184 | send_0_byte(rt); /* 14: test bit - always 0 */ | ||
185 | send_0_byte(rt); /* 15: test bit - always 0 */ | ||
186 | |||
187 | send_0_byte(rt); /* 16: band data 0 - always 0 */ | ||
188 | send_0_byte(rt); /* 17: band data 1 - always 0 */ | ||
189 | send_0_byte(rt); /* 18: band data 2 - always 0 */ | ||
190 | send_0_byte(rt); /* 19: time base - always 0 */ | ||
191 | |||
192 | send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */ | ||
193 | send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */ | ||
194 | send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */ | ||
195 | send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */ | ||
196 | |||
197 | if (rt->curvol == 0 || rt->muted) | ||
198 | outb(0xd0, rt->io); /* volume steady + sigstr */ | ||
199 | else | ||
200 | outb(0xd8, rt->io); /* volume steady + sigstr + on */ | ||
201 | |||
202 | mutex_unlock(&rt->lock); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int rt_getsigstr(struct rtrack *rt) | ||
208 | { | ||
209 | int sig = 1; | ||
210 | |||
211 | mutex_lock(&rt->lock); | ||
212 | if (inb(rt->io) & 2) /* bit set = no signal present */ | ||
213 | sig = 0; | ||
214 | mutex_unlock(&rt->lock); | ||
215 | return sig; | ||
216 | } | ||
217 | |||
218 | static int vidioc_querycap(struct file *file, void *priv, | ||
219 | struct v4l2_capability *v) | ||
220 | { | ||
221 | strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); | ||
222 | strlcpy(v->card, "RadioTrack", sizeof(v->card)); | ||
223 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
224 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
229 | struct v4l2_tuner *v) | ||
230 | { | ||
231 | struct rtrack *rt = video_drvdata(file); | ||
232 | 109 | ||
233 | if (v->index > 0) | 110 | send_0_byte(isa, on); /* 14: test bit - always 0 */ |
234 | return -EINVAL; | 111 | send_0_byte(isa, on); /* 15: test bit - always 0 */ |
235 | 112 | ||
236 | strlcpy(v->name, "FM", sizeof(v->name)); | 113 | send_0_byte(isa, on); /* 16: band data 0 - always 0 */ |
237 | v->type = V4L2_TUNER_RADIO; | 114 | send_0_byte(isa, on); /* 17: band data 1 - always 0 */ |
238 | v->rangelow = 87 * 16000; | 115 | send_0_byte(isa, on); /* 18: band data 2 - always 0 */ |
239 | v->rangehigh = 108 * 16000; | 116 | send_0_byte(isa, on); /* 19: time base - always 0 */ |
240 | v->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
241 | v->capability = V4L2_TUNER_CAP_LOW; | ||
242 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
243 | v->signal = 0xffff * rt_getsigstr(rt); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
248 | struct v4l2_tuner *v) | ||
249 | { | ||
250 | return v->index ? -EINVAL : 0; | ||
251 | } | ||
252 | |||
253 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
254 | struct v4l2_frequency *f) | ||
255 | { | ||
256 | struct rtrack *rt = video_drvdata(file); | ||
257 | |||
258 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
259 | return -EINVAL; | ||
260 | rt_setfreq(rt, f->frequency); | ||
261 | return 0; | ||
262 | } | ||
263 | 117 | ||
264 | static int vidioc_g_frequency(struct file *file, void *priv, | 118 | send_0_byte(isa, on); /* 20: spacing (0 = 25 kHz) */ |
265 | struct v4l2_frequency *f) | 119 | send_1_byte(isa, on); /* 21: spacing (1 = 25 kHz) */ |
266 | { | 120 | send_0_byte(isa, on); /* 22: spacing (0 = 25 kHz) */ |
267 | struct rtrack *rt = video_drvdata(file); | 121 | send_1_byte(isa, on); /* 23: AM/FM (FM = 1, always) */ |
268 | 122 | ||
269 | if (f->tuner != 0) | 123 | outb(0xd0 + on, isa->io); /* volume steady + sigstr */ |
270 | return -EINVAL; | ||
271 | f->type = V4L2_TUNER_RADIO; | ||
272 | f->frequency = rt->curfreq; | ||
273 | return 0; | 124 | return 0; |
274 | } | 125 | } |
275 | 126 | ||
276 | static int vidioc_queryctrl(struct file *file, void *priv, | 127 | static u32 rtrack_g_signal(struct radio_isa_card *isa) |
277 | struct v4l2_queryctrl *qc) | ||
278 | { | 128 | { |
279 | switch (qc->id) { | 129 | /* bit set = no signal present */ |
280 | case V4L2_CID_AUDIO_MUTE: | 130 | return 0xffff * !(inb(isa->io) & 2); |
281 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
282 | case V4L2_CID_AUDIO_VOLUME: | ||
283 | return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); | ||
284 | } | ||
285 | return -EINVAL; | ||
286 | } | 131 | } |
287 | 132 | ||
288 | static int vidioc_g_ctrl(struct file *file, void *priv, | 133 | static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
289 | struct v4l2_control *ctrl) | ||
290 | { | 134 | { |
291 | struct rtrack *rt = video_drvdata(file); | 135 | struct rtrack *rt = container_of(isa, struct rtrack, isa); |
136 | int curvol = rt->curvol; | ||
292 | 137 | ||
293 | switch (ctrl->id) { | 138 | if (mute) { |
294 | case V4L2_CID_AUDIO_MUTE: | 139 | outb(0xd0, isa->io); /* volume steady + sigstr + off */ |
295 | ctrl->value = rt->muted; | ||
296 | return 0; | ||
297 | case V4L2_CID_AUDIO_VOLUME: | ||
298 | ctrl->value = rt->curvol; | ||
299 | return 0; | 140 | return 0; |
300 | } | 141 | } |
301 | return -EINVAL; | 142 | if (vol == 0) { /* volume = 0 means mute the card */ |
302 | } | 143 | outb(0x48, isa->io); /* volume down but still "on" */ |
303 | 144 | msleep(curvol * 3); /* make sure it's totally down */ | |
304 | static int vidioc_s_ctrl(struct file *file, void *priv, | 145 | } else if (curvol < vol) { |
305 | struct v4l2_control *ctrl) | 146 | outb(0x98, isa->io); /* volume up + sigstr + on */ |
306 | { | 147 | for (; curvol < vol; curvol++) |
307 | struct rtrack *rt = video_drvdata(file); | 148 | udelay(3000); |
308 | 149 | } else if (curvol > vol) { | |
309 | switch (ctrl->id) { | 150 | outb(0x58, isa->io); /* volume down + sigstr + on */ |
310 | case V4L2_CID_AUDIO_MUTE: | 151 | for (; curvol > vol; curvol--) |
311 | if (ctrl->value) | 152 | udelay(3000); |
312 | rt_mute(rt); | ||
313 | else | ||
314 | rt_setvol(rt, rt->curvol); | ||
315 | return 0; | ||
316 | case V4L2_CID_AUDIO_VOLUME: | ||
317 | rt_setvol(rt, ctrl->value); | ||
318 | return 0; | ||
319 | } | 153 | } |
320 | return -EINVAL; | 154 | outb(0xd8, isa->io); /* volume steady + sigstr + on */ |
321 | } | 155 | rt->curvol = vol; |
322 | |||
323 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
324 | { | ||
325 | *i = 0; | ||
326 | return 0; | 156 | return 0; |
327 | } | 157 | } |
328 | 158 | ||
329 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | 159 | /* Mute card - prevents noisy bootups */ |
160 | static int rtrack_initialize(struct radio_isa_card *isa) | ||
330 | { | 161 | { |
331 | return i ? -EINVAL : 0; | 162 | /* this ensures that the volume is all the way up */ |
332 | } | 163 | outb(0x90, isa->io); /* volume up but still "on" */ |
333 | 164 | msleep(3000); /* make sure it's totally up */ | |
334 | static int vidioc_g_audio(struct file *file, void *priv, | 165 | outb(0xc0, isa->io); /* steady volume, mute card */ |
335 | struct v4l2_audio *a) | ||
336 | { | ||
337 | a->index = 0; | ||
338 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
339 | a->capability = V4L2_AUDCAP_STEREO; | ||
340 | return 0; | 166 | return 0; |
341 | } | 167 | } |
342 | 168 | ||
343 | static int vidioc_s_audio(struct file *file, void *priv, | 169 | static const struct radio_isa_ops rtrack_ops = { |
344 | struct v4l2_audio *a) | 170 | .alloc = rtrack_alloc, |
345 | { | 171 | .init = rtrack_initialize, |
346 | return a->index ? -EINVAL : 0; | 172 | .s_mute_volume = rtrack_s_mute_volume, |
347 | } | 173 | .s_frequency = rtrack_s_frequency, |
348 | 174 | .g_signal = rtrack_g_signal, | |
349 | static const struct v4l2_file_operations rtrack_fops = { | ||
350 | .owner = THIS_MODULE, | ||
351 | .unlocked_ioctl = video_ioctl2, | ||
352 | }; | 175 | }; |
353 | 176 | ||
354 | static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { | 177 | static const int rtrack_ioports[] = { 0x20f, 0x30f }; |
355 | .vidioc_querycap = vidioc_querycap, | 178 | |
356 | .vidioc_g_tuner = vidioc_g_tuner, | 179 | static struct radio_isa_driver rtrack_driver = { |
357 | .vidioc_s_tuner = vidioc_s_tuner, | 180 | .driver = { |
358 | .vidioc_g_audio = vidioc_g_audio, | 181 | .match = radio_isa_match, |
359 | .vidioc_s_audio = vidioc_s_audio, | 182 | .probe = radio_isa_probe, |
360 | .vidioc_g_input = vidioc_g_input, | 183 | .remove = radio_isa_remove, |
361 | .vidioc_s_input = vidioc_s_input, | 184 | .driver = { |
362 | .vidioc_g_frequency = vidioc_g_frequency, | 185 | .name = "radio-aimslab", |
363 | .vidioc_s_frequency = vidioc_s_frequency, | 186 | }, |
364 | .vidioc_queryctrl = vidioc_queryctrl, | 187 | }, |
365 | .vidioc_g_ctrl = vidioc_g_ctrl, | 188 | .io_params = io, |
366 | .vidioc_s_ctrl = vidioc_s_ctrl, | 189 | .radio_nr_params = radio_nr, |
190 | .io_ports = rtrack_ioports, | ||
191 | .num_of_io_ports = ARRAY_SIZE(rtrack_ioports), | ||
192 | .region_size = 2, | ||
193 | .card = "AIMSlab RadioTrack/RadioReveal", | ||
194 | .ops = &rtrack_ops, | ||
195 | .has_stereo = true, | ||
196 | .max_volume = 0xff, | ||
367 | }; | 197 | }; |
368 | 198 | ||
369 | static int __init rtrack_init(void) | 199 | static int __init rtrack_init(void) |
370 | { | 200 | { |
371 | struct rtrack *rt = &rtrack_card; | 201 | return isa_register_driver(&rtrack_driver.driver, RTRACK_MAX); |
372 | struct v4l2_device *v4l2_dev = &rt->v4l2_dev; | ||
373 | int res; | ||
374 | |||
375 | strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name)); | ||
376 | rt->io = io; | ||
377 | |||
378 | if (rt->io == -1) { | ||
379 | v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n"); | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
383 | if (!request_region(rt->io, 2, "rtrack")) { | ||
384 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io); | ||
385 | return -EBUSY; | ||
386 | } | ||
387 | |||
388 | res = v4l2_device_register(NULL, v4l2_dev); | ||
389 | if (res < 0) { | ||
390 | release_region(rt->io, 2); | ||
391 | v4l2_err(v4l2_dev, "could not register v4l2_device\n"); | ||
392 | return res; | ||
393 | } | ||
394 | |||
395 | strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name)); | ||
396 | rt->vdev.v4l2_dev = v4l2_dev; | ||
397 | rt->vdev.fops = &rtrack_fops; | ||
398 | rt->vdev.ioctl_ops = &rtrack_ioctl_ops; | ||
399 | rt->vdev.release = video_device_release_empty; | ||
400 | video_set_drvdata(&rt->vdev, rt); | ||
401 | |||
402 | /* Set up the I/O locking */ | ||
403 | |||
404 | mutex_init(&rt->lock); | ||
405 | |||
406 | /* mute card - prevents noisy bootups */ | ||
407 | |||
408 | /* this ensures that the volume is all the way down */ | ||
409 | outb(0x48, rt->io); /* volume down but still "on" */ | ||
410 | msleep(2000); /* make sure it's totally down */ | ||
411 | outb(0xc0, rt->io); /* steady volume, mute card */ | ||
412 | |||
413 | if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
414 | v4l2_device_unregister(&rt->v4l2_dev); | ||
415 | release_region(rt->io, 2); | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); | ||
419 | |||
420 | return 0; | ||
421 | } | 202 | } |
422 | 203 | ||
423 | static void __exit rtrack_exit(void) | 204 | static void __exit rtrack_exit(void) |
424 | { | 205 | { |
425 | struct rtrack *rt = &rtrack_card; | 206 | isa_unregister_driver(&rtrack_driver.driver); |
426 | |||
427 | video_unregister_device(&rt->vdev); | ||
428 | v4l2_device_unregister(&rt->v4l2_dev); | ||
429 | release_region(rt->io, 2); | ||
430 | } | 207 | } |
431 | 208 | ||
432 | module_init(rtrack_init); | 209 | module_init(rtrack_init); |
433 | module_exit(rtrack_exit); | 210 | module_exit(rtrack_exit); |
434 | |||
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index eed7b0840734..177bcbd7a7c1 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c | |||
@@ -1,5 +1,7 @@ | |||
1 | /* radio-aztech.c - Aztech radio card driver for Linux 2.2 | 1 | /* |
2 | * radio-aztech.c - Aztech radio card driver | ||
2 | * | 3 | * |
4 | * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@xs4all.nl> | ||
3 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> | 5 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> |
4 | * Adapted to support the Video for Linux API by | 6 | * Adapted to support the Video for Linux API by |
5 | * Russell Kroll <rkroll@exploits.org>. Based on original tuner code by: | 7 | * Russell Kroll <rkroll@exploits.org>. Based on original tuner code by: |
@@ -10,19 +12,7 @@ | |||
10 | * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) | 12 | * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) |
11 | * William McGrath (wmcgrath@twilight.vtc.vsc.edu) | 13 | * William McGrath (wmcgrath@twilight.vtc.vsc.edu) |
12 | * | 14 | * |
13 | * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ | 15 | * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. |
14 | * along with more information on the card itself. | ||
15 | * | ||
16 | * History: | ||
17 | * 1999-02-24 Russell Kroll <rkroll@exploits.org> | ||
18 | * Fine tuning/VIDEO_TUNER_LOW | ||
19 | * Range expanded to 87-108 MHz (from 87.9-107.8) | ||
20 | * | ||
21 | * Notable changes from the original source: | ||
22 | * - includes stripped down to the essentials | ||
23 | * - for loops used as delays replaced with udelay() | ||
24 | * - #defines removed, changed to static values | ||
25 | * - tuning structure changed - no more character arrays, other changes | ||
26 | */ | 16 | */ |
27 | 17 | ||
28 | #include <linux/module.h> /* Modules */ | 18 | #include <linux/module.h> /* Modules */ |
@@ -31,126 +21,72 @@ | |||
31 | #include <linux/delay.h> /* udelay */ | 21 | #include <linux/delay.h> /* udelay */ |
32 | #include <linux/videodev2.h> /* kernel radio structs */ | 22 | #include <linux/videodev2.h> /* kernel radio structs */ |
33 | #include <linux/io.h> /* outb, outb_p */ | 23 | #include <linux/io.h> /* outb, outb_p */ |
24 | #include <linux/slab.h> | ||
34 | #include <media/v4l2-device.h> | 25 | #include <media/v4l2-device.h> |
35 | #include <media/v4l2-ioctl.h> | 26 | #include <media/v4l2-ioctl.h> |
27 | #include <media/v4l2-ctrls.h> | ||
28 | #include "radio-isa.h" | ||
36 | 29 | ||
37 | MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); | 30 | MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); |
38 | MODULE_DESCRIPTION("A driver for the Aztech radio card."); | 31 | MODULE_DESCRIPTION("A driver for the Aztech radio card."); |
39 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
40 | MODULE_VERSION("0.0.3"); | 33 | MODULE_VERSION("1.0.0"); |
41 | 34 | ||
42 | /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ | 35 | /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ |
43 | |||
44 | #ifndef CONFIG_RADIO_AZTECH_PORT | 36 | #ifndef CONFIG_RADIO_AZTECH_PORT |
45 | #define CONFIG_RADIO_AZTECH_PORT -1 | 37 | #define CONFIG_RADIO_AZTECH_PORT -1 |
46 | #endif | 38 | #endif |
47 | 39 | ||
48 | static int io = CONFIG_RADIO_AZTECH_PORT; | 40 | #define AZTECH_MAX 2 |
49 | static int radio_nr = -1; | ||
50 | static int radio_wait_time = 1000; | ||
51 | 41 | ||
52 | module_param(io, int, 0); | 42 | static int io[AZTECH_MAX] = { [0] = CONFIG_RADIO_AZTECH_PORT, |
53 | module_param(radio_nr, int, 0); | 43 | [1 ... (AZTECH_MAX - 1)] = -1 }; |
54 | MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); | 44 | static int radio_nr[AZTECH_MAX] = { [0 ... (AZTECH_MAX - 1)] = -1 }; |
45 | static const int radio_wait_time = 1000; | ||
55 | 46 | ||
56 | struct aztech | 47 | module_param_array(io, int, NULL, 0444); |
57 | { | 48 | MODULE_PARM_DESC(io, "I/O addresses of the Aztech card (0x350 or 0x358)"); |
58 | struct v4l2_device v4l2_dev; | 49 | module_param_array(radio_nr, int, NULL, 0444); |
59 | struct video_device vdev; | 50 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); |
60 | int io; | 51 | |
52 | struct aztech { | ||
53 | struct radio_isa_card isa; | ||
61 | int curvol; | 54 | int curvol; |
62 | unsigned long curfreq; | ||
63 | int stereo; | ||
64 | struct mutex lock; | ||
65 | }; | 55 | }; |
66 | 56 | ||
67 | static struct aztech aztech_card; | ||
68 | |||
69 | static int volconvert(int level) | ||
70 | { | ||
71 | level >>= 14; /* Map 16bits down to 2 bit */ | ||
72 | level &= 3; | ||
73 | |||
74 | /* convert to card-friendly values */ | ||
75 | switch (level) { | ||
76 | case 0: | ||
77 | return 0; | ||
78 | case 1: | ||
79 | return 1; | ||
80 | case 2: | ||
81 | return 4; | ||
82 | case 3: | ||
83 | return 5; | ||
84 | } | ||
85 | return 0; /* Quieten gcc */ | ||
86 | } | ||
87 | |||
88 | static void send_0_byte(struct aztech *az) | 57 | static void send_0_byte(struct aztech *az) |
89 | { | 58 | { |
90 | udelay(radio_wait_time); | 59 | udelay(radio_wait_time); |
91 | outb_p(2 + volconvert(az->curvol), az->io); | 60 | outb_p(2 + az->curvol, az->isa.io); |
92 | outb_p(64 + 2 + volconvert(az->curvol), az->io); | 61 | outb_p(64 + 2 + az->curvol, az->isa.io); |
93 | } | 62 | } |
94 | 63 | ||
95 | static void send_1_byte(struct aztech *az) | 64 | static void send_1_byte(struct aztech *az) |
96 | { | 65 | { |
97 | udelay (radio_wait_time); | 66 | udelay(radio_wait_time); |
98 | outb_p(128 + 2 + volconvert(az->curvol), az->io); | 67 | outb_p(128 + 2 + az->curvol, az->isa.io); |
99 | outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io); | 68 | outb_p(128 + 64 + 2 + az->curvol, az->isa.io); |
100 | } | ||
101 | |||
102 | static int az_setvol(struct aztech *az, int vol) | ||
103 | { | ||
104 | mutex_lock(&az->lock); | ||
105 | outb(volconvert(vol), az->io); | ||
106 | mutex_unlock(&az->lock); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* thanks to Michael Dwyer for giving me a dose of clues in | ||
111 | * the signal strength department.. | ||
112 | * | ||
113 | * This card has a stereo bit - bit 0 set = mono, not set = stereo | ||
114 | * It also has a "signal" bit - bit 1 set = bad signal, not set = good | ||
115 | * | ||
116 | */ | ||
117 | |||
118 | static int az_getsigstr(struct aztech *az) | ||
119 | { | ||
120 | int sig = 1; | ||
121 | |||
122 | mutex_lock(&az->lock); | ||
123 | if (inb(az->io) & 2) /* bit set = no signal present */ | ||
124 | sig = 0; | ||
125 | mutex_unlock(&az->lock); | ||
126 | return sig; | ||
127 | } | 69 | } |
128 | 70 | ||
129 | static int az_getstereo(struct aztech *az) | 71 | static struct radio_isa_card *aztech_alloc(void) |
130 | { | 72 | { |
131 | int stereo = 1; | 73 | struct aztech *az = kzalloc(sizeof(*az), GFP_KERNEL); |
132 | 74 | ||
133 | mutex_lock(&az->lock); | 75 | return az ? &az->isa : NULL; |
134 | if (inb(az->io) & 1) /* bit set = mono */ | ||
135 | stereo = 0; | ||
136 | mutex_unlock(&az->lock); | ||
137 | return stereo; | ||
138 | } | 76 | } |
139 | 77 | ||
140 | static int az_setfreq(struct aztech *az, unsigned long frequency) | 78 | static int aztech_s_frequency(struct radio_isa_card *isa, u32 freq) |
141 | { | 79 | { |
80 | struct aztech *az = container_of(isa, struct aztech, isa); | ||
142 | int i; | 81 | int i; |
143 | 82 | ||
144 | mutex_lock(&az->lock); | 83 | freq += 171200; /* Add 10.7 MHz IF */ |
145 | 84 | freq /= 800; /* Convert to 50 kHz units */ | |
146 | az->curfreq = frequency; | ||
147 | frequency += 171200; /* Add 10.7 MHz IF */ | ||
148 | frequency /= 800; /* Convert to 50 kHz units */ | ||
149 | 85 | ||
150 | send_0_byte(az); /* 0: LSB of frequency */ | 86 | send_0_byte(az); /* 0: LSB of frequency */ |
151 | 87 | ||
152 | for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ | 88 | for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ |
153 | if (frequency & (1 << i)) | 89 | if (freq & (1 << i)) |
154 | send_1_byte(az); | 90 | send_1_byte(az); |
155 | else | 91 | else |
156 | send_0_byte(az); | 92 | send_0_byte(az); |
@@ -158,7 +94,7 @@ static int az_setfreq(struct aztech *az, unsigned long frequency) | |||
158 | send_0_byte(az); /* 14: test bit - always 0 */ | 94 | send_0_byte(az); /* 14: test bit - always 0 */ |
159 | send_0_byte(az); /* 15: test bit - always 0 */ | 95 | send_0_byte(az); /* 15: test bit - always 0 */ |
160 | send_0_byte(az); /* 16: band data 0 - always 0 */ | 96 | send_0_byte(az); /* 16: band data 0 - always 0 */ |
161 | if (az->stereo) /* 17: stereo (1 to enable) */ | 97 | if (isa->stereo) /* 17: stereo (1 to enable) */ |
162 | send_1_byte(az); | 98 | send_1_byte(az); |
163 | else | 99 | else |
164 | send_0_byte(az); | 100 | send_0_byte(az); |
@@ -173,225 +109,77 @@ static int az_setfreq(struct aztech *az, unsigned long frequency) | |||
173 | /* latch frequency */ | 109 | /* latch frequency */ |
174 | 110 | ||
175 | udelay(radio_wait_time); | 111 | udelay(radio_wait_time); |
176 | outb_p(128 + 64 + volconvert(az->curvol), az->io); | 112 | outb_p(128 + 64 + az->curvol, az->isa.io); |
177 | |||
178 | mutex_unlock(&az->lock); | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int vidioc_querycap(struct file *file, void *priv, | ||
184 | struct v4l2_capability *v) | ||
185 | { | ||
186 | strlcpy(v->driver, "radio-aztech", sizeof(v->driver)); | ||
187 | strlcpy(v->card, "Aztech Radio", sizeof(v->card)); | ||
188 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
189 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
194 | struct v4l2_tuner *v) | ||
195 | { | ||
196 | struct aztech *az = video_drvdata(file); | ||
197 | |||
198 | if (v->index > 0) | ||
199 | return -EINVAL; | ||
200 | |||
201 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
202 | v->type = V4L2_TUNER_RADIO; | ||
203 | |||
204 | v->rangelow = 87 * 16000; | ||
205 | v->rangehigh = 108 * 16000; | ||
206 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
207 | v->capability = V4L2_TUNER_CAP_LOW; | ||
208 | if (az_getstereo(az)) | ||
209 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
210 | else | ||
211 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
212 | v->signal = 0xFFFF * az_getsigstr(az); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
218 | struct v4l2_tuner *v) | ||
219 | { | ||
220 | return v->index ? -EINVAL : 0; | ||
221 | } | ||
222 | 113 | ||
223 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
224 | { | ||
225 | *i = 0; | ||
226 | return 0; | 114 | return 0; |
227 | } | 115 | } |
228 | 116 | ||
229 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | 117 | /* thanks to Michael Dwyer for giving me a dose of clues in |
230 | { | 118 | * the signal strength department.. |
231 | return i ? -EINVAL : 0; | 119 | * |
232 | } | 120 | * This card has a stereo bit - bit 0 set = mono, not set = stereo |
233 | 121 | */ | |
234 | static int vidioc_g_audio(struct file *file, void *priv, | 122 | static u32 aztech_g_rxsubchans(struct radio_isa_card *isa) |
235 | struct v4l2_audio *a) | ||
236 | { | ||
237 | a->index = 0; | ||
238 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
239 | a->capability = V4L2_AUDCAP_STEREO; | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int vidioc_s_audio(struct file *file, void *priv, | ||
244 | struct v4l2_audio *a) | ||
245 | { | 123 | { |
246 | return a->index ? -EINVAL : 0; | 124 | if (inb(isa->io) & 1) |
125 | return V4L2_TUNER_SUB_MONO; | ||
126 | return V4L2_TUNER_SUB_STEREO; | ||
247 | } | 127 | } |
248 | 128 | ||
249 | static int vidioc_s_frequency(struct file *file, void *priv, | 129 | static int aztech_s_stereo(struct radio_isa_card *isa, bool stereo) |
250 | struct v4l2_frequency *f) | ||
251 | { | 130 | { |
252 | struct aztech *az = video_drvdata(file); | 131 | return aztech_s_frequency(isa, isa->freq); |
253 | |||
254 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
255 | return -EINVAL; | ||
256 | az_setfreq(az, f->frequency); | ||
257 | return 0; | ||
258 | } | 132 | } |
259 | 133 | ||
260 | static int vidioc_g_frequency(struct file *file, void *priv, | 134 | static int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
261 | struct v4l2_frequency *f) | ||
262 | { | 135 | { |
263 | struct aztech *az = video_drvdata(file); | 136 | struct aztech *az = container_of(isa, struct aztech, isa); |
264 | 137 | ||
265 | if (f->tuner != 0) | 138 | if (mute) |
266 | return -EINVAL; | 139 | vol = 0; |
267 | f->type = V4L2_TUNER_RADIO; | 140 | az->curvol = (vol & 1) + ((vol & 2) << 1); |
268 | f->frequency = az->curfreq; | 141 | outb(az->curvol, isa->io); |
269 | return 0; | 142 | return 0; |
270 | } | 143 | } |
271 | 144 | ||
272 | static int vidioc_queryctrl(struct file *file, void *priv, | 145 | static const struct radio_isa_ops aztech_ops = { |
273 | struct v4l2_queryctrl *qc) | 146 | .alloc = aztech_alloc, |
274 | { | 147 | .s_mute_volume = aztech_s_mute_volume, |
275 | switch (qc->id) { | 148 | .s_frequency = aztech_s_frequency, |
276 | case V4L2_CID_AUDIO_MUTE: | 149 | .s_stereo = aztech_s_stereo, |
277 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | 150 | .g_rxsubchans = aztech_g_rxsubchans, |
278 | case V4L2_CID_AUDIO_VOLUME: | ||
279 | return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); | ||
280 | } | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | |||
284 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
285 | struct v4l2_control *ctrl) | ||
286 | { | ||
287 | struct aztech *az = video_drvdata(file); | ||
288 | |||
289 | switch (ctrl->id) { | ||
290 | case V4L2_CID_AUDIO_MUTE: | ||
291 | if (az->curvol == 0) | ||
292 | ctrl->value = 1; | ||
293 | else | ||
294 | ctrl->value = 0; | ||
295 | return 0; | ||
296 | case V4L2_CID_AUDIO_VOLUME: | ||
297 | ctrl->value = az->curvol * 6554; | ||
298 | return 0; | ||
299 | } | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | |||
303 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
304 | struct v4l2_control *ctrl) | ||
305 | { | ||
306 | struct aztech *az = video_drvdata(file); | ||
307 | |||
308 | switch (ctrl->id) { | ||
309 | case V4L2_CID_AUDIO_MUTE: | ||
310 | if (ctrl->value) | ||
311 | az_setvol(az, 0); | ||
312 | else | ||
313 | az_setvol(az, az->curvol); | ||
314 | return 0; | ||
315 | case V4L2_CID_AUDIO_VOLUME: | ||
316 | az_setvol(az, ctrl->value); | ||
317 | return 0; | ||
318 | } | ||
319 | return -EINVAL; | ||
320 | } | ||
321 | |||
322 | static const struct v4l2_file_operations aztech_fops = { | ||
323 | .owner = THIS_MODULE, | ||
324 | .unlocked_ioctl = video_ioctl2, | ||
325 | }; | 151 | }; |
326 | 152 | ||
327 | static const struct v4l2_ioctl_ops aztech_ioctl_ops = { | 153 | static const int aztech_ioports[] = { 0x350, 0x358 }; |
328 | .vidioc_querycap = vidioc_querycap, | 154 | |
329 | .vidioc_g_tuner = vidioc_g_tuner, | 155 | static struct radio_isa_driver aztech_driver = { |
330 | .vidioc_s_tuner = vidioc_s_tuner, | 156 | .driver = { |
331 | .vidioc_g_audio = vidioc_g_audio, | 157 | .match = radio_isa_match, |
332 | .vidioc_s_audio = vidioc_s_audio, | 158 | .probe = radio_isa_probe, |
333 | .vidioc_g_input = vidioc_g_input, | 159 | .remove = radio_isa_remove, |
334 | .vidioc_s_input = vidioc_s_input, | 160 | .driver = { |
335 | .vidioc_g_frequency = vidioc_g_frequency, | 161 | .name = "radio-aztech", |
336 | .vidioc_s_frequency = vidioc_s_frequency, | 162 | }, |
337 | .vidioc_queryctrl = vidioc_queryctrl, | 163 | }, |
338 | .vidioc_g_ctrl = vidioc_g_ctrl, | 164 | .io_params = io, |
339 | .vidioc_s_ctrl = vidioc_s_ctrl, | 165 | .radio_nr_params = radio_nr, |
166 | .io_ports = aztech_ioports, | ||
167 | .num_of_io_ports = ARRAY_SIZE(aztech_ioports), | ||
168 | .region_size = 2, | ||
169 | .card = "Aztech Radio", | ||
170 | .ops = &aztech_ops, | ||
171 | .has_stereo = true, | ||
172 | .max_volume = 3, | ||
340 | }; | 173 | }; |
341 | 174 | ||
342 | static int __init aztech_init(void) | 175 | static int __init aztech_init(void) |
343 | { | 176 | { |
344 | struct aztech *az = &aztech_card; | 177 | return isa_register_driver(&aztech_driver.driver, AZTECH_MAX); |
345 | struct v4l2_device *v4l2_dev = &az->v4l2_dev; | ||
346 | int res; | ||
347 | |||
348 | strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name)); | ||
349 | az->io = io; | ||
350 | |||
351 | if (az->io == -1) { | ||
352 | v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n"); | ||
353 | return -EINVAL; | ||
354 | } | ||
355 | |||
356 | if (!request_region(az->io, 2, "aztech")) { | ||
357 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io); | ||
358 | return -EBUSY; | ||
359 | } | ||
360 | |||
361 | res = v4l2_device_register(NULL, v4l2_dev); | ||
362 | if (res < 0) { | ||
363 | release_region(az->io, 2); | ||
364 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
365 | return res; | ||
366 | } | ||
367 | |||
368 | mutex_init(&az->lock); | ||
369 | strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name)); | ||
370 | az->vdev.v4l2_dev = v4l2_dev; | ||
371 | az->vdev.fops = &aztech_fops; | ||
372 | az->vdev.ioctl_ops = &aztech_ioctl_ops; | ||
373 | az->vdev.release = video_device_release_empty; | ||
374 | video_set_drvdata(&az->vdev, az); | ||
375 | /* mute card - prevents noisy bootups */ | ||
376 | outb(0, az->io); | ||
377 | |||
378 | if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
379 | v4l2_device_unregister(v4l2_dev); | ||
380 | release_region(az->io, 2); | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | |||
384 | v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); | ||
385 | return 0; | ||
386 | } | 178 | } |
387 | 179 | ||
388 | static void __exit aztech_exit(void) | 180 | static void __exit aztech_exit(void) |
389 | { | 181 | { |
390 | struct aztech *az = &aztech_card; | 182 | isa_unregister_driver(&aztech_driver.driver); |
391 | |||
392 | video_unregister_device(&az->vdev); | ||
393 | v4l2_device_unregister(&az->v4l2_dev); | ||
394 | release_region(az->io, 2); | ||
395 | } | 183 | } |
396 | 184 | ||
397 | module_init(aztech_init); | 185 | module_init(aztech_init); |
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 36ce0611c037..2e639ce6f256 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c | |||
@@ -1,4 +1,7 @@ | |||
1 | /* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi> | 1 | /* |
2 | * GemTek radio card driver | ||
3 | * | ||
4 | * Copyright 1998 Jonas Munsin <jmunsin@iki.fi> | ||
2 | * | 5 | * |
3 | * GemTek hasn't released any specs on the card, so the protocol had to | 6 | * GemTek hasn't released any specs on the card, so the protocol had to |
4 | * be reverse engineered with dosemu. | 7 | * be reverse engineered with dosemu. |
@@ -11,9 +14,12 @@ | |||
11 | * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> | 14 | * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> |
12 | * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> | 15 | * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> |
13 | * | 16 | * |
14 | * TODO: Allow for more than one of these foolish entities :-) | 17 | * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> |
15 | * | ||
16 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> | 18 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> |
19 | * | ||
20 | * Note: this card seems to swap the left and right audio channels! | ||
21 | * | ||
22 | * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. | ||
17 | */ | 23 | */ |
18 | 24 | ||
19 | #include <linux/module.h> /* Modules */ | 25 | #include <linux/module.h> /* Modules */ |
@@ -23,8 +29,10 @@ | |||
23 | #include <linux/videodev2.h> /* kernel radio structs */ | 29 | #include <linux/videodev2.h> /* kernel radio structs */ |
24 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
25 | #include <linux/io.h> /* outb, outb_p */ | 31 | #include <linux/io.h> /* outb, outb_p */ |
32 | #include <linux/slab.h> | ||
26 | #include <media/v4l2-ioctl.h> | 33 | #include <media/v4l2-ioctl.h> |
27 | #include <media/v4l2-device.h> | 34 | #include <media/v4l2-device.h> |
35 | #include "radio-isa.h" | ||
28 | 36 | ||
29 | /* | 37 | /* |
30 | * Module info. | 38 | * Module info. |
@@ -33,7 +41,7 @@ | |||
33 | MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>"); | 41 | MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>"); |
34 | MODULE_DESCRIPTION("A driver for the GemTek Radio card."); | 42 | MODULE_DESCRIPTION("A driver for the GemTek Radio card."); |
35 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
36 | MODULE_VERSION("0.0.4"); | 44 | MODULE_VERSION("1.0.0"); |
37 | 45 | ||
38 | /* | 46 | /* |
39 | * Module params. | 47 | * Module params. |
@@ -46,45 +54,29 @@ MODULE_VERSION("0.0.4"); | |||
46 | #define CONFIG_RADIO_GEMTEK_PROBE 1 | 54 | #define CONFIG_RADIO_GEMTEK_PROBE 1 |
47 | #endif | 55 | #endif |
48 | 56 | ||
49 | static int io = CONFIG_RADIO_GEMTEK_PORT; | 57 | #define GEMTEK_MAX 4 |
50 | static bool probe = CONFIG_RADIO_GEMTEK_PROBE; | ||
51 | static bool hardmute; | ||
52 | static bool shutdown = 1; | ||
53 | static bool keepmuted = 1; | ||
54 | static bool initmute = 1; | ||
55 | static int radio_nr = -1; | ||
56 | 58 | ||
57 | module_param(io, int, 0444); | 59 | static bool probe = CONFIG_RADIO_GEMTEK_PROBE; |
58 | MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " | 60 | static bool hardmute; |
59 | "probing is disabled or fails. The most common I/O ports are: 0x20c " | 61 | static int io[GEMTEK_MAX] = { [0] = CONFIG_RADIO_GEMTEK_PORT, |
60 | "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " | 62 | [1 ... (GEMTEK_MAX - 1)] = -1 }; |
61 | "work for the combined sound/radiocard)."); | 63 | static int radio_nr[GEMTEK_MAX] = { [0 ... (GEMTEK_MAX - 1)] = -1 }; |
62 | 64 | ||
63 | module_param(probe, bool, 0444); | 65 | module_param(probe, bool, 0444); |
64 | MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " | 66 | MODULE_PARM_DESC(probe, "Enable automatic device probing."); |
65 | "common I/O ports used by the card are probed."); | ||
66 | 67 | ||
67 | module_param(hardmute, bool, 0644); | 68 | module_param(hardmute, bool, 0644); |
68 | MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " | 69 | MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may " |
69 | "reduce static noise."); | 70 | "reduce static noise."); |
70 | 71 | ||
71 | module_param(shutdown, bool, 0644); | 72 | module_param_array(io, int, NULL, 0444); |
72 | MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " | 73 | MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic " |
73 | "module is unloaded."); | 74 | "probing is disabled or fails. The most common I/O ports are: 0x20c " |
74 | 75 | "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " | |
75 | module_param(keepmuted, bool, 0644); | 76 | "work for the combined sound/radiocard)."); |
76 | MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); | ||
77 | |||
78 | module_param(initmute, bool, 0444); | ||
79 | MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); | ||
80 | |||
81 | module_param(radio_nr, int, 0444); | ||
82 | 77 | ||
83 | /* | 78 | module_param_array(radio_nr, int, NULL, 0444); |
84 | * Functions for controlling the card. | 79 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); |
85 | */ | ||
86 | #define GEMTEK_LOWFREQ (87*16000) | ||
87 | #define GEMTEK_HIGHFREQ (108*16000) | ||
88 | 80 | ||
89 | /* | 81 | /* |
90 | * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal | 82 | * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal |
@@ -108,18 +100,11 @@ module_param(radio_nr, int, 0444); | |||
108 | #define LONG_DELAY 75 /* usec */ | 100 | #define LONG_DELAY 75 /* usec */ |
109 | 101 | ||
110 | struct gemtek { | 102 | struct gemtek { |
111 | struct v4l2_device v4l2_dev; | 103 | struct radio_isa_card isa; |
112 | struct video_device vdev; | 104 | bool muted; |
113 | struct mutex lock; | ||
114 | unsigned long lastfreq; | ||
115 | int muted; | ||
116 | int verified; | ||
117 | int io; | ||
118 | u32 bu2614data; | 105 | u32 bu2614data; |
119 | }; | 106 | }; |
120 | 107 | ||
121 | static struct gemtek gemtek_card; | ||
122 | |||
123 | #define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ | 108 | #define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ |
124 | #define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ | 109 | #define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ |
125 | #define BU2614_VOID_BITS 4 /* unused */ | 110 | #define BU2614_VOID_BITS 4 /* unused */ |
@@ -166,31 +151,24 @@ static struct gemtek gemtek_card; | |||
166 | */ | 151 | */ |
167 | static void gemtek_bu2614_transmit(struct gemtek *gt) | 152 | static void gemtek_bu2614_transmit(struct gemtek *gt) |
168 | { | 153 | { |
154 | struct radio_isa_card *isa = >->isa; | ||
169 | int i, bit, q, mute; | 155 | int i, bit, q, mute; |
170 | 156 | ||
171 | mutex_lock(>->lock); | ||
172 | |||
173 | mute = gt->muted ? GEMTEK_MT : 0x00; | 157 | mute = gt->muted ? GEMTEK_MT : 0x00; |
174 | 158 | ||
175 | outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); | 159 | outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, isa->io); |
176 | udelay(SHORT_DELAY); | ||
177 | outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); | ||
178 | udelay(LONG_DELAY); | 160 | udelay(LONG_DELAY); |
179 | 161 | ||
180 | for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { | 162 | for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { |
181 | bit = (q & 1) ? GEMTEK_DA : 0; | 163 | bit = (q & 1) ? GEMTEK_DA : 0; |
182 | outb_p(mute | GEMTEK_CE | bit, gt->io); | 164 | outb_p(mute | GEMTEK_CE | bit, isa->io); |
183 | udelay(SHORT_DELAY); | 165 | udelay(SHORT_DELAY); |
184 | outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io); | 166 | outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, isa->io); |
185 | udelay(SHORT_DELAY); | 167 | udelay(SHORT_DELAY); |
186 | } | 168 | } |
187 | 169 | ||
188 | outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); | 170 | outb_p(mute | GEMTEK_DA | GEMTEK_CK, isa->io); |
189 | udelay(SHORT_DELAY); | 171 | udelay(SHORT_DELAY); |
190 | outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); | ||
191 | udelay(LONG_DELAY); | ||
192 | |||
193 | mutex_unlock(>->lock); | ||
194 | } | 172 | } |
195 | 173 | ||
196 | /* | 174 | /* |
@@ -198,21 +176,27 @@ static void gemtek_bu2614_transmit(struct gemtek *gt) | |||
198 | */ | 176 | */ |
199 | static unsigned long gemtek_convfreq(unsigned long freq) | 177 | static unsigned long gemtek_convfreq(unsigned long freq) |
200 | { | 178 | { |
201 | return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ; | 179 | return ((freq << FSCALE) + IF_OFFSET + REF_FREQ / 2) / REF_FREQ; |
180 | } | ||
181 | |||
182 | static struct radio_isa_card *gemtek_alloc(void) | ||
183 | { | ||
184 | struct gemtek *gt = kzalloc(sizeof(*gt), GFP_KERNEL); | ||
185 | |||
186 | if (gt) | ||
187 | gt->muted = true; | ||
188 | return gt ? >->isa : NULL; | ||
202 | } | 189 | } |
203 | 190 | ||
204 | /* | 191 | /* |
205 | * Set FM-frequency. | 192 | * Set FM-frequency. |
206 | */ | 193 | */ |
207 | static void gemtek_setfreq(struct gemtek *gt, unsigned long freq) | 194 | static int gemtek_s_frequency(struct radio_isa_card *isa, u32 freq) |
208 | { | 195 | { |
209 | if (keepmuted && hardmute && gt->muted) | 196 | struct gemtek *gt = container_of(isa, struct gemtek, isa); |
210 | return; | ||
211 | 197 | ||
212 | freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ); | 198 | if (hardmute && gt->muted) |
213 | 199 | return 0; | |
214 | gt->lastfreq = freq; | ||
215 | gt->muted = 0; | ||
216 | 200 | ||
217 | gemtek_bu2614_set(gt, BU2614_PORT, 0); | 201 | gemtek_bu2614_set(gt, BU2614_PORT, 0); |
218 | gemtek_bu2614_set(gt, BU2614_FMES, 0); | 202 | gemtek_bu2614_set(gt, BU2614_FMES, 0); |
@@ -220,23 +204,25 @@ static void gemtek_setfreq(struct gemtek *gt, unsigned long freq) | |||
220 | gemtek_bu2614_set(gt, BU2614_SWAL, 0); | 204 | gemtek_bu2614_set(gt, BU2614_SWAL, 0); |
221 | gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ | 205 | gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ |
222 | gemtek_bu2614_set(gt, BU2614_TEST, 0); | 206 | gemtek_bu2614_set(gt, BU2614_TEST, 0); |
223 | |||
224 | gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); | 207 | gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); |
225 | gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); | 208 | gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); |
226 | |||
227 | gemtek_bu2614_transmit(gt); | 209 | gemtek_bu2614_transmit(gt); |
210 | return 0; | ||
228 | } | 211 | } |
229 | 212 | ||
230 | /* | 213 | /* |
231 | * Set mute flag. | 214 | * Set mute flag. |
232 | */ | 215 | */ |
233 | static void gemtek_mute(struct gemtek *gt) | 216 | static int gemtek_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
234 | { | 217 | { |
218 | struct gemtek *gt = container_of(isa, struct gemtek, isa); | ||
235 | int i; | 219 | int i; |
236 | 220 | ||
237 | gt->muted = 1; | 221 | gt->muted = mute; |
238 | |||
239 | if (hardmute) { | 222 | if (hardmute) { |
223 | if (!mute) | ||
224 | return gemtek_s_frequency(isa, isa->freq); | ||
225 | |||
240 | /* Turn off PLL, disable data output */ | 226 | /* Turn off PLL, disable data output */ |
241 | gemtek_bu2614_set(gt, BU2614_PORT, 0); | 227 | gemtek_bu2614_set(gt, BU2614_PORT, 0); |
242 | gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ | 228 | gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ |
@@ -247,367 +233,85 @@ static void gemtek_mute(struct gemtek *gt) | |||
247 | gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); | 233 | gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); |
248 | gemtek_bu2614_set(gt, BU2614_FREQ, 0); | 234 | gemtek_bu2614_set(gt, BU2614_FREQ, 0); |
249 | gemtek_bu2614_transmit(gt); | 235 | gemtek_bu2614_transmit(gt); |
250 | return; | 236 | return 0; |
251 | } | 237 | } |
252 | 238 | ||
253 | mutex_lock(>->lock); | ||
254 | |||
255 | /* Read bus contents (CE, CK and DA). */ | 239 | /* Read bus contents (CE, CK and DA). */ |
256 | i = inb_p(gt->io); | 240 | i = inb_p(isa->io); |
257 | /* Write it back with mute flag set. */ | 241 | /* Write it back with mute flag set. */ |
258 | outb_p((i >> 5) | GEMTEK_MT, gt->io); | 242 | outb_p((i >> 5) | (mute ? GEMTEK_MT : 0), isa->io); |
259 | udelay(SHORT_DELAY); | 243 | udelay(SHORT_DELAY); |
260 | 244 | return 0; | |
261 | mutex_unlock(>->lock); | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * Unset mute flag. | ||
266 | */ | ||
267 | static void gemtek_unmute(struct gemtek *gt) | ||
268 | { | ||
269 | int i; | ||
270 | |||
271 | gt->muted = 0; | ||
272 | if (hardmute) { | ||
273 | /* Turn PLL back on. */ | ||
274 | gemtek_setfreq(gt, gt->lastfreq); | ||
275 | return; | ||
276 | } | ||
277 | mutex_lock(>->lock); | ||
278 | |||
279 | i = inb_p(gt->io); | ||
280 | outb_p(i >> 5, gt->io); | ||
281 | udelay(SHORT_DELAY); | ||
282 | |||
283 | mutex_unlock(>->lock); | ||
284 | } | 245 | } |
285 | 246 | ||
286 | /* | 247 | static u32 gemtek_g_rxsubchans(struct radio_isa_card *isa) |
287 | * Get signal strength (= stereo status). | ||
288 | */ | ||
289 | static inline int gemtek_getsigstr(struct gemtek *gt) | ||
290 | { | 248 | { |
291 | int sig; | 249 | if (inb_p(isa->io) & GEMTEK_NS) |
292 | 250 | return V4L2_TUNER_SUB_MONO; | |
293 | mutex_lock(>->lock); | 251 | return V4L2_TUNER_SUB_STEREO; |
294 | sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1; | ||
295 | mutex_unlock(>->lock); | ||
296 | return sig; | ||
297 | } | 252 | } |
298 | 253 | ||
299 | /* | 254 | /* |
300 | * Check if requested card acts like GemTek Radio card. | 255 | * Check if requested card acts like GemTek Radio card. |
301 | */ | 256 | */ |
302 | static int gemtek_verify(struct gemtek *gt, int port) | 257 | static bool gemtek_probe(struct radio_isa_card *isa, int io) |
303 | { | 258 | { |
304 | int i, q; | 259 | int i, q; |
305 | 260 | ||
306 | if (gt->verified == port) | 261 | q = inb_p(io); /* Read bus contents before probing. */ |
307 | return 1; | ||
308 | |||
309 | mutex_lock(>->lock); | ||
310 | |||
311 | q = inb_p(port); /* Read bus contents before probing. */ | ||
312 | /* Try to turn on CE, CK and DA respectively and check if card responds | 262 | /* Try to turn on CE, CK and DA respectively and check if card responds |
313 | properly. */ | 263 | properly. */ |
314 | for (i = 0; i < 3; ++i) { | 264 | for (i = 0; i < 3; ++i) { |
315 | outb_p(1 << i, port); | 265 | outb_p(1 << i, io); |
316 | udelay(SHORT_DELAY); | 266 | udelay(SHORT_DELAY); |
317 | 267 | ||
318 | if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { | 268 | if ((inb_p(io) & ~GEMTEK_NS) != (0x17 | (1 << (i + 5)))) |
319 | mutex_unlock(>->lock); | 269 | return false; |
320 | return 0; | ||
321 | } | ||
322 | } | 270 | } |
323 | outb_p(q >> 5, port); /* Write bus contents back. */ | 271 | outb_p(q >> 5, io); /* Write bus contents back. */ |
324 | udelay(SHORT_DELAY); | 272 | udelay(SHORT_DELAY); |
325 | 273 | return true; | |
326 | mutex_unlock(>->lock); | ||
327 | gt->verified = port; | ||
328 | |||
329 | return 1; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Automatic probing for card. | ||
334 | */ | ||
335 | static int gemtek_probe(struct gemtek *gt) | ||
336 | { | ||
337 | struct v4l2_device *v4l2_dev = >->v4l2_dev; | ||
338 | int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; | ||
339 | int i; | ||
340 | |||
341 | if (!probe) { | ||
342 | v4l2_info(v4l2_dev, "Automatic device probing disabled.\n"); | ||
343 | return -1; | ||
344 | } | ||
345 | |||
346 | v4l2_info(v4l2_dev, "Automatic device probing enabled.\n"); | ||
347 | |||
348 | for (i = 0; i < ARRAY_SIZE(ioports); ++i) { | ||
349 | v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]); | ||
350 | |||
351 | if (!request_region(ioports[i], 1, "gemtek-probe")) { | ||
352 | v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n", | ||
353 | ioports[i]); | ||
354 | continue; | ||
355 | } | ||
356 | |||
357 | if (gemtek_verify(gt, ioports[i])) { | ||
358 | v4l2_info(v4l2_dev, "Card found from I/O port " | ||
359 | "0x%x!\n", ioports[i]); | ||
360 | |||
361 | release_region(ioports[i], 1); | ||
362 | gt->io = ioports[i]; | ||
363 | return gt->io; | ||
364 | } | ||
365 | |||
366 | release_region(ioports[i], 1); | ||
367 | } | ||
368 | |||
369 | v4l2_err(v4l2_dev, "Automatic probing failed!\n"); | ||
370 | return -1; | ||
371 | } | 274 | } |
372 | 275 | ||
373 | /* | 276 | static const struct radio_isa_ops gemtek_ops = { |
374 | * Video 4 Linux stuff. | 277 | .alloc = gemtek_alloc, |
375 | */ | 278 | .probe = gemtek_probe, |
376 | 279 | .s_mute_volume = gemtek_s_mute_volume, | |
377 | static const struct v4l2_file_operations gemtek_fops = { | 280 | .s_frequency = gemtek_s_frequency, |
378 | .owner = THIS_MODULE, | 281 | .g_rxsubchans = gemtek_g_rxsubchans, |
379 | .unlocked_ioctl = video_ioctl2, | ||
380 | }; | 282 | }; |
381 | 283 | ||
382 | static int vidioc_querycap(struct file *file, void *priv, | 284 | static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; |
383 | struct v4l2_capability *v) | 285 | |
384 | { | 286 | static struct radio_isa_driver gemtek_driver = { |
385 | strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); | 287 | .driver = { |
386 | strlcpy(v->card, "GemTek", sizeof(v->card)); | 288 | .match = radio_isa_match, |
387 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | 289 | .probe = radio_isa_probe, |
388 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | 290 | .remove = radio_isa_remove, |
389 | return 0; | 291 | .driver = { |
390 | } | 292 | .name = "radio-gemtek", |
391 | 293 | }, | |
392 | static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) | 294 | }, |
393 | { | 295 | .io_params = io, |
394 | struct gemtek *gt = video_drvdata(file); | 296 | .radio_nr_params = radio_nr, |
395 | 297 | .io_ports = gemtek_ioports, | |
396 | if (v->index > 0) | 298 | .num_of_io_ports = ARRAY_SIZE(gemtek_ioports), |
397 | return -EINVAL; | 299 | .region_size = 1, |
398 | 300 | .card = "GemTek Radio", | |
399 | strlcpy(v->name, "FM", sizeof(v->name)); | 301 | .ops = &gemtek_ops, |
400 | v->type = V4L2_TUNER_RADIO; | 302 | .has_stereo = true, |
401 | v->rangelow = GEMTEK_LOWFREQ; | ||
402 | v->rangehigh = GEMTEK_HIGHFREQ; | ||
403 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
404 | v->signal = 0xffff * gemtek_getsigstr(gt); | ||
405 | if (v->signal) { | ||
406 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
407 | v->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
408 | } else { | ||
409 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
410 | v->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
411 | } | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) | ||
416 | { | ||
417 | return (v->index != 0) ? -EINVAL : 0; | ||
418 | } | ||
419 | |||
420 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
421 | struct v4l2_frequency *f) | ||
422 | { | ||
423 | struct gemtek *gt = video_drvdata(file); | ||
424 | |||
425 | if (f->tuner != 0) | ||
426 | return -EINVAL; | ||
427 | f->type = V4L2_TUNER_RADIO; | ||
428 | f->frequency = gt->lastfreq; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
433 | struct v4l2_frequency *f) | ||
434 | { | ||
435 | struct gemtek *gt = video_drvdata(file); | ||
436 | |||
437 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
438 | return -EINVAL; | ||
439 | gemtek_setfreq(gt, f->frequency); | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
444 | struct v4l2_queryctrl *qc) | ||
445 | { | ||
446 | switch (qc->id) { | ||
447 | case V4L2_CID_AUDIO_MUTE: | ||
448 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
449 | default: | ||
450 | return -EINVAL; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
455 | struct v4l2_control *ctrl) | ||
456 | { | ||
457 | struct gemtek *gt = video_drvdata(file); | ||
458 | |||
459 | switch (ctrl->id) { | ||
460 | case V4L2_CID_AUDIO_MUTE: | ||
461 | ctrl->value = gt->muted; | ||
462 | return 0; | ||
463 | } | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | |||
467 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
468 | struct v4l2_control *ctrl) | ||
469 | { | ||
470 | struct gemtek *gt = video_drvdata(file); | ||
471 | |||
472 | switch (ctrl->id) { | ||
473 | case V4L2_CID_AUDIO_MUTE: | ||
474 | if (ctrl->value) | ||
475 | gemtek_mute(gt); | ||
476 | else | ||
477 | gemtek_unmute(gt); | ||
478 | return 0; | ||
479 | } | ||
480 | return -EINVAL; | ||
481 | } | ||
482 | |||
483 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
484 | { | ||
485 | *i = 0; | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
490 | { | ||
491 | return (i != 0) ? -EINVAL : 0; | ||
492 | } | ||
493 | |||
494 | static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) | ||
495 | { | ||
496 | a->index = 0; | ||
497 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
498 | a->capability = V4L2_AUDCAP_STEREO; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) | ||
503 | { | ||
504 | return (a->index != 0) ? -EINVAL : 0; | ||
505 | } | ||
506 | |||
507 | static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { | ||
508 | .vidioc_querycap = vidioc_querycap, | ||
509 | .vidioc_g_tuner = vidioc_g_tuner, | ||
510 | .vidioc_s_tuner = vidioc_s_tuner, | ||
511 | .vidioc_g_audio = vidioc_g_audio, | ||
512 | .vidioc_s_audio = vidioc_s_audio, | ||
513 | .vidioc_g_input = vidioc_g_input, | ||
514 | .vidioc_s_input = vidioc_s_input, | ||
515 | .vidioc_g_frequency = vidioc_g_frequency, | ||
516 | .vidioc_s_frequency = vidioc_s_frequency, | ||
517 | .vidioc_queryctrl = vidioc_queryctrl, | ||
518 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
519 | .vidioc_s_ctrl = vidioc_s_ctrl | ||
520 | }; | 303 | }; |
521 | 304 | ||
522 | /* | ||
523 | * Initialization / cleanup related stuff. | ||
524 | */ | ||
525 | |||
526 | static int __init gemtek_init(void) | 305 | static int __init gemtek_init(void) |
527 | { | 306 | { |
528 | struct gemtek *gt = &gemtek_card; | 307 | gemtek_driver.probe = probe; |
529 | struct v4l2_device *v4l2_dev = >->v4l2_dev; | 308 | return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX); |
530 | int res; | ||
531 | |||
532 | strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name)); | ||
533 | |||
534 | v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n"); | ||
535 | |||
536 | mutex_init(>->lock); | ||
537 | |||
538 | gt->verified = -1; | ||
539 | gt->io = io; | ||
540 | gemtek_probe(gt); | ||
541 | if (gt->io) { | ||
542 | if (!request_region(gt->io, 1, "gemtek")) { | ||
543 | v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io); | ||
544 | return -EBUSY; | ||
545 | } | ||
546 | |||
547 | if (!gemtek_verify(gt, gt->io)) | ||
548 | v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not " | ||
549 | "respond properly, check your " | ||
550 | "configuration.\n", gt->io); | ||
551 | else | ||
552 | v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io); | ||
553 | } else if (probe) { | ||
554 | v4l2_err(v4l2_dev, "Automatic probing failed and no " | ||
555 | "fixed I/O port defined.\n"); | ||
556 | return -ENODEV; | ||
557 | } else { | ||
558 | v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed " | ||
559 | "I/O port defined."); | ||
560 | return -EINVAL; | ||
561 | } | ||
562 | |||
563 | res = v4l2_device_register(NULL, v4l2_dev); | ||
564 | if (res < 0) { | ||
565 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
566 | release_region(gt->io, 1); | ||
567 | return res; | ||
568 | } | ||
569 | |||
570 | strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name)); | ||
571 | gt->vdev.v4l2_dev = v4l2_dev; | ||
572 | gt->vdev.fops = &gemtek_fops; | ||
573 | gt->vdev.ioctl_ops = &gemtek_ioctl_ops; | ||
574 | gt->vdev.release = video_device_release_empty; | ||
575 | video_set_drvdata(>->vdev, gt); | ||
576 | |||
577 | /* Set defaults */ | ||
578 | gt->lastfreq = GEMTEK_LOWFREQ; | ||
579 | gt->bu2614data = 0; | ||
580 | |||
581 | if (initmute) | ||
582 | gemtek_mute(gt); | ||
583 | |||
584 | if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
585 | v4l2_device_unregister(v4l2_dev); | ||
586 | release_region(gt->io, 1); | ||
587 | return -EBUSY; | ||
588 | } | ||
589 | |||
590 | return 0; | ||
591 | } | 309 | } |
592 | 310 | ||
593 | /* | ||
594 | * Module cleanup | ||
595 | */ | ||
596 | static void __exit gemtek_exit(void) | 311 | static void __exit gemtek_exit(void) |
597 | { | 312 | { |
598 | struct gemtek *gt = &gemtek_card; | 313 | hardmute = 1; /* Turn off PLL */ |
599 | struct v4l2_device *v4l2_dev = >->v4l2_dev; | 314 | isa_unregister_driver(&gemtek_driver.driver); |
600 | |||
601 | if (shutdown) { | ||
602 | hardmute = 1; /* Turn off PLL */ | ||
603 | gemtek_mute(gt); | ||
604 | } else { | ||
605 | v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n"); | ||
606 | } | ||
607 | |||
608 | video_unregister_device(>->vdev); | ||
609 | v4l2_device_unregister(>->v4l2_dev); | ||
610 | release_region(gt->io, 1); | ||
611 | } | 315 | } |
612 | 316 | ||
613 | module_init(gemtek_init); | 317 | module_init(gemtek_init); |
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c new file mode 100644 index 000000000000..06f906351fad --- /dev/null +++ b/drivers/media/radio/radio-isa.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | * Framework for ISA radio drivers. | ||
3 | * This takes care of all the V4L2 scaffolding, allowing the ISA drivers | ||
4 | * to concentrate on the actual hardware operation. | ||
5 | * | ||
6 | * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/ioport.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | #include <linux/io.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <media/v4l2-device.h> | ||
31 | #include <media/v4l2-ioctl.h> | ||
32 | #include <media/v4l2-fh.h> | ||
33 | #include <media/v4l2-ctrls.h> | ||
34 | #include <media/v4l2-event.h> | ||
35 | |||
36 | #include "radio-isa.h" | ||
37 | |||
38 | MODULE_AUTHOR("Hans Verkuil"); | ||
39 | MODULE_DESCRIPTION("A framework for ISA radio drivers."); | ||
40 | MODULE_LICENSE("GPL"); | ||
41 | |||
42 | #define FREQ_LOW (87U * 16000U) | ||
43 | #define FREQ_HIGH (108U * 16000U) | ||
44 | |||
45 | static int radio_isa_querycap(struct file *file, void *priv, | ||
46 | struct v4l2_capability *v) | ||
47 | { | ||
48 | struct radio_isa_card *isa = video_drvdata(file); | ||
49 | |||
50 | strlcpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver)); | ||
51 | strlcpy(v->card, isa->drv->card, sizeof(v->card)); | ||
52 | snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); | ||
53 | |||
54 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
55 | v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS; | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int radio_isa_g_tuner(struct file *file, void *priv, | ||
60 | struct v4l2_tuner *v) | ||
61 | { | ||
62 | struct radio_isa_card *isa = video_drvdata(file); | ||
63 | const struct radio_isa_ops *ops = isa->drv->ops; | ||
64 | |||
65 | if (v->index > 0) | ||
66 | return -EINVAL; | ||
67 | |||
68 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
69 | v->type = V4L2_TUNER_RADIO; | ||
70 | v->rangelow = FREQ_LOW; | ||
71 | v->rangehigh = FREQ_HIGH; | ||
72 | v->capability = V4L2_TUNER_CAP_LOW; | ||
73 | if (isa->drv->has_stereo) | ||
74 | v->capability |= V4L2_TUNER_CAP_STEREO; | ||
75 | |||
76 | if (ops->g_rxsubchans) | ||
77 | v->rxsubchans = ops->g_rxsubchans(isa); | ||
78 | else | ||
79 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
80 | v->audmode = isa->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; | ||
81 | if (ops->g_signal) | ||
82 | v->signal = ops->g_signal(isa); | ||
83 | else | ||
84 | v->signal = (v->rxsubchans & V4L2_TUNER_SUB_STEREO) ? | ||
85 | 0xffff : 0; | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int radio_isa_s_tuner(struct file *file, void *priv, | ||
90 | struct v4l2_tuner *v) | ||
91 | { | ||
92 | struct radio_isa_card *isa = video_drvdata(file); | ||
93 | const struct radio_isa_ops *ops = isa->drv->ops; | ||
94 | |||
95 | if (v->index) | ||
96 | return -EINVAL; | ||
97 | if (ops->s_stereo) { | ||
98 | isa->stereo = (v->audmode == V4L2_TUNER_MODE_STEREO); | ||
99 | return ops->s_stereo(isa, isa->stereo); | ||
100 | } | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int radio_isa_s_frequency(struct file *file, void *priv, | ||
105 | struct v4l2_frequency *f) | ||
106 | { | ||
107 | struct radio_isa_card *isa = video_drvdata(file); | ||
108 | int res; | ||
109 | |||
110 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
111 | return -EINVAL; | ||
112 | f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH); | ||
113 | res = isa->drv->ops->s_frequency(isa, f->frequency); | ||
114 | if (res == 0) | ||
115 | isa->freq = f->frequency; | ||
116 | return res; | ||
117 | } | ||
118 | |||
119 | static int radio_isa_g_frequency(struct file *file, void *priv, | ||
120 | struct v4l2_frequency *f) | ||
121 | { | ||
122 | struct radio_isa_card *isa = video_drvdata(file); | ||
123 | |||
124 | if (f->tuner != 0) | ||
125 | return -EINVAL; | ||
126 | f->type = V4L2_TUNER_RADIO; | ||
127 | f->frequency = isa->freq; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int radio_isa_s_ctrl(struct v4l2_ctrl *ctrl) | ||
132 | { | ||
133 | struct radio_isa_card *isa = | ||
134 | container_of(ctrl->handler, struct radio_isa_card, hdl); | ||
135 | |||
136 | switch (ctrl->id) { | ||
137 | case V4L2_CID_AUDIO_MUTE: | ||
138 | return isa->drv->ops->s_mute_volume(isa, ctrl->val, | ||
139 | isa->volume ? isa->volume->val : 0); | ||
140 | } | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | |||
144 | static int radio_isa_log_status(struct file *file, void *priv) | ||
145 | { | ||
146 | struct radio_isa_card *isa = video_drvdata(file); | ||
147 | |||
148 | v4l2_info(&isa->v4l2_dev, "I/O Port = 0x%03x\n", isa->io); | ||
149 | v4l2_ctrl_handler_log_status(&isa->hdl, isa->v4l2_dev.name); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int radio_isa_subscribe_event(struct v4l2_fh *fh, | ||
154 | struct v4l2_event_subscription *sub) | ||
155 | { | ||
156 | if (sub->type == V4L2_EVENT_CTRL) | ||
157 | return v4l2_event_subscribe(fh, sub, 0); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = { | ||
162 | .s_ctrl = radio_isa_s_ctrl, | ||
163 | }; | ||
164 | |||
165 | static const struct v4l2_file_operations radio_isa_fops = { | ||
166 | .owner = THIS_MODULE, | ||
167 | .open = v4l2_fh_open, | ||
168 | .release = v4l2_fh_release, | ||
169 | .poll = v4l2_ctrl_poll, | ||
170 | .unlocked_ioctl = video_ioctl2, | ||
171 | }; | ||
172 | |||
173 | static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = { | ||
174 | .vidioc_querycap = radio_isa_querycap, | ||
175 | .vidioc_g_tuner = radio_isa_g_tuner, | ||
176 | .vidioc_s_tuner = radio_isa_s_tuner, | ||
177 | .vidioc_g_frequency = radio_isa_g_frequency, | ||
178 | .vidioc_s_frequency = radio_isa_s_frequency, | ||
179 | .vidioc_log_status = radio_isa_log_status, | ||
180 | .vidioc_subscribe_event = radio_isa_subscribe_event, | ||
181 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
182 | }; | ||
183 | |||
184 | int radio_isa_match(struct device *pdev, unsigned int dev) | ||
185 | { | ||
186 | struct radio_isa_driver *drv = pdev->platform_data; | ||
187 | |||
188 | return drv->probe || drv->io_params[dev] >= 0; | ||
189 | } | ||
190 | EXPORT_SYMBOL_GPL(radio_isa_match); | ||
191 | |||
192 | static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io) | ||
193 | { | ||
194 | int i; | ||
195 | |||
196 | for (i = 0; i < drv->num_of_io_ports; i++) | ||
197 | if (drv->io_ports[i] == io) | ||
198 | return true; | ||
199 | return false; | ||
200 | } | ||
201 | |||
202 | int radio_isa_probe(struct device *pdev, unsigned int dev) | ||
203 | { | ||
204 | struct radio_isa_driver *drv = pdev->platform_data; | ||
205 | const struct radio_isa_ops *ops = drv->ops; | ||
206 | struct v4l2_device *v4l2_dev; | ||
207 | struct radio_isa_card *isa; | ||
208 | int res; | ||
209 | |||
210 | isa = drv->ops->alloc(); | ||
211 | if (isa == NULL) | ||
212 | return -ENOMEM; | ||
213 | dev_set_drvdata(pdev, isa); | ||
214 | isa->drv = drv; | ||
215 | isa->io = drv->io_params[dev]; | ||
216 | v4l2_dev = &isa->v4l2_dev; | ||
217 | strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name)); | ||
218 | |||
219 | if (drv->probe && ops->probe) { | ||
220 | int i; | ||
221 | |||
222 | for (i = 0; i < drv->num_of_io_ports; ++i) { | ||
223 | int io = drv->io_ports[i]; | ||
224 | |||
225 | if (request_region(io, drv->region_size, v4l2_dev->name)) { | ||
226 | bool found = ops->probe(isa, io); | ||
227 | |||
228 | release_region(io, drv->region_size); | ||
229 | if (found) { | ||
230 | isa->io = io; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | if (!radio_isa_valid_io(drv, isa->io)) { | ||
238 | int i; | ||
239 | |||
240 | if (isa->io < 0) | ||
241 | return -ENODEV; | ||
242 | v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x", | ||
243 | drv->io_ports[0]); | ||
244 | for (i = 1; i < drv->num_of_io_ports; i++) | ||
245 | printk(KERN_CONT "/0x%03x", drv->io_ports[i]); | ||
246 | printk(KERN_CONT ".\n"); | ||
247 | kfree(isa); | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | |||
251 | if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) { | ||
252 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io); | ||
253 | kfree(isa); | ||
254 | return -EBUSY; | ||
255 | } | ||
256 | |||
257 | res = v4l2_device_register(pdev, v4l2_dev); | ||
258 | if (res < 0) { | ||
259 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
260 | goto err_dev_reg; | ||
261 | } | ||
262 | |||
263 | v4l2_ctrl_handler_init(&isa->hdl, 1); | ||
264 | isa->mute = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops, | ||
265 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | ||
266 | if (drv->max_volume) | ||
267 | isa->volume = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops, | ||
268 | V4L2_CID_AUDIO_VOLUME, 0, drv->max_volume, 1, | ||
269 | drv->max_volume); | ||
270 | v4l2_dev->ctrl_handler = &isa->hdl; | ||
271 | if (isa->hdl.error) { | ||
272 | res = isa->hdl.error; | ||
273 | v4l2_err(v4l2_dev, "Could not register controls\n"); | ||
274 | goto err_hdl; | ||
275 | } | ||
276 | if (drv->max_volume) | ||
277 | v4l2_ctrl_cluster(2, &isa->mute); | ||
278 | v4l2_dev->ctrl_handler = &isa->hdl; | ||
279 | |||
280 | mutex_init(&isa->lock); | ||
281 | isa->vdev.lock = &isa->lock; | ||
282 | strlcpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name)); | ||
283 | isa->vdev.v4l2_dev = v4l2_dev; | ||
284 | isa->vdev.fops = &radio_isa_fops; | ||
285 | isa->vdev.ioctl_ops = &radio_isa_ioctl_ops; | ||
286 | isa->vdev.release = video_device_release_empty; | ||
287 | set_bit(V4L2_FL_USE_FH_PRIO, &isa->vdev.flags); | ||
288 | video_set_drvdata(&isa->vdev, isa); | ||
289 | isa->freq = FREQ_LOW; | ||
290 | isa->stereo = drv->has_stereo; | ||
291 | |||
292 | if (ops->init) | ||
293 | res = ops->init(isa); | ||
294 | if (!res) | ||
295 | res = v4l2_ctrl_handler_setup(&isa->hdl); | ||
296 | if (!res) | ||
297 | res = ops->s_frequency(isa, isa->freq); | ||
298 | if (!res && ops->s_stereo) | ||
299 | res = ops->s_stereo(isa, isa->stereo); | ||
300 | if (res < 0) { | ||
301 | v4l2_err(v4l2_dev, "Could not setup card\n"); | ||
302 | goto err_node_reg; | ||
303 | } | ||
304 | res = video_register_device(&isa->vdev, VFL_TYPE_RADIO, | ||
305 | drv->radio_nr_params[dev]); | ||
306 | if (res < 0) { | ||
307 | v4l2_err(v4l2_dev, "Could not register device node\n"); | ||
308 | goto err_node_reg; | ||
309 | } | ||
310 | |||
311 | v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n", | ||
312 | drv->card, isa->io); | ||
313 | return 0; | ||
314 | |||
315 | err_node_reg: | ||
316 | v4l2_ctrl_handler_free(&isa->hdl); | ||
317 | err_hdl: | ||
318 | v4l2_device_unregister(&isa->v4l2_dev); | ||
319 | err_dev_reg: | ||
320 | release_region(isa->io, drv->region_size); | ||
321 | kfree(isa); | ||
322 | return res; | ||
323 | } | ||
324 | EXPORT_SYMBOL_GPL(radio_isa_probe); | ||
325 | |||
326 | int radio_isa_remove(struct device *pdev, unsigned int dev) | ||
327 | { | ||
328 | struct radio_isa_card *isa = dev_get_drvdata(pdev); | ||
329 | const struct radio_isa_ops *ops = isa->drv->ops; | ||
330 | |||
331 | ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0); | ||
332 | video_unregister_device(&isa->vdev); | ||
333 | v4l2_ctrl_handler_free(&isa->hdl); | ||
334 | v4l2_device_unregister(&isa->v4l2_dev); | ||
335 | release_region(isa->io, isa->drv->region_size); | ||
336 | v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card); | ||
337 | kfree(isa); | ||
338 | return 0; | ||
339 | } | ||
340 | EXPORT_SYMBOL_GPL(radio_isa_remove); | ||
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h new file mode 100644 index 000000000000..8a0ea84d86de --- /dev/null +++ b/drivers/media/radio/radio-isa.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Framework for ISA radio drivers. | ||
3 | * This takes care of all the V4L2 scaffolding, allowing the ISA drivers | ||
4 | * to concentrate on the actual hardware operation. | ||
5 | * | ||
6 | * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #ifndef _RADIO_ISA_H_ | ||
24 | #define _RADIO_ISA_H_ | ||
25 | |||
26 | #include <linux/isa.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/v4l2-ctrls.h> | ||
30 | |||
31 | struct radio_isa_driver; | ||
32 | struct radio_isa_ops; | ||
33 | |||
34 | /* Core structure for radio ISA cards */ | ||
35 | struct radio_isa_card { | ||
36 | const struct radio_isa_driver *drv; | ||
37 | struct v4l2_device v4l2_dev; | ||
38 | struct v4l2_ctrl_handler hdl; | ||
39 | struct video_device vdev; | ||
40 | struct mutex lock; | ||
41 | const struct radio_isa_ops *ops; | ||
42 | struct { /* mute/volume cluster */ | ||
43 | struct v4l2_ctrl *mute; | ||
44 | struct v4l2_ctrl *volume; | ||
45 | }; | ||
46 | /* I/O port */ | ||
47 | int io; | ||
48 | |||
49 | /* Card is in stereo audio mode */ | ||
50 | bool stereo; | ||
51 | /* Current frequency */ | ||
52 | u32 freq; | ||
53 | }; | ||
54 | |||
55 | struct radio_isa_ops { | ||
56 | /* Allocate and initialize a radio_isa_card struct */ | ||
57 | struct radio_isa_card *(*alloc)(void); | ||
58 | /* Probe whether a card is present at the given port */ | ||
59 | bool (*probe)(struct radio_isa_card *isa, int io); | ||
60 | /* Special card initialization can be done here, this is called after | ||
61 | * the standard controls are registered, but before they are setup, | ||
62 | * thus allowing drivers to add their own controls here. */ | ||
63 | int (*init)(struct radio_isa_card *isa); | ||
64 | /* Set mute and volume. */ | ||
65 | int (*s_mute_volume)(struct radio_isa_card *isa, bool mute, int volume); | ||
66 | /* Set frequency */ | ||
67 | int (*s_frequency)(struct radio_isa_card *isa, u32 freq); | ||
68 | /* Set stereo/mono audio mode */ | ||
69 | int (*s_stereo)(struct radio_isa_card *isa, bool stereo); | ||
70 | /* Get rxsubchans value for VIDIOC_G_TUNER */ | ||
71 | u32 (*g_rxsubchans)(struct radio_isa_card *isa); | ||
72 | /* Get the signal strength for VIDIOC_G_TUNER */ | ||
73 | u32 (*g_signal)(struct radio_isa_card *isa); | ||
74 | }; | ||
75 | |||
76 | /* Top level structure needed to instantiate the cards */ | ||
77 | struct radio_isa_driver { | ||
78 | struct isa_driver driver; | ||
79 | const struct radio_isa_ops *ops; | ||
80 | /* The module_param_array with the specified I/O ports */ | ||
81 | int *io_params; | ||
82 | /* The module_param_array with the radio_nr values */ | ||
83 | int *radio_nr_params; | ||
84 | /* Whether we should probe for possible cards */ | ||
85 | bool probe; | ||
86 | /* The list of possible I/O ports */ | ||
87 | const int *io_ports; | ||
88 | /* The size of that list */ | ||
89 | int num_of_io_ports; | ||
90 | /* The region size to request */ | ||
91 | unsigned region_size; | ||
92 | /* The name of the card */ | ||
93 | const char *card; | ||
94 | /* Card can capture stereo audio */ | ||
95 | bool has_stereo; | ||
96 | /* The maximum volume for the volume control. If 0, then there | ||
97 | is no volume control possible. */ | ||
98 | int max_volume; | ||
99 | }; | ||
100 | |||
101 | int radio_isa_match(struct device *pdev, unsigned int dev); | ||
102 | int radio_isa_probe(struct device *pdev, unsigned int dev); | ||
103 | int radio_isa_remove(struct device *pdev, unsigned int dev); | ||
104 | |||
105 | #endif | ||
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c new file mode 100644 index 000000000000..55bd1d2937c8 --- /dev/null +++ b/drivers/media/radio/radio-keene.c | |||
@@ -0,0 +1,427 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Hans Verkuil <hverkuil@xs4all.nl> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | /* kernel includes */ | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/input.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-ioctl.h> | ||
28 | #include <media/v4l2-ctrls.h> | ||
29 | #include <media/v4l2-event.h> | ||
30 | #include <linux/usb.h> | ||
31 | #include <linux/version.h> | ||
32 | #include <linux/mutex.h> | ||
33 | |||
34 | /* driver and module definitions */ | ||
35 | MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); | ||
36 | MODULE_DESCRIPTION("Keene FM Transmitter driver"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | /* Actually, it advertises itself as a Logitech */ | ||
40 | #define USB_KEENE_VENDOR 0x046d | ||
41 | #define USB_KEENE_PRODUCT 0x0a0e | ||
42 | |||
43 | /* Probably USB_TIMEOUT should be modified in module parameter */ | ||
44 | #define BUFFER_LENGTH 8 | ||
45 | #define USB_TIMEOUT 500 | ||
46 | |||
47 | /* Frequency limits in MHz */ | ||
48 | #define FREQ_MIN 76U | ||
49 | #define FREQ_MAX 108U | ||
50 | #define FREQ_MUL 16000U | ||
51 | |||
52 | /* USB Device ID List */ | ||
53 | static struct usb_device_id usb_keene_device_table[] = { | ||
54 | {USB_DEVICE_AND_INTERFACE_INFO(USB_KEENE_VENDOR, USB_KEENE_PRODUCT, | ||
55 | USB_CLASS_HID, 0, 0) }, | ||
56 | { } /* Terminating entry */ | ||
57 | }; | ||
58 | |||
59 | MODULE_DEVICE_TABLE(usb, usb_keene_device_table); | ||
60 | |||
61 | struct keene_device { | ||
62 | struct usb_device *usbdev; | ||
63 | struct usb_interface *intf; | ||
64 | struct video_device vdev; | ||
65 | struct v4l2_device v4l2_dev; | ||
66 | struct v4l2_ctrl_handler hdl; | ||
67 | struct mutex lock; | ||
68 | |||
69 | u8 *buffer; | ||
70 | unsigned curfreq; | ||
71 | u8 tx; | ||
72 | u8 pa; | ||
73 | bool stereo; | ||
74 | bool muted; | ||
75 | bool preemph_75_us; | ||
76 | }; | ||
77 | |||
78 | static inline struct keene_device *to_keene_dev(struct v4l2_device *v4l2_dev) | ||
79 | { | ||
80 | return container_of(v4l2_dev, struct keene_device, v4l2_dev); | ||
81 | } | ||
82 | |||
83 | /* Set frequency (if non-0), PA, mute and turn on/off the FM transmitter. */ | ||
84 | static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play) | ||
85 | { | ||
86 | unsigned short freq_send = freq ? (freq - 76 * 16000) / 800 : 0; | ||
87 | int ret; | ||
88 | |||
89 | radio->buffer[0] = 0x00; | ||
90 | radio->buffer[1] = 0x50; | ||
91 | radio->buffer[2] = (freq_send >> 8) & 0xff; | ||
92 | radio->buffer[3] = freq_send & 0xff; | ||
93 | radio->buffer[4] = radio->pa; | ||
94 | /* If bit 4 is set, then tune to the frequency. | ||
95 | If bit 3 is set, then unmute; if bit 2 is set, then mute. | ||
96 | If bit 1 is set, then enter idle mode; if bit 0 is set, | ||
97 | then enter transit mode. | ||
98 | */ | ||
99 | radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) | | ||
100 | (freq ? 0x10 : 0); | ||
101 | radio->buffer[6] = 0x00; | ||
102 | radio->buffer[7] = 0x00; | ||
103 | |||
104 | ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | ||
105 | 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); | ||
106 | |||
107 | if (ret < 0) { | ||
108 | dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret); | ||
109 | return ret; | ||
110 | } | ||
111 | if (freq) | ||
112 | radio->curfreq = freq; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /* Set TX, stereo and preemphasis mode (50 us vs 75 us). */ | ||
117 | static int keene_cmd_set(struct keene_device *radio) | ||
118 | { | ||
119 | int ret; | ||
120 | |||
121 | radio->buffer[0] = 0x00; | ||
122 | radio->buffer[1] = 0x51; | ||
123 | radio->buffer[2] = radio->tx; | ||
124 | /* If bit 0 is set, then transmit mono, otherwise stereo. | ||
125 | If bit 2 is set, then enable 75 us preemphasis, otherwise | ||
126 | it is 50 us. */ | ||
127 | radio->buffer[3] = (!radio->stereo) | (radio->preemph_75_us ? 4 : 0); | ||
128 | radio->buffer[4] = 0x00; | ||
129 | radio->buffer[5] = 0x00; | ||
130 | radio->buffer[6] = 0x00; | ||
131 | radio->buffer[7] = 0x00; | ||
132 | |||
133 | ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | ||
134 | 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); | ||
135 | |||
136 | if (ret < 0) { | ||
137 | dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret); | ||
138 | return ret; | ||
139 | } | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* Handle unplugging the device. | ||
144 | * We call video_unregister_device in any case. | ||
145 | * The last function called in this procedure is | ||
146 | * usb_keene_device_release. | ||
147 | */ | ||
148 | static void usb_keene_disconnect(struct usb_interface *intf) | ||
149 | { | ||
150 | struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf)); | ||
151 | |||
152 | v4l2_device_get(&radio->v4l2_dev); | ||
153 | mutex_lock(&radio->lock); | ||
154 | usb_set_intfdata(intf, NULL); | ||
155 | video_unregister_device(&radio->vdev); | ||
156 | v4l2_device_disconnect(&radio->v4l2_dev); | ||
157 | mutex_unlock(&radio->lock); | ||
158 | v4l2_device_put(&radio->v4l2_dev); | ||
159 | } | ||
160 | |||
161 | static int vidioc_querycap(struct file *file, void *priv, | ||
162 | struct v4l2_capability *v) | ||
163 | { | ||
164 | struct keene_device *radio = video_drvdata(file); | ||
165 | |||
166 | strlcpy(v->driver, "radio-keene", sizeof(v->driver)); | ||
167 | strlcpy(v->card, "Keene FM Transmitter", sizeof(v->card)); | ||
168 | usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); | ||
169 | v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR; | ||
170 | v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int vidioc_g_modulator(struct file *file, void *priv, | ||
175 | struct v4l2_modulator *v) | ||
176 | { | ||
177 | struct keene_device *radio = video_drvdata(file); | ||
178 | |||
179 | if (v->index > 0) | ||
180 | return -EINVAL; | ||
181 | |||
182 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
183 | v->rangelow = FREQ_MIN * FREQ_MUL; | ||
184 | v->rangehigh = FREQ_MAX * FREQ_MUL; | ||
185 | v->txsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; | ||
186 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int vidioc_s_modulator(struct file *file, void *priv, | ||
191 | struct v4l2_modulator *v) | ||
192 | { | ||
193 | struct keene_device *radio = video_drvdata(file); | ||
194 | |||
195 | if (v->index > 0) | ||
196 | return -EINVAL; | ||
197 | |||
198 | radio->stereo = (v->txsubchans == V4L2_TUNER_SUB_STEREO); | ||
199 | return keene_cmd_set(radio); | ||
200 | } | ||
201 | |||
202 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
203 | struct v4l2_frequency *f) | ||
204 | { | ||
205 | struct keene_device *radio = video_drvdata(file); | ||
206 | |||
207 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
208 | return -EINVAL; | ||
209 | f->frequency = clamp(f->frequency, | ||
210 | FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); | ||
211 | return keene_cmd_main(radio, f->frequency, true); | ||
212 | } | ||
213 | |||
214 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
215 | struct v4l2_frequency *f) | ||
216 | { | ||
217 | struct keene_device *radio = video_drvdata(file); | ||
218 | |||
219 | if (f->tuner != 0) | ||
220 | return -EINVAL; | ||
221 | f->type = V4L2_TUNER_RADIO; | ||
222 | f->frequency = radio->curfreq; | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int keene_s_ctrl(struct v4l2_ctrl *ctrl) | ||
227 | { | ||
228 | static const u8 db2tx[] = { | ||
229 | /* -15, -12, -9, -6, -3, 0 dB */ | ||
230 | 0x03, 0x13, 0x02, 0x12, 0x22, 0x32, | ||
231 | /* 3, 6, 9, 12, 15, 18 dB */ | ||
232 | 0x21, 0x31, 0x20, 0x30, 0x40, 0x50 | ||
233 | }; | ||
234 | struct keene_device *radio = | ||
235 | container_of(ctrl->handler, struct keene_device, hdl); | ||
236 | |||
237 | switch (ctrl->id) { | ||
238 | case V4L2_CID_AUDIO_MUTE: | ||
239 | radio->muted = ctrl->val; | ||
240 | return keene_cmd_main(radio, 0, true); | ||
241 | |||
242 | case V4L2_CID_TUNE_POWER_LEVEL: | ||
243 | /* To go from dBuV to the register value we apply the | ||
244 | following formula: */ | ||
245 | radio->pa = (ctrl->val - 71) * 100 / 62; | ||
246 | return keene_cmd_main(radio, 0, true); | ||
247 | |||
248 | case V4L2_CID_TUNE_PREEMPHASIS: | ||
249 | radio->preemph_75_us = ctrl->val == V4L2_PREEMPHASIS_75_uS; | ||
250 | return keene_cmd_set(radio); | ||
251 | |||
252 | case V4L2_CID_AUDIO_COMPRESSION_GAIN: | ||
253 | radio->tx = db2tx[(ctrl->val - ctrl->minimum) / ctrl->step]; | ||
254 | return keene_cmd_set(radio); | ||
255 | } | ||
256 | return -EINVAL; | ||
257 | } | ||
258 | |||
259 | static int vidioc_subscribe_event(struct v4l2_fh *fh, | ||
260 | struct v4l2_event_subscription *sub) | ||
261 | { | ||
262 | switch (sub->type) { | ||
263 | case V4L2_EVENT_CTRL: | ||
264 | return v4l2_event_subscribe(fh, sub, 0); | ||
265 | default: | ||
266 | return -EINVAL; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | |||
271 | /* File system interface */ | ||
272 | static const struct v4l2_file_operations usb_keene_fops = { | ||
273 | .owner = THIS_MODULE, | ||
274 | .open = v4l2_fh_open, | ||
275 | .release = v4l2_fh_release, | ||
276 | .poll = v4l2_ctrl_poll, | ||
277 | .unlocked_ioctl = video_ioctl2, | ||
278 | }; | ||
279 | |||
280 | static const struct v4l2_ctrl_ops keene_ctrl_ops = { | ||
281 | .s_ctrl = keene_s_ctrl, | ||
282 | }; | ||
283 | |||
284 | static const struct v4l2_ioctl_ops usb_keene_ioctl_ops = { | ||
285 | .vidioc_querycap = vidioc_querycap, | ||
286 | .vidioc_g_modulator = vidioc_g_modulator, | ||
287 | .vidioc_s_modulator = vidioc_s_modulator, | ||
288 | .vidioc_g_frequency = vidioc_g_frequency, | ||
289 | .vidioc_s_frequency = vidioc_s_frequency, | ||
290 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
291 | .vidioc_subscribe_event = vidioc_subscribe_event, | ||
292 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
293 | }; | ||
294 | |||
295 | static void usb_keene_video_device_release(struct v4l2_device *v4l2_dev) | ||
296 | { | ||
297 | struct keene_device *radio = to_keene_dev(v4l2_dev); | ||
298 | |||
299 | /* free rest memory */ | ||
300 | v4l2_ctrl_handler_free(&radio->hdl); | ||
301 | kfree(radio->buffer); | ||
302 | kfree(radio); | ||
303 | } | ||
304 | |||
305 | /* check if the device is present and register with v4l and usb if it is */ | ||
306 | static int usb_keene_probe(struct usb_interface *intf, | ||
307 | const struct usb_device_id *id) | ||
308 | { | ||
309 | struct usb_device *dev = interface_to_usbdev(intf); | ||
310 | struct keene_device *radio; | ||
311 | struct v4l2_ctrl_handler *hdl; | ||
312 | int retval = 0; | ||
313 | |||
314 | /* | ||
315 | * The Keene FM transmitter USB device has the same USB ID as | ||
316 | * the Logitech AudioHub Speaker, but it should ignore the hid. | ||
317 | * Check if the name is that of the Keene device. | ||
318 | * If not, then someone connected the AudioHub and we shouldn't | ||
319 | * attempt to handle this driver. | ||
320 | * For reference: the product name of the AudioHub is | ||
321 | * "AudioHub Speaker". | ||
322 | */ | ||
323 | if (dev->product && strcmp(dev->product, "B-LINK USB Audio ")) | ||
324 | return -ENODEV; | ||
325 | |||
326 | radio = kzalloc(sizeof(struct keene_device), GFP_KERNEL); | ||
327 | if (radio) | ||
328 | radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); | ||
329 | |||
330 | if (!radio || !radio->buffer) { | ||
331 | dev_err(&intf->dev, "kmalloc for keene_device failed\n"); | ||
332 | kfree(radio); | ||
333 | retval = -ENOMEM; | ||
334 | goto err; | ||
335 | } | ||
336 | |||
337 | hdl = &radio->hdl; | ||
338 | v4l2_ctrl_handler_init(hdl, 4); | ||
339 | v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_MUTE, | ||
340 | 0, 1, 1, 0); | ||
341 | v4l2_ctrl_new_std_menu(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS, | ||
342 | V4L2_PREEMPHASIS_75_uS, 1, V4L2_PREEMPHASIS_50_uS); | ||
343 | v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_POWER_LEVEL, | ||
344 | 84, 118, 1, 118); | ||
345 | v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_COMPRESSION_GAIN, | ||
346 | -15, 18, 3, 0); | ||
347 | radio->pa = 118; | ||
348 | radio->tx = 0x32; | ||
349 | radio->stereo = true; | ||
350 | radio->curfreq = 95.16 * FREQ_MUL; | ||
351 | if (hdl->error) { | ||
352 | retval = hdl->error; | ||
353 | |||
354 | v4l2_ctrl_handler_free(hdl); | ||
355 | goto err_v4l2; | ||
356 | } | ||
357 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); | ||
358 | if (retval < 0) { | ||
359 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); | ||
360 | goto err_v4l2; | ||
361 | } | ||
362 | |||
363 | mutex_init(&radio->lock); | ||
364 | |||
365 | radio->v4l2_dev.ctrl_handler = hdl; | ||
366 | radio->v4l2_dev.release = usb_keene_video_device_release; | ||
367 | strlcpy(radio->vdev.name, radio->v4l2_dev.name, | ||
368 | sizeof(radio->vdev.name)); | ||
369 | radio->vdev.v4l2_dev = &radio->v4l2_dev; | ||
370 | radio->vdev.fops = &usb_keene_fops; | ||
371 | radio->vdev.ioctl_ops = &usb_keene_ioctl_ops; | ||
372 | radio->vdev.lock = &radio->lock; | ||
373 | radio->vdev.release = video_device_release_empty; | ||
374 | |||
375 | radio->usbdev = interface_to_usbdev(intf); | ||
376 | radio->intf = intf; | ||
377 | usb_set_intfdata(intf, &radio->v4l2_dev); | ||
378 | |||
379 | video_set_drvdata(&radio->vdev, radio); | ||
380 | set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags); | ||
381 | |||
382 | retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1); | ||
383 | if (retval < 0) { | ||
384 | dev_err(&intf->dev, "could not register video device\n"); | ||
385 | goto err_vdev; | ||
386 | } | ||
387 | v4l2_ctrl_handler_setup(hdl); | ||
388 | dev_info(&intf->dev, "V4L2 device registered as %s\n", | ||
389 | video_device_node_name(&radio->vdev)); | ||
390 | return 0; | ||
391 | |||
392 | err_vdev: | ||
393 | v4l2_device_unregister(&radio->v4l2_dev); | ||
394 | err_v4l2: | ||
395 | kfree(radio->buffer); | ||
396 | kfree(radio); | ||
397 | err: | ||
398 | return retval; | ||
399 | } | ||
400 | |||
401 | /* USB subsystem interface */ | ||
402 | static struct usb_driver usb_keene_driver = { | ||
403 | .name = "radio-keene", | ||
404 | .probe = usb_keene_probe, | ||
405 | .disconnect = usb_keene_disconnect, | ||
406 | .id_table = usb_keene_device_table, | ||
407 | }; | ||
408 | |||
409 | static int __init keene_init(void) | ||
410 | { | ||
411 | int retval = usb_register(&usb_keene_driver); | ||
412 | |||
413 | if (retval) | ||
414 | pr_err(KBUILD_MODNAME | ||
415 | ": usb_register failed. Error number %d\n", retval); | ||
416 | |||
417 | return retval; | ||
418 | } | ||
419 | |||
420 | static void __exit keene_exit(void) | ||
421 | { | ||
422 | usb_deregister(&usb_keene_driver); | ||
423 | } | ||
424 | |||
425 | module_init(keene_init); | ||
426 | module_exit(keene_exit); | ||
427 | |||
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index f872a54cf3d9..740a3d5520c7 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c | |||
@@ -42,67 +42,37 @@ | |||
42 | #include <linux/videodev2.h> | 42 | #include <linux/videodev2.h> |
43 | #include <linux/io.h> | 43 | #include <linux/io.h> |
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <sound/tea575x-tuner.h> | ||
45 | #include <media/v4l2-device.h> | 46 | #include <media/v4l2-device.h> |
46 | #include <media/v4l2-ioctl.h> | 47 | #include <media/v4l2-ioctl.h> |
47 | 48 | #include <media/v4l2-fh.h> | |
48 | #define DRIVER_VERSION "0.7.8" | 49 | #include <media/v4l2-ctrls.h> |
49 | 50 | #include <media/v4l2-event.h> | |
50 | 51 | ||
51 | MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); | 52 | MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); |
52 | MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); | 53 | MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000."); |
53 | MODULE_LICENSE("GPL"); | 54 | MODULE_LICENSE("GPL"); |
54 | MODULE_VERSION(DRIVER_VERSION); | 55 | MODULE_VERSION("1.0.0"); |
55 | 56 | ||
56 | static int radio_nr = -1; | 57 | static int radio_nr = -1; |
57 | module_param(radio_nr, int, 0); | 58 | module_param(radio_nr, int, 0644); |
58 | 59 | MODULE_PARM_DESC(radio_nr, "Radio device number"); | |
59 | static int debug; | ||
60 | |||
61 | module_param(debug, int, 0644); | ||
62 | MODULE_PARM_DESC(debug, "activates debug info"); | ||
63 | |||
64 | #define dprintk(dev, num, fmt, arg...) \ | ||
65 | v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) | ||
66 | |||
67 | #ifndef PCI_VENDOR_ID_GUILLEMOT | ||
68 | #define PCI_VENDOR_ID_GUILLEMOT 0x5046 | ||
69 | #endif | ||
70 | |||
71 | #ifndef PCI_DEVICE_ID_GUILLEMOT | ||
72 | #define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 | ||
73 | #endif | ||
74 | |||
75 | 60 | ||
76 | /* TEA5757 pin mappings */ | 61 | /* TEA5757 pin mappings */ |
77 | static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; | 62 | static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; |
78 | 63 | ||
79 | #define FREQ_LO (87 * 16000) | 64 | static atomic_t maxiradio_instance = ATOMIC_INIT(0); |
80 | #define FREQ_HI (108 * 16000) | ||
81 | |||
82 | #define FREQ_IF 171200 /* 10.7*16000 */ | ||
83 | #define FREQ_STEP 200 /* 12.5*16 */ | ||
84 | |||
85 | /* (x==fmhz*16*1000) -> bits */ | ||
86 | #define FREQ2BITS(x) \ | ||
87 | ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2) | ||
88 | |||
89 | #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) | ||
90 | 65 | ||
66 | #define PCI_VENDOR_ID_GUILLEMOT 0x5046 | ||
67 | #define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 | ||
91 | 68 | ||
92 | struct maxiradio | 69 | struct maxiradio |
93 | { | 70 | { |
71 | struct snd_tea575x tea; | ||
94 | struct v4l2_device v4l2_dev; | 72 | struct v4l2_device v4l2_dev; |
95 | struct video_device vdev; | ||
96 | struct pci_dev *pdev; | 73 | struct pci_dev *pdev; |
97 | 74 | ||
98 | u16 io; /* base of radio io */ | 75 | u16 io; /* base of radio io */ |
99 | u16 muted; /* VIDEO_AUDIO_MUTE */ | ||
100 | u16 stereo; /* VIDEO_TUNER_STEREO_ON */ | ||
101 | u16 tuned; /* signal strength (0 or 0xffff) */ | ||
102 | |||
103 | unsigned long freq; | ||
104 | |||
105 | struct mutex lock; | ||
106 | }; | 76 | }; |
107 | 77 | ||
108 | static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) | 78 | static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) |
@@ -110,259 +80,41 @@ static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) | |||
110 | return container_of(v4l2_dev, struct maxiradio, v4l2_dev); | 80 | return container_of(v4l2_dev, struct maxiradio, v4l2_dev); |
111 | } | 81 | } |
112 | 82 | ||
113 | static void outbit(unsigned long bit, u16 io) | 83 | static void maxiradio_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) |
114 | { | ||
115 | int val = power | wren | (bit ? data : 0); | ||
116 | |||
117 | outb(val, io); | ||
118 | udelay(4); | ||
119 | outb(val | clk, io); | ||
120 | udelay(4); | ||
121 | outb(val, io); | ||
122 | udelay(4); | ||
123 | } | ||
124 | |||
125 | static void turn_power(struct maxiradio *dev, int p) | ||
126 | { | ||
127 | if (p != 0) { | ||
128 | dprintk(dev, 1, "Radio powered on\n"); | ||
129 | outb(power, dev->io); | ||
130 | } else { | ||
131 | dprintk(dev, 1, "Radio powered off\n"); | ||
132 | outb(0, dev->io); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | static void set_freq(struct maxiradio *dev, u32 freq) | ||
137 | { | ||
138 | unsigned long int si; | ||
139 | int bl; | ||
140 | int io = dev->io; | ||
141 | int val = FREQ2BITS(freq); | ||
142 | |||
143 | /* TEA5757 shift register bits (see pdf) */ | ||
144 | |||
145 | outbit(0, io); /* 24 search */ | ||
146 | outbit(1, io); /* 23 search up/down */ | ||
147 | |||
148 | outbit(0, io); /* 22 stereo/mono */ | ||
149 | |||
150 | outbit(0, io); /* 21 band */ | ||
151 | outbit(0, io); /* 20 band (only 00=FM works I think) */ | ||
152 | |||
153 | outbit(0, io); /* 19 port ? */ | ||
154 | outbit(0, io); /* 18 port ? */ | ||
155 | |||
156 | outbit(0, io); /* 17 search level */ | ||
157 | outbit(0, io); /* 16 search level */ | ||
158 | |||
159 | si = 0x8000; | ||
160 | for (bl = 1; bl <= 16; bl++) { | ||
161 | outbit(val & si, io); | ||
162 | si >>= 1; | ||
163 | } | ||
164 | |||
165 | dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n", | ||
166 | freq / 16000, | ||
167 | freq % 16000 * 100 / 16000); | ||
168 | |||
169 | turn_power(dev, 1); | ||
170 | } | ||
171 | |||
172 | static int get_stereo(u16 io) | ||
173 | { | 84 | { |
174 | outb(power,io); | 85 | struct maxiradio *dev = tea->private_data; |
175 | udelay(4); | 86 | u8 bits = 0; |
176 | 87 | ||
177 | return !(inb(io) & mo_st); | 88 | bits |= (pins & TEA575X_DATA) ? data : 0; |
178 | } | 89 | bits |= (pins & TEA575X_CLK) ? clk : 0; |
90 | bits |= (pins & TEA575X_WREN) ? wren : 0; | ||
91 | bits |= power; | ||
179 | 92 | ||
180 | static int get_tune(u16 io) | 93 | outb(bits, dev->io); |
181 | { | ||
182 | outb(power+clk,io); | ||
183 | udelay(4); | ||
184 | |||
185 | return !(inb(io) & mo_st); | ||
186 | } | ||
187 | |||
188 | |||
189 | static int vidioc_querycap(struct file *file, void *priv, | ||
190 | struct v4l2_capability *v) | ||
191 | { | ||
192 | struct maxiradio *dev = video_drvdata(file); | ||
193 | |||
194 | strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); | ||
195 | strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); | ||
196 | snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); | ||
197 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
198 | return 0; | ||
199 | } | 94 | } |
200 | 95 | ||
201 | static int vidioc_g_tuner(struct file *file, void *priv, | 96 | /* Note: this card cannot read out the data of the shift registers, |
202 | struct v4l2_tuner *v) | 97 | only the mono/stereo pin works. */ |
98 | static u8 maxiradio_tea575x_get_pins(struct snd_tea575x *tea) | ||
203 | { | 99 | { |
204 | struct maxiradio *dev = video_drvdata(file); | 100 | struct maxiradio *dev = tea->private_data; |
205 | 101 | u8 bits = inb(dev->io); | |
206 | if (v->index > 0) | ||
207 | return -EINVAL; | ||
208 | |||
209 | mutex_lock(&dev->lock); | ||
210 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
211 | v->type = V4L2_TUNER_RADIO; | ||
212 | v->rangelow = FREQ_LO; | ||
213 | v->rangehigh = FREQ_HI; | ||
214 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
215 | v->capability = V4L2_TUNER_CAP_LOW; | ||
216 | if (get_stereo(dev->io)) | ||
217 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
218 | else | ||
219 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
220 | v->signal = 0xffff * get_tune(dev->io); | ||
221 | mutex_unlock(&dev->lock); | ||
222 | 102 | ||
223 | return 0; | 103 | return ((bits & data) ? TEA575X_DATA : 0) | |
104 | ((bits & mo_st) ? TEA575X_MOST : 0); | ||
224 | } | 105 | } |
225 | 106 | ||
226 | static int vidioc_s_tuner(struct file *file, void *priv, | 107 | static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output) |
227 | struct v4l2_tuner *v) | ||
228 | { | 108 | { |
229 | return v->index ? -EINVAL : 0; | ||
230 | } | 109 | } |
231 | 110 | ||
232 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | 111 | static struct snd_tea575x_ops maxiradio_tea_ops = { |
233 | { | 112 | .set_pins = maxiradio_tea575x_set_pins, |
234 | *i = 0; | 113 | .get_pins = maxiradio_tea575x_get_pins, |
235 | return 0; | 114 | .set_direction = maxiradio_tea575x_set_direction, |
236 | } | ||
237 | |||
238 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
239 | { | ||
240 | return i ? -EINVAL : 0; | ||
241 | } | ||
242 | |||
243 | static int vidioc_g_audio(struct file *file, void *priv, | ||
244 | struct v4l2_audio *a) | ||
245 | { | ||
246 | a->index = 0; | ||
247 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
248 | a->capability = V4L2_AUDCAP_STEREO; | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | |||
253 | static int vidioc_s_audio(struct file *file, void *priv, | ||
254 | struct v4l2_audio *a) | ||
255 | { | ||
256 | return a->index ? -EINVAL : 0; | ||
257 | } | ||
258 | |||
259 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
260 | struct v4l2_frequency *f) | ||
261 | { | ||
262 | struct maxiradio *dev = video_drvdata(file); | ||
263 | |||
264 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
265 | return -EINVAL; | ||
266 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { | ||
267 | dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", | ||
268 | f->frequency / 16000, | ||
269 | f->frequency % 16000 * 100 / 16000, | ||
270 | FREQ_LO / 16000, FREQ_HI / 16000); | ||
271 | |||
272 | return -EINVAL; | ||
273 | } | ||
274 | |||
275 | mutex_lock(&dev->lock); | ||
276 | dev->freq = f->frequency; | ||
277 | set_freq(dev, dev->freq); | ||
278 | msleep(125); | ||
279 | mutex_unlock(&dev->lock); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
285 | struct v4l2_frequency *f) | ||
286 | { | ||
287 | struct maxiradio *dev = video_drvdata(file); | ||
288 | |||
289 | if (f->tuner != 0) | ||
290 | return -EINVAL; | ||
291 | f->type = V4L2_TUNER_RADIO; | ||
292 | f->frequency = dev->freq; | ||
293 | |||
294 | dprintk(dev, 4, "radio freq is %d.%02d MHz", | ||
295 | f->frequency / 16000, | ||
296 | f->frequency % 16000 * 100 / 16000); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
302 | struct v4l2_queryctrl *qc) | ||
303 | { | ||
304 | switch (qc->id) { | ||
305 | case V4L2_CID_AUDIO_MUTE: | ||
306 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
307 | } | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
311 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
312 | struct v4l2_control *ctrl) | ||
313 | { | ||
314 | struct maxiradio *dev = video_drvdata(file); | ||
315 | |||
316 | switch (ctrl->id) { | ||
317 | case V4L2_CID_AUDIO_MUTE: | ||
318 | ctrl->value = dev->muted; | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | return -EINVAL; | ||
323 | } | ||
324 | |||
325 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
326 | struct v4l2_control *ctrl) | ||
327 | { | ||
328 | struct maxiradio *dev = video_drvdata(file); | ||
329 | |||
330 | switch (ctrl->id) { | ||
331 | case V4L2_CID_AUDIO_MUTE: | ||
332 | mutex_lock(&dev->lock); | ||
333 | dev->muted = ctrl->value; | ||
334 | if (dev->muted) | ||
335 | turn_power(dev, 0); | ||
336 | else | ||
337 | set_freq(dev, dev->freq); | ||
338 | mutex_unlock(&dev->lock); | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | return -EINVAL; | ||
343 | } | ||
344 | |||
345 | static const struct v4l2_file_operations maxiradio_fops = { | ||
346 | .owner = THIS_MODULE, | ||
347 | .unlocked_ioctl = video_ioctl2, | ||
348 | }; | 115 | }; |
349 | 116 | ||
350 | static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { | 117 | static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
351 | .vidioc_querycap = vidioc_querycap, | ||
352 | .vidioc_g_tuner = vidioc_g_tuner, | ||
353 | .vidioc_s_tuner = vidioc_s_tuner, | ||
354 | .vidioc_g_audio = vidioc_g_audio, | ||
355 | .vidioc_s_audio = vidioc_s_audio, | ||
356 | .vidioc_g_input = vidioc_g_input, | ||
357 | .vidioc_s_input = vidioc_s_input, | ||
358 | .vidioc_g_frequency = vidioc_g_frequency, | ||
359 | .vidioc_s_frequency = vidioc_s_frequency, | ||
360 | .vidioc_queryctrl = vidioc_queryctrl, | ||
361 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
362 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
363 | }; | ||
364 | |||
365 | static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
366 | { | 118 | { |
367 | struct maxiradio *dev; | 119 | struct maxiradio *dev; |
368 | struct v4l2_device *v4l2_dev; | 120 | struct v4l2_device *v4l2_dev; |
@@ -375,63 +127,60 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d | |||
375 | } | 127 | } |
376 | 128 | ||
377 | v4l2_dev = &dev->v4l2_dev; | 129 | v4l2_dev = &dev->v4l2_dev; |
378 | mutex_init(&dev->lock); | 130 | v4l2_device_set_name(v4l2_dev, "maxiradio", &maxiradio_instance); |
379 | dev->pdev = pdev; | ||
380 | dev->muted = 1; | ||
381 | dev->freq = FREQ_LO; | ||
382 | |||
383 | strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); | ||
384 | 131 | ||
385 | retval = v4l2_device_register(&pdev->dev, v4l2_dev); | 132 | retval = v4l2_device_register(&pdev->dev, v4l2_dev); |
386 | if (retval < 0) { | 133 | if (retval < 0) { |
387 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | 134 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); |
388 | goto errfr; | 135 | goto errfr; |
389 | } | 136 | } |
137 | dev->tea.private_data = dev; | ||
138 | dev->tea.ops = &maxiradio_tea_ops; | ||
139 | /* The data pin cannot be read. This may be a hardware limitation, or | ||
140 | we just don't know how to read it. */ | ||
141 | dev->tea.cannot_read_data = true; | ||
142 | dev->tea.v4l2_dev = v4l2_dev; | ||
143 | dev->tea.radio_nr = radio_nr; | ||
144 | strlcpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card)); | ||
145 | snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info), | ||
146 | "PCI:%s", pci_name(pdev)); | ||
147 | |||
148 | retval = -ENODEV; | ||
390 | 149 | ||
391 | if (!request_region(pci_resource_start(pdev, 0), | 150 | if (!request_region(pci_resource_start(pdev, 0), |
392 | pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { | 151 | pci_resource_len(pdev, 0), v4l2_dev->name)) { |
393 | v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); | 152 | dev_err(&pdev->dev, "can't reserve I/O ports\n"); |
394 | goto err_out; | 153 | goto err_hdl; |
395 | } | 154 | } |
396 | 155 | ||
397 | if (pci_enable_device(pdev)) | 156 | if (pci_enable_device(pdev)) |
398 | goto err_out_free_region; | 157 | goto err_out_free_region; |
399 | 158 | ||
400 | dev->io = pci_resource_start(pdev, 0); | 159 | dev->io = pci_resource_start(pdev, 0); |
401 | strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); | 160 | if (snd_tea575x_init(&dev->tea)) { |
402 | dev->vdev.v4l2_dev = v4l2_dev; | 161 | printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n"); |
403 | dev->vdev.fops = &maxiradio_fops; | ||
404 | dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; | ||
405 | dev->vdev.release = video_device_release_empty; | ||
406 | video_set_drvdata(&dev->vdev, dev); | ||
407 | |||
408 | if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
409 | v4l2_err(v4l2_dev, "can't register device!"); | ||
410 | goto err_out_free_region; | 162 | goto err_out_free_region; |
411 | } | 163 | } |
412 | |||
413 | v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); | ||
414 | |||
415 | v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", | ||
416 | dev->io); | ||
417 | return 0; | 164 | return 0; |
418 | 165 | ||
419 | err_out_free_region: | 166 | err_out_free_region: |
420 | release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); | 167 | release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); |
421 | err_out: | 168 | err_hdl: |
422 | v4l2_device_unregister(v4l2_dev); | 169 | v4l2_device_unregister(v4l2_dev); |
423 | errfr: | 170 | errfr: |
424 | kfree(dev); | 171 | kfree(dev); |
425 | return -ENODEV; | 172 | return retval; |
426 | } | 173 | } |
427 | 174 | ||
428 | static void __devexit maxiradio_remove_one(struct pci_dev *pdev) | 175 | static void __devexit maxiradio_remove(struct pci_dev *pdev) |
429 | { | 176 | { |
430 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); | 177 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); |
431 | struct maxiradio *dev = to_maxiradio(v4l2_dev); | 178 | struct maxiradio *dev = to_maxiradio(v4l2_dev); |
432 | 179 | ||
433 | video_unregister_device(&dev->vdev); | 180 | snd_tea575x_exit(&dev->tea); |
434 | v4l2_device_unregister(&dev->v4l2_dev); | 181 | /* Turn off power */ |
182 | outb(0, dev->io); | ||
183 | v4l2_device_unregister(v4l2_dev); | ||
435 | release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); | 184 | release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); |
436 | } | 185 | } |
437 | 186 | ||
@@ -446,19 +195,19 @@ MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); | |||
446 | static struct pci_driver maxiradio_driver = { | 195 | static struct pci_driver maxiradio_driver = { |
447 | .name = "radio-maxiradio", | 196 | .name = "radio-maxiradio", |
448 | .id_table = maxiradio_pci_tbl, | 197 | .id_table = maxiradio_pci_tbl, |
449 | .probe = maxiradio_init_one, | 198 | .probe = maxiradio_probe, |
450 | .remove = __devexit_p(maxiradio_remove_one), | 199 | .remove = __devexit_p(maxiradio_remove), |
451 | }; | 200 | }; |
452 | 201 | ||
453 | static int __init maxiradio_radio_init(void) | 202 | static int __init maxiradio_init(void) |
454 | { | 203 | { |
455 | return pci_register_driver(&maxiradio_driver); | 204 | return pci_register_driver(&maxiradio_driver); |
456 | } | 205 | } |
457 | 206 | ||
458 | static void __exit maxiradio_radio_exit(void) | 207 | static void __exit maxiradio_exit(void) |
459 | { | 208 | { |
460 | pci_unregister_driver(&maxiradio_driver); | 209 | pci_unregister_driver(&maxiradio_driver); |
461 | } | 210 | } |
462 | 211 | ||
463 | module_init(maxiradio_radio_init); | 212 | module_init(maxiradio_init); |
464 | module_exit(maxiradio_radio_exit); | 213 | module_exit(maxiradio_exit); |
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 3628be617ee9..b275c5d0fe9a 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c | |||
@@ -1,11 +1,12 @@ | |||
1 | /* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff | 1 | /* |
2 | * RadioTrack II driver | ||
3 | * Copyright 1998 Ben Pfaff | ||
2 | * | 4 | * |
3 | * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood | 5 | * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood |
4 | * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> | 6 | * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> |
5 | * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> | 7 | * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> |
6 | * | 8 | * |
7 | * TODO: Allow for more than one of these foolish entities :-) | 9 | * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> |
8 | * | ||
9 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> | 10 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> |
10 | */ | 11 | */ |
11 | 12 | ||
@@ -18,323 +19,120 @@ | |||
18 | #include <linux/io.h> /* outb, outb_p */ | 19 | #include <linux/io.h> /* outb, outb_p */ |
19 | #include <media/v4l2-device.h> | 20 | #include <media/v4l2-device.h> |
20 | #include <media/v4l2-ioctl.h> | 21 | #include <media/v4l2-ioctl.h> |
22 | #include "radio-isa.h" | ||
21 | 23 | ||
22 | MODULE_AUTHOR("Ben Pfaff"); | 24 | MODULE_AUTHOR("Ben Pfaff"); |
23 | MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); | 25 | MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); |
24 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
25 | MODULE_VERSION("0.0.3"); | 27 | MODULE_VERSION("0.1.99"); |
26 | 28 | ||
27 | #ifndef CONFIG_RADIO_RTRACK2_PORT | 29 | #ifndef CONFIG_RADIO_RTRACK2_PORT |
28 | #define CONFIG_RADIO_RTRACK2_PORT -1 | 30 | #define CONFIG_RADIO_RTRACK2_PORT -1 |
29 | #endif | 31 | #endif |
30 | 32 | ||
31 | static int io = CONFIG_RADIO_RTRACK2_PORT; | 33 | #define RTRACK2_MAX 2 |
32 | static int radio_nr = -1; | ||
33 | |||
34 | module_param(io, int, 0); | ||
35 | MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); | ||
36 | module_param(radio_nr, int, 0); | ||
37 | |||
38 | struct rtrack2 | ||
39 | { | ||
40 | struct v4l2_device v4l2_dev; | ||
41 | struct video_device vdev; | ||
42 | int io; | ||
43 | unsigned long curfreq; | ||
44 | int muted; | ||
45 | struct mutex lock; | ||
46 | }; | ||
47 | 34 | ||
48 | static struct rtrack2 rtrack2_card; | 35 | static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT, |
36 | [1 ... (RTRACK2_MAX - 1)] = -1 }; | ||
37 | static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 }; | ||
49 | 38 | ||
39 | module_param_array(io, int, NULL, 0444); | ||
40 | MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)"); | ||
41 | module_param_array(radio_nr, int, NULL, 0444); | ||
42 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); | ||
50 | 43 | ||
51 | /* local things */ | 44 | static struct radio_isa_card *rtrack2_alloc(void) |
52 | |||
53 | static void rt_mute(struct rtrack2 *dev) | ||
54 | { | ||
55 | if (dev->muted) | ||
56 | return; | ||
57 | mutex_lock(&dev->lock); | ||
58 | outb(1, dev->io); | ||
59 | mutex_unlock(&dev->lock); | ||
60 | dev->muted = 1; | ||
61 | } | ||
62 | |||
63 | static void rt_unmute(struct rtrack2 *dev) | ||
64 | { | 45 | { |
65 | if(dev->muted == 0) | 46 | return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL); |
66 | return; | ||
67 | mutex_lock(&dev->lock); | ||
68 | outb(0, dev->io); | ||
69 | mutex_unlock(&dev->lock); | ||
70 | dev->muted = 0; | ||
71 | } | 47 | } |
72 | 48 | ||
73 | static void zero(struct rtrack2 *dev) | 49 | static void zero(struct radio_isa_card *isa) |
74 | { | 50 | { |
75 | outb_p(1, dev->io); | 51 | outb_p(1, isa->io); |
76 | outb_p(3, dev->io); | 52 | outb_p(3, isa->io); |
77 | outb_p(1, dev->io); | 53 | outb_p(1, isa->io); |
78 | } | 54 | } |
79 | 55 | ||
80 | static void one(struct rtrack2 *dev) | 56 | static void one(struct radio_isa_card *isa) |
81 | { | 57 | { |
82 | outb_p(5, dev->io); | 58 | outb_p(5, isa->io); |
83 | outb_p(7, dev->io); | 59 | outb_p(7, isa->io); |
84 | outb_p(5, dev->io); | 60 | outb_p(5, isa->io); |
85 | } | 61 | } |
86 | 62 | ||
87 | static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) | 63 | static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq) |
88 | { | 64 | { |
89 | int i; | 65 | int i; |
90 | 66 | ||
91 | mutex_lock(&dev->lock); | ||
92 | dev->curfreq = freq; | ||
93 | freq = freq / 200 + 856; | 67 | freq = freq / 200 + 856; |
94 | 68 | ||
95 | outb_p(0xc8, dev->io); | 69 | outb_p(0xc8, isa->io); |
96 | outb_p(0xc9, dev->io); | 70 | outb_p(0xc9, isa->io); |
97 | outb_p(0xc9, dev->io); | 71 | outb_p(0xc9, isa->io); |
98 | 72 | ||
99 | for (i = 0; i < 10; i++) | 73 | for (i = 0; i < 10; i++) |
100 | zero(dev); | 74 | zero(isa); |
101 | 75 | ||
102 | for (i = 14; i >= 0; i--) | 76 | for (i = 14; i >= 0; i--) |
103 | if (freq & (1 << i)) | 77 | if (freq & (1 << i)) |
104 | one(dev); | 78 | one(isa); |
105 | else | 79 | else |
106 | zero(dev); | 80 | zero(isa); |
107 | |||
108 | outb_p(0xc8, dev->io); | ||
109 | if (!dev->muted) | ||
110 | outb_p(0, dev->io); | ||
111 | |||
112 | mutex_unlock(&dev->lock); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int vidioc_querycap(struct file *file, void *priv, | ||
117 | struct v4l2_capability *v) | ||
118 | { | ||
119 | strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); | ||
120 | strlcpy(v->card, "RadioTrack II", sizeof(v->card)); | ||
121 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
122 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
123 | return 0; | ||
124 | } | ||
125 | 81 | ||
126 | static int vidioc_s_tuner(struct file *file, void *priv, | 82 | outb_p(0xc8, isa->io); |
127 | struct v4l2_tuner *v) | 83 | if (!v4l2_ctrl_g_ctrl(isa->mute)) |
128 | { | 84 | outb_p(0, isa->io); |
129 | return v->index ? -EINVAL : 0; | ||
130 | } | ||
131 | |||
132 | static int rt_getsigstr(struct rtrack2 *dev) | ||
133 | { | ||
134 | int sig = 1; | ||
135 | |||
136 | mutex_lock(&dev->lock); | ||
137 | if (inb(dev->io) & 2) /* bit set = no signal present */ | ||
138 | sig = 0; | ||
139 | mutex_unlock(&dev->lock); | ||
140 | return sig; | ||
141 | } | ||
142 | |||
143 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
144 | struct v4l2_tuner *v) | ||
145 | { | ||
146 | struct rtrack2 *rt = video_drvdata(file); | ||
147 | |||
148 | if (v->index > 0) | ||
149 | return -EINVAL; | ||
150 | |||
151 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
152 | v->type = V4L2_TUNER_RADIO; | ||
153 | v->rangelow = 88 * 16000; | ||
154 | v->rangehigh = 108 * 16000; | ||
155 | v->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
156 | v->capability = V4L2_TUNER_CAP_LOW; | ||
157 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
158 | v->signal = 0xFFFF * rt_getsigstr(rt); | ||
159 | return 0; | 85 | return 0; |
160 | } | 86 | } |
161 | 87 | ||
162 | static int vidioc_s_frequency(struct file *file, void *priv, | 88 | static u32 rtrack2_g_signal(struct radio_isa_card *isa) |
163 | struct v4l2_frequency *f) | ||
164 | { | 89 | { |
165 | struct rtrack2 *rt = video_drvdata(file); | 90 | /* bit set = no signal present */ |
166 | 91 | return (inb(isa->io) & 2) ? 0 : 0xffff; | |
167 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
168 | return -EINVAL; | ||
169 | rt_setfreq(rt, f->frequency); | ||
170 | return 0; | ||
171 | } | 92 | } |
172 | 93 | ||
173 | static int vidioc_g_frequency(struct file *file, void *priv, | 94 | static int rtrack2_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
174 | struct v4l2_frequency *f) | ||
175 | { | 95 | { |
176 | struct rtrack2 *rt = video_drvdata(file); | 96 | outb(mute, isa->io); |
177 | |||
178 | if (f->tuner != 0) | ||
179 | return -EINVAL; | ||
180 | f->type = V4L2_TUNER_RADIO; | ||
181 | f->frequency = rt->curfreq; | ||
182 | return 0; | 97 | return 0; |
183 | } | 98 | } |
184 | 99 | ||
185 | static int vidioc_queryctrl(struct file *file, void *priv, | 100 | static const struct radio_isa_ops rtrack2_ops = { |
186 | struct v4l2_queryctrl *qc) | 101 | .alloc = rtrack2_alloc, |
187 | { | 102 | .s_mute_volume = rtrack2_s_mute_volume, |
188 | switch (qc->id) { | 103 | .s_frequency = rtrack2_s_frequency, |
189 | case V4L2_CID_AUDIO_MUTE: | 104 | .g_signal = rtrack2_g_signal, |
190 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
191 | case V4L2_CID_AUDIO_VOLUME: | ||
192 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); | ||
193 | } | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
198 | struct v4l2_control *ctrl) | ||
199 | { | ||
200 | struct rtrack2 *rt = video_drvdata(file); | ||
201 | |||
202 | switch (ctrl->id) { | ||
203 | case V4L2_CID_AUDIO_MUTE: | ||
204 | ctrl->value = rt->muted; | ||
205 | return 0; | ||
206 | case V4L2_CID_AUDIO_VOLUME: | ||
207 | if (rt->muted) | ||
208 | ctrl->value = 0; | ||
209 | else | ||
210 | ctrl->value = 65535; | ||
211 | return 0; | ||
212 | } | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | |||
216 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
217 | struct v4l2_control *ctrl) | ||
218 | { | ||
219 | struct rtrack2 *rt = video_drvdata(file); | ||
220 | |||
221 | switch (ctrl->id) { | ||
222 | case V4L2_CID_AUDIO_MUTE: | ||
223 | if (ctrl->value) | ||
224 | rt_mute(rt); | ||
225 | else | ||
226 | rt_unmute(rt); | ||
227 | return 0; | ||
228 | case V4L2_CID_AUDIO_VOLUME: | ||
229 | if (ctrl->value) | ||
230 | rt_unmute(rt); | ||
231 | else | ||
232 | rt_mute(rt); | ||
233 | return 0; | ||
234 | } | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | |||
238 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
239 | { | ||
240 | *i = 0; | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
245 | { | ||
246 | return i ? -EINVAL : 0; | ||
247 | } | ||
248 | |||
249 | static int vidioc_g_audio(struct file *file, void *priv, | ||
250 | struct v4l2_audio *a) | ||
251 | { | ||
252 | a->index = 0; | ||
253 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
254 | a->capability = V4L2_AUDCAP_STEREO; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int vidioc_s_audio(struct file *file, void *priv, | ||
259 | struct v4l2_audio *a) | ||
260 | { | ||
261 | return a->index ? -EINVAL : 0; | ||
262 | } | ||
263 | |||
264 | static const struct v4l2_file_operations rtrack2_fops = { | ||
265 | .owner = THIS_MODULE, | ||
266 | .unlocked_ioctl = video_ioctl2, | ||
267 | }; | 105 | }; |
268 | 106 | ||
269 | static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { | 107 | static const int rtrack2_ioports[] = { 0x20f, 0x30f }; |
270 | .vidioc_querycap = vidioc_querycap, | 108 | |
271 | .vidioc_g_tuner = vidioc_g_tuner, | 109 | static struct radio_isa_driver rtrack2_driver = { |
272 | .vidioc_s_tuner = vidioc_s_tuner, | 110 | .driver = { |
273 | .vidioc_g_frequency = vidioc_g_frequency, | 111 | .match = radio_isa_match, |
274 | .vidioc_s_frequency = vidioc_s_frequency, | 112 | .probe = radio_isa_probe, |
275 | .vidioc_queryctrl = vidioc_queryctrl, | 113 | .remove = radio_isa_remove, |
276 | .vidioc_g_ctrl = vidioc_g_ctrl, | 114 | .driver = { |
277 | .vidioc_s_ctrl = vidioc_s_ctrl, | 115 | .name = "radio-rtrack2", |
278 | .vidioc_g_audio = vidioc_g_audio, | 116 | }, |
279 | .vidioc_s_audio = vidioc_s_audio, | 117 | }, |
280 | .vidioc_g_input = vidioc_g_input, | 118 | .io_params = io, |
281 | .vidioc_s_input = vidioc_s_input, | 119 | .radio_nr_params = radio_nr, |
120 | .io_ports = rtrack2_ioports, | ||
121 | .num_of_io_ports = ARRAY_SIZE(rtrack2_ioports), | ||
122 | .region_size = 4, | ||
123 | .card = "AIMSlab RadioTrack II", | ||
124 | .ops = &rtrack2_ops, | ||
125 | .has_stereo = true, | ||
282 | }; | 126 | }; |
283 | 127 | ||
284 | static int __init rtrack2_init(void) | 128 | static int __init rtrack2_init(void) |
285 | { | 129 | { |
286 | struct rtrack2 *dev = &rtrack2_card; | 130 | return isa_register_driver(&rtrack2_driver.driver, RTRACK2_MAX); |
287 | struct v4l2_device *v4l2_dev = &dev->v4l2_dev; | ||
288 | int res; | ||
289 | |||
290 | strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name)); | ||
291 | dev->io = io; | ||
292 | if (dev->io == -1) { | ||
293 | v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n"); | ||
294 | return -EINVAL; | ||
295 | } | ||
296 | if (!request_region(dev->io, 4, "rtrack2")) { | ||
297 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io); | ||
298 | return -EBUSY; | ||
299 | } | ||
300 | |||
301 | res = v4l2_device_register(NULL, v4l2_dev); | ||
302 | if (res < 0) { | ||
303 | release_region(dev->io, 4); | ||
304 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
305 | return res; | ||
306 | } | ||
307 | |||
308 | strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); | ||
309 | dev->vdev.v4l2_dev = v4l2_dev; | ||
310 | dev->vdev.fops = &rtrack2_fops; | ||
311 | dev->vdev.ioctl_ops = &rtrack2_ioctl_ops; | ||
312 | dev->vdev.release = video_device_release_empty; | ||
313 | video_set_drvdata(&dev->vdev, dev); | ||
314 | |||
315 | /* mute card - prevents noisy bootups */ | ||
316 | outb(1, dev->io); | ||
317 | dev->muted = 1; | ||
318 | |||
319 | mutex_init(&dev->lock); | ||
320 | if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
321 | v4l2_device_unregister(v4l2_dev); | ||
322 | release_region(dev->io, 4); | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | |||
326 | v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); | ||
327 | |||
328 | return 0; | ||
329 | } | 131 | } |
330 | 132 | ||
331 | static void __exit rtrack2_exit(void) | 133 | static void __exit rtrack2_exit(void) |
332 | { | 134 | { |
333 | struct rtrack2 *dev = &rtrack2_card; | 135 | isa_unregister_driver(&rtrack2_driver.driver); |
334 | |||
335 | video_unregister_device(&dev->vdev); | ||
336 | v4l2_device_unregister(&dev->v4l2_dev); | ||
337 | release_region(dev->io, 4); | ||
338 | } | 136 | } |
339 | 137 | ||
340 | module_init(rtrack2_init); | 138 | module_init(rtrack2_init); |
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 7ab9afadf29b..7c69214334bf 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c | |||
@@ -9,16 +9,23 @@ | |||
9 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
10 | #include <linux/module.h> /* Modules */ | 10 | #include <linux/module.h> /* Modules */ |
11 | #include <linux/init.h> /* Initdata */ | 11 | #include <linux/init.h> /* Initdata */ |
12 | #include <linux/slab.h> | ||
12 | #include <linux/ioport.h> /* request_region */ | 13 | #include <linux/ioport.h> /* request_region */ |
13 | #include <linux/io.h> /* outb, outb_p */ | 14 | #include <linux/io.h> /* outb, outb_p */ |
15 | #include <linux/isa.h> | ||
14 | #include <sound/tea575x-tuner.h> | 16 | #include <sound/tea575x-tuner.h> |
15 | 17 | ||
16 | MODULE_AUTHOR("Ondrej Zary"); | 18 | MODULE_AUTHOR("Ondrej Zary"); |
17 | MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); | 19 | MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); |
18 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
19 | 21 | ||
22 | static int radio_nr = -1; | ||
23 | module_param(radio_nr, int, 0444); | ||
24 | MODULE_PARM_DESC(radio_nr, "Radio device number"); | ||
25 | |||
20 | struct fmr2 { | 26 | struct fmr2 { |
21 | int io; | 27 | int io; |
28 | struct v4l2_device v4l2_dev; | ||
22 | struct snd_tea575x tea; | 29 | struct snd_tea575x tea; |
23 | struct v4l2_ctrl *volume; | 30 | struct v4l2_ctrl *volume; |
24 | struct v4l2_ctrl *balance; | 31 | struct v4l2_ctrl *balance; |
@@ -26,7 +33,6 @@ struct fmr2 { | |||
26 | 33 | ||
27 | /* the port is hardwired so no need to support multiple cards */ | 34 | /* the port is hardwired so no need to support multiple cards */ |
28 | #define FMR2_PORT 0x384 | 35 | #define FMR2_PORT 0x384 |
29 | static struct fmr2 fmr2_card; | ||
30 | 36 | ||
31 | /* TEA575x tuner pins */ | 37 | /* TEA575x tuner pins */ |
32 | #define STR_DATA (1 << 0) | 38 | #define STR_DATA (1 << 0) |
@@ -180,26 +186,46 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea) | |||
180 | return 0; | 186 | return 0; |
181 | } | 187 | } |
182 | 188 | ||
183 | static int __init fmr2_init(void) | 189 | static int __devinit fmr2_probe(struct device *pdev, unsigned int dev) |
184 | { | 190 | { |
185 | struct fmr2 *fmr2 = &fmr2_card; | 191 | struct fmr2 *fmr2; |
192 | int err; | ||
193 | |||
194 | fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL); | ||
195 | if (fmr2 == NULL) | ||
196 | return -ENOMEM; | ||
186 | 197 | ||
198 | strlcpy(fmr2->v4l2_dev.name, dev_name(pdev), | ||
199 | sizeof(fmr2->v4l2_dev.name)); | ||
187 | fmr2->io = FMR2_PORT; | 200 | fmr2->io = FMR2_PORT; |
188 | 201 | ||
189 | if (!request_region(fmr2->io, 2, "SF16-FMR2")) { | 202 | if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) { |
190 | printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); | 203 | printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); |
204 | kfree(fmr2); | ||
191 | return -EBUSY; | 205 | return -EBUSY; |
192 | } | 206 | } |
193 | 207 | ||
208 | dev_set_drvdata(pdev, fmr2); | ||
209 | err = v4l2_device_register(pdev, &fmr2->v4l2_dev); | ||
210 | if (err < 0) { | ||
211 | v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n"); | ||
212 | release_region(fmr2->io, 2); | ||
213 | kfree(fmr2); | ||
214 | return err; | ||
215 | } | ||
216 | fmr2->tea.v4l2_dev = &fmr2->v4l2_dev; | ||
194 | fmr2->tea.private_data = fmr2; | 217 | fmr2->tea.private_data = fmr2; |
218 | fmr2->tea.radio_nr = radio_nr; | ||
195 | fmr2->tea.ops = &fmr2_tea_ops; | 219 | fmr2->tea.ops = &fmr2_tea_ops; |
196 | fmr2->tea.ext_init = fmr2_tea_ext_init; | 220 | fmr2->tea.ext_init = fmr2_tea_ext_init; |
197 | strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); | 221 | strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); |
198 | strcpy(fmr2->tea.bus_info, "ISA"); | 222 | snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s", |
223 | fmr2->v4l2_dev.name); | ||
199 | 224 | ||
200 | if (snd_tea575x_init(&fmr2->tea)) { | 225 | if (snd_tea575x_init(&fmr2->tea)) { |
201 | printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); | 226 | printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); |
202 | release_region(fmr2->io, 2); | 227 | release_region(fmr2->io, 2); |
228 | kfree(fmr2); | ||
203 | return -ENODEV; | 229 | return -ENODEV; |
204 | } | 230 | } |
205 | 231 | ||
@@ -207,12 +233,33 @@ static int __init fmr2_init(void) | |||
207 | return 0; | 233 | return 0; |
208 | } | 234 | } |
209 | 235 | ||
210 | static void __exit fmr2_exit(void) | 236 | static int __exit fmr2_remove(struct device *pdev, unsigned int dev) |
211 | { | 237 | { |
212 | struct fmr2 *fmr2 = &fmr2_card; | 238 | struct fmr2 *fmr2 = dev_get_drvdata(pdev); |
213 | 239 | ||
214 | snd_tea575x_exit(&fmr2->tea); | 240 | snd_tea575x_exit(&fmr2->tea); |
215 | release_region(fmr2->io, 2); | 241 | release_region(fmr2->io, 2); |
242 | v4l2_device_unregister(&fmr2->v4l2_dev); | ||
243 | kfree(fmr2); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | struct isa_driver fmr2_driver = { | ||
248 | .probe = fmr2_probe, | ||
249 | .remove = fmr2_remove, | ||
250 | .driver = { | ||
251 | .name = "radio-sf16fmr2", | ||
252 | }, | ||
253 | }; | ||
254 | |||
255 | static int __init fmr2_init(void) | ||
256 | { | ||
257 | return isa_register_driver(&fmr2_driver, 1); | ||
258 | } | ||
259 | |||
260 | static void __exit fmr2_exit(void) | ||
261 | { | ||
262 | isa_unregister_driver(&fmr2_driver); | ||
216 | } | 263 | } |
217 | 264 | ||
218 | module_init(fmr2_init); | 265 | module_init(fmr2_init); |
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index db20904d01f0..6b1fae32b483 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c | |||
@@ -575,21 +575,7 @@ static struct i2c_driver tea5764_i2c_driver = { | |||
575 | .id_table = tea5764_id, | 575 | .id_table = tea5764_id, |
576 | }; | 576 | }; |
577 | 577 | ||
578 | /* init the driver */ | 578 | module_i2c_driver(tea5764_i2c_driver); |
579 | static int __init tea5764_init(void) | ||
580 | { | ||
581 | int ret = i2c_add_driver(&tea5764_i2c_driver); | ||
582 | |||
583 | printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": " | ||
584 | DRIVER_DESC "\n"); | ||
585 | return ret; | ||
586 | } | ||
587 | |||
588 | /* cleanup the driver */ | ||
589 | static void __exit tea5764_exit(void) | ||
590 | { | ||
591 | i2c_del_driver(&tea5764_i2c_driver); | ||
592 | } | ||
593 | 579 | ||
594 | MODULE_AUTHOR(DRIVER_AUTHOR); | 580 | MODULE_AUTHOR(DRIVER_AUTHOR); |
595 | MODULE_DESCRIPTION(DRIVER_DESC); | 581 | MODULE_DESCRIPTION(DRIVER_DESC); |
@@ -600,6 +586,3 @@ module_param(use_xtal, int, 0); | |||
600 | MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); | 586 | MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); |
601 | module_param(radio_nr, int, 0); | 587 | module_param(radio_nr, int, 0); |
602 | MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); | 588 | MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); |
603 | |||
604 | module_init(tea5764_init); | ||
605 | module_exit(tea5764_exit); | ||
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index f2ed9cc3cf3b..be10a802e3a9 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c | |||
@@ -16,11 +16,7 @@ | |||
16 | * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); | 16 | * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); |
17 | * Volume Control is done digitally | 17 | * Volume Control is done digitally |
18 | * | 18 | * |
19 | * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday | 19 | * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> |
20 | * (as soon i have understand how to get started :) | ||
21 | * If you can help me out with that, please contact me!! | ||
22 | * | ||
23 | * | ||
24 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> | 20 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> |
25 | */ | 21 | */ |
26 | 22 | ||
@@ -30,43 +26,24 @@ | |||
30 | #include <linux/videodev2.h> /* kernel radio structs */ | 26 | #include <linux/videodev2.h> /* kernel radio structs */ |
31 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
32 | #include <linux/io.h> /* outb, outb_p */ | 28 | #include <linux/io.h> /* outb, outb_p */ |
29 | #include <linux/slab.h> | ||
33 | #include <media/v4l2-device.h> | 30 | #include <media/v4l2-device.h> |
34 | #include <media/v4l2-ioctl.h> | 31 | #include <media/v4l2-ioctl.h> |
32 | #include "radio-isa.h" | ||
35 | 33 | ||
36 | MODULE_AUTHOR("R.OFFERMANNS & others"); | 34 | MODULE_AUTHOR("R. Offermans & others"); |
37 | MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); | 35 | MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); |
38 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
39 | MODULE_VERSION("0.0.3"); | 37 | MODULE_VERSION("0.1.99"); |
40 | |||
41 | #ifndef CONFIG_RADIO_TERRATEC_PORT | ||
42 | #define CONFIG_RADIO_TERRATEC_PORT 0x590 | ||
43 | #endif | ||
44 | 38 | ||
45 | static int io = CONFIG_RADIO_TERRATEC_PORT; | 39 | /* Note: there seems to be only one possible port (0x590), but without |
40 | hardware this is hard to verify. For now, this is the only one we will | ||
41 | support. */ | ||
42 | static int io = 0x590; | ||
46 | static int radio_nr = -1; | 43 | static int radio_nr = -1; |
47 | 44 | ||
48 | module_param(io, int, 0); | 45 | module_param(radio_nr, int, 0444); |
49 | MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); | 46 | MODULE_PARM_DESC(radio_nr, "Radio device number"); |
50 | module_param(radio_nr, int, 0); | ||
51 | |||
52 | static struct v4l2_queryctrl radio_qctrl[] = { | ||
53 | { | ||
54 | .id = V4L2_CID_AUDIO_MUTE, | ||
55 | .name = "Mute", | ||
56 | .minimum = 0, | ||
57 | .maximum = 1, | ||
58 | .default_value = 1, | ||
59 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
60 | },{ | ||
61 | .id = V4L2_CID_AUDIO_VOLUME, | ||
62 | .name = "Volume", | ||
63 | .minimum = 0, | ||
64 | .maximum = 0xff, | ||
65 | .step = 1, | ||
66 | .default_value = 0xff, | ||
67 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
68 | } | ||
69 | }; | ||
70 | 47 | ||
71 | #define WRT_DIS 0x00 | 48 | #define WRT_DIS 0x00 |
72 | #define CLK_OFF 0x00 | 49 | #define CLK_OFF 0x00 |
@@ -76,63 +53,24 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
76 | #define CLK_ON 0x08 | 53 | #define CLK_ON 0x08 |
77 | #define WRT_EN 0x10 | 54 | #define WRT_EN 0x10 |
78 | 55 | ||
79 | struct terratec | 56 | static struct radio_isa_card *terratec_alloc(void) |
80 | { | 57 | { |
81 | struct v4l2_device v4l2_dev; | 58 | return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL); |
82 | struct video_device vdev; | 59 | } |
83 | int io; | ||
84 | int curvol; | ||
85 | unsigned long curfreq; | ||
86 | int muted; | ||
87 | struct mutex lock; | ||
88 | }; | ||
89 | |||
90 | static struct terratec terratec_card; | ||
91 | |||
92 | /* local things */ | ||
93 | 60 | ||
94 | static void tt_write_vol(struct terratec *tt, int volume) | 61 | static int terratec_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
95 | { | 62 | { |
96 | int i; | 63 | int i; |
97 | 64 | ||
98 | volume = volume + (volume * 32); /* change both channels */ | 65 | if (mute) |
99 | mutex_lock(&tt->lock); | 66 | vol = 0; |
67 | vol = vol + (vol * 32); /* change both channels */ | ||
100 | for (i = 0; i < 8; i++) { | 68 | for (i = 0; i < 8; i++) { |
101 | if (volume & (0x80 >> i)) | 69 | if (vol & (0x80 >> i)) |
102 | outb(0x80, tt->io + 1); | 70 | outb(0x80, isa->io + 1); |
103 | else | 71 | else |
104 | outb(0x00, tt->io + 1); | 72 | outb(0x00, isa->io + 1); |
105 | } | ||
106 | mutex_unlock(&tt->lock); | ||
107 | } | ||
108 | |||
109 | |||
110 | |||
111 | static void tt_mute(struct terratec *tt) | ||
112 | { | ||
113 | tt->muted = 1; | ||
114 | tt_write_vol(tt, 0); | ||
115 | } | ||
116 | |||
117 | static int tt_setvol(struct terratec *tt, int vol) | ||
118 | { | ||
119 | if (vol == tt->curvol) { /* requested volume = current */ | ||
120 | if (tt->muted) { /* user is unmuting the card */ | ||
121 | tt->muted = 0; | ||
122 | tt_write_vol(tt, vol); /* enable card */ | ||
123 | } | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | if (vol == 0) { /* volume = 0 means mute the card */ | ||
128 | tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */ | ||
129 | tt->curvol = vol; /* track the volume state! */ | ||
130 | return 0; | ||
131 | } | 73 | } |
132 | |||
133 | tt->muted = 0; | ||
134 | tt_write_vol(tt, vol); | ||
135 | tt->curvol = vol; | ||
136 | return 0; | 74 | return 0; |
137 | } | 75 | } |
138 | 76 | ||
@@ -140,20 +78,15 @@ static int tt_setvol(struct terratec *tt, int vol) | |||
140 | /* this is the worst part in this driver */ | 78 | /* this is the worst part in this driver */ |
141 | /* many more or less strange things are going on here, but hey, it works :) */ | 79 | /* many more or less strange things are going on here, but hey, it works :) */ |
142 | 80 | ||
143 | static int tt_setfreq(struct terratec *tt, unsigned long freq1) | 81 | static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq) |
144 | { | 82 | { |
145 | int freq; | ||
146 | int i; | 83 | int i; |
147 | int p; | 84 | int p; |
148 | int temp; | 85 | int temp; |
149 | long rest; | 86 | long rest; |
150 | unsigned char buffer[25]; /* we have to bit shift 25 registers */ | 87 | unsigned char buffer[25]; /* we have to bit shift 25 registers */ |
151 | 88 | ||
152 | mutex_lock(&tt->lock); | 89 | freq = freq / 160; /* convert the freq. to a nice to handle value */ |
153 | |||
154 | tt->curfreq = freq1; | ||
155 | |||
156 | freq = freq1 / 160; /* convert the freq. to a nice to handle value */ | ||
157 | memset(buffer, 0, sizeof(buffer)); | 90 | memset(buffer, 0, sizeof(buffer)); |
158 | 91 | ||
159 | rest = freq * 10 + 10700; /* I once had understood what is going on here */ | 92 | rest = freq * 10 + 10700; /* I once had understood what is going on here */ |
@@ -175,239 +108,61 @@ static int tt_setfreq(struct terratec *tt, unsigned long freq1) | |||
175 | 108 | ||
176 | for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ | 109 | for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ |
177 | if (buffer[i] == 1) { | 110 | if (buffer[i] == 1) { |
178 | outb(WRT_EN | DATA, tt->io); | 111 | outb(WRT_EN | DATA, isa->io); |
179 | outb(WRT_EN | DATA | CLK_ON, tt->io); | 112 | outb(WRT_EN | DATA | CLK_ON, isa->io); |
180 | outb(WRT_EN | DATA, tt->io); | 113 | outb(WRT_EN | DATA, isa->io); |
181 | } else { | 114 | } else { |
182 | outb(WRT_EN | 0x00, tt->io); | 115 | outb(WRT_EN | 0x00, isa->io); |
183 | outb(WRT_EN | 0x00 | CLK_ON, tt->io); | 116 | outb(WRT_EN | 0x00 | CLK_ON, isa->io); |
184 | } | ||
185 | } | ||
186 | outb(0x00, tt->io); | ||
187 | |||
188 | mutex_unlock(&tt->lock); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int tt_getsigstr(struct terratec *tt) | ||
194 | { | ||
195 | if (inb(tt->io) & 2) /* bit set = no signal present */ | ||
196 | return 0; | ||
197 | return 1; /* signal present */ | ||
198 | } | ||
199 | |||
200 | static int vidioc_querycap(struct file *file, void *priv, | ||
201 | struct v4l2_capability *v) | ||
202 | { | ||
203 | strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); | ||
204 | strlcpy(v->card, "ActiveRadio", sizeof(v->card)); | ||
205 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
206 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
211 | struct v4l2_tuner *v) | ||
212 | { | ||
213 | struct terratec *tt = video_drvdata(file); | ||
214 | |||
215 | if (v->index > 0) | ||
216 | return -EINVAL; | ||
217 | |||
218 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
219 | v->type = V4L2_TUNER_RADIO; | ||
220 | v->rangelow = 87 * 16000; | ||
221 | v->rangehigh = 108 * 16000; | ||
222 | v->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
223 | v->capability = V4L2_TUNER_CAP_LOW; | ||
224 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
225 | v->signal = 0xFFFF * tt_getsigstr(tt); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
230 | struct v4l2_tuner *v) | ||
231 | { | ||
232 | return v->index ? -EINVAL : 0; | ||
233 | } | ||
234 | |||
235 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
236 | struct v4l2_frequency *f) | ||
237 | { | ||
238 | struct terratec *tt = video_drvdata(file); | ||
239 | |||
240 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
241 | return -EINVAL; | ||
242 | tt_setfreq(tt, f->frequency); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
247 | struct v4l2_frequency *f) | ||
248 | { | ||
249 | struct terratec *tt = video_drvdata(file); | ||
250 | |||
251 | if (f->tuner != 0) | ||
252 | return -EINVAL; | ||
253 | f->type = V4L2_TUNER_RADIO; | ||
254 | f->frequency = tt->curfreq; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
259 | struct v4l2_queryctrl *qc) | ||
260 | { | ||
261 | int i; | ||
262 | |||
263 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
264 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
265 | memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); | ||
266 | return 0; | ||
267 | } | 117 | } |
268 | } | 118 | } |
269 | return -EINVAL; | 119 | outb(0x00, isa->io); |
270 | } | ||
271 | |||
272 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
273 | struct v4l2_control *ctrl) | ||
274 | { | ||
275 | struct terratec *tt = video_drvdata(file); | ||
276 | |||
277 | switch (ctrl->id) { | ||
278 | case V4L2_CID_AUDIO_MUTE: | ||
279 | if (tt->muted) | ||
280 | ctrl->value = 1; | ||
281 | else | ||
282 | ctrl->value = 0; | ||
283 | return 0; | ||
284 | case V4L2_CID_AUDIO_VOLUME: | ||
285 | ctrl->value = tt->curvol * 6554; | ||
286 | return 0; | ||
287 | } | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
292 | struct v4l2_control *ctrl) | ||
293 | { | ||
294 | struct terratec *tt = video_drvdata(file); | ||
295 | |||
296 | switch (ctrl->id) { | ||
297 | case V4L2_CID_AUDIO_MUTE: | ||
298 | if (ctrl->value) | ||
299 | tt_mute(tt); | ||
300 | else | ||
301 | tt_setvol(tt,tt->curvol); | ||
302 | return 0; | ||
303 | case V4L2_CID_AUDIO_VOLUME: | ||
304 | tt_setvol(tt,ctrl->value); | ||
305 | return 0; | ||
306 | } | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | |||
310 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
311 | { | ||
312 | *i = 0; | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
317 | { | ||
318 | return i ? -EINVAL : 0; | ||
319 | } | ||
320 | |||
321 | static int vidioc_g_audio(struct file *file, void *priv, | ||
322 | struct v4l2_audio *a) | ||
323 | { | ||
324 | a->index = 0; | ||
325 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
326 | a->capability = V4L2_AUDCAP_STEREO; | ||
327 | return 0; | 120 | return 0; |
328 | } | 121 | } |
329 | 122 | ||
330 | static int vidioc_s_audio(struct file *file, void *priv, | 123 | static u32 terratec_g_signal(struct radio_isa_card *isa) |
331 | struct v4l2_audio *a) | ||
332 | { | 124 | { |
333 | return a->index ? -EINVAL : 0; | 125 | /* bit set = no signal present */ |
126 | return (inb(isa->io) & 2) ? 0 : 0xffff; | ||
334 | } | 127 | } |
335 | 128 | ||
336 | static const struct v4l2_file_operations terratec_fops = { | 129 | static const struct radio_isa_ops terratec_ops = { |
337 | .owner = THIS_MODULE, | 130 | .alloc = terratec_alloc, |
338 | .unlocked_ioctl = video_ioctl2, | 131 | .s_mute_volume = terratec_s_mute_volume, |
132 | .s_frequency = terratec_s_frequency, | ||
133 | .g_signal = terratec_g_signal, | ||
339 | }; | 134 | }; |
340 | 135 | ||
341 | static const struct v4l2_ioctl_ops terratec_ioctl_ops = { | 136 | static const int terratec_ioports[] = { 0x590 }; |
342 | .vidioc_querycap = vidioc_querycap, | 137 | |
343 | .vidioc_g_tuner = vidioc_g_tuner, | 138 | static struct radio_isa_driver terratec_driver = { |
344 | .vidioc_s_tuner = vidioc_s_tuner, | 139 | .driver = { |
345 | .vidioc_g_frequency = vidioc_g_frequency, | 140 | .match = radio_isa_match, |
346 | .vidioc_s_frequency = vidioc_s_frequency, | 141 | .probe = radio_isa_probe, |
347 | .vidioc_queryctrl = vidioc_queryctrl, | 142 | .remove = radio_isa_remove, |
348 | .vidioc_g_ctrl = vidioc_g_ctrl, | 143 | .driver = { |
349 | .vidioc_s_ctrl = vidioc_s_ctrl, | 144 | .name = "radio-terratec", |
350 | .vidioc_g_audio = vidioc_g_audio, | 145 | }, |
351 | .vidioc_s_audio = vidioc_s_audio, | 146 | }, |
352 | .vidioc_g_input = vidioc_g_input, | 147 | .io_params = &io, |
353 | .vidioc_s_input = vidioc_s_input, | 148 | .radio_nr_params = &radio_nr, |
149 | .io_ports = terratec_ioports, | ||
150 | .num_of_io_ports = ARRAY_SIZE(terratec_ioports), | ||
151 | .region_size = 2, | ||
152 | .card = "TerraTec ActiveRadio", | ||
153 | .ops = &terratec_ops, | ||
154 | .has_stereo = true, | ||
155 | .max_volume = 10, | ||
354 | }; | 156 | }; |
355 | 157 | ||
356 | static int __init terratec_init(void) | 158 | static int __init terratec_init(void) |
357 | { | 159 | { |
358 | struct terratec *tt = &terratec_card; | 160 | return isa_register_driver(&terratec_driver.driver, 1); |
359 | struct v4l2_device *v4l2_dev = &tt->v4l2_dev; | ||
360 | int res; | ||
361 | |||
362 | strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name)); | ||
363 | tt->io = io; | ||
364 | if (tt->io == -1) { | ||
365 | v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n"); | ||
366 | return -EINVAL; | ||
367 | } | ||
368 | if (!request_region(tt->io, 2, "terratec")) { | ||
369 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", io); | ||
370 | return -EBUSY; | ||
371 | } | ||
372 | |||
373 | res = v4l2_device_register(NULL, v4l2_dev); | ||
374 | if (res < 0) { | ||
375 | release_region(tt->io, 2); | ||
376 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
377 | return res; | ||
378 | } | ||
379 | |||
380 | strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name)); | ||
381 | tt->vdev.v4l2_dev = v4l2_dev; | ||
382 | tt->vdev.fops = &terratec_fops; | ||
383 | tt->vdev.ioctl_ops = &terratec_ioctl_ops; | ||
384 | tt->vdev.release = video_device_release_empty; | ||
385 | video_set_drvdata(&tt->vdev, tt); | ||
386 | |||
387 | mutex_init(&tt->lock); | ||
388 | |||
389 | /* mute card - prevents noisy bootups */ | ||
390 | tt_write_vol(tt, 0); | ||
391 | |||
392 | if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
393 | v4l2_device_unregister(&tt->v4l2_dev); | ||
394 | release_region(tt->io, 2); | ||
395 | return -EINVAL; | ||
396 | } | ||
397 | |||
398 | v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); | ||
399 | return 0; | ||
400 | } | 161 | } |
401 | 162 | ||
402 | static void __exit terratec_exit(void) | 163 | static void __exit terratec_exit(void) |
403 | { | 164 | { |
404 | struct terratec *tt = &terratec_card; | 165 | isa_unregister_driver(&terratec_driver.driver); |
405 | struct v4l2_device *v4l2_dev = &tt->v4l2_dev; | ||
406 | |||
407 | video_unregister_device(&tt->vdev); | ||
408 | v4l2_device_unregister(&tt->v4l2_dev); | ||
409 | release_region(tt->io, 2); | ||
410 | v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n"); | ||
411 | } | 166 | } |
412 | 167 | ||
413 | module_init(terratec_init); | 168 | module_init(terratec_init); |
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index b3f45a019d82..26a8c6002121 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c | |||
@@ -21,13 +21,15 @@ | |||
21 | #include <linux/ioport.h> | 21 | #include <linux/ioport.h> |
22 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/slab.h> | ||
24 | #include <media/v4l2-device.h> | 25 | #include <media/v4l2-device.h> |
25 | #include <media/v4l2-ioctl.h> | 26 | #include <media/v4l2-ioctl.h> |
27 | #include "radio-isa.h" | ||
26 | 28 | ||
27 | MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); | 29 | MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); |
28 | MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); | 30 | MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); |
29 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
30 | MODULE_VERSION("0.0.3"); | 32 | MODULE_VERSION("0.1.99"); |
31 | 33 | ||
32 | /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ | 34 | /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ |
33 | 35 | ||
@@ -35,39 +37,38 @@ MODULE_VERSION("0.0.3"); | |||
35 | #define CONFIG_RADIO_TRUST_PORT -1 | 37 | #define CONFIG_RADIO_TRUST_PORT -1 |
36 | #endif | 38 | #endif |
37 | 39 | ||
38 | static int io = CONFIG_RADIO_TRUST_PORT; | 40 | #define TRUST_MAX 2 |
39 | static int radio_nr = -1; | ||
40 | 41 | ||
41 | module_param(io, int, 0); | 42 | static int io[TRUST_MAX] = { [0] = CONFIG_RADIO_TRUST_PORT, |
42 | MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); | 43 | [1 ... (TRUST_MAX - 1)] = -1 }; |
43 | module_param(radio_nr, int, 0); | 44 | static int radio_nr[TRUST_MAX] = { [0 ... (TRUST_MAX - 1)] = -1 }; |
45 | |||
46 | module_param_array(io, int, NULL, 0444); | ||
47 | MODULE_PARM_DESC(io, "I/O addresses of the Trust FM Radio card (0x350 or 0x358)"); | ||
48 | module_param_array(radio_nr, int, NULL, 0444); | ||
49 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); | ||
44 | 50 | ||
45 | struct trust { | 51 | struct trust { |
46 | struct v4l2_device v4l2_dev; | 52 | struct radio_isa_card isa; |
47 | struct video_device vdev; | ||
48 | int io; | ||
49 | int ioval; | 53 | int ioval; |
50 | __u16 curvol; | ||
51 | __u16 curbass; | ||
52 | __u16 curtreble; | ||
53 | int muted; | ||
54 | unsigned long curfreq; | ||
55 | int curstereo; | ||
56 | int curmute; | ||
57 | struct mutex lock; | ||
58 | }; | 54 | }; |
59 | 55 | ||
60 | static struct trust trust_card; | 56 | static struct radio_isa_card *trust_alloc(void) |
57 | { | ||
58 | struct trust *tr = kzalloc(sizeof(*tr), GFP_KERNEL); | ||
59 | |||
60 | return tr ? &tr->isa : NULL; | ||
61 | } | ||
61 | 62 | ||
62 | /* i2c addresses */ | 63 | /* i2c addresses */ |
63 | #define TDA7318_ADDR 0x88 | 64 | #define TDA7318_ADDR 0x88 |
64 | #define TSA6060T_ADDR 0xc4 | 65 | #define TSA6060T_ADDR 0xc4 |
65 | 66 | ||
66 | #define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0) | 67 | #define TR_DELAY do { inb(tr->isa.io); inb(tr->isa.io); inb(tr->isa.io); } while (0) |
67 | #define TR_SET_SCL outb(tr->ioval |= 2, tr->io) | 68 | #define TR_SET_SCL outb(tr->ioval |= 2, tr->isa.io) |
68 | #define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io) | 69 | #define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->isa.io) |
69 | #define TR_SET_SDA outb(tr->ioval |= 1, tr->io) | 70 | #define TR_SET_SDA outb(tr->ioval |= 1, tr->isa.io) |
70 | #define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io) | 71 | #define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->isa.io) |
71 | 72 | ||
72 | static void write_i2c(struct trust *tr, int n, ...) | 73 | static void write_i2c(struct trust *tr, int n, ...) |
73 | { | 74 | { |
@@ -84,10 +85,10 @@ static void write_i2c(struct trust *tr, int n, ...) | |||
84 | TR_CLR_SCL; | 85 | TR_CLR_SCL; |
85 | TR_DELAY; | 86 | TR_DELAY; |
86 | 87 | ||
87 | for(; n; n--) { | 88 | for (; n; n--) { |
88 | val = va_arg(args, unsigned); | 89 | val = va_arg(args, unsigned); |
89 | for(mask = 0x80; mask; mask >>= 1) { | 90 | for (mask = 0x80; mask; mask >>= 1) { |
90 | if(val & mask) | 91 | if (val & mask) |
91 | TR_SET_SDA; | 92 | TR_SET_SDA; |
92 | else | 93 | else |
93 | TR_CLR_SDA; | 94 | TR_CLR_SDA; |
@@ -115,317 +116,128 @@ static void write_i2c(struct trust *tr, int n, ...) | |||
115 | va_end(args); | 116 | va_end(args); |
116 | } | 117 | } |
117 | 118 | ||
118 | static void tr_setvol(struct trust *tr, __u16 vol) | 119 | static int trust_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
119 | { | 120 | { |
120 | mutex_lock(&tr->lock); | 121 | struct trust *tr = container_of(isa, struct trust, isa); |
121 | tr->curvol = vol / 2048; | ||
122 | write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f); | ||
123 | mutex_unlock(&tr->lock); | ||
124 | } | ||
125 | 122 | ||
126 | static int basstreble2chip[15] = { | 123 | tr->ioval = (tr->ioval & 0xf7) | (mute << 3); |
127 | 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 | 124 | outb(tr->ioval, isa->io); |
128 | }; | 125 | write_i2c(tr, 2, TDA7318_ADDR, vol ^ 0x1f); |
129 | 126 | return 0; | |
130 | static void tr_setbass(struct trust *tr, __u16 bass) | ||
131 | { | ||
132 | mutex_lock(&tr->lock); | ||
133 | tr->curbass = bass / 4370; | ||
134 | write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]); | ||
135 | mutex_unlock(&tr->lock); | ||
136 | } | ||
137 | |||
138 | static void tr_settreble(struct trust *tr, __u16 treble) | ||
139 | { | ||
140 | mutex_lock(&tr->lock); | ||
141 | tr->curtreble = treble / 4370; | ||
142 | write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]); | ||
143 | mutex_unlock(&tr->lock); | ||
144 | } | 127 | } |
145 | 128 | ||
146 | static void tr_setstereo(struct trust *tr, int stereo) | 129 | static int trust_s_stereo(struct radio_isa_card *isa, bool stereo) |
147 | { | 130 | { |
148 | mutex_lock(&tr->lock); | 131 | struct trust *tr = container_of(isa, struct trust, isa); |
149 | tr->curstereo = !!stereo; | ||
150 | tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2); | ||
151 | outb(tr->ioval, tr->io); | ||
152 | mutex_unlock(&tr->lock); | ||
153 | } | ||
154 | 132 | ||
155 | static void tr_setmute(struct trust *tr, int mute) | 133 | tr->ioval = (tr->ioval & 0xfb) | (!stereo << 2); |
156 | { | 134 | outb(tr->ioval, isa->io); |
157 | mutex_lock(&tr->lock); | 135 | return 0; |
158 | tr->curmute = !!mute; | ||
159 | tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3); | ||
160 | outb(tr->ioval, tr->io); | ||
161 | mutex_unlock(&tr->lock); | ||
162 | } | 136 | } |
163 | 137 | ||
164 | static int tr_getsigstr(struct trust *tr) | 138 | static u32 trust_g_signal(struct radio_isa_card *isa) |
165 | { | 139 | { |
166 | int i, v; | 140 | int i, v; |
167 | 141 | ||
168 | mutex_lock(&tr->lock); | ||
169 | for (i = 0, v = 0; i < 100; i++) | 142 | for (i = 0, v = 0; i < 100; i++) |
170 | v |= inb(tr->io); | 143 | v |= inb(isa->io); |
171 | mutex_unlock(&tr->lock); | ||
172 | return (v & 1) ? 0 : 0xffff; | 144 | return (v & 1) ? 0 : 0xffff; |
173 | } | 145 | } |
174 | 146 | ||
175 | static int tr_getstereo(struct trust *tr) | 147 | static int trust_s_frequency(struct radio_isa_card *isa, u32 freq) |
176 | { | ||
177 | /* don't know how to determine it, just return the setting */ | ||
178 | return tr->curstereo; | ||
179 | } | ||
180 | |||
181 | static void tr_setfreq(struct trust *tr, unsigned long f) | ||
182 | { | 148 | { |
183 | mutex_lock(&tr->lock); | 149 | struct trust *tr = container_of(isa, struct trust, isa); |
184 | tr->curfreq = f; | ||
185 | f /= 160; /* Convert to 10 kHz units */ | ||
186 | f += 1070; /* Add 10.7 MHz IF */ | ||
187 | write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); | ||
188 | mutex_unlock(&tr->lock); | ||
189 | } | ||
190 | 150 | ||
191 | static int vidioc_querycap(struct file *file, void *priv, | 151 | freq /= 160; /* Convert to 10 kHz units */ |
192 | struct v4l2_capability *v) | 152 | freq += 1070; /* Add 10.7 MHz IF */ |
193 | { | 153 | write_i2c(tr, 5, TSA6060T_ADDR, (freq << 1) | 1, |
194 | strlcpy(v->driver, "radio-trust", sizeof(v->driver)); | 154 | freq >> 7, 0x60 | ((freq >> 15) & 1), 0); |
195 | strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); | ||
196 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
197 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
198 | return 0; | 155 | return 0; |
199 | } | 156 | } |
200 | 157 | ||
201 | static int vidioc_g_tuner(struct file *file, void *priv, | 158 | static int basstreble2chip[15] = { |
202 | struct v4l2_tuner *v) | 159 | 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 |
203 | { | 160 | }; |
204 | struct trust *tr = video_drvdata(file); | ||
205 | |||
206 | if (v->index > 0) | ||
207 | return -EINVAL; | ||
208 | |||
209 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
210 | v->type = V4L2_TUNER_RADIO; | ||
211 | v->rangelow = 87.5 * 16000; | ||
212 | v->rangehigh = 108 * 16000; | ||
213 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
214 | v->capability = V4L2_TUNER_CAP_LOW; | ||
215 | if (tr_getstereo(tr)) | ||
216 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
217 | else | ||
218 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
219 | v->signal = tr_getsigstr(tr); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
224 | struct v4l2_tuner *v) | ||
225 | { | ||
226 | struct trust *tr = video_drvdata(file); | ||
227 | |||
228 | if (v->index) | ||
229 | return -EINVAL; | ||
230 | tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
235 | struct v4l2_frequency *f) | ||
236 | { | ||
237 | struct trust *tr = video_drvdata(file); | ||
238 | |||
239 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
240 | return -EINVAL; | ||
241 | tr_setfreq(tr, f->frequency); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
246 | struct v4l2_frequency *f) | ||
247 | { | ||
248 | struct trust *tr = video_drvdata(file); | ||
249 | |||
250 | if (f->tuner != 0) | ||
251 | return -EINVAL; | ||
252 | f->type = V4L2_TUNER_RADIO; | ||
253 | f->frequency = tr->curfreq; | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
258 | struct v4l2_queryctrl *qc) | ||
259 | { | ||
260 | switch (qc->id) { | ||
261 | case V4L2_CID_AUDIO_MUTE: | ||
262 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
263 | case V4L2_CID_AUDIO_VOLUME: | ||
264 | return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535); | ||
265 | case V4L2_CID_AUDIO_BASS: | ||
266 | case V4L2_CID_AUDIO_TREBLE: | ||
267 | return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768); | ||
268 | } | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | |||
272 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
273 | struct v4l2_control *ctrl) | ||
274 | { | ||
275 | struct trust *tr = video_drvdata(file); | ||
276 | |||
277 | switch (ctrl->id) { | ||
278 | case V4L2_CID_AUDIO_MUTE: | ||
279 | ctrl->value = tr->curmute; | ||
280 | return 0; | ||
281 | case V4L2_CID_AUDIO_VOLUME: | ||
282 | ctrl->value = tr->curvol * 2048; | ||
283 | return 0; | ||
284 | case V4L2_CID_AUDIO_BASS: | ||
285 | ctrl->value = tr->curbass * 4370; | ||
286 | return 0; | ||
287 | case V4L2_CID_AUDIO_TREBLE: | ||
288 | ctrl->value = tr->curtreble * 4370; | ||
289 | return 0; | ||
290 | } | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | 161 | ||
294 | static int vidioc_s_ctrl(struct file *file, void *priv, | 162 | static int trust_s_ctrl(struct v4l2_ctrl *ctrl) |
295 | struct v4l2_control *ctrl) | ||
296 | { | 163 | { |
297 | struct trust *tr = video_drvdata(file); | 164 | struct radio_isa_card *isa = |
165 | container_of(ctrl->handler, struct radio_isa_card, hdl); | ||
166 | struct trust *tr = container_of(isa, struct trust, isa); | ||
298 | 167 | ||
299 | switch (ctrl->id) { | 168 | switch (ctrl->id) { |
300 | case V4L2_CID_AUDIO_MUTE: | ||
301 | tr_setmute(tr, ctrl->value); | ||
302 | return 0; | ||
303 | case V4L2_CID_AUDIO_VOLUME: | ||
304 | tr_setvol(tr, ctrl->value); | ||
305 | return 0; | ||
306 | case V4L2_CID_AUDIO_BASS: | 169 | case V4L2_CID_AUDIO_BASS: |
307 | tr_setbass(tr, ctrl->value); | 170 | write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[ctrl->val]); |
308 | return 0; | 171 | return 0; |
309 | case V4L2_CID_AUDIO_TREBLE: | 172 | case V4L2_CID_AUDIO_TREBLE: |
310 | tr_settreble(tr, ctrl->value); | 173 | write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[ctrl->val]); |
311 | return 0; | 174 | return 0; |
312 | } | 175 | } |
313 | return -EINVAL; | 176 | return -EINVAL; |
314 | } | 177 | } |
315 | 178 | ||
316 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | 179 | static const struct v4l2_ctrl_ops trust_ctrl_ops = { |
317 | { | 180 | .s_ctrl = trust_s_ctrl, |
318 | *i = 0; | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
323 | { | ||
324 | return i ? -EINVAL : 0; | ||
325 | } | ||
326 | |||
327 | static int vidioc_g_audio(struct file *file, void *priv, | ||
328 | struct v4l2_audio *a) | ||
329 | { | ||
330 | a->index = 0; | ||
331 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
332 | a->capability = V4L2_AUDCAP_STEREO; | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int vidioc_s_audio(struct file *file, void *priv, | ||
337 | struct v4l2_audio *a) | ||
338 | { | ||
339 | return a->index ? -EINVAL : 0; | ||
340 | } | ||
341 | |||
342 | static const struct v4l2_file_operations trust_fops = { | ||
343 | .owner = THIS_MODULE, | ||
344 | .unlocked_ioctl = video_ioctl2, | ||
345 | }; | ||
346 | |||
347 | static const struct v4l2_ioctl_ops trust_ioctl_ops = { | ||
348 | .vidioc_querycap = vidioc_querycap, | ||
349 | .vidioc_g_tuner = vidioc_g_tuner, | ||
350 | .vidioc_s_tuner = vidioc_s_tuner, | ||
351 | .vidioc_g_frequency = vidioc_g_frequency, | ||
352 | .vidioc_s_frequency = vidioc_s_frequency, | ||
353 | .vidioc_queryctrl = vidioc_queryctrl, | ||
354 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
355 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
356 | .vidioc_g_audio = vidioc_g_audio, | ||
357 | .vidioc_s_audio = vidioc_s_audio, | ||
358 | .vidioc_g_input = vidioc_g_input, | ||
359 | .vidioc_s_input = vidioc_s_input, | ||
360 | }; | 181 | }; |
361 | 182 | ||
362 | static int __init trust_init(void) | 183 | static int trust_initialize(struct radio_isa_card *isa) |
363 | { | 184 | { |
364 | struct trust *tr = &trust_card; | 185 | struct trust *tr = container_of(isa, struct trust, isa); |
365 | struct v4l2_device *v4l2_dev = &tr->v4l2_dev; | ||
366 | int res; | ||
367 | 186 | ||
368 | strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name)); | ||
369 | tr->io = io; | ||
370 | tr->ioval = 0xf; | 187 | tr->ioval = 0xf; |
371 | mutex_init(&tr->lock); | ||
372 | |||
373 | if (tr->io == -1) { | ||
374 | v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n"); | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | if (!request_region(tr->io, 2, "Trust FM Radio")) { | ||
378 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io); | ||
379 | return -EBUSY; | ||
380 | } | ||
381 | |||
382 | res = v4l2_device_register(NULL, v4l2_dev); | ||
383 | if (res < 0) { | ||
384 | release_region(tr->io, 2); | ||
385 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
386 | return res; | ||
387 | } | ||
388 | |||
389 | strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name)); | ||
390 | tr->vdev.v4l2_dev = v4l2_dev; | ||
391 | tr->vdev.fops = &trust_fops; | ||
392 | tr->vdev.ioctl_ops = &trust_ioctl_ops; | ||
393 | tr->vdev.release = video_device_release_empty; | ||
394 | video_set_drvdata(&tr->vdev, tr); | ||
395 | |||
396 | write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ | 188 | write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ |
397 | write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ | 189 | write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ |
398 | write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ | 190 | write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ |
399 | write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ | 191 | write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ |
400 | write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ | 192 | write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ |
401 | 193 | ||
402 | tr_setvol(tr, 0xffff); | 194 | v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, |
403 | tr_setbass(tr, 0x8000); | 195 | V4L2_CID_AUDIO_BASS, 0, 15, 1, 8); |
404 | tr_settreble(tr, 0x8000); | 196 | v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, |
405 | tr_setstereo(tr, 1); | 197 | V4L2_CID_AUDIO_TREBLE, 0, 15, 1, 8); |
406 | 198 | return isa->hdl.error; | |
407 | /* mute card - prevents noisy bootups */ | 199 | } |
408 | tr_setmute(tr, 1); | ||
409 | 200 | ||
410 | if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | 201 | static const struct radio_isa_ops trust_ops = { |
411 | v4l2_device_unregister(v4l2_dev); | 202 | .init = trust_initialize, |
412 | release_region(tr->io, 2); | 203 | .alloc = trust_alloc, |
413 | return -EINVAL; | 204 | .s_mute_volume = trust_s_mute_volume, |
414 | } | 205 | .s_frequency = trust_s_frequency, |
206 | .s_stereo = trust_s_stereo, | ||
207 | .g_signal = trust_g_signal, | ||
208 | }; | ||
415 | 209 | ||
416 | v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); | 210 | static const int trust_ioports[] = { 0x350, 0x358 }; |
211 | |||
212 | static struct radio_isa_driver trust_driver = { | ||
213 | .driver = { | ||
214 | .match = radio_isa_match, | ||
215 | .probe = radio_isa_probe, | ||
216 | .remove = radio_isa_remove, | ||
217 | .driver = { | ||
218 | .name = "radio-trust", | ||
219 | }, | ||
220 | }, | ||
221 | .io_params = io, | ||
222 | .radio_nr_params = radio_nr, | ||
223 | .io_ports = trust_ioports, | ||
224 | .num_of_io_ports = ARRAY_SIZE(trust_ioports), | ||
225 | .region_size = 2, | ||
226 | .card = "Trust FM Radio", | ||
227 | .ops = &trust_ops, | ||
228 | .has_stereo = true, | ||
229 | .max_volume = 31, | ||
230 | }; | ||
417 | 231 | ||
418 | return 0; | 232 | static int __init trust_init(void) |
233 | { | ||
234 | return isa_register_driver(&trust_driver.driver, TRUST_MAX); | ||
419 | } | 235 | } |
420 | 236 | ||
421 | static void __exit cleanup_trust_module(void) | 237 | static void __exit trust_exit(void) |
422 | { | 238 | { |
423 | struct trust *tr = &trust_card; | 239 | isa_unregister_driver(&trust_driver.driver); |
424 | |||
425 | video_unregister_device(&tr->vdev); | ||
426 | v4l2_device_unregister(&tr->v4l2_dev); | ||
427 | release_region(tr->io, 2); | ||
428 | } | 240 | } |
429 | 241 | ||
430 | module_init(trust_init); | 242 | module_init(trust_init); |
431 | module_exit(cleanup_trust_module); | 243 | module_exit(trust_exit); |
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 398726abc0c8..eb72a4d13758 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c | |||
@@ -33,63 +33,53 @@ | |||
33 | #include <linux/ioport.h> /* request_region */ | 33 | #include <linux/ioport.h> /* request_region */ |
34 | #include <linux/videodev2.h> /* kernel radio structs */ | 34 | #include <linux/videodev2.h> /* kernel radio structs */ |
35 | #include <linux/io.h> /* outb, outb_p */ | 35 | #include <linux/io.h> /* outb, outb_p */ |
36 | #include <linux/slab.h> | ||
36 | #include <media/v4l2-device.h> | 37 | #include <media/v4l2-device.h> |
37 | #include <media/v4l2-ioctl.h> | 38 | #include <media/v4l2-ioctl.h> |
39 | #include "radio-isa.h" | ||
38 | 40 | ||
39 | #define DRIVER_VERSION "0.1.2" | 41 | #define DRIVER_VERSION "0.1.2" |
40 | 42 | ||
41 | MODULE_AUTHOR("Dr. Henrik Seidel"); | 43 | MODULE_AUTHOR("Dr. Henrik Seidel"); |
42 | MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); | 44 | MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); |
43 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
44 | MODULE_VERSION(DRIVER_VERSION); | 46 | MODULE_VERSION("0.1.99"); |
45 | 47 | ||
46 | #ifndef CONFIG_RADIO_TYPHOON_PORT | 48 | #ifndef CONFIG_RADIO_TYPHOON_PORT |
47 | #define CONFIG_RADIO_TYPHOON_PORT -1 | 49 | #define CONFIG_RADIO_TYPHOON_PORT -1 |
48 | #endif | 50 | #endif |
49 | 51 | ||
50 | #ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ | 52 | #ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ |
51 | #define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 | 53 | #define CONFIG_RADIO_TYPHOON_MUTEFREQ 87000 |
52 | #endif | 54 | #endif |
53 | 55 | ||
54 | static int io = CONFIG_RADIO_TYPHOON_PORT; | 56 | #define TYPHOON_MAX 2 |
55 | static int radio_nr = -1; | ||
56 | |||
57 | module_param(io, int, 0); | ||
58 | MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); | ||
59 | |||
60 | module_param(radio_nr, int, 0); | ||
61 | 57 | ||
58 | static int io[TYPHOON_MAX] = { [0] = CONFIG_RADIO_TYPHOON_PORT, | ||
59 | [1 ... (TYPHOON_MAX - 1)] = -1 }; | ||
60 | static int radio_nr[TYPHOON_MAX] = { [0 ... (TYPHOON_MAX - 1)] = -1 }; | ||
62 | static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; | 61 | static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; |
62 | |||
63 | module_param_array(io, int, NULL, 0444); | ||
64 | MODULE_PARM_DESC(io, "I/O addresses of the Typhoon card (0x316 or 0x336)"); | ||
65 | module_param_array(radio_nr, int, NULL, 0444); | ||
66 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); | ||
63 | module_param(mutefreq, ulong, 0); | 67 | module_param(mutefreq, ulong, 0); |
64 | MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); | 68 | MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); |
65 | 69 | ||
66 | #define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n" | ||
67 | |||
68 | struct typhoon { | 70 | struct typhoon { |
69 | struct v4l2_device v4l2_dev; | 71 | struct radio_isa_card isa; |
70 | struct video_device vdev; | ||
71 | int io; | ||
72 | int curvol; | ||
73 | int muted; | 72 | int muted; |
74 | unsigned long curfreq; | ||
75 | unsigned long mutefreq; | ||
76 | struct mutex lock; | ||
77 | }; | 73 | }; |
78 | 74 | ||
79 | static struct typhoon typhoon_card; | 75 | static struct radio_isa_card *typhoon_alloc(void) |
80 | |||
81 | static void typhoon_setvol_generic(struct typhoon *dev, int vol) | ||
82 | { | 76 | { |
83 | mutex_lock(&dev->lock); | 77 | struct typhoon *ty = kzalloc(sizeof(*ty), GFP_KERNEL); |
84 | vol >>= 14; /* Map 16 bit to 2 bit */ | 78 | |
85 | vol &= 3; | 79 | return ty ? &ty->isa : NULL; |
86 | outb_p(vol / 2, dev->io); /* Set the volume, high bit. */ | ||
87 | outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */ | ||
88 | mutex_unlock(&dev->lock); | ||
89 | } | 80 | } |
90 | 81 | ||
91 | static int typhoon_setfreq_generic(struct typhoon *dev, | 82 | static int typhoon_s_frequency(struct radio_isa_card *isa, u32 freq) |
92 | unsigned long frequency) | ||
93 | { | 83 | { |
94 | unsigned long outval; | 84 | unsigned long outval; |
95 | unsigned long x; | 85 | unsigned long x; |
@@ -105,302 +95,86 @@ static int typhoon_setfreq_generic(struct typhoon *dev, | |||
105 | * | 95 | * |
106 | */ | 96 | */ |
107 | 97 | ||
108 | mutex_lock(&dev->lock); | 98 | x = freq / 160; |
109 | x = frequency / 160; | ||
110 | outval = (x * x + 2500) / 5000; | 99 | outval = (x * x + 2500) / 5000; |
111 | outval = (outval * x + 5000) / 10000; | 100 | outval = (outval * x + 5000) / 10000; |
112 | outval -= (10 * x * x + 10433) / 20866; | 101 | outval -= (10 * x * x + 10433) / 20866; |
113 | outval += 4 * x - 11505; | 102 | outval += 4 * x - 11505; |
114 | 103 | ||
115 | outb_p((outval >> 8) & 0x01, dev->io + 4); | 104 | outb_p((outval >> 8) & 0x01, isa->io + 4); |
116 | outb_p(outval >> 9, dev->io + 6); | 105 | outb_p(outval >> 9, isa->io + 6); |
117 | outb_p(outval & 0xff, dev->io + 8); | 106 | outb_p(outval & 0xff, isa->io + 8); |
118 | mutex_unlock(&dev->lock); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency) | ||
124 | { | ||
125 | typhoon_setfreq_generic(dev, frequency); | ||
126 | dev->curfreq = frequency; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static void typhoon_mute(struct typhoon *dev) | ||
131 | { | ||
132 | if (dev->muted == 1) | ||
133 | return; | ||
134 | typhoon_setvol_generic(dev, 0); | ||
135 | typhoon_setfreq_generic(dev, dev->mutefreq); | ||
136 | dev->muted = 1; | ||
137 | } | ||
138 | |||
139 | static void typhoon_unmute(struct typhoon *dev) | ||
140 | { | ||
141 | if (dev->muted == 0) | ||
142 | return; | ||
143 | typhoon_setfreq_generic(dev, dev->curfreq); | ||
144 | typhoon_setvol_generic(dev, dev->curvol); | ||
145 | dev->muted = 0; | ||
146 | } | ||
147 | |||
148 | static int typhoon_setvol(struct typhoon *dev, int vol) | ||
149 | { | ||
150 | if (dev->muted && vol != 0) { /* user is unmuting the card */ | ||
151 | dev->curvol = vol; | ||
152 | typhoon_unmute(dev); | ||
153 | return 0; | ||
154 | } | ||
155 | if (vol == dev->curvol) /* requested volume == current */ | ||
156 | return 0; | ||
157 | |||
158 | if (vol == 0) { /* volume == 0 means mute the card */ | ||
159 | typhoon_mute(dev); | ||
160 | dev->curvol = vol; | ||
161 | return 0; | ||
162 | } | ||
163 | typhoon_setvol_generic(dev, vol); | ||
164 | dev->curvol = vol; | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int vidioc_querycap(struct file *file, void *priv, | ||
169 | struct v4l2_capability *v) | ||
170 | { | ||
171 | strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); | ||
172 | strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); | ||
173 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
174 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
179 | struct v4l2_tuner *v) | ||
180 | { | ||
181 | if (v->index > 0) | ||
182 | return -EINVAL; | ||
183 | |||
184 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
185 | v->type = V4L2_TUNER_RADIO; | ||
186 | v->rangelow = 87.5 * 16000; | ||
187 | v->rangehigh = 108 * 16000; | ||
188 | v->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
189 | v->capability = V4L2_TUNER_CAP_LOW; | ||
190 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
191 | v->signal = 0xFFFF; /* We can't get the signal strength */ | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
196 | struct v4l2_tuner *v) | ||
197 | { | ||
198 | return v->index ? -EINVAL : 0; | ||
199 | } | ||
200 | |||
201 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
202 | struct v4l2_frequency *f) | ||
203 | { | ||
204 | struct typhoon *dev = video_drvdata(file); | ||
205 | |||
206 | if (f->tuner != 0) | ||
207 | return -EINVAL; | ||
208 | f->type = V4L2_TUNER_RADIO; | ||
209 | f->frequency = dev->curfreq; | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
214 | struct v4l2_frequency *f) | ||
215 | { | ||
216 | struct typhoon *dev = video_drvdata(file); | ||
217 | |||
218 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
219 | return -EINVAL; | ||
220 | dev->curfreq = f->frequency; | ||
221 | typhoon_setfreq(dev, dev->curfreq); | ||
222 | return 0; | 107 | return 0; |
223 | } | 108 | } |
224 | 109 | ||
225 | static int vidioc_queryctrl(struct file *file, void *priv, | 110 | static int typhoon_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
226 | struct v4l2_queryctrl *qc) | ||
227 | { | 111 | { |
228 | switch (qc->id) { | 112 | struct typhoon *ty = container_of(isa, struct typhoon, isa); |
229 | case V4L2_CID_AUDIO_MUTE: | ||
230 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
231 | case V4L2_CID_AUDIO_VOLUME: | ||
232 | return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535); | ||
233 | } | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | 113 | ||
237 | static int vidioc_g_ctrl(struct file *file, void *priv, | 114 | if (mute) |
238 | struct v4l2_control *ctrl) | 115 | vol = 0; |
239 | { | 116 | vol >>= 14; /* Map 16 bit to 2 bit */ |
240 | struct typhoon *dev = video_drvdata(file); | 117 | vol &= 3; |
118 | outb_p(vol / 2, isa->io); /* Set the volume, high bit. */ | ||
119 | outb_p(vol % 2, isa->io + 2); /* Set the volume, low bit. */ | ||
241 | 120 | ||
242 | switch (ctrl->id) { | 121 | if (vol == 0 && !ty->muted) { |
243 | case V4L2_CID_AUDIO_MUTE: | 122 | ty->muted = true; |
244 | ctrl->value = dev->muted; | 123 | return typhoon_s_frequency(isa, mutefreq << 4); |
245 | return 0; | ||
246 | case V4L2_CID_AUDIO_VOLUME: | ||
247 | ctrl->value = dev->curvol; | ||
248 | return 0; | ||
249 | } | 124 | } |
250 | return -EINVAL; | 125 | if (vol && ty->muted) { |
251 | } | 126 | ty->muted = false; |
252 | 127 | return typhoon_s_frequency(isa, isa->freq); | |
253 | static int vidioc_s_ctrl (struct file *file, void *priv, | ||
254 | struct v4l2_control *ctrl) | ||
255 | { | ||
256 | struct typhoon *dev = video_drvdata(file); | ||
257 | |||
258 | switch (ctrl->id) { | ||
259 | case V4L2_CID_AUDIO_MUTE: | ||
260 | if (ctrl->value) | ||
261 | typhoon_mute(dev); | ||
262 | else | ||
263 | typhoon_unmute(dev); | ||
264 | return 0; | ||
265 | case V4L2_CID_AUDIO_VOLUME: | ||
266 | typhoon_setvol(dev, ctrl->value); | ||
267 | return 0; | ||
268 | } | 128 | } |
269 | return -EINVAL; | ||
270 | } | ||
271 | |||
272 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
273 | { | ||
274 | *i = 0; | ||
275 | return 0; | 129 | return 0; |
276 | } | 130 | } |
277 | 131 | ||
278 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | 132 | static const struct radio_isa_ops typhoon_ops = { |
279 | { | 133 | .alloc = typhoon_alloc, |
280 | return i ? -EINVAL : 0; | 134 | .s_mute_volume = typhoon_s_mute_volume, |
281 | } | 135 | .s_frequency = typhoon_s_frequency, |
282 | |||
283 | static int vidioc_g_audio(struct file *file, void *priv, | ||
284 | struct v4l2_audio *a) | ||
285 | { | ||
286 | a->index = 0; | ||
287 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
288 | a->capability = V4L2_AUDCAP_STEREO; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int vidioc_s_audio(struct file *file, void *priv, | ||
293 | struct v4l2_audio *a) | ||
294 | { | ||
295 | return a->index ? -EINVAL : 0; | ||
296 | } | ||
297 | |||
298 | static int vidioc_log_status(struct file *file, void *priv) | ||
299 | { | ||
300 | struct typhoon *dev = video_drvdata(file); | ||
301 | struct v4l2_device *v4l2_dev = &dev->v4l2_dev; | ||
302 | |||
303 | v4l2_info(v4l2_dev, BANNER); | ||
304 | #ifdef MODULE | ||
305 | v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n"); | ||
306 | #else | ||
307 | v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n"); | ||
308 | #endif | ||
309 | v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4); | ||
310 | v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol); | ||
311 | v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off"); | ||
312 | v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io); | ||
313 | v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static const struct v4l2_file_operations typhoon_fops = { | ||
318 | .owner = THIS_MODULE, | ||
319 | .unlocked_ioctl = video_ioctl2, | ||
320 | }; | 136 | }; |
321 | 137 | ||
322 | static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { | 138 | static const int typhoon_ioports[] = { 0x316, 0x336 }; |
323 | .vidioc_log_status = vidioc_log_status, | 139 | |
324 | .vidioc_querycap = vidioc_querycap, | 140 | static struct radio_isa_driver typhoon_driver = { |
325 | .vidioc_g_tuner = vidioc_g_tuner, | 141 | .driver = { |
326 | .vidioc_s_tuner = vidioc_s_tuner, | 142 | .match = radio_isa_match, |
327 | .vidioc_g_audio = vidioc_g_audio, | 143 | .probe = radio_isa_probe, |
328 | .vidioc_s_audio = vidioc_s_audio, | 144 | .remove = radio_isa_remove, |
329 | .vidioc_g_input = vidioc_g_input, | 145 | .driver = { |
330 | .vidioc_s_input = vidioc_s_input, | 146 | .name = "radio-typhoon", |
331 | .vidioc_g_frequency = vidioc_g_frequency, | 147 | }, |
332 | .vidioc_s_frequency = vidioc_s_frequency, | 148 | }, |
333 | .vidioc_queryctrl = vidioc_queryctrl, | 149 | .io_params = io, |
334 | .vidioc_g_ctrl = vidioc_g_ctrl, | 150 | .radio_nr_params = radio_nr, |
335 | .vidioc_s_ctrl = vidioc_s_ctrl, | 151 | .io_ports = typhoon_ioports, |
152 | .num_of_io_ports = ARRAY_SIZE(typhoon_ioports), | ||
153 | .region_size = 8, | ||
154 | .card = "Typhoon Radio", | ||
155 | .ops = &typhoon_ops, | ||
156 | .has_stereo = true, | ||
157 | .max_volume = 3, | ||
336 | }; | 158 | }; |
337 | 159 | ||
338 | static int __init typhoon_init(void) | 160 | static int __init typhoon_init(void) |
339 | { | 161 | { |
340 | struct typhoon *dev = &typhoon_card; | 162 | if (mutefreq < 87000 || mutefreq > 108000) { |
341 | struct v4l2_device *v4l2_dev = &dev->v4l2_dev; | 163 | printk(KERN_ERR "%s: You must set a frequency (in kHz) used when muting the card,\n", |
342 | int res; | 164 | typhoon_driver.driver.driver.name); |
343 | 165 | printk(KERN_ERR "%s: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108000)\n", | |
344 | strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); | 166 | typhoon_driver.driver.driver.name); |
345 | dev->io = io; | 167 | return -ENODEV; |
346 | |||
347 | if (dev->io == -1) { | ||
348 | v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); | ||
349 | return -EINVAL; | ||
350 | } | ||
351 | |||
352 | if (mutefreq < 87000 || mutefreq > 108500) { | ||
353 | v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); | ||
354 | v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); | ||
355 | return -EINVAL; | ||
356 | } | ||
357 | dev->curfreq = dev->mutefreq = mutefreq << 4; | ||
358 | |||
359 | mutex_init(&dev->lock); | ||
360 | if (!request_region(dev->io, 8, "typhoon")) { | ||
361 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", | ||
362 | dev->io); | ||
363 | return -EBUSY; | ||
364 | } | ||
365 | |||
366 | res = v4l2_device_register(NULL, v4l2_dev); | ||
367 | if (res < 0) { | ||
368 | release_region(dev->io, 8); | ||
369 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
370 | return res; | ||
371 | } | 168 | } |
372 | v4l2_info(v4l2_dev, BANNER); | 169 | return isa_register_driver(&typhoon_driver.driver, TYPHOON_MAX); |
373 | |||
374 | strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); | ||
375 | dev->vdev.v4l2_dev = v4l2_dev; | ||
376 | dev->vdev.fops = &typhoon_fops; | ||
377 | dev->vdev.ioctl_ops = &typhoon_ioctl_ops; | ||
378 | dev->vdev.release = video_device_release_empty; | ||
379 | video_set_drvdata(&dev->vdev, dev); | ||
380 | |||
381 | /* mute card - prevents noisy bootups */ | ||
382 | typhoon_mute(dev); | ||
383 | |||
384 | if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
385 | v4l2_device_unregister(&dev->v4l2_dev); | ||
386 | release_region(dev->io, 8); | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); | ||
390 | v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq); | ||
391 | |||
392 | return 0; | ||
393 | } | 170 | } |
394 | 171 | ||
395 | static void __exit typhoon_exit(void) | 172 | static void __exit typhoon_exit(void) |
396 | { | 173 | { |
397 | struct typhoon *dev = &typhoon_card; | 174 | isa_unregister_driver(&typhoon_driver.driver); |
398 | |||
399 | video_unregister_device(&dev->vdev); | ||
400 | v4l2_device_unregister(&dev->v4l2_dev); | ||
401 | release_region(dev->io, 8); | ||
402 | } | 175 | } |
403 | 176 | ||
177 | |||
404 | module_init(typhoon_init); | 178 | module_init(typhoon_init); |
405 | module_exit(typhoon_exit); | 179 | module_exit(typhoon_exit); |
406 | 180 | ||
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index f5613b948203..026e88eef29c 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* zoltrix radio plus driver for Linux radio support | 1 | /* |
2 | * (c) 1998 C. van Schaik <carl@leg.uct.ac.za> | 2 | * Zoltrix Radio Plus driver |
3 | * Copyright 1998 C. van Schaik <carl@leg.uct.ac.za> | ||
3 | * | 4 | * |
4 | * BUGS | 5 | * BUGS |
5 | * Due to the inconsistency in reading from the signal flags | 6 | * Due to the inconsistency in reading from the signal flags |
@@ -27,6 +28,14 @@ | |||
27 | * | 28 | * |
28 | * 2006-07-24 - Converted to V4L2 API | 29 | * 2006-07-24 - Converted to V4L2 API |
29 | * by Mauro Carvalho Chehab <mchehab@infradead.org> | 30 | * by Mauro Carvalho Chehab <mchehab@infradead.org> |
31 | * | ||
32 | * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> | ||
33 | * | ||
34 | * Note that this is the driver for the Zoltrix Radio Plus. | ||
35 | * This driver does not work for the Zoltrix Radio Plus 108 or the | ||
36 | * Zoltrix Radio Plus for Windows. | ||
37 | * | ||
38 | * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. | ||
30 | */ | 39 | */ |
31 | 40 | ||
32 | #include <linux/module.h> /* Modules */ | 41 | #include <linux/module.h> /* Modules */ |
@@ -36,82 +45,70 @@ | |||
36 | #include <linux/videodev2.h> /* kernel radio structs */ | 45 | #include <linux/videodev2.h> /* kernel radio structs */ |
37 | #include <linux/mutex.h> | 46 | #include <linux/mutex.h> |
38 | #include <linux/io.h> /* outb, outb_p */ | 47 | #include <linux/io.h> /* outb, outb_p */ |
48 | #include <linux/slab.h> | ||
39 | #include <media/v4l2-device.h> | 49 | #include <media/v4l2-device.h> |
40 | #include <media/v4l2-ioctl.h> | 50 | #include <media/v4l2-ioctl.h> |
51 | #include "radio-isa.h" | ||
41 | 52 | ||
42 | MODULE_AUTHOR("C.van Schaik"); | 53 | MODULE_AUTHOR("C. van Schaik"); |
43 | MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); | 54 | MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); |
44 | MODULE_LICENSE("GPL"); | 55 | MODULE_LICENSE("GPL"); |
45 | MODULE_VERSION("0.0.3"); | 56 | MODULE_VERSION("0.1.99"); |
46 | 57 | ||
47 | #ifndef CONFIG_RADIO_ZOLTRIX_PORT | 58 | #ifndef CONFIG_RADIO_ZOLTRIX_PORT |
48 | #define CONFIG_RADIO_ZOLTRIX_PORT -1 | 59 | #define CONFIG_RADIO_ZOLTRIX_PORT -1 |
49 | #endif | 60 | #endif |
50 | 61 | ||
51 | static int io = CONFIG_RADIO_ZOLTRIX_PORT; | 62 | #define ZOLTRIX_MAX 2 |
52 | static int radio_nr = -1; | 63 | |
64 | static int io[ZOLTRIX_MAX] = { [0] = CONFIG_RADIO_ZOLTRIX_PORT, | ||
65 | [1 ... (ZOLTRIX_MAX - 1)] = -1 }; | ||
66 | static int radio_nr[ZOLTRIX_MAX] = { [0 ... (ZOLTRIX_MAX - 1)] = -1 }; | ||
53 | 67 | ||
54 | module_param(io, int, 0); | 68 | module_param_array(io, int, NULL, 0444); |
55 | MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); | 69 | MODULE_PARM_DESC(io, "I/O addresses of the Zoltrix Radio Plus card (0x20c or 0x30c)"); |
56 | module_param(radio_nr, int, 0); | 70 | module_param_array(radio_nr, int, NULL, 0444); |
71 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); | ||
57 | 72 | ||
58 | struct zoltrix { | 73 | struct zoltrix { |
59 | struct v4l2_device v4l2_dev; | 74 | struct radio_isa_card isa; |
60 | struct video_device vdev; | ||
61 | int io; | ||
62 | int curvol; | 75 | int curvol; |
63 | unsigned long curfreq; | 76 | bool muted; |
64 | int muted; | ||
65 | unsigned int stereo; | ||
66 | struct mutex lock; | ||
67 | }; | 77 | }; |
68 | 78 | ||
69 | static struct zoltrix zoltrix_card; | 79 | static struct radio_isa_card *zoltrix_alloc(void) |
80 | { | ||
81 | struct zoltrix *zol = kzalloc(sizeof(*zol), GFP_KERNEL); | ||
82 | |||
83 | return zol ? &zol->isa : NULL; | ||
84 | } | ||
70 | 85 | ||
71 | static int zol_setvol(struct zoltrix *zol, int vol) | 86 | static int zoltrix_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
72 | { | 87 | { |
73 | zol->curvol = vol; | 88 | struct zoltrix *zol = container_of(isa, struct zoltrix, isa); |
74 | if (zol->muted) | ||
75 | return 0; | ||
76 | 89 | ||
77 | mutex_lock(&zol->lock); | 90 | zol->curvol = vol; |
78 | if (vol == 0) { | 91 | zol->muted = mute; |
79 | outb(0, zol->io); | 92 | if (mute || vol == 0) { |
80 | outb(0, zol->io); | 93 | outb(0, isa->io); |
81 | inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ | 94 | outb(0, isa->io); |
82 | mutex_unlock(&zol->lock); | 95 | inb(isa->io + 3); /* Zoltrix needs to be read to confirm */ |
83 | return 0; | 96 | return 0; |
84 | } | 97 | } |
85 | 98 | ||
86 | outb(zol->curvol-1, zol->io); | 99 | outb(vol - 1, isa->io); |
87 | msleep(10); | 100 | msleep(10); |
88 | inb(zol->io + 2); | 101 | inb(isa->io + 2); |
89 | mutex_unlock(&zol->lock); | ||
90 | return 0; | 102 | return 0; |
91 | } | 103 | } |
92 | 104 | ||
93 | static void zol_mute(struct zoltrix *zol) | 105 | /* tunes the radio to the desired frequency */ |
94 | { | 106 | static int zoltrix_s_frequency(struct radio_isa_card *isa, u32 freq) |
95 | zol->muted = 1; | ||
96 | mutex_lock(&zol->lock); | ||
97 | outb(0, zol->io); | ||
98 | outb(0, zol->io); | ||
99 | inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ | ||
100 | mutex_unlock(&zol->lock); | ||
101 | } | ||
102 | |||
103 | static void zol_unmute(struct zoltrix *zol) | ||
104 | { | ||
105 | zol->muted = 0; | ||
106 | zol_setvol(zol, zol->curvol); | ||
107 | } | ||
108 | |||
109 | static int zol_setfreq(struct zoltrix *zol, unsigned long freq) | ||
110 | { | 107 | { |
111 | /* tunes the radio to the desired frequency */ | 108 | struct zoltrix *zol = container_of(isa, struct zoltrix, isa); |
112 | struct v4l2_device *v4l2_dev = &zol->v4l2_dev; | 109 | struct v4l2_device *v4l2_dev = &isa->v4l2_dev; |
113 | unsigned long long bitmask, f, m; | 110 | unsigned long long bitmask, f, m; |
114 | unsigned int stereo = zol->stereo; | 111 | bool stereo = isa->stereo; |
115 | int i; | 112 | int i; |
116 | 113 | ||
117 | if (freq == 0) { | 114 | if (freq == 0) { |
@@ -125,340 +122,125 @@ static int zol_setfreq(struct zoltrix *zol, unsigned long freq) | |||
125 | bitmask = 0xc480402c10080000ull; | 122 | bitmask = 0xc480402c10080000ull; |
126 | i = 45; | 123 | i = 45; |
127 | 124 | ||
128 | mutex_lock(&zol->lock); | 125 | outb(0, isa->io); |
129 | 126 | outb(0, isa->io); | |
130 | zol->curfreq = freq; | 127 | inb(isa->io + 3); /* Zoltrix needs to be read to confirm */ |
131 | |||
132 | outb(0, zol->io); | ||
133 | outb(0, zol->io); | ||
134 | inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ | ||
135 | 128 | ||
136 | outb(0x40, zol->io); | 129 | outb(0x40, isa->io); |
137 | outb(0xc0, zol->io); | 130 | outb(0xc0, isa->io); |
138 | 131 | ||
139 | bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31)); | 132 | bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31)); |
140 | while (i--) { | 133 | while (i--) { |
141 | if ((bitmask & 0x8000000000000000ull) != 0) { | 134 | if ((bitmask & 0x8000000000000000ull) != 0) { |
142 | outb(0x80, zol->io); | 135 | outb(0x80, isa->io); |
143 | udelay(50); | 136 | udelay(50); |
144 | outb(0x00, zol->io); | 137 | outb(0x00, isa->io); |
145 | udelay(50); | 138 | udelay(50); |
146 | outb(0x80, zol->io); | 139 | outb(0x80, isa->io); |
147 | udelay(50); | 140 | udelay(50); |
148 | } else { | 141 | } else { |
149 | outb(0xc0, zol->io); | 142 | outb(0xc0, isa->io); |
150 | udelay(50); | 143 | udelay(50); |
151 | outb(0x40, zol->io); | 144 | outb(0x40, isa->io); |
152 | udelay(50); | 145 | udelay(50); |
153 | outb(0xc0, zol->io); | 146 | outb(0xc0, isa->io); |
154 | udelay(50); | 147 | udelay(50); |
155 | } | 148 | } |
156 | bitmask *= 2; | 149 | bitmask *= 2; |
157 | } | 150 | } |
158 | /* termination sequence */ | 151 | /* termination sequence */ |
159 | outb(0x80, zol->io); | 152 | outb(0x80, isa->io); |
160 | outb(0xc0, zol->io); | 153 | outb(0xc0, isa->io); |
161 | outb(0x40, zol->io); | 154 | outb(0x40, isa->io); |
162 | udelay(1000); | 155 | udelay(1000); |
163 | inb(zol->io + 2); | 156 | inb(isa->io + 2); |
164 | |||
165 | udelay(1000); | 157 | udelay(1000); |
166 | 158 | ||
167 | if (zol->muted) { | 159 | return zoltrix_s_mute_volume(isa, zol->muted, zol->curvol); |
168 | outb(0, zol->io); | ||
169 | outb(0, zol->io); | ||
170 | inb(zol->io + 3); | ||
171 | udelay(1000); | ||
172 | } | ||
173 | |||
174 | mutex_unlock(&zol->lock); | ||
175 | |||
176 | if (!zol->muted) | ||
177 | zol_setvol(zol, zol->curvol); | ||
178 | return 0; | ||
179 | } | 160 | } |
180 | 161 | ||
181 | /* Get signal strength */ | 162 | /* Get signal strength */ |
182 | static int zol_getsigstr(struct zoltrix *zol) | 163 | static u32 zoltrix_g_rxsubchans(struct radio_isa_card *isa) |
183 | { | 164 | { |
165 | struct zoltrix *zol = container_of(isa, struct zoltrix, isa); | ||
184 | int a, b; | 166 | int a, b; |
185 | 167 | ||
186 | mutex_lock(&zol->lock); | 168 | outb(0x00, isa->io); /* This stuff I found to do nothing */ |
187 | outb(0x00, zol->io); /* This stuff I found to do nothing */ | 169 | outb(zol->curvol, isa->io); |
188 | outb(zol->curvol, zol->io); | ||
189 | msleep(20); | 170 | msleep(20); |
190 | 171 | ||
191 | a = inb(zol->io); | 172 | a = inb(isa->io); |
192 | msleep(10); | 173 | msleep(10); |
193 | b = inb(zol->io); | 174 | b = inb(isa->io); |
194 | 175 | ||
195 | mutex_unlock(&zol->lock); | 176 | return (a == b && a == 0xcf) ? |
196 | 177 | V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; | |
197 | if (a != b) | ||
198 | return 0; | ||
199 | |||
200 | /* I found this out by playing with a binary scanner on the card io */ | ||
201 | return a == 0xcf || a == 0xdf || a == 0xef; | ||
202 | } | 178 | } |
203 | 179 | ||
204 | static int zol_is_stereo(struct zoltrix *zol) | 180 | static u32 zoltrix_g_signal(struct radio_isa_card *isa) |
205 | { | 181 | { |
206 | int x1, x2; | 182 | struct zoltrix *zol = container_of(isa, struct zoltrix, isa); |
207 | 183 | int a, b; | |
208 | mutex_lock(&zol->lock); | ||
209 | 184 | ||
210 | outb(0x00, zol->io); | 185 | outb(0x00, isa->io); /* This stuff I found to do nothing */ |
211 | outb(zol->curvol, zol->io); | 186 | outb(zol->curvol, isa->io); |
212 | msleep(20); | 187 | msleep(20); |
213 | 188 | ||
214 | x1 = inb(zol->io); | 189 | a = inb(isa->io); |
215 | msleep(10); | 190 | msleep(10); |
216 | x2 = inb(zol->io); | 191 | b = inb(isa->io); |
217 | |||
218 | mutex_unlock(&zol->lock); | ||
219 | |||
220 | return x1 == x2 && x1 == 0xcf; | ||
221 | } | ||
222 | |||
223 | static int vidioc_querycap(struct file *file, void *priv, | ||
224 | struct v4l2_capability *v) | ||
225 | { | ||
226 | strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); | ||
227 | strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); | ||
228 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
229 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
234 | struct v4l2_tuner *v) | ||
235 | { | ||
236 | struct zoltrix *zol = video_drvdata(file); | ||
237 | |||
238 | if (v->index > 0) | ||
239 | return -EINVAL; | ||
240 | |||
241 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
242 | v->type = V4L2_TUNER_RADIO; | ||
243 | v->rangelow = 88 * 16000; | ||
244 | v->rangehigh = 108 * 16000; | ||
245 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
246 | v->capability = V4L2_TUNER_CAP_LOW; | ||
247 | if (zol_is_stereo(zol)) | ||
248 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
249 | else | ||
250 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
251 | v->signal = 0xFFFF * zol_getsigstr(zol); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
256 | struct v4l2_tuner *v) | ||
257 | { | ||
258 | return v->index ? -EINVAL : 0; | ||
259 | } | ||
260 | |||
261 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
262 | struct v4l2_frequency *f) | ||
263 | { | ||
264 | struct zoltrix *zol = video_drvdata(file); | ||
265 | |||
266 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
267 | return -EINVAL; | ||
268 | if (zol_setfreq(zol, f->frequency) != 0) | ||
269 | return -EINVAL; | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
274 | struct v4l2_frequency *f) | ||
275 | { | ||
276 | struct zoltrix *zol = video_drvdata(file); | ||
277 | 192 | ||
278 | if (f->tuner != 0) | 193 | if (a != b) |
279 | return -EINVAL; | ||
280 | f->type = V4L2_TUNER_RADIO; | ||
281 | f->frequency = zol->curfreq; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
286 | struct v4l2_queryctrl *qc) | ||
287 | { | ||
288 | switch (qc->id) { | ||
289 | case V4L2_CID_AUDIO_MUTE: | ||
290 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
291 | case V4L2_CID_AUDIO_VOLUME: | ||
292 | return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535); | ||
293 | } | ||
294 | return -EINVAL; | ||
295 | } | ||
296 | |||
297 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
298 | struct v4l2_control *ctrl) | ||
299 | { | ||
300 | struct zoltrix *zol = video_drvdata(file); | ||
301 | |||
302 | switch (ctrl->id) { | ||
303 | case V4L2_CID_AUDIO_MUTE: | ||
304 | ctrl->value = zol->muted; | ||
305 | return 0; | ||
306 | case V4L2_CID_AUDIO_VOLUME: | ||
307 | ctrl->value = zol->curvol * 4096; | ||
308 | return 0; | ||
309 | } | ||
310 | return -EINVAL; | ||
311 | } | ||
312 | |||
313 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
314 | struct v4l2_control *ctrl) | ||
315 | { | ||
316 | struct zoltrix *zol = video_drvdata(file); | ||
317 | |||
318 | switch (ctrl->id) { | ||
319 | case V4L2_CID_AUDIO_MUTE: | ||
320 | if (ctrl->value) | ||
321 | zol_mute(zol); | ||
322 | else { | ||
323 | zol_unmute(zol); | ||
324 | zol_setvol(zol, zol->curvol); | ||
325 | } | ||
326 | return 0; | ||
327 | case V4L2_CID_AUDIO_VOLUME: | ||
328 | zol_setvol(zol, ctrl->value / 4096); | ||
329 | return 0; | 194 | return 0; |
330 | } | ||
331 | zol->stereo = 1; | ||
332 | if (zol_setfreq(zol, zol->curfreq) != 0) | ||
333 | return -EINVAL; | ||
334 | #if 0 | ||
335 | /* FIXME: Implement stereo/mono switch on V4L2 */ | ||
336 | if (v->mode & VIDEO_SOUND_STEREO) { | ||
337 | zol->stereo = 1; | ||
338 | zol_setfreq(zol, zol->curfreq); | ||
339 | } | ||
340 | if (v->mode & VIDEO_SOUND_MONO) { | ||
341 | zol->stereo = 0; | ||
342 | zol_setfreq(zol, zol->curfreq); | ||
343 | } | ||
344 | #endif | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
349 | { | ||
350 | *i = 0; | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
355 | { | ||
356 | return i ? -EINVAL : 0; | ||
357 | } | ||
358 | 195 | ||
359 | static int vidioc_g_audio(struct file *file, void *priv, | 196 | /* I found this out by playing with a binary scanner on the card io */ |
360 | struct v4l2_audio *a) | 197 | return (a == 0xcf || a == 0xdf || a == 0xef) ? 0xffff : 0; |
361 | { | ||
362 | a->index = 0; | ||
363 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
364 | a->capability = V4L2_AUDCAP_STEREO; | ||
365 | return 0; | ||
366 | } | 198 | } |
367 | 199 | ||
368 | static int vidioc_s_audio(struct file *file, void *priv, | 200 | static int zoltrix_s_stereo(struct radio_isa_card *isa, bool stereo) |
369 | struct v4l2_audio *a) | ||
370 | { | 201 | { |
371 | return a->index ? -EINVAL : 0; | 202 | return zoltrix_s_frequency(isa, isa->freq); |
372 | } | 203 | } |
373 | 204 | ||
374 | static const struct v4l2_file_operations zoltrix_fops = | 205 | static const struct radio_isa_ops zoltrix_ops = { |
375 | { | 206 | .alloc = zoltrix_alloc, |
376 | .owner = THIS_MODULE, | 207 | .s_mute_volume = zoltrix_s_mute_volume, |
377 | .unlocked_ioctl = video_ioctl2, | 208 | .s_frequency = zoltrix_s_frequency, |
209 | .s_stereo = zoltrix_s_stereo, | ||
210 | .g_rxsubchans = zoltrix_g_rxsubchans, | ||
211 | .g_signal = zoltrix_g_signal, | ||
378 | }; | 212 | }; |
379 | 213 | ||
380 | static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { | 214 | static const int zoltrix_ioports[] = { 0x20c, 0x30c }; |
381 | .vidioc_querycap = vidioc_querycap, | 215 | |
382 | .vidioc_g_tuner = vidioc_g_tuner, | 216 | static struct radio_isa_driver zoltrix_driver = { |
383 | .vidioc_s_tuner = vidioc_s_tuner, | 217 | .driver = { |
384 | .vidioc_g_audio = vidioc_g_audio, | 218 | .match = radio_isa_match, |
385 | .vidioc_s_audio = vidioc_s_audio, | 219 | .probe = radio_isa_probe, |
386 | .vidioc_g_input = vidioc_g_input, | 220 | .remove = radio_isa_remove, |
387 | .vidioc_s_input = vidioc_s_input, | 221 | .driver = { |
388 | .vidioc_g_frequency = vidioc_g_frequency, | 222 | .name = "radio-zoltrix", |
389 | .vidioc_s_frequency = vidioc_s_frequency, | 223 | }, |
390 | .vidioc_queryctrl = vidioc_queryctrl, | 224 | }, |
391 | .vidioc_g_ctrl = vidioc_g_ctrl, | 225 | .io_params = io, |
392 | .vidioc_s_ctrl = vidioc_s_ctrl, | 226 | .radio_nr_params = radio_nr, |
227 | .io_ports = zoltrix_ioports, | ||
228 | .num_of_io_ports = ARRAY_SIZE(zoltrix_ioports), | ||
229 | .region_size = 2, | ||
230 | .card = "Zoltrix Radio Plus", | ||
231 | .ops = &zoltrix_ops, | ||
232 | .has_stereo = true, | ||
233 | .max_volume = 15, | ||
393 | }; | 234 | }; |
394 | 235 | ||
395 | static int __init zoltrix_init(void) | 236 | static int __init zoltrix_init(void) |
396 | { | 237 | { |
397 | struct zoltrix *zol = &zoltrix_card; | 238 | return isa_register_driver(&zoltrix_driver.driver, ZOLTRIX_MAX); |
398 | struct v4l2_device *v4l2_dev = &zol->v4l2_dev; | ||
399 | int res; | ||
400 | |||
401 | strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name)); | ||
402 | zol->io = io; | ||
403 | if (zol->io == -1) { | ||
404 | v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n"); | ||
405 | return -EINVAL; | ||
406 | } | ||
407 | if (zol->io != 0x20c && zol->io != 0x30c) { | ||
408 | v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n"); | ||
409 | return -ENXIO; | ||
410 | } | ||
411 | |||
412 | if (!request_region(zol->io, 2, "zoltrix")) { | ||
413 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io); | ||
414 | return -EBUSY; | ||
415 | } | ||
416 | |||
417 | res = v4l2_device_register(NULL, v4l2_dev); | ||
418 | if (res < 0) { | ||
419 | release_region(zol->io, 2); | ||
420 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
421 | return res; | ||
422 | } | ||
423 | |||
424 | mutex_init(&zol->lock); | ||
425 | |||
426 | /* mute card - prevents noisy bootups */ | ||
427 | |||
428 | /* this ensures that the volume is all the way down */ | ||
429 | |||
430 | outb(0, zol->io); | ||
431 | outb(0, zol->io); | ||
432 | msleep(20); | ||
433 | inb(zol->io + 3); | ||
434 | |||
435 | zol->curvol = 0; | ||
436 | zol->stereo = 1; | ||
437 | |||
438 | strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); | ||
439 | zol->vdev.v4l2_dev = v4l2_dev; | ||
440 | zol->vdev.fops = &zoltrix_fops; | ||
441 | zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; | ||
442 | zol->vdev.release = video_device_release_empty; | ||
443 | video_set_drvdata(&zol->vdev, zol); | ||
444 | |||
445 | if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | ||
446 | v4l2_device_unregister(v4l2_dev); | ||
447 | release_region(zol->io, 2); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); | ||
451 | |||
452 | return 0; | ||
453 | } | 239 | } |
454 | 240 | ||
455 | static void __exit zoltrix_exit(void) | 241 | static void __exit zoltrix_exit(void) |
456 | { | 242 | { |
457 | struct zoltrix *zol = &zoltrix_card; | 243 | isa_unregister_driver(&zoltrix_driver.driver); |
458 | |||
459 | video_unregister_device(&zol->vdev); | ||
460 | v4l2_device_unregister(&zol->v4l2_dev); | ||
461 | release_region(zol->io, 2); | ||
462 | } | 244 | } |
463 | 245 | ||
464 | module_init(zoltrix_init); | 246 | module_init(zoltrix_init); |
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index b1193dfc5087..9474706350f8 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c | |||
@@ -434,18 +434,7 @@ static struct i2c_driver saa7706h_driver = { | |||
434 | .id_table = saa7706h_id, | 434 | .id_table = saa7706h_id, |
435 | }; | 435 | }; |
436 | 436 | ||
437 | static __init int saa7706h_init(void) | 437 | module_i2c_driver(saa7706h_driver); |
438 | { | ||
439 | return i2c_add_driver(&saa7706h_driver); | ||
440 | } | ||
441 | |||
442 | static __exit void saa7706h_exit(void) | ||
443 | { | ||
444 | i2c_del_driver(&saa7706h_driver); | ||
445 | } | ||
446 | |||
447 | module_init(saa7706h_init); | ||
448 | module_exit(saa7706h_exit); | ||
449 | 438 | ||
450 | MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver"); | 439 | MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver"); |
451 | MODULE_AUTHOR("Mocean Laboratories"); | 440 | MODULE_AUTHOR("Mocean Laboratories"); |
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index fd3541b0e91c..9b546a5523f3 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c | |||
@@ -539,33 +539,7 @@ static struct i2c_driver si470x_i2c_driver = { | |||
539 | .id_table = si470x_i2c_id, | 539 | .id_table = si470x_i2c_id, |
540 | }; | 540 | }; |
541 | 541 | ||
542 | 542 | module_i2c_driver(si470x_i2c_driver); | |
543 | |||
544 | /************************************************************************** | ||
545 | * Module Interface | ||
546 | **************************************************************************/ | ||
547 | |||
548 | /* | ||
549 | * si470x_i2c_init - module init | ||
550 | */ | ||
551 | static int __init si470x_i2c_init(void) | ||
552 | { | ||
553 | printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); | ||
554 | return i2c_add_driver(&si470x_i2c_driver); | ||
555 | } | ||
556 | |||
557 | |||
558 | /* | ||
559 | * si470x_i2c_exit - module exit | ||
560 | */ | ||
561 | static void __exit si470x_i2c_exit(void) | ||
562 | { | ||
563 | i2c_del_driver(&si470x_i2c_driver); | ||
564 | } | ||
565 | |||
566 | |||
567 | module_init(si470x_i2c_init); | ||
568 | module_exit(si470x_i2c_exit); | ||
569 | 543 | ||
570 | MODULE_LICENSE("GPL"); | 544 | MODULE_LICENSE("GPL"); |
571 | MODULE_AUTHOR(DRIVER_AUTHOR); | 545 | MODULE_AUTHOR(DRIVER_AUTHOR); |
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index 27aba936fb2b..b898c8925ab7 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c | |||
@@ -2106,17 +2106,4 @@ static struct i2c_driver si4713_i2c_driver = { | |||
2106 | .id_table = si4713_id, | 2106 | .id_table = si4713_id, |
2107 | }; | 2107 | }; |
2108 | 2108 | ||
2109 | /* Module Interface */ | 2109 | module_i2c_driver(si4713_i2c_driver); |
2110 | static int __init si4713_module_init(void) | ||
2111 | { | ||
2112 | return i2c_add_driver(&si4713_i2c_driver); | ||
2113 | } | ||
2114 | |||
2115 | static void __exit si4713_module_exit(void) | ||
2116 | { | ||
2117 | i2c_del_driver(&si4713_i2c_driver); | ||
2118 | } | ||
2119 | |||
2120 | module_init(si4713_module_init); | ||
2121 | module_exit(si4713_module_exit); | ||
2122 | |||
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 3408685b690c..6418c4c9faf1 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c | |||
@@ -215,20 +215,8 @@ static struct i2c_driver tef6862_driver = { | |||
215 | .id_table = tef6862_id, | 215 | .id_table = tef6862_id, |
216 | }; | 216 | }; |
217 | 217 | ||
218 | static __init int tef6862_init(void) | 218 | module_i2c_driver(tef6862_driver); |
219 | { | ||
220 | return i2c_add_driver(&tef6862_driver); | ||
221 | } | ||
222 | |||
223 | static __exit void tef6862_exit(void) | ||
224 | { | ||
225 | i2c_del_driver(&tef6862_driver); | ||
226 | } | ||
227 | |||
228 | module_init(tef6862_init); | ||
229 | module_exit(tef6862_exit); | ||
230 | 219 | ||
231 | MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner"); | 220 | MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner"); |
232 | MODULE_AUTHOR("Mocean Laboratories"); | 221 | MODULE_AUTHOR("Mocean Laboratories"); |
233 | MODULE_LICENSE("GPL v2"); | 222 | MODULE_LICENSE("GPL v2"); |
234 | |||
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 4df4affeea5f..a3fbb21350e9 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig | |||
@@ -266,4 +266,13 @@ config RC_LOOPBACK | |||
266 | To compile this driver as a module, choose M here: the module will | 266 | To compile this driver as a module, choose M here: the module will |
267 | be called rc_loopback. | 267 | be called rc_loopback. |
268 | 268 | ||
269 | config IR_GPIO_CIR | ||
270 | tristate "GPIO IR remote control" | ||
271 | depends on RC_CORE | ||
272 | ---help--- | ||
273 | Say Y if you want to use GPIO based IR Receiver. | ||
274 | |||
275 | To compile this driver as a module, choose M here: the module will | ||
276 | be called gpio-ir-recv. | ||
277 | |||
269 | endif #RC_CORE | 278 | endif #RC_CORE |
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index fb3dee2dd845..29f364f88a94 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile | |||
@@ -26,3 +26,4 @@ obj-$(CONFIG_IR_REDRAT3) += redrat3.o | |||
26 | obj-$(CONFIG_IR_STREAMZAP) += streamzap.o | 26 | obj-$(CONFIG_IR_STREAMZAP) += streamzap.o |
27 | obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o | 27 | obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o |
28 | obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o | 28 | obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o |
29 | obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o | ||
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 7f7079b12f23..392d4be91f8f 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c | |||
@@ -117,7 +117,7 @@ static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset) | |||
117 | static void cir_dump_regs(struct fintek_dev *fintek) | 117 | static void cir_dump_regs(struct fintek_dev *fintek) |
118 | { | 118 | { |
119 | fintek_config_mode_enable(fintek); | 119 | fintek_config_mode_enable(fintek); |
120 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | 120 | fintek_select_logical_dev(fintek, fintek->logical_dev_cir); |
121 | 121 | ||
122 | pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); | 122 | pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); |
123 | pr_reg(" * CR CIR BASE ADDR: 0x%x\n", | 123 | pr_reg(" * CR CIR BASE ADDR: 0x%x\n", |
@@ -143,7 +143,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek) | |||
143 | u8 chip_major, chip_minor; | 143 | u8 chip_major, chip_minor; |
144 | u8 vendor_major, vendor_minor; | 144 | u8 vendor_major, vendor_minor; |
145 | u8 portsel, ir_class; | 145 | u8 portsel, ir_class; |
146 | u16 vendor; | 146 | u16 vendor, chip; |
147 | int ret = 0; | 147 | int ret = 0; |
148 | 148 | ||
149 | fintek_config_mode_enable(fintek); | 149 | fintek_config_mode_enable(fintek); |
@@ -176,6 +176,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek) | |||
176 | 176 | ||
177 | chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI); | 177 | chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI); |
178 | chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO); | 178 | chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO); |
179 | chip = chip_major << 8 | chip_minor; | ||
179 | 180 | ||
180 | vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI); | 181 | vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI); |
181 | vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO); | 182 | vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO); |
@@ -192,6 +193,15 @@ static int fintek_hw_detect(struct fintek_dev *fintek) | |||
192 | fintek->chip_major = chip_major; | 193 | fintek->chip_major = chip_major; |
193 | fintek->chip_minor = chip_minor; | 194 | fintek->chip_minor = chip_minor; |
194 | fintek->chip_vendor = vendor; | 195 | fintek->chip_vendor = vendor; |
196 | |||
197 | /* | ||
198 | * Newer reviews of this chipset uses port 8 instead of 5 | ||
199 | */ | ||
200 | if ((chip != 0x0408) || (chip != 0x0804)) | ||
201 | fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV2; | ||
202 | else | ||
203 | fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV1; | ||
204 | |||
195 | spin_unlock_irqrestore(&fintek->fintek_lock, flags); | 205 | spin_unlock_irqrestore(&fintek->fintek_lock, flags); |
196 | 206 | ||
197 | return ret; | 207 | return ret; |
@@ -200,7 +210,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek) | |||
200 | static void fintek_cir_ldev_init(struct fintek_dev *fintek) | 210 | static void fintek_cir_ldev_init(struct fintek_dev *fintek) |
201 | { | 211 | { |
202 | /* Select CIR logical device and enable */ | 212 | /* Select CIR logical device and enable */ |
203 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | 213 | fintek_select_logical_dev(fintek, fintek->logical_dev_cir); |
204 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); | 214 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); |
205 | 215 | ||
206 | /* Write allocated CIR address and IRQ information to hardware */ | 216 | /* Write allocated CIR address and IRQ information to hardware */ |
@@ -381,7 +391,7 @@ static irqreturn_t fintek_cir_isr(int irq, void *data) | |||
381 | fit_dbg_verbose("%s firing", __func__); | 391 | fit_dbg_verbose("%s firing", __func__); |
382 | 392 | ||
383 | fintek_config_mode_enable(fintek); | 393 | fintek_config_mode_enable(fintek); |
384 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | 394 | fintek_select_logical_dev(fintek, fintek->logical_dev_cir); |
385 | fintek_config_mode_disable(fintek); | 395 | fintek_config_mode_disable(fintek); |
386 | 396 | ||
387 | /* | 397 | /* |
@@ -422,7 +432,7 @@ static void fintek_enable_cir(struct fintek_dev *fintek) | |||
422 | fintek_config_mode_enable(fintek); | 432 | fintek_config_mode_enable(fintek); |
423 | 433 | ||
424 | /* enable the CIR logical device */ | 434 | /* enable the CIR logical device */ |
425 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | 435 | fintek_select_logical_dev(fintek, fintek->logical_dev_cir); |
426 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); | 436 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); |
427 | 437 | ||
428 | fintek_config_mode_disable(fintek); | 438 | fintek_config_mode_disable(fintek); |
@@ -439,7 +449,7 @@ static void fintek_disable_cir(struct fintek_dev *fintek) | |||
439 | fintek_config_mode_enable(fintek); | 449 | fintek_config_mode_enable(fintek); |
440 | 450 | ||
441 | /* disable the CIR logical device */ | 451 | /* disable the CIR logical device */ |
442 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | 452 | fintek_select_logical_dev(fintek, fintek->logical_dev_cir); |
443 | fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); | 453 | fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); |
444 | 454 | ||
445 | fintek_config_mode_disable(fintek); | 455 | fintek_config_mode_disable(fintek); |
@@ -611,7 +621,7 @@ static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state) | |||
611 | fintek_config_mode_enable(fintek); | 621 | fintek_config_mode_enable(fintek); |
612 | 622 | ||
613 | /* disable cir logical dev */ | 623 | /* disable cir logical dev */ |
614 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | 624 | fintek_select_logical_dev(fintek, fintek->logical_dev_cir); |
615 | fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); | 625 | fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); |
616 | 626 | ||
617 | fintek_config_mode_disable(fintek); | 627 | fintek_config_mode_disable(fintek); |
@@ -634,7 +644,7 @@ static int fintek_resume(struct pnp_dev *pdev) | |||
634 | 644 | ||
635 | /* Enable CIR logical device */ | 645 | /* Enable CIR logical device */ |
636 | fintek_config_mode_enable(fintek); | 646 | fintek_config_mode_enable(fintek); |
637 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | 647 | fintek_select_logical_dev(fintek, fintek->logical_dev_cir); |
638 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); | 648 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); |
639 | 649 | ||
640 | fintek_config_mode_disable(fintek); | 650 | fintek_config_mode_disable(fintek); |
diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h index 1b10b2011f5e..82516a1d39b0 100644 --- a/drivers/media/rc/fintek-cir.h +++ b/drivers/media/rc/fintek-cir.h | |||
@@ -88,6 +88,7 @@ struct fintek_dev { | |||
88 | u8 chip_major; | 88 | u8 chip_major; |
89 | u8 chip_minor; | 89 | u8 chip_minor; |
90 | u16 chip_vendor; | 90 | u16 chip_vendor; |
91 | u8 logical_dev_cir; | ||
91 | 92 | ||
92 | /* hardware features */ | 93 | /* hardware features */ |
93 | bool hw_learning_capable; | 94 | bool hw_learning_capable; |
@@ -172,7 +173,8 @@ struct fintek_dev { | |||
172 | #define LOGICAL_DEV_ENABLE 0x01 | 173 | #define LOGICAL_DEV_ENABLE 0x01 |
173 | 174 | ||
174 | /* Logical device number of the CIR function */ | 175 | /* Logical device number of the CIR function */ |
175 | #define LOGICAL_DEV_CIR 0x05 | 176 | #define LOGICAL_DEV_CIR_REV1 0x05 |
177 | #define LOGICAL_DEV_CIR_REV2 0x08 | ||
176 | 178 | ||
177 | /* CIR Logical Device (LDN 0x08) config registers */ | 179 | /* CIR Logical Device (LDN 0x08) config registers */ |
178 | #define CIR_CR_COMMAND_INDEX 0x04 | 180 | #define CIR_CR_COMMAND_INDEX 0x04 |
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c new file mode 100644 index 000000000000..0d875450c5ce --- /dev/null +++ b/drivers/media/rc/gpio-ir-recv.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* Copyright (c) 2012, Code Aurora Forum. All rights reserved. | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <media/rc-core.h> | ||
22 | #include <media/gpio-ir-recv.h> | ||
23 | |||
24 | #define GPIO_IR_DRIVER_NAME "gpio-rc-recv" | ||
25 | #define GPIO_IR_DEVICE_NAME "gpio_ir_recv" | ||
26 | |||
27 | struct gpio_rc_dev { | ||
28 | struct rc_dev *rcdev; | ||
29 | int gpio_nr; | ||
30 | bool active_low; | ||
31 | }; | ||
32 | |||
33 | static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) | ||
34 | { | ||
35 | struct gpio_rc_dev *gpio_dev = dev_id; | ||
36 | int gval; | ||
37 | int rc = 0; | ||
38 | enum raw_event_type type = IR_SPACE; | ||
39 | |||
40 | gval = gpio_get_value_cansleep(gpio_dev->gpio_nr); | ||
41 | |||
42 | if (gval < 0) | ||
43 | goto err_get_value; | ||
44 | |||
45 | if (gpio_dev->active_low) | ||
46 | gval = !gval; | ||
47 | |||
48 | if (gval == 1) | ||
49 | type = IR_PULSE; | ||
50 | |||
51 | rc = ir_raw_event_store_edge(gpio_dev->rcdev, type); | ||
52 | if (rc < 0) | ||
53 | goto err_get_value; | ||
54 | |||
55 | ir_raw_event_handle(gpio_dev->rcdev); | ||
56 | |||
57 | err_get_value: | ||
58 | return IRQ_HANDLED; | ||
59 | } | ||
60 | |||
61 | static int __devinit gpio_ir_recv_probe(struct platform_device *pdev) | ||
62 | { | ||
63 | struct gpio_rc_dev *gpio_dev; | ||
64 | struct rc_dev *rcdev; | ||
65 | const struct gpio_ir_recv_platform_data *pdata = | ||
66 | pdev->dev.platform_data; | ||
67 | int rc; | ||
68 | |||
69 | if (!pdata) | ||
70 | return -EINVAL; | ||
71 | |||
72 | if (pdata->gpio_nr < 0) | ||
73 | return -EINVAL; | ||
74 | |||
75 | gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL); | ||
76 | if (!gpio_dev) | ||
77 | return -ENOMEM; | ||
78 | |||
79 | rcdev = rc_allocate_device(); | ||
80 | if (!rcdev) { | ||
81 | rc = -ENOMEM; | ||
82 | goto err_allocate_device; | ||
83 | } | ||
84 | |||
85 | rcdev->driver_type = RC_DRIVER_IR_RAW; | ||
86 | rcdev->allowed_protos = RC_TYPE_ALL; | ||
87 | rcdev->input_name = GPIO_IR_DEVICE_NAME; | ||
88 | rcdev->input_id.bustype = BUS_HOST; | ||
89 | rcdev->driver_name = GPIO_IR_DRIVER_NAME; | ||
90 | rcdev->map_name = RC_MAP_EMPTY; | ||
91 | |||
92 | gpio_dev->rcdev = rcdev; | ||
93 | gpio_dev->gpio_nr = pdata->gpio_nr; | ||
94 | gpio_dev->active_low = pdata->active_low; | ||
95 | |||
96 | rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); | ||
97 | if (rc < 0) | ||
98 | goto err_gpio_request; | ||
99 | rc = gpio_direction_input(pdata->gpio_nr); | ||
100 | if (rc < 0) | ||
101 | goto err_gpio_direction_input; | ||
102 | |||
103 | rc = rc_register_device(rcdev); | ||
104 | if (rc < 0) { | ||
105 | dev_err(&pdev->dev, "failed to register rc device\n"); | ||
106 | goto err_register_rc_device; | ||
107 | } | ||
108 | |||
109 | platform_set_drvdata(pdev, gpio_dev); | ||
110 | |||
111 | rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr), | ||
112 | gpio_ir_recv_irq, | ||
113 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | ||
114 | "gpio-ir-recv-irq", gpio_dev); | ||
115 | if (rc < 0) | ||
116 | goto err_request_irq; | ||
117 | |||
118 | return 0; | ||
119 | |||
120 | err_request_irq: | ||
121 | platform_set_drvdata(pdev, NULL); | ||
122 | rc_unregister_device(rcdev); | ||
123 | err_register_rc_device: | ||
124 | err_gpio_direction_input: | ||
125 | gpio_free(pdata->gpio_nr); | ||
126 | err_gpio_request: | ||
127 | rc_free_device(rcdev); | ||
128 | rcdev = NULL; | ||
129 | err_allocate_device: | ||
130 | kfree(gpio_dev); | ||
131 | return rc; | ||
132 | } | ||
133 | |||
134 | static int __devexit gpio_ir_recv_remove(struct platform_device *pdev) | ||
135 | { | ||
136 | struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); | ||
137 | |||
138 | free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); | ||
139 | platform_set_drvdata(pdev, NULL); | ||
140 | rc_unregister_device(gpio_dev->rcdev); | ||
141 | gpio_free(gpio_dev->gpio_nr); | ||
142 | rc_free_device(gpio_dev->rcdev); | ||
143 | kfree(gpio_dev); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | #ifdef CONFIG_PM | ||
148 | static int gpio_ir_recv_suspend(struct device *dev) | ||
149 | { | ||
150 | struct platform_device *pdev = to_platform_device(dev); | ||
151 | struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); | ||
152 | |||
153 | if (device_may_wakeup(dev)) | ||
154 | enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); | ||
155 | else | ||
156 | disable_irq(gpio_to_irq(gpio_dev->gpio_nr)); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int gpio_ir_recv_resume(struct device *dev) | ||
162 | { | ||
163 | struct platform_device *pdev = to_platform_device(dev); | ||
164 | struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); | ||
165 | |||
166 | if (device_may_wakeup(dev)) | ||
167 | disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); | ||
168 | else | ||
169 | enable_irq(gpio_to_irq(gpio_dev->gpio_nr)); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static const struct dev_pm_ops gpio_ir_recv_pm_ops = { | ||
175 | .suspend = gpio_ir_recv_suspend, | ||
176 | .resume = gpio_ir_recv_resume, | ||
177 | }; | ||
178 | #endif | ||
179 | |||
180 | static struct platform_driver gpio_ir_recv_driver = { | ||
181 | .probe = gpio_ir_recv_probe, | ||
182 | .remove = __devexit_p(gpio_ir_recv_remove), | ||
183 | .driver = { | ||
184 | .name = GPIO_IR_DRIVER_NAME, | ||
185 | .owner = THIS_MODULE, | ||
186 | #ifdef CONFIG_PM | ||
187 | .pm = &gpio_ir_recv_pm_ops, | ||
188 | #endif | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | static int __init gpio_ir_recv_init(void) | ||
193 | { | ||
194 | return platform_driver_register(&gpio_ir_recv_driver); | ||
195 | } | ||
196 | module_init(gpio_ir_recv_init); | ||
197 | |||
198 | static void __exit gpio_ir_recv_exit(void) | ||
199 | { | ||
200 | platform_driver_unregister(&gpio_ir_recv_driver); | ||
201 | } | ||
202 | module_exit(gpio_ir_recv_exit); | ||
203 | |||
204 | MODULE_DESCRIPTION("GPIO IR Receiver driver"); | ||
205 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index d5e2b50aff1f..dab98b37621a 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c | |||
@@ -130,7 +130,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) | |||
130 | case 15: | 130 | case 15: |
131 | device = bitrev8((data->bits >> 0) & 0xFF); | 131 | device = bitrev8((data->bits >> 0) & 0xFF); |
132 | subdevice = 0; | 132 | subdevice = 0; |
133 | function = bitrev8((data->bits >> 7) & 0xFD); | 133 | function = bitrev8((data->bits >> 7) & 0xFE); |
134 | break; | 134 | break; |
135 | case 20: | 135 | case 20: |
136 | device = bitrev8((data->bits >> 5) & 0xF8); | 136 | device = bitrev8((data->bits >> 5) & 0xF8); |
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 36e4d5e8dd6a..49ce2662f56b 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile | |||
@@ -41,8 +41,11 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | |||
41 | rc-imon-mce.o \ | 41 | rc-imon-mce.o \ |
42 | rc-imon-pad.o \ | 42 | rc-imon-pad.o \ |
43 | rc-iodata-bctv7e.o \ | 43 | rc-iodata-bctv7e.o \ |
44 | rc-it913x-v1.o \ | ||
45 | rc-it913x-v2.o \ | ||
44 | rc-kaiomy.o \ | 46 | rc-kaiomy.o \ |
45 | rc-kworld-315u.o \ | 47 | rc-kworld-315u.o \ |
48 | rc-kworld-pc150u.o \ | ||
46 | rc-kworld-plus-tv-analog.o \ | 49 | rc-kworld-plus-tv-analog.o \ |
47 | rc-leadtek-y04g0051.o \ | 50 | rc-leadtek-y04g0051.o \ |
48 | rc-lirc.o \ | 51 | rc-lirc.o \ |
diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c new file mode 100644 index 000000000000..0ac775fd109d --- /dev/null +++ b/drivers/media/rc/keymaps/rc-it913x-v1.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* ITE Generic remotes Version 1 | ||
2 | * | ||
3 | * Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <media/rc-map.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | |||
15 | static struct rc_map_table it913x_v1_rc[] = { | ||
16 | /* Type 1 */ | ||
17 | { 0x61d601, KEY_VIDEO }, /* Source */ | ||
18 | { 0x61d602, KEY_3 }, | ||
19 | { 0x61d603, KEY_POWER }, /* ShutDown */ | ||
20 | { 0x61d604, KEY_1 }, | ||
21 | { 0x61d605, KEY_5 }, | ||
22 | { 0x61d606, KEY_6 }, | ||
23 | { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ | ||
24 | { 0x61d608, KEY_2 }, | ||
25 | { 0x61d609, KEY_CHANNELUP }, /* CH+ */ | ||
26 | { 0x61d60a, KEY_9 }, | ||
27 | { 0x61d60b, KEY_ZOOM }, /* Zoom */ | ||
28 | { 0x61d60c, KEY_7 }, | ||
29 | { 0x61d60d, KEY_8 }, | ||
30 | { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ | ||
31 | { 0x61d60f, KEY_4 }, | ||
32 | { 0x61d610, KEY_ESC }, /* [back up arrow] */ | ||
33 | { 0x61d611, KEY_0 }, | ||
34 | { 0x61d612, KEY_OK }, /* [enter arrow] */ | ||
35 | { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ | ||
36 | { 0x61d614, KEY_RECORD }, /* Rec */ | ||
37 | { 0x61d615, KEY_STOP }, /* Stop */ | ||
38 | { 0x61d616, KEY_PLAY }, /* Play */ | ||
39 | { 0x61d617, KEY_MUTE }, /* Mute */ | ||
40 | { 0x61d618, KEY_UP }, | ||
41 | { 0x61d619, KEY_DOWN }, | ||
42 | { 0x61d61a, KEY_LEFT }, | ||
43 | { 0x61d61b, KEY_RIGHT }, | ||
44 | { 0x61d61c, KEY_RED }, | ||
45 | { 0x61d61d, KEY_GREEN }, | ||
46 | { 0x61d61e, KEY_YELLOW }, | ||
47 | { 0x61d61f, KEY_BLUE }, | ||
48 | { 0x61d643, KEY_POWER2 }, /* [red power button] */ | ||
49 | /* Type 2 - 20 buttons */ | ||
50 | { 0x807f0d, KEY_0 }, | ||
51 | { 0x807f04, KEY_1 }, | ||
52 | { 0x807f05, KEY_2 }, | ||
53 | { 0x807f06, KEY_3 }, | ||
54 | { 0x807f07, KEY_4 }, | ||
55 | { 0x807f08, KEY_5 }, | ||
56 | { 0x807f09, KEY_6 }, | ||
57 | { 0x807f0a, KEY_7 }, | ||
58 | { 0x807f1b, KEY_8 }, | ||
59 | { 0x807f1f, KEY_9 }, | ||
60 | { 0x807f12, KEY_POWER }, | ||
61 | { 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */ | ||
62 | { 0x807f19, KEY_PAUSE }, /* Timeshift */ | ||
63 | { 0x807f1e, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ | ||
64 | { 0x807f03, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ | ||
65 | { 0x807f1a, KEY_CHANNELUP }, | ||
66 | { 0x807f02, KEY_CHANNELDOWN }, | ||
67 | { 0x807f0c, KEY_ZOOM }, | ||
68 | { 0x807f00, KEY_RECORD }, | ||
69 | { 0x807f0e, KEY_STOP }, | ||
70 | }; | ||
71 | |||
72 | static struct rc_map_list it913x_v1_map = { | ||
73 | .map = { | ||
74 | .scan = it913x_v1_rc, | ||
75 | .size = ARRAY_SIZE(it913x_v1_rc), | ||
76 | .rc_type = RC_TYPE_NEC, | ||
77 | .name = RC_MAP_IT913X_V1, | ||
78 | } | ||
79 | }; | ||
80 | |||
81 | static int __init init_rc_it913x_v1_map(void) | ||
82 | { | ||
83 | return rc_map_register(&it913x_v1_map); | ||
84 | } | ||
85 | |||
86 | static void __exit exit_rc_it913x_v1_map(void) | ||
87 | { | ||
88 | rc_map_unregister(&it913x_v1_map); | ||
89 | } | ||
90 | |||
91 | module_init(init_rc_it913x_v1_map) | ||
92 | module_exit(exit_rc_it913x_v1_map) | ||
93 | |||
94 | MODULE_LICENSE("GPL"); | ||
95 | MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); | ||
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c new file mode 100644 index 000000000000..28e376e18b99 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-it913x-v2.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* ITE Generic remotes Version 2 | ||
2 | * | ||
3 | * Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <media/rc-map.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | |||
15 | static struct rc_map_table it913x_v2_rc[] = { | ||
16 | /* Type 1 */ | ||
17 | /* 9005 remote */ | ||
18 | { 0x807f12, KEY_POWER2 }, /* Power (RED POWER BUTTON)*/ | ||
19 | { 0x807f1a, KEY_VIDEO }, /* Source */ | ||
20 | { 0x807f1e, KEY_MUTE }, /* Mute */ | ||
21 | { 0x807f01, KEY_RECORD }, /* Record */ | ||
22 | { 0x807f02, KEY_CHANNELUP }, /* Channel+ */ | ||
23 | { 0x807f03, KEY_TIME }, /* TimeShift */ | ||
24 | { 0x807f04, KEY_VOLUMEUP }, /* Volume- */ | ||
25 | { 0x807f05, KEY_SCREEN }, /* FullScreen */ | ||
26 | { 0x807f06, KEY_VOLUMEDOWN }, /* Volume- */ | ||
27 | { 0x807f07, KEY_0 }, /* 0 */ | ||
28 | { 0x807f08, KEY_CHANNELDOWN }, /* Channel- */ | ||
29 | { 0x807f09, KEY_PREVIOUS }, /* Recall */ | ||
30 | { 0x807f0a, KEY_1 }, /* 1 */ | ||
31 | { 0x807f1b, KEY_2 }, /* 2 */ | ||
32 | { 0x807f1f, KEY_3 }, /* 3 */ | ||
33 | { 0x807f0c, KEY_4 }, /* 4 */ | ||
34 | { 0x807f0d, KEY_5 }, /* 5 */ | ||
35 | { 0x807f0e, KEY_6 }, /* 6 */ | ||
36 | { 0x807f00, KEY_7 }, /* 7 */ | ||
37 | { 0x807f0f, KEY_8 }, /* 8 */ | ||
38 | { 0x807f19, KEY_9 }, /* 9 */ | ||
39 | |||
40 | /* Type 2 */ | ||
41 | /* keys stereo, snapshot unassigned */ | ||
42 | { 0x866b00, KEY_0 }, | ||
43 | { 0x866b1b, KEY_1 }, | ||
44 | { 0x866b02, KEY_2 }, | ||
45 | { 0x866b03, KEY_3 }, | ||
46 | { 0x866b04, KEY_4 }, | ||
47 | { 0x866b05, KEY_5 }, | ||
48 | { 0x866b06, KEY_6 }, | ||
49 | { 0x866b07, KEY_7 }, | ||
50 | { 0x866b08, KEY_8 }, | ||
51 | { 0x866b09, KEY_9 }, | ||
52 | { 0x866b12, KEY_POWER }, | ||
53 | { 0x866b13, KEY_MUTE }, | ||
54 | { 0x866b0a, KEY_PREVIOUS }, /* Recall */ | ||
55 | { 0x866b1e, KEY_PAUSE }, | ||
56 | { 0x866b0c, KEY_VOLUMEUP }, | ||
57 | { 0x866b18, KEY_VOLUMEDOWN }, | ||
58 | { 0x866b0b, KEY_CHANNELUP }, | ||
59 | { 0x866b18, KEY_CHANNELDOWN }, | ||
60 | { 0x866b10, KEY_ZOOM }, | ||
61 | { 0x866b1d, KEY_RECORD }, | ||
62 | { 0x866b0e, KEY_STOP }, | ||
63 | { 0x866b11, KEY_EPG}, | ||
64 | { 0x866b1a, KEY_FASTFORWARD }, | ||
65 | { 0x866b0f, KEY_REWIND }, | ||
66 | { 0x866b1c, KEY_TV }, | ||
67 | { 0x866b1b, KEY_TEXT }, | ||
68 | |||
69 | }; | ||
70 | |||
71 | static struct rc_map_list it913x_v2_map = { | ||
72 | .map = { | ||
73 | .scan = it913x_v2_rc, | ||
74 | .size = ARRAY_SIZE(it913x_v2_rc), | ||
75 | .rc_type = RC_TYPE_NEC, | ||
76 | .name = RC_MAP_IT913X_V2, | ||
77 | } | ||
78 | }; | ||
79 | |||
80 | static int __init init_rc_it913x_v2_map(void) | ||
81 | { | ||
82 | return rc_map_register(&it913x_v2_map); | ||
83 | } | ||
84 | |||
85 | static void __exit exit_rc_it913x_v2_map(void) | ||
86 | { | ||
87 | rc_map_unregister(&it913x_v2_map); | ||
88 | } | ||
89 | |||
90 | module_init(init_rc_it913x_v2_map) | ||
91 | module_exit(exit_rc_it913x_v2_map) | ||
92 | |||
93 | MODULE_LICENSE("GPL"); | ||
94 | MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); | ||
diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c new file mode 100644 index 000000000000..233bb5ee087f --- /dev/null +++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* kworld-pc150u.c - Keytable for kworld_pc150u Remote Controller | ||
2 | * | ||
3 | * keymap imported from ir-keymaps.c | ||
4 | * | ||
5 | * Copyright (c) 2010 by Kyle Strickland | ||
6 | * (based on kworld-plus-tv-analog.c by | ||
7 | * Mauro Carvalho Chehab <mchehab@redhat.com>) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <media/rc-map.h> | ||
16 | #include <linux/module.h> | ||
17 | |||
18 | /* Kworld PC150-U | ||
19 | Kyle Strickland <kyle@kyle.strickland.name> | ||
20 | */ | ||
21 | |||
22 | static struct rc_map_table kworld_pc150u[] = { | ||
23 | { 0x0c, KEY_MEDIA }, /* Kworld key */ | ||
24 | { 0x16, KEY_EJECTCLOSECD }, /* -> ) */ | ||
25 | { 0x1d, KEY_POWER2 }, | ||
26 | |||
27 | { 0x00, KEY_1 }, | ||
28 | { 0x01, KEY_2 }, | ||
29 | { 0x02, KEY_3 }, | ||
30 | { 0x03, KEY_4 }, | ||
31 | { 0x04, KEY_5 }, | ||
32 | { 0x05, KEY_6 }, | ||
33 | { 0x06, KEY_7 }, | ||
34 | { 0x07, KEY_8 }, | ||
35 | { 0x08, KEY_9 }, | ||
36 | { 0x0a, KEY_0 }, | ||
37 | |||
38 | { 0x09, KEY_AGAIN }, | ||
39 | { 0x14, KEY_MUTE }, | ||
40 | |||
41 | { 0x1e, KEY_LAST }, | ||
42 | { 0x17, KEY_ZOOM }, | ||
43 | { 0x1f, KEY_HOMEPAGE }, | ||
44 | { 0x0e, KEY_ESC }, | ||
45 | |||
46 | { 0x20, KEY_UP }, | ||
47 | { 0x21, KEY_DOWN }, | ||
48 | { 0x42, KEY_LEFT }, | ||
49 | { 0x43, KEY_RIGHT }, | ||
50 | { 0x0b, KEY_ENTER }, | ||
51 | |||
52 | { 0x10, KEY_CHANNELUP }, | ||
53 | { 0x11, KEY_CHANNELDOWN }, | ||
54 | |||
55 | { 0x13, KEY_VOLUMEUP }, | ||
56 | { 0x12, KEY_VOLUMEDOWN }, | ||
57 | |||
58 | { 0x19, KEY_TIME}, /* Timeshift */ | ||
59 | { 0x1a, KEY_STOP}, | ||
60 | { 0x1b, KEY_RECORD}, | ||
61 | { 0x4b, KEY_EMAIL}, | ||
62 | |||
63 | { 0x40, KEY_REWIND}, | ||
64 | { 0x44, KEY_PLAYPAUSE}, | ||
65 | { 0x41, KEY_FORWARD}, | ||
66 | { 0x22, KEY_TEXT}, | ||
67 | |||
68 | { 0x15, KEY_AUDIO}, /* ((*)) */ | ||
69 | { 0x0f, KEY_MODE}, /* display ratio */ | ||
70 | { 0x1c, KEY_SYSRQ}, /* snapshot */ | ||
71 | { 0x4a, KEY_SLEEP}, /* sleep timer */ | ||
72 | |||
73 | { 0x48, KEY_SOUND}, /* switch theater mode */ | ||
74 | { 0x49, KEY_BLUE}, /* A */ | ||
75 | { 0x18, KEY_RED}, /* B */ | ||
76 | { 0x23, KEY_GREEN}, /* C */ | ||
77 | }; | ||
78 | |||
79 | static struct rc_map_list kworld_pc150u_map = { | ||
80 | .map = { | ||
81 | .scan = kworld_pc150u, | ||
82 | .size = ARRAY_SIZE(kworld_pc150u), | ||
83 | .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ | ||
84 | .name = RC_MAP_KWORLD_PC150U, | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | static int __init init_rc_map_kworld_pc150u(void) | ||
89 | { | ||
90 | return rc_map_register(&kworld_pc150u_map); | ||
91 | } | ||
92 | |||
93 | static void __exit exit_rc_map_kworld_pc150u(void) | ||
94 | { | ||
95 | rc_map_unregister(&kworld_pc150u_map); | ||
96 | } | ||
97 | |||
98 | module_init(init_rc_map_kworld_pc150u) | ||
99 | module_exit(exit_rc_map_kworld_pc150u) | ||
100 | |||
101 | MODULE_LICENSE("GPL"); | ||
102 | MODULE_AUTHOR("Kyle Strickland <kyle@kyle.strickland.name>"); | ||
diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c index f3b86c8db679..8d4dae2e2ece 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c | |||
@@ -18,6 +18,8 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | static struct rc_map_table nec_terratec_cinergy_xs[] = { | 20 | static struct rc_map_table nec_terratec_cinergy_xs[] = { |
21 | |||
22 | /* Terratec Grey IR, with most keys in orange */ | ||
21 | { 0x1441, KEY_HOME}, | 23 | { 0x1441, KEY_HOME}, |
22 | { 0x1401, KEY_POWER2}, | 24 | { 0x1401, KEY_POWER2}, |
23 | 25 | ||
@@ -78,6 +80,56 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = { | |||
78 | { 0x144e, KEY_REWIND}, | 80 | { 0x144e, KEY_REWIND}, |
79 | { 0x144f, KEY_FASTFORWARD}, | 81 | { 0x144f, KEY_FASTFORWARD}, |
80 | { 0x145c, KEY_NEXT}, | 82 | { 0x145c, KEY_NEXT}, |
83 | |||
84 | /* Terratec Black IR, with most keys in black */ | ||
85 | { 0x04eb01, KEY_POWER2}, | ||
86 | |||
87 | { 0x04eb02, KEY_1}, | ||
88 | { 0x04eb03, KEY_2}, | ||
89 | { 0x04eb04, KEY_3}, | ||
90 | { 0x04eb05, KEY_4}, | ||
91 | { 0x04eb06, KEY_5}, | ||
92 | { 0x04eb07, KEY_6}, | ||
93 | { 0x04eb08, KEY_7}, | ||
94 | { 0x04eb09, KEY_8}, | ||
95 | { 0x04eb0a, KEY_9}, | ||
96 | { 0x04eb0c, KEY_0}, | ||
97 | |||
98 | { 0x04eb0b, KEY_TEXT}, /* TXT */ | ||
99 | { 0x04eb0d, KEY_REFRESH}, /* Refresh */ | ||
100 | |||
101 | { 0x04eb0e, KEY_HOME}, | ||
102 | { 0x04eb0f, KEY_EPG}, | ||
103 | |||
104 | { 0x04eb10, KEY_UP}, | ||
105 | { 0x04eb11, KEY_LEFT}, | ||
106 | { 0x04eb12, KEY_OK}, | ||
107 | { 0x04eb13, KEY_RIGHT}, | ||
108 | { 0x04eb14, KEY_DOWN}, | ||
109 | |||
110 | { 0x04eb15, KEY_BACKSPACE}, | ||
111 | { 0x04eb16, KEY_INFO}, | ||
112 | |||
113 | { 0x04eb17, KEY_RED}, | ||
114 | { 0x04eb18, KEY_GREEN}, | ||
115 | { 0x04eb19, KEY_YELLOW}, | ||
116 | { 0x04eb1a, KEY_BLUE}, | ||
117 | |||
118 | { 0x04eb1c, KEY_VOLUMEUP}, | ||
119 | { 0x04eb1e, KEY_VOLUMEDOWN}, | ||
120 | |||
121 | { 0x04eb1d, KEY_MUTE}, | ||
122 | |||
123 | { 0x04eb1b, KEY_CHANNELUP}, | ||
124 | { 0x04eb1f, KEY_CHANNELDOWN}, | ||
125 | |||
126 | { 0x04eb40, KEY_RECORD}, | ||
127 | { 0x04eb4c, KEY_PLAY}, | ||
128 | { 0x04eb58, KEY_PAUSE}, | ||
129 | |||
130 | { 0x04eb54, KEY_REWIND}, | ||
131 | { 0x04eb48, KEY_STOP}, | ||
132 | { 0x04eb5c, KEY_NEXT}, | ||
81 | }; | 133 | }; |
82 | 134 | ||
83 | static struct rc_map_list nec_terratec_cinergy_xs_map = { | 135 | static struct rc_map_list nec_terratec_cinergy_xs_map = { |
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 21105bf9594d..e150a2e29a4b 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c | |||
@@ -361,6 +361,8 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
361 | { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, | 361 | { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, |
362 | /* Formosa Industrial Computing */ | 362 | /* Formosa Industrial Computing */ |
363 | { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, | 363 | { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, |
364 | /* Formosa Industrial Computing */ | ||
365 | { USB_DEVICE(VENDOR_FORMOSA, 0xe042) }, | ||
364 | /* Fintek eHome Infrared Transceiver (HP branded) */ | 366 | /* Fintek eHome Infrared Transceiver (HP branded) */ |
365 | { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, | 367 | { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, |
366 | /* Fintek eHome Infrared Transceiver */ | 368 | /* Fintek eHome Infrared Transceiver */ |
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index b72f8580e317..96f0a8bb39ea 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h | |||
@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl { | |||
35 | struct list_head list; /* to keep track of raw clients */ | 35 | struct list_head list; /* to keep track of raw clients */ |
36 | struct task_struct *thread; | 36 | struct task_struct *thread; |
37 | spinlock_t lock; | 37 | spinlock_t lock; |
38 | struct kfifo kfifo; /* fifo for the pulse/space durations */ | 38 | struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations */ |
39 | ktime_t last_event; /* when last event occurred */ | 39 | ktime_t last_event; /* when last event occurred */ |
40 | enum raw_event_type last_type; /* last event type */ | 40 | enum raw_event_type last_type; /* last event type */ |
41 | struct rc_dev *dev; /* pointer to the parent rc_dev */ | 41 | struct rc_dev *dev; /* pointer to the parent rc_dev */ |
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f6a930b70c69..6e16b09c24a9 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c | |||
@@ -1029,6 +1029,7 @@ EXPORT_SYMBOL_GPL(rc_free_device); | |||
1029 | 1029 | ||
1030 | int rc_register_device(struct rc_dev *dev) | 1030 | int rc_register_device(struct rc_dev *dev) |
1031 | { | 1031 | { |
1032 | static bool raw_init = false; /* raw decoders loaded? */ | ||
1032 | static atomic_t devno = ATOMIC_INIT(0); | 1033 | static atomic_t devno = ATOMIC_INIT(0); |
1033 | struct rc_map *rc_map; | 1034 | struct rc_map *rc_map; |
1034 | const char *path; | 1035 | const char *path; |
@@ -1103,6 +1104,12 @@ int rc_register_device(struct rc_dev *dev) | |||
1103 | kfree(path); | 1104 | kfree(path); |
1104 | 1105 | ||
1105 | if (dev->driver_type == RC_DRIVER_IR_RAW) { | 1106 | if (dev->driver_type == RC_DRIVER_IR_RAW) { |
1107 | /* Load raw decoders, if they aren't already */ | ||
1108 | if (!raw_init) { | ||
1109 | IR_dprintk(1, "Loading raw decoders\n"); | ||
1110 | ir_raw_init(); | ||
1111 | raw_init = true; | ||
1112 | } | ||
1106 | rc = ir_raw_event_register(dev); | 1113 | rc = ir_raw_event_register(dev); |
1107 | if (rc < 0) | 1114 | if (rc < 0) |
1108 | goto out_input; | 1115 | goto out_input; |
@@ -1176,8 +1183,6 @@ static int __init rc_core_init(void) | |||
1176 | return rc; | 1183 | return rc; |
1177 | } | 1184 | } |
1178 | 1185 | ||
1179 | /* Initialize/load the decoders/keymap code that will be used */ | ||
1180 | ir_raw_init(); | ||
1181 | rc_map_register(&empty_map); | 1186 | rc_map_register(&empty_map); |
1182 | 1187 | ||
1183 | return 0; | 1188 | return 0; |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9adada0d7447..f2479c5c0eb2 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -273,6 +273,16 @@ config VIDEO_ADV7180 | |||
273 | To compile this driver as a module, choose M here: the | 273 | To compile this driver as a module, choose M here: the |
274 | module will be called adv7180. | 274 | module will be called adv7180. |
275 | 275 | ||
276 | config VIDEO_ADV7183 | ||
277 | tristate "Analog Devices ADV7183 decoder" | ||
278 | depends on VIDEO_V4L2 && I2C | ||
279 | ---help--- | ||
280 | V4l2 subdevice driver for the Analog Devices | ||
281 | ADV7183 video decoder. | ||
282 | |||
283 | To compile this driver as a module, choose M here: the | ||
284 | module will be called adv7183. | ||
285 | |||
276 | config VIDEO_BT819 | 286 | config VIDEO_BT819 |
277 | tristate "BT819A VideoStream decoder" | 287 | tristate "BT819A VideoStream decoder" |
278 | depends on VIDEO_V4L2 && I2C | 288 | depends on VIDEO_V4L2 && I2C |
@@ -459,6 +469,9 @@ config VIDEO_AK881X | |||
459 | 469 | ||
460 | comment "Camera sensor devices" | 470 | comment "Camera sensor devices" |
461 | 471 | ||
472 | config VIDEO_APTINA_PLL | ||
473 | tristate | ||
474 | |||
462 | config VIDEO_OV7670 | 475 | config VIDEO_OV7670 |
463 | tristate "OmniVision OV7670 sensor support" | 476 | tristate "OmniVision OV7670 sensor support" |
464 | depends on I2C && VIDEO_V4L2 | 477 | depends on I2C && VIDEO_V4L2 |
@@ -467,9 +480,28 @@ config VIDEO_OV7670 | |||
467 | OV7670 VGA camera. It currently only works with the M88ALP01 | 480 | OV7670 VGA camera. It currently only works with the M88ALP01 |
468 | controller. | 481 | controller. |
469 | 482 | ||
483 | config VIDEO_VS6624 | ||
484 | tristate "ST VS6624 sensor support" | ||
485 | depends on VIDEO_V4L2 && I2C | ||
486 | ---help--- | ||
487 | This is a Video4Linux2 sensor-level driver for the ST VS6624 | ||
488 | camera. | ||
489 | |||
490 | To compile this driver as a module, choose M here: the | ||
491 | module will be called vs6624. | ||
492 | |||
493 | config VIDEO_MT9M032 | ||
494 | tristate "MT9M032 camera sensor support" | ||
495 | depends on I2C && VIDEO_V4L2 | ||
496 | select VIDEO_APTINA_PLL | ||
497 | ---help--- | ||
498 | This driver supports MT9M032 camera sensors from Aptina, monochrome | ||
499 | models only. | ||
500 | |||
470 | config VIDEO_MT9P031 | 501 | config VIDEO_MT9P031 |
471 | tristate "Aptina MT9P031 support" | 502 | tristate "Aptina MT9P031 support" |
472 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | 503 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
504 | select VIDEO_APTINA_PLL | ||
473 | ---help--- | 505 | ---help--- |
474 | This is a Video4Linux2 sensor-level driver for the Aptina | 506 | This is a Video4Linux2 sensor-level driver for the Aptina |
475 | (Micron) mt9p031 5 Mpixel camera. | 507 | (Micron) mt9p031 5 Mpixel camera. |
@@ -851,6 +883,8 @@ source "drivers/media/video/davinci/Kconfig" | |||
851 | 883 | ||
852 | source "drivers/media/video/omap/Kconfig" | 884 | source "drivers/media/video/omap/Kconfig" |
853 | 885 | ||
886 | source "drivers/media/video/blackfin/Kconfig" | ||
887 | |||
854 | config VIDEO_SH_VOU | 888 | config VIDEO_SH_VOU |
855 | tristate "SuperH VOU video output driver" | 889 | tristate "SuperH VOU video output driver" |
856 | depends on VIDEO_DEV && ARCH_SHMOBILE | 890 | depends on VIDEO_DEV && ARCH_SHMOBILE |
@@ -1087,7 +1121,7 @@ config VIDEO_MX2_HOSTSUPPORT | |||
1087 | config VIDEO_MX2 | 1121 | config VIDEO_MX2 |
1088 | tristate "i.MX27/i.MX25 Camera Sensor Interface driver" | 1122 | tristate "i.MX27/i.MX25 Camera Sensor Interface driver" |
1089 | depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25) | 1123 | depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25) |
1090 | select VIDEOBUF_DMA_CONTIG | 1124 | select VIDEOBUF2_DMA_CONTIG |
1091 | select VIDEO_MX2_HOSTSUPPORT | 1125 | select VIDEO_MX2_HOSTSUPPORT |
1092 | ---help--- | 1126 | ---help--- |
1093 | This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor | 1127 | This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor |
@@ -1116,7 +1150,8 @@ config VIDEO_ATMEL_ISI | |||
1116 | 1150 | ||
1117 | config VIDEO_S5P_MIPI_CSIS | 1151 | config VIDEO_S5P_MIPI_CSIS |
1118 | tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" | 1152 | tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" |
1119 | depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API | 1153 | depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P |
1154 | depends on VIDEO_V4L2_SUBDEV_API && REGULATOR | ||
1120 | ---help--- | 1155 | ---help--- |
1121 | This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. | 1156 | This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. |
1122 | 1157 | ||
@@ -1176,4 +1211,14 @@ config VIDEO_SAMSUNG_S5P_MFC | |||
1176 | help | 1211 | help |
1177 | MFC 5.1 driver for V4L2. | 1212 | MFC 5.1 driver for V4L2. |
1178 | 1213 | ||
1214 | config VIDEO_MX2_EMMAPRP | ||
1215 | tristate "MX2 eMMa-PrP support" | ||
1216 | depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27 | ||
1217 | select VIDEOBUF2_DMA_CONTIG | ||
1218 | select V4L2_MEM2MEM_DEV | ||
1219 | help | ||
1220 | MX2X chips have a PrP that can be used to process buffers from | ||
1221 | memory to memory. Operations include resizing and format | ||
1222 | conversion. | ||
1223 | |||
1179 | endif # V4L_MEM2MEM_DRIVERS | 1224 | endif # V4L_MEM2MEM_DRIVERS |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 354138804cda..a6282a3a6a82 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -12,16 +12,19 @@ omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o | |||
12 | 12 | ||
13 | videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ | 13 | videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ |
14 | v4l2-event.o v4l2-ctrls.o v4l2-subdev.o | 14 | v4l2-event.o v4l2-ctrls.o v4l2-subdev.o |
15 | ifeq ($(CONFIG_COMPAT),y) | ||
16 | videodev-objs += v4l2-compat-ioctl32.o | ||
17 | endif | ||
15 | 18 | ||
16 | # V4L2 core modules | 19 | # V4L2 core modules |
17 | 20 | ||
18 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o | 21 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o |
19 | ifeq ($(CONFIG_COMPAT),y) | ||
20 | obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o | ||
21 | endif | ||
22 | |||
23 | obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o | 22 | obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o |
24 | 23 | ||
24 | # Helper modules | ||
25 | |||
26 | obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o | ||
27 | |||
25 | # All i2c modules must come first: | 28 | # All i2c modules must come first: |
26 | 29 | ||
27 | obj-$(CONFIG_VIDEO_TUNER) += tuner.o | 30 | obj-$(CONFIG_VIDEO_TUNER) += tuner.o |
@@ -40,8 +43,10 @@ obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o | |||
40 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o | 43 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o |
41 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o | 44 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o |
42 | obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o | 45 | obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o |
46 | obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o | ||
43 | obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o | 47 | obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o |
44 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o | 48 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o |
49 | obj-$(CONFIG_VIDEO_VS6624) += vs6624.o | ||
45 | obj-$(CONFIG_VIDEO_BT819) += bt819.o | 50 | obj-$(CONFIG_VIDEO_BT819) += bt819.o |
46 | obj-$(CONFIG_VIDEO_BT856) += bt856.o | 51 | obj-$(CONFIG_VIDEO_BT856) += bt856.o |
47 | obj-$(CONFIG_VIDEO_BT866) += bt866.o | 52 | obj-$(CONFIG_VIDEO_BT866) += bt866.o |
@@ -65,6 +70,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | |||
65 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | 70 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o |
66 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o | 71 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o |
67 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o | 72 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o |
73 | obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o | ||
68 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o | 74 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o |
69 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o | 75 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o |
70 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | 76 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o |
@@ -177,6 +183,8 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o | |||
177 | obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o | 183 | obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o |
178 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o | 184 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o |
179 | 185 | ||
186 | obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o | ||
187 | |||
180 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ | 188 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ |
181 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ | 189 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ |
182 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ | 190 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ |
@@ -184,6 +192,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ | |||
184 | 192 | ||
185 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ | 193 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ |
186 | 194 | ||
195 | obj-$(CONFIG_BLACKFIN) += blackfin/ | ||
196 | |||
187 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ | 197 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ |
188 | 198 | ||
189 | obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o | 199 | obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o |
@@ -199,6 +209,6 @@ obj-y += davinci/ | |||
199 | 209 | ||
200 | obj-$(CONFIG_ARCH_OMAP) += omap/ | 210 | obj-$(CONFIG_ARCH_OMAP) += omap/ |
201 | 211 | ||
202 | ccflags-y += -Idrivers/media/dvb/dvb-core | 212 | ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core |
203 | ccflags-y += -Idrivers/media/dvb/frontends | 213 | ccflags-y += -I$(srctree)/drivers/media/dvb/frontends |
204 | ccflags-y += -Idrivers/media/common/tuners | 214 | ccflags-y += -I$(srctree)/drivers/media/common/tuners |
diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index 12eedf4d515a..5b045b4a66fe 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/i2c.h> | 35 | #include <linux/i2c.h> |
36 | #include <linux/module.h> | ||
37 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
38 | #include <linux/version.h> | 37 | #include <linux/version.h> |
39 | #include <media/adp1653.h> | 38 | #include <media/adp1653.h> |
@@ -482,24 +481,7 @@ static struct i2c_driver adp1653_i2c_driver = { | |||
482 | .id_table = adp1653_id_table, | 481 | .id_table = adp1653_id_table, |
483 | }; | 482 | }; |
484 | 483 | ||
485 | static int __init adp1653_init(void) | 484 | module_i2c_driver(adp1653_i2c_driver); |
486 | { | ||
487 | int rval; | ||
488 | |||
489 | rval = i2c_add_driver(&adp1653_i2c_driver); | ||
490 | if (rval) | ||
491 | printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__); | ||
492 | |||
493 | return rval; | ||
494 | } | ||
495 | |||
496 | static void __exit adp1653_exit(void) | ||
497 | { | ||
498 | i2c_del_driver(&adp1653_i2c_driver); | ||
499 | } | ||
500 | |||
501 | module_init(adp1653_init); | ||
502 | module_exit(adp1653_exit); | ||
503 | 485 | ||
504 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>"); | 486 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>"); |
505 | MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver"); | 487 | MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver"); |
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 879f1d839760..6bc01fb98ff8 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c | |||
@@ -407,15 +407,4 @@ static struct i2c_driver adv7170_driver = { | |||
407 | .id_table = adv7170_id, | 407 | .id_table = adv7170_id, |
408 | }; | 408 | }; |
409 | 409 | ||
410 | static __init int init_adv7170(void) | 410 | module_i2c_driver(adv7170_driver); |
411 | { | ||
412 | return i2c_add_driver(&adv7170_driver); | ||
413 | } | ||
414 | |||
415 | static __exit void exit_adv7170(void) | ||
416 | { | ||
417 | i2c_del_driver(&adv7170_driver); | ||
418 | } | ||
419 | |||
420 | module_init(init_adv7170); | ||
421 | module_exit(exit_adv7170); | ||
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 206078eca853..c7640fab5730 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c | |||
@@ -457,15 +457,4 @@ static struct i2c_driver adv7175_driver = { | |||
457 | .id_table = adv7175_id, | 457 | .id_table = adv7175_id, |
458 | }; | 458 | }; |
459 | 459 | ||
460 | static __init int init_adv7175(void) | 460 | module_i2c_driver(adv7175_driver); |
461 | { | ||
462 | return i2c_add_driver(&adv7175_driver); | ||
463 | } | ||
464 | |||
465 | static __exit void exit_adv7175(void) | ||
466 | { | ||
467 | i2c_del_driver(&adv7175_driver); | ||
468 | } | ||
469 | |||
470 | module_init(init_adv7175); | ||
471 | module_exit(exit_adv7175); | ||
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c index d2138d06bcad..b8b6c4b0cad4 100644 --- a/drivers/media/video/adv7180.c +++ b/drivers/media/video/adv7180.c | |||
@@ -444,20 +444,8 @@ static struct i2c_driver adv7180_driver = { | |||
444 | .id_table = adv7180_id, | 444 | .id_table = adv7180_id, |
445 | }; | 445 | }; |
446 | 446 | ||
447 | static __init int adv7180_init(void) | 447 | module_i2c_driver(adv7180_driver); |
448 | { | ||
449 | return i2c_add_driver(&adv7180_driver); | ||
450 | } | ||
451 | |||
452 | static __exit void adv7180_exit(void) | ||
453 | { | ||
454 | i2c_del_driver(&adv7180_driver); | ||
455 | } | ||
456 | |||
457 | module_init(adv7180_init); | ||
458 | module_exit(adv7180_exit); | ||
459 | 448 | ||
460 | MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); | 449 | MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); |
461 | MODULE_AUTHOR("Mocean Laboratories"); | 450 | MODULE_AUTHOR("Mocean Laboratories"); |
462 | MODULE_LICENSE("GPL v2"); | 451 | MODULE_LICENSE("GPL v2"); |
463 | |||
diff --git a/drivers/media/video/adv7183.c b/drivers/media/video/adv7183.c new file mode 100644 index 000000000000..e1d4c89d7140 --- /dev/null +++ b/drivers/media/video/adv7183.c | |||
@@ -0,0 +1,699 @@ | |||
1 | /* | ||
2 | * adv7183.c Analog Devices ADV7183 video decoder driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/videodev2.h> | ||
29 | |||
30 | #include <media/adv7183.h> | ||
31 | #include <media/v4l2-chip-ident.h> | ||
32 | #include <media/v4l2-ctrls.h> | ||
33 | #include <media/v4l2-device.h> | ||
34 | |||
35 | #include "adv7183_regs.h" | ||
36 | |||
37 | struct adv7183 { | ||
38 | struct v4l2_subdev sd; | ||
39 | struct v4l2_ctrl_handler hdl; | ||
40 | |||
41 | v4l2_std_id std; /* Current set standard */ | ||
42 | u32 input; | ||
43 | u32 output; | ||
44 | unsigned reset_pin; | ||
45 | unsigned oe_pin; | ||
46 | struct v4l2_mbus_framefmt fmt; | ||
47 | }; | ||
48 | |||
49 | /* EXAMPLES USING 27 MHz CLOCK | ||
50 | * Mode 1 CVBS Input (Composite Video on AIN5) | ||
51 | * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8. | ||
52 | */ | ||
53 | static const unsigned char adv7183_init_regs[] = { | ||
54 | ADV7183_IN_CTRL, 0x04, /* CVBS input on AIN5 */ | ||
55 | ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */ | ||
56 | ADV7183_SHAP_FILT_CTRL, 0x41, /* Set CSFM to SH1 */ | ||
57 | ADV7183_ADC_CTRL, 0x16, /* Power down ADC 1 and ADC 2 */ | ||
58 | ADV7183_CTI_DNR_CTRL_4, 0x04, /* Set DNR threshold to 4 for flat response */ | ||
59 | /* ADI recommended programming sequence */ | ||
60 | ADV7183_ADI_CTRL, 0x80, | ||
61 | ADV7183_CTI_DNR_CTRL_4, 0x20, | ||
62 | 0x52, 0x18, | ||
63 | 0x58, 0xED, | ||
64 | 0x77, 0xC5, | ||
65 | 0x7C, 0x93, | ||
66 | 0x7D, 0x00, | ||
67 | 0xD0, 0x48, | ||
68 | 0xD5, 0xA0, | ||
69 | 0xD7, 0xEA, | ||
70 | ADV7183_SD_SATURATION_CR, 0x3E, | ||
71 | ADV7183_PAL_V_END, 0x3E, | ||
72 | ADV7183_PAL_F_TOGGLE, 0x0F, | ||
73 | ADV7183_ADI_CTRL, 0x00, | ||
74 | }; | ||
75 | |||
76 | static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd) | ||
77 | { | ||
78 | return container_of(sd, struct adv7183, sd); | ||
79 | } | ||
80 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
81 | { | ||
82 | return &container_of(ctrl->handler, struct adv7183, hdl)->sd; | ||
83 | } | ||
84 | |||
85 | static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg) | ||
86 | { | ||
87 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
88 | |||
89 | return i2c_smbus_read_byte_data(client, reg); | ||
90 | } | ||
91 | |||
92 | static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg, | ||
93 | unsigned char value) | ||
94 | { | ||
95 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
96 | |||
97 | return i2c_smbus_write_byte_data(client, reg, value); | ||
98 | } | ||
99 | |||
100 | static int adv7183_writeregs(struct v4l2_subdev *sd, | ||
101 | const unsigned char *regs, unsigned int num) | ||
102 | { | ||
103 | unsigned char reg, data; | ||
104 | unsigned int cnt = 0; | ||
105 | |||
106 | if (num & 0x1) { | ||
107 | v4l2_err(sd, "invalid regs array\n"); | ||
108 | return -1; | ||
109 | } | ||
110 | |||
111 | while (cnt < num) { | ||
112 | reg = *regs++; | ||
113 | data = *regs++; | ||
114 | cnt += 2; | ||
115 | |||
116 | adv7183_write(sd, reg, data); | ||
117 | } | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int adv7183_log_status(struct v4l2_subdev *sd) | ||
122 | { | ||
123 | struct adv7183 *decoder = to_adv7183(sd); | ||
124 | |||
125 | v4l2_info(sd, "adv7183: Input control = 0x%02x\n", | ||
126 | adv7183_read(sd, ADV7183_IN_CTRL)); | ||
127 | v4l2_info(sd, "adv7183: Video selection = 0x%02x\n", | ||
128 | adv7183_read(sd, ADV7183_VD_SEL)); | ||
129 | v4l2_info(sd, "adv7183: Output control = 0x%02x\n", | ||
130 | adv7183_read(sd, ADV7183_OUT_CTRL)); | ||
131 | v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n", | ||
132 | adv7183_read(sd, ADV7183_EXT_OUT_CTRL)); | ||
133 | v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n", | ||
134 | adv7183_read(sd, ADV7183_AUTO_DET_EN)); | ||
135 | v4l2_info(sd, "adv7183: Contrast = 0x%02x\n", | ||
136 | adv7183_read(sd, ADV7183_CONTRAST)); | ||
137 | v4l2_info(sd, "adv7183: Brightness = 0x%02x\n", | ||
138 | adv7183_read(sd, ADV7183_BRIGHTNESS)); | ||
139 | v4l2_info(sd, "adv7183: Hue = 0x%02x\n", | ||
140 | adv7183_read(sd, ADV7183_HUE)); | ||
141 | v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n", | ||
142 | adv7183_read(sd, ADV7183_DEF_Y)); | ||
143 | v4l2_info(sd, "adv7183: Default value C = 0x%02x\n", | ||
144 | adv7183_read(sd, ADV7183_DEF_C)); | ||
145 | v4l2_info(sd, "adv7183: ADI control = 0x%02x\n", | ||
146 | adv7183_read(sd, ADV7183_ADI_CTRL)); | ||
147 | v4l2_info(sd, "adv7183: Power Management = 0x%02x\n", | ||
148 | adv7183_read(sd, ADV7183_POW_MANAGE)); | ||
149 | v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", | ||
150 | adv7183_read(sd, ADV7183_STATUS_1), | ||
151 | adv7183_read(sd, ADV7183_STATUS_2), | ||
152 | adv7183_read(sd, ADV7183_STATUS_3)); | ||
153 | v4l2_info(sd, "adv7183: Ident = 0x%02x\n", | ||
154 | adv7183_read(sd, ADV7183_IDENT)); | ||
155 | v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n", | ||
156 | adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL)); | ||
157 | v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n", | ||
158 | adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1)); | ||
159 | v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n", | ||
160 | adv7183_read(sd, ADV7183_SHAP_FILT_CTRL), | ||
161 | adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2)); | ||
162 | v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n", | ||
163 | adv7183_read(sd, ADV7183_COMB_FILT_CTRL)); | ||
164 | v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n", | ||
165 | adv7183_read(sd, ADV7183_ADI_CTRL_2)); | ||
166 | v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n", | ||
167 | adv7183_read(sd, ADV7183_PIX_DELAY_CTRL)); | ||
168 | v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n", | ||
169 | adv7183_read(sd, ADV7183_MISC_GAIN_CTRL)); | ||
170 | v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n", | ||
171 | adv7183_read(sd, ADV7183_AGC_MODE_CTRL)); | ||
172 | v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n", | ||
173 | adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1), | ||
174 | adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2)); | ||
175 | v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n", | ||
176 | adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1), | ||
177 | adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2)); | ||
178 | v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", | ||
179 | adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1), | ||
180 | adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2), | ||
181 | adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3)); | ||
182 | v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", | ||
183 | adv7183_read(sd, ADV7183_HS_POS_CTRL_1), | ||
184 | adv7183_read(sd, ADV7183_HS_POS_CTRL_2), | ||
185 | adv7183_read(sd, ADV7183_HS_POS_CTRL_3)); | ||
186 | v4l2_info(sd, "adv7183: Polarity = 0x%02x\n", | ||
187 | adv7183_read(sd, ADV7183_POLARITY)); | ||
188 | v4l2_info(sd, "adv7183: ADC control = 0x%02x\n", | ||
189 | adv7183_read(sd, ADV7183_ADC_CTRL)); | ||
190 | v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n", | ||
191 | adv7183_read(sd, ADV7183_SD_OFFSET_CB), | ||
192 | adv7183_read(sd, ADV7183_SD_OFFSET_CR)); | ||
193 | v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n", | ||
194 | adv7183_read(sd, ADV7183_SD_SATURATION_CB), | ||
195 | adv7183_read(sd, ADV7183_SD_SATURATION_CR)); | ||
196 | v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n", | ||
197 | adv7183_read(sd, ADV7183_DRIVE_STR)); | ||
198 | v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) | ||
203 | { | ||
204 | struct adv7183 *decoder = to_adv7183(sd); | ||
205 | |||
206 | *std = decoder->std; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std) | ||
211 | { | ||
212 | struct adv7183 *decoder = to_adv7183(sd); | ||
213 | int reg; | ||
214 | |||
215 | reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; | ||
216 | if (std == V4L2_STD_PAL_60) | ||
217 | reg |= 0x60; | ||
218 | else if (std == V4L2_STD_NTSC_443) | ||
219 | reg |= 0x70; | ||
220 | else if (std == V4L2_STD_PAL_N) | ||
221 | reg |= 0x90; | ||
222 | else if (std == V4L2_STD_PAL_M) | ||
223 | reg |= 0xA0; | ||
224 | else if (std == V4L2_STD_PAL_Nc) | ||
225 | reg |= 0xC0; | ||
226 | else if (std & V4L2_STD_PAL) | ||
227 | reg |= 0x80; | ||
228 | else if (std & V4L2_STD_NTSC) | ||
229 | reg |= 0x50; | ||
230 | else if (std & V4L2_STD_SECAM) | ||
231 | reg |= 0xE0; | ||
232 | else | ||
233 | return -EINVAL; | ||
234 | adv7183_write(sd, ADV7183_IN_CTRL, reg); | ||
235 | |||
236 | decoder->std = std; | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int adv7183_reset(struct v4l2_subdev *sd, u32 val) | ||
242 | { | ||
243 | int reg; | ||
244 | |||
245 | reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80; | ||
246 | adv7183_write(sd, ADV7183_POW_MANAGE, reg); | ||
247 | /* wait 5ms before any further i2c writes are performed */ | ||
248 | usleep_range(5000, 10000); | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int adv7183_s_routing(struct v4l2_subdev *sd, | ||
253 | u32 input, u32 output, u32 config) | ||
254 | { | ||
255 | struct adv7183 *decoder = to_adv7183(sd); | ||
256 | int reg; | ||
257 | |||
258 | if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT)) | ||
259 | return -EINVAL; | ||
260 | |||
261 | if (input != decoder->input) { | ||
262 | decoder->input = input; | ||
263 | reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0; | ||
264 | switch (input) { | ||
265 | case ADV7183_COMPOSITE1: | ||
266 | reg |= 0x1; | ||
267 | break; | ||
268 | case ADV7183_COMPOSITE2: | ||
269 | reg |= 0x2; | ||
270 | break; | ||
271 | case ADV7183_COMPOSITE3: | ||
272 | reg |= 0x3; | ||
273 | break; | ||
274 | case ADV7183_COMPOSITE4: | ||
275 | reg |= 0x4; | ||
276 | break; | ||
277 | case ADV7183_COMPOSITE5: | ||
278 | reg |= 0x5; | ||
279 | break; | ||
280 | case ADV7183_COMPOSITE6: | ||
281 | reg |= 0xB; | ||
282 | break; | ||
283 | case ADV7183_COMPOSITE7: | ||
284 | reg |= 0xC; | ||
285 | break; | ||
286 | case ADV7183_COMPOSITE8: | ||
287 | reg |= 0xD; | ||
288 | break; | ||
289 | case ADV7183_COMPOSITE9: | ||
290 | reg |= 0xE; | ||
291 | break; | ||
292 | case ADV7183_COMPOSITE10: | ||
293 | reg |= 0xF; | ||
294 | break; | ||
295 | case ADV7183_SVIDEO0: | ||
296 | reg |= 0x6; | ||
297 | break; | ||
298 | case ADV7183_SVIDEO1: | ||
299 | reg |= 0x7; | ||
300 | break; | ||
301 | case ADV7183_SVIDEO2: | ||
302 | reg |= 0x8; | ||
303 | break; | ||
304 | case ADV7183_COMPONENT0: | ||
305 | reg |= 0x9; | ||
306 | break; | ||
307 | case ADV7183_COMPONENT1: | ||
308 | reg |= 0xA; | ||
309 | break; | ||
310 | default: | ||
311 | break; | ||
312 | } | ||
313 | adv7183_write(sd, ADV7183_IN_CTRL, reg); | ||
314 | } | ||
315 | |||
316 | if (output != decoder->output) { | ||
317 | decoder->output = output; | ||
318 | reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0; | ||
319 | switch (output) { | ||
320 | case ADV7183_16BIT_OUT: | ||
321 | reg |= 0x9; | ||
322 | break; | ||
323 | default: | ||
324 | reg |= 0xC; | ||
325 | break; | ||
326 | } | ||
327 | adv7183_write(sd, ADV7183_OUT_CTRL, reg); | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl) | ||
334 | { | ||
335 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
336 | int val = ctrl->val; | ||
337 | |||
338 | switch (ctrl->id) { | ||
339 | case V4L2_CID_BRIGHTNESS: | ||
340 | if (val < 0) | ||
341 | val = 127 - val; | ||
342 | adv7183_write(sd, ADV7183_BRIGHTNESS, val); | ||
343 | break; | ||
344 | case V4L2_CID_CONTRAST: | ||
345 | adv7183_write(sd, ADV7183_CONTRAST, val); | ||
346 | break; | ||
347 | case V4L2_CID_SATURATION: | ||
348 | adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8); | ||
349 | adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF)); | ||
350 | break; | ||
351 | case V4L2_CID_HUE: | ||
352 | adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8); | ||
353 | adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF)); | ||
354 | break; | ||
355 | default: | ||
356 | return -EINVAL; | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) | ||
363 | { | ||
364 | struct adv7183 *decoder = to_adv7183(sd); | ||
365 | int reg; | ||
366 | |||
367 | /* enable autodetection block */ | ||
368 | reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; | ||
369 | adv7183_write(sd, ADV7183_IN_CTRL, reg); | ||
370 | |||
371 | /* wait autodetection switch */ | ||
372 | mdelay(10); | ||
373 | |||
374 | /* get autodetection result */ | ||
375 | reg = adv7183_read(sd, ADV7183_STATUS_1); | ||
376 | switch ((reg >> 0x4) & 0x7) { | ||
377 | case 0: | ||
378 | *std = V4L2_STD_NTSC; | ||
379 | break; | ||
380 | case 1: | ||
381 | *std = V4L2_STD_NTSC_443; | ||
382 | break; | ||
383 | case 2: | ||
384 | *std = V4L2_STD_PAL_M; | ||
385 | break; | ||
386 | case 3: | ||
387 | *std = V4L2_STD_PAL_60; | ||
388 | break; | ||
389 | case 4: | ||
390 | *std = V4L2_STD_PAL; | ||
391 | break; | ||
392 | case 5: | ||
393 | *std = V4L2_STD_SECAM; | ||
394 | break; | ||
395 | case 6: | ||
396 | *std = V4L2_STD_PAL_Nc; | ||
397 | break; | ||
398 | case 7: | ||
399 | *std = V4L2_STD_SECAM; | ||
400 | break; | ||
401 | default: | ||
402 | *std = V4L2_STD_UNKNOWN; | ||
403 | break; | ||
404 | } | ||
405 | |||
406 | /* after std detection, write back user set std */ | ||
407 | adv7183_s_std(sd, decoder->std); | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
412 | { | ||
413 | int reg; | ||
414 | |||
415 | *status = V4L2_IN_ST_NO_SIGNAL; | ||
416 | reg = adv7183_read(sd, ADV7183_STATUS_1); | ||
417 | if (reg < 0) | ||
418 | return reg; | ||
419 | if (reg & 0x1) | ||
420 | *status = 0; | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, | ||
425 | enum v4l2_mbus_pixelcode *code) | ||
426 | { | ||
427 | if (index > 0) | ||
428 | return -EINVAL; | ||
429 | |||
430 | *code = V4L2_MBUS_FMT_UYVY8_2X8; | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, | ||
435 | struct v4l2_mbus_framefmt *fmt) | ||
436 | { | ||
437 | struct adv7183 *decoder = to_adv7183(sd); | ||
438 | |||
439 | fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; | ||
440 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
441 | if (decoder->std & V4L2_STD_525_60) { | ||
442 | fmt->field = V4L2_FIELD_SEQ_TB; | ||
443 | fmt->width = 720; | ||
444 | fmt->height = 480; | ||
445 | } else { | ||
446 | fmt->field = V4L2_FIELD_SEQ_BT; | ||
447 | fmt->width = 720; | ||
448 | fmt->height = 576; | ||
449 | } | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd, | ||
454 | struct v4l2_mbus_framefmt *fmt) | ||
455 | { | ||
456 | struct adv7183 *decoder = to_adv7183(sd); | ||
457 | |||
458 | adv7183_try_mbus_fmt(sd, fmt); | ||
459 | decoder->fmt = *fmt; | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd, | ||
464 | struct v4l2_mbus_framefmt *fmt) | ||
465 | { | ||
466 | struct adv7183 *decoder = to_adv7183(sd); | ||
467 | |||
468 | *fmt = decoder->fmt; | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int adv7183_s_stream(struct v4l2_subdev *sd, int enable) | ||
473 | { | ||
474 | struct adv7183 *decoder = to_adv7183(sd); | ||
475 | |||
476 | if (enable) | ||
477 | gpio_direction_output(decoder->oe_pin, 0); | ||
478 | else | ||
479 | gpio_direction_output(decoder->oe_pin, 1); | ||
480 | udelay(1); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int adv7183_g_chip_ident(struct v4l2_subdev *sd, | ||
485 | struct v4l2_dbg_chip_ident *chip) | ||
486 | { | ||
487 | int rev; | ||
488 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
489 | |||
490 | /* 0x11 for adv7183, 0x13 for adv7183b */ | ||
491 | rev = adv7183_read(sd, ADV7183_IDENT); | ||
492 | |||
493 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev); | ||
494 | } | ||
495 | |||
496 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
497 | static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | ||
498 | { | ||
499 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
500 | |||
501 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
502 | return -EINVAL; | ||
503 | if (!capable(CAP_SYS_ADMIN)) | ||
504 | return -EPERM; | ||
505 | reg->val = adv7183_read(sd, reg->reg & 0xff); | ||
506 | reg->size = 1; | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | ||
511 | { | ||
512 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
513 | |||
514 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
515 | return -EINVAL; | ||
516 | if (!capable(CAP_SYS_ADMIN)) | ||
517 | return -EPERM; | ||
518 | adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff); | ||
519 | return 0; | ||
520 | } | ||
521 | #endif | ||
522 | |||
523 | static const struct v4l2_ctrl_ops adv7183_ctrl_ops = { | ||
524 | .s_ctrl = adv7183_s_ctrl, | ||
525 | }; | ||
526 | |||
527 | static const struct v4l2_subdev_core_ops adv7183_core_ops = { | ||
528 | .log_status = adv7183_log_status, | ||
529 | .g_std = adv7183_g_std, | ||
530 | .s_std = adv7183_s_std, | ||
531 | .reset = adv7183_reset, | ||
532 | .g_chip_ident = adv7183_g_chip_ident, | ||
533 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
534 | .g_register = adv7183_g_register, | ||
535 | .s_register = adv7183_s_register, | ||
536 | #endif | ||
537 | }; | ||
538 | |||
539 | static const struct v4l2_subdev_video_ops adv7183_video_ops = { | ||
540 | .s_routing = adv7183_s_routing, | ||
541 | .querystd = adv7183_querystd, | ||
542 | .g_input_status = adv7183_g_input_status, | ||
543 | .enum_mbus_fmt = adv7183_enum_mbus_fmt, | ||
544 | .try_mbus_fmt = adv7183_try_mbus_fmt, | ||
545 | .s_mbus_fmt = adv7183_s_mbus_fmt, | ||
546 | .g_mbus_fmt = adv7183_g_mbus_fmt, | ||
547 | .s_stream = adv7183_s_stream, | ||
548 | }; | ||
549 | |||
550 | static const struct v4l2_subdev_ops adv7183_ops = { | ||
551 | .core = &adv7183_core_ops, | ||
552 | .video = &adv7183_video_ops, | ||
553 | }; | ||
554 | |||
555 | static int adv7183_probe(struct i2c_client *client, | ||
556 | const struct i2c_device_id *id) | ||
557 | { | ||
558 | struct adv7183 *decoder; | ||
559 | struct v4l2_subdev *sd; | ||
560 | struct v4l2_ctrl_handler *hdl; | ||
561 | int ret; | ||
562 | struct v4l2_mbus_framefmt fmt; | ||
563 | const unsigned *pin_array; | ||
564 | |||
565 | /* Check if the adapter supports the needed features */ | ||
566 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
567 | return -EIO; | ||
568 | |||
569 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | ||
570 | client->addr << 1, client->adapter->name); | ||
571 | |||
572 | pin_array = client->dev.platform_data; | ||
573 | if (pin_array == NULL) | ||
574 | return -EINVAL; | ||
575 | |||
576 | decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL); | ||
577 | if (decoder == NULL) | ||
578 | return -ENOMEM; | ||
579 | |||
580 | decoder->reset_pin = pin_array[0]; | ||
581 | decoder->oe_pin = pin_array[1]; | ||
582 | |||
583 | if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) { | ||
584 | v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin); | ||
585 | ret = -EBUSY; | ||
586 | goto err_free_decoder; | ||
587 | } | ||
588 | |||
589 | if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) { | ||
590 | v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin); | ||
591 | ret = -EBUSY; | ||
592 | goto err_free_reset; | ||
593 | } | ||
594 | |||
595 | sd = &decoder->sd; | ||
596 | v4l2_i2c_subdev_init(sd, client, &adv7183_ops); | ||
597 | |||
598 | hdl = &decoder->hdl; | ||
599 | v4l2_ctrl_handler_init(hdl, 4); | ||
600 | v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, | ||
601 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); | ||
602 | v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, | ||
603 | V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80); | ||
604 | v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, | ||
605 | V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080); | ||
606 | v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, | ||
607 | V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080); | ||
608 | /* hook the control handler into the driver */ | ||
609 | sd->ctrl_handler = hdl; | ||
610 | if (hdl->error) { | ||
611 | ret = hdl->error; | ||
612 | |||
613 | v4l2_ctrl_handler_free(hdl); | ||
614 | goto err_free_oe; | ||
615 | } | ||
616 | |||
617 | /* v4l2 doesn't support an autodetect standard, pick PAL as default */ | ||
618 | decoder->std = V4L2_STD_PAL; | ||
619 | decoder->input = ADV7183_COMPOSITE4; | ||
620 | decoder->output = ADV7183_8BIT_OUT; | ||
621 | |||
622 | gpio_direction_output(decoder->oe_pin, 1); | ||
623 | /* reset chip */ | ||
624 | gpio_direction_output(decoder->reset_pin, 0); | ||
625 | /* reset pulse width at least 5ms */ | ||
626 | mdelay(10); | ||
627 | gpio_direction_output(decoder->reset_pin, 1); | ||
628 | /* wait 5ms before any further i2c writes are performed */ | ||
629 | mdelay(5); | ||
630 | |||
631 | adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs)); | ||
632 | adv7183_s_std(sd, decoder->std); | ||
633 | fmt.width = 720; | ||
634 | fmt.height = 576; | ||
635 | adv7183_s_mbus_fmt(sd, &fmt); | ||
636 | |||
637 | /* initialize the hardware to the default control values */ | ||
638 | ret = v4l2_ctrl_handler_setup(hdl); | ||
639 | if (ret) { | ||
640 | v4l2_ctrl_handler_free(hdl); | ||
641 | goto err_free_oe; | ||
642 | } | ||
643 | |||
644 | return 0; | ||
645 | err_free_oe: | ||
646 | gpio_free(decoder->oe_pin); | ||
647 | err_free_reset: | ||
648 | gpio_free(decoder->reset_pin); | ||
649 | err_free_decoder: | ||
650 | kfree(decoder); | ||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | static int adv7183_remove(struct i2c_client *client) | ||
655 | { | ||
656 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
657 | struct adv7183 *decoder = to_adv7183(sd); | ||
658 | |||
659 | v4l2_device_unregister_subdev(sd); | ||
660 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
661 | gpio_free(decoder->oe_pin); | ||
662 | gpio_free(decoder->reset_pin); | ||
663 | kfree(decoder); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static const struct i2c_device_id adv7183_id[] = { | ||
668 | {"adv7183", 0}, | ||
669 | {}, | ||
670 | }; | ||
671 | |||
672 | MODULE_DEVICE_TABLE(i2c, adv7183_id); | ||
673 | |||
674 | static struct i2c_driver adv7183_driver = { | ||
675 | .driver = { | ||
676 | .owner = THIS_MODULE, | ||
677 | .name = "adv7183", | ||
678 | }, | ||
679 | .probe = adv7183_probe, | ||
680 | .remove = __devexit_p(adv7183_remove), | ||
681 | .id_table = adv7183_id, | ||
682 | }; | ||
683 | |||
684 | static __init int adv7183_init(void) | ||
685 | { | ||
686 | return i2c_add_driver(&adv7183_driver); | ||
687 | } | ||
688 | |||
689 | static __exit void adv7183_exit(void) | ||
690 | { | ||
691 | i2c_del_driver(&adv7183_driver); | ||
692 | } | ||
693 | |||
694 | module_init(adv7183_init); | ||
695 | module_exit(adv7183_exit); | ||
696 | |||
697 | MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver"); | ||
698 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
699 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/adv7183_regs.h b/drivers/media/video/adv7183_regs.h new file mode 100644 index 000000000000..4a5b7d211d2f --- /dev/null +++ b/drivers/media/video/adv7183_regs.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * adv7183 - Analog Devices ADV7183 video decoder registers | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef _ADV7183_REGS_H_ | ||
21 | #define _ADV7183_REGS_H_ | ||
22 | |||
23 | #define ADV7183_IN_CTRL 0x00 /* Input control */ | ||
24 | #define ADV7183_VD_SEL 0x01 /* Video selection */ | ||
25 | #define ADV7183_OUT_CTRL 0x03 /* Output control */ | ||
26 | #define ADV7183_EXT_OUT_CTRL 0x04 /* Extended output control */ | ||
27 | #define ADV7183_AUTO_DET_EN 0x07 /* Autodetect enable */ | ||
28 | #define ADV7183_CONTRAST 0x08 /* Contrast */ | ||
29 | #define ADV7183_BRIGHTNESS 0x0A /* Brightness */ | ||
30 | #define ADV7183_HUE 0x0B /* Hue */ | ||
31 | #define ADV7183_DEF_Y 0x0C /* Default value Y */ | ||
32 | #define ADV7183_DEF_C 0x0D /* Default value C */ | ||
33 | #define ADV7183_ADI_CTRL 0x0E /* ADI control */ | ||
34 | #define ADV7183_POW_MANAGE 0x0F /* Power Management */ | ||
35 | #define ADV7183_STATUS_1 0x10 /* Status 1 */ | ||
36 | #define ADV7183_IDENT 0x11 /* Ident */ | ||
37 | #define ADV7183_STATUS_2 0x12 /* Status 2 */ | ||
38 | #define ADV7183_STATUS_3 0x13 /* Status 3 */ | ||
39 | #define ADV7183_ANAL_CLAMP_CTRL 0x14 /* Analog clamp control */ | ||
40 | #define ADV7183_DIGI_CLAMP_CTRL_1 0x15 /* Digital clamp control 1 */ | ||
41 | #define ADV7183_SHAP_FILT_CTRL 0x17 /* Shaping filter control */ | ||
42 | #define ADV7183_SHAP_FILT_CTRL_2 0x18 /* Shaping filter control 2 */ | ||
43 | #define ADV7183_COMB_FILT_CTRL 0x19 /* Comb filter control */ | ||
44 | #define ADV7183_ADI_CTRL_2 0x1D /* ADI control 2 */ | ||
45 | #define ADV7183_PIX_DELAY_CTRL 0x27 /* Pixel delay control */ | ||
46 | #define ADV7183_MISC_GAIN_CTRL 0x2B /* Misc gain control */ | ||
47 | #define ADV7183_AGC_MODE_CTRL 0x2C /* AGC mode control */ | ||
48 | #define ADV7183_CHRO_GAIN_CTRL_1 0x2D /* Chroma gain control 1 */ | ||
49 | #define ADV7183_CHRO_GAIN_CTRL_2 0x2E /* Chroma gain control 2 */ | ||
50 | #define ADV7183_LUMA_GAIN_CTRL_1 0x2F /* Luma gain control 1 */ | ||
51 | #define ADV7183_LUMA_GAIN_CTRL_2 0x30 /* Luma gain control 2 */ | ||
52 | #define ADV7183_VS_FIELD_CTRL_1 0x31 /* Vsync field control 1 */ | ||
53 | #define ADV7183_VS_FIELD_CTRL_2 0x32 /* Vsync field control 2 */ | ||
54 | #define ADV7183_VS_FIELD_CTRL_3 0x33 /* Vsync field control 3 */ | ||
55 | #define ADV7183_HS_POS_CTRL_1 0x34 /* Hsync positon control 1 */ | ||
56 | #define ADV7183_HS_POS_CTRL_2 0x35 /* Hsync positon control 2 */ | ||
57 | #define ADV7183_HS_POS_CTRL_3 0x36 /* Hsync positon control 3 */ | ||
58 | #define ADV7183_POLARITY 0x37 /* Polarity */ | ||
59 | #define ADV7183_NTSC_COMB_CTRL 0x38 /* NTSC comb control */ | ||
60 | #define ADV7183_PAL_COMB_CTRL 0x39 /* PAL comb control */ | ||
61 | #define ADV7183_ADC_CTRL 0x3A /* ADC control */ | ||
62 | #define ADV7183_MAN_WIN_CTRL 0x3D /* Manual window control */ | ||
63 | #define ADV7183_RESAMPLE_CTRL 0x41 /* Resample control */ | ||
64 | #define ADV7183_GEMSTAR_CTRL_1 0x48 /* Gemstar ctrl 1 */ | ||
65 | #define ADV7183_GEMSTAR_CTRL_2 0x49 /* Gemstar ctrl 2 */ | ||
66 | #define ADV7183_GEMSTAR_CTRL_3 0x4A /* Gemstar ctrl 3 */ | ||
67 | #define ADV7183_GEMSTAR_CTRL_4 0x4B /* Gemstar ctrl 4 */ | ||
68 | #define ADV7183_GEMSTAR_CTRL_5 0x4C /* Gemstar ctrl 5 */ | ||
69 | #define ADV7183_CTI_DNR_CTRL_1 0x4D /* CTI DNR ctrl 1 */ | ||
70 | #define ADV7183_CTI_DNR_CTRL_2 0x4E /* CTI DNR ctrl 2 */ | ||
71 | #define ADV7183_CTI_DNR_CTRL_4 0x50 /* CTI DNR ctrl 4 */ | ||
72 | #define ADV7183_LOCK_CNT 0x51 /* Lock count */ | ||
73 | #define ADV7183_FREE_LINE_LEN 0x8F /* Free-Run line length 1 */ | ||
74 | #define ADV7183_VBI_INFO 0x90 /* VBI info */ | ||
75 | #define ADV7183_WSS_1 0x91 /* WSS 1 */ | ||
76 | #define ADV7183_WSS_2 0x92 /* WSS 2 */ | ||
77 | #define ADV7183_EDTV_1 0x93 /* EDTV 1 */ | ||
78 | #define ADV7183_EDTV_2 0x94 /* EDTV 2 */ | ||
79 | #define ADV7183_EDTV_3 0x95 /* EDTV 3 */ | ||
80 | #define ADV7183_CGMS_1 0x96 /* CGMS 1 */ | ||
81 | #define ADV7183_CGMS_2 0x97 /* CGMS 2 */ | ||
82 | #define ADV7183_CGMS_3 0x98 /* CGMS 3 */ | ||
83 | #define ADV7183_CCAP_1 0x99 /* CCAP 1 */ | ||
84 | #define ADV7183_CCAP_2 0x9A /* CCAP 2 */ | ||
85 | #define ADV7183_LETTERBOX_1 0x9B /* Letterbox 1 */ | ||
86 | #define ADV7183_LETTERBOX_2 0x9C /* Letterbox 2 */ | ||
87 | #define ADV7183_LETTERBOX_3 0x9D /* Letterbox 3 */ | ||
88 | #define ADV7183_CRC_EN 0xB2 /* CRC enable */ | ||
89 | #define ADV7183_ADC_SWITCH_1 0xC3 /* ADC switch 1 */ | ||
90 | #define ADV7183_ADC_SWITCH_2 0xC4 /* ADC swithc 2 */ | ||
91 | #define ADV7183_LETTERBOX_CTRL_1 0xDC /* Letterbox control 1 */ | ||
92 | #define ADV7183_LETTERBOX_CTRL_2 0xDD /* Letterbox control 2 */ | ||
93 | #define ADV7183_SD_OFFSET_CB 0xE1 /* SD offset Cb */ | ||
94 | #define ADV7183_SD_OFFSET_CR 0xE2 /* SD offset Cr */ | ||
95 | #define ADV7183_SD_SATURATION_CB 0xE3 /* SD saturation Cb */ | ||
96 | #define ADV7183_SD_SATURATION_CR 0xE4 /* SD saturation Cr */ | ||
97 | #define ADV7183_NTSC_V_BEGIN 0xE5 /* NTSC V bit begin */ | ||
98 | #define ADV7183_NTSC_V_END 0xE6 /* NTSC V bit end */ | ||
99 | #define ADV7183_NTSC_F_TOGGLE 0xE7 /* NTSC F bit toggle */ | ||
100 | #define ADV7183_PAL_V_BEGIN 0xE8 /* PAL V bit begin */ | ||
101 | #define ADV7183_PAL_V_END 0xE9 /* PAL V bit end */ | ||
102 | #define ADV7183_PAL_F_TOGGLE 0xEA /* PAL F bit toggle */ | ||
103 | #define ADV7183_DRIVE_STR 0xF4 /* Drive strength */ | ||
104 | #define ADV7183_IF_COMP_CTRL 0xF8 /* IF comp control */ | ||
105 | #define ADV7183_VS_MODE_CTRL 0xF9 /* VS mode control */ | ||
106 | |||
107 | #endif | ||
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c index 021fab23070d..119b60401bf3 100644 --- a/drivers/media/video/adv7343.c +++ b/drivers/media/video/adv7343.c | |||
@@ -475,15 +475,4 @@ static struct i2c_driver adv7343_driver = { | |||
475 | .id_table = adv7343_id, | 475 | .id_table = adv7343_id, |
476 | }; | 476 | }; |
477 | 477 | ||
478 | static __init int init_adv7343(void) | 478 | module_i2c_driver(adv7343_driver); |
479 | { | ||
480 | return i2c_add_driver(&adv7343_driver); | ||
481 | } | ||
482 | |||
483 | static __exit void exit_adv7343(void) | ||
484 | { | ||
485 | i2c_del_driver(&adv7343_driver); | ||
486 | } | ||
487 | |||
488 | module_init(init_adv7343); | ||
489 | module_exit(exit_adv7343); | ||
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c index 53c496c00fb6..ba674656b10d 100644 --- a/drivers/media/video/ak881x.c +++ b/drivers/media/video/ak881x.c | |||
@@ -352,18 +352,7 @@ static struct i2c_driver ak881x_i2c_driver = { | |||
352 | .id_table = ak881x_id, | 352 | .id_table = ak881x_id, |
353 | }; | 353 | }; |
354 | 354 | ||
355 | static int __init ak881x_module_init(void) | 355 | module_i2c_driver(ak881x_i2c_driver); |
356 | { | ||
357 | return i2c_add_driver(&ak881x_i2c_driver); | ||
358 | } | ||
359 | |||
360 | static void __exit ak881x_module_exit(void) | ||
361 | { | ||
362 | i2c_del_driver(&ak881x_i2c_driver); | ||
363 | } | ||
364 | |||
365 | module_init(ak881x_module_init); | ||
366 | module_exit(ak881x_module_exit); | ||
367 | 356 | ||
368 | MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814"); | 357 | MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814"); |
369 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | 358 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); |
diff --git a/drivers/media/video/aptina-pll.c b/drivers/media/video/aptina-pll.c new file mode 100644 index 000000000000..0bd3813bb59d --- /dev/null +++ b/drivers/media/video/aptina-pll.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /* | ||
2 | * Aptina Sensor PLL Configuration | ||
3 | * | ||
4 | * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/device.h> | ||
22 | #include <linux/gcd.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/lcm.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "aptina-pll.h" | ||
28 | |||
29 | int aptina_pll_calculate(struct device *dev, | ||
30 | const struct aptina_pll_limits *limits, | ||
31 | struct aptina_pll *pll) | ||
32 | { | ||
33 | unsigned int mf_min; | ||
34 | unsigned int mf_max; | ||
35 | unsigned int p1_min; | ||
36 | unsigned int p1_max; | ||
37 | unsigned int p1; | ||
38 | unsigned int div; | ||
39 | |||
40 | dev_dbg(dev, "PLL: ext clock %u pix clock %u\n", | ||
41 | pll->ext_clock, pll->pix_clock); | ||
42 | |||
43 | if (pll->ext_clock < limits->ext_clock_min || | ||
44 | pll->ext_clock > limits->ext_clock_max) { | ||
45 | dev_err(dev, "pll: invalid external clock frequency.\n"); | ||
46 | return -EINVAL; | ||
47 | } | ||
48 | |||
49 | if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) { | ||
50 | dev_err(dev, "pll: invalid pixel clock frequency.\n"); | ||
51 | return -EINVAL; | ||
52 | } | ||
53 | |||
54 | /* Compute the multiplier M and combined N*P1 divisor. */ | ||
55 | div = gcd(pll->pix_clock, pll->ext_clock); | ||
56 | pll->m = pll->pix_clock / div; | ||
57 | div = pll->ext_clock / div; | ||
58 | |||
59 | /* We now have the smallest M and N*P1 values that will result in the | ||
60 | * desired pixel clock frequency, but they might be out of the valid | ||
61 | * range. Compute the factor by which we should multiply them given the | ||
62 | * following constraints: | ||
63 | * | ||
64 | * - minimum/maximum multiplier | ||
65 | * - minimum/maximum multiplier output clock frequency assuming the | ||
66 | * minimum/maximum N value | ||
67 | * - minimum/maximum combined N*P1 divisor | ||
68 | */ | ||
69 | mf_min = DIV_ROUND_UP(limits->m_min, pll->m); | ||
70 | mf_min = max(mf_min, limits->out_clock_min / | ||
71 | (pll->ext_clock / limits->n_min * pll->m)); | ||
72 | mf_min = max(mf_min, limits->n_min * limits->p1_min / div); | ||
73 | mf_max = limits->m_max / pll->m; | ||
74 | mf_max = min(mf_max, limits->out_clock_max / | ||
75 | (pll->ext_clock / limits->n_max * pll->m)); | ||
76 | mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div)); | ||
77 | |||
78 | dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max); | ||
79 | if (mf_min > mf_max) { | ||
80 | dev_err(dev, "pll: no valid combined N*P1 divisor.\n"); | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * We're looking for the highest acceptable P1 value for which a | ||
86 | * multiplier factor MF exists that fulfills the following conditions: | ||
87 | * | ||
88 | * 1. p1 is in the [p1_min, p1_max] range given by the limits and is | ||
89 | * even | ||
90 | * 2. mf is in the [mf_min, mf_max] range computed above | ||
91 | * 3. div * mf is a multiple of p1, in order to compute | ||
92 | * n = div * mf / p1 | ||
93 | * m = pll->m * mf | ||
94 | * 4. the internal clock frequency, given by ext_clock / n, is in the | ||
95 | * [int_clock_min, int_clock_max] range given by the limits | ||
96 | * 5. the output clock frequency, given by ext_clock / n * m, is in the | ||
97 | * [out_clock_min, out_clock_max] range given by the limits | ||
98 | * | ||
99 | * The first naive approach is to iterate over all p1 values acceptable | ||
100 | * according to (1) and all mf values acceptable according to (2), and | ||
101 | * stop at the first combination that fulfills (3), (4) and (5). This | ||
102 | * has a O(n^2) complexity. | ||
103 | * | ||
104 | * Instead of iterating over all mf values in the [mf_min, mf_max] range | ||
105 | * we can compute the mf increment between two acceptable values | ||
106 | * according to (3) with | ||
107 | * | ||
108 | * mf_inc = p1 / gcd(div, p1) (6) | ||
109 | * | ||
110 | * and round the minimum up to the nearest multiple of mf_inc. This will | ||
111 | * restrict the number of mf values to be checked. | ||
112 | * | ||
113 | * Furthermore, conditions (4) and (5) only restrict the range of | ||
114 | * acceptable p1 and mf values by modifying the minimum and maximum | ||
115 | * limits. (5) can be expressed as | ||
116 | * | ||
117 | * ext_clock / (div * mf / p1) * m * mf >= out_clock_min | ||
118 | * ext_clock / (div * mf / p1) * m * mf <= out_clock_max | ||
119 | * | ||
120 | * or | ||
121 | * | ||
122 | * p1 >= out_clock_min * div / (ext_clock * m) (7) | ||
123 | * p1 <= out_clock_max * div / (ext_clock * m) | ||
124 | * | ||
125 | * Similarly, (4) can be expressed as | ||
126 | * | ||
127 | * mf >= ext_clock * p1 / (int_clock_max * div) (8) | ||
128 | * mf <= ext_clock * p1 / (int_clock_min * div) | ||
129 | * | ||
130 | * We can thus iterate over the restricted p1 range defined by the | ||
131 | * combination of (1) and (7), and then compute the restricted mf range | ||
132 | * defined by the combination of (2), (6) and (8). If the resulting mf | ||
133 | * range is not empty, any value in the mf range is acceptable. We thus | ||
134 | * select the mf lwoer bound and the corresponding p1 value. | ||
135 | */ | ||
136 | if (limits->p1_min == 0) { | ||
137 | dev_err(dev, "pll: P1 minimum value must be >0.\n"); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div, | ||
142 | pll->ext_clock * pll->m)); | ||
143 | p1_max = min(limits->p1_max, limits->out_clock_max * div / | ||
144 | (pll->ext_clock * pll->m)); | ||
145 | |||
146 | for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) { | ||
147 | unsigned int mf_inc = p1 / gcd(div, p1); | ||
148 | unsigned int mf_high; | ||
149 | unsigned int mf_low; | ||
150 | |||
151 | mf_low = max(roundup(mf_min, mf_inc), | ||
152 | DIV_ROUND_UP(pll->ext_clock * p1, | ||
153 | limits->int_clock_max * div)); | ||
154 | mf_high = min(mf_max, pll->ext_clock * p1 / | ||
155 | (limits->int_clock_min * div)); | ||
156 | |||
157 | if (mf_low > mf_high) | ||
158 | continue; | ||
159 | |||
160 | pll->n = div * mf_low / p1; | ||
161 | pll->m *= mf_low; | ||
162 | pll->p1 = p1; | ||
163 | dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1); | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | dev_err(dev, "pll: no valid N and P1 divisors found.\n"); | ||
168 | return -EINVAL; | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(aptina_pll_calculate); | ||
171 | |||
172 | MODULE_DESCRIPTION("Aptina PLL Helpers"); | ||
173 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | ||
174 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/aptina-pll.h b/drivers/media/video/aptina-pll.h new file mode 100644 index 000000000000..b370e341e75d --- /dev/null +++ b/drivers/media/video/aptina-pll.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Aptina Sensor PLL Configuration | ||
3 | * | ||
4 | * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef __APTINA_PLL_H | ||
22 | #define __APTINA_PLL_H | ||
23 | |||
24 | struct aptina_pll { | ||
25 | unsigned int ext_clock; | ||
26 | unsigned int pix_clock; | ||
27 | |||
28 | unsigned int n; | ||
29 | unsigned int m; | ||
30 | unsigned int p1; | ||
31 | }; | ||
32 | |||
33 | struct aptina_pll_limits { | ||
34 | unsigned int ext_clock_min; | ||
35 | unsigned int ext_clock_max; | ||
36 | unsigned int int_clock_min; | ||
37 | unsigned int int_clock_max; | ||
38 | unsigned int out_clock_min; | ||
39 | unsigned int out_clock_max; | ||
40 | unsigned int pix_clock_max; | ||
41 | |||
42 | unsigned int n_min; | ||
43 | unsigned int n_max; | ||
44 | unsigned int m_min; | ||
45 | unsigned int m_max; | ||
46 | unsigned int p1_min; | ||
47 | unsigned int p1_max; | ||
48 | }; | ||
49 | |||
50 | struct device; | ||
51 | |||
52 | int aptina_pll_calculate(struct device *dev, | ||
53 | const struct aptina_pll_limits *limits, | ||
54 | struct aptina_pll *pll); | ||
55 | |||
56 | #endif /* __APTINA_PLL_H */ | ||
diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c index f241702a0f36..7a3371f044fc 100644 --- a/drivers/media/video/as3645a.c +++ b/drivers/media/video/as3645a.c | |||
@@ -881,24 +881,7 @@ static struct i2c_driver as3645a_i2c_driver = { | |||
881 | .id_table = as3645a_id_table, | 881 | .id_table = as3645a_id_table, |
882 | }; | 882 | }; |
883 | 883 | ||
884 | static int __init as3645a_init(void) | 884 | module_i2c_driver(as3645a_i2c_driver); |
885 | { | ||
886 | int rval; | ||
887 | |||
888 | rval = i2c_add_driver(&as3645a_i2c_driver); | ||
889 | if (rval) | ||
890 | pr_err("%s: Failed to register the driver\n", AS3645A_NAME); | ||
891 | |||
892 | return rval; | ||
893 | } | ||
894 | |||
895 | static void __exit as3645a_exit(void) | ||
896 | { | ||
897 | i2c_del_driver(&as3645a_i2c_driver); | ||
898 | } | ||
899 | |||
900 | module_init(as3645a_init); | ||
901 | module_exit(as3645a_exit); | ||
902 | 885 | ||
903 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | 886 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); |
904 | MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones"); | 887 | MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones"); |
diff --git a/drivers/media/video/blackfin/Kconfig b/drivers/media/video/blackfin/Kconfig new file mode 100644 index 000000000000..ecd5323768b7 --- /dev/null +++ b/drivers/media/video/blackfin/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | config VIDEO_BLACKFIN_CAPTURE | ||
2 | tristate "Blackfin Video Capture Driver" | ||
3 | depends on VIDEO_V4L2 && BLACKFIN && I2C | ||
4 | select VIDEOBUF2_DMA_CONTIG | ||
5 | help | ||
6 | V4L2 bridge driver for Blackfin video capture device. | ||
7 | Choose PPI or EPPI as its interface. | ||
8 | |||
9 | To compile this driver as a module, choose M here: the | ||
10 | module will be called bfin_video_capture. | ||
diff --git a/drivers/media/video/blackfin/Makefile b/drivers/media/video/blackfin/Makefile new file mode 100644 index 000000000000..aa3a0a216387 --- /dev/null +++ b/drivers/media/video/blackfin/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | bfin_video_capture-objs := bfin_capture.o ppi.o | ||
2 | obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o | ||
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c new file mode 100644 index 000000000000..514fcf742f5a --- /dev/null +++ b/drivers/media/video/blackfin/bfin_capture.c | |||
@@ -0,0 +1,1059 @@ | |||
1 | /* | ||
2 | * Analog Devices video capture driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/completion.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <linux/types.h> | ||
34 | |||
35 | #include <media/v4l2-chip-ident.h> | ||
36 | #include <media/v4l2-common.h> | ||
37 | #include <media/v4l2-ctrls.h> | ||
38 | #include <media/v4l2-device.h> | ||
39 | #include <media/v4l2-ioctl.h> | ||
40 | #include <media/videobuf2-dma-contig.h> | ||
41 | |||
42 | #include <asm/dma.h> | ||
43 | |||
44 | #include <media/blackfin/bfin_capture.h> | ||
45 | #include <media/blackfin/ppi.h> | ||
46 | |||
47 | #define CAPTURE_DRV_NAME "bfin_capture" | ||
48 | #define BCAP_MIN_NUM_BUF 2 | ||
49 | |||
50 | struct bcap_format { | ||
51 | char *desc; | ||
52 | u32 pixelformat; | ||
53 | enum v4l2_mbus_pixelcode mbus_code; | ||
54 | int bpp; /* bits per pixel */ | ||
55 | }; | ||
56 | |||
57 | struct bcap_buffer { | ||
58 | struct vb2_buffer vb; | ||
59 | struct list_head list; | ||
60 | }; | ||
61 | |||
62 | struct bcap_device { | ||
63 | /* capture device instance */ | ||
64 | struct v4l2_device v4l2_dev; | ||
65 | /* v4l2 control handler */ | ||
66 | struct v4l2_ctrl_handler ctrl_handler; | ||
67 | /* device node data */ | ||
68 | struct video_device *video_dev; | ||
69 | /* sub device instance */ | ||
70 | struct v4l2_subdev *sd; | ||
71 | /* capture config */ | ||
72 | struct bfin_capture_config *cfg; | ||
73 | /* ppi interface */ | ||
74 | struct ppi_if *ppi; | ||
75 | /* current input */ | ||
76 | unsigned int cur_input; | ||
77 | /* current selected standard */ | ||
78 | v4l2_std_id std; | ||
79 | /* used to store pixel format */ | ||
80 | struct v4l2_pix_format fmt; | ||
81 | /* bits per pixel*/ | ||
82 | int bpp; | ||
83 | /* used to store sensor supported format */ | ||
84 | struct bcap_format *sensor_formats; | ||
85 | /* number of sensor formats array */ | ||
86 | int num_sensor_formats; | ||
87 | /* pointing to current video buffer */ | ||
88 | struct bcap_buffer *cur_frm; | ||
89 | /* pointing to next video buffer */ | ||
90 | struct bcap_buffer *next_frm; | ||
91 | /* buffer queue used in videobuf2 */ | ||
92 | struct vb2_queue buffer_queue; | ||
93 | /* allocator-specific contexts for each plane */ | ||
94 | struct vb2_alloc_ctx *alloc_ctx; | ||
95 | /* queue of filled frames */ | ||
96 | struct list_head dma_queue; | ||
97 | /* used in videobuf2 callback */ | ||
98 | spinlock_t lock; | ||
99 | /* used to access capture device */ | ||
100 | struct mutex mutex; | ||
101 | /* used to wait ppi to complete one transfer */ | ||
102 | struct completion comp; | ||
103 | /* prepare to stop */ | ||
104 | bool stop; | ||
105 | }; | ||
106 | |||
107 | struct bcap_fh { | ||
108 | struct v4l2_fh fh; | ||
109 | /* indicates whether this file handle is doing IO */ | ||
110 | bool io_allowed; | ||
111 | }; | ||
112 | |||
113 | static const struct bcap_format bcap_formats[] = { | ||
114 | { | ||
115 | .desc = "YCbCr 4:2:2 Interleaved UYVY", | ||
116 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
117 | .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
118 | .bpp = 16, | ||
119 | }, | ||
120 | { | ||
121 | .desc = "YCbCr 4:2:2 Interleaved YUYV", | ||
122 | .pixelformat = V4L2_PIX_FMT_YUYV, | ||
123 | .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
124 | .bpp = 16, | ||
125 | }, | ||
126 | { | ||
127 | .desc = "RGB 565", | ||
128 | .pixelformat = V4L2_PIX_FMT_RGB565, | ||
129 | .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
130 | .bpp = 16, | ||
131 | }, | ||
132 | { | ||
133 | .desc = "RGB 444", | ||
134 | .pixelformat = V4L2_PIX_FMT_RGB444, | ||
135 | .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, | ||
136 | .bpp = 16, | ||
137 | }, | ||
138 | |||
139 | }; | ||
140 | #define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats) | ||
141 | |||
142 | static irqreturn_t bcap_isr(int irq, void *dev_id); | ||
143 | |||
144 | static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb) | ||
145 | { | ||
146 | return container_of(vb, struct bcap_buffer, vb); | ||
147 | } | ||
148 | |||
149 | static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) | ||
150 | { | ||
151 | enum v4l2_mbus_pixelcode code; | ||
152 | struct bcap_format *sf; | ||
153 | unsigned int num_formats = 0; | ||
154 | int i, j; | ||
155 | |||
156 | while (!v4l2_subdev_call(bcap_dev->sd, video, | ||
157 | enum_mbus_fmt, num_formats, &code)) | ||
158 | num_formats++; | ||
159 | if (!num_formats) | ||
160 | return -ENXIO; | ||
161 | |||
162 | sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL); | ||
163 | if (!sf) | ||
164 | return -ENOMEM; | ||
165 | |||
166 | for (i = 0; i < num_formats; i++) { | ||
167 | v4l2_subdev_call(bcap_dev->sd, video, | ||
168 | enum_mbus_fmt, i, &code); | ||
169 | for (j = 0; j < BCAP_MAX_FMTS; j++) | ||
170 | if (code == bcap_formats[j].mbus_code) | ||
171 | break; | ||
172 | if (j == BCAP_MAX_FMTS) { | ||
173 | /* we don't allow this sensor working with our bridge */ | ||
174 | kfree(sf); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | sf[i] = bcap_formats[j]; | ||
178 | } | ||
179 | bcap_dev->sensor_formats = sf; | ||
180 | bcap_dev->num_sensor_formats = num_formats; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) | ||
185 | { | ||
186 | bcap_dev->num_sensor_formats = 0; | ||
187 | kfree(bcap_dev->sensor_formats); | ||
188 | bcap_dev->sensor_formats = NULL; | ||
189 | } | ||
190 | |||
191 | static int bcap_open(struct file *file) | ||
192 | { | ||
193 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
194 | struct video_device *vfd = bcap_dev->video_dev; | ||
195 | struct bcap_fh *bcap_fh; | ||
196 | |||
197 | if (!bcap_dev->sd) { | ||
198 | v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n"); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | |||
202 | bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL); | ||
203 | if (!bcap_fh) { | ||
204 | v4l2_err(&bcap_dev->v4l2_dev, | ||
205 | "unable to allocate memory for file handle object\n"); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | v4l2_fh_init(&bcap_fh->fh, vfd); | ||
210 | |||
211 | /* store pointer to v4l2_fh in private_data member of file */ | ||
212 | file->private_data = &bcap_fh->fh; | ||
213 | v4l2_fh_add(&bcap_fh->fh); | ||
214 | bcap_fh->io_allowed = false; | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int bcap_release(struct file *file) | ||
219 | { | ||
220 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
221 | struct v4l2_fh *fh = file->private_data; | ||
222 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
223 | |||
224 | /* if this instance is doing IO */ | ||
225 | if (bcap_fh->io_allowed) | ||
226 | vb2_queue_release(&bcap_dev->buffer_queue); | ||
227 | |||
228 | file->private_data = NULL; | ||
229 | v4l2_fh_del(&bcap_fh->fh); | ||
230 | v4l2_fh_exit(&bcap_fh->fh); | ||
231 | kfree(bcap_fh); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int bcap_mmap(struct file *file, struct vm_area_struct *vma) | ||
236 | { | ||
237 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
238 | |||
239 | return vb2_mmap(&bcap_dev->buffer_queue, vma); | ||
240 | } | ||
241 | |||
242 | #ifndef CONFIG_MMU | ||
243 | static unsigned long bcap_get_unmapped_area(struct file *file, | ||
244 | unsigned long addr, | ||
245 | unsigned long len, | ||
246 | unsigned long pgoff, | ||
247 | unsigned long flags) | ||
248 | { | ||
249 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
250 | |||
251 | return vb2_get_unmapped_area(&bcap_dev->buffer_queue, | ||
252 | addr, | ||
253 | len, | ||
254 | pgoff, | ||
255 | flags); | ||
256 | } | ||
257 | #endif | ||
258 | |||
259 | static unsigned int bcap_poll(struct file *file, poll_table *wait) | ||
260 | { | ||
261 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
262 | |||
263 | return vb2_poll(&bcap_dev->buffer_queue, file, wait); | ||
264 | } | ||
265 | |||
266 | static int bcap_queue_setup(struct vb2_queue *vq, | ||
267 | const struct v4l2_format *fmt, | ||
268 | unsigned int *nbuffers, unsigned int *nplanes, | ||
269 | unsigned int sizes[], void *alloc_ctxs[]) | ||
270 | { | ||
271 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
272 | |||
273 | if (*nbuffers < BCAP_MIN_NUM_BUF) | ||
274 | *nbuffers = BCAP_MIN_NUM_BUF; | ||
275 | |||
276 | *nplanes = 1; | ||
277 | sizes[0] = bcap_dev->fmt.sizeimage; | ||
278 | alloc_ctxs[0] = bcap_dev->alloc_ctx; | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int bcap_buffer_init(struct vb2_buffer *vb) | ||
284 | { | ||
285 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
286 | |||
287 | INIT_LIST_HEAD(&buf->list); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int bcap_buffer_prepare(struct vb2_buffer *vb) | ||
292 | { | ||
293 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
294 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
295 | unsigned long size; | ||
296 | |||
297 | size = bcap_dev->fmt.sizeimage; | ||
298 | if (vb2_plane_size(vb, 0) < size) { | ||
299 | v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", | ||
300 | vb2_plane_size(vb, 0), size); | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | vb2_set_plane_payload(&buf->vb, 0, size); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static void bcap_buffer_queue(struct vb2_buffer *vb) | ||
309 | { | ||
310 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
311 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
312 | unsigned long flags; | ||
313 | |||
314 | spin_lock_irqsave(&bcap_dev->lock, flags); | ||
315 | list_add_tail(&buf->list, &bcap_dev->dma_queue); | ||
316 | spin_unlock_irqrestore(&bcap_dev->lock, flags); | ||
317 | } | ||
318 | |||
319 | static void bcap_buffer_cleanup(struct vb2_buffer *vb) | ||
320 | { | ||
321 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
322 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
323 | unsigned long flags; | ||
324 | |||
325 | spin_lock_irqsave(&bcap_dev->lock, flags); | ||
326 | list_del_init(&buf->list); | ||
327 | spin_unlock_irqrestore(&bcap_dev->lock, flags); | ||
328 | } | ||
329 | |||
330 | static void bcap_lock(struct vb2_queue *vq) | ||
331 | { | ||
332 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
333 | mutex_lock(&bcap_dev->mutex); | ||
334 | } | ||
335 | |||
336 | static void bcap_unlock(struct vb2_queue *vq) | ||
337 | { | ||
338 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
339 | mutex_unlock(&bcap_dev->mutex); | ||
340 | } | ||
341 | |||
342 | static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
343 | { | ||
344 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
345 | struct ppi_if *ppi = bcap_dev->ppi; | ||
346 | struct ppi_params params; | ||
347 | int ret; | ||
348 | |||
349 | /* enable streamon on the sub device */ | ||
350 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); | ||
351 | if (ret && (ret != -ENOIOCTLCMD)) { | ||
352 | v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | /* set ppi params */ | ||
357 | params.width = bcap_dev->fmt.width; | ||
358 | params.height = bcap_dev->fmt.height; | ||
359 | params.bpp = bcap_dev->bpp; | ||
360 | params.ppi_control = bcap_dev->cfg->ppi_control; | ||
361 | params.int_mask = bcap_dev->cfg->int_mask; | ||
362 | params.blank_clocks = bcap_dev->cfg->blank_clocks; | ||
363 | ret = ppi->ops->set_params(ppi, ¶ms); | ||
364 | if (ret < 0) { | ||
365 | v4l2_err(&bcap_dev->v4l2_dev, | ||
366 | "Error in setting ppi params\n"); | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | /* attach ppi DMA irq handler */ | ||
371 | ret = ppi->ops->attach_irq(ppi, bcap_isr); | ||
372 | if (ret < 0) { | ||
373 | v4l2_err(&bcap_dev->v4l2_dev, | ||
374 | "Error in attaching interrupt handler\n"); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | INIT_COMPLETION(bcap_dev->comp); | ||
379 | bcap_dev->stop = false; | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int bcap_stop_streaming(struct vb2_queue *vq) | ||
384 | { | ||
385 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
386 | struct ppi_if *ppi = bcap_dev->ppi; | ||
387 | int ret; | ||
388 | |||
389 | if (!vb2_is_streaming(vq)) | ||
390 | return 0; | ||
391 | |||
392 | bcap_dev->stop = true; | ||
393 | wait_for_completion(&bcap_dev->comp); | ||
394 | ppi->ops->stop(ppi); | ||
395 | ppi->ops->detach_irq(ppi); | ||
396 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0); | ||
397 | if (ret && (ret != -ENOIOCTLCMD)) | ||
398 | v4l2_err(&bcap_dev->v4l2_dev, | ||
399 | "stream off failed in subdev\n"); | ||
400 | |||
401 | /* release all active buffers */ | ||
402 | while (!list_empty(&bcap_dev->dma_queue)) { | ||
403 | bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, | ||
404 | struct bcap_buffer, list); | ||
405 | list_del(&bcap_dev->next_frm->list); | ||
406 | vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR); | ||
407 | } | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static struct vb2_ops bcap_video_qops = { | ||
412 | .queue_setup = bcap_queue_setup, | ||
413 | .buf_init = bcap_buffer_init, | ||
414 | .buf_prepare = bcap_buffer_prepare, | ||
415 | .buf_cleanup = bcap_buffer_cleanup, | ||
416 | .buf_queue = bcap_buffer_queue, | ||
417 | .wait_prepare = bcap_unlock, | ||
418 | .wait_finish = bcap_lock, | ||
419 | .start_streaming = bcap_start_streaming, | ||
420 | .stop_streaming = bcap_stop_streaming, | ||
421 | }; | ||
422 | |||
423 | static int bcap_reqbufs(struct file *file, void *priv, | ||
424 | struct v4l2_requestbuffers *req_buf) | ||
425 | { | ||
426 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
427 | struct vb2_queue *vq = &bcap_dev->buffer_queue; | ||
428 | struct v4l2_fh *fh = file->private_data; | ||
429 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
430 | |||
431 | if (vb2_is_busy(vq)) | ||
432 | return -EBUSY; | ||
433 | |||
434 | bcap_fh->io_allowed = true; | ||
435 | |||
436 | return vb2_reqbufs(vq, req_buf); | ||
437 | } | ||
438 | |||
439 | static int bcap_querybuf(struct file *file, void *priv, | ||
440 | struct v4l2_buffer *buf) | ||
441 | { | ||
442 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
443 | |||
444 | return vb2_querybuf(&bcap_dev->buffer_queue, buf); | ||
445 | } | ||
446 | |||
447 | static int bcap_qbuf(struct file *file, void *priv, | ||
448 | struct v4l2_buffer *buf) | ||
449 | { | ||
450 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
451 | struct v4l2_fh *fh = file->private_data; | ||
452 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
453 | |||
454 | if (!bcap_fh->io_allowed) | ||
455 | return -EBUSY; | ||
456 | |||
457 | return vb2_qbuf(&bcap_dev->buffer_queue, buf); | ||
458 | } | ||
459 | |||
460 | static int bcap_dqbuf(struct file *file, void *priv, | ||
461 | struct v4l2_buffer *buf) | ||
462 | { | ||
463 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
464 | struct v4l2_fh *fh = file->private_data; | ||
465 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
466 | |||
467 | if (!bcap_fh->io_allowed) | ||
468 | return -EBUSY; | ||
469 | |||
470 | return vb2_dqbuf(&bcap_dev->buffer_queue, | ||
471 | buf, file->f_flags & O_NONBLOCK); | ||
472 | } | ||
473 | |||
474 | static irqreturn_t bcap_isr(int irq, void *dev_id) | ||
475 | { | ||
476 | struct ppi_if *ppi = dev_id; | ||
477 | struct bcap_device *bcap_dev = ppi->priv; | ||
478 | struct timeval timevalue; | ||
479 | struct vb2_buffer *vb = &bcap_dev->cur_frm->vb; | ||
480 | dma_addr_t addr; | ||
481 | |||
482 | spin_lock(&bcap_dev->lock); | ||
483 | |||
484 | if (bcap_dev->cur_frm != bcap_dev->next_frm) { | ||
485 | do_gettimeofday(&timevalue); | ||
486 | vb->v4l2_buf.timestamp = timevalue; | ||
487 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
488 | bcap_dev->cur_frm = bcap_dev->next_frm; | ||
489 | } | ||
490 | |||
491 | ppi->ops->stop(ppi); | ||
492 | |||
493 | if (bcap_dev->stop) { | ||
494 | complete(&bcap_dev->comp); | ||
495 | } else { | ||
496 | if (!list_empty(&bcap_dev->dma_queue)) { | ||
497 | bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, | ||
498 | struct bcap_buffer, list); | ||
499 | list_del(&bcap_dev->next_frm->list); | ||
500 | addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0); | ||
501 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
502 | } | ||
503 | ppi->ops->start(ppi); | ||
504 | } | ||
505 | |||
506 | spin_unlock(&bcap_dev->lock); | ||
507 | |||
508 | return IRQ_HANDLED; | ||
509 | } | ||
510 | |||
511 | static int bcap_streamon(struct file *file, void *priv, | ||
512 | enum v4l2_buf_type buf_type) | ||
513 | { | ||
514 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
515 | struct bcap_fh *fh = file->private_data; | ||
516 | struct ppi_if *ppi = bcap_dev->ppi; | ||
517 | dma_addr_t addr; | ||
518 | int ret; | ||
519 | |||
520 | if (!fh->io_allowed) | ||
521 | return -EBUSY; | ||
522 | |||
523 | /* call streamon to start streaming in videobuf */ | ||
524 | ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type); | ||
525 | if (ret) | ||
526 | return ret; | ||
527 | |||
528 | /* if dma queue is empty, return error */ | ||
529 | if (list_empty(&bcap_dev->dma_queue)) { | ||
530 | v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n"); | ||
531 | ret = -EINVAL; | ||
532 | goto err; | ||
533 | } | ||
534 | |||
535 | /* get the next frame from the dma queue */ | ||
536 | bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, | ||
537 | struct bcap_buffer, list); | ||
538 | bcap_dev->cur_frm = bcap_dev->next_frm; | ||
539 | /* remove buffer from the dma queue */ | ||
540 | list_del(&bcap_dev->cur_frm->list); | ||
541 | addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); | ||
542 | /* update DMA address */ | ||
543 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
544 | /* enable ppi */ | ||
545 | ppi->ops->start(ppi); | ||
546 | |||
547 | return 0; | ||
548 | err: | ||
549 | vb2_streamoff(&bcap_dev->buffer_queue, buf_type); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | static int bcap_streamoff(struct file *file, void *priv, | ||
554 | enum v4l2_buf_type buf_type) | ||
555 | { | ||
556 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
557 | struct bcap_fh *fh = file->private_data; | ||
558 | |||
559 | if (!fh->io_allowed) | ||
560 | return -EBUSY; | ||
561 | |||
562 | return vb2_streamoff(&bcap_dev->buffer_queue, buf_type); | ||
563 | } | ||
564 | |||
565 | static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) | ||
566 | { | ||
567 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
568 | |||
569 | return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); | ||
570 | } | ||
571 | |||
572 | static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
573 | { | ||
574 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
575 | |||
576 | *std = bcap_dev->std; | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) | ||
581 | { | ||
582 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
583 | int ret; | ||
584 | |||
585 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
586 | return -EBUSY; | ||
587 | |||
588 | ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std); | ||
589 | if (ret < 0) | ||
590 | return ret; | ||
591 | |||
592 | bcap_dev->std = *std; | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int bcap_enum_input(struct file *file, void *priv, | ||
597 | struct v4l2_input *input) | ||
598 | { | ||
599 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
600 | struct bfin_capture_config *config = bcap_dev->cfg; | ||
601 | int ret; | ||
602 | u32 status; | ||
603 | |||
604 | if (input->index >= config->num_inputs) | ||
605 | return -EINVAL; | ||
606 | |||
607 | *input = config->inputs[input->index]; | ||
608 | /* get input status */ | ||
609 | ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status); | ||
610 | if (!ret) | ||
611 | input->status = status; | ||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | static int bcap_g_input(struct file *file, void *priv, unsigned int *index) | ||
616 | { | ||
617 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
618 | |||
619 | *index = bcap_dev->cur_input; | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int bcap_s_input(struct file *file, void *priv, unsigned int index) | ||
624 | { | ||
625 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
626 | struct bfin_capture_config *config = bcap_dev->cfg; | ||
627 | struct bcap_route *route; | ||
628 | int ret; | ||
629 | |||
630 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
631 | return -EBUSY; | ||
632 | |||
633 | if (index >= config->num_inputs) | ||
634 | return -EINVAL; | ||
635 | |||
636 | route = &config->routes[index]; | ||
637 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, | ||
638 | route->input, route->output, 0); | ||
639 | if ((ret < 0) && (ret != -ENOIOCTLCMD)) { | ||
640 | v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); | ||
641 | return ret; | ||
642 | } | ||
643 | bcap_dev->cur_input = index; | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int bcap_try_format(struct bcap_device *bcap, | ||
648 | struct v4l2_pix_format *pixfmt, | ||
649 | enum v4l2_mbus_pixelcode *mbus_code, | ||
650 | int *bpp) | ||
651 | { | ||
652 | struct bcap_format *sf = bcap->sensor_formats; | ||
653 | struct bcap_format *fmt = NULL; | ||
654 | struct v4l2_mbus_framefmt mbus_fmt; | ||
655 | int ret, i; | ||
656 | |||
657 | for (i = 0; i < bcap->num_sensor_formats; i++) { | ||
658 | fmt = &sf[i]; | ||
659 | if (pixfmt->pixelformat == fmt->pixelformat) | ||
660 | break; | ||
661 | } | ||
662 | if (i == bcap->num_sensor_formats) | ||
663 | fmt = &sf[0]; | ||
664 | |||
665 | if (mbus_code) | ||
666 | *mbus_code = fmt->mbus_code; | ||
667 | if (bpp) | ||
668 | *bpp = fmt->bpp; | ||
669 | v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code); | ||
670 | ret = v4l2_subdev_call(bcap->sd, video, | ||
671 | try_mbus_fmt, &mbus_fmt); | ||
672 | if (ret < 0) | ||
673 | return ret; | ||
674 | v4l2_fill_pix_format(pixfmt, &mbus_fmt); | ||
675 | pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8; | ||
676 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | static int bcap_enum_fmt_vid_cap(struct file *file, void *priv, | ||
681 | struct v4l2_fmtdesc *fmt) | ||
682 | { | ||
683 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
684 | struct bcap_format *sf = bcap_dev->sensor_formats; | ||
685 | |||
686 | if (fmt->index >= bcap_dev->num_sensor_formats) | ||
687 | return -EINVAL; | ||
688 | |||
689 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
690 | strlcpy(fmt->description, | ||
691 | sf[fmt->index].desc, | ||
692 | sizeof(fmt->description)); | ||
693 | fmt->pixelformat = sf[fmt->index].pixelformat; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static int bcap_try_fmt_vid_cap(struct file *file, void *priv, | ||
698 | struct v4l2_format *fmt) | ||
699 | { | ||
700 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
701 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
702 | |||
703 | return bcap_try_format(bcap_dev, pixfmt, NULL, NULL); | ||
704 | } | ||
705 | |||
706 | static int bcap_g_fmt_vid_cap(struct file *file, void *priv, | ||
707 | struct v4l2_format *fmt) | ||
708 | { | ||
709 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
710 | |||
711 | fmt->fmt.pix = bcap_dev->fmt; | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static int bcap_s_fmt_vid_cap(struct file *file, void *priv, | ||
716 | struct v4l2_format *fmt) | ||
717 | { | ||
718 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
719 | struct v4l2_mbus_framefmt mbus_fmt; | ||
720 | enum v4l2_mbus_pixelcode mbus_code; | ||
721 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
722 | int ret, bpp; | ||
723 | |||
724 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
725 | return -EBUSY; | ||
726 | |||
727 | /* see if format works */ | ||
728 | ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp); | ||
729 | if (ret < 0) | ||
730 | return ret; | ||
731 | |||
732 | v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code); | ||
733 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt); | ||
734 | if (ret < 0) | ||
735 | return ret; | ||
736 | bcap_dev->fmt = *pixfmt; | ||
737 | bcap_dev->bpp = bpp; | ||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | static int bcap_querycap(struct file *file, void *priv, | ||
742 | struct v4l2_capability *cap) | ||
743 | { | ||
744 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
745 | |||
746 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
747 | strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); | ||
748 | strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info)); | ||
749 | strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card)); | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int bcap_g_parm(struct file *file, void *fh, | ||
754 | struct v4l2_streamparm *a) | ||
755 | { | ||
756 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
757 | |||
758 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
759 | return -EINVAL; | ||
760 | return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a); | ||
761 | } | ||
762 | |||
763 | static int bcap_s_parm(struct file *file, void *fh, | ||
764 | struct v4l2_streamparm *a) | ||
765 | { | ||
766 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
767 | |||
768 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
769 | return -EINVAL; | ||
770 | return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a); | ||
771 | } | ||
772 | |||
773 | static int bcap_g_chip_ident(struct file *file, void *priv, | ||
774 | struct v4l2_dbg_chip_ident *chip) | ||
775 | { | ||
776 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
777 | |||
778 | chip->ident = V4L2_IDENT_NONE; | ||
779 | chip->revision = 0; | ||
780 | if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && | ||
781 | chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | ||
782 | return -EINVAL; | ||
783 | |||
784 | return v4l2_subdev_call(bcap_dev->sd, core, | ||
785 | g_chip_ident, chip); | ||
786 | } | ||
787 | |||
788 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
789 | static int bcap_dbg_g_register(struct file *file, void *priv, | ||
790 | struct v4l2_dbg_register *reg) | ||
791 | { | ||
792 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
793 | |||
794 | return v4l2_subdev_call(bcap_dev->sd, core, | ||
795 | g_register, reg); | ||
796 | } | ||
797 | |||
798 | static int bcap_dbg_s_register(struct file *file, void *priv, | ||
799 | struct v4l2_dbg_register *reg) | ||
800 | { | ||
801 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
802 | |||
803 | return v4l2_subdev_call(bcap_dev->sd, core, | ||
804 | s_register, reg); | ||
805 | } | ||
806 | #endif | ||
807 | |||
808 | static int bcap_log_status(struct file *file, void *priv) | ||
809 | { | ||
810 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
811 | /* status for sub devices */ | ||
812 | v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status); | ||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | static const struct v4l2_ioctl_ops bcap_ioctl_ops = { | ||
817 | .vidioc_querycap = bcap_querycap, | ||
818 | .vidioc_g_fmt_vid_cap = bcap_g_fmt_vid_cap, | ||
819 | .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap, | ||
820 | .vidioc_s_fmt_vid_cap = bcap_s_fmt_vid_cap, | ||
821 | .vidioc_try_fmt_vid_cap = bcap_try_fmt_vid_cap, | ||
822 | .vidioc_enum_input = bcap_enum_input, | ||
823 | .vidioc_g_input = bcap_g_input, | ||
824 | .vidioc_s_input = bcap_s_input, | ||
825 | .vidioc_querystd = bcap_querystd, | ||
826 | .vidioc_s_std = bcap_s_std, | ||
827 | .vidioc_g_std = bcap_g_std, | ||
828 | .vidioc_reqbufs = bcap_reqbufs, | ||
829 | .vidioc_querybuf = bcap_querybuf, | ||
830 | .vidioc_qbuf = bcap_qbuf, | ||
831 | .vidioc_dqbuf = bcap_dqbuf, | ||
832 | .vidioc_streamon = bcap_streamon, | ||
833 | .vidioc_streamoff = bcap_streamoff, | ||
834 | .vidioc_g_parm = bcap_g_parm, | ||
835 | .vidioc_s_parm = bcap_s_parm, | ||
836 | .vidioc_g_chip_ident = bcap_g_chip_ident, | ||
837 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
838 | .vidioc_g_register = bcap_dbg_g_register, | ||
839 | .vidioc_s_register = bcap_dbg_s_register, | ||
840 | #endif | ||
841 | .vidioc_log_status = bcap_log_status, | ||
842 | }; | ||
843 | |||
844 | static struct v4l2_file_operations bcap_fops = { | ||
845 | .owner = THIS_MODULE, | ||
846 | .open = bcap_open, | ||
847 | .release = bcap_release, | ||
848 | .unlocked_ioctl = video_ioctl2, | ||
849 | .mmap = bcap_mmap, | ||
850 | #ifndef CONFIG_MMU | ||
851 | .get_unmapped_area = bcap_get_unmapped_area, | ||
852 | #endif | ||
853 | .poll = bcap_poll | ||
854 | }; | ||
855 | |||
856 | static int __devinit bcap_probe(struct platform_device *pdev) | ||
857 | { | ||
858 | struct bcap_device *bcap_dev; | ||
859 | struct video_device *vfd; | ||
860 | struct i2c_adapter *i2c_adap; | ||
861 | struct bfin_capture_config *config; | ||
862 | struct vb2_queue *q; | ||
863 | int ret; | ||
864 | |||
865 | config = pdev->dev.platform_data; | ||
866 | if (!config) { | ||
867 | v4l2_err(pdev->dev.driver, "Unable to get board config\n"); | ||
868 | return -ENODEV; | ||
869 | } | ||
870 | |||
871 | bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL); | ||
872 | if (!bcap_dev) { | ||
873 | v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n"); | ||
874 | return -ENOMEM; | ||
875 | } | ||
876 | |||
877 | bcap_dev->cfg = config; | ||
878 | |||
879 | bcap_dev->ppi = ppi_create_instance(config->ppi_info); | ||
880 | if (!bcap_dev->ppi) { | ||
881 | v4l2_err(pdev->dev.driver, "Unable to create ppi\n"); | ||
882 | ret = -ENODEV; | ||
883 | goto err_free_dev; | ||
884 | } | ||
885 | bcap_dev->ppi->priv = bcap_dev; | ||
886 | |||
887 | bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
888 | if (IS_ERR(bcap_dev->alloc_ctx)) { | ||
889 | ret = PTR_ERR(bcap_dev->alloc_ctx); | ||
890 | goto err_free_ppi; | ||
891 | } | ||
892 | |||
893 | vfd = video_device_alloc(); | ||
894 | if (!vfd) { | ||
895 | ret = -ENOMEM; | ||
896 | v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); | ||
897 | goto err_cleanup_ctx; | ||
898 | } | ||
899 | |||
900 | /* initialize field of video device */ | ||
901 | vfd->release = video_device_release; | ||
902 | vfd->fops = &bcap_fops; | ||
903 | vfd->ioctl_ops = &bcap_ioctl_ops; | ||
904 | vfd->tvnorms = 0; | ||
905 | vfd->v4l2_dev = &bcap_dev->v4l2_dev; | ||
906 | set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); | ||
907 | strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); | ||
908 | bcap_dev->video_dev = vfd; | ||
909 | |||
910 | ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); | ||
911 | if (ret) { | ||
912 | v4l2_err(pdev->dev.driver, | ||
913 | "Unable to register v4l2 device\n"); | ||
914 | goto err_release_vdev; | ||
915 | } | ||
916 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); | ||
917 | |||
918 | bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler; | ||
919 | ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0); | ||
920 | if (ret) { | ||
921 | v4l2_err(&bcap_dev->v4l2_dev, | ||
922 | "Unable to init control handler\n"); | ||
923 | goto err_unreg_v4l2; | ||
924 | } | ||
925 | |||
926 | spin_lock_init(&bcap_dev->lock); | ||
927 | /* initialize queue */ | ||
928 | q = &bcap_dev->buffer_queue; | ||
929 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
930 | q->io_modes = VB2_MMAP; | ||
931 | q->drv_priv = bcap_dev; | ||
932 | q->buf_struct_size = sizeof(struct bcap_buffer); | ||
933 | q->ops = &bcap_video_qops; | ||
934 | q->mem_ops = &vb2_dma_contig_memops; | ||
935 | |||
936 | vb2_queue_init(q); | ||
937 | |||
938 | mutex_init(&bcap_dev->mutex); | ||
939 | init_completion(&bcap_dev->comp); | ||
940 | |||
941 | /* init video dma queues */ | ||
942 | INIT_LIST_HEAD(&bcap_dev->dma_queue); | ||
943 | |||
944 | vfd->lock = &bcap_dev->mutex; | ||
945 | |||
946 | /* register video device */ | ||
947 | ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); | ||
948 | if (ret) { | ||
949 | v4l2_err(&bcap_dev->v4l2_dev, | ||
950 | "Unable to register video device\n"); | ||
951 | goto err_free_handler; | ||
952 | } | ||
953 | video_set_drvdata(bcap_dev->video_dev, bcap_dev); | ||
954 | v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", | ||
955 | video_device_node_name(vfd)); | ||
956 | |||
957 | /* load up the subdevice */ | ||
958 | i2c_adap = i2c_get_adapter(config->i2c_adapter_id); | ||
959 | if (!i2c_adap) { | ||
960 | v4l2_err(&bcap_dev->v4l2_dev, | ||
961 | "Unable to find i2c adapter\n"); | ||
962 | goto err_unreg_vdev; | ||
963 | |||
964 | } | ||
965 | bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev, | ||
966 | i2c_adap, | ||
967 | &config->board_info, | ||
968 | NULL); | ||
969 | if (bcap_dev->sd) { | ||
970 | int i; | ||
971 | /* update tvnorms from the sub devices */ | ||
972 | for (i = 0; i < config->num_inputs; i++) | ||
973 | vfd->tvnorms |= config->inputs[i].std; | ||
974 | } else { | ||
975 | v4l2_err(&bcap_dev->v4l2_dev, | ||
976 | "Unable to register sub device\n"); | ||
977 | goto err_unreg_vdev; | ||
978 | } | ||
979 | |||
980 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n"); | ||
981 | |||
982 | /* now we can probe the default state */ | ||
983 | if (vfd->tvnorms) { | ||
984 | v4l2_std_id std; | ||
985 | ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std); | ||
986 | if (ret) { | ||
987 | v4l2_err(&bcap_dev->v4l2_dev, | ||
988 | "Unable to get std\n"); | ||
989 | goto err_unreg_vdev; | ||
990 | } | ||
991 | bcap_dev->std = std; | ||
992 | } | ||
993 | ret = bcap_init_sensor_formats(bcap_dev); | ||
994 | if (ret) { | ||
995 | v4l2_err(&bcap_dev->v4l2_dev, | ||
996 | "Unable to create sensor formats table\n"); | ||
997 | goto err_unreg_vdev; | ||
998 | } | ||
999 | return 0; | ||
1000 | err_unreg_vdev: | ||
1001 | video_unregister_device(bcap_dev->video_dev); | ||
1002 | bcap_dev->video_dev = NULL; | ||
1003 | err_free_handler: | ||
1004 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | ||
1005 | err_unreg_v4l2: | ||
1006 | v4l2_device_unregister(&bcap_dev->v4l2_dev); | ||
1007 | err_release_vdev: | ||
1008 | if (bcap_dev->video_dev) | ||
1009 | video_device_release(bcap_dev->video_dev); | ||
1010 | err_cleanup_ctx: | ||
1011 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | ||
1012 | err_free_ppi: | ||
1013 | ppi_delete_instance(bcap_dev->ppi); | ||
1014 | err_free_dev: | ||
1015 | kfree(bcap_dev); | ||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | static int __devexit bcap_remove(struct platform_device *pdev) | ||
1020 | { | ||
1021 | struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); | ||
1022 | struct bcap_device *bcap_dev = container_of(v4l2_dev, | ||
1023 | struct bcap_device, v4l2_dev); | ||
1024 | |||
1025 | bcap_free_sensor_formats(bcap_dev); | ||
1026 | video_unregister_device(bcap_dev->video_dev); | ||
1027 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | ||
1028 | v4l2_device_unregister(v4l2_dev); | ||
1029 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | ||
1030 | ppi_delete_instance(bcap_dev->ppi); | ||
1031 | kfree(bcap_dev); | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static struct platform_driver bcap_driver = { | ||
1036 | .driver = { | ||
1037 | .name = CAPTURE_DRV_NAME, | ||
1038 | .owner = THIS_MODULE, | ||
1039 | }, | ||
1040 | .probe = bcap_probe, | ||
1041 | .remove = __devexit_p(bcap_remove), | ||
1042 | }; | ||
1043 | |||
1044 | static __init int bcap_init(void) | ||
1045 | { | ||
1046 | return platform_driver_register(&bcap_driver); | ||
1047 | } | ||
1048 | |||
1049 | static __exit void bcap_exit(void) | ||
1050 | { | ||
1051 | platform_driver_unregister(&bcap_driver); | ||
1052 | } | ||
1053 | |||
1054 | module_init(bcap_init); | ||
1055 | module_exit(bcap_exit); | ||
1056 | |||
1057 | MODULE_DESCRIPTION("Analog Devices blackfin video capture driver"); | ||
1058 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
1059 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/blackfin/ppi.c b/drivers/media/video/blackfin/ppi.c new file mode 100644 index 000000000000..d29592186b02 --- /dev/null +++ b/drivers/media/video/blackfin/ppi.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * ppi.c Analog Devices Parallel Peripheral Interface driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <asm/bfin_ppi.h> | ||
23 | #include <asm/blackfin.h> | ||
24 | #include <asm/cacheflush.h> | ||
25 | #include <asm/dma.h> | ||
26 | #include <asm/portmux.h> | ||
27 | |||
28 | #include <media/blackfin/ppi.h> | ||
29 | |||
30 | static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler); | ||
31 | static void ppi_detach_irq(struct ppi_if *ppi); | ||
32 | static int ppi_start(struct ppi_if *ppi); | ||
33 | static int ppi_stop(struct ppi_if *ppi); | ||
34 | static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params); | ||
35 | static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr); | ||
36 | |||
37 | static const struct ppi_ops ppi_ops = { | ||
38 | .attach_irq = ppi_attach_irq, | ||
39 | .detach_irq = ppi_detach_irq, | ||
40 | .start = ppi_start, | ||
41 | .stop = ppi_stop, | ||
42 | .set_params = ppi_set_params, | ||
43 | .update_addr = ppi_update_addr, | ||
44 | }; | ||
45 | |||
46 | static irqreturn_t ppi_irq_err(int irq, void *dev_id) | ||
47 | { | ||
48 | struct ppi_if *ppi = dev_id; | ||
49 | const struct ppi_info *info = ppi->info; | ||
50 | |||
51 | switch (info->type) { | ||
52 | case PPI_TYPE_PPI: | ||
53 | { | ||
54 | struct bfin_ppi_regs *reg = info->base; | ||
55 | unsigned short status; | ||
56 | |||
57 | /* register on bf561 is cleared when read | ||
58 | * others are W1C | ||
59 | */ | ||
60 | status = bfin_read16(®->status); | ||
61 | bfin_write16(®->status, 0xff00); | ||
62 | break; | ||
63 | } | ||
64 | case PPI_TYPE_EPPI: | ||
65 | { | ||
66 | struct bfin_eppi_regs *reg = info->base; | ||
67 | bfin_write16(®->status, 0xffff); | ||
68 | break; | ||
69 | } | ||
70 | default: | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | return IRQ_HANDLED; | ||
75 | } | ||
76 | |||
77 | static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler) | ||
78 | { | ||
79 | const struct ppi_info *info = ppi->info; | ||
80 | int ret; | ||
81 | |||
82 | ret = request_dma(info->dma_ch, "PPI_DMA"); | ||
83 | |||
84 | if (ret) { | ||
85 | pr_err("Unable to allocate DMA channel for PPI\n"); | ||
86 | return ret; | ||
87 | } | ||
88 | set_dma_callback(info->dma_ch, handler, ppi); | ||
89 | |||
90 | if (ppi->err_int) { | ||
91 | ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi); | ||
92 | if (ret) { | ||
93 | pr_err("Unable to allocate IRQ for PPI\n"); | ||
94 | free_dma(info->dma_ch); | ||
95 | } | ||
96 | } | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | static void ppi_detach_irq(struct ppi_if *ppi) | ||
101 | { | ||
102 | const struct ppi_info *info = ppi->info; | ||
103 | |||
104 | if (ppi->err_int) | ||
105 | free_irq(info->irq_err, ppi); | ||
106 | free_dma(info->dma_ch); | ||
107 | } | ||
108 | |||
109 | static int ppi_start(struct ppi_if *ppi) | ||
110 | { | ||
111 | const struct ppi_info *info = ppi->info; | ||
112 | |||
113 | /* enable DMA */ | ||
114 | enable_dma(info->dma_ch); | ||
115 | |||
116 | /* enable PPI */ | ||
117 | ppi->ppi_control |= PORT_EN; | ||
118 | switch (info->type) { | ||
119 | case PPI_TYPE_PPI: | ||
120 | { | ||
121 | struct bfin_ppi_regs *reg = info->base; | ||
122 | bfin_write16(®->control, ppi->ppi_control); | ||
123 | break; | ||
124 | } | ||
125 | case PPI_TYPE_EPPI: | ||
126 | { | ||
127 | struct bfin_eppi_regs *reg = info->base; | ||
128 | bfin_write32(®->control, ppi->ppi_control); | ||
129 | break; | ||
130 | } | ||
131 | default: | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | |||
135 | SSYNC(); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int ppi_stop(struct ppi_if *ppi) | ||
140 | { | ||
141 | const struct ppi_info *info = ppi->info; | ||
142 | |||
143 | /* disable PPI */ | ||
144 | ppi->ppi_control &= ~PORT_EN; | ||
145 | switch (info->type) { | ||
146 | case PPI_TYPE_PPI: | ||
147 | { | ||
148 | struct bfin_ppi_regs *reg = info->base; | ||
149 | bfin_write16(®->control, ppi->ppi_control); | ||
150 | break; | ||
151 | } | ||
152 | case PPI_TYPE_EPPI: | ||
153 | { | ||
154 | struct bfin_eppi_regs *reg = info->base; | ||
155 | bfin_write32(®->control, ppi->ppi_control); | ||
156 | break; | ||
157 | } | ||
158 | default: | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | /* disable DMA */ | ||
163 | clear_dma_irqstat(info->dma_ch); | ||
164 | disable_dma(info->dma_ch); | ||
165 | |||
166 | SSYNC(); | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) | ||
171 | { | ||
172 | const struct ppi_info *info = ppi->info; | ||
173 | int dma32 = 0; | ||
174 | int dma_config, bytes_per_line, lines_per_frame; | ||
175 | |||
176 | bytes_per_line = params->width * params->bpp / 8; | ||
177 | lines_per_frame = params->height; | ||
178 | if (params->int_mask == 0xFFFFFFFF) | ||
179 | ppi->err_int = false; | ||
180 | else | ||
181 | ppi->err_int = true; | ||
182 | |||
183 | dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN); | ||
184 | ppi->ppi_control = params->ppi_control & ~PORT_EN; | ||
185 | switch (info->type) { | ||
186 | case PPI_TYPE_PPI: | ||
187 | { | ||
188 | struct bfin_ppi_regs *reg = info->base; | ||
189 | |||
190 | if (params->ppi_control & DMA32) | ||
191 | dma32 = 1; | ||
192 | |||
193 | bfin_write16(®->control, ppi->ppi_control); | ||
194 | bfin_write16(®->count, bytes_per_line - 1); | ||
195 | bfin_write16(®->frame, lines_per_frame); | ||
196 | break; | ||
197 | } | ||
198 | case PPI_TYPE_EPPI: | ||
199 | { | ||
200 | struct bfin_eppi_regs *reg = info->base; | ||
201 | |||
202 | if ((params->ppi_control & PACK_EN) | ||
203 | || (params->ppi_control & 0x38000) > DLEN_16) | ||
204 | dma32 = 1; | ||
205 | |||
206 | bfin_write32(®->control, ppi->ppi_control); | ||
207 | bfin_write16(®->line, bytes_per_line + params->blank_clocks); | ||
208 | bfin_write16(®->frame, lines_per_frame); | ||
209 | bfin_write16(®->hdelay, 0); | ||
210 | bfin_write16(®->vdelay, 0); | ||
211 | bfin_write16(®->hcount, bytes_per_line); | ||
212 | bfin_write16(®->vcount, lines_per_frame); | ||
213 | break; | ||
214 | } | ||
215 | default: | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | if (dma32) { | ||
220 | dma_config |= WDSIZE_32; | ||
221 | set_dma_x_count(info->dma_ch, bytes_per_line >> 2); | ||
222 | set_dma_x_modify(info->dma_ch, 4); | ||
223 | set_dma_y_modify(info->dma_ch, 4); | ||
224 | } else { | ||
225 | dma_config |= WDSIZE_16; | ||
226 | set_dma_x_count(info->dma_ch, bytes_per_line >> 1); | ||
227 | set_dma_x_modify(info->dma_ch, 2); | ||
228 | set_dma_y_modify(info->dma_ch, 2); | ||
229 | } | ||
230 | set_dma_y_count(info->dma_ch, lines_per_frame); | ||
231 | set_dma_config(info->dma_ch, dma_config); | ||
232 | |||
233 | SSYNC(); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr) | ||
238 | { | ||
239 | set_dma_start_addr(ppi->info->dma_ch, addr); | ||
240 | } | ||
241 | |||
242 | struct ppi_if *ppi_create_instance(const struct ppi_info *info) | ||
243 | { | ||
244 | struct ppi_if *ppi; | ||
245 | |||
246 | if (!info || !info->pin_req) | ||
247 | return NULL; | ||
248 | |||
249 | if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) { | ||
250 | pr_err("request peripheral failed\n"); | ||
251 | return NULL; | ||
252 | } | ||
253 | |||
254 | ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); | ||
255 | if (!ppi) { | ||
256 | peripheral_free_list(info->pin_req); | ||
257 | pr_err("unable to allocate memory for ppi handle\n"); | ||
258 | return NULL; | ||
259 | } | ||
260 | ppi->ops = &ppi_ops; | ||
261 | ppi->info = info; | ||
262 | |||
263 | pr_info("ppi probe success\n"); | ||
264 | return ppi; | ||
265 | } | ||
266 | |||
267 | void ppi_delete_instance(struct ppi_if *ppi) | ||
268 | { | ||
269 | peripheral_free_list(ppi->info->pin_req); | ||
270 | kfree(ppi); | ||
271 | } | ||
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index 859eabf57978..377bf05b1efd 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c | |||
@@ -514,15 +514,4 @@ static struct i2c_driver bt819_driver = { | |||
514 | .id_table = bt819_id, | 514 | .id_table = bt819_id, |
515 | }; | 515 | }; |
516 | 516 | ||
517 | static __init int init_bt819(void) | 517 | module_i2c_driver(bt819_driver); |
518 | { | ||
519 | return i2c_add_driver(&bt819_driver); | ||
520 | } | ||
521 | |||
522 | static __exit void exit_bt819(void) | ||
523 | { | ||
524 | i2c_del_driver(&bt819_driver); | ||
525 | } | ||
526 | |||
527 | module_init(init_bt819); | ||
528 | module_exit(exit_bt819); | ||
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index a43059d4c799..7e5bd365c239 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c | |||
@@ -270,15 +270,4 @@ static struct i2c_driver bt856_driver = { | |||
270 | .id_table = bt856_id, | 270 | .id_table = bt856_id, |
271 | }; | 271 | }; |
272 | 272 | ||
273 | static __init int init_bt856(void) | 273 | module_i2c_driver(bt856_driver); |
274 | { | ||
275 | return i2c_add_driver(&bt856_driver); | ||
276 | } | ||
277 | |||
278 | static __exit void exit_bt856(void) | ||
279 | { | ||
280 | i2c_del_driver(&bt856_driver); | ||
281 | } | ||
282 | |||
283 | module_init(init_bt856); | ||
284 | module_exit(exit_bt856); | ||
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c index 4e5dcea0501d..905320b67a1c 100644 --- a/drivers/media/video/bt866.c +++ b/drivers/media/video/bt866.c | |||
@@ -240,15 +240,4 @@ static struct i2c_driver bt866_driver = { | |||
240 | .id_table = bt866_id, | 240 | .id_table = bt866_id, |
241 | }; | 241 | }; |
242 | 242 | ||
243 | static __init int init_bt866(void) | 243 | module_i2c_driver(bt866_driver); |
244 | { | ||
245 | return i2c_add_driver(&bt866_driver); | ||
246 | } | ||
247 | |||
248 | static __exit void exit_bt866(void) | ||
249 | { | ||
250 | i2c_del_driver(&bt866_driver); | ||
251 | } | ||
252 | |||
253 | module_init(init_bt866); | ||
254 | module_exit(exit_bt866); | ||
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 76c301f05095..e581b37be789 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c | |||
@@ -2035,11 +2035,7 @@ static int bttv_log_status(struct file *file, void *f) | |||
2035 | struct bttv_fh *fh = f; | 2035 | struct bttv_fh *fh = f; |
2036 | struct bttv *btv = fh->btv; | 2036 | struct bttv *btv = fh->btv; |
2037 | 2037 | ||
2038 | pr_info("%d: ======== START STATUS CARD #%d ========\n", | ||
2039 | btv->c.nr, btv->c.nr); | ||
2040 | bttv_call_all(btv, core, log_status); | 2038 | bttv_call_all(btv, core, log_status); |
2041 | pr_info("%d: ======== END STATUS CARD #%d ========\n", | ||
2042 | btv->c.nr, btv->c.nr); | ||
2043 | return 0; | 2039 | return 0; |
2044 | } | 2040 | } |
2045 | 2041 | ||
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 1d64af9adf71..c8581e26fa9c 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c | |||
@@ -249,15 +249,4 @@ static struct i2c_driver cs5345_driver = { | |||
249 | .id_table = cs5345_id, | 249 | .id_table = cs5345_id, |
250 | }; | 250 | }; |
251 | 251 | ||
252 | static __init int init_cs5345(void) | 252 | module_i2c_driver(cs5345_driver); |
253 | { | ||
254 | return i2c_add_driver(&cs5345_driver); | ||
255 | } | ||
256 | |||
257 | static __exit void exit_cs5345(void) | ||
258 | { | ||
259 | i2c_del_driver(&cs5345_driver); | ||
260 | } | ||
261 | |||
262 | module_init(init_cs5345); | ||
263 | module_exit(exit_cs5345); | ||
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index 51c5b9ad67d8..b293912206eb 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c | |||
@@ -248,15 +248,4 @@ static struct i2c_driver cs53l32a_driver = { | |||
248 | .id_table = cs53l32a_id, | 248 | .id_table = cs53l32a_id, |
249 | }; | 249 | }; |
250 | 250 | ||
251 | static __init int init_cs53l32a(void) | 251 | module_i2c_driver(cs53l32a_driver); |
252 | { | ||
253 | return i2c_add_driver(&cs53l32a_driver); | ||
254 | } | ||
255 | |||
256 | static __exit void exit_cs53l32a(void) | ||
257 | { | ||
258 | i2c_del_driver(&cs53l32a_driver); | ||
259 | } | ||
260 | |||
261 | module_init(init_cs53l32a); | ||
262 | module_exit(exit_cs53l32a); | ||
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 349bd9c2aff5..b55d57cc1a1c 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include "cx18-ioctl.h" | 38 | #include "cx18-ioctl.h" |
39 | #include "cx18-controls.h" | 39 | #include "cx18-controls.h" |
40 | #include "tuner-xc2028.h" | 40 | #include "tuner-xc2028.h" |
41 | 41 | #include <linux/dma-mapping.h> | |
42 | #include <media/tveeprom.h> | 42 | #include <media/tveeprom.h> |
43 | 43 | ||
44 | /* If you have already X v4l cards, then set this to X. This way | 44 | /* If you have already X v4l cards, then set this to X. This way |
@@ -75,7 +75,7 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, | |||
75 | -1, -1, -1, -1, -1, -1, -1, -1 }; | 75 | -1, -1, -1, -1, -1, -1, -1, -1 }; |
76 | static unsigned cardtype_c = 1; | 76 | static unsigned cardtype_c = 1; |
77 | static unsigned tuner_c = 1; | 77 | static unsigned tuner_c = 1; |
78 | static bool radio_c = 1; | 78 | static unsigned radio_c = 1; |
79 | static char pal[] = "--"; | 79 | static char pal[] = "--"; |
80 | static char secam[] = "--"; | 80 | static char secam[] = "--"; |
81 | static char ntsc[] = "-"; | 81 | static char ntsc[] = "-"; |
@@ -110,7 +110,7 @@ static int retry_mmio = 1; | |||
110 | int cx18_debug; | 110 | int cx18_debug; |
111 | 111 | ||
112 | module_param_array(tuner, int, &tuner_c, 0644); | 112 | module_param_array(tuner, int, &tuner_c, 0644); |
113 | module_param_array(radio, bool, &radio_c, 0644); | 113 | module_param_array(radio, int, &radio_c, 0644); |
114 | module_param_array(cardtype, int, &cardtype_c, 0644); | 114 | module_param_array(cardtype, int, &cardtype_c, 0644); |
115 | module_param_string(pal, pal, sizeof(pal), 0644); | 115 | module_param_string(pal, pal, sizeof(pal), 0644); |
116 | module_param_string(secam, secam, sizeof(secam), 0644); | 116 | module_param_string(secam, secam, sizeof(secam), 0644); |
@@ -812,7 +812,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, | |||
812 | CX18_ERR("Can't enable device %d!\n", cx->instance); | 812 | CX18_ERR("Can't enable device %d!\n", cx->instance); |
813 | return -EIO; | 813 | return -EIO; |
814 | } | 814 | } |
815 | if (pci_set_dma_mask(pci_dev, 0xffffffff)) { | 815 | if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) { |
816 | CX18_ERR("No suitable DMA available, card %d\n", cx->instance); | 816 | CX18_ERR("No suitable DMA available, card %d\n", cx->instance); |
817 | return -EIO; | 817 | return -EIO; |
818 | } | 818 | } |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index b9a94fc5146d..7a37e0ee136f 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -44,8 +44,6 @@ | |||
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <asm/byteorder.h> | 45 | #include <asm/byteorder.h> |
46 | 46 | ||
47 | #include <linux/dvb/video.h> | ||
48 | #include <linux/dvb/audio.h> | ||
49 | #include <media/v4l2-common.h> | 47 | #include <media/v4l2-common.h> |
50 | #include <media/v4l2-ioctl.h> | 48 | #include <media/v4l2-ioctl.h> |
51 | #include <media/v4l2-device.h> | 49 | #include <media/v4l2-device.h> |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 66b1c15c3541..be49f68ddf37 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -1085,8 +1085,6 @@ static int cx18_log_status(struct file *file, void *fh) | |||
1085 | struct v4l2_audio audin; | 1085 | struct v4l2_audio audin; |
1086 | int i; | 1086 | int i; |
1087 | 1087 | ||
1088 | CX18_INFO("================= START STATUS CARD #%d " | ||
1089 | "=================\n", cx->instance); | ||
1090 | CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); | 1088 | CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); |
1091 | if (cx->hw_flags & CX18_HW_TVEEPROM) { | 1089 | if (cx->hw_flags & CX18_HW_TVEEPROM) { |
1092 | struct tveeprom tv; | 1090 | struct tveeprom tv; |
@@ -1120,8 +1118,6 @@ static int cx18_log_status(struct file *file, void *fh) | |||
1120 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", | 1118 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", |
1121 | (long long)cx->mpg_data_received, | 1119 | (long long)cx->mpg_data_received, |
1122 | (long long)cx->vbi_data_inserted); | 1120 | (long long)cx->vbi_data_inserted); |
1123 | CX18_INFO("================== END STATUS CARD #%d " | ||
1124 | "==================\n", cx->instance); | ||
1125 | return 0; | 1121 | return 0; |
1126 | } | 1122 | } |
1127 | 1123 | ||
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c index f8f0e59cd583..d4327dab5a36 100644 --- a/drivers/media/video/cx231xx/cx231xx-417.c +++ b/drivers/media/video/cx231xx/cx231xx-417.c | |||
@@ -1686,7 +1686,6 @@ static struct v4l2_capability pvr_capability = { | |||
1686 | .capabilities = (V4L2_CAP_VIDEO_CAPTURE | | 1686 | .capabilities = (V4L2_CAP_VIDEO_CAPTURE | |
1687 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | | 1687 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | |
1688 | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE), | 1688 | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE), |
1689 | .reserved = {0, 0, 0, 0} | ||
1690 | }; | 1689 | }; |
1691 | static int vidioc_querycap(struct file *file, void *priv, | 1690 | static int vidioc_querycap(struct file *file, void *priv, |
1692 | struct v4l2_capability *cap) | 1691 | struct v4l2_capability *cap) |
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 875a7ce94736..8ed460d692e0 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c | |||
@@ -861,7 +861,6 @@ void cx231xx_release_resources(struct cx231xx *dev) | |||
861 | kfree(dev->sliced_cc_mode.alt_max_pkt_size); | 861 | kfree(dev->sliced_cc_mode.alt_max_pkt_size); |
862 | kfree(dev->ts1_mode.alt_max_pkt_size); | 862 | kfree(dev->ts1_mode.alt_max_pkt_size); |
863 | kfree(dev); | 863 | kfree(dev); |
864 | dev = NULL; | ||
865 | } | 864 | } |
866 | 865 | ||
867 | /* | 866 | /* |
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index 829a41b0c9ef..7f916f0685e9 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c | |||
@@ -2319,8 +2319,7 @@ static int cx231xx_v4l2_close(struct file *filp) | |||
2319 | if (dev->state & DEV_DISCONNECTED) { | 2319 | if (dev->state & DEV_DISCONNECTED) { |
2320 | if (atomic_read(&dev->devlist_count) > 0) { | 2320 | if (atomic_read(&dev->devlist_count) > 0) { |
2321 | cx231xx_release_resources(dev); | 2321 | cx231xx_release_resources(dev); |
2322 | kfree(dev); | 2322 | fh->dev = NULL; |
2323 | dev = NULL; | ||
2324 | return 0; | 2323 | return 0; |
2325 | } | 2324 | } |
2326 | return 0; | 2325 | return 0; |
@@ -2350,8 +2349,7 @@ static int cx231xx_v4l2_close(struct file *filp) | |||
2350 | free the remaining resources */ | 2349 | free the remaining resources */ |
2351 | if (dev->state & DEV_DISCONNECTED) { | 2350 | if (dev->state & DEV_DISCONNECTED) { |
2352 | cx231xx_release_resources(dev); | 2351 | cx231xx_release_resources(dev); |
2353 | kfree(dev); | 2352 | fh->dev = NULL; |
2354 | dev = NULL; | ||
2355 | return 0; | 2353 | return 0; |
2356 | } | 2354 | } |
2357 | 2355 | ||
diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c index f617474f9073..7930ca58349f 100644 --- a/drivers/media/video/cx25821/cx25821-core.c +++ b/drivers/media/video/cx25821/cx25821-core.c | |||
@@ -1474,8 +1474,13 @@ static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = { | |||
1474 | .device = 0x8210, | 1474 | .device = 0x8210, |
1475 | .subvendor = 0x14f1, | 1475 | .subvendor = 0x14f1, |
1476 | .subdevice = 0x0920, | 1476 | .subdevice = 0x0920, |
1477 | }, | 1477 | }, { |
1478 | { | 1478 | /* CX25821 No Brand */ |
1479 | .vendor = 0x14f1, | ||
1480 | .device = 0x8210, | ||
1481 | .subvendor = 0x0000, | ||
1482 | .subdevice = 0x0000, | ||
1483 | }, { | ||
1479 | /* --- end of list --- */ | 1484 | /* --- end of list --- */ |
1480 | } | 1485 | } |
1481 | }; | 1486 | }; |
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 05247d4c340a..fc1ff69cffd0 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -5301,15 +5301,4 @@ static struct i2c_driver cx25840_driver = { | |||
5301 | .id_table = cx25840_id, | 5301 | .id_table = cx25840_id, |
5302 | }; | 5302 | }; |
5303 | 5303 | ||
5304 | static __init int init_cx25840(void) | 5304 | module_i2c_driver(cx25840_driver); |
5305 | { | ||
5306 | return i2c_add_driver(&cx25840_driver); | ||
5307 | } | ||
5308 | |||
5309 | static __exit void exit_cx25840(void) | ||
5310 | { | ||
5311 | i2c_del_driver(&cx25840_driver); | ||
5312 | } | ||
5313 | |||
5314 | module_init(init_cx25840); | ||
5315 | module_exit(exit_cx25840); | ||
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index 25036cb11bea..8bcac65f9294 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h | |||
@@ -18,8 +18,6 @@ | |||
18 | 18 | ||
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/videodev2.h> | 20 | #include <linux/videodev2.h> |
21 | #include <mach/hardware.h> | ||
22 | #include <mach/dm646x.h> | ||
23 | #include <media/davinci/vpif_types.h> | 21 | #include <media/davinci/vpif_types.h> |
24 | 22 | ||
25 | /* Maximum channel allowed */ | 23 | /* Maximum channel allowed */ |
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 286f02910044..7fa34b4fae26 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c | |||
@@ -39,8 +39,6 @@ | |||
39 | #include <media/v4l2-ioctl.h> | 39 | #include <media/v4l2-ioctl.h> |
40 | #include <media/v4l2-chip-ident.h> | 40 | #include <media/v4l2-chip-ident.h> |
41 | 41 | ||
42 | #include <mach/dm646x.h> | ||
43 | |||
44 | #include "vpif_display.h" | 42 | #include "vpif_display.h" |
45 | #include "vpif.h" | 43 | #include "vpif.h" |
46 | 44 | ||
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4561cd89938d..9fd8cc7dbb23 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -353,6 +353,44 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = { | |||
353 | }; | 353 | }; |
354 | #endif | 354 | #endif |
355 | 355 | ||
356 | /* 1b80:e425 MaxMedia UB425-TC | ||
357 | * GPIO_6 - demod reset, 0=active | ||
358 | * GPIO_7 - LED, 0=active | ||
359 | */ | ||
360 | static struct em28xx_reg_seq maxmedia_ub425_tc[] = { | ||
361 | {EM2874_R80_GPIO, 0x83, 0xff, 100}, | ||
362 | {EM2874_R80_GPIO, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */ | ||
363 | {EM2874_R80_GPIO, 0x43, 0xff, 000}, /* GPIO_7 = 0 */ | ||
364 | {-1, -1, -1, -1}, | ||
365 | }; | ||
366 | |||
367 | /* 2304:0242 PCTV QuatroStick (510e) | ||
368 | * GPIO_2: decoder reset, 0=active | ||
369 | * GPIO_4: decoder suspend, 0=active | ||
370 | * GPIO_6: demod reset, 0=active | ||
371 | * GPIO_7: LED, 1=active | ||
372 | */ | ||
373 | static struct em28xx_reg_seq pctv_510e[] = { | ||
374 | {EM2874_R80_GPIO, 0x10, 0xff, 100}, | ||
375 | {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ | ||
376 | {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ | ||
377 | { -1, -1, -1, -1}, | ||
378 | }; | ||
379 | |||
380 | /* 2013:0251 PCTV QuatroStick nano (520e) | ||
381 | * GPIO_2: decoder reset, 0=active | ||
382 | * GPIO_4: decoder suspend, 0=active | ||
383 | * GPIO_6: demod reset, 0=active | ||
384 | * GPIO_7: LED, 1=active | ||
385 | */ | ||
386 | static struct em28xx_reg_seq pctv_520e[] = { | ||
387 | {EM2874_R80_GPIO, 0x10, 0xff, 100}, | ||
388 | {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ | ||
389 | {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ | ||
390 | {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */ | ||
391 | { -1, -1, -1, -1}, | ||
392 | }; | ||
393 | |||
356 | /* | 394 | /* |
357 | * Board definitions | 395 | * Board definitions |
358 | */ | 396 | */ |
@@ -1908,6 +1946,41 @@ struct em28xx_board em28xx_boards[] = { | |||
1908 | .amux = EM28XX_AMUX_LINE_IN, | 1946 | .amux = EM28XX_AMUX_LINE_IN, |
1909 | } }, | 1947 | } }, |
1910 | }, | 1948 | }, |
1949 | /* 1b80:e425 MaxMedia UB425-TC | ||
1950 | * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */ | ||
1951 | [EM2874_BOARD_MAXMEDIA_UB425_TC] = { | ||
1952 | .name = "MaxMedia UB425-TC", | ||
1953 | .tuner_type = TUNER_ABSENT, | ||
1954 | .tuner_gpio = maxmedia_ub425_tc, | ||
1955 | .has_dvb = 1, | ||
1956 | .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | | ||
1957 | EM28XX_I2C_CLK_WAIT_ENABLE | | ||
1958 | EM28XX_I2C_FREQ_400_KHZ, | ||
1959 | }, | ||
1960 | /* 2304:0242 PCTV QuatroStick (510e) | ||
1961 | * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ | ||
1962 | [EM2884_BOARD_PCTV_510E] = { | ||
1963 | .name = "PCTV QuatroStick (510e)", | ||
1964 | .tuner_type = TUNER_ABSENT, | ||
1965 | .tuner_gpio = pctv_510e, | ||
1966 | .has_dvb = 1, | ||
1967 | .ir_codes = RC_MAP_PINNACLE_PCTV_HD, | ||
1968 | .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | | ||
1969 | EM28XX_I2C_CLK_WAIT_ENABLE | | ||
1970 | EM28XX_I2C_FREQ_400_KHZ, | ||
1971 | }, | ||
1972 | /* 2013:0251 PCTV QuatroStick nano (520e) | ||
1973 | * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ | ||
1974 | [EM2884_BOARD_PCTV_520E] = { | ||
1975 | .name = "PCTV QuatroStick nano (520e)", | ||
1976 | .tuner_type = TUNER_ABSENT, | ||
1977 | .tuner_gpio = pctv_520e, | ||
1978 | .has_dvb = 1, | ||
1979 | .ir_codes = RC_MAP_PINNACLE_PCTV_HD, | ||
1980 | .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | | ||
1981 | EM28XX_I2C_CLK_WAIT_ENABLE | | ||
1982 | EM28XX_I2C_FREQ_400_KHZ, | ||
1983 | }, | ||
1911 | }; | 1984 | }; |
1912 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); | 1985 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); |
1913 | 1986 | ||
@@ -2059,6 +2132,12 @@ struct usb_device_id em28xx_id_table[] = { | |||
2059 | .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 }, | 2132 | .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 }, |
2060 | { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */ | 2133 | { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */ |
2061 | .driver_info = EM2860_BOARD_EASYCAP }, | 2134 | .driver_info = EM2860_BOARD_EASYCAP }, |
2135 | { USB_DEVICE(0x1b80, 0xe425), | ||
2136 | .driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC }, | ||
2137 | { USB_DEVICE(0x2304, 0x0242), | ||
2138 | .driver_info = EM2884_BOARD_PCTV_510E }, | ||
2139 | { USB_DEVICE(0x2013, 0x0251), | ||
2140 | .driver_info = EM2884_BOARD_PCTV_520E }, | ||
2062 | { }, | 2141 | { }, |
2063 | }; | 2142 | }; |
2064 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); | 2143 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); |
@@ -3122,7 +3201,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3122 | int i, nr; | 3201 | int i, nr; |
3123 | const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; | 3202 | const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; |
3124 | char *speed; | 3203 | char *speed; |
3125 | char descr[255] = ""; | ||
3126 | 3204 | ||
3127 | udev = usb_get_dev(interface_to_usbdev(interface)); | 3205 | udev = usb_get_dev(interface_to_usbdev(interface)); |
3128 | 3206 | ||
@@ -3227,21 +3305,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3227 | speed = "unknown"; | 3305 | speed = "unknown"; |
3228 | } | 3306 | } |
3229 | 3307 | ||
3230 | if (udev->manufacturer) | ||
3231 | strlcpy(descr, udev->manufacturer, sizeof(descr)); | ||
3232 | |||
3233 | if (udev->product) { | ||
3234 | if (*descr) | ||
3235 | strlcat(descr, " ", sizeof(descr)); | ||
3236 | strlcat(descr, udev->product, sizeof(descr)); | ||
3237 | } | ||
3238 | |||
3239 | if (*descr) | ||
3240 | strlcat(descr, " ", sizeof(descr)); | ||
3241 | |||
3242 | printk(KERN_INFO DRIVER_NAME | 3308 | printk(KERN_INFO DRIVER_NAME |
3243 | ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n", | 3309 | ": New device %s %s @ %s Mbps " |
3244 | descr, | 3310 | "(%04x:%04x, interface %d, class %d)\n", |
3311 | udev->manufacturer ? udev->manufacturer : "", | ||
3312 | udev->product ? udev->product : "", | ||
3245 | speed, | 3313 | speed, |
3246 | le16_to_cpu(udev->descriptor.idVendor), | 3314 | le16_to_cpu(udev->descriptor.idVendor), |
3247 | le16_to_cpu(udev->descriptor.idProduct), | 3315 | le16_to_cpu(udev->descriptor.idProduct), |
@@ -3307,6 +3375,17 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3307 | goto unlock_and_free; | 3375 | goto unlock_and_free; |
3308 | } | 3376 | } |
3309 | 3377 | ||
3378 | if (has_dvb) { | ||
3379 | /* pre-allocate DVB isoc transfer buffers */ | ||
3380 | retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE, | ||
3381 | EM28XX_DVB_MAX_PACKETS, | ||
3382 | EM28XX_DVB_NUM_BUFS, | ||
3383 | dev->dvb_max_pkt_size); | ||
3384 | if (retval) { | ||
3385 | goto unlock_and_free; | ||
3386 | } | ||
3387 | } | ||
3388 | |||
3310 | request_modules(dev); | 3389 | request_modules(dev); |
3311 | 3390 | ||
3312 | /* Should be the last thing to do, to avoid newer udev's to | 3391 | /* Should be the last thing to do, to avoid newer udev's to |
@@ -3379,7 +3458,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) | |||
3379 | video_device_node_name(dev->vdev)); | 3458 | video_device_node_name(dev->vdev)); |
3380 | 3459 | ||
3381 | dev->state |= DEV_MISCONFIGURED; | 3460 | dev->state |= DEV_MISCONFIGURED; |
3382 | em28xx_uninit_isoc(dev); | 3461 | em28xx_uninit_isoc(dev, dev->mode); |
3383 | dev->state |= DEV_DISCONNECTED; | 3462 | dev->state |= DEV_DISCONNECTED; |
3384 | wake_up_interruptible(&dev->wait_frame); | 3463 | wake_up_interruptible(&dev->wait_frame); |
3385 | wake_up_interruptible(&dev->wait_stream); | 3464 | wake_up_interruptible(&dev->wait_stream); |
@@ -3388,6 +3467,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) | |||
3388 | em28xx_release_resources(dev); | 3467 | em28xx_release_resources(dev); |
3389 | } | 3468 | } |
3390 | 3469 | ||
3470 | /* free DVB isoc buffers */ | ||
3471 | em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE); | ||
3472 | |||
3391 | mutex_unlock(&dev->lock); | 3473 | mutex_unlock(&dev->lock); |
3392 | 3474 | ||
3393 | em28xx_close_extension(dev); | 3475 | em28xx_close_extension(dev); |
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 0aacc96f9a23..53a9fb91e97e 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c | |||
@@ -666,6 +666,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) | |||
666 | 666 | ||
667 | return rc; | 667 | return rc; |
668 | } | 668 | } |
669 | EXPORT_SYMBOL_GPL(em28xx_capture_start); | ||
669 | 670 | ||
670 | int em28xx_vbi_supported(struct em28xx *dev) | 671 | int em28xx_vbi_supported(struct em28xx *dev) |
671 | { | 672 | { |
@@ -961,146 +962,192 @@ static void em28xx_irq_callback(struct urb *urb) | |||
961 | /* | 962 | /* |
962 | * Stop and Deallocate URBs | 963 | * Stop and Deallocate URBs |
963 | */ | 964 | */ |
964 | void em28xx_uninit_isoc(struct em28xx *dev) | 965 | void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode) |
965 | { | 966 | { |
966 | struct urb *urb; | 967 | struct urb *urb; |
968 | struct em28xx_usb_isoc_bufs *isoc_bufs; | ||
967 | int i; | 969 | int i; |
968 | 970 | ||
969 | em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); | 971 | em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode); |
972 | |||
973 | if (mode == EM28XX_DIGITAL_MODE) | ||
974 | isoc_bufs = &dev->isoc_ctl.digital_bufs; | ||
975 | else | ||
976 | isoc_bufs = &dev->isoc_ctl.analog_bufs; | ||
970 | 977 | ||
971 | dev->isoc_ctl.nfields = -1; | 978 | dev->isoc_ctl.nfields = -1; |
972 | for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { | 979 | for (i = 0; i < isoc_bufs->num_bufs; i++) { |
973 | urb = dev->isoc_ctl.urb[i]; | 980 | urb = isoc_bufs->urb[i]; |
974 | if (urb) { | 981 | if (urb) { |
975 | if (!irqs_disabled()) | 982 | if (!irqs_disabled()) |
976 | usb_kill_urb(urb); | 983 | usb_kill_urb(urb); |
977 | else | 984 | else |
978 | usb_unlink_urb(urb); | 985 | usb_unlink_urb(urb); |
979 | 986 | ||
980 | if (dev->isoc_ctl.transfer_buffer[i]) { | 987 | if (isoc_bufs->transfer_buffer[i]) { |
981 | usb_free_coherent(dev->udev, | 988 | usb_free_coherent(dev->udev, |
982 | urb->transfer_buffer_length, | 989 | urb->transfer_buffer_length, |
983 | dev->isoc_ctl.transfer_buffer[i], | 990 | isoc_bufs->transfer_buffer[i], |
984 | urb->transfer_dma); | 991 | urb->transfer_dma); |
985 | } | 992 | } |
986 | usb_free_urb(urb); | 993 | usb_free_urb(urb); |
987 | dev->isoc_ctl.urb[i] = NULL; | 994 | isoc_bufs->urb[i] = NULL; |
988 | } | 995 | } |
989 | dev->isoc_ctl.transfer_buffer[i] = NULL; | 996 | isoc_bufs->transfer_buffer[i] = NULL; |
990 | } | 997 | } |
991 | 998 | ||
992 | kfree(dev->isoc_ctl.urb); | 999 | kfree(isoc_bufs->urb); |
993 | kfree(dev->isoc_ctl.transfer_buffer); | 1000 | kfree(isoc_bufs->transfer_buffer); |
994 | 1001 | ||
995 | dev->isoc_ctl.urb = NULL; | 1002 | isoc_bufs->urb = NULL; |
996 | dev->isoc_ctl.transfer_buffer = NULL; | 1003 | isoc_bufs->transfer_buffer = NULL; |
997 | dev->isoc_ctl.num_bufs = 0; | 1004 | isoc_bufs->num_bufs = 0; |
998 | 1005 | ||
999 | em28xx_capture_start(dev, 0); | 1006 | em28xx_capture_start(dev, 0); |
1000 | } | 1007 | } |
1001 | EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); | 1008 | EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); |
1002 | 1009 | ||
1003 | /* | 1010 | /* |
1004 | * Allocate URBs and start IRQ | 1011 | * Allocate URBs |
1005 | */ | 1012 | */ |
1006 | int em28xx_init_isoc(struct em28xx *dev, int max_packets, | 1013 | int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode, |
1007 | int num_bufs, int max_pkt_size, | 1014 | int max_packets, int num_bufs, int max_pkt_size) |
1008 | int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) | ||
1009 | { | 1015 | { |
1010 | struct em28xx_dmaqueue *dma_q = &dev->vidq; | 1016 | struct em28xx_usb_isoc_bufs *isoc_bufs; |
1011 | struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; | ||
1012 | int i; | 1017 | int i; |
1013 | int sb_size, pipe; | 1018 | int sb_size, pipe; |
1014 | struct urb *urb; | 1019 | struct urb *urb; |
1015 | int j, k; | 1020 | int j, k; |
1016 | int rc; | ||
1017 | 1021 | ||
1018 | em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); | 1022 | em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode); |
1023 | |||
1024 | if (mode == EM28XX_DIGITAL_MODE) | ||
1025 | isoc_bufs = &dev->isoc_ctl.digital_bufs; | ||
1026 | else | ||
1027 | isoc_bufs = &dev->isoc_ctl.analog_bufs; | ||
1019 | 1028 | ||
1020 | /* De-allocates all pending stuff */ | 1029 | /* De-allocates all pending stuff */ |
1021 | em28xx_uninit_isoc(dev); | 1030 | em28xx_uninit_isoc(dev, mode); |
1022 | 1031 | ||
1023 | dev->isoc_ctl.isoc_copy = isoc_copy; | 1032 | isoc_bufs->num_bufs = num_bufs; |
1024 | dev->isoc_ctl.num_bufs = num_bufs; | ||
1025 | 1033 | ||
1026 | dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); | 1034 | isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); |
1027 | if (!dev->isoc_ctl.urb) { | 1035 | if (!isoc_bufs->urb) { |
1028 | em28xx_errdev("cannot alloc memory for usb buffers\n"); | 1036 | em28xx_errdev("cannot alloc memory for usb buffers\n"); |
1029 | return -ENOMEM; | 1037 | return -ENOMEM; |
1030 | } | 1038 | } |
1031 | 1039 | ||
1032 | dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, | 1040 | isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs, |
1033 | GFP_KERNEL); | 1041 | GFP_KERNEL); |
1034 | if (!dev->isoc_ctl.transfer_buffer) { | 1042 | if (!isoc_bufs->transfer_buffer) { |
1035 | em28xx_errdev("cannot allocate memory for usb transfer\n"); | 1043 | em28xx_errdev("cannot allocate memory for usb transfer\n"); |
1036 | kfree(dev->isoc_ctl.urb); | 1044 | kfree(isoc_bufs->urb); |
1037 | return -ENOMEM; | 1045 | return -ENOMEM; |
1038 | } | 1046 | } |
1039 | 1047 | ||
1040 | dev->isoc_ctl.max_pkt_size = max_pkt_size; | 1048 | isoc_bufs->max_pkt_size = max_pkt_size; |
1049 | isoc_bufs->num_packets = max_packets; | ||
1041 | dev->isoc_ctl.vid_buf = NULL; | 1050 | dev->isoc_ctl.vid_buf = NULL; |
1042 | dev->isoc_ctl.vbi_buf = NULL; | 1051 | dev->isoc_ctl.vbi_buf = NULL; |
1043 | 1052 | ||
1044 | sb_size = max_packets * dev->isoc_ctl.max_pkt_size; | 1053 | sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size; |
1045 | 1054 | ||
1046 | /* allocate urbs and transfer buffers */ | 1055 | /* allocate urbs and transfer buffers */ |
1047 | for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { | 1056 | for (i = 0; i < isoc_bufs->num_bufs; i++) { |
1048 | urb = usb_alloc_urb(max_packets, GFP_KERNEL); | 1057 | urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL); |
1049 | if (!urb) { | 1058 | if (!urb) { |
1050 | em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); | 1059 | em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); |
1051 | em28xx_uninit_isoc(dev); | 1060 | em28xx_uninit_isoc(dev, mode); |
1052 | return -ENOMEM; | 1061 | return -ENOMEM; |
1053 | } | 1062 | } |
1054 | dev->isoc_ctl.urb[i] = urb; | 1063 | isoc_bufs->urb[i] = urb; |
1055 | 1064 | ||
1056 | dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, | 1065 | isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, |
1057 | sb_size, GFP_KERNEL, &urb->transfer_dma); | 1066 | sb_size, GFP_KERNEL, &urb->transfer_dma); |
1058 | if (!dev->isoc_ctl.transfer_buffer[i]) { | 1067 | if (!isoc_bufs->transfer_buffer[i]) { |
1059 | em28xx_err("unable to allocate %i bytes for transfer" | 1068 | em28xx_err("unable to allocate %i bytes for transfer" |
1060 | " buffer %i%s\n", | 1069 | " buffer %i%s\n", |
1061 | sb_size, i, | 1070 | sb_size, i, |
1062 | in_interrupt() ? " while in int" : ""); | 1071 | in_interrupt() ? " while in int" : ""); |
1063 | em28xx_uninit_isoc(dev); | 1072 | em28xx_uninit_isoc(dev, mode); |
1064 | return -ENOMEM; | 1073 | return -ENOMEM; |
1065 | } | 1074 | } |
1066 | memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); | 1075 | memset(isoc_bufs->transfer_buffer[i], 0, sb_size); |
1067 | 1076 | ||
1068 | /* FIXME: this is a hack - should be | 1077 | /* FIXME: this is a hack - should be |
1069 | 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' | 1078 | 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' |
1070 | should also be using 'desc.bInterval' | 1079 | should also be using 'desc.bInterval' |
1071 | */ | 1080 | */ |
1072 | pipe = usb_rcvisocpipe(dev->udev, | 1081 | pipe = usb_rcvisocpipe(dev->udev, |
1073 | dev->mode == EM28XX_ANALOG_MODE ? | 1082 | mode == EM28XX_ANALOG_MODE ? |
1074 | EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL); | 1083 | EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL); |
1075 | 1084 | ||
1076 | usb_fill_int_urb(urb, dev->udev, pipe, | 1085 | usb_fill_int_urb(urb, dev->udev, pipe, |
1077 | dev->isoc_ctl.transfer_buffer[i], sb_size, | 1086 | isoc_bufs->transfer_buffer[i], sb_size, |
1078 | em28xx_irq_callback, dev, 1); | 1087 | em28xx_irq_callback, dev, 1); |
1079 | 1088 | ||
1080 | urb->number_of_packets = max_packets; | 1089 | urb->number_of_packets = isoc_bufs->num_packets; |
1081 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | 1090 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; |
1082 | 1091 | ||
1083 | k = 0; | 1092 | k = 0; |
1084 | for (j = 0; j < max_packets; j++) { | 1093 | for (j = 0; j < isoc_bufs->num_packets; j++) { |
1085 | urb->iso_frame_desc[j].offset = k; | 1094 | urb->iso_frame_desc[j].offset = k; |
1086 | urb->iso_frame_desc[j].length = | 1095 | urb->iso_frame_desc[j].length = |
1087 | dev->isoc_ctl.max_pkt_size; | 1096 | isoc_bufs->max_pkt_size; |
1088 | k += dev->isoc_ctl.max_pkt_size; | 1097 | k += isoc_bufs->max_pkt_size; |
1089 | } | 1098 | } |
1090 | } | 1099 | } |
1091 | 1100 | ||
1101 | return 0; | ||
1102 | } | ||
1103 | EXPORT_SYMBOL_GPL(em28xx_alloc_isoc); | ||
1104 | |||
1105 | /* | ||
1106 | * Allocate URBs and start IRQ | ||
1107 | */ | ||
1108 | int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode, | ||
1109 | int max_packets, int num_bufs, int max_pkt_size, | ||
1110 | int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) | ||
1111 | { | ||
1112 | struct em28xx_dmaqueue *dma_q = &dev->vidq; | ||
1113 | struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; | ||
1114 | struct em28xx_usb_isoc_bufs *isoc_bufs; | ||
1115 | int i; | ||
1116 | int rc; | ||
1117 | int alloc; | ||
1118 | |||
1119 | em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode); | ||
1120 | |||
1121 | dev->isoc_ctl.isoc_copy = isoc_copy; | ||
1122 | |||
1123 | if (mode == EM28XX_DIGITAL_MODE) { | ||
1124 | isoc_bufs = &dev->isoc_ctl.digital_bufs; | ||
1125 | /* no need to free/alloc isoc buffers in digital mode */ | ||
1126 | alloc = 0; | ||
1127 | } else { | ||
1128 | isoc_bufs = &dev->isoc_ctl.analog_bufs; | ||
1129 | alloc = 1; | ||
1130 | } | ||
1131 | |||
1132 | if (alloc) { | ||
1133 | rc = em28xx_alloc_isoc(dev, mode, max_packets, | ||
1134 | num_bufs, max_pkt_size); | ||
1135 | if (rc) | ||
1136 | return rc; | ||
1137 | } | ||
1138 | |||
1092 | init_waitqueue_head(&dma_q->wq); | 1139 | init_waitqueue_head(&dma_q->wq); |
1093 | init_waitqueue_head(&vbi_dma_q->wq); | 1140 | init_waitqueue_head(&vbi_dma_q->wq); |
1094 | 1141 | ||
1095 | em28xx_capture_start(dev, 1); | 1142 | em28xx_capture_start(dev, 1); |
1096 | 1143 | ||
1097 | /* submit urbs and enables IRQ */ | 1144 | /* submit urbs and enables IRQ */ |
1098 | for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { | 1145 | for (i = 0; i < isoc_bufs->num_bufs; i++) { |
1099 | rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); | 1146 | rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC); |
1100 | if (rc) { | 1147 | if (rc) { |
1101 | em28xx_err("submit of urb %i failed (error=%i)\n", i, | 1148 | em28xx_err("submit of urb %i failed (error=%i)\n", i, |
1102 | rc); | 1149 | rc); |
1103 | em28xx_uninit_isoc(dev); | 1150 | em28xx_uninit_isoc(dev, mode); |
1104 | return rc; | 1151 | return rc; |
1105 | } | 1152 | } |
1106 | } | 1153 | } |
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index aabbf4854f66..503a8d5b5382 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c | |||
@@ -61,9 +61,6 @@ if (debug >= level) \ | |||
61 | printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ | 61 | printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ |
62 | } while (0) | 62 | } while (0) |
63 | 63 | ||
64 | #define EM28XX_DVB_NUM_BUFS 5 | ||
65 | #define EM28XX_DVB_MAX_PACKETS 64 | ||
66 | |||
67 | struct em28xx_dvb { | 64 | struct em28xx_dvb { |
68 | struct dvb_frontend *fe[2]; | 65 | struct dvb_frontend *fe[2]; |
69 | 66 | ||
@@ -172,20 +169,21 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) | |||
172 | max_dvb_packet_size = dev->dvb_max_pkt_size; | 169 | max_dvb_packet_size = dev->dvb_max_pkt_size; |
173 | if (max_dvb_packet_size < 0) | 170 | if (max_dvb_packet_size < 0) |
174 | return max_dvb_packet_size; | 171 | return max_dvb_packet_size; |
175 | dprintk(1, "Using %d buffers each with %d bytes\n", | 172 | dprintk(1, "Using %d buffers each with %d x %d bytes\n", |
176 | EM28XX_DVB_NUM_BUFS, | 173 | EM28XX_DVB_NUM_BUFS, |
174 | EM28XX_DVB_MAX_PACKETS, | ||
177 | max_dvb_packet_size); | 175 | max_dvb_packet_size); |
178 | 176 | ||
179 | return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, | 177 | return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE, |
180 | EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, | 178 | EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS, |
181 | em28xx_dvb_isoc_copy); | 179 | max_dvb_packet_size, em28xx_dvb_isoc_copy); |
182 | } | 180 | } |
183 | 181 | ||
184 | static int em28xx_stop_streaming(struct em28xx_dvb *dvb) | 182 | static int em28xx_stop_streaming(struct em28xx_dvb *dvb) |
185 | { | 183 | { |
186 | struct em28xx *dev = dvb->adapter.priv; | 184 | struct em28xx *dev = dvb->adapter.priv; |
187 | 185 | ||
188 | em28xx_uninit_isoc(dev); | 186 | em28xx_capture_start(dev, 0); |
189 | 187 | ||
190 | em28xx_set_mode(dev, EM28XX_SUSPEND); | 188 | em28xx_set_mode(dev, EM28XX_SUSPEND); |
191 | 189 | ||
@@ -327,6 +325,19 @@ struct drxk_config hauppauge_930c_drxk = { | |||
327 | .chunk_size = 56, | 325 | .chunk_size = 56, |
328 | }; | 326 | }; |
329 | 327 | ||
328 | struct drxk_config maxmedia_ub425_tc_drxk = { | ||
329 | .adr = 0x29, | ||
330 | .single_master = 1, | ||
331 | .no_i2c_bridge = 1, | ||
332 | }; | ||
333 | |||
334 | struct drxk_config pctv_520e_drxk = { | ||
335 | .adr = 0x29, | ||
336 | .single_master = 1, | ||
337 | .microcode_name = "dvb-demod-drxk-pctv.fw", | ||
338 | .chunk_size = 58, | ||
339 | }; | ||
340 | |||
330 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) | 341 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) |
331 | { | 342 | { |
332 | struct em28xx_dvb *dvb = fe->sec_priv; | 343 | struct em28xx_dvb *dvb = fe->sec_priv; |
@@ -460,6 +471,33 @@ static void terratec_h5_init(struct em28xx *dev) | |||
460 | em28xx_gpio_set(dev, terratec_h5_end); | 471 | em28xx_gpio_set(dev, terratec_h5_end); |
461 | }; | 472 | }; |
462 | 473 | ||
474 | static void pctv_520e_init(struct em28xx *dev) | ||
475 | { | ||
476 | /* | ||
477 | * Init TDA8295(?) analog demodulator. Looks like I2C traffic to | ||
478 | * digital demodulator and tuner are routed via TDA8295. | ||
479 | */ | ||
480 | int i; | ||
481 | struct { | ||
482 | unsigned char r[4]; | ||
483 | int len; | ||
484 | } regs[] = { | ||
485 | {{ 0x06, 0x02, 0x00, 0x31 }, 4}, | ||
486 | {{ 0x01, 0x02 }, 2}, | ||
487 | {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, | ||
488 | {{ 0x01, 0x00 }, 2}, | ||
489 | {{ 0x01, 0x00, 0xff, 0xaf }, 4}, | ||
490 | {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, | ||
491 | {{ 0x01, 0x00 }, 2}, | ||
492 | {{ 0x01, 0x00, 0x73, 0xaf }, 4}, | ||
493 | }; | ||
494 | |||
495 | dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */ | ||
496 | |||
497 | for (i = 0; i < ARRAY_SIZE(regs); i++) | ||
498 | i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); | ||
499 | }; | ||
500 | |||
463 | static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) | 501 | static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) |
464 | { | 502 | { |
465 | /* Values extracted from a USB trace of the Terratec Windows driver */ | 503 | /* Values extracted from a USB trace of the Terratec Windows driver */ |
@@ -938,6 +976,48 @@ static int em28xx_dvb_init(struct em28xx *dev) | |||
938 | dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, | 976 | dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, |
939 | &em28xx_a8293_config); | 977 | &em28xx_a8293_config); |
940 | break; | 978 | break; |
979 | case EM2874_BOARD_MAXMEDIA_UB425_TC: | ||
980 | /* attach demodulator */ | ||
981 | dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk, | ||
982 | &dev->i2c_adap); | ||
983 | |||
984 | if (dvb->fe[0]) { | ||
985 | /* disable I2C-gate */ | ||
986 | dvb->fe[0]->ops.i2c_gate_ctrl = NULL; | ||
987 | |||
988 | /* attach tuner */ | ||
989 | if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], | ||
990 | &dev->i2c_adap, 0x60)) { | ||
991 | dvb_frontend_detach(dvb->fe[0]); | ||
992 | result = -EINVAL; | ||
993 | goto out_free; | ||
994 | } | ||
995 | } | ||
996 | |||
997 | /* TODO: we need drx-3913k firmware in order to support DVB-T */ | ||
998 | em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \ | ||
999 | "driver version\n"); | ||
1000 | |||
1001 | break; | ||
1002 | case EM2884_BOARD_PCTV_510E: | ||
1003 | case EM2884_BOARD_PCTV_520E: | ||
1004 | pctv_520e_init(dev); | ||
1005 | |||
1006 | /* attach demodulator */ | ||
1007 | dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk, | ||
1008 | &dev->i2c_adap); | ||
1009 | |||
1010 | if (dvb->fe[0]) { | ||
1011 | /* attach tuner */ | ||
1012 | if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, | ||
1013 | &dev->i2c_adap, | ||
1014 | &em28xx_cxd2820r_tda18271_config)) { | ||
1015 | dvb_frontend_detach(dvb->fe[0]); | ||
1016 | result = -EINVAL; | ||
1017 | goto out_free; | ||
1018 | } | ||
1019 | } | ||
1020 | break; | ||
941 | default: | 1021 | default: |
942 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" | 1022 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" |
943 | " isn't supported yet\n"); | 1023 | " isn't supported yet\n"); |
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 36f5a9bc8b76..a88e169dba23 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c | |||
@@ -41,14 +41,6 @@ static unsigned int i2c_debug; | |||
41 | module_param(i2c_debug, int, 0644); | 41 | module_param(i2c_debug, int, 0644); |
42 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | 42 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); |
43 | 43 | ||
44 | |||
45 | #define dprintk1(lvl, fmt, args...) \ | ||
46 | do { \ | ||
47 | if (i2c_debug >= lvl) { \ | ||
48 | printk(fmt, ##args); \ | ||
49 | } \ | ||
50 | } while (0) | ||
51 | |||
52 | #define dprintk2(lvl, fmt, args...) \ | 44 | #define dprintk2(lvl, fmt, args...) \ |
53 | do { \ | 45 | do { \ |
54 | if (i2c_debug >= lvl) { \ | 46 | if (i2c_debug >= lvl) { \ |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 613300b51a9e..324b695c0724 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -760,17 +760,19 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |||
760 | goto fail; | 760 | goto fail; |
761 | } | 761 | } |
762 | 762 | ||
763 | if (!dev->isoc_ctl.num_bufs) | 763 | if (!dev->isoc_ctl.analog_bufs.num_bufs) |
764 | urb_init = 1; | 764 | urb_init = 1; |
765 | 765 | ||
766 | if (urb_init) { | 766 | if (urb_init) { |
767 | if (em28xx_vbi_supported(dev) == 1) | 767 | if (em28xx_vbi_supported(dev) == 1) |
768 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, | 768 | rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE, |
769 | EM28XX_NUM_PACKETS, | ||
769 | EM28XX_NUM_BUFS, | 770 | EM28XX_NUM_BUFS, |
770 | dev->max_pkt_size, | 771 | dev->max_pkt_size, |
771 | em28xx_isoc_copy_vbi); | 772 | em28xx_isoc_copy_vbi); |
772 | else | 773 | else |
773 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, | 774 | rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE, |
775 | EM28XX_NUM_PACKETS, | ||
774 | EM28XX_NUM_BUFS, | 776 | EM28XX_NUM_BUFS, |
775 | dev->max_pkt_size, | 777 | dev->max_pkt_size, |
776 | em28xx_isoc_copy); | 778 | em28xx_isoc_copy); |
@@ -2267,7 +2269,7 @@ static int em28xx_v4l2_close(struct file *filp) | |||
2267 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); | 2269 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); |
2268 | 2270 | ||
2269 | /* do this before setting alternate! */ | 2271 | /* do this before setting alternate! */ |
2270 | em28xx_uninit_isoc(dev); | 2272 | em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE); |
2271 | em28xx_set_mode(dev, EM28XX_SUSPEND); | 2273 | em28xx_set_mode(dev, EM28XX_SUSPEND); |
2272 | 2274 | ||
2273 | /* set alternate 0 */ | 2275 | /* set alternate 0 */ |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 22e252bcc41e..2868b19f8b54 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -125,6 +125,9 @@ | |||
125 | #define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81 | 125 | #define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81 |
126 | #define EM2884_BOARD_CINERGY_HTC_STICK 82 | 126 | #define EM2884_BOARD_CINERGY_HTC_STICK 82 |
127 | #define EM2860_BOARD_HT_VIDBOX_NW03 83 | 127 | #define EM2860_BOARD_HT_VIDBOX_NW03 83 |
128 | #define EM2874_BOARD_MAXMEDIA_UB425_TC 84 | ||
129 | #define EM2884_BOARD_PCTV_510E 85 | ||
130 | #define EM2884_BOARD_PCTV_520E 86 | ||
128 | 131 | ||
129 | /* Limits minimum and default number of buffers */ | 132 | /* Limits minimum and default number of buffers */ |
130 | #define EM28XX_MIN_BUF 4 | 133 | #define EM28XX_MIN_BUF 4 |
@@ -151,12 +154,14 @@ | |||
151 | 154 | ||
152 | /* number of buffers for isoc transfers */ | 155 | /* number of buffers for isoc transfers */ |
153 | #define EM28XX_NUM_BUFS 5 | 156 | #define EM28XX_NUM_BUFS 5 |
157 | #define EM28XX_DVB_NUM_BUFS 5 | ||
154 | 158 | ||
155 | /* number of packets for each buffer | 159 | /* number of packets for each buffer |
156 | windows requests only 64 packets .. so we better do the same | 160 | windows requests only 64 packets .. so we better do the same |
157 | this is what I found out for all alternate numbers there! | 161 | this is what I found out for all alternate numbers there! |
158 | */ | 162 | */ |
159 | #define EM28XX_NUM_PACKETS 64 | 163 | #define EM28XX_NUM_PACKETS 64 |
164 | #define EM28XX_DVB_MAX_PACKETS 64 | ||
160 | 165 | ||
161 | #define EM28XX_INTERLACED_DEFAULT 1 | 166 | #define EM28XX_INTERLACED_DEFAULT 1 |
162 | 167 | ||
@@ -197,10 +202,13 @@ enum em28xx_mode { | |||
197 | 202 | ||
198 | struct em28xx; | 203 | struct em28xx; |
199 | 204 | ||
200 | struct em28xx_usb_isoc_ctl { | 205 | struct em28xx_usb_isoc_bufs { |
201 | /* max packet size of isoc transaction */ | 206 | /* max packet size of isoc transaction */ |
202 | int max_pkt_size; | 207 | int max_pkt_size; |
203 | 208 | ||
209 | /* number of packets in each buffer */ | ||
210 | int num_packets; | ||
211 | |||
204 | /* number of allocated urbs */ | 212 | /* number of allocated urbs */ |
205 | int num_bufs; | 213 | int num_bufs; |
206 | 214 | ||
@@ -209,6 +217,14 @@ struct em28xx_usb_isoc_ctl { | |||
209 | 217 | ||
210 | /* transfer buffers for isoc transfer */ | 218 | /* transfer buffers for isoc transfer */ |
211 | char **transfer_buffer; | 219 | char **transfer_buffer; |
220 | }; | ||
221 | |||
222 | struct em28xx_usb_isoc_ctl { | ||
223 | /* isoc transfer buffers for analog mode */ | ||
224 | struct em28xx_usb_isoc_bufs analog_bufs; | ||
225 | |||
226 | /* isoc transfer buffers for digital mode */ | ||
227 | struct em28xx_usb_isoc_bufs digital_bufs; | ||
212 | 228 | ||
213 | /* Last buffer command and region */ | 229 | /* Last buffer command and region */ |
214 | u8 cmd; | 230 | u8 cmd; |
@@ -600,9 +616,6 @@ struct em28xx { | |||
600 | unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ | 616 | unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ |
601 | int dvb_alt; /* alternate for DVB */ | 617 | int dvb_alt; /* alternate for DVB */ |
602 | unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */ | 618 | unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */ |
603 | struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ | ||
604 | char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc | ||
605 | transfer */ | ||
606 | char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ | 619 | char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ |
607 | 620 | ||
608 | /* helper funcs that call usb_control_msg */ | 621 | /* helper funcs that call usb_control_msg */ |
@@ -676,10 +689,12 @@ int em28xx_vbi_supported(struct em28xx *dev); | |||
676 | int em28xx_set_outfmt(struct em28xx *dev); | 689 | int em28xx_set_outfmt(struct em28xx *dev); |
677 | int em28xx_resolution_set(struct em28xx *dev); | 690 | int em28xx_resolution_set(struct em28xx *dev); |
678 | int em28xx_set_alternate(struct em28xx *dev); | 691 | int em28xx_set_alternate(struct em28xx *dev); |
679 | int em28xx_init_isoc(struct em28xx *dev, int max_packets, | 692 | int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode, |
680 | int num_bufs, int max_pkt_size, | 693 | int max_packets, int num_bufs, int max_pkt_size); |
694 | int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode, | ||
695 | int max_packets, int num_bufs, int max_pkt_size, | ||
681 | int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); | 696 | int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); |
682 | void em28xx_uninit_isoc(struct em28xx *dev); | 697 | void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode); |
683 | int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); | 698 | int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); |
684 | int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); | 699 | int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); |
685 | int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); | 700 | int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); |
diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile index f511eccdfd9c..773ea3426561 100644 --- a/drivers/media/video/gspca/gl860/Makefile +++ b/drivers/media/video/gspca/gl860/Makefile | |||
@@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \ | |||
6 | gl860-ov9655.o \ | 6 | gl860-ov9655.o \ |
7 | gl860-mi2020.o | 7 | gl860-mi2020.o |
8 | 8 | ||
9 | ccflags-y += -Idrivers/media/video/gspca | 9 | ccflags-y += -I$(srctree)/drivers/media/video/gspca |
10 | 10 | ||
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile index 7f52961f439c..575b75bacb62 100644 --- a/drivers/media/video/gspca/m5602/Makefile +++ b/drivers/media/video/gspca/m5602/Makefile | |||
@@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \ | |||
8 | m5602_s5k83a.o \ | 8 | m5602_s5k83a.o \ |
9 | m5602_s5k4aa.o | 9 | m5602_s5k4aa.o |
10 | 10 | ||
11 | ccflags-y += -Idrivers/media/video/gspca | 11 | ccflags-y += -I$(srctree)/drivers/media/video/gspca |
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index fbfa02affa13..e6601b886032 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c | |||
@@ -1107,16 +1107,34 @@ static void setbrightness(struct gspca_dev *gspca_dev) | |||
1107 | { | 1107 | { |
1108 | struct sd *sd = (struct sd *) gspca_dev; | 1108 | struct sd *sd = (struct sd *) gspca_dev; |
1109 | u8 val; | 1109 | u8 val; |
1110 | s8 sval; | ||
1110 | 1111 | ||
1111 | if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) | 1112 | if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) |
1112 | return; | 1113 | return; |
1113 | val = sd->ctrls[BRIGHTNESS].val; | 1114 | if (sd->sensor == SENSOR_OV562x) { |
1114 | if (val < 8) | 1115 | sval = sd->ctrls[BRIGHTNESS].val; |
1115 | val = 15 - val; /* f .. 8 */ | 1116 | val = 0x76; |
1116 | else | 1117 | val += sval; |
1117 | val = val - 8; /* 0 .. 7 */ | 1118 | sccb_write(gspca_dev, 0x24, val); |
1118 | sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ | 1119 | val = 0x6a; |
1119 | 0x0f | (val << 4)); | 1120 | val += sval; |
1121 | sccb_write(gspca_dev, 0x25, val); | ||
1122 | if (sval < -40) | ||
1123 | val = 0x71; | ||
1124 | else if (sval < 20) | ||
1125 | val = 0x94; | ||
1126 | else | ||
1127 | val = 0xe6; | ||
1128 | sccb_write(gspca_dev, 0x26, val); | ||
1129 | } else { | ||
1130 | val = sd->ctrls[BRIGHTNESS].val; | ||
1131 | if (val < 8) | ||
1132 | val = 15 - val; /* f .. 8 */ | ||
1133 | else | ||
1134 | val = val - 8; /* 0 .. 7 */ | ||
1135 | sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ | ||
1136 | 0x0f | (val << 4)); | ||
1137 | } | ||
1120 | } | 1138 | } |
1121 | 1139 | ||
1122 | static void setcontrast(struct gspca_dev *gspca_dev) | 1140 | static void setcontrast(struct gspca_dev *gspca_dev) |
@@ -1339,7 +1357,16 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
1339 | reg_w(gspca_dev, 0x56, 0x17); | 1357 | reg_w(gspca_dev, 0x56, 0x17); |
1340 | } else if ((sensor_id & 0xfff0) == 0x5620) { | 1358 | } else if ((sensor_id & 0xfff0) == 0x5620) { |
1341 | sd->sensor = SENSOR_OV562x; | 1359 | sd->sensor = SENSOR_OV562x; |
1342 | 1360 | gspca_dev->ctrl_dis = (1 << CONTRAST) | | |
1361 | (1 << AUTOGAIN) | | ||
1362 | (1 << EXPOSURE) | | ||
1363 | (1 << SHARPNESS) | | ||
1364 | (1 << SATUR) | | ||
1365 | (1 << LIGHTFREQ); | ||
1366 | |||
1367 | sd->ctrls[BRIGHTNESS].min = -90; | ||
1368 | sd->ctrls[BRIGHTNESS].max = 90; | ||
1369 | sd->ctrls[BRIGHTNESS].def = 0; | ||
1343 | gspca_dev->cam.cam_mode = ov562x_mode; | 1370 | gspca_dev->cam.cam_mode = ov562x_mode; |
1344 | gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode); | 1371 | gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode); |
1345 | 1372 | ||
@@ -1360,8 +1387,12 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
1360 | { | 1387 | { |
1361 | struct sd *sd = (struct sd *) gspca_dev; | 1388 | struct sd *sd = (struct sd *) gspca_dev; |
1362 | 1389 | ||
1363 | if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x) | 1390 | if (sd->sensor == SENSOR_OV971x) |
1364 | return gspca_dev->usb_err; | 1391 | return gspca_dev->usb_err; |
1392 | else if (sd->sensor == SENSOR_OV562x) { | ||
1393 | setbrightness(gspca_dev); | ||
1394 | return gspca_dev->usb_err; | ||
1395 | } | ||
1365 | switch (gspca_dev->curr_mode) { | 1396 | switch (gspca_dev->curr_mode) { |
1366 | case QVGA_MODE: /* 320x240 */ | 1397 | case QVGA_MODE: /* 320x240 */ |
1367 | sccb_w_array(gspca_dev, ov965x_start_1_vga, | 1398 | sccb_w_array(gspca_dev, ov965x_start_1_vga, |
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 9db2b34d172c..30662fccb0cf 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Pixart PAC7302 library | 2 | * Pixart PAC7302 driver |
3 | * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li | ||
4 | * | 3 | * |
5 | * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> | 4 | * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr> |
5 | * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li | ||
6 | * | 6 | * |
7 | * Separated from Pixart PAC7311 library by Márton Németh | 7 | * Separated from Pixart PAC7311 library by Márton Németh |
8 | * Camera button input handling by Márton Németh <nm127@freemail.hu> | 8 | * Camera button input handling by Márton Németh <nm127@freemail.hu> |
@@ -63,67 +63,61 @@ | |||
63 | 63 | ||
64 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 64 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
65 | 65 | ||
66 | #define MODULE_NAME "pac7302" | ||
67 | |||
68 | #include <linux/input.h> | 66 | #include <linux/input.h> |
69 | #include <media/v4l2-chip-ident.h> | 67 | #include <media/v4l2-chip-ident.h> |
70 | #include "gspca.h" | 68 | #include "gspca.h" |
69 | /* Include pac common sof detection functions */ | ||
70 | #include "pac_common.h" | ||
71 | 71 | ||
72 | MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); | 72 | MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, " |
73 | "Thomas Kaiser thomas@kaiser-linux.li"); | ||
73 | MODULE_DESCRIPTION("Pixart PAC7302"); | 74 | MODULE_DESCRIPTION("Pixart PAC7302"); |
74 | MODULE_LICENSE("GPL"); | 75 | MODULE_LICENSE("GPL"); |
75 | 76 | ||
77 | enum e_ctrl { | ||
78 | BRIGHTNESS, | ||
79 | CONTRAST, | ||
80 | COLORS, | ||
81 | WHITE_BALANCE, | ||
82 | RED_BALANCE, | ||
83 | BLUE_BALANCE, | ||
84 | GAIN, | ||
85 | AUTOGAIN, | ||
86 | EXPOSURE, | ||
87 | VFLIP, | ||
88 | HFLIP, | ||
89 | NCTRLS /* number of controls */ | ||
90 | }; | ||
91 | |||
76 | /* specific webcam descriptor for pac7302 */ | 92 | /* specific webcam descriptor for pac7302 */ |
77 | struct sd { | 93 | struct sd { |
78 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 94 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
79 | 95 | ||
80 | unsigned char brightness; | 96 | struct gspca_ctrl ctrls[NCTRLS]; |
81 | unsigned char contrast; | 97 | |
82 | unsigned char colors; | ||
83 | unsigned char white_balance; | ||
84 | unsigned char red_balance; | ||
85 | unsigned char blue_balance; | ||
86 | unsigned char gain; | ||
87 | unsigned char autogain; | ||
88 | unsigned short exposure; | ||
89 | __u8 hflip; | ||
90 | __u8 vflip; | ||
91 | u8 flags; | 98 | u8 flags; |
92 | #define FL_HFLIP 0x01 /* mirrored by default */ | 99 | #define FL_HFLIP 0x01 /* mirrored by default */ |
93 | #define FL_VFLIP 0x02 /* vertical flipped by default */ | 100 | #define FL_VFLIP 0x02 /* vertical flipped by default */ |
94 | 101 | ||
95 | u8 sof_read; | 102 | u8 sof_read; |
96 | u8 autogain_ignore_frames; | 103 | s8 autogain_ignore_frames; |
97 | 104 | ||
98 | atomic_t avg_lum; | 105 | atomic_t avg_lum; |
99 | }; | 106 | }; |
100 | 107 | ||
101 | /* V4L2 controls supported by the driver */ | 108 | /* V4L2 controls supported by the driver */ |
102 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); | 109 | static void setbrightcont(struct gspca_dev *gspca_dev); |
103 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); | 110 | static void setcolors(struct gspca_dev *gspca_dev); |
104 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); | 111 | static void setwhitebalance(struct gspca_dev *gspca_dev); |
105 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); | 112 | static void setredbalance(struct gspca_dev *gspca_dev); |
106 | static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); | 113 | static void setbluebalance(struct gspca_dev *gspca_dev); |
107 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); | 114 | static void setgain(struct gspca_dev *gspca_dev); |
108 | static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); | 115 | static void setexposure(struct gspca_dev *gspca_dev); |
109 | static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); | 116 | static void setautogain(struct gspca_dev *gspca_dev); |
110 | static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val); | 117 | static void sethvflip(struct gspca_dev *gspca_dev); |
111 | static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val); | ||
112 | static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val); | ||
113 | static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val); | ||
114 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); | ||
115 | static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); | ||
116 | static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); | ||
117 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
118 | static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); | ||
119 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
120 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); | ||
121 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); | ||
122 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); | ||
123 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
124 | 118 | ||
125 | static const struct ctrl sd_ctrls[] = { | 119 | static const struct ctrl sd_ctrls[] = { |
126 | { | 120 | [BRIGHTNESS] = { |
127 | { | 121 | { |
128 | .id = V4L2_CID_BRIGHTNESS, | 122 | .id = V4L2_CID_BRIGHTNESS, |
129 | .type = V4L2_CTRL_TYPE_INTEGER, | 123 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -132,13 +126,11 @@ static const struct ctrl sd_ctrls[] = { | |||
132 | #define BRIGHTNESS_MAX 0x20 | 126 | #define BRIGHTNESS_MAX 0x20 |
133 | .maximum = BRIGHTNESS_MAX, | 127 | .maximum = BRIGHTNESS_MAX, |
134 | .step = 1, | 128 | .step = 1, |
135 | #define BRIGHTNESS_DEF 0x10 | 129 | .default_value = 0x10, |
136 | .default_value = BRIGHTNESS_DEF, | ||
137 | }, | 130 | }, |
138 | .set = sd_setbrightness, | 131 | .set_control = setbrightcont |
139 | .get = sd_getbrightness, | ||
140 | }, | 132 | }, |
141 | { | 133 | [CONTRAST] = { |
142 | { | 134 | { |
143 | .id = V4L2_CID_CONTRAST, | 135 | .id = V4L2_CID_CONTRAST, |
144 | .type = V4L2_CTRL_TYPE_INTEGER, | 136 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -147,13 +139,11 @@ static const struct ctrl sd_ctrls[] = { | |||
147 | #define CONTRAST_MAX 255 | 139 | #define CONTRAST_MAX 255 |
148 | .maximum = CONTRAST_MAX, | 140 | .maximum = CONTRAST_MAX, |
149 | .step = 1, | 141 | .step = 1, |
150 | #define CONTRAST_DEF 127 | 142 | .default_value = 127, |
151 | .default_value = CONTRAST_DEF, | ||
152 | }, | 143 | }, |
153 | .set = sd_setcontrast, | 144 | .set_control = setbrightcont |
154 | .get = sd_getcontrast, | ||
155 | }, | 145 | }, |
156 | { | 146 | [COLORS] = { |
157 | { | 147 | { |
158 | .id = V4L2_CID_SATURATION, | 148 | .id = V4L2_CID_SATURATION, |
159 | .type = V4L2_CTRL_TYPE_INTEGER, | 149 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -162,13 +152,11 @@ static const struct ctrl sd_ctrls[] = { | |||
162 | #define COLOR_MAX 255 | 152 | #define COLOR_MAX 255 |
163 | .maximum = COLOR_MAX, | 153 | .maximum = COLOR_MAX, |
164 | .step = 1, | 154 | .step = 1, |
165 | #define COLOR_DEF 127 | 155 | .default_value = 127 |
166 | .default_value = COLOR_DEF, | ||
167 | }, | 156 | }, |
168 | .set = sd_setcolors, | 157 | .set_control = setcolors |
169 | .get = sd_getcolors, | ||
170 | }, | 158 | }, |
171 | { | 159 | [WHITE_BALANCE] = { |
172 | { | 160 | { |
173 | .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, | 161 | .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, |
174 | .type = V4L2_CTRL_TYPE_INTEGER, | 162 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -176,13 +164,11 @@ static const struct ctrl sd_ctrls[] = { | |||
176 | .minimum = 0, | 164 | .minimum = 0, |
177 | .maximum = 255, | 165 | .maximum = 255, |
178 | .step = 1, | 166 | .step = 1, |
179 | #define WHITEBALANCE_DEF 4 | 167 | .default_value = 4, |
180 | .default_value = WHITEBALANCE_DEF, | ||
181 | }, | 168 | }, |
182 | .set = sd_setwhitebalance, | 169 | .set_control = setwhitebalance |
183 | .get = sd_getwhitebalance, | ||
184 | }, | 170 | }, |
185 | { | 171 | [RED_BALANCE] = { |
186 | { | 172 | { |
187 | .id = V4L2_CID_RED_BALANCE, | 173 | .id = V4L2_CID_RED_BALANCE, |
188 | .type = V4L2_CTRL_TYPE_INTEGER, | 174 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -190,13 +176,11 @@ static const struct ctrl sd_ctrls[] = { | |||
190 | .minimum = 0, | 176 | .minimum = 0, |
191 | .maximum = 3, | 177 | .maximum = 3, |
192 | .step = 1, | 178 | .step = 1, |
193 | #define REDBALANCE_DEF 1 | 179 | .default_value = 1, |
194 | .default_value = REDBALANCE_DEF, | ||
195 | }, | 180 | }, |
196 | .set = sd_setredbalance, | 181 | .set_control = setredbalance |
197 | .get = sd_getredbalance, | ||
198 | }, | 182 | }, |
199 | { | 183 | [BLUE_BALANCE] = { |
200 | { | 184 | { |
201 | .id = V4L2_CID_BLUE_BALANCE, | 185 | .id = V4L2_CID_BLUE_BALANCE, |
202 | .type = V4L2_CTRL_TYPE_INTEGER, | 186 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -204,29 +188,25 @@ static const struct ctrl sd_ctrls[] = { | |||
204 | .minimum = 0, | 188 | .minimum = 0, |
205 | .maximum = 3, | 189 | .maximum = 3, |
206 | .step = 1, | 190 | .step = 1, |
207 | #define BLUEBALANCE_DEF 1 | 191 | .default_value = 1, |
208 | .default_value = BLUEBALANCE_DEF, | ||
209 | }, | 192 | }, |
210 | .set = sd_setbluebalance, | 193 | .set_control = setbluebalance |
211 | .get = sd_getbluebalance, | ||
212 | }, | 194 | }, |
213 | { | 195 | [GAIN] = { |
214 | { | 196 | { |
215 | .id = V4L2_CID_GAIN, | 197 | .id = V4L2_CID_GAIN, |
216 | .type = V4L2_CTRL_TYPE_INTEGER, | 198 | .type = V4L2_CTRL_TYPE_INTEGER, |
217 | .name = "Gain", | 199 | .name = "Gain", |
218 | .minimum = 0, | 200 | .minimum = 0, |
219 | #define GAIN_MAX 255 | 201 | .maximum = 255, |
220 | .maximum = GAIN_MAX, | ||
221 | .step = 1, | 202 | .step = 1, |
222 | #define GAIN_DEF 127 | 203 | #define GAIN_DEF 127 |
223 | #define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ | 204 | #define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ |
224 | .default_value = GAIN_DEF, | 205 | .default_value = GAIN_DEF, |
225 | }, | 206 | }, |
226 | .set = sd_setgain, | 207 | .set_control = setgain |
227 | .get = sd_getgain, | ||
228 | }, | 208 | }, |
229 | { | 209 | [EXPOSURE] = { |
230 | { | 210 | { |
231 | .id = V4L2_CID_EXPOSURE, | 211 | .id = V4L2_CID_EXPOSURE, |
232 | .type = V4L2_CTRL_TYPE_INTEGER, | 212 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -238,10 +218,9 @@ static const struct ctrl sd_ctrls[] = { | |||
238 | #define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ | 218 | #define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ |
239 | .default_value = EXPOSURE_DEF, | 219 | .default_value = EXPOSURE_DEF, |
240 | }, | 220 | }, |
241 | .set = sd_setexposure, | 221 | .set_control = setexposure |
242 | .get = sd_getexposure, | ||
243 | }, | 222 | }, |
244 | { | 223 | [AUTOGAIN] = { |
245 | { | 224 | { |
246 | .id = V4L2_CID_AUTOGAIN, | 225 | .id = V4L2_CID_AUTOGAIN, |
247 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 226 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
@@ -252,10 +231,9 @@ static const struct ctrl sd_ctrls[] = { | |||
252 | #define AUTOGAIN_DEF 1 | 231 | #define AUTOGAIN_DEF 1 |
253 | .default_value = AUTOGAIN_DEF, | 232 | .default_value = AUTOGAIN_DEF, |
254 | }, | 233 | }, |
255 | .set = sd_setautogain, | 234 | .set_control = setautogain, |
256 | .get = sd_getautogain, | ||
257 | }, | 235 | }, |
258 | { | 236 | [HFLIP] = { |
259 | { | 237 | { |
260 | .id = V4L2_CID_HFLIP, | 238 | .id = V4L2_CID_HFLIP, |
261 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 239 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
@@ -263,13 +241,11 @@ static const struct ctrl sd_ctrls[] = { | |||
263 | .minimum = 0, | 241 | .minimum = 0, |
264 | .maximum = 1, | 242 | .maximum = 1, |
265 | .step = 1, | 243 | .step = 1, |
266 | #define HFLIP_DEF 0 | 244 | .default_value = 0, |
267 | .default_value = HFLIP_DEF, | ||
268 | }, | 245 | }, |
269 | .set = sd_sethflip, | 246 | .set_control = sethvflip, |
270 | .get = sd_gethflip, | ||
271 | }, | 247 | }, |
272 | { | 248 | [VFLIP] = { |
273 | { | 249 | { |
274 | .id = V4L2_CID_VFLIP, | 250 | .id = V4L2_CID_VFLIP, |
275 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 251 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
@@ -277,11 +253,9 @@ static const struct ctrl sd_ctrls[] = { | |||
277 | .minimum = 0, | 253 | .minimum = 0, |
278 | .maximum = 1, | 254 | .maximum = 1, |
279 | .step = 1, | 255 | .step = 1, |
280 | #define VFLIP_DEF 0 | 256 | .default_value = 0, |
281 | .default_value = VFLIP_DEF, | ||
282 | }, | 257 | }, |
283 | .set = sd_setvflip, | 258 | .set_control = sethvflip |
284 | .get = sd_getvflip, | ||
285 | }, | 259 | }, |
286 | }; | 260 | }; |
287 | 261 | ||
@@ -290,21 +264,21 @@ static const struct v4l2_pix_format vga_mode[] = { | |||
290 | .bytesperline = 640, | 264 | .bytesperline = 640, |
291 | .sizeimage = 640 * 480 * 3 / 8 + 590, | 265 | .sizeimage = 640 * 480 * 3 / 8 + 590, |
292 | .colorspace = V4L2_COLORSPACE_JPEG, | 266 | .colorspace = V4L2_COLORSPACE_JPEG, |
293 | .priv = 0}, | 267 | }, |
294 | }; | 268 | }; |
295 | 269 | ||
296 | #define LOAD_PAGE3 255 | 270 | #define LOAD_PAGE3 255 |
297 | #define END_OF_SEQUENCE 0 | 271 | #define END_OF_SEQUENCE 0 |
298 | 272 | ||
299 | /* pac 7302 */ | 273 | /* pac 7302 */ |
300 | static const __u8 init_7302[] = { | 274 | static const u8 init_7302[] = { |
301 | /* index,value */ | 275 | /* index,value */ |
302 | 0xff, 0x01, /* page 1 */ | 276 | 0xff, 0x01, /* page 1 */ |
303 | 0x78, 0x00, /* deactivate */ | 277 | 0x78, 0x00, /* deactivate */ |
304 | 0xff, 0x01, | 278 | 0xff, 0x01, |
305 | 0x78, 0x40, /* led off */ | 279 | 0x78, 0x40, /* led off */ |
306 | }; | 280 | }; |
307 | static const __u8 start_7302[] = { | 281 | static const u8 start_7302[] = { |
308 | /* index, len, [value]* */ | 282 | /* index, len, [value]* */ |
309 | 0xff, 1, 0x00, /* page 0 */ | 283 | 0xff, 1, 0x00, /* page 0 */ |
310 | 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, | 284 | 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, |
@@ -319,7 +293,7 @@ static const __u8 start_7302[] = { | |||
319 | 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, | 293 | 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, |
320 | 0x00, 0x54, 0x11, | 294 | 0x00, 0x54, 0x11, |
321 | 0x55, 1, 0x00, | 295 | 0x55, 1, 0x00, |
322 | 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, | 296 | 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, |
323 | 0x6b, 1, 0x00, | 297 | 0x6b, 1, 0x00, |
324 | 0x6e, 3, 0x08, 0x06, 0x00, | 298 | 0x6e, 3, 0x08, 0x06, 0x00, |
325 | 0x72, 3, 0x00, 0xff, 0x00, | 299 | 0x72, 3, 0x00, 0xff, 0x00, |
@@ -370,7 +344,7 @@ static const __u8 start_7302[] = { | |||
370 | 344 | ||
371 | #define SKIP 0xaa | 345 | #define SKIP 0xaa |
372 | /* page 3 - the value SKIP says skip the index - see reg_w_page() */ | 346 | /* page 3 - the value SKIP says skip the index - see reg_w_page() */ |
373 | static const __u8 page3_7302[] = { | 347 | static const u8 page3_7302[] = { |
374 | 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, | 348 | 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, |
375 | 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, | 349 | 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, |
376 | 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 350 | 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
@@ -394,7 +368,7 @@ static const __u8 page3_7302[] = { | |||
394 | }; | 368 | }; |
395 | 369 | ||
396 | static void reg_w_buf(struct gspca_dev *gspca_dev, | 370 | static void reg_w_buf(struct gspca_dev *gspca_dev, |
397 | __u8 index, | 371 | u8 index, |
398 | const u8 *buffer, int len) | 372 | const u8 *buffer, int len) |
399 | { | 373 | { |
400 | int ret; | 374 | int ret; |
@@ -410,7 +384,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, | |||
410 | index, gspca_dev->usb_buf, len, | 384 | index, gspca_dev->usb_buf, len, |
411 | 500); | 385 | 500); |
412 | if (ret < 0) { | 386 | if (ret < 0) { |
413 | pr_err("reg_w_buf failed index 0x%02x, error %d\n", | 387 | pr_err("reg_w_buf failed i: %02x error %d\n", |
414 | index, ret); | 388 | index, ret); |
415 | gspca_dev->usb_err = ret; | 389 | gspca_dev->usb_err = ret; |
416 | } | 390 | } |
@@ -418,8 +392,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, | |||
418 | 392 | ||
419 | 393 | ||
420 | static void reg_w(struct gspca_dev *gspca_dev, | 394 | static void reg_w(struct gspca_dev *gspca_dev, |
421 | __u8 index, | 395 | u8 index, |
422 | __u8 value) | 396 | u8 value) |
423 | { | 397 | { |
424 | int ret; | 398 | int ret; |
425 | 399 | ||
@@ -433,14 +407,14 @@ static void reg_w(struct gspca_dev *gspca_dev, | |||
433 | 0, index, gspca_dev->usb_buf, 1, | 407 | 0, index, gspca_dev->usb_buf, 1, |
434 | 500); | 408 | 500); |
435 | if (ret < 0) { | 409 | if (ret < 0) { |
436 | pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n", | 410 | pr_err("reg_w() failed i: %02x v: %02x error %d\n", |
437 | index, value, ret); | 411 | index, value, ret); |
438 | gspca_dev->usb_err = ret; | 412 | gspca_dev->usb_err = ret; |
439 | } | 413 | } |
440 | } | 414 | } |
441 | 415 | ||
442 | static void reg_w_seq(struct gspca_dev *gspca_dev, | 416 | static void reg_w_seq(struct gspca_dev *gspca_dev, |
443 | const __u8 *seq, int len) | 417 | const u8 *seq, int len) |
444 | { | 418 | { |
445 | while (--len >= 0) { | 419 | while (--len >= 0) { |
446 | reg_w(gspca_dev, seq[0], seq[1]); | 420 | reg_w(gspca_dev, seq[0], seq[1]); |
@@ -450,7 +424,7 @@ static void reg_w_seq(struct gspca_dev *gspca_dev, | |||
450 | 424 | ||
451 | /* load the beginning of a page */ | 425 | /* load the beginning of a page */ |
452 | static void reg_w_page(struct gspca_dev *gspca_dev, | 426 | static void reg_w_page(struct gspca_dev *gspca_dev, |
453 | const __u8 *page, int len) | 427 | const u8 *page, int len) |
454 | { | 428 | { |
455 | int index; | 429 | int index; |
456 | int ret = 0; | 430 | int ret = 0; |
@@ -468,7 +442,7 @@ static void reg_w_page(struct gspca_dev *gspca_dev, | |||
468 | 0, index, gspca_dev->usb_buf, 1, | 442 | 0, index, gspca_dev->usb_buf, 1, |
469 | 500); | 443 | 500); |
470 | if (ret < 0) { | 444 | if (ret < 0) { |
471 | pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n", | 445 | pr_err("reg_w_page() failed i: %02x v: %02x error %d\n", |
472 | index, page[index], ret); | 446 | index, page[index], ret); |
473 | gspca_dev->usb_err = ret; | 447 | gspca_dev->usb_err = ret; |
474 | break; | 448 | break; |
@@ -478,8 +452,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev, | |||
478 | 452 | ||
479 | /* output a variable sequence */ | 453 | /* output a variable sequence */ |
480 | static void reg_w_var(struct gspca_dev *gspca_dev, | 454 | static void reg_w_var(struct gspca_dev *gspca_dev, |
481 | const __u8 *seq, | 455 | const u8 *seq, |
482 | const __u8 *page3, unsigned int page3_len) | 456 | const u8 *page3, unsigned int page3_len) |
483 | { | 457 | { |
484 | int index, len; | 458 | int index, len; |
485 | 459 | ||
@@ -493,11 +467,13 @@ static void reg_w_var(struct gspca_dev *gspca_dev, | |||
493 | reg_w_page(gspca_dev, page3, page3_len); | 467 | reg_w_page(gspca_dev, page3, page3_len); |
494 | break; | 468 | break; |
495 | default: | 469 | default: |
470 | #ifdef GSPCA_DEBUG | ||
496 | if (len > USB_BUF_SZ) { | 471 | if (len > USB_BUF_SZ) { |
497 | PDEBUG(D_ERR|D_STREAM, | 472 | PDEBUG(D_ERR|D_STREAM, |
498 | "Incorrect variable sequence"); | 473 | "Incorrect variable sequence"); |
499 | return; | 474 | return; |
500 | } | 475 | } |
476 | #endif | ||
501 | while (len > 0) { | 477 | while (len > 0) { |
502 | if (len < 8) { | 478 | if (len < 8) { |
503 | reg_w_buf(gspca_dev, | 479 | reg_w_buf(gspca_dev, |
@@ -524,21 +500,11 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
524 | 500 | ||
525 | cam = &gspca_dev->cam; | 501 | cam = &gspca_dev->cam; |
526 | 502 | ||
527 | PDEBUG(D_CONF, "Find Sensor PAC7302"); | ||
528 | cam->cam_mode = vga_mode; /* only 640x480 */ | 503 | cam->cam_mode = vga_mode; /* only 640x480 */ |
529 | cam->nmodes = ARRAY_SIZE(vga_mode); | 504 | cam->nmodes = ARRAY_SIZE(vga_mode); |
530 | 505 | ||
531 | sd->brightness = BRIGHTNESS_DEF; | 506 | gspca_dev->cam.ctrls = sd->ctrls; |
532 | sd->contrast = CONTRAST_DEF; | 507 | |
533 | sd->colors = COLOR_DEF; | ||
534 | sd->white_balance = WHITEBALANCE_DEF; | ||
535 | sd->red_balance = REDBALANCE_DEF; | ||
536 | sd->blue_balance = BLUEBALANCE_DEF; | ||
537 | sd->gain = GAIN_DEF; | ||
538 | sd->exposure = EXPOSURE_DEF; | ||
539 | sd->autogain = AUTOGAIN_DEF; | ||
540 | sd->hflip = HFLIP_DEF; | ||
541 | sd->vflip = VFLIP_DEF; | ||
542 | sd->flags = id->driver_info; | 508 | sd->flags = id->driver_info; |
543 | return 0; | 509 | return 0; |
544 | } | 510 | } |
@@ -548,19 +514,19 @@ static void setbrightcont(struct gspca_dev *gspca_dev) | |||
548 | { | 514 | { |
549 | struct sd *sd = (struct sd *) gspca_dev; | 515 | struct sd *sd = (struct sd *) gspca_dev; |
550 | int i, v; | 516 | int i, v; |
551 | static const __u8 max[10] = | 517 | static const u8 max[10] = |
552 | {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, | 518 | {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, |
553 | 0xd4, 0xec}; | 519 | 0xd4, 0xec}; |
554 | static const __u8 delta[10] = | 520 | static const u8 delta[10] = |
555 | {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, | 521 | {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, |
556 | 0x11, 0x0b}; | 522 | 0x11, 0x0b}; |
557 | 523 | ||
558 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 524 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
559 | for (i = 0; i < 10; i++) { | 525 | for (i = 0; i < 10; i++) { |
560 | v = max[i]; | 526 | v = max[i]; |
561 | v += (sd->brightness - BRIGHTNESS_MAX) | 527 | v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX) |
562 | * 150 / BRIGHTNESS_MAX; /* 200 ? */ | 528 | * 150 / BRIGHTNESS_MAX; /* 200 ? */ |
563 | v -= delta[i] * sd->contrast / CONTRAST_MAX; | 529 | v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX; |
564 | if (v < 0) | 530 | if (v < 0) |
565 | v = 0; | 531 | v = 0; |
566 | else if (v > 0xff) | 532 | else if (v > 0xff) |
@@ -584,12 +550,11 @@ static void setcolors(struct gspca_dev *gspca_dev) | |||
584 | reg_w(gspca_dev, 0x11, 0x01); | 550 | reg_w(gspca_dev, 0x11, 0x01); |
585 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 551 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
586 | for (i = 0; i < 9; i++) { | 552 | for (i = 0; i < 9; i++) { |
587 | v = a[i] * sd->colors / COLOR_MAX + b[i]; | 553 | v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i]; |
588 | reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); | 554 | reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); |
589 | reg_w(gspca_dev, 0x0f + 2 * i + 1, v); | 555 | reg_w(gspca_dev, 0x0f + 2 * i + 1, v); |
590 | } | 556 | } |
591 | reg_w(gspca_dev, 0xdc, 0x01); | 557 | reg_w(gspca_dev, 0xdc, 0x01); |
592 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); | ||
593 | } | 558 | } |
594 | 559 | ||
595 | static void setwhitebalance(struct gspca_dev *gspca_dev) | 560 | static void setwhitebalance(struct gspca_dev *gspca_dev) |
@@ -597,10 +562,9 @@ static void setwhitebalance(struct gspca_dev *gspca_dev) | |||
597 | struct sd *sd = (struct sd *) gspca_dev; | 562 | struct sd *sd = (struct sd *) gspca_dev; |
598 | 563 | ||
599 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 564 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
600 | reg_w(gspca_dev, 0xc6, sd->white_balance); | 565 | reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val); |
601 | 566 | ||
602 | reg_w(gspca_dev, 0xdc, 0x01); | 567 | reg_w(gspca_dev, 0xdc, 0x01); |
603 | PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); | ||
604 | } | 568 | } |
605 | 569 | ||
606 | static void setredbalance(struct gspca_dev *gspca_dev) | 570 | static void setredbalance(struct gspca_dev *gspca_dev) |
@@ -608,10 +572,9 @@ static void setredbalance(struct gspca_dev *gspca_dev) | |||
608 | struct sd *sd = (struct sd *) gspca_dev; | 572 | struct sd *sd = (struct sd *) gspca_dev; |
609 | 573 | ||
610 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 574 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
611 | reg_w(gspca_dev, 0xc5, sd->red_balance); | 575 | reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val); |
612 | 576 | ||
613 | reg_w(gspca_dev, 0xdc, 0x01); | 577 | reg_w(gspca_dev, 0xdc, 0x01); |
614 | PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); | ||
615 | } | 578 | } |
616 | 579 | ||
617 | static void setbluebalance(struct gspca_dev *gspca_dev) | 580 | static void setbluebalance(struct gspca_dev *gspca_dev) |
@@ -619,10 +582,9 @@ static void setbluebalance(struct gspca_dev *gspca_dev) | |||
619 | struct sd *sd = (struct sd *) gspca_dev; | 582 | struct sd *sd = (struct sd *) gspca_dev; |
620 | 583 | ||
621 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 584 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
622 | reg_w(gspca_dev, 0xc7, sd->blue_balance); | 585 | reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val); |
623 | 586 | ||
624 | reg_w(gspca_dev, 0xdc, 0x01); | 587 | reg_w(gspca_dev, 0xdc, 0x01); |
625 | PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); | ||
626 | } | 588 | } |
627 | 589 | ||
628 | static void setgain(struct gspca_dev *gspca_dev) | 590 | static void setgain(struct gspca_dev *gspca_dev) |
@@ -630,7 +592,7 @@ static void setgain(struct gspca_dev *gspca_dev) | |||
630 | struct sd *sd = (struct sd *) gspca_dev; | 592 | struct sd *sd = (struct sd *) gspca_dev; |
631 | 593 | ||
632 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 594 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
633 | reg_w(gspca_dev, 0x10, sd->gain >> 3); | 595 | reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3); |
634 | 596 | ||
635 | /* load registers to sensor (Bit 0, auto clear) */ | 597 | /* load registers to sensor (Bit 0, auto clear) */ |
636 | reg_w(gspca_dev, 0x11, 0x01); | 598 | reg_w(gspca_dev, 0x11, 0x01); |
@@ -639,13 +601,13 @@ static void setgain(struct gspca_dev *gspca_dev) | |||
639 | static void setexposure(struct gspca_dev *gspca_dev) | 601 | static void setexposure(struct gspca_dev *gspca_dev) |
640 | { | 602 | { |
641 | struct sd *sd = (struct sd *) gspca_dev; | 603 | struct sd *sd = (struct sd *) gspca_dev; |
642 | __u8 clockdiv; | 604 | u8 clockdiv; |
643 | __u16 exposure; | 605 | u16 exposure; |
644 | 606 | ||
645 | /* register 2 of frame 3 contains the clock divider configuring the | 607 | /* register 2 of frame 3 contains the clock divider configuring the |
646 | no fps according to the formula: 90 / reg. sd->exposure is the | 608 | no fps according to the formula: 90 / reg. sd->exposure is the |
647 | desired exposure time in 0.5 ms. */ | 609 | desired exposure time in 0.5 ms. */ |
648 | clockdiv = (90 * sd->exposure + 1999) / 2000; | 610 | clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000; |
649 | 611 | ||
650 | /* Note clockdiv = 3 also works, but when running at 30 fps, depending | 612 | /* Note clockdiv = 3 also works, but when running at 30 fps, depending |
651 | on the scene being recorded, the camera switches to another | 613 | on the scene being recorded, the camera switches to another |
@@ -664,7 +626,7 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
664 | 626 | ||
665 | /* frame exposure time in ms = 1000 * clockdiv / 90 -> | 627 | /* frame exposure time in ms = 1000 * clockdiv / 90 -> |
666 | exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ | 628 | exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ |
667 | exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); | 629 | exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv); |
668 | /* 0 = use full frametime, 448 = no exposure, reverse it */ | 630 | /* 0 = use full frametime, 448 = no exposure, reverse it */ |
669 | exposure = 448 - exposure; | 631 | exposure = 448 - exposure; |
670 | 632 | ||
@@ -677,15 +639,35 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
677 | reg_w(gspca_dev, 0x11, 0x01); | 639 | reg_w(gspca_dev, 0x11, 0x01); |
678 | } | 640 | } |
679 | 641 | ||
642 | static void setautogain(struct gspca_dev *gspca_dev) | ||
643 | { | ||
644 | struct sd *sd = (struct sd *) gspca_dev; | ||
645 | |||
646 | /* when switching to autogain set defaults to make sure | ||
647 | we are on a valid point of the autogain gain / | ||
648 | exposure knee graph, and give this change time to | ||
649 | take effect before doing autogain. */ | ||
650 | if (sd->ctrls[AUTOGAIN].val) { | ||
651 | sd->ctrls[EXPOSURE].val = EXPOSURE_DEF; | ||
652 | sd->ctrls[GAIN].val = GAIN_DEF; | ||
653 | sd->autogain_ignore_frames = | ||
654 | PAC_AUTOGAIN_IGNORE_FRAMES; | ||
655 | } else { | ||
656 | sd->autogain_ignore_frames = -1; | ||
657 | } | ||
658 | setexposure(gspca_dev); | ||
659 | setgain(gspca_dev); | ||
660 | } | ||
661 | |||
680 | static void sethvflip(struct gspca_dev *gspca_dev) | 662 | static void sethvflip(struct gspca_dev *gspca_dev) |
681 | { | 663 | { |
682 | struct sd *sd = (struct sd *) gspca_dev; | 664 | struct sd *sd = (struct sd *) gspca_dev; |
683 | u8 data, hflip, vflip; | 665 | u8 data, hflip, vflip; |
684 | 666 | ||
685 | hflip = sd->hflip; | 667 | hflip = sd->ctrls[HFLIP].val; |
686 | if (sd->flags & FL_HFLIP) | 668 | if (sd->flags & FL_HFLIP) |
687 | hflip = !hflip; | 669 | hflip = !hflip; |
688 | vflip = sd->vflip; | 670 | vflip = sd->ctrls[VFLIP].val; |
689 | if (sd->flags & FL_VFLIP) | 671 | if (sd->flags & FL_VFLIP) |
690 | vflip = !vflip; | 672 | vflip = !vflip; |
691 | 673 | ||
@@ -708,8 +690,6 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
708 | { | 690 | { |
709 | struct sd *sd = (struct sd *) gspca_dev; | 691 | struct sd *sd = (struct sd *) gspca_dev; |
710 | 692 | ||
711 | sd->sof_read = 0; | ||
712 | |||
713 | reg_w_var(gspca_dev, start_7302, | 693 | reg_w_var(gspca_dev, start_7302, |
714 | page3_7302, sizeof(page3_7302)); | 694 | page3_7302, sizeof(page3_7302)); |
715 | setbrightcont(gspca_dev); | 695 | setbrightcont(gspca_dev); |
@@ -717,15 +697,13 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
717 | setwhitebalance(gspca_dev); | 697 | setwhitebalance(gspca_dev); |
718 | setredbalance(gspca_dev); | 698 | setredbalance(gspca_dev); |
719 | setbluebalance(gspca_dev); | 699 | setbluebalance(gspca_dev); |
720 | setgain(gspca_dev); | 700 | setautogain(gspca_dev); |
721 | setexposure(gspca_dev); | ||
722 | sethvflip(gspca_dev); | 701 | sethvflip(gspca_dev); |
723 | 702 | ||
724 | /* only resolution 640x480 is supported for pac7302 */ | 703 | /* only resolution 640x480 is supported for pac7302 */ |
725 | 704 | ||
726 | sd->sof_read = 0; | 705 | sd->sof_read = 0; |
727 | sd->autogain_ignore_frames = 0; | 706 | atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val); |
728 | atomic_set(&sd->avg_lum, -1); | ||
729 | 707 | ||
730 | /* start stream */ | 708 | /* start stream */ |
731 | reg_w(gspca_dev, 0xff, 0x01); | 709 | reg_w(gspca_dev, 0xff, 0x01); |
@@ -751,8 +729,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
751 | reg_w(gspca_dev, 0x78, 0x40); | 729 | reg_w(gspca_dev, 0x78, 0x40); |
752 | } | 730 | } |
753 | 731 | ||
754 | /* Include pac common sof detection functions */ | 732 | /* !! coarse_grained_expo_autogain is not used !! */ |
755 | #include "pac_common.h" | 733 | #define exp_too_low_cnt flags |
734 | #define exp_too_high_cnt sof_read | ||
735 | #include "autogain_functions.h" | ||
756 | 736 | ||
757 | static void do_autogain(struct gspca_dev *gspca_dev) | 737 | static void do_autogain(struct gspca_dev *gspca_dev) |
758 | { | 738 | { |
@@ -761,65 +741,44 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
761 | int desired_lum; | 741 | int desired_lum; |
762 | const int deadzone = 30; | 742 | const int deadzone = 30; |
763 | 743 | ||
764 | if (avg_lum == -1) | 744 | if (sd->autogain_ignore_frames < 0) |
765 | return; | 745 | return; |
766 | 746 | ||
767 | desired_lum = 270 + sd->brightness; | 747 | if (sd->autogain_ignore_frames > 0) { |
768 | |||
769 | if (sd->autogain_ignore_frames > 0) | ||
770 | sd->autogain_ignore_frames--; | 748 | sd->autogain_ignore_frames--; |
771 | else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, | 749 | } else { |
772 | deadzone, GAIN_KNEE, EXPOSURE_KNEE)) | 750 | desired_lum = 270 + sd->ctrls[BRIGHTNESS].val; |
751 | |||
752 | auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, | ||
753 | deadzone, GAIN_KNEE, EXPOSURE_KNEE); | ||
773 | sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; | 754 | sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; |
755 | } | ||
774 | } | 756 | } |
775 | 757 | ||
776 | /* JPEG header, part 1 */ | 758 | /* JPEG header */ |
777 | static const unsigned char pac_jpeg_header1[] = { | 759 | static const u8 jpeg_header[] = { |
778 | 0xff, 0xd8, /* SOI: Start of Image */ | 760 | 0xff, 0xd8, /* SOI: Start of Image */ |
779 | 761 | ||
780 | 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ | 762 | 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ |
781 | 0x00, 0x11, /* length = 17 bytes (including this length field) */ | 763 | 0x00, 0x11, /* length = 17 bytes (including this length field) */ |
782 | 0x08 /* Precision: 8 */ | 764 | 0x08, /* Precision: 8 */ |
783 | /* 2 bytes is placed here: number of image lines */ | 765 | 0x02, 0x80, /* height = 640 (image rotated) */ |
784 | /* 2 bytes is placed here: samples per line */ | 766 | 0x01, 0xe0, /* width = 480 */ |
785 | }; | 767 | 0x03, /* Number of image components: 3 */ |
786 | 768 | 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ | |
787 | /* JPEG header, continued */ | 769 | 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ |
788 | static const unsigned char pac_jpeg_header2[] = { | 770 | 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ |
789 | 0x03, /* Number of image components: 3 */ | 771 | |
790 | 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ | 772 | 0xff, 0xda, /* SOS: Start Of Scan */ |
791 | 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ | 773 | 0x00, 0x0c, /* length = 12 bytes (including this length field) */ |
792 | 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ | 774 | 0x03, /* number of components: 3 */ |
793 | 775 | 0x01, 0x00, /* selector 1, table 0x00 */ | |
794 | 0xff, 0xda, /* SOS: Start Of Scan */ | 776 | 0x02, 0x11, /* selector 2, table 0x11 */ |
795 | 0x00, 0x0c, /* length = 12 bytes (including this length field) */ | 777 | 0x03, 0x11, /* selector 3, table 0x11 */ |
796 | 0x03, /* number of components: 3 */ | 778 | 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ |
797 | 0x01, 0x00, /* selector 1, table 0x00 */ | 779 | 0x00 /* Successive approximation: 0 */ |
798 | 0x02, 0x11, /* selector 2, table 0x11 */ | ||
799 | 0x03, 0x11, /* selector 3, table 0x11 */ | ||
800 | 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ | ||
801 | 0x00 /* Successive approximation: 0 */ | ||
802 | }; | 780 | }; |
803 | 781 | ||
804 | static void pac_start_frame(struct gspca_dev *gspca_dev, | ||
805 | __u16 lines, __u16 samples_per_line) | ||
806 | { | ||
807 | unsigned char tmpbuf[4]; | ||
808 | |||
809 | gspca_frame_add(gspca_dev, FIRST_PACKET, | ||
810 | pac_jpeg_header1, sizeof(pac_jpeg_header1)); | ||
811 | |||
812 | tmpbuf[0] = lines >> 8; | ||
813 | tmpbuf[1] = lines & 0xff; | ||
814 | tmpbuf[2] = samples_per_line >> 8; | ||
815 | tmpbuf[3] = samples_per_line & 0xff; | ||
816 | |||
817 | gspca_frame_add(gspca_dev, INTER_PACKET, | ||
818 | tmpbuf, sizeof(tmpbuf)); | ||
819 | gspca_frame_add(gspca_dev, INTER_PACKET, | ||
820 | pac_jpeg_header2, sizeof(pac_jpeg_header2)); | ||
821 | } | ||
822 | |||
823 | /* this function is run at interrupt level */ | 782 | /* this function is run at interrupt level */ |
824 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 783 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
825 | u8 *data, /* isoc packet */ | 784 | u8 *data, /* isoc packet */ |
@@ -827,7 +786,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
827 | { | 786 | { |
828 | struct sd *sd = (struct sd *) gspca_dev; | 787 | struct sd *sd = (struct sd *) gspca_dev; |
829 | u8 *image; | 788 | u8 *image; |
830 | unsigned char *sof; | 789 | u8 *sof; |
831 | 790 | ||
832 | sof = pac_find_sof(&sd->sof_read, data, len); | 791 | sof = pac_find_sof(&sd->sof_read, data, len); |
833 | if (sof) { | 792 | if (sof) { |
@@ -864,234 +823,21 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
864 | n >= lum_offset) | 823 | n >= lum_offset) |
865 | atomic_set(&sd->avg_lum, data[-lum_offset] + | 824 | atomic_set(&sd->avg_lum, data[-lum_offset] + |
866 | data[-lum_offset + 1]); | 825 | data[-lum_offset + 1]); |
867 | else | ||
868 | atomic_set(&sd->avg_lum, -1); | ||
869 | 826 | ||
870 | /* Start the new frame with the jpeg header */ | 827 | /* Start the new frame with the jpeg header */ |
871 | /* The PAC7302 has the image rotated 90 degrees */ | 828 | /* The PAC7302 has the image rotated 90 degrees */ |
872 | pac_start_frame(gspca_dev, | 829 | gspca_frame_add(gspca_dev, FIRST_PACKET, |
873 | gspca_dev->width, gspca_dev->height); | 830 | jpeg_header, sizeof jpeg_header); |
874 | } | 831 | } |
875 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); | 832 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); |
876 | } | 833 | } |
877 | 834 | ||
878 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | ||
879 | { | ||
880 | struct sd *sd = (struct sd *) gspca_dev; | ||
881 | |||
882 | sd->brightness = val; | ||
883 | if (gspca_dev->streaming) | ||
884 | setbrightcont(gspca_dev); | ||
885 | return gspca_dev->usb_err; | ||
886 | } | ||
887 | |||
888 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | ||
889 | { | ||
890 | struct sd *sd = (struct sd *) gspca_dev; | ||
891 | |||
892 | *val = sd->brightness; | ||
893 | return 0; | ||
894 | } | ||
895 | |||
896 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | ||
897 | { | ||
898 | struct sd *sd = (struct sd *) gspca_dev; | ||
899 | |||
900 | sd->contrast = val; | ||
901 | if (gspca_dev->streaming) | ||
902 | setbrightcont(gspca_dev); | ||
903 | return gspca_dev->usb_err; | ||
904 | } | ||
905 | |||
906 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | ||
907 | { | ||
908 | struct sd *sd = (struct sd *) gspca_dev; | ||
909 | |||
910 | *val = sd->contrast; | ||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) | ||
915 | { | ||
916 | struct sd *sd = (struct sd *) gspca_dev; | ||
917 | |||
918 | sd->colors = val; | ||
919 | if (gspca_dev->streaming) | ||
920 | setcolors(gspca_dev); | ||
921 | return gspca_dev->usb_err; | ||
922 | } | ||
923 | |||
924 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | ||
925 | { | ||
926 | struct sd *sd = (struct sd *) gspca_dev; | ||
927 | |||
928 | *val = sd->colors; | ||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) | ||
933 | { | ||
934 | struct sd *sd = (struct sd *) gspca_dev; | ||
935 | |||
936 | sd->white_balance = val; | ||
937 | if (gspca_dev->streaming) | ||
938 | setwhitebalance(gspca_dev); | ||
939 | return gspca_dev->usb_err; | ||
940 | } | ||
941 | |||
942 | static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) | ||
943 | { | ||
944 | struct sd *sd = (struct sd *) gspca_dev; | ||
945 | |||
946 | *val = sd->white_balance; | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) | ||
951 | { | ||
952 | struct sd *sd = (struct sd *) gspca_dev; | ||
953 | |||
954 | sd->red_balance = val; | ||
955 | if (gspca_dev->streaming) | ||
956 | setredbalance(gspca_dev); | ||
957 | return gspca_dev->usb_err; | ||
958 | } | ||
959 | |||
960 | static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) | ||
961 | { | ||
962 | struct sd *sd = (struct sd *) gspca_dev; | ||
963 | |||
964 | *val = sd->red_balance; | ||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) | ||
969 | { | ||
970 | struct sd *sd = (struct sd *) gspca_dev; | ||
971 | |||
972 | sd->blue_balance = val; | ||
973 | if (gspca_dev->streaming) | ||
974 | setbluebalance(gspca_dev); | ||
975 | return gspca_dev->usb_err; | ||
976 | } | ||
977 | |||
978 | static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) | ||
979 | { | ||
980 | struct sd *sd = (struct sd *) gspca_dev; | ||
981 | |||
982 | *val = sd->blue_balance; | ||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) | ||
987 | { | ||
988 | struct sd *sd = (struct sd *) gspca_dev; | ||
989 | |||
990 | sd->gain = val; | ||
991 | if (gspca_dev->streaming) | ||
992 | setgain(gspca_dev); | ||
993 | return gspca_dev->usb_err; | ||
994 | } | ||
995 | |||
996 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) | ||
997 | { | ||
998 | struct sd *sd = (struct sd *) gspca_dev; | ||
999 | |||
1000 | *val = sd->gain; | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) | ||
1005 | { | ||
1006 | struct sd *sd = (struct sd *) gspca_dev; | ||
1007 | |||
1008 | sd->exposure = val; | ||
1009 | if (gspca_dev->streaming) | ||
1010 | setexposure(gspca_dev); | ||
1011 | return gspca_dev->usb_err; | ||
1012 | } | ||
1013 | |||
1014 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
1015 | { | ||
1016 | struct sd *sd = (struct sd *) gspca_dev; | ||
1017 | |||
1018 | *val = sd->exposure; | ||
1019 | return 0; | ||
1020 | } | ||
1021 | |||
1022 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | ||
1023 | { | ||
1024 | struct sd *sd = (struct sd *) gspca_dev; | ||
1025 | |||
1026 | sd->autogain = val; | ||
1027 | /* when switching to autogain set defaults to make sure | ||
1028 | we are on a valid point of the autogain gain / | ||
1029 | exposure knee graph, and give this change time to | ||
1030 | take effect before doing autogain. */ | ||
1031 | if (sd->autogain) { | ||
1032 | sd->exposure = EXPOSURE_DEF; | ||
1033 | sd->gain = GAIN_DEF; | ||
1034 | if (gspca_dev->streaming) { | ||
1035 | sd->autogain_ignore_frames = | ||
1036 | PAC_AUTOGAIN_IGNORE_FRAMES; | ||
1037 | setexposure(gspca_dev); | ||
1038 | setgain(gspca_dev); | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | return gspca_dev->usb_err; | ||
1043 | } | ||
1044 | |||
1045 | static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) | ||
1046 | { | ||
1047 | struct sd *sd = (struct sd *) gspca_dev; | ||
1048 | |||
1049 | *val = sd->autogain; | ||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) | ||
1054 | { | ||
1055 | struct sd *sd = (struct sd *) gspca_dev; | ||
1056 | |||
1057 | sd->hflip = val; | ||
1058 | if (gspca_dev->streaming) | ||
1059 | sethvflip(gspca_dev); | ||
1060 | return gspca_dev->usb_err; | ||
1061 | } | ||
1062 | |||
1063 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
1064 | { | ||
1065 | struct sd *sd = (struct sd *) gspca_dev; | ||
1066 | |||
1067 | *val = sd->hflip; | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) | ||
1072 | { | ||
1073 | struct sd *sd = (struct sd *) gspca_dev; | ||
1074 | |||
1075 | sd->vflip = val; | ||
1076 | if (gspca_dev->streaming) | ||
1077 | sethvflip(gspca_dev); | ||
1078 | return gspca_dev->usb_err; | ||
1079 | } | ||
1080 | |||
1081 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
1082 | { | ||
1083 | struct sd *sd = (struct sd *) gspca_dev; | ||
1084 | |||
1085 | *val = sd->vflip; | ||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 835 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1090 | static int sd_dbg_s_register(struct gspca_dev *gspca_dev, | 836 | static int sd_dbg_s_register(struct gspca_dev *gspca_dev, |
1091 | struct v4l2_dbg_register *reg) | 837 | struct v4l2_dbg_register *reg) |
1092 | { | 838 | { |
1093 | __u8 index; | 839 | u8 index; |
1094 | __u8 value; | 840 | u8 value; |
1095 | 841 | ||
1096 | /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit | 842 | /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit |
1097 | long on the USB bus) | 843 | long on the USB bus) |
@@ -1103,8 +849,8 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev, | |||
1103 | ) { | 849 | ) { |
1104 | /* Currently writing to page 0 is only supported. */ | 850 | /* Currently writing to page 0 is only supported. */ |
1105 | /* reg_w() only supports 8bit index */ | 851 | /* reg_w() only supports 8bit index */ |
1106 | index = reg->reg & 0x000000ff; | 852 | index = reg->reg; |
1107 | value = reg->val & 0x000000ff; | 853 | value = reg->val; |
1108 | 854 | ||
1109 | /* Note that there shall be no access to other page | 855 | /* Note that there shall be no access to other page |
1110 | by any other function between the page swith and | 856 | by any other function between the page swith and |
@@ -1165,7 +911,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, | |||
1165 | 911 | ||
1166 | /* sub-driver description for pac7302 */ | 912 | /* sub-driver description for pac7302 */ |
1167 | static const struct sd_desc sd_desc = { | 913 | static const struct sd_desc sd_desc = { |
1168 | .name = MODULE_NAME, | 914 | .name = KBUILD_MODNAME, |
1169 | .ctrls = sd_ctrls, | 915 | .ctrls = sd_ctrls, |
1170 | .nctrls = ARRAY_SIZE(sd_ctrls), | 916 | .nctrls = ARRAY_SIZE(sd_ctrls), |
1171 | .config = sd_config, | 917 | .config = sd_config, |
@@ -1187,6 +933,7 @@ static const struct sd_desc sd_desc = { | |||
1187 | /* -- module initialisation -- */ | 933 | /* -- module initialisation -- */ |
1188 | static const struct usb_device_id device_table[] = { | 934 | static const struct usb_device_id device_table[] = { |
1189 | {USB_DEVICE(0x06f8, 0x3009)}, | 935 | {USB_DEVICE(0x06f8, 0x3009)}, |
936 | {USB_DEVICE(0x06f8, 0x301b)}, | ||
1190 | {USB_DEVICE(0x093a, 0x2620)}, | 937 | {USB_DEVICE(0x093a, 0x2620)}, |
1191 | {USB_DEVICE(0x093a, 0x2621)}, | 938 | {USB_DEVICE(0x093a, 0x2621)}, |
1192 | {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, | 939 | {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, |
@@ -1211,7 +958,7 @@ static int sd_probe(struct usb_interface *intf, | |||
1211 | } | 958 | } |
1212 | 959 | ||
1213 | static struct usb_driver sd_driver = { | 960 | static struct usb_driver sd_driver = { |
1214 | .name = MODULE_NAME, | 961 | .name = KBUILD_MODNAME, |
1215 | .id_table = device_table, | 962 | .id_table = device_table, |
1216 | .probe = sd_probe, | 963 | .probe = sd_probe, |
1217 | .disconnect = gspca_disconnect, | 964 | .disconnect = gspca_disconnect, |
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 9e198b45c3c8..7e71aa2d2522 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c | |||
@@ -1,5 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Sonix sn9c201 sn9c202 library | 2 | * Sonix sn9c201 sn9c202 library |
3 | * | ||
4 | * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr> | ||
3 | * Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com> | 5 | * Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com> |
4 | * Copyright (C) 2009 Brian Johnson <brijohn@gmail.com> | 6 | * Copyright (C) 2009 Brian Johnson <brijohn@gmail.com> |
5 | * | 7 | * |
@@ -33,8 +35,6 @@ MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, " | |||
33 | MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver"); | 35 | MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver"); |
34 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
35 | 37 | ||
36 | #define MODULE_NAME "sn9c20x" | ||
37 | |||
38 | /* | 38 | /* |
39 | * Pixel format private data | 39 | * Pixel format private data |
40 | */ | 40 | */ |
@@ -66,10 +66,37 @@ MODULE_LICENSE("GPL"); | |||
66 | #define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ | 66 | #define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ |
67 | #define FLIP_DETECT 0x4 | 67 | #define FLIP_DETECT 0x4 |
68 | 68 | ||
69 | enum e_ctrl { | ||
70 | BRIGHTNESS, | ||
71 | CONTRAST, | ||
72 | SATURATION, | ||
73 | HUE, | ||
74 | GAMMA, | ||
75 | BLUE, | ||
76 | RED, | ||
77 | VFLIP, | ||
78 | HFLIP, | ||
79 | EXPOSURE, | ||
80 | GAIN, | ||
81 | AUTOGAIN, | ||
82 | QUALITY, | ||
83 | NCTRLS /* number of controls */ | ||
84 | }; | ||
85 | |||
69 | /* specific webcam descriptor */ | 86 | /* specific webcam descriptor */ |
70 | struct sd { | 87 | struct sd { |
71 | struct gspca_dev gspca_dev; | 88 | struct gspca_dev gspca_dev; |
72 | 89 | ||
90 | struct gspca_ctrl ctrls[NCTRLS]; | ||
91 | |||
92 | struct work_struct work; | ||
93 | struct workqueue_struct *work_thread; | ||
94 | |||
95 | u32 pktsz; /* (used by pkt_scan) */ | ||
96 | u16 npkt; | ||
97 | s8 nchg; | ||
98 | u8 fmt; /* (used for JPEG QTAB update */ | ||
99 | |||
73 | #define MIN_AVG_LUM 80 | 100 | #define MIN_AVG_LUM 80 |
74 | #define MAX_AVG_LUM 130 | 101 | #define MAX_AVG_LUM 130 |
75 | atomic_t avg_lum; | 102 | atomic_t avg_lum; |
@@ -77,31 +104,18 @@ struct sd { | |||
77 | u8 older_step; | 104 | u8 older_step; |
78 | u8 exposure_step; | 105 | u8 exposure_step; |
79 | 106 | ||
80 | u8 brightness; | ||
81 | u8 contrast; | ||
82 | u8 saturation; | ||
83 | s16 hue; | ||
84 | u8 gamma; | ||
85 | u8 red; | ||
86 | u8 blue; | ||
87 | |||
88 | u8 hflip; | ||
89 | u8 vflip; | ||
90 | u8 gain; | ||
91 | u16 exposure; | ||
92 | u8 auto_exposure; | ||
93 | |||
94 | u8 i2c_addr; | 107 | u8 i2c_addr; |
95 | u8 sensor; | 108 | u8 sensor; |
96 | u8 hstart; | 109 | u8 hstart; |
97 | u8 vstart; | 110 | u8 vstart; |
98 | 111 | ||
99 | u8 jpeg_hdr[JPEG_HDR_SZ]; | 112 | u8 jpeg_hdr[JPEG_HDR_SZ]; |
100 | u8 quality; | ||
101 | 113 | ||
102 | u8 flags; | 114 | u8 flags; |
103 | }; | 115 | }; |
104 | 116 | ||
117 | static void qual_upd(struct work_struct *work); | ||
118 | |||
105 | struct i2c_reg_u8 { | 119 | struct i2c_reg_u8 { |
106 | u8 reg; | 120 | u8 reg; |
107 | u8 val; | 121 | u8 val; |
@@ -112,31 +126,6 @@ struct i2c_reg_u16 { | |||
112 | u16 val; | 126 | u16 val; |
113 | }; | 127 | }; |
114 | 128 | ||
115 | static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val); | ||
116 | static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val); | ||
117 | static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val); | ||
118 | static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val); | ||
119 | static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val); | ||
120 | static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val); | ||
121 | static int sd_sethue(struct gspca_dev *gspca_dev, s32 val); | ||
122 | static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val); | ||
123 | static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val); | ||
124 | static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val); | ||
125 | static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val); | ||
126 | static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val); | ||
127 | static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val); | ||
128 | static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val); | ||
129 | static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val); | ||
130 | static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val); | ||
131 | static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val); | ||
132 | static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val); | ||
133 | static int sd_setgain(struct gspca_dev *gspca_dev, s32 val); | ||
134 | static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val); | ||
135 | static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val); | ||
136 | static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val); | ||
137 | static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val); | ||
138 | static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val); | ||
139 | |||
140 | static const struct dmi_system_id flip_dmi_table[] = { | 129 | static const struct dmi_system_id flip_dmi_table[] = { |
141 | { | 130 | { |
142 | .ident = "MSI MS-1034", | 131 | .ident = "MSI MS-1034", |
@@ -177,9 +166,16 @@ static const struct dmi_system_id flip_dmi_table[] = { | |||
177 | {} | 166 | {} |
178 | }; | 167 | }; |
179 | 168 | ||
180 | static const struct ctrl sd_ctrls[] = { | 169 | static void set_cmatrix(struct gspca_dev *gspca_dev); |
181 | { | 170 | static void set_gamma(struct gspca_dev *gspca_dev); |
182 | #define BRIGHTNESS_IDX 0 | 171 | static void set_redblue(struct gspca_dev *gspca_dev); |
172 | static void set_hvflip(struct gspca_dev *gspca_dev); | ||
173 | static void set_exposure(struct gspca_dev *gspca_dev); | ||
174 | static void set_gain(struct gspca_dev *gspca_dev); | ||
175 | static void set_quality(struct gspca_dev *gspca_dev); | ||
176 | |||
177 | static const struct ctrl sd_ctrls[NCTRLS] = { | ||
178 | [BRIGHTNESS] = { | ||
183 | { | 179 | { |
184 | .id = V4L2_CID_BRIGHTNESS, | 180 | .id = V4L2_CID_BRIGHTNESS, |
185 | .type = V4L2_CTRL_TYPE_INTEGER, | 181 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -187,14 +183,11 @@ static const struct ctrl sd_ctrls[] = { | |||
187 | .minimum = 0, | 183 | .minimum = 0, |
188 | .maximum = 0xff, | 184 | .maximum = 0xff, |
189 | .step = 1, | 185 | .step = 1, |
190 | #define BRIGHTNESS_DEFAULT 0x7f | 186 | .default_value = 0x7f |
191 | .default_value = BRIGHTNESS_DEFAULT, | ||
192 | }, | 187 | }, |
193 | .set = sd_setbrightness, | 188 | .set_control = set_cmatrix |
194 | .get = sd_getbrightness, | ||
195 | }, | 189 | }, |
196 | { | 190 | [CONTRAST] = { |
197 | #define CONTRAST_IDX 1 | ||
198 | { | 191 | { |
199 | .id = V4L2_CID_CONTRAST, | 192 | .id = V4L2_CID_CONTRAST, |
200 | .type = V4L2_CTRL_TYPE_INTEGER, | 193 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -202,14 +195,11 @@ static const struct ctrl sd_ctrls[] = { | |||
202 | .minimum = 0, | 195 | .minimum = 0, |
203 | .maximum = 0xff, | 196 | .maximum = 0xff, |
204 | .step = 1, | 197 | .step = 1, |
205 | #define CONTRAST_DEFAULT 0x7f | 198 | .default_value = 0x7f |
206 | .default_value = CONTRAST_DEFAULT, | ||
207 | }, | 199 | }, |
208 | .set = sd_setcontrast, | 200 | .set_control = set_cmatrix |
209 | .get = sd_getcontrast, | ||
210 | }, | 201 | }, |
211 | { | 202 | [SATURATION] = { |
212 | #define SATURATION_IDX 2 | ||
213 | { | 203 | { |
214 | .id = V4L2_CID_SATURATION, | 204 | .id = V4L2_CID_SATURATION, |
215 | .type = V4L2_CTRL_TYPE_INTEGER, | 205 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -217,14 +207,11 @@ static const struct ctrl sd_ctrls[] = { | |||
217 | .minimum = 0, | 207 | .minimum = 0, |
218 | .maximum = 0xff, | 208 | .maximum = 0xff, |
219 | .step = 1, | 209 | .step = 1, |
220 | #define SATURATION_DEFAULT 0x7f | 210 | .default_value = 0x7f |
221 | .default_value = SATURATION_DEFAULT, | ||
222 | }, | 211 | }, |
223 | .set = sd_setsaturation, | 212 | .set_control = set_cmatrix |
224 | .get = sd_getsaturation, | ||
225 | }, | 213 | }, |
226 | { | 214 | [HUE] = { |
227 | #define HUE_IDX 3 | ||
228 | { | 215 | { |
229 | .id = V4L2_CID_HUE, | 216 | .id = V4L2_CID_HUE, |
230 | .type = V4L2_CTRL_TYPE_INTEGER, | 217 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -232,14 +219,11 @@ static const struct ctrl sd_ctrls[] = { | |||
232 | .minimum = -180, | 219 | .minimum = -180, |
233 | .maximum = 180, | 220 | .maximum = 180, |
234 | .step = 1, | 221 | .step = 1, |
235 | #define HUE_DEFAULT 0 | 222 | .default_value = 0 |
236 | .default_value = HUE_DEFAULT, | ||
237 | }, | 223 | }, |
238 | .set = sd_sethue, | 224 | .set_control = set_cmatrix |
239 | .get = sd_gethue, | ||
240 | }, | 225 | }, |
241 | { | 226 | [GAMMA] = { |
242 | #define GAMMA_IDX 4 | ||
243 | { | 227 | { |
244 | .id = V4L2_CID_GAMMA, | 228 | .id = V4L2_CID_GAMMA, |
245 | .type = V4L2_CTRL_TYPE_INTEGER, | 229 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -247,14 +231,11 @@ static const struct ctrl sd_ctrls[] = { | |||
247 | .minimum = 0, | 231 | .minimum = 0, |
248 | .maximum = 0xff, | 232 | .maximum = 0xff, |
249 | .step = 1, | 233 | .step = 1, |
250 | #define GAMMA_DEFAULT 0x10 | 234 | .default_value = 0x10 |
251 | .default_value = GAMMA_DEFAULT, | ||
252 | }, | 235 | }, |
253 | .set = sd_setgamma, | 236 | .set_control = set_gamma |
254 | .get = sd_getgamma, | ||
255 | }, | 237 | }, |
256 | { | 238 | [BLUE] = { |
257 | #define BLUE_IDX 5 | ||
258 | { | 239 | { |
259 | .id = V4L2_CID_BLUE_BALANCE, | 240 | .id = V4L2_CID_BLUE_BALANCE, |
260 | .type = V4L2_CTRL_TYPE_INTEGER, | 241 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -262,14 +243,11 @@ static const struct ctrl sd_ctrls[] = { | |||
262 | .minimum = 0, | 243 | .minimum = 0, |
263 | .maximum = 0x7f, | 244 | .maximum = 0x7f, |
264 | .step = 1, | 245 | .step = 1, |
265 | #define BLUE_DEFAULT 0x28 | 246 | .default_value = 0x28 |
266 | .default_value = BLUE_DEFAULT, | ||
267 | }, | 247 | }, |
268 | .set = sd_setbluebalance, | 248 | .set_control = set_redblue |
269 | .get = sd_getbluebalance, | ||
270 | }, | 249 | }, |
271 | { | 250 | [RED] = { |
272 | #define RED_IDX 6 | ||
273 | { | 251 | { |
274 | .id = V4L2_CID_RED_BALANCE, | 252 | .id = V4L2_CID_RED_BALANCE, |
275 | .type = V4L2_CTRL_TYPE_INTEGER, | 253 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -277,14 +255,11 @@ static const struct ctrl sd_ctrls[] = { | |||
277 | .minimum = 0, | 255 | .minimum = 0, |
278 | .maximum = 0x7f, | 256 | .maximum = 0x7f, |
279 | .step = 1, | 257 | .step = 1, |
280 | #define RED_DEFAULT 0x28 | 258 | .default_value = 0x28 |
281 | .default_value = RED_DEFAULT, | ||
282 | }, | 259 | }, |
283 | .set = sd_setredbalance, | 260 | .set_control = set_redblue |
284 | .get = sd_getredbalance, | ||
285 | }, | 261 | }, |
286 | { | 262 | [HFLIP] = { |
287 | #define HFLIP_IDX 7 | ||
288 | { | 263 | { |
289 | .id = V4L2_CID_HFLIP, | 264 | .id = V4L2_CID_HFLIP, |
290 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 265 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
@@ -292,14 +267,11 @@ static const struct ctrl sd_ctrls[] = { | |||
292 | .minimum = 0, | 267 | .minimum = 0, |
293 | .maximum = 1, | 268 | .maximum = 1, |
294 | .step = 1, | 269 | .step = 1, |
295 | #define HFLIP_DEFAULT 0 | 270 | .default_value = 0, |
296 | .default_value = HFLIP_DEFAULT, | ||
297 | }, | 271 | }, |
298 | .set = sd_sethflip, | 272 | .set_control = set_hvflip |
299 | .get = sd_gethflip, | ||
300 | }, | 273 | }, |
301 | { | 274 | [VFLIP] = { |
302 | #define VFLIP_IDX 8 | ||
303 | { | 275 | { |
304 | .id = V4L2_CID_VFLIP, | 276 | .id = V4L2_CID_VFLIP, |
305 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 277 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
@@ -307,14 +279,11 @@ static const struct ctrl sd_ctrls[] = { | |||
307 | .minimum = 0, | 279 | .minimum = 0, |
308 | .maximum = 1, | 280 | .maximum = 1, |
309 | .step = 1, | 281 | .step = 1, |
310 | #define VFLIP_DEFAULT 0 | 282 | .default_value = 0, |
311 | .default_value = VFLIP_DEFAULT, | ||
312 | }, | 283 | }, |
313 | .set = sd_setvflip, | 284 | .set_control = set_hvflip |
314 | .get = sd_getvflip, | ||
315 | }, | 285 | }, |
316 | { | 286 | [EXPOSURE] = { |
317 | #define EXPOSURE_IDX 9 | ||
318 | { | 287 | { |
319 | .id = V4L2_CID_EXPOSURE, | 288 | .id = V4L2_CID_EXPOSURE, |
320 | .type = V4L2_CTRL_TYPE_INTEGER, | 289 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -322,14 +291,11 @@ static const struct ctrl sd_ctrls[] = { | |||
322 | .minimum = 0, | 291 | .minimum = 0, |
323 | .maximum = 0x1780, | 292 | .maximum = 0x1780, |
324 | .step = 1, | 293 | .step = 1, |
325 | #define EXPOSURE_DEFAULT 0x33 | 294 | .default_value = 0x33, |
326 | .default_value = EXPOSURE_DEFAULT, | ||
327 | }, | 295 | }, |
328 | .set = sd_setexposure, | 296 | .set_control = set_exposure |
329 | .get = sd_getexposure, | ||
330 | }, | 297 | }, |
331 | { | 298 | [GAIN] = { |
332 | #define GAIN_IDX 10 | ||
333 | { | 299 | { |
334 | .id = V4L2_CID_GAIN, | 300 | .id = V4L2_CID_GAIN, |
335 | .type = V4L2_CTRL_TYPE_INTEGER, | 301 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -337,14 +303,11 @@ static const struct ctrl sd_ctrls[] = { | |||
337 | .minimum = 0, | 303 | .minimum = 0, |
338 | .maximum = 28, | 304 | .maximum = 28, |
339 | .step = 1, | 305 | .step = 1, |
340 | #define GAIN_DEFAULT 0x00 | 306 | .default_value = 0, |
341 | .default_value = GAIN_DEFAULT, | ||
342 | }, | 307 | }, |
343 | .set = sd_setgain, | 308 | .set_control = set_gain |
344 | .get = sd_getgain, | ||
345 | }, | 309 | }, |
346 | { | 310 | [AUTOGAIN] = { |
347 | #define AUTOGAIN_IDX 11 | ||
348 | { | 311 | { |
349 | .id = V4L2_CID_AUTOGAIN, | 312 | .id = V4L2_CID_AUTOGAIN, |
350 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 313 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
@@ -352,11 +315,23 @@ static const struct ctrl sd_ctrls[] = { | |||
352 | .minimum = 0, | 315 | .minimum = 0, |
353 | .maximum = 1, | 316 | .maximum = 1, |
354 | .step = 1, | 317 | .step = 1, |
355 | #define AUTO_EXPOSURE_DEFAULT 1 | 318 | .default_value = 1, |
356 | .default_value = AUTO_EXPOSURE_DEFAULT, | 319 | }, |
320 | }, | ||
321 | [QUALITY] = { | ||
322 | { | ||
323 | .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, | ||
324 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
325 | .name = "Compression Quality", | ||
326 | #define QUALITY_MIN 50 | ||
327 | #define QUALITY_MAX 90 | ||
328 | #define QUALITY_DEF 80 | ||
329 | .minimum = QUALITY_MIN, | ||
330 | .maximum = QUALITY_MAX, | ||
331 | .step = 1, | ||
332 | .default_value = QUALITY_DEF, | ||
357 | }, | 333 | }, |
358 | .set = sd_setautoexposure, | 334 | .set_control = set_quality |
359 | .get = sd_getautoexposure, | ||
360 | }, | 335 | }, |
361 | }; | 336 | }; |
362 | 337 | ||
@@ -876,7 +851,7 @@ static u8 hv7131r_gain[] = { | |||
876 | }; | 851 | }; |
877 | 852 | ||
878 | static struct i2c_reg_u8 soi968_init[] = { | 853 | static struct i2c_reg_u8 soi968_init[] = { |
879 | {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f}, | 854 | {0x0c, 0x00}, {0x0f, 0x1f}, |
880 | {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00}, | 855 | {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00}, |
881 | {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c}, | 856 | {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c}, |
882 | {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff}, | 857 | {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff}, |
@@ -902,7 +877,7 @@ static struct i2c_reg_u8 ov7660_init[] = { | |||
902 | }; | 877 | }; |
903 | 878 | ||
904 | static struct i2c_reg_u8 ov7670_init[] = { | 879 | static struct i2c_reg_u8 ov7670_init[] = { |
905 | {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01}, | 880 | {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01}, |
906 | {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00}, | 881 | {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00}, |
907 | {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0}, | 882 | {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0}, |
908 | {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00}, | 883 | {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00}, |
@@ -959,7 +934,7 @@ static struct i2c_reg_u8 ov7670_init[] = { | |||
959 | }; | 934 | }; |
960 | 935 | ||
961 | static struct i2c_reg_u8 ov9650_init[] = { | 936 | static struct i2c_reg_u8 ov9650_init[] = { |
962 | {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78}, | 937 | {0x00, 0x00}, {0x01, 0x78}, |
963 | {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03}, | 938 | {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03}, |
964 | {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00}, | 939 | {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00}, |
965 | {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00}, | 940 | {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00}, |
@@ -989,7 +964,7 @@ static struct i2c_reg_u8 ov9650_init[] = { | |||
989 | }; | 964 | }; |
990 | 965 | ||
991 | static struct i2c_reg_u8 ov9655_init[] = { | 966 | static struct i2c_reg_u8 ov9655_init[] = { |
992 | {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba}, | 967 | {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba}, |
993 | {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08}, | 968 | {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08}, |
994 | {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d}, | 969 | {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d}, |
995 | {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57}, | 970 | {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57}, |
@@ -1112,10 +1087,13 @@ static struct i2c_reg_u8 hv7131r_init[] = { | |||
1112 | {0x23, 0x09}, {0x01, 0x08}, | 1087 | {0x23, 0x09}, {0x01, 0x08}, |
1113 | }; | 1088 | }; |
1114 | 1089 | ||
1115 | static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) | 1090 | static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) |
1116 | { | 1091 | { |
1117 | struct usb_device *dev = gspca_dev->dev; | 1092 | struct usb_device *dev = gspca_dev->dev; |
1118 | int result; | 1093 | int result; |
1094 | |||
1095 | if (gspca_dev->usb_err < 0) | ||
1096 | return; | ||
1119 | result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | 1097 | result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), |
1120 | 0x00, | 1098 | 0x00, |
1121 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 1099 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
@@ -1125,17 +1103,19 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) | |||
1125 | length, | 1103 | length, |
1126 | 500); | 1104 | 500); |
1127 | if (unlikely(result < 0 || result != length)) { | 1105 | if (unlikely(result < 0 || result != length)) { |
1128 | pr_err("Read register failed 0x%02X\n", reg); | 1106 | pr_err("Read register %02x failed %d\n", reg, result); |
1129 | return -EIO; | 1107 | gspca_dev->usb_err = result; |
1130 | } | 1108 | } |
1131 | return 0; | ||
1132 | } | 1109 | } |
1133 | 1110 | ||
1134 | static int reg_w(struct gspca_dev *gspca_dev, u16 reg, | 1111 | static void reg_w(struct gspca_dev *gspca_dev, u16 reg, |
1135 | const u8 *buffer, int length) | 1112 | const u8 *buffer, int length) |
1136 | { | 1113 | { |
1137 | struct usb_device *dev = gspca_dev->dev; | 1114 | struct usb_device *dev = gspca_dev->dev; |
1138 | int result; | 1115 | int result; |
1116 | |||
1117 | if (gspca_dev->usb_err < 0) | ||
1118 | return; | ||
1139 | memcpy(gspca_dev->usb_buf, buffer, length); | 1119 | memcpy(gspca_dev->usb_buf, buffer, length); |
1140 | result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 1120 | result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
1141 | 0x08, | 1121 | 0x08, |
@@ -1146,38 +1126,41 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg, | |||
1146 | length, | 1126 | length, |
1147 | 500); | 1127 | 500); |
1148 | if (unlikely(result < 0 || result != length)) { | 1128 | if (unlikely(result < 0 || result != length)) { |
1149 | pr_err("Write register failed index 0x%02X\n", reg); | 1129 | pr_err("Write register %02x failed %d\n", reg, result); |
1150 | return -EIO; | 1130 | gspca_dev->usb_err = result; |
1151 | } | 1131 | } |
1152 | return 0; | ||
1153 | } | 1132 | } |
1154 | 1133 | ||
1155 | static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) | 1134 | static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) |
1156 | { | 1135 | { |
1157 | u8 data[1] = {value}; | 1136 | reg_w(gspca_dev, reg, &value, 1); |
1158 | return reg_w(gspca_dev, reg, data, 1); | ||
1159 | } | 1137 | } |
1160 | 1138 | ||
1161 | static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) | 1139 | static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) |
1162 | { | 1140 | { |
1163 | int i; | 1141 | int i; |
1142 | |||
1164 | reg_w(gspca_dev, 0x10c0, buffer, 8); | 1143 | reg_w(gspca_dev, 0x10c0, buffer, 8); |
1165 | for (i = 0; i < 5; i++) { | 1144 | for (i = 0; i < 5; i++) { |
1166 | reg_r(gspca_dev, 0x10c0, 1); | 1145 | reg_r(gspca_dev, 0x10c0, 1); |
1146 | if (gspca_dev->usb_err < 0) | ||
1147 | return; | ||
1167 | if (gspca_dev->usb_buf[0] & 0x04) { | 1148 | if (gspca_dev->usb_buf[0] & 0x04) { |
1168 | if (gspca_dev->usb_buf[0] & 0x08) | 1149 | if (gspca_dev->usb_buf[0] & 0x08) { |
1169 | return -EIO; | 1150 | pr_err("i2c_w error\n"); |
1170 | return 0; | 1151 | gspca_dev->usb_err = -EIO; |
1152 | } | ||
1153 | return; | ||
1171 | } | 1154 | } |
1172 | msleep(1); | 1155 | msleep(10); |
1173 | } | 1156 | } |
1174 | return -EIO; | 1157 | pr_err("i2c_w reg %02x no response\n", buffer[2]); |
1158 | /* gspca_dev->usb_err = -EIO; fixme: may occur */ | ||
1175 | } | 1159 | } |
1176 | 1160 | ||
1177 | static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) | 1161 | static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) |
1178 | { | 1162 | { |
1179 | struct sd *sd = (struct sd *) gspca_dev; | 1163 | struct sd *sd = (struct sd *) gspca_dev; |
1180 | |||
1181 | u8 row[8]; | 1164 | u8 row[8]; |
1182 | 1165 | ||
1183 | /* | 1166 | /* |
@@ -1193,10 +1176,19 @@ static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) | |||
1193 | row[6] = 0x00; | 1176 | row[6] = 0x00; |
1194 | row[7] = 0x10; | 1177 | row[7] = 0x10; |
1195 | 1178 | ||
1196 | return i2c_w(gspca_dev, row); | 1179 | i2c_w(gspca_dev, row); |
1180 | } | ||
1181 | |||
1182 | static void i2c_w1_buf(struct gspca_dev *gspca_dev, | ||
1183 | struct i2c_reg_u8 *buf, int sz) | ||
1184 | { | ||
1185 | while (--sz >= 0) { | ||
1186 | i2c_w1(gspca_dev, buf->reg, buf->val); | ||
1187 | buf++; | ||
1188 | } | ||
1197 | } | 1189 | } |
1198 | 1190 | ||
1199 | static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) | 1191 | static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) |
1200 | { | 1192 | { |
1201 | struct sd *sd = (struct sd *) gspca_dev; | 1193 | struct sd *sd = (struct sd *) gspca_dev; |
1202 | u8 row[8]; | 1194 | u8 row[8]; |
@@ -1208,16 +1200,25 @@ static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) | |||
1208 | row[0] = 0x81 | (3 << 4); | 1200 | row[0] = 0x81 | (3 << 4); |
1209 | row[1] = sd->i2c_addr; | 1201 | row[1] = sd->i2c_addr; |
1210 | row[2] = reg; | 1202 | row[2] = reg; |
1211 | row[3] = (val >> 8) & 0xff; | 1203 | row[3] = val >> 8; |
1212 | row[4] = val & 0xff; | 1204 | row[4] = val; |
1213 | row[5] = 0x00; | 1205 | row[5] = 0x00; |
1214 | row[6] = 0x00; | 1206 | row[6] = 0x00; |
1215 | row[7] = 0x10; | 1207 | row[7] = 0x10; |
1216 | 1208 | ||
1217 | return i2c_w(gspca_dev, row); | 1209 | i2c_w(gspca_dev, row); |
1210 | } | ||
1211 | |||
1212 | static void i2c_w2_buf(struct gspca_dev *gspca_dev, | ||
1213 | struct i2c_reg_u16 *buf, int sz) | ||
1214 | { | ||
1215 | while (--sz >= 0) { | ||
1216 | i2c_w2(gspca_dev, buf->reg, buf->val); | ||
1217 | buf++; | ||
1218 | } | ||
1218 | } | 1219 | } |
1219 | 1220 | ||
1220 | static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) | 1221 | static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) |
1221 | { | 1222 | { |
1222 | struct sd *sd = (struct sd *) gspca_dev; | 1223 | struct sd *sd = (struct sd *) gspca_dev; |
1223 | u8 row[8]; | 1224 | u8 row[8]; |
@@ -1230,19 +1231,15 @@ static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) | |||
1230 | row[5] = 0; | 1231 | row[5] = 0; |
1231 | row[6] = 0; | 1232 | row[6] = 0; |
1232 | row[7] = 0x10; | 1233 | row[7] = 0x10; |
1233 | if (i2c_w(gspca_dev, row) < 0) | 1234 | i2c_w(gspca_dev, row); |
1234 | return -EIO; | ||
1235 | row[0] = 0x81 | (1 << 4) | 0x02; | 1235 | row[0] = 0x81 | (1 << 4) | 0x02; |
1236 | row[2] = 0; | 1236 | row[2] = 0; |
1237 | if (i2c_w(gspca_dev, row) < 0) | 1237 | i2c_w(gspca_dev, row); |
1238 | return -EIO; | 1238 | reg_r(gspca_dev, 0x10c2, 5); |
1239 | if (reg_r(gspca_dev, 0x10c2, 5) < 0) | ||
1240 | return -EIO; | ||
1241 | *val = gspca_dev->usb_buf[4]; | 1239 | *val = gspca_dev->usb_buf[4]; |
1242 | return 0; | ||
1243 | } | 1240 | } |
1244 | 1241 | ||
1245 | static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) | 1242 | static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) |
1246 | { | 1243 | { |
1247 | struct sd *sd = (struct sd *) gspca_dev; | 1244 | struct sd *sd = (struct sd *) gspca_dev; |
1248 | u8 row[8]; | 1245 | u8 row[8]; |
@@ -1255,233 +1252,204 @@ static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) | |||
1255 | row[5] = 0; | 1252 | row[5] = 0; |
1256 | row[6] = 0; | 1253 | row[6] = 0; |
1257 | row[7] = 0x10; | 1254 | row[7] = 0x10; |
1258 | if (i2c_w(gspca_dev, row) < 0) | 1255 | i2c_w(gspca_dev, row); |
1259 | return -EIO; | ||
1260 | row[0] = 0x81 | (2 << 4) | 0x02; | 1256 | row[0] = 0x81 | (2 << 4) | 0x02; |
1261 | row[2] = 0; | 1257 | row[2] = 0; |
1262 | if (i2c_w(gspca_dev, row) < 0) | 1258 | i2c_w(gspca_dev, row); |
1263 | return -EIO; | 1259 | reg_r(gspca_dev, 0x10c2, 5); |
1264 | if (reg_r(gspca_dev, 0x10c2, 5) < 0) | ||
1265 | return -EIO; | ||
1266 | *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; | 1260 | *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; |
1267 | return 0; | ||
1268 | } | 1261 | } |
1269 | 1262 | ||
1270 | static int ov9650_init_sensor(struct gspca_dev *gspca_dev) | 1263 | static void ov9650_init_sensor(struct gspca_dev *gspca_dev) |
1271 | { | 1264 | { |
1272 | int i; | ||
1273 | u16 id; | 1265 | u16 id; |
1274 | struct sd *sd = (struct sd *) gspca_dev; | 1266 | struct sd *sd = (struct sd *) gspca_dev; |
1275 | 1267 | ||
1276 | if (i2c_r2(gspca_dev, 0x1c, &id) < 0) | 1268 | i2c_r2(gspca_dev, 0x1c, &id); |
1277 | return -EINVAL; | 1269 | if (gspca_dev->usb_err < 0) |
1270 | return; | ||
1278 | 1271 | ||
1279 | if (id != 0x7fa2) { | 1272 | if (id != 0x7fa2) { |
1280 | pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id); | 1273 | pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id); |
1281 | return -ENODEV; | 1274 | gspca_dev->usb_err = -ENODEV; |
1275 | return; | ||
1282 | } | 1276 | } |
1283 | 1277 | ||
1284 | for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { | 1278 | i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ |
1285 | if (i2c_w1(gspca_dev, ov9650_init[i].reg, | 1279 | msleep(200); |
1286 | ov9650_init[i].val) < 0) { | 1280 | i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init)); |
1287 | pr_err("OV9650 sensor initialization failed\n"); | 1281 | if (gspca_dev->usb_err < 0) |
1288 | return -ENODEV; | 1282 | pr_err("OV9650 sensor initialization failed\n"); |
1289 | } | ||
1290 | } | ||
1291 | sd->hstart = 1; | 1283 | sd->hstart = 1; |
1292 | sd->vstart = 7; | 1284 | sd->vstart = 7; |
1293 | return 0; | ||
1294 | } | 1285 | } |
1295 | 1286 | ||
1296 | static int ov9655_init_sensor(struct gspca_dev *gspca_dev) | 1287 | static void ov9655_init_sensor(struct gspca_dev *gspca_dev) |
1297 | { | 1288 | { |
1298 | int i; | ||
1299 | struct sd *sd = (struct sd *) gspca_dev; | 1289 | struct sd *sd = (struct sd *) gspca_dev; |
1300 | 1290 | ||
1301 | for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { | 1291 | i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ |
1302 | if (i2c_w1(gspca_dev, ov9655_init[i].reg, | 1292 | msleep(200); |
1303 | ov9655_init[i].val) < 0) { | 1293 | i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init)); |
1304 | pr_err("OV9655 sensor initialization failed\n"); | 1294 | if (gspca_dev->usb_err < 0) |
1305 | return -ENODEV; | 1295 | pr_err("OV9655 sensor initialization failed\n"); |
1306 | } | 1296 | |
1307 | } | ||
1308 | /* disable hflip and vflip */ | 1297 | /* disable hflip and vflip */ |
1309 | gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); | 1298 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); |
1310 | sd->hstart = 1; | 1299 | sd->hstart = 1; |
1311 | sd->vstart = 2; | 1300 | sd->vstart = 2; |
1312 | return 0; | ||
1313 | } | 1301 | } |
1314 | 1302 | ||
1315 | static int soi968_init_sensor(struct gspca_dev *gspca_dev) | 1303 | static void soi968_init_sensor(struct gspca_dev *gspca_dev) |
1316 | { | 1304 | { |
1317 | int i; | ||
1318 | struct sd *sd = (struct sd *) gspca_dev; | 1305 | struct sd *sd = (struct sd *) gspca_dev; |
1319 | 1306 | ||
1320 | for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { | 1307 | i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ |
1321 | if (i2c_w1(gspca_dev, soi968_init[i].reg, | 1308 | msleep(200); |
1322 | soi968_init[i].val) < 0) { | 1309 | i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init)); |
1323 | pr_err("SOI968 sensor initialization failed\n"); | 1310 | if (gspca_dev->usb_err < 0) |
1324 | return -ENODEV; | 1311 | pr_err("SOI968 sensor initialization failed\n"); |
1325 | } | 1312 | |
1326 | } | ||
1327 | /* disable hflip and vflip */ | 1313 | /* disable hflip and vflip */ |
1328 | gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | 1314 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP) |
1329 | | (1 << EXPOSURE_IDX); | 1315 | | (1 << EXPOSURE); |
1330 | sd->hstart = 60; | 1316 | sd->hstart = 60; |
1331 | sd->vstart = 11; | 1317 | sd->vstart = 11; |
1332 | return 0; | ||
1333 | } | 1318 | } |
1334 | 1319 | ||
1335 | static int ov7660_init_sensor(struct gspca_dev *gspca_dev) | 1320 | static void ov7660_init_sensor(struct gspca_dev *gspca_dev) |
1336 | { | 1321 | { |
1337 | int i; | ||
1338 | struct sd *sd = (struct sd *) gspca_dev; | 1322 | struct sd *sd = (struct sd *) gspca_dev; |
1339 | 1323 | ||
1340 | for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { | 1324 | i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ |
1341 | if (i2c_w1(gspca_dev, ov7660_init[i].reg, | 1325 | msleep(200); |
1342 | ov7660_init[i].val) < 0) { | 1326 | i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init)); |
1343 | pr_err("OV7660 sensor initialization failed\n"); | 1327 | if (gspca_dev->usb_err < 0) |
1344 | return -ENODEV; | 1328 | pr_err("OV7660 sensor initialization failed\n"); |
1345 | } | ||
1346 | } | ||
1347 | sd->hstart = 3; | 1329 | sd->hstart = 3; |
1348 | sd->vstart = 3; | 1330 | sd->vstart = 3; |
1349 | return 0; | ||
1350 | } | 1331 | } |
1351 | 1332 | ||
1352 | static int ov7670_init_sensor(struct gspca_dev *gspca_dev) | 1333 | static void ov7670_init_sensor(struct gspca_dev *gspca_dev) |
1353 | { | 1334 | { |
1354 | int i; | ||
1355 | struct sd *sd = (struct sd *) gspca_dev; | 1335 | struct sd *sd = (struct sd *) gspca_dev; |
1356 | 1336 | ||
1357 | for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { | 1337 | i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ |
1358 | if (i2c_w1(gspca_dev, ov7670_init[i].reg, | 1338 | msleep(200); |
1359 | ov7670_init[i].val) < 0) { | 1339 | i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init)); |
1360 | pr_err("OV7670 sensor initialization failed\n"); | 1340 | if (gspca_dev->usb_err < 0) |
1361 | return -ENODEV; | 1341 | pr_err("OV7670 sensor initialization failed\n"); |
1362 | } | 1342 | |
1363 | } | ||
1364 | /* disable hflip and vflip */ | 1343 | /* disable hflip and vflip */ |
1365 | gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); | 1344 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); |
1366 | sd->hstart = 0; | 1345 | sd->hstart = 0; |
1367 | sd->vstart = 1; | 1346 | sd->vstart = 1; |
1368 | return 0; | ||
1369 | } | 1347 | } |
1370 | 1348 | ||
1371 | static int mt9v_init_sensor(struct gspca_dev *gspca_dev) | 1349 | static void mt9v_init_sensor(struct gspca_dev *gspca_dev) |
1372 | { | 1350 | { |
1373 | struct sd *sd = (struct sd *) gspca_dev; | 1351 | struct sd *sd = (struct sd *) gspca_dev; |
1374 | int i; | ||
1375 | u16 value; | 1352 | u16 value; |
1376 | int ret; | ||
1377 | 1353 | ||
1378 | sd->i2c_addr = 0x5d; | 1354 | sd->i2c_addr = 0x5d; |
1379 | ret = i2c_r2(gspca_dev, 0xff, &value); | 1355 | i2c_r2(gspca_dev, 0xff, &value); |
1380 | if ((ret == 0) && (value == 0x8243)) { | 1356 | if (gspca_dev->usb_err >= 0 |
1381 | for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { | 1357 | && value == 0x8243) { |
1382 | if (i2c_w2(gspca_dev, mt9v011_init[i].reg, | 1358 | i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init)); |
1383 | mt9v011_init[i].val) < 0) { | 1359 | if (gspca_dev->usb_err < 0) { |
1384 | pr_err("MT9V011 sensor initialization failed\n"); | 1360 | pr_err("MT9V011 sensor initialization failed\n"); |
1385 | return -ENODEV; | 1361 | return; |
1386 | } | ||
1387 | } | 1362 | } |
1388 | sd->hstart = 2; | 1363 | sd->hstart = 2; |
1389 | sd->vstart = 2; | 1364 | sd->vstart = 2; |
1390 | sd->sensor = SENSOR_MT9V011; | 1365 | sd->sensor = SENSOR_MT9V011; |
1391 | pr_info("MT9V011 sensor detected\n"); | 1366 | pr_info("MT9V011 sensor detected\n"); |
1392 | return 0; | 1367 | return; |
1393 | } | 1368 | } |
1394 | 1369 | ||
1370 | gspca_dev->usb_err = 0; | ||
1395 | sd->i2c_addr = 0x5c; | 1371 | sd->i2c_addr = 0x5c; |
1396 | i2c_w2(gspca_dev, 0x01, 0x0004); | 1372 | i2c_w2(gspca_dev, 0x01, 0x0004); |
1397 | ret = i2c_r2(gspca_dev, 0xff, &value); | 1373 | i2c_r2(gspca_dev, 0xff, &value); |
1398 | if ((ret == 0) && (value == 0x823a)) { | 1374 | if (gspca_dev->usb_err >= 0 |
1399 | for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { | 1375 | && value == 0x823a) { |
1400 | if (i2c_w2(gspca_dev, mt9v111_init[i].reg, | 1376 | i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init)); |
1401 | mt9v111_init[i].val) < 0) { | 1377 | if (gspca_dev->usb_err < 0) { |
1402 | pr_err("MT9V111 sensor initialization failed\n"); | 1378 | pr_err("MT9V111 sensor initialization failed\n"); |
1403 | return -ENODEV; | 1379 | return; |
1404 | } | ||
1405 | } | 1380 | } |
1406 | gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | 1381 | gspca_dev->ctrl_dis = (1 << EXPOSURE) |
1407 | | (1 << AUTOGAIN_IDX) | 1382 | | (1 << AUTOGAIN) |
1408 | | (1 << GAIN_IDX); | 1383 | | (1 << GAIN); |
1409 | sd->hstart = 2; | 1384 | sd->hstart = 2; |
1410 | sd->vstart = 2; | 1385 | sd->vstart = 2; |
1411 | sd->sensor = SENSOR_MT9V111; | 1386 | sd->sensor = SENSOR_MT9V111; |
1412 | pr_info("MT9V111 sensor detected\n"); | 1387 | pr_info("MT9V111 sensor detected\n"); |
1413 | return 0; | 1388 | return; |
1414 | } | 1389 | } |
1415 | 1390 | ||
1391 | gspca_dev->usb_err = 0; | ||
1416 | sd->i2c_addr = 0x5d; | 1392 | sd->i2c_addr = 0x5d; |
1417 | ret = i2c_w2(gspca_dev, 0xf0, 0x0000); | 1393 | i2c_w2(gspca_dev, 0xf0, 0x0000); |
1418 | if (ret < 0) { | 1394 | if (gspca_dev->usb_err < 0) { |
1395 | gspca_dev->usb_err = 0; | ||
1419 | sd->i2c_addr = 0x48; | 1396 | sd->i2c_addr = 0x48; |
1420 | i2c_w2(gspca_dev, 0xf0, 0x0000); | 1397 | i2c_w2(gspca_dev, 0xf0, 0x0000); |
1421 | } | 1398 | } |
1422 | ret = i2c_r2(gspca_dev, 0x00, &value); | 1399 | i2c_r2(gspca_dev, 0x00, &value); |
1423 | if ((ret == 0) && (value == 0x1229)) { | 1400 | if (gspca_dev->usb_err >= 0 |
1424 | for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { | 1401 | && value == 0x1229) { |
1425 | if (i2c_w2(gspca_dev, mt9v112_init[i].reg, | 1402 | i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init)); |
1426 | mt9v112_init[i].val) < 0) { | 1403 | if (gspca_dev->usb_err < 0) { |
1427 | pr_err("MT9V112 sensor initialization failed\n"); | 1404 | pr_err("MT9V112 sensor initialization failed\n"); |
1428 | return -ENODEV; | 1405 | return; |
1429 | } | ||
1430 | } | 1406 | } |
1431 | sd->hstart = 6; | 1407 | sd->hstart = 6; |
1432 | sd->vstart = 2; | 1408 | sd->vstart = 2; |
1433 | sd->sensor = SENSOR_MT9V112; | 1409 | sd->sensor = SENSOR_MT9V112; |
1434 | pr_info("MT9V112 sensor detected\n"); | 1410 | pr_info("MT9V112 sensor detected\n"); |
1435 | return 0; | 1411 | return; |
1436 | } | 1412 | } |
1437 | 1413 | ||
1438 | return -ENODEV; | 1414 | gspca_dev->usb_err = -ENODEV; |
1439 | } | 1415 | } |
1440 | 1416 | ||
1441 | static int mt9m112_init_sensor(struct gspca_dev *gspca_dev) | 1417 | static void mt9m112_init_sensor(struct gspca_dev *gspca_dev) |
1442 | { | 1418 | { |
1443 | struct sd *sd = (struct sd *) gspca_dev; | 1419 | struct sd *sd = (struct sd *) gspca_dev; |
1444 | int i; | 1420 | |
1445 | for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) { | 1421 | i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init)); |
1446 | if (i2c_w2(gspca_dev, mt9m112_init[i].reg, | 1422 | if (gspca_dev->usb_err < 0) |
1447 | mt9m112_init[i].val) < 0) { | 1423 | pr_err("MT9M112 sensor initialization failed\n"); |
1448 | pr_err("MT9M112 sensor initialization failed\n"); | 1424 | |
1449 | return -ENODEV; | 1425 | gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) |
1450 | } | 1426 | | (1 << GAIN); |
1451 | } | ||
1452 | gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | ||
1453 | | (1 << GAIN_IDX); | ||
1454 | sd->hstart = 0; | 1427 | sd->hstart = 0; |
1455 | sd->vstart = 2; | 1428 | sd->vstart = 2; |
1456 | return 0; | ||
1457 | } | 1429 | } |
1458 | 1430 | ||
1459 | static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) | 1431 | static void mt9m111_init_sensor(struct gspca_dev *gspca_dev) |
1460 | { | 1432 | { |
1461 | struct sd *sd = (struct sd *) gspca_dev; | 1433 | struct sd *sd = (struct sd *) gspca_dev; |
1462 | int i; | 1434 | |
1463 | for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { | 1435 | i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init)); |
1464 | if (i2c_w2(gspca_dev, mt9m111_init[i].reg, | 1436 | if (gspca_dev->usb_err < 0) |
1465 | mt9m111_init[i].val) < 0) { | 1437 | pr_err("MT9M111 sensor initialization failed\n"); |
1466 | pr_err("MT9M111 sensor initialization failed\n"); | 1438 | |
1467 | return -ENODEV; | 1439 | gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) |
1468 | } | 1440 | | (1 << GAIN); |
1469 | } | ||
1470 | gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | ||
1471 | | (1 << GAIN_IDX); | ||
1472 | sd->hstart = 0; | 1441 | sd->hstart = 0; |
1473 | sd->vstart = 2; | 1442 | sd->vstart = 2; |
1474 | return 0; | ||
1475 | } | 1443 | } |
1476 | 1444 | ||
1477 | static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) | 1445 | static void mt9m001_init_sensor(struct gspca_dev *gspca_dev) |
1478 | { | 1446 | { |
1479 | struct sd *sd = (struct sd *) gspca_dev; | 1447 | struct sd *sd = (struct sd *) gspca_dev; |
1480 | int i; | ||
1481 | u16 id; | 1448 | u16 id; |
1482 | 1449 | ||
1483 | if (i2c_r2(gspca_dev, 0x00, &id) < 0) | 1450 | i2c_r2(gspca_dev, 0x00, &id); |
1484 | return -EINVAL; | 1451 | if (gspca_dev->usb_err < 0) |
1452 | return; | ||
1485 | 1453 | ||
1486 | /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ | 1454 | /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ |
1487 | switch (id) { | 1455 | switch (id) { |
@@ -1494,85 +1462,78 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) | |||
1494 | break; | 1462 | break; |
1495 | default: | 1463 | default: |
1496 | pr_err("No MT9M001 chip detected, ID = %x\n\n", id); | 1464 | pr_err("No MT9M001 chip detected, ID = %x\n\n", id); |
1497 | return -ENODEV; | 1465 | gspca_dev->usb_err = -ENODEV; |
1466 | return; | ||
1498 | } | 1467 | } |
1499 | 1468 | ||
1500 | for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { | 1469 | i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init)); |
1501 | if (i2c_w2(gspca_dev, mt9m001_init[i].reg, | 1470 | if (gspca_dev->usb_err < 0) |
1502 | mt9m001_init[i].val) < 0) { | 1471 | pr_err("MT9M001 sensor initialization failed\n"); |
1503 | pr_err("MT9M001 sensor initialization failed\n"); | 1472 | |
1504 | return -ENODEV; | ||
1505 | } | ||
1506 | } | ||
1507 | /* disable hflip and vflip */ | 1473 | /* disable hflip and vflip */ |
1508 | gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); | 1474 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); |
1509 | sd->hstart = 1; | 1475 | sd->hstart = 1; |
1510 | sd->vstart = 1; | 1476 | sd->vstart = 1; |
1511 | return 0; | ||
1512 | } | 1477 | } |
1513 | 1478 | ||
1514 | static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) | 1479 | static void hv7131r_init_sensor(struct gspca_dev *gspca_dev) |
1515 | { | 1480 | { |
1516 | int i; | ||
1517 | struct sd *sd = (struct sd *) gspca_dev; | 1481 | struct sd *sd = (struct sd *) gspca_dev; |
1518 | 1482 | ||
1519 | for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { | 1483 | i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init)); |
1520 | if (i2c_w1(gspca_dev, hv7131r_init[i].reg, | 1484 | if (gspca_dev->usb_err < 0) |
1521 | hv7131r_init[i].val) < 0) { | 1485 | pr_err("HV7131R Sensor initialization failed\n"); |
1522 | pr_err("HV7131R Sensor initialization failed\n"); | 1486 | |
1523 | return -ENODEV; | ||
1524 | } | ||
1525 | } | ||
1526 | sd->hstart = 0; | 1487 | sd->hstart = 0; |
1527 | sd->vstart = 1; | 1488 | sd->vstart = 1; |
1528 | return 0; | ||
1529 | } | 1489 | } |
1530 | 1490 | ||
1531 | static int set_cmatrix(struct gspca_dev *gspca_dev) | 1491 | static void set_cmatrix(struct gspca_dev *gspca_dev) |
1532 | { | 1492 | { |
1533 | struct sd *sd = (struct sd *) gspca_dev; | 1493 | struct sd *sd = (struct sd *) gspca_dev; |
1534 | s32 hue_coord, hue_index = 180 + sd->hue; | 1494 | int satur; |
1495 | s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val; | ||
1535 | u8 cmatrix[21]; | 1496 | u8 cmatrix[21]; |
1536 | 1497 | ||
1537 | memset(cmatrix, 0, sizeof cmatrix); | 1498 | memset(cmatrix, 0, sizeof cmatrix); |
1538 | cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26; | 1499 | cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26; |
1539 | cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; | 1500 | cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; |
1540 | cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; | 1501 | cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; |
1541 | cmatrix[18] = sd->brightness - 0x80; | 1502 | cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80; |
1542 | 1503 | ||
1543 | hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8; | 1504 | satur = sd->ctrls[SATURATION].val; |
1505 | hue_coord = (hsv_red_x[hue_index] * satur) >> 8; | ||
1544 | cmatrix[6] = hue_coord; | 1506 | cmatrix[6] = hue_coord; |
1545 | cmatrix[7] = (hue_coord >> 8) & 0x0f; | 1507 | cmatrix[7] = (hue_coord >> 8) & 0x0f; |
1546 | 1508 | ||
1547 | hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8; | 1509 | hue_coord = (hsv_red_y[hue_index] * satur) >> 8; |
1548 | cmatrix[8] = hue_coord; | 1510 | cmatrix[8] = hue_coord; |
1549 | cmatrix[9] = (hue_coord >> 8) & 0x0f; | 1511 | cmatrix[9] = (hue_coord >> 8) & 0x0f; |
1550 | 1512 | ||
1551 | hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8; | 1513 | hue_coord = (hsv_green_x[hue_index] * satur) >> 8; |
1552 | cmatrix[10] = hue_coord; | 1514 | cmatrix[10] = hue_coord; |
1553 | cmatrix[11] = (hue_coord >> 8) & 0x0f; | 1515 | cmatrix[11] = (hue_coord >> 8) & 0x0f; |
1554 | 1516 | ||
1555 | hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8; | 1517 | hue_coord = (hsv_green_y[hue_index] * satur) >> 8; |
1556 | cmatrix[12] = hue_coord; | 1518 | cmatrix[12] = hue_coord; |
1557 | cmatrix[13] = (hue_coord >> 8) & 0x0f; | 1519 | cmatrix[13] = (hue_coord >> 8) & 0x0f; |
1558 | 1520 | ||
1559 | hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8; | 1521 | hue_coord = (hsv_blue_x[hue_index] * satur) >> 8; |
1560 | cmatrix[14] = hue_coord; | 1522 | cmatrix[14] = hue_coord; |
1561 | cmatrix[15] = (hue_coord >> 8) & 0x0f; | 1523 | cmatrix[15] = (hue_coord >> 8) & 0x0f; |
1562 | 1524 | ||
1563 | hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8; | 1525 | hue_coord = (hsv_blue_y[hue_index] * satur) >> 8; |
1564 | cmatrix[16] = hue_coord; | 1526 | cmatrix[16] = hue_coord; |
1565 | cmatrix[17] = (hue_coord >> 8) & 0x0f; | 1527 | cmatrix[17] = (hue_coord >> 8) & 0x0f; |
1566 | 1528 | ||
1567 | return reg_w(gspca_dev, 0x10e1, cmatrix, 21); | 1529 | reg_w(gspca_dev, 0x10e1, cmatrix, 21); |
1568 | } | 1530 | } |
1569 | 1531 | ||
1570 | static int set_gamma(struct gspca_dev *gspca_dev) | 1532 | static void set_gamma(struct gspca_dev *gspca_dev) |
1571 | { | 1533 | { |
1572 | struct sd *sd = (struct sd *) gspca_dev; | 1534 | struct sd *sd = (struct sd *) gspca_dev; |
1573 | u8 gamma[17]; | 1535 | u8 gamma[17]; |
1574 | u8 gval = sd->gamma * 0xb8 / 0x100; | 1536 | u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100; |
1575 | |||
1576 | 1537 | ||
1577 | gamma[0] = 0x0a; | 1538 | gamma[0] = 0x0a; |
1578 | gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); | 1539 | gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); |
@@ -1592,29 +1553,29 @@ static int set_gamma(struct gspca_dev *gspca_dev) | |||
1592 | gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8); | 1553 | gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8); |
1593 | gamma[16] = 0xf5; | 1554 | gamma[16] = 0xf5; |
1594 | 1555 | ||
1595 | return reg_w(gspca_dev, 0x1190, gamma, 17); | 1556 | reg_w(gspca_dev, 0x1190, gamma, 17); |
1596 | } | 1557 | } |
1597 | 1558 | ||
1598 | static int set_redblue(struct gspca_dev *gspca_dev) | 1559 | static void set_redblue(struct gspca_dev *gspca_dev) |
1599 | { | 1560 | { |
1600 | struct sd *sd = (struct sd *) gspca_dev; | 1561 | struct sd *sd = (struct sd *) gspca_dev; |
1601 | reg_w1(gspca_dev, 0x118c, sd->red); | 1562 | |
1602 | reg_w1(gspca_dev, 0x118f, sd->blue); | 1563 | reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val); |
1603 | return 0; | 1564 | reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val); |
1604 | } | 1565 | } |
1605 | 1566 | ||
1606 | static int set_hvflip(struct gspca_dev *gspca_dev) | 1567 | static void set_hvflip(struct gspca_dev *gspca_dev) |
1607 | { | 1568 | { |
1608 | u8 value, tslb, hflip, vflip; | 1569 | u8 value, tslb, hflip, vflip; |
1609 | u16 value2; | 1570 | u16 value2; |
1610 | struct sd *sd = (struct sd *) gspca_dev; | 1571 | struct sd *sd = (struct sd *) gspca_dev; |
1611 | 1572 | ||
1612 | if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { | 1573 | if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { |
1613 | hflip = !sd->hflip; | 1574 | hflip = !sd->ctrls[HFLIP].val; |
1614 | vflip = !sd->vflip; | 1575 | vflip = !sd->ctrls[VFLIP].val; |
1615 | } else { | 1576 | } else { |
1616 | hflip = sd->hflip; | 1577 | hflip = sd->ctrls[HFLIP].val; |
1617 | vflip = sd->vflip; | 1578 | vflip = sd->ctrls[VFLIP].val; |
1618 | } | 1579 | } |
1619 | 1580 | ||
1620 | switch (sd->sensor) { | 1581 | switch (sd->sensor) { |
@@ -1625,8 +1586,9 @@ static int set_hvflip(struct gspca_dev *gspca_dev) | |||
1625 | if (vflip) { | 1586 | if (vflip) { |
1626 | value |= 0x10; | 1587 | value |= 0x10; |
1627 | sd->vstart = 2; | 1588 | sd->vstart = 2; |
1628 | } else | 1589 | } else { |
1629 | sd->vstart = 3; | 1590 | sd->vstart = 3; |
1591 | } | ||
1630 | reg_w1(gspca_dev, 0x1182, sd->vstart); | 1592 | reg_w1(gspca_dev, 0x1182, sd->vstart); |
1631 | i2c_w1(gspca_dev, 0x1e, value); | 1593 | i2c_w1(gspca_dev, 0x1e, value); |
1632 | break; | 1594 | break; |
@@ -1674,13 +1636,15 @@ static int set_hvflip(struct gspca_dev *gspca_dev) | |||
1674 | i2c_w1(gspca_dev, 0x01, value); | 1636 | i2c_w1(gspca_dev, 0x01, value); |
1675 | break; | 1637 | break; |
1676 | } | 1638 | } |
1677 | return 0; | ||
1678 | } | 1639 | } |
1679 | 1640 | ||
1680 | static int set_exposure(struct gspca_dev *gspca_dev) | 1641 | static void set_exposure(struct gspca_dev *gspca_dev) |
1681 | { | 1642 | { |
1682 | struct sd *sd = (struct sd *) gspca_dev; | 1643 | struct sd *sd = (struct sd *) gspca_dev; |
1683 | u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; | 1644 | u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; |
1645 | int expo; | ||
1646 | |||
1647 | expo = sd->ctrls[EXPOSURE].val; | ||
1684 | switch (sd->sensor) { | 1648 | switch (sd->sensor) { |
1685 | case SENSOR_OV7660: | 1649 | case SENSOR_OV7660: |
1686 | case SENSOR_OV7670: | 1650 | case SENSOR_OV7670: |
@@ -1688,35 +1652,37 @@ static int set_exposure(struct gspca_dev *gspca_dev) | |||
1688 | case SENSOR_OV9650: | 1652 | case SENSOR_OV9650: |
1689 | exp[0] |= (3 << 4); | 1653 | exp[0] |= (3 << 4); |
1690 | exp[2] = 0x2d; | 1654 | exp[2] = 0x2d; |
1691 | exp[3] = sd->exposure & 0xff; | 1655 | exp[3] = expo; |
1692 | exp[4] = sd->exposure >> 8; | 1656 | exp[4] = expo >> 8; |
1693 | break; | 1657 | break; |
1694 | case SENSOR_MT9M001: | 1658 | case SENSOR_MT9M001: |
1695 | case SENSOR_MT9V112: | 1659 | case SENSOR_MT9V112: |
1696 | case SENSOR_MT9V011: | 1660 | case SENSOR_MT9V011: |
1697 | exp[0] |= (3 << 4); | 1661 | exp[0] |= (3 << 4); |
1698 | exp[2] = 0x09; | 1662 | exp[2] = 0x09; |
1699 | exp[3] = sd->exposure >> 8; | 1663 | exp[3] = expo >> 8; |
1700 | exp[4] = sd->exposure & 0xff; | 1664 | exp[4] = expo; |
1701 | break; | 1665 | break; |
1702 | case SENSOR_HV7131R: | 1666 | case SENSOR_HV7131R: |
1703 | exp[0] |= (4 << 4); | 1667 | exp[0] |= (4 << 4); |
1704 | exp[2] = 0x25; | 1668 | exp[2] = 0x25; |
1705 | exp[3] = (sd->exposure >> 5) & 0xff; | 1669 | exp[3] = expo >> 5; |
1706 | exp[4] = (sd->exposure << 3) & 0xff; | 1670 | exp[4] = expo << 3; |
1707 | exp[5] = 0; | 1671 | exp[5] = 0; |
1708 | break; | 1672 | break; |
1709 | default: | 1673 | default: |
1710 | return 0; | 1674 | return; |
1711 | } | 1675 | } |
1712 | i2c_w(gspca_dev, exp); | 1676 | i2c_w(gspca_dev, exp); |
1713 | return 0; | ||
1714 | } | 1677 | } |
1715 | 1678 | ||
1716 | static int set_gain(struct gspca_dev *gspca_dev) | 1679 | static void set_gain(struct gspca_dev *gspca_dev) |
1717 | { | 1680 | { |
1718 | struct sd *sd = (struct sd *) gspca_dev; | 1681 | struct sd *sd = (struct sd *) gspca_dev; |
1719 | u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; | 1682 | u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; |
1683 | int g; | ||
1684 | |||
1685 | g = sd->ctrls[GAIN].val; | ||
1720 | switch (sd->sensor) { | 1686 | switch (sd->sensor) { |
1721 | case SENSOR_OV7660: | 1687 | case SENSOR_OV7660: |
1722 | case SENSOR_OV7670: | 1688 | case SENSOR_OV7670: |
@@ -1724,238 +1690,50 @@ static int set_gain(struct gspca_dev *gspca_dev) | |||
1724 | case SENSOR_OV9655: | 1690 | case SENSOR_OV9655: |
1725 | case SENSOR_OV9650: | 1691 | case SENSOR_OV9650: |
1726 | gain[0] |= (2 << 4); | 1692 | gain[0] |= (2 << 4); |
1727 | gain[3] = ov_gain[sd->gain]; | 1693 | gain[3] = ov_gain[g]; |
1728 | break; | 1694 | break; |
1729 | case SENSOR_MT9V011: | 1695 | case SENSOR_MT9V011: |
1730 | gain[0] |= (3 << 4); | 1696 | gain[0] |= (3 << 4); |
1731 | gain[2] = 0x35; | 1697 | gain[2] = 0x35; |
1732 | gain[3] = micron1_gain[sd->gain] >> 8; | 1698 | gain[3] = micron1_gain[g] >> 8; |
1733 | gain[4] = micron1_gain[sd->gain] & 0xff; | 1699 | gain[4] = micron1_gain[g]; |
1734 | break; | 1700 | break; |
1735 | case SENSOR_MT9V112: | 1701 | case SENSOR_MT9V112: |
1736 | gain[0] |= (3 << 4); | 1702 | gain[0] |= (3 << 4); |
1737 | gain[2] = 0x2f; | 1703 | gain[2] = 0x2f; |
1738 | gain[3] = micron1_gain[sd->gain] >> 8; | 1704 | gain[3] = micron1_gain[g] >> 8; |
1739 | gain[4] = micron1_gain[sd->gain] & 0xff; | 1705 | gain[4] = micron1_gain[g]; |
1740 | break; | 1706 | break; |
1741 | case SENSOR_MT9M001: | 1707 | case SENSOR_MT9M001: |
1742 | gain[0] |= (3 << 4); | 1708 | gain[0] |= (3 << 4); |
1743 | gain[2] = 0x2f; | 1709 | gain[2] = 0x2f; |
1744 | gain[3] = micron2_gain[sd->gain] >> 8; | 1710 | gain[3] = micron2_gain[g] >> 8; |
1745 | gain[4] = micron2_gain[sd->gain] & 0xff; | 1711 | gain[4] = micron2_gain[g]; |
1746 | break; | 1712 | break; |
1747 | case SENSOR_HV7131R: | 1713 | case SENSOR_HV7131R: |
1748 | gain[0] |= (2 << 4); | 1714 | gain[0] |= (2 << 4); |
1749 | gain[2] = 0x30; | 1715 | gain[2] = 0x30; |
1750 | gain[3] = hv7131r_gain[sd->gain]; | 1716 | gain[3] = hv7131r_gain[g]; |
1751 | break; | 1717 | break; |
1752 | default: | 1718 | default: |
1753 | return 0; | 1719 | return; |
1754 | } | 1720 | } |
1755 | i2c_w(gspca_dev, gain); | 1721 | i2c_w(gspca_dev, gain); |
1756 | return 0; | ||
1757 | } | ||
1758 | |||
1759 | static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val) | ||
1760 | { | ||
1761 | struct sd *sd = (struct sd *) gspca_dev; | ||
1762 | |||
1763 | sd->brightness = val; | ||
1764 | if (gspca_dev->streaming) | ||
1765 | return set_cmatrix(gspca_dev); | ||
1766 | return 0; | ||
1767 | } | ||
1768 | |||
1769 | static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val) | ||
1770 | { | ||
1771 | struct sd *sd = (struct sd *) gspca_dev; | ||
1772 | *val = sd->brightness; | ||
1773 | return 0; | ||
1774 | } | ||
1775 | |||
1776 | |||
1777 | static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val) | ||
1778 | { | ||
1779 | struct sd *sd = (struct sd *) gspca_dev; | ||
1780 | |||
1781 | sd->contrast = val; | ||
1782 | if (gspca_dev->streaming) | ||
1783 | return set_cmatrix(gspca_dev); | ||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val) | ||
1788 | { | ||
1789 | struct sd *sd = (struct sd *) gspca_dev; | ||
1790 | *val = sd->contrast; | ||
1791 | return 0; | ||
1792 | } | ||
1793 | |||
1794 | static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val) | ||
1795 | { | ||
1796 | struct sd *sd = (struct sd *) gspca_dev; | ||
1797 | |||
1798 | sd->saturation = val; | ||
1799 | if (gspca_dev->streaming) | ||
1800 | return set_cmatrix(gspca_dev); | ||
1801 | return 0; | ||
1802 | } | 1722 | } |
1803 | 1723 | ||
1804 | static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val) | 1724 | static void set_quality(struct gspca_dev *gspca_dev) |
1805 | { | 1725 | { |
1806 | struct sd *sd = (struct sd *) gspca_dev; | 1726 | struct sd *sd = (struct sd *) gspca_dev; |
1807 | *val = sd->saturation; | ||
1808 | return 0; | ||
1809 | } | ||
1810 | |||
1811 | static int sd_sethue(struct gspca_dev *gspca_dev, s32 val) | ||
1812 | { | ||
1813 | struct sd *sd = (struct sd *) gspca_dev; | ||
1814 | |||
1815 | sd->hue = val; | ||
1816 | if (gspca_dev->streaming) | ||
1817 | return set_cmatrix(gspca_dev); | ||
1818 | return 0; | ||
1819 | } | ||
1820 | |||
1821 | static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val) | ||
1822 | { | ||
1823 | struct sd *sd = (struct sd *) gspca_dev; | ||
1824 | *val = sd->hue; | ||
1825 | return 0; | ||
1826 | } | ||
1827 | |||
1828 | static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val) | ||
1829 | { | ||
1830 | struct sd *sd = (struct sd *) gspca_dev; | ||
1831 | |||
1832 | sd->gamma = val; | ||
1833 | if (gspca_dev->streaming) | ||
1834 | return set_gamma(gspca_dev); | ||
1835 | return 0; | ||
1836 | } | ||
1837 | |||
1838 | static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val) | ||
1839 | { | ||
1840 | struct sd *sd = (struct sd *) gspca_dev; | ||
1841 | *val = sd->gamma; | ||
1842 | return 0; | ||
1843 | } | ||
1844 | |||
1845 | static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val) | ||
1846 | { | ||
1847 | struct sd *sd = (struct sd *) gspca_dev; | ||
1848 | |||
1849 | sd->red = val; | ||
1850 | if (gspca_dev->streaming) | ||
1851 | return set_redblue(gspca_dev); | ||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val) | ||
1856 | { | ||
1857 | struct sd *sd = (struct sd *) gspca_dev; | ||
1858 | *val = sd->red; | ||
1859 | return 0; | ||
1860 | } | ||
1861 | |||
1862 | static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val) | ||
1863 | { | ||
1864 | struct sd *sd = (struct sd *) gspca_dev; | ||
1865 | |||
1866 | sd->blue = val; | ||
1867 | if (gspca_dev->streaming) | ||
1868 | return set_redblue(gspca_dev); | ||
1869 | return 0; | ||
1870 | } | ||
1871 | |||
1872 | static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val) | ||
1873 | { | ||
1874 | struct sd *sd = (struct sd *) gspca_dev; | ||
1875 | *val = sd->blue; | ||
1876 | return 0; | ||
1877 | } | ||
1878 | |||
1879 | static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val) | ||
1880 | { | ||
1881 | struct sd *sd = (struct sd *) gspca_dev; | ||
1882 | |||
1883 | sd->hflip = val; | ||
1884 | if (gspca_dev->streaming) | ||
1885 | return set_hvflip(gspca_dev); | ||
1886 | return 0; | ||
1887 | } | ||
1888 | |||
1889 | static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val) | ||
1890 | { | ||
1891 | struct sd *sd = (struct sd *) gspca_dev; | ||
1892 | *val = sd->hflip; | ||
1893 | return 0; | ||
1894 | } | ||
1895 | |||
1896 | static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val) | ||
1897 | { | ||
1898 | struct sd *sd = (struct sd *) gspca_dev; | ||
1899 | |||
1900 | sd->vflip = val; | ||
1901 | if (gspca_dev->streaming) | ||
1902 | return set_hvflip(gspca_dev); | ||
1903 | return 0; | ||
1904 | } | ||
1905 | |||
1906 | static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val) | ||
1907 | { | ||
1908 | struct sd *sd = (struct sd *) gspca_dev; | ||
1909 | *val = sd->vflip; | ||
1910 | return 0; | ||
1911 | } | ||
1912 | |||
1913 | static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val) | ||
1914 | { | ||
1915 | struct sd *sd = (struct sd *) gspca_dev; | ||
1916 | |||
1917 | sd->exposure = val; | ||
1918 | if (gspca_dev->streaming) | ||
1919 | return set_exposure(gspca_dev); | ||
1920 | return 0; | ||
1921 | } | ||
1922 | |||
1923 | static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val) | ||
1924 | { | ||
1925 | struct sd *sd = (struct sd *) gspca_dev; | ||
1926 | *val = sd->exposure; | ||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | static int sd_setgain(struct gspca_dev *gspca_dev, s32 val) | ||
1931 | { | ||
1932 | struct sd *sd = (struct sd *) gspca_dev; | ||
1933 | |||
1934 | sd->gain = val; | ||
1935 | if (gspca_dev->streaming) | ||
1936 | return set_gain(gspca_dev); | ||
1937 | return 0; | ||
1938 | } | ||
1939 | |||
1940 | static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val) | ||
1941 | { | ||
1942 | struct sd *sd = (struct sd *) gspca_dev; | ||
1943 | *val = sd->gain; | ||
1944 | return 0; | ||
1945 | } | ||
1946 | |||
1947 | static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val) | ||
1948 | { | ||
1949 | struct sd *sd = (struct sd *) gspca_dev; | ||
1950 | sd->auto_exposure = val; | ||
1951 | return 0; | ||
1952 | } | ||
1953 | 1727 | ||
1954 | static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val) | 1728 | jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); |
1955 | { | 1729 | reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */ |
1956 | struct sd *sd = (struct sd *) gspca_dev; | 1730 | reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */ |
1957 | *val = sd->auto_exposure; | 1731 | reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); |
1958 | return 0; | 1732 | reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); |
1733 | reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */ | ||
1734 | reg_w1(gspca_dev, 0x10e0, sd->fmt); | ||
1735 | sd->fmt ^= 0x0c; /* invert QTAB use + write */ | ||
1736 | reg_w1(gspca_dev, 0x10e0, sd->fmt); | ||
1959 | } | 1737 | } |
1960 | 1738 | ||
1961 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1739 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -1963,28 +1741,26 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev, | |||
1963 | struct v4l2_dbg_register *reg) | 1741 | struct v4l2_dbg_register *reg) |
1964 | { | 1742 | { |
1965 | struct sd *sd = (struct sd *) gspca_dev; | 1743 | struct sd *sd = (struct sd *) gspca_dev; |
1744 | |||
1966 | switch (reg->match.type) { | 1745 | switch (reg->match.type) { |
1967 | case V4L2_CHIP_MATCH_HOST: | 1746 | case V4L2_CHIP_MATCH_HOST: |
1968 | if (reg->match.addr != 0) | 1747 | if (reg->match.addr != 0) |
1969 | return -EINVAL; | 1748 | return -EINVAL; |
1970 | if (reg->reg < 0x1000 || reg->reg > 0x11ff) | 1749 | if (reg->reg < 0x1000 || reg->reg > 0x11ff) |
1971 | return -EINVAL; | 1750 | return -EINVAL; |
1972 | if (reg_r(gspca_dev, reg->reg, 1) < 0) | 1751 | reg_r(gspca_dev, reg->reg, 1); |
1973 | return -EINVAL; | ||
1974 | reg->val = gspca_dev->usb_buf[0]; | 1752 | reg->val = gspca_dev->usb_buf[0]; |
1975 | return 0; | 1753 | return gspca_dev->usb_err; |
1976 | case V4L2_CHIP_MATCH_I2C_ADDR: | 1754 | case V4L2_CHIP_MATCH_I2C_ADDR: |
1977 | if (reg->match.addr != sd->i2c_addr) | 1755 | if (reg->match.addr != sd->i2c_addr) |
1978 | return -EINVAL; | 1756 | return -EINVAL; |
1979 | if (sd->sensor >= SENSOR_MT9V011 && | 1757 | if (sd->sensor >= SENSOR_MT9V011 && |
1980 | sd->sensor <= SENSOR_MT9M112) { | 1758 | sd->sensor <= SENSOR_MT9M112) { |
1981 | if (i2c_r2(gspca_dev, reg->reg, (u16 *)®->val) < 0) | 1759 | i2c_r2(gspca_dev, reg->reg, (u16 *) ®->val); |
1982 | return -EINVAL; | ||
1983 | } else { | 1760 | } else { |
1984 | if (i2c_r1(gspca_dev, reg->reg, (u8 *)®->val) < 0) | 1761 | i2c_r1(gspca_dev, reg->reg, (u8 *) ®->val); |
1985 | return -EINVAL; | ||
1986 | } | 1762 | } |
1987 | return 0; | 1763 | return gspca_dev->usb_err; |
1988 | } | 1764 | } |
1989 | return -EINVAL; | 1765 | return -EINVAL; |
1990 | } | 1766 | } |
@@ -1993,27 +1769,25 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev, | |||
1993 | struct v4l2_dbg_register *reg) | 1769 | struct v4l2_dbg_register *reg) |
1994 | { | 1770 | { |
1995 | struct sd *sd = (struct sd *) gspca_dev; | 1771 | struct sd *sd = (struct sd *) gspca_dev; |
1772 | |||
1996 | switch (reg->match.type) { | 1773 | switch (reg->match.type) { |
1997 | case V4L2_CHIP_MATCH_HOST: | 1774 | case V4L2_CHIP_MATCH_HOST: |
1998 | if (reg->match.addr != 0) | 1775 | if (reg->match.addr != 0) |
1999 | return -EINVAL; | 1776 | return -EINVAL; |
2000 | if (reg->reg < 0x1000 || reg->reg > 0x11ff) | 1777 | if (reg->reg < 0x1000 || reg->reg > 0x11ff) |
2001 | return -EINVAL; | 1778 | return -EINVAL; |
2002 | if (reg_w1(gspca_dev, reg->reg, reg->val) < 0) | 1779 | reg_w1(gspca_dev, reg->reg, reg->val); |
2003 | return -EINVAL; | 1780 | return gspca_dev->usb_err; |
2004 | return 0; | ||
2005 | case V4L2_CHIP_MATCH_I2C_ADDR: | 1781 | case V4L2_CHIP_MATCH_I2C_ADDR: |
2006 | if (reg->match.addr != sd->i2c_addr) | 1782 | if (reg->match.addr != sd->i2c_addr) |
2007 | return -EINVAL; | 1783 | return -EINVAL; |
2008 | if (sd->sensor >= SENSOR_MT9V011 && | 1784 | if (sd->sensor >= SENSOR_MT9V011 && |
2009 | sd->sensor <= SENSOR_MT9M112) { | 1785 | sd->sensor <= SENSOR_MT9M112) { |
2010 | if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0) | 1786 | i2c_w2(gspca_dev, reg->reg, reg->val); |
2011 | return -EINVAL; | ||
2012 | } else { | 1787 | } else { |
2013 | if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0) | 1788 | i2c_w1(gspca_dev, reg->reg, reg->val); |
2014 | return -EINVAL; | ||
2015 | } | 1789 | } |
2016 | return 0; | 1790 | return gspca_dev->usb_err; |
2017 | } | 1791 | } |
2018 | return -EINVAL; | 1792 | return -EINVAL; |
2019 | } | 1793 | } |
@@ -2050,9 +1824,9 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
2050 | cam = &gspca_dev->cam; | 1824 | cam = &gspca_dev->cam; |
2051 | cam->needs_full_bandwidth = 1; | 1825 | cam->needs_full_bandwidth = 1; |
2052 | 1826 | ||
2053 | sd->sensor = (id->driver_info >> 8) & 0xff; | 1827 | sd->sensor = id->driver_info >> 8; |
2054 | sd->i2c_addr = id->driver_info & 0xff; | 1828 | sd->i2c_addr = id->driver_info; |
2055 | sd->flags = (id->driver_info >> 16) & 0xff; | 1829 | sd->flags = id->driver_info >> 16; |
2056 | 1830 | ||
2057 | switch (sd->sensor) { | 1831 | switch (sd->sensor) { |
2058 | case SENSOR_MT9M112: | 1832 | case SENSOR_MT9M112: |
@@ -2076,21 +1850,9 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
2076 | sd->older_step = 0; | 1850 | sd->older_step = 0; |
2077 | sd->exposure_step = 16; | 1851 | sd->exposure_step = 16; |
2078 | 1852 | ||
2079 | sd->brightness = BRIGHTNESS_DEFAULT; | 1853 | gspca_dev->cam.ctrls = sd->ctrls; |
2080 | sd->contrast = CONTRAST_DEFAULT; | ||
2081 | sd->saturation = SATURATION_DEFAULT; | ||
2082 | sd->hue = HUE_DEFAULT; | ||
2083 | sd->gamma = GAMMA_DEFAULT; | ||
2084 | sd->red = RED_DEFAULT; | ||
2085 | sd->blue = BLUE_DEFAULT; | ||
2086 | 1854 | ||
2087 | sd->hflip = HFLIP_DEFAULT; | 1855 | INIT_WORK(&sd->work, qual_upd); |
2088 | sd->vflip = VFLIP_DEFAULT; | ||
2089 | sd->exposure = EXPOSURE_DEFAULT; | ||
2090 | sd->gain = GAIN_DEFAULT; | ||
2091 | sd->auto_exposure = AUTO_EXPOSURE_DEFAULT; | ||
2092 | |||
2093 | sd->quality = 95; | ||
2094 | 1856 | ||
2095 | return 0; | 1857 | return 0; |
2096 | } | 1858 | } |
@@ -2105,9 +1867,10 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
2105 | 1867 | ||
2106 | for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { | 1868 | for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { |
2107 | value = bridge_init[i][1]; | 1869 | value = bridge_init[i][1]; |
2108 | if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { | 1870 | reg_w(gspca_dev, bridge_init[i][0], &value, 1); |
1871 | if (gspca_dev->usb_err < 0) { | ||
2109 | pr_err("Device initialization failed\n"); | 1872 | pr_err("Device initialization failed\n"); |
2110 | return -ENODEV; | 1873 | return gspca_dev->usb_err; |
2111 | } | 1874 | } |
2112 | } | 1875 | } |
2113 | 1876 | ||
@@ -2116,72 +1879,85 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
2116 | else | 1879 | else |
2117 | reg_w1(gspca_dev, 0x1006, 0x20); | 1880 | reg_w1(gspca_dev, 0x1006, 0x20); |
2118 | 1881 | ||
2119 | if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { | 1882 | reg_w(gspca_dev, 0x10c0, i2c_init, 9); |
1883 | if (gspca_dev->usb_err < 0) { | ||
2120 | pr_err("Device initialization failed\n"); | 1884 | pr_err("Device initialization failed\n"); |
2121 | return -ENODEV; | 1885 | return gspca_dev->usb_err; |
2122 | } | 1886 | } |
2123 | 1887 | ||
2124 | switch (sd->sensor) { | 1888 | switch (sd->sensor) { |
2125 | case SENSOR_OV9650: | 1889 | case SENSOR_OV9650: |
2126 | if (ov9650_init_sensor(gspca_dev) < 0) | 1890 | ov9650_init_sensor(gspca_dev); |
2127 | return -ENODEV; | 1891 | if (gspca_dev->usb_err < 0) |
1892 | break; | ||
2128 | pr_info("OV9650 sensor detected\n"); | 1893 | pr_info("OV9650 sensor detected\n"); |
2129 | break; | 1894 | break; |
2130 | case SENSOR_OV9655: | 1895 | case SENSOR_OV9655: |
2131 | if (ov9655_init_sensor(gspca_dev) < 0) | 1896 | ov9655_init_sensor(gspca_dev); |
2132 | return -ENODEV; | 1897 | if (gspca_dev->usb_err < 0) |
1898 | break; | ||
2133 | pr_info("OV9655 sensor detected\n"); | 1899 | pr_info("OV9655 sensor detected\n"); |
2134 | break; | 1900 | break; |
2135 | case SENSOR_SOI968: | 1901 | case SENSOR_SOI968: |
2136 | if (soi968_init_sensor(gspca_dev) < 0) | 1902 | soi968_init_sensor(gspca_dev); |
2137 | return -ENODEV; | 1903 | if (gspca_dev->usb_err < 0) |
1904 | break; | ||
2138 | pr_info("SOI968 sensor detected\n"); | 1905 | pr_info("SOI968 sensor detected\n"); |
2139 | break; | 1906 | break; |
2140 | case SENSOR_OV7660: | 1907 | case SENSOR_OV7660: |
2141 | if (ov7660_init_sensor(gspca_dev) < 0) | 1908 | ov7660_init_sensor(gspca_dev); |
2142 | return -ENODEV; | 1909 | if (gspca_dev->usb_err < 0) |
1910 | break; | ||
2143 | pr_info("OV7660 sensor detected\n"); | 1911 | pr_info("OV7660 sensor detected\n"); |
2144 | break; | 1912 | break; |
2145 | case SENSOR_OV7670: | 1913 | case SENSOR_OV7670: |
2146 | if (ov7670_init_sensor(gspca_dev) < 0) | 1914 | ov7670_init_sensor(gspca_dev); |
2147 | return -ENODEV; | 1915 | if (gspca_dev->usb_err < 0) |
1916 | break; | ||
2148 | pr_info("OV7670 sensor detected\n"); | 1917 | pr_info("OV7670 sensor detected\n"); |
2149 | break; | 1918 | break; |
2150 | case SENSOR_MT9VPRB: | 1919 | case SENSOR_MT9VPRB: |
2151 | if (mt9v_init_sensor(gspca_dev) < 0) | 1920 | mt9v_init_sensor(gspca_dev); |
2152 | return -ENODEV; | 1921 | if (gspca_dev->usb_err < 0) |
1922 | break; | ||
1923 | pr_info("MT9VPRB sensor detected\n"); | ||
2153 | break; | 1924 | break; |
2154 | case SENSOR_MT9M111: | 1925 | case SENSOR_MT9M111: |
2155 | if (mt9m111_init_sensor(gspca_dev) < 0) | 1926 | mt9m111_init_sensor(gspca_dev); |
2156 | return -ENODEV; | 1927 | if (gspca_dev->usb_err < 0) |
1928 | break; | ||
2157 | pr_info("MT9M111 sensor detected\n"); | 1929 | pr_info("MT9M111 sensor detected\n"); |
2158 | break; | 1930 | break; |
2159 | case SENSOR_MT9M112: | 1931 | case SENSOR_MT9M112: |
2160 | if (mt9m112_init_sensor(gspca_dev) < 0) | 1932 | mt9m112_init_sensor(gspca_dev); |
2161 | return -ENODEV; | 1933 | if (gspca_dev->usb_err < 0) |
1934 | break; | ||
2162 | pr_info("MT9M112 sensor detected\n"); | 1935 | pr_info("MT9M112 sensor detected\n"); |
2163 | break; | 1936 | break; |
2164 | case SENSOR_MT9M001: | 1937 | case SENSOR_MT9M001: |
2165 | if (mt9m001_init_sensor(gspca_dev) < 0) | 1938 | mt9m001_init_sensor(gspca_dev); |
2166 | return -ENODEV; | 1939 | if (gspca_dev->usb_err < 0) |
1940 | break; | ||
2167 | break; | 1941 | break; |
2168 | case SENSOR_HV7131R: | 1942 | case SENSOR_HV7131R: |
2169 | if (hv7131r_init_sensor(gspca_dev) < 0) | 1943 | hv7131r_init_sensor(gspca_dev); |
2170 | return -ENODEV; | 1944 | if (gspca_dev->usb_err < 0) |
1945 | break; | ||
2171 | pr_info("HV7131R sensor detected\n"); | 1946 | pr_info("HV7131R sensor detected\n"); |
2172 | break; | 1947 | break; |
2173 | default: | 1948 | default: |
2174 | pr_info("Unsupported Sensor\n"); | 1949 | pr_err("Unsupported sensor\n"); |
2175 | return -ENODEV; | 1950 | gspca_dev->usb_err = -ENODEV; |
2176 | } | 1951 | } |
2177 | 1952 | ||
2178 | return 0; | 1953 | return gspca_dev->usb_err; |
2179 | } | 1954 | } |
2180 | 1955 | ||
2181 | static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) | 1956 | static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) |
2182 | { | 1957 | { |
2183 | struct sd *sd = (struct sd *) gspca_dev; | 1958 | struct sd *sd = (struct sd *) gspca_dev; |
2184 | u8 value; | 1959 | u8 value; |
1960 | |||
2185 | switch (sd->sensor) { | 1961 | switch (sd->sensor) { |
2186 | case SENSOR_SOI968: | 1962 | case SENSOR_SOI968: |
2187 | if (mode & MODE_SXGA) { | 1963 | if (mode & MODE_SXGA) { |
@@ -2264,6 +2040,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) | |||
2264 | break; | 2040 | break; |
2265 | default: /* >= 640x480 */ | 2041 | default: /* >= 640x480 */ |
2266 | gspca_dev->alt = 9; | 2042 | gspca_dev->alt = 9; |
2043 | break; | ||
2267 | } | 2044 | } |
2268 | } | 2045 | } |
2269 | 2046 | ||
@@ -2290,14 +2067,15 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
2290 | 2067 | ||
2291 | jpeg_define(sd->jpeg_hdr, height, width, | 2068 | jpeg_define(sd->jpeg_hdr, height, width, |
2292 | 0x21); | 2069 | 0x21); |
2293 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | 2070 | jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); |
2294 | 2071 | ||
2295 | if (mode & MODE_RAW) | 2072 | if (mode & MODE_RAW) |
2296 | fmt = 0x2d; | 2073 | fmt = 0x2d; |
2297 | else if (mode & MODE_JPEG) | 2074 | else if (mode & MODE_JPEG) |
2298 | fmt = 0x2c; | 2075 | fmt = 0x24; |
2299 | else | 2076 | else |
2300 | fmt = 0x2f; /* YUV 420 */ | 2077 | fmt = 0x2f; /* YUV 420 */ |
2078 | sd->fmt = fmt; | ||
2301 | 2079 | ||
2302 | switch (mode & SCALE_MASK) { | 2080 | switch (mode & SCALE_MASK) { |
2303 | case SCALE_1280x1024: | 2081 | case SCALE_1280x1024: |
@@ -2334,18 +2112,37 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
2334 | set_hvflip(gspca_dev); | 2112 | set_hvflip(gspca_dev); |
2335 | 2113 | ||
2336 | reg_w1(gspca_dev, 0x1007, 0x20); | 2114 | reg_w1(gspca_dev, 0x1007, 0x20); |
2115 | reg_w1(gspca_dev, 0x1061, 0x03); | ||
2116 | |||
2117 | /* if JPEG, prepare the compression quality update */ | ||
2118 | if (mode & MODE_JPEG) { | ||
2119 | sd->pktsz = sd->npkt = 0; | ||
2120 | sd->nchg = 0; | ||
2121 | sd->work_thread = | ||
2122 | create_singlethread_workqueue(KBUILD_MODNAME); | ||
2123 | } | ||
2337 | 2124 | ||
2338 | reg_r(gspca_dev, 0x1061, 1); | 2125 | return gspca_dev->usb_err; |
2339 | reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02); | ||
2340 | return 0; | ||
2341 | } | 2126 | } |
2342 | 2127 | ||
2343 | static void sd_stopN(struct gspca_dev *gspca_dev) | 2128 | static void sd_stopN(struct gspca_dev *gspca_dev) |
2344 | { | 2129 | { |
2345 | reg_w1(gspca_dev, 0x1007, 0x00); | 2130 | reg_w1(gspca_dev, 0x1007, 0x00); |
2131 | reg_w1(gspca_dev, 0x1061, 0x01); | ||
2132 | } | ||
2133 | |||
2134 | /* called on streamoff with alt==0 and on disconnect */ | ||
2135 | /* the usb_lock is held at entry - restore on exit */ | ||
2136 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
2137 | { | ||
2138 | struct sd *sd = (struct sd *) gspca_dev; | ||
2346 | 2139 | ||
2347 | reg_r(gspca_dev, 0x1061, 1); | 2140 | if (sd->work_thread != NULL) { |
2348 | reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02); | 2141 | mutex_unlock(&gspca_dev->usb_lock); |
2142 | destroy_workqueue(sd->work_thread); | ||
2143 | mutex_lock(&gspca_dev->usb_lock); | ||
2144 | sd->work_thread = NULL; | ||
2145 | } | ||
2349 | } | 2146 | } |
2350 | 2147 | ||
2351 | static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) | 2148 | static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) |
@@ -2359,15 +2156,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) | |||
2359 | * and exposure steps | 2156 | * and exposure steps |
2360 | */ | 2157 | */ |
2361 | if (avg_lum < MIN_AVG_LUM) { | 2158 | if (avg_lum < MIN_AVG_LUM) { |
2362 | if (sd->exposure > 0x1770) | 2159 | if (sd->ctrls[EXPOSURE].val > 0x1770) |
2363 | return; | 2160 | return; |
2364 | 2161 | ||
2365 | new_exp = sd->exposure + sd->exposure_step; | 2162 | new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step; |
2366 | if (new_exp > 0x1770) | 2163 | if (new_exp > 0x1770) |
2367 | new_exp = 0x1770; | 2164 | new_exp = 0x1770; |
2368 | if (new_exp < 0x10) | 2165 | if (new_exp < 0x10) |
2369 | new_exp = 0x10; | 2166 | new_exp = 0x10; |
2370 | sd->exposure = new_exp; | 2167 | sd->ctrls[EXPOSURE].val = new_exp; |
2371 | set_exposure(gspca_dev); | 2168 | set_exposure(gspca_dev); |
2372 | 2169 | ||
2373 | sd->older_step = sd->old_step; | 2170 | sd->older_step = sd->old_step; |
@@ -2379,14 +2176,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) | |||
2379 | sd->exposure_step += 2; | 2176 | sd->exposure_step += 2; |
2380 | } | 2177 | } |
2381 | if (avg_lum > MAX_AVG_LUM) { | 2178 | if (avg_lum > MAX_AVG_LUM) { |
2382 | if (sd->exposure < 0x10) | 2179 | if (sd->ctrls[EXPOSURE].val < 0x10) |
2383 | return; | 2180 | return; |
2384 | new_exp = sd->exposure - sd->exposure_step; | 2181 | new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step; |
2385 | if (new_exp > 0x1700) | 2182 | if (new_exp > 0x1700) |
2386 | new_exp = 0x1770; | 2183 | new_exp = 0x1770; |
2387 | if (new_exp < 0x10) | 2184 | if (new_exp < 0x10) |
2388 | new_exp = 0x10; | 2185 | new_exp = 0x10; |
2389 | sd->exposure = new_exp; | 2186 | sd->ctrls[EXPOSURE].val = new_exp; |
2390 | set_exposure(gspca_dev); | 2187 | set_exposure(gspca_dev); |
2391 | sd->older_step = sd->old_step; | 2188 | sd->older_step = sd->old_step; |
2392 | sd->old_step = 0; | 2189 | sd->old_step = 0; |
@@ -2403,14 +2200,14 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) | |||
2403 | struct sd *sd = (struct sd *) gspca_dev; | 2200 | struct sd *sd = (struct sd *) gspca_dev; |
2404 | 2201 | ||
2405 | if (avg_lum < MIN_AVG_LUM) { | 2202 | if (avg_lum < MIN_AVG_LUM) { |
2406 | if (sd->gain + 1 <= 28) { | 2203 | if (sd->ctrls[GAIN].val + 1 <= 28) { |
2407 | sd->gain++; | 2204 | sd->ctrls[GAIN].val++; |
2408 | set_gain(gspca_dev); | 2205 | set_gain(gspca_dev); |
2409 | } | 2206 | } |
2410 | } | 2207 | } |
2411 | if (avg_lum > MAX_AVG_LUM) { | 2208 | if (avg_lum > MAX_AVG_LUM) { |
2412 | if (sd->gain > 0) { | 2209 | if (sd->ctrls[GAIN].val > 0) { |
2413 | sd->gain--; | 2210 | sd->ctrls[GAIN].val--; |
2414 | set_gain(gspca_dev); | 2211 | set_gain(gspca_dev); |
2415 | } | 2212 | } |
2416 | } | 2213 | } |
@@ -2421,7 +2218,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev) | |||
2421 | struct sd *sd = (struct sd *) gspca_dev; | 2218 | struct sd *sd = (struct sd *) gspca_dev; |
2422 | int avg_lum; | 2219 | int avg_lum; |
2423 | 2220 | ||
2424 | if (!sd->auto_exposure) | 2221 | if (!sd->ctrls[AUTOGAIN].val) |
2425 | return; | 2222 | return; |
2426 | 2223 | ||
2427 | avg_lum = atomic_read(&sd->avg_lum); | 2224 | avg_lum = atomic_read(&sd->avg_lum); |
@@ -2431,33 +2228,92 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev) | |||
2431 | do_autoexposure(gspca_dev, avg_lum); | 2228 | do_autoexposure(gspca_dev, avg_lum); |
2432 | } | 2229 | } |
2433 | 2230 | ||
2231 | /* JPEG quality update */ | ||
2232 | /* This function is executed from a work queue. */ | ||
2233 | static void qual_upd(struct work_struct *work) | ||
2234 | { | ||
2235 | struct sd *sd = container_of(work, struct sd, work); | ||
2236 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
2237 | |||
2238 | mutex_lock(&gspca_dev->usb_lock); | ||
2239 | PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val); | ||
2240 | set_quality(gspca_dev); | ||
2241 | mutex_unlock(&gspca_dev->usb_lock); | ||
2242 | } | ||
2243 | |||
2434 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | 2244 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
2435 | static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, | 2245 | static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, |
2436 | u8 *data, /* interrupt packet */ | 2246 | u8 *data, /* interrupt packet */ |
2437 | int len) /* interrupt packet length */ | 2247 | int len) /* interrupt packet length */ |
2438 | { | 2248 | { |
2439 | struct sd *sd = (struct sd *) gspca_dev; | 2249 | struct sd *sd = (struct sd *) gspca_dev; |
2440 | int ret = -EINVAL; | 2250 | |
2441 | if (!(sd->flags & HAS_NO_BUTTON) && len == 1) { | 2251 | if (!(sd->flags & HAS_NO_BUTTON) && len == 1) { |
2442 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); | 2252 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); |
2443 | input_sync(gspca_dev->input_dev); | 2253 | input_sync(gspca_dev->input_dev); |
2444 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); | 2254 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); |
2445 | input_sync(gspca_dev->input_dev); | 2255 | input_sync(gspca_dev->input_dev); |
2446 | ret = 0; | 2256 | return 0; |
2447 | } | 2257 | } |
2448 | return ret; | 2258 | return -EINVAL; |
2449 | } | 2259 | } |
2450 | #endif | 2260 | #endif |
2451 | 2261 | ||
2262 | /* check the JPEG compression */ | ||
2263 | static void transfer_check(struct gspca_dev *gspca_dev, | ||
2264 | u8 *data) | ||
2265 | { | ||
2266 | struct sd *sd = (struct sd *) gspca_dev; | ||
2267 | int new_qual, r; | ||
2268 | |||
2269 | new_qual = 0; | ||
2270 | |||
2271 | /* if USB error, discard the frame and decrease the quality */ | ||
2272 | if (data[6] & 0x08) { /* USB FIFO full */ | ||
2273 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
2274 | new_qual = -5; | ||
2275 | } else { | ||
2276 | |||
2277 | /* else, compute the filling rate and a new JPEG quality */ | ||
2278 | r = (sd->pktsz * 100) / | ||
2279 | (sd->npkt * | ||
2280 | gspca_dev->urb[0]->iso_frame_desc[0].length); | ||
2281 | if (r >= 85) | ||
2282 | new_qual = -3; | ||
2283 | else if (r < 75) | ||
2284 | new_qual = 2; | ||
2285 | } | ||
2286 | if (new_qual != 0) { | ||
2287 | sd->nchg += new_qual; | ||
2288 | if (sd->nchg < -6 || sd->nchg >= 12) { | ||
2289 | sd->nchg = 0; | ||
2290 | new_qual += sd->ctrls[QUALITY].val; | ||
2291 | if (new_qual < QUALITY_MIN) | ||
2292 | new_qual = QUALITY_MIN; | ||
2293 | else if (new_qual > QUALITY_MAX) | ||
2294 | new_qual = QUALITY_MAX; | ||
2295 | if (new_qual != sd->ctrls[QUALITY].val) { | ||
2296 | sd->ctrls[QUALITY].val = new_qual; | ||
2297 | queue_work(sd->work_thread, &sd->work); | ||
2298 | } | ||
2299 | } | ||
2300 | } else { | ||
2301 | sd->nchg = 0; | ||
2302 | } | ||
2303 | sd->pktsz = sd->npkt = 0; | ||
2304 | } | ||
2305 | |||
2452 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 2306 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
2453 | u8 *data, /* isoc packet */ | 2307 | u8 *data, /* isoc packet */ |
2454 | int len) /* iso packet length */ | 2308 | int len) /* iso packet length */ |
2455 | { | 2309 | { |
2456 | struct sd *sd = (struct sd *) gspca_dev; | 2310 | struct sd *sd = (struct sd *) gspca_dev; |
2457 | int avg_lum; | 2311 | int avg_lum, is_jpeg; |
2458 | static u8 frame_header[] = | 2312 | static u8 frame_header[] = |
2459 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; | 2313 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; |
2460 | if (len == 64 && memcmp(data, frame_header, 6) == 0) { | 2314 | |
2315 | is_jpeg = (sd->fmt & 0x03) == 0; | ||
2316 | if (len >= 64 && memcmp(data, frame_header, 6) == 0) { | ||
2461 | avg_lum = ((data[35] >> 2) & 3) | | 2317 | avg_lum = ((data[35] >> 2) & 3) | |
2462 | (data[20] << 2) | | 2318 | (data[20] << 2) | |
2463 | (data[19] << 10); | 2319 | (data[19] << 10); |
@@ -2484,12 +2340,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
2484 | (data[33] << 10); | 2340 | (data[33] << 10); |
2485 | avg_lum >>= 9; | 2341 | avg_lum >>= 9; |
2486 | atomic_set(&sd->avg_lum, avg_lum); | 2342 | atomic_set(&sd->avg_lum, avg_lum); |
2343 | |||
2344 | if (is_jpeg) | ||
2345 | transfer_check(gspca_dev, data); | ||
2346 | |||
2487 | gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); | 2347 | gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); |
2488 | return; | 2348 | len -= 64; |
2349 | if (len == 0) | ||
2350 | return; | ||
2351 | data += 64; | ||
2489 | } | 2352 | } |
2490 | if (gspca_dev->last_packet_type == LAST_PACKET) { | 2353 | if (gspca_dev->last_packet_type == LAST_PACKET) { |
2491 | if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv | 2354 | if (is_jpeg) { |
2492 | & MODE_JPEG) { | ||
2493 | gspca_frame_add(gspca_dev, FIRST_PACKET, | 2355 | gspca_frame_add(gspca_dev, FIRST_PACKET, |
2494 | sd->jpeg_hdr, JPEG_HDR_SZ); | 2356 | sd->jpeg_hdr, JPEG_HDR_SZ); |
2495 | gspca_frame_add(gspca_dev, INTER_PACKET, | 2357 | gspca_frame_add(gspca_dev, INTER_PACKET, |
@@ -2499,13 +2361,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
2499 | data, len); | 2361 | data, len); |
2500 | } | 2362 | } |
2501 | } else { | 2363 | } else { |
2364 | /* if JPEG, count the packets and their size */ | ||
2365 | if (is_jpeg) { | ||
2366 | sd->npkt++; | ||
2367 | sd->pktsz += len; | ||
2368 | } | ||
2502 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); | 2369 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); |
2503 | } | 2370 | } |
2504 | } | 2371 | } |
2505 | 2372 | ||
2506 | /* sub-driver description */ | 2373 | /* sub-driver description */ |
2507 | static const struct sd_desc sd_desc = { | 2374 | static const struct sd_desc sd_desc = { |
2508 | .name = MODULE_NAME, | 2375 | .name = KBUILD_MODNAME, |
2509 | .ctrls = sd_ctrls, | 2376 | .ctrls = sd_ctrls, |
2510 | .nctrls = ARRAY_SIZE(sd_ctrls), | 2377 | .nctrls = ARRAY_SIZE(sd_ctrls), |
2511 | .config = sd_config, | 2378 | .config = sd_config, |
@@ -2513,6 +2380,7 @@ static const struct sd_desc sd_desc = { | |||
2513 | .isoc_init = sd_isoc_init, | 2380 | .isoc_init = sd_isoc_init, |
2514 | .start = sd_start, | 2381 | .start = sd_start, |
2515 | .stopN = sd_stopN, | 2382 | .stopN = sd_stopN, |
2383 | .stop0 = sd_stop0, | ||
2516 | .pkt_scan = sd_pkt_scan, | 2384 | .pkt_scan = sd_pkt_scan, |
2517 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | 2385 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
2518 | .int_pkt_scan = sd_int_pkt_scan, | 2386 | .int_pkt_scan = sd_int_pkt_scan, |
@@ -2581,7 +2449,7 @@ static int sd_probe(struct usb_interface *intf, | |||
2581 | } | 2449 | } |
2582 | 2450 | ||
2583 | static struct usb_driver sd_driver = { | 2451 | static struct usb_driver sd_driver = { |
2584 | .name = MODULE_NAME, | 2452 | .name = KBUILD_MODNAME, |
2585 | .id_table = device_table, | 2453 | .id_table = device_table, |
2586 | .probe = sd_probe, | 2454 | .probe = sd_probe, |
2587 | .disconnect = gspca_disconnect, | 2455 | .disconnect = gspca_disconnect, |
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 0c9e6ddabd2c..db8e5084df06 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c | |||
@@ -39,7 +39,9 @@ enum e_ctrl { | |||
39 | BLUE, | 39 | BLUE, |
40 | RED, | 40 | RED, |
41 | GAMMA, | 41 | GAMMA, |
42 | EXPOSURE, | ||
42 | AUTOGAIN, | 43 | AUTOGAIN, |
44 | GAIN, | ||
43 | HFLIP, | 45 | HFLIP, |
44 | VFLIP, | 46 | VFLIP, |
45 | SHARPNESS, | 47 | SHARPNESS, |
@@ -131,7 +133,9 @@ static void setcontrast(struct gspca_dev *gspca_dev); | |||
131 | static void setcolors(struct gspca_dev *gspca_dev); | 133 | static void setcolors(struct gspca_dev *gspca_dev); |
132 | static void setredblue(struct gspca_dev *gspca_dev); | 134 | static void setredblue(struct gspca_dev *gspca_dev); |
133 | static void setgamma(struct gspca_dev *gspca_dev); | 135 | static void setgamma(struct gspca_dev *gspca_dev); |
134 | static void setautogain(struct gspca_dev *gspca_dev); | 136 | static void setexposure(struct gspca_dev *gspca_dev); |
137 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); | ||
138 | static void setgain(struct gspca_dev *gspca_dev); | ||
135 | static void sethvflip(struct gspca_dev *gspca_dev); | 139 | static void sethvflip(struct gspca_dev *gspca_dev); |
136 | static void setsharpness(struct gspca_dev *gspca_dev); | 140 | static void setsharpness(struct gspca_dev *gspca_dev); |
137 | static void setillum(struct gspca_dev *gspca_dev); | 141 | static void setillum(struct gspca_dev *gspca_dev); |
@@ -213,6 +217,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = { | |||
213 | }, | 217 | }, |
214 | .set_control = setgamma | 218 | .set_control = setgamma |
215 | }, | 219 | }, |
220 | [EXPOSURE] = { | ||
221 | { | ||
222 | .id = V4L2_CID_EXPOSURE, | ||
223 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
224 | .name = "Exposure", | ||
225 | .minimum = 500, | ||
226 | .maximum = 1500, | ||
227 | .step = 1, | ||
228 | .default_value = 1024 | ||
229 | }, | ||
230 | .set_control = setexposure | ||
231 | }, | ||
216 | [AUTOGAIN] = { | 232 | [AUTOGAIN] = { |
217 | { | 233 | { |
218 | .id = V4L2_CID_AUTOGAIN, | 234 | .id = V4L2_CID_AUTOGAIN, |
@@ -223,7 +239,19 @@ static const struct ctrl sd_ctrls[NCTRLS] = { | |||
223 | .step = 1, | 239 | .step = 1, |
224 | .default_value = 1 | 240 | .default_value = 1 |
225 | }, | 241 | }, |
226 | .set_control = setautogain | 242 | .set = sd_setautogain, |
243 | }, | ||
244 | [GAIN] = { | ||
245 | { | ||
246 | .id = V4L2_CID_GAIN, | ||
247 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
248 | .name = "Gain", | ||
249 | .minimum = 4, | ||
250 | .maximum = 49, | ||
251 | .step = 1, | ||
252 | .default_value = 15 | ||
253 | }, | ||
254 | .set_control = setgain | ||
227 | }, | 255 | }, |
228 | [HFLIP] = { | 256 | [HFLIP] = { |
229 | { | 257 | { |
@@ -290,60 +318,87 @@ static const struct ctrl sd_ctrls[NCTRLS] = { | |||
290 | 318 | ||
291 | /* table of the disabled controls */ | 319 | /* table of the disabled controls */ |
292 | static const __u32 ctrl_dis[] = { | 320 | static const __u32 ctrl_dis[] = { |
293 | [SENSOR_ADCM1700] = (1 << AUTOGAIN) | | 321 | [SENSOR_ADCM1700] = (1 << EXPOSURE) | |
322 | (1 << AUTOGAIN) | | ||
323 | (1 << GAIN) | | ||
294 | (1 << HFLIP) | | 324 | (1 << HFLIP) | |
295 | (1 << VFLIP) | | 325 | (1 << VFLIP) | |
296 | (1 << FREQ), | 326 | (1 << FREQ), |
297 | 327 | ||
298 | [SENSOR_GC0307] = (1 << HFLIP) | | 328 | [SENSOR_GC0307] = (1 << EXPOSURE) | |
329 | (1 << GAIN) | | ||
330 | (1 << HFLIP) | | ||
299 | (1 << VFLIP) | | 331 | (1 << VFLIP) | |
300 | (1 << FREQ), | 332 | (1 << FREQ), |
301 | 333 | ||
302 | [SENSOR_HV7131R] = (1 << HFLIP) | | 334 | [SENSOR_HV7131R] = (1 << EXPOSURE) | |
335 | (1 << GAIN) | | ||
336 | (1 << HFLIP) | | ||
303 | (1 << FREQ), | 337 | (1 << FREQ), |
304 | 338 | ||
305 | [SENSOR_MI0360] = (1 << HFLIP) | | 339 | [SENSOR_MI0360] = (1 << EXPOSURE) | |
340 | (1 << GAIN) | | ||
341 | (1 << HFLIP) | | ||
306 | (1 << VFLIP) | | 342 | (1 << VFLIP) | |
307 | (1 << FREQ), | 343 | (1 << FREQ), |
308 | 344 | ||
309 | [SENSOR_MI0360B] = (1 << HFLIP) | | 345 | [SENSOR_MI0360B] = (1 << EXPOSURE) | |
346 | (1 << GAIN) | | ||
347 | (1 << HFLIP) | | ||
310 | (1 << VFLIP) | | 348 | (1 << VFLIP) | |
311 | (1 << FREQ), | 349 | (1 << FREQ), |
312 | 350 | ||
313 | [SENSOR_MO4000] = (1 << HFLIP) | | 351 | [SENSOR_MO4000] = (1 << EXPOSURE) | |
352 | (1 << GAIN) | | ||
353 | (1 << HFLIP) | | ||
314 | (1 << VFLIP) | | 354 | (1 << VFLIP) | |
315 | (1 << FREQ), | 355 | (1 << FREQ), |
316 | 356 | ||
317 | [SENSOR_MT9V111] = (1 << HFLIP) | | 357 | [SENSOR_MT9V111] = (1 << EXPOSURE) | |
358 | (1 << GAIN) | | ||
359 | (1 << HFLIP) | | ||
318 | (1 << VFLIP) | | 360 | (1 << VFLIP) | |
319 | (1 << FREQ), | 361 | (1 << FREQ), |
320 | 362 | ||
321 | [SENSOR_OM6802] = (1 << HFLIP) | | 363 | [SENSOR_OM6802] = (1 << EXPOSURE) | |
364 | (1 << GAIN) | | ||
365 | (1 << HFLIP) | | ||
322 | (1 << VFLIP) | | 366 | (1 << VFLIP) | |
323 | (1 << FREQ), | 367 | (1 << FREQ), |
324 | 368 | ||
325 | [SENSOR_OV7630] = (1 << HFLIP), | 369 | [SENSOR_OV7630] = (1 << EXPOSURE) | |
370 | (1 << GAIN) | | ||
371 | (1 << HFLIP), | ||
326 | 372 | ||
327 | [SENSOR_OV7648] = (1 << HFLIP), | 373 | [SENSOR_OV7648] = (1 << EXPOSURE) | |
374 | (1 << GAIN) | | ||
375 | (1 << HFLIP), | ||
328 | 376 | ||
329 | [SENSOR_OV7660] = (1 << AUTOGAIN) | | 377 | [SENSOR_OV7660] = (1 << EXPOSURE) | |
378 | (1 << AUTOGAIN) | | ||
379 | (1 << GAIN) | | ||
330 | (1 << HFLIP) | | 380 | (1 << HFLIP) | |
331 | (1 << VFLIP), | 381 | (1 << VFLIP), |
332 | 382 | ||
333 | [SENSOR_PO1030] = (1 << AUTOGAIN) | | 383 | [SENSOR_PO1030] = (1 << EXPOSURE) | |
384 | (1 << AUTOGAIN) | | ||
385 | (1 << GAIN) | | ||
334 | (1 << HFLIP) | | 386 | (1 << HFLIP) | |
335 | (1 << VFLIP) | | 387 | (1 << VFLIP) | |
336 | (1 << FREQ), | 388 | (1 << FREQ), |
337 | 389 | ||
338 | [SENSOR_PO2030N] = (1 << AUTOGAIN) | | 390 | [SENSOR_PO2030N] = (1 << FREQ), |
339 | (1 << FREQ), | ||
340 | 391 | ||
341 | [SENSOR_SOI768] = (1 << AUTOGAIN) | | 392 | [SENSOR_SOI768] = (1 << EXPOSURE) | |
393 | (1 << AUTOGAIN) | | ||
394 | (1 << GAIN) | | ||
342 | (1 << HFLIP) | | 395 | (1 << HFLIP) | |
343 | (1 << VFLIP) | | 396 | (1 << VFLIP) | |
344 | (1 << FREQ), | 397 | (1 << FREQ), |
345 | 398 | ||
346 | [SENSOR_SP80708] = (1 << AUTOGAIN) | | 399 | [SENSOR_SP80708] = (1 << EXPOSURE) | |
400 | (1 << AUTOGAIN) | | ||
401 | (1 << GAIN) | | ||
347 | (1 << HFLIP) | | 402 | (1 << HFLIP) | |
348 | (1 << VFLIP) | | 403 | (1 << VFLIP) | |
349 | (1 << FREQ), | 404 | (1 << FREQ), |
@@ -1242,14 +1297,6 @@ static const u8 po2030n_sensor_param1[][8] = { | |||
1242 | {0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10}, | 1297 | {0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10}, |
1243 | {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, | 1298 | {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, |
1244 | {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, | 1299 | {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, |
1245 | {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, | ||
1246 | {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10}, | ||
1247 | /*after start*/ | ||
1248 | {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10}, | ||
1249 | {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ | ||
1250 | {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10}, | ||
1251 | {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ | ||
1252 | {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10}, | ||
1253 | {} | 1300 | {} |
1254 | }; | 1301 | }; |
1255 | 1302 | ||
@@ -1858,7 +1905,7 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
1858 | return gspca_dev->usb_err; | 1905 | return gspca_dev->usb_err; |
1859 | } | 1906 | } |
1860 | 1907 | ||
1861 | static u32 setexposure(struct gspca_dev *gspca_dev, | 1908 | static u32 expo_adjust(struct gspca_dev *gspca_dev, |
1862 | u32 expo) | 1909 | u32 expo) |
1863 | { | 1910 | { |
1864 | struct sd *sd = (struct sd *) gspca_dev; | 1911 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -1982,28 +2029,28 @@ static void setbrightness(struct gspca_dev *gspca_dev) | |||
1982 | expo = 0x002dc6c0; | 2029 | expo = 0x002dc6c0; |
1983 | else if (expo < 0x02a0) | 2030 | else if (expo < 0x02a0) |
1984 | expo = 0x02a0; | 2031 | expo = 0x02a0; |
1985 | sd->exposure = setexposure(gspca_dev, expo); | 2032 | sd->exposure = expo_adjust(gspca_dev, expo); |
1986 | break; | 2033 | break; |
1987 | case SENSOR_MI0360: | 2034 | case SENSOR_MI0360: |
1988 | case SENSOR_MO4000: | 2035 | case SENSOR_MO4000: |
1989 | expo = brightness << 4; | 2036 | expo = brightness << 4; |
1990 | sd->exposure = setexposure(gspca_dev, expo); | 2037 | sd->exposure = expo_adjust(gspca_dev, expo); |
1991 | break; | 2038 | break; |
1992 | case SENSOR_MI0360B: | 2039 | case SENSOR_MI0360B: |
1993 | expo = brightness << 2; | 2040 | expo = brightness << 2; |
1994 | sd->exposure = setexposure(gspca_dev, expo); | 2041 | sd->exposure = expo_adjust(gspca_dev, expo); |
1995 | break; | 2042 | break; |
1996 | case SENSOR_GC0307: | 2043 | case SENSOR_GC0307: |
1997 | expo = brightness; | 2044 | expo = brightness; |
1998 | sd->exposure = setexposure(gspca_dev, expo); | 2045 | sd->exposure = expo_adjust(gspca_dev, expo); |
1999 | return; /* don't set the Y offset */ | 2046 | return; /* don't set the Y offset */ |
2000 | case SENSOR_MT9V111: | 2047 | case SENSOR_MT9V111: |
2001 | expo = brightness << 2; | 2048 | expo = brightness << 2; |
2002 | sd->exposure = setexposure(gspca_dev, expo); | 2049 | sd->exposure = expo_adjust(gspca_dev, expo); |
2003 | return; /* don't set the Y offset */ | 2050 | return; /* don't set the Y offset */ |
2004 | case SENSOR_OM6802: | 2051 | case SENSOR_OM6802: |
2005 | expo = brightness << 2; | 2052 | expo = brightness << 2; |
2006 | sd->exposure = setexposure(gspca_dev, expo); | 2053 | sd->exposure = expo_adjust(gspca_dev, expo); |
2007 | return; /* Y offset already set */ | 2054 | return; /* Y offset already set */ |
2008 | } | 2055 | } |
2009 | 2056 | ||
@@ -2112,6 +2159,23 @@ static void setgamma(struct gspca_dev *gspca_dev) | |||
2112 | reg_w(gspca_dev, 0x20, gamma, sizeof gamma); | 2159 | reg_w(gspca_dev, 0x20, gamma, sizeof gamma); |
2113 | } | 2160 | } |
2114 | 2161 | ||
2162 | static void setexposure(struct gspca_dev *gspca_dev) | ||
2163 | { | ||
2164 | struct sd *sd = (struct sd *) gspca_dev; | ||
2165 | |||
2166 | if (sd->sensor == SENSOR_PO2030N) { | ||
2167 | u8 rexpo[] = /* 1a: expo H, 1b: expo M */ | ||
2168 | {0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10}; | ||
2169 | |||
2170 | rexpo[3] = sd->ctrls[EXPOSURE].val >> 8; | ||
2171 | i2c_w8(gspca_dev, rexpo); | ||
2172 | msleep(6); | ||
2173 | rexpo[2] = 0x1b; | ||
2174 | rexpo[3] = sd->ctrls[EXPOSURE].val; | ||
2175 | i2c_w8(gspca_dev, rexpo); | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2115 | static void setautogain(struct gspca_dev *gspca_dev) | 2179 | static void setautogain(struct gspca_dev *gspca_dev) |
2116 | { | 2180 | { |
2117 | struct sd *sd = (struct sd *) gspca_dev; | 2181 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -2139,6 +2203,19 @@ static void setautogain(struct gspca_dev *gspca_dev) | |||
2139 | sd->ag_cnt = -1; | 2203 | sd->ag_cnt = -1; |
2140 | } | 2204 | } |
2141 | 2205 | ||
2206 | static void setgain(struct gspca_dev *gspca_dev) | ||
2207 | { | ||
2208 | struct sd *sd = (struct sd *) gspca_dev; | ||
2209 | |||
2210 | if (sd->sensor == SENSOR_PO2030N) { | ||
2211 | u8 rgain[] = /* 15: gain */ | ||
2212 | {0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15}; | ||
2213 | |||
2214 | rgain[3] = sd->ctrls[GAIN].val; | ||
2215 | i2c_w8(gspca_dev, rgain); | ||
2216 | } | ||
2217 | } | ||
2218 | |||
2142 | static void sethvflip(struct gspca_dev *gspca_dev) | 2219 | static void sethvflip(struct gspca_dev *gspca_dev) |
2143 | { | 2220 | { |
2144 | struct sd *sd = (struct sd *) gspca_dev; | 2221 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -2623,6 +2700,10 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
2623 | setcontrast(gspca_dev); | 2700 | setcontrast(gspca_dev); |
2624 | setcolors(gspca_dev); | 2701 | setcolors(gspca_dev); |
2625 | setautogain(gspca_dev); | 2702 | setautogain(gspca_dev); |
2703 | if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) { | ||
2704 | setexposure(gspca_dev); | ||
2705 | setgain(gspca_dev); | ||
2706 | } | ||
2626 | setfreq(gspca_dev); | 2707 | setfreq(gspca_dev); |
2627 | 2708 | ||
2628 | sd->pktsz = sd->npkt = 0; | 2709 | sd->pktsz = sd->npkt = 0; |
@@ -2719,6 +2800,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
2719 | } | 2800 | } |
2720 | } | 2801 | } |
2721 | 2802 | ||
2803 | /* !! coarse_grained_expo_autogain is not used !! */ | ||
2804 | #define exp_too_low_cnt bridge | ||
2805 | #define exp_too_high_cnt sensor | ||
2806 | |||
2807 | #include "autogain_functions.h" | ||
2808 | |||
2722 | static void do_autogain(struct gspca_dev *gspca_dev) | 2809 | static void do_autogain(struct gspca_dev *gspca_dev) |
2723 | { | 2810 | { |
2724 | struct sd *sd = (struct sd *) gspca_dev; | 2811 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -2736,6 +2823,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
2736 | 2823 | ||
2737 | delta = atomic_read(&sd->avg_lum); | 2824 | delta = atomic_read(&sd->avg_lum); |
2738 | PDEBUG(D_FRAM, "mean lum %d", delta); | 2825 | PDEBUG(D_FRAM, "mean lum %d", delta); |
2826 | |||
2827 | if (sd->sensor == SENSOR_PO2030N) { | ||
2828 | auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta, | ||
2829 | 15, 1024); | ||
2830 | return; | ||
2831 | } | ||
2832 | |||
2739 | if (delta < luma_mean - luma_delta || | 2833 | if (delta < luma_mean - luma_delta || |
2740 | delta > luma_mean + luma_delta) { | 2834 | delta > luma_mean + luma_delta) { |
2741 | switch (sd->sensor) { | 2835 | switch (sd->sensor) { |
@@ -2744,7 +2838,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
2744 | expotimes += (luma_mean - delta) >> 6; | 2838 | expotimes += (luma_mean - delta) >> 6; |
2745 | if (expotimes < 0) | 2839 | if (expotimes < 0) |
2746 | expotimes = 0; | 2840 | expotimes = 0; |
2747 | sd->exposure = setexposure(gspca_dev, | 2841 | sd->exposure = expo_adjust(gspca_dev, |
2748 | (unsigned int) expotimes); | 2842 | (unsigned int) expotimes); |
2749 | break; | 2843 | break; |
2750 | case SENSOR_HV7131R: | 2844 | case SENSOR_HV7131R: |
@@ -2752,7 +2846,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
2752 | expotimes += (luma_mean - delta) >> 4; | 2846 | expotimes += (luma_mean - delta) >> 4; |
2753 | if (expotimes < 0) | 2847 | if (expotimes < 0) |
2754 | expotimes = 0; | 2848 | expotimes = 0; |
2755 | sd->exposure = setexposure(gspca_dev, | 2849 | sd->exposure = expo_adjust(gspca_dev, |
2756 | (unsigned int) (expotimes << 8)); | 2850 | (unsigned int) (expotimes << 8)); |
2757 | break; | 2851 | break; |
2758 | case SENSOR_OM6802: | 2852 | case SENSOR_OM6802: |
@@ -2761,7 +2855,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
2761 | expotimes += (luma_mean - delta) >> 2; | 2855 | expotimes += (luma_mean - delta) >> 2; |
2762 | if (expotimes < 0) | 2856 | if (expotimes < 0) |
2763 | expotimes = 0; | 2857 | expotimes = 0; |
2764 | sd->exposure = setexposure(gspca_dev, | 2858 | sd->exposure = expo_adjust(gspca_dev, |
2765 | (unsigned int) expotimes); | 2859 | (unsigned int) expotimes); |
2766 | setredblue(gspca_dev); | 2860 | setredblue(gspca_dev); |
2767 | break; | 2861 | break; |
@@ -2773,7 +2867,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
2773 | expotimes += (luma_mean - delta) >> 6; | 2867 | expotimes += (luma_mean - delta) >> 6; |
2774 | if (expotimes < 0) | 2868 | if (expotimes < 0) |
2775 | expotimes = 0; | 2869 | expotimes = 0; |
2776 | sd->exposure = setexposure(gspca_dev, | 2870 | sd->exposure = expo_adjust(gspca_dev, |
2777 | (unsigned int) expotimes); | 2871 | (unsigned int) expotimes); |
2778 | setredblue(gspca_dev); | 2872 | setredblue(gspca_dev); |
2779 | break; | 2873 | break; |
@@ -2948,16 +3042,18 @@ marker_found: | |||
2948 | } | 3042 | } |
2949 | } | 3043 | } |
2950 | 3044 | ||
2951 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, | 3045 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) |
2952 | struct v4l2_jpegcompression *jcomp) | ||
2953 | { | 3046 | { |
2954 | struct sd *sd = (struct sd *) gspca_dev; | 3047 | struct sd *sd = (struct sd *) gspca_dev; |
2955 | 3048 | ||
2956 | memset(jcomp, 0, sizeof *jcomp); | 3049 | sd->ctrls[AUTOGAIN].val = val; |
2957 | jcomp->quality = sd->quality; | 3050 | if (val) |
2958 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | 3051 | gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); |
2959 | | V4L2_JPEG_MARKER_DQT; | 3052 | else |
2960 | return 0; | 3053 | gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN); |
3054 | if (gspca_dev->streaming) | ||
3055 | setautogain(gspca_dev); | ||
3056 | return gspca_dev->usb_err; | ||
2961 | } | 3057 | } |
2962 | 3058 | ||
2963 | static int sd_querymenu(struct gspca_dev *gspca_dev, | 3059 | static int sd_querymenu(struct gspca_dev *gspca_dev, |
@@ -3012,7 +3108,6 @@ static const struct sd_desc sd_desc = { | |||
3012 | .stop0 = sd_stop0, | 3108 | .stop0 = sd_stop0, |
3013 | .pkt_scan = sd_pkt_scan, | 3109 | .pkt_scan = sd_pkt_scan, |
3014 | .dq_callback = do_autogain, | 3110 | .dq_callback = do_autogain, |
3015 | .get_jcomp = sd_get_jcomp, | ||
3016 | .querymenu = sd_querymenu, | 3111 | .querymenu = sd_querymenu, |
3017 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | 3112 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
3018 | .int_pkt_scan = sd_int_pkt_scan, | 3113 | .int_pkt_scan = sd_int_pkt_scan, |
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile index 5b318faf9aa8..38bc41061d83 100644 --- a/drivers/media/video/gspca/stv06xx/Makefile +++ b/drivers/media/video/gspca/stv06xx/Makefile | |||
@@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \ | |||
6 | stv06xx_pb0100.o \ | 6 | stv06xx_pb0100.o \ |
7 | stv06xx_st6422.o | 7 | stv06xx_st6422.o |
8 | 8 | ||
9 | ccflags-y += -Idrivers/media/video/gspca | 9 | ccflags-y += -I$(srctree)/drivers/media/video/gspca |
10 | 10 | ||
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index b9e15bb0328b..7d9a4f1be9dc 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Z-Star/Vimicro zc301/zc302p/vc30x library | 2 | * Z-Star/Vimicro zc301/zc302p/vc30x driver |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2011 Jean-Francois Moine <http://moinejf.free.fr> | 4 | * Copyright (C) 2009-2012 Jean-Francois Moine <http://moinejf.free.fr> |
5 | * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr | 5 | * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -21,8 +21,6 @@ | |||
21 | 21 | ||
22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
23 | 23 | ||
24 | #define MODULE_NAME "zc3xx" | ||
25 | |||
26 | #include <linux/input.h> | 24 | #include <linux/input.h> |
27 | #include "gspca.h" | 25 | #include "gspca.h" |
28 | #include "jpeg.h" | 26 | #include "jpeg.h" |
@@ -34,7 +32,7 @@ MODULE_LICENSE("GPL"); | |||
34 | 32 | ||
35 | static int force_sensor = -1; | 33 | static int force_sensor = -1; |
36 | 34 | ||
37 | #define QUANT_VAL 1 /* quantization table */ | 35 | #define REG08_DEF 3 /* default JPEG compression (70%) */ |
38 | #include "zc3xx-reg.h" | 36 | #include "zc3xx-reg.h" |
39 | 37 | ||
40 | /* controls */ | 38 | /* controls */ |
@@ -46,6 +44,7 @@ enum e_ctrl { | |||
46 | AUTOGAIN, | 44 | AUTOGAIN, |
47 | LIGHTFREQ, | 45 | LIGHTFREQ, |
48 | SHARPNESS, | 46 | SHARPNESS, |
47 | QUALITY, | ||
49 | NCTRLS /* number of controls */ | 48 | NCTRLS /* number of controls */ |
50 | }; | 49 | }; |
51 | 50 | ||
@@ -57,10 +56,10 @@ struct sd { | |||
57 | 56 | ||
58 | struct gspca_ctrl ctrls[NCTRLS]; | 57 | struct gspca_ctrl ctrls[NCTRLS]; |
59 | 58 | ||
60 | u8 quality; /* image quality */ | 59 | struct work_struct work; |
61 | #define QUALITY_MIN 50 | 60 | struct workqueue_struct *work_thread; |
62 | #define QUALITY_MAX 80 | 61 | |
63 | #define QUALITY_DEF 70 | 62 | u8 reg08; /* webcam compression quality */ |
64 | 63 | ||
65 | u8 bridge; | 64 | u8 bridge; |
66 | u8 sensor; /* Type of image sensor chip */ | 65 | u8 sensor; /* Type of image sensor chip */ |
@@ -101,6 +100,7 @@ static void setexposure(struct gspca_dev *gspca_dev); | |||
101 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); | 100 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); |
102 | static void setlightfreq(struct gspca_dev *gspca_dev); | 101 | static void setlightfreq(struct gspca_dev *gspca_dev); |
103 | static void setsharpness(struct gspca_dev *gspca_dev); | 102 | static void setsharpness(struct gspca_dev *gspca_dev); |
103 | static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val); | ||
104 | 104 | ||
105 | static const struct ctrl sd_ctrls[NCTRLS] = { | 105 | static const struct ctrl sd_ctrls[NCTRLS] = { |
106 | [BRIGHTNESS] = { | 106 | [BRIGHTNESS] = { |
@@ -188,6 +188,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = { | |||
188 | }, | 188 | }, |
189 | .set_control = setsharpness | 189 | .set_control = setsharpness |
190 | }, | 190 | }, |
191 | [QUALITY] = { | ||
192 | { | ||
193 | .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, | ||
194 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
195 | .name = "Compression Quality", | ||
196 | .minimum = 40, | ||
197 | .maximum = 70, | ||
198 | .step = 1, | ||
199 | .default_value = 70 /* updated in sd_init() */ | ||
200 | }, | ||
201 | .set = sd_setquality | ||
202 | }, | ||
191 | }; | 203 | }; |
192 | 204 | ||
193 | static const struct v4l2_pix_format vga_mode[] = { | 205 | static const struct v4l2_pix_format vga_mode[] = { |
@@ -229,6 +241,9 @@ static const struct v4l2_pix_format sif_mode[] = { | |||
229 | .priv = 0}, | 241 | .priv = 0}, |
230 | }; | 242 | }; |
231 | 243 | ||
244 | /* bridge reg08 -> JPEG quality conversion table */ | ||
245 | static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/}; | ||
246 | |||
232 | /* usb exchanges */ | 247 | /* usb exchanges */ |
233 | struct usb_action { | 248 | struct usb_action { |
234 | u8 req; | 249 | u8 req; |
@@ -3894,7 +3909,6 @@ static const struct usb_action pas106b_Initial[] = { /* 352x288 */ | |||
3894 | /* Gains */ | 3909 | /* Gains */ |
3895 | {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, | 3910 | {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, |
3896 | {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, | 3911 | {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, |
3897 | {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, | ||
3898 | {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, | 3912 | {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, |
3899 | /* Auto correction */ | 3913 | /* Auto correction */ |
3900 | {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, | 3914 | {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, |
@@ -5640,7 +5654,7 @@ static const struct usb_action gc0303_NoFlikerScale[] = { | |||
5640 | {} | 5654 | {} |
5641 | }; | 5655 | }; |
5642 | 5656 | ||
5643 | static u8 reg_r_i(struct gspca_dev *gspca_dev, | 5657 | static u8 reg_r(struct gspca_dev *gspca_dev, |
5644 | u16 index) | 5658 | u16 index) |
5645 | { | 5659 | { |
5646 | int ret; | 5660 | int ret; |
@@ -5655,24 +5669,14 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev, | |||
5655 | index, gspca_dev->usb_buf, 1, | 5669 | index, gspca_dev->usb_buf, 1, |
5656 | 500); | 5670 | 500); |
5657 | if (ret < 0) { | 5671 | if (ret < 0) { |
5658 | pr_err("reg_r_i err %d\n", ret); | 5672 | pr_err("reg_r err %d\n", ret); |
5659 | gspca_dev->usb_err = ret; | 5673 | gspca_dev->usb_err = ret; |
5660 | return 0; | 5674 | return 0; |
5661 | } | 5675 | } |
5662 | return gspca_dev->usb_buf[0]; | 5676 | return gspca_dev->usb_buf[0]; |
5663 | } | 5677 | } |
5664 | 5678 | ||
5665 | static u8 reg_r(struct gspca_dev *gspca_dev, | 5679 | static void reg_w(struct gspca_dev *gspca_dev, |
5666 | u16 index) | ||
5667 | { | ||
5668 | u8 ret; | ||
5669 | |||
5670 | ret = reg_r_i(gspca_dev, index); | ||
5671 | PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret); | ||
5672 | return ret; | ||
5673 | } | ||
5674 | |||
5675 | static void reg_w_i(struct gspca_dev *gspca_dev, | ||
5676 | u8 value, | 5680 | u8 value, |
5677 | u16 index) | 5681 | u16 index) |
5678 | { | 5682 | { |
@@ -5692,14 +5696,6 @@ static void reg_w_i(struct gspca_dev *gspca_dev, | |||
5692 | } | 5696 | } |
5693 | } | 5697 | } |
5694 | 5698 | ||
5695 | static void reg_w(struct gspca_dev *gspca_dev, | ||
5696 | u8 value, | ||
5697 | u16 index) | ||
5698 | { | ||
5699 | PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value); | ||
5700 | reg_w_i(gspca_dev, value, index); | ||
5701 | } | ||
5702 | |||
5703 | static u16 i2c_read(struct gspca_dev *gspca_dev, | 5699 | static u16 i2c_read(struct gspca_dev *gspca_dev, |
5704 | u8 reg) | 5700 | u8 reg) |
5705 | { | 5701 | { |
@@ -5708,16 +5704,14 @@ static u16 i2c_read(struct gspca_dev *gspca_dev, | |||
5708 | 5704 | ||
5709 | if (gspca_dev->usb_err < 0) | 5705 | if (gspca_dev->usb_err < 0) |
5710 | return 0; | 5706 | return 0; |
5711 | reg_w_i(gspca_dev, reg, 0x0092); | 5707 | reg_w(gspca_dev, reg, 0x0092); |
5712 | reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */ | 5708 | reg_w(gspca_dev, 0x02, 0x0090); /* <- read command */ |
5713 | msleep(20); | 5709 | msleep(20); |
5714 | retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ | 5710 | retbyte = reg_r(gspca_dev, 0x0091); /* read status */ |
5715 | if (retbyte != 0x00) | 5711 | if (retbyte != 0x00) |
5716 | pr_err("i2c_r status error %02x\n", retbyte); | 5712 | pr_err("i2c_r status error %02x\n", retbyte); |
5717 | retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ | 5713 | retval = reg_r(gspca_dev, 0x0095); /* read Lowbyte */ |
5718 | retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ | 5714 | retval |= reg_r(gspca_dev, 0x0096) << 8; /* read Hightbyte */ |
5719 | PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", | ||
5720 | reg, retval, retbyte); | ||
5721 | return retval; | 5715 | return retval; |
5722 | } | 5716 | } |
5723 | 5717 | ||
@@ -5730,16 +5724,14 @@ static u8 i2c_write(struct gspca_dev *gspca_dev, | |||
5730 | 5724 | ||
5731 | if (gspca_dev->usb_err < 0) | 5725 | if (gspca_dev->usb_err < 0) |
5732 | return 0; | 5726 | return 0; |
5733 | reg_w_i(gspca_dev, reg, 0x92); | 5727 | reg_w(gspca_dev, reg, 0x92); |
5734 | reg_w_i(gspca_dev, valL, 0x93); | 5728 | reg_w(gspca_dev, valL, 0x93); |
5735 | reg_w_i(gspca_dev, valH, 0x94); | 5729 | reg_w(gspca_dev, valH, 0x94); |
5736 | reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */ | 5730 | reg_w(gspca_dev, 0x01, 0x90); /* <- write command */ |
5737 | msleep(1); | 5731 | msleep(1); |
5738 | retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ | 5732 | retbyte = reg_r(gspca_dev, 0x0091); /* read status */ |
5739 | if (retbyte != 0x00) | 5733 | if (retbyte != 0x00) |
5740 | pr_err("i2c_w status error %02x\n", retbyte); | 5734 | pr_err("i2c_w status error %02x\n", retbyte); |
5741 | PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", | ||
5742 | reg, valH, valL, retbyte); | ||
5743 | return retbyte; | 5735 | return retbyte; |
5744 | } | 5736 | } |
5745 | 5737 | ||
@@ -5906,6 +5898,8 @@ static void getexposure(struct gspca_dev *gspca_dev) | |||
5906 | { | 5898 | { |
5907 | struct sd *sd = (struct sd *) gspca_dev; | 5899 | struct sd *sd = (struct sd *) gspca_dev; |
5908 | 5900 | ||
5901 | if (sd->sensor != SENSOR_HV7131R) | ||
5902 | return; | ||
5909 | sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) | 5903 | sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) |
5910 | | (i2c_read(gspca_dev, 0x26) << 1) | 5904 | | (i2c_read(gspca_dev, 0x26) << 1) |
5911 | | (i2c_read(gspca_dev, 0x27) >> 7); | 5905 | | (i2c_read(gspca_dev, 0x27) >> 7); |
@@ -5916,6 +5910,8 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
5916 | struct sd *sd = (struct sd *) gspca_dev; | 5910 | struct sd *sd = (struct sd *) gspca_dev; |
5917 | int val; | 5911 | int val; |
5918 | 5912 | ||
5913 | if (sd->sensor != SENSOR_HV7131R) | ||
5914 | return; | ||
5919 | val = sd->ctrls[EXPOSURE].val; | 5915 | val = sd->ctrls[EXPOSURE].val; |
5920 | i2c_write(gspca_dev, 0x25, val >> 9, 0x00); | 5916 | i2c_write(gspca_dev, 0x25, val >> 9, 0x00); |
5921 | i2c_write(gspca_dev, 0x26, val >> 1, 0x00); | 5917 | i2c_write(gspca_dev, 0x26, val >> 1, 0x00); |
@@ -5925,32 +5921,20 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
5925 | static void setquality(struct gspca_dev *gspca_dev) | 5921 | static void setquality(struct gspca_dev *gspca_dev) |
5926 | { | 5922 | { |
5927 | struct sd *sd = (struct sd *) gspca_dev; | 5923 | struct sd *sd = (struct sd *) gspca_dev; |
5928 | u8 frxt; | 5924 | s8 reg07; |
5929 | 5925 | ||
5926 | reg07 = 0; | ||
5930 | switch (sd->sensor) { | 5927 | switch (sd->sensor) { |
5931 | case SENSOR_ADCM2700: | ||
5932 | case SENSOR_GC0305: | ||
5933 | case SENSOR_HV7131B: | ||
5934 | case SENSOR_HV7131R: | ||
5935 | case SENSOR_OV7620: | 5928 | case SENSOR_OV7620: |
5929 | reg07 = 0x30; | ||
5930 | break; | ||
5931 | case SENSOR_HV7131R: | ||
5936 | case SENSOR_PAS202B: | 5932 | case SENSOR_PAS202B: |
5937 | case SENSOR_PO2030: | 5933 | return; /* done by work queue */ |
5938 | return; | ||
5939 | } | 5934 | } |
5940 | /*fixme: is it really 0008 0007 0018 for all other sensors? */ | 5935 | reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); |
5941 | reg_w(gspca_dev, QUANT_VAL, 0x0008); | 5936 | if (reg07 != 0) |
5942 | frxt = 0x30; | 5937 | reg_w(gspca_dev, reg07, 0x0007); |
5943 | reg_w(gspca_dev, frxt, 0x0007); | ||
5944 | #if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2 | ||
5945 | frxt = 0xff; | ||
5946 | #elif QUANT_VAL == 3 | ||
5947 | frxt = 0xf0; | ||
5948 | #elif QUANT_VAL == 4 | ||
5949 | frxt = 0xe0; | ||
5950 | #else | ||
5951 | frxt = 0x20; | ||
5952 | #endif | ||
5953 | reg_w(gspca_dev, frxt, 0x0018); | ||
5954 | } | 5938 | } |
5955 | 5939 | ||
5956 | /* Matches the sensor's internal frame rate to the lighting frequency. | 5940 | /* Matches the sensor's internal frame rate to the lighting frequency. |
@@ -6084,6 +6068,115 @@ static void setautogain(struct gspca_dev *gspca_dev) | |||
6084 | reg_w(gspca_dev, autoval, 0x0180); | 6068 | reg_w(gspca_dev, autoval, 0x0180); |
6085 | } | 6069 | } |
6086 | 6070 | ||
6071 | /* update the transfer parameters */ | ||
6072 | /* This function is executed from a work queue. */ | ||
6073 | /* The exact use of the bridge registers 07 and 08 is not known. | ||
6074 | * The following algorithm has been adapted from ms-win traces */ | ||
6075 | static void transfer_update(struct work_struct *work) | ||
6076 | { | ||
6077 | struct sd *sd = container_of(work, struct sd, work); | ||
6078 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
6079 | int change, good; | ||
6080 | u8 reg07, reg11; | ||
6081 | |||
6082 | /* synchronize with the main driver and initialize the registers */ | ||
6083 | mutex_lock(&gspca_dev->usb_lock); | ||
6084 | reg07 = 0; /* max */ | ||
6085 | reg_w(gspca_dev, reg07, 0x0007); | ||
6086 | reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); | ||
6087 | mutex_unlock(&gspca_dev->usb_lock); | ||
6088 | |||
6089 | good = 0; | ||
6090 | for (;;) { | ||
6091 | msleep(100); | ||
6092 | |||
6093 | /* get the transfer status */ | ||
6094 | /* the bit 0 of the bridge register 11 indicates overflow */ | ||
6095 | mutex_lock(&gspca_dev->usb_lock); | ||
6096 | if (!gspca_dev->present || !gspca_dev->streaming) | ||
6097 | goto err; | ||
6098 | reg11 = reg_r(gspca_dev, 0x0011); | ||
6099 | if (gspca_dev->usb_err < 0 | ||
6100 | || !gspca_dev->present || !gspca_dev->streaming) | ||
6101 | goto err; | ||
6102 | |||
6103 | change = reg11 & 0x01; | ||
6104 | if (change) { /* overflow */ | ||
6105 | switch (reg07) { | ||
6106 | case 0: /* max */ | ||
6107 | reg07 = sd->sensor == SENSOR_HV7131R | ||
6108 | ? 0x30 : 0x32; | ||
6109 | if (sd->reg08 != 0) { | ||
6110 | change = 3; | ||
6111 | sd->reg08--; | ||
6112 | } | ||
6113 | break; | ||
6114 | case 0x32: | ||
6115 | reg07 -= 4; | ||
6116 | break; | ||
6117 | default: | ||
6118 | reg07 -= 2; | ||
6119 | break; | ||
6120 | case 2: | ||
6121 | change = 0; /* already min */ | ||
6122 | break; | ||
6123 | } | ||
6124 | good = 0; | ||
6125 | } else { /* no overflow */ | ||
6126 | if (reg07 != 0) { /* if not max */ | ||
6127 | good++; | ||
6128 | if (good >= 10) { | ||
6129 | good = 0; | ||
6130 | change = 1; | ||
6131 | reg07 += 2; | ||
6132 | switch (reg07) { | ||
6133 | case 0x30: | ||
6134 | if (sd->sensor == SENSOR_PAS202B) | ||
6135 | reg07 += 2; | ||
6136 | break; | ||
6137 | case 0x32: | ||
6138 | case 0x34: | ||
6139 | reg07 = 0; | ||
6140 | break; | ||
6141 | } | ||
6142 | } | ||
6143 | } else { /* reg07 max */ | ||
6144 | if (sd->reg08 < sizeof jpeg_qual - 1) { | ||
6145 | good++; | ||
6146 | if (good > 10) { | ||
6147 | sd->reg08++; | ||
6148 | change = 2; | ||
6149 | } | ||
6150 | } | ||
6151 | } | ||
6152 | } | ||
6153 | if (change) { | ||
6154 | if (change & 1) { | ||
6155 | reg_w(gspca_dev, reg07, 0x0007); | ||
6156 | if (gspca_dev->usb_err < 0 | ||
6157 | || !gspca_dev->present | ||
6158 | || !gspca_dev->streaming) | ||
6159 | goto err; | ||
6160 | } | ||
6161 | if (change & 2) { | ||
6162 | reg_w(gspca_dev, sd->reg08, | ||
6163 | ZC3XX_R008_CLOCKSETTING); | ||
6164 | if (gspca_dev->usb_err < 0 | ||
6165 | || !gspca_dev->present | ||
6166 | || !gspca_dev->streaming) | ||
6167 | goto err; | ||
6168 | sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08]; | ||
6169 | jpeg_set_qual(sd->jpeg_hdr, | ||
6170 | jpeg_qual[sd->reg08]); | ||
6171 | } | ||
6172 | } | ||
6173 | mutex_unlock(&gspca_dev->usb_lock); | ||
6174 | } | ||
6175 | return; | ||
6176 | err: | ||
6177 | mutex_unlock(&gspca_dev->usb_lock); | ||
6178 | } | ||
6179 | |||
6087 | static void send_unknown(struct gspca_dev *gspca_dev, int sensor) | 6180 | static void send_unknown(struct gspca_dev *gspca_dev, int sensor) |
6088 | { | 6181 | { |
6089 | reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ | 6182 | reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ |
@@ -6411,7 +6504,9 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
6411 | sd->sensor = id->driver_info; | 6504 | sd->sensor = id->driver_info; |
6412 | 6505 | ||
6413 | gspca_dev->cam.ctrls = sd->ctrls; | 6506 | gspca_dev->cam.ctrls = sd->ctrls; |
6414 | sd->quality = QUALITY_DEF; | 6507 | sd->reg08 = REG08_DEF; |
6508 | |||
6509 | INIT_WORK(&sd->work, transfer_update); | ||
6415 | 6510 | ||
6416 | return 0; | 6511 | return 0; |
6417 | } | 6512 | } |
@@ -6464,6 +6559,27 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
6464 | [SENSOR_PO2030] = 1, | 6559 | [SENSOR_PO2030] = 1, |
6465 | [SENSOR_TAS5130C] = 1, | 6560 | [SENSOR_TAS5130C] = 1, |
6466 | }; | 6561 | }; |
6562 | static const u8 reg08_tb[SENSOR_MAX] = { | ||
6563 | [SENSOR_ADCM2700] = 1, | ||
6564 | [SENSOR_CS2102] = 3, | ||
6565 | [SENSOR_CS2102K] = 3, | ||
6566 | [SENSOR_GC0303] = 2, | ||
6567 | [SENSOR_GC0305] = 3, | ||
6568 | [SENSOR_HDCS2020] = 1, | ||
6569 | [SENSOR_HV7131B] = 3, | ||
6570 | [SENSOR_HV7131R] = 3, | ||
6571 | [SENSOR_ICM105A] = 3, | ||
6572 | [SENSOR_MC501CB] = 3, | ||
6573 | [SENSOR_MT9V111_1] = 3, | ||
6574 | [SENSOR_MT9V111_3] = 3, | ||
6575 | [SENSOR_OV7620] = 1, | ||
6576 | [SENSOR_OV7630C] = 3, | ||
6577 | [SENSOR_PAS106] = 3, | ||
6578 | [SENSOR_PAS202B] = 3, | ||
6579 | [SENSOR_PB0330] = 3, | ||
6580 | [SENSOR_PO2030] = 2, | ||
6581 | [SENSOR_TAS5130C] = 3, | ||
6582 | }; | ||
6467 | 6583 | ||
6468 | sensor = zcxx_probeSensor(gspca_dev); | 6584 | sensor = zcxx_probeSensor(gspca_dev); |
6469 | if (sensor >= 0) | 6585 | if (sensor >= 0) |
@@ -6528,7 +6644,6 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
6528 | case 0x0e: | 6644 | case 0x0e: |
6529 | PDEBUG(D_PROBE, "Find Sensor PAS202B"); | 6645 | PDEBUG(D_PROBE, "Find Sensor PAS202B"); |
6530 | sd->sensor = SENSOR_PAS202B; | 6646 | sd->sensor = SENSOR_PAS202B; |
6531 | /* sd->sharpness = 1; */ | ||
6532 | break; | 6647 | break; |
6533 | case 0x0f: | 6648 | case 0x0f: |
6534 | PDEBUG(D_PROBE, "Find Sensor PAS106"); | 6649 | PDEBUG(D_PROBE, "Find Sensor PAS106"); |
@@ -6616,13 +6731,21 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
6616 | } | 6731 | } |
6617 | 6732 | ||
6618 | sd->ctrls[GAMMA].def = gamma[sd->sensor]; | 6733 | sd->ctrls[GAMMA].def = gamma[sd->sensor]; |
6734 | sd->reg08 = reg08_tb[sd->sensor]; | ||
6735 | sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08]; | ||
6736 | sd->ctrls[QUALITY].min = jpeg_qual[0]; | ||
6737 | sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1]; | ||
6619 | 6738 | ||
6620 | switch (sd->sensor) { | 6739 | switch (sd->sensor) { |
6621 | case SENSOR_HV7131R: | 6740 | case SENSOR_HV7131R: |
6741 | gspca_dev->ctrl_dis = (1 << QUALITY); | ||
6622 | break; | 6742 | break; |
6623 | case SENSOR_OV7630C: | 6743 | case SENSOR_OV7630C: |
6624 | gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); | 6744 | gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); |
6625 | break; | 6745 | break; |
6746 | case SENSOR_PAS202B: | ||
6747 | gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE); | ||
6748 | break; | ||
6626 | default: | 6749 | default: |
6627 | gspca_dev->ctrl_dis = (1 << EXPOSURE); | 6750 | gspca_dev->ctrl_dis = (1 << EXPOSURE); |
6628 | break; | 6751 | break; |
@@ -6685,7 +6808,6 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
6685 | /* create the JPEG header */ | 6808 | /* create the JPEG header */ |
6686 | jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, | 6809 | jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, |
6687 | 0x21); /* JPEG 422 */ | 6810 | 0x21); /* JPEG 422 */ |
6688 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | ||
6689 | 6811 | ||
6690 | mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | 6812 | mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; |
6691 | switch (sd->sensor) { | 6813 | switch (sd->sensor) { |
@@ -6761,10 +6883,9 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
6761 | reg_r(gspca_dev, 0x0180); /* from win */ | 6883 | reg_r(gspca_dev, 0x0180); /* from win */ |
6762 | reg_w(gspca_dev, 0x00, 0x0180); | 6884 | reg_w(gspca_dev, 0x00, 0x0180); |
6763 | break; | 6885 | break; |
6764 | default: | ||
6765 | setquality(gspca_dev); | ||
6766 | break; | ||
6767 | } | 6886 | } |
6887 | setquality(gspca_dev); | ||
6888 | jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]); | ||
6768 | setlightfreq(gspca_dev); | 6889 | setlightfreq(gspca_dev); |
6769 | 6890 | ||
6770 | switch (sd->sensor) { | 6891 | switch (sd->sensor) { |
@@ -6776,8 +6897,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
6776 | reg_w(gspca_dev, 0x40, 0x0117); | 6897 | reg_w(gspca_dev, 0x40, 0x0117); |
6777 | break; | 6898 | break; |
6778 | case SENSOR_HV7131R: | 6899 | case SENSOR_HV7131R: |
6779 | if (!sd->ctrls[AUTOGAIN].val) | 6900 | setexposure(gspca_dev); |
6780 | setexposure(gspca_dev); | ||
6781 | reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); | 6901 | reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); |
6782 | break; | 6902 | break; |
6783 | case SENSOR_GC0305: | 6903 | case SENSOR_GC0305: |
@@ -6802,13 +6922,19 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
6802 | } | 6922 | } |
6803 | 6923 | ||
6804 | setautogain(gspca_dev); | 6924 | setautogain(gspca_dev); |
6805 | switch (sd->sensor) { | 6925 | |
6806 | case SENSOR_PO2030: | 6926 | /* start the transfer update thread if needed */ |
6807 | msleep(50); | 6927 | if (gspca_dev->usb_err >= 0) { |
6808 | reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */ | 6928 | switch (sd->sensor) { |
6809 | reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING); | 6929 | case SENSOR_HV7131R: |
6810 | break; | 6930 | case SENSOR_PAS202B: |
6931 | sd->work_thread = | ||
6932 | create_singlethread_workqueue(KBUILD_MODNAME); | ||
6933 | queue_work(sd->work_thread, &sd->work); | ||
6934 | break; | ||
6935 | } | ||
6811 | } | 6936 | } |
6937 | |||
6812 | return gspca_dev->usb_err; | 6938 | return gspca_dev->usb_err; |
6813 | } | 6939 | } |
6814 | 6940 | ||
@@ -6817,6 +6943,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
6817 | { | 6943 | { |
6818 | struct sd *sd = (struct sd *) gspca_dev; | 6944 | struct sd *sd = (struct sd *) gspca_dev; |
6819 | 6945 | ||
6946 | if (sd->work_thread != NULL) { | ||
6947 | mutex_unlock(&gspca_dev->usb_lock); | ||
6948 | destroy_workqueue(sd->work_thread); | ||
6949 | mutex_lock(&gspca_dev->usb_lock); | ||
6950 | sd->work_thread = NULL; | ||
6951 | } | ||
6820 | if (!gspca_dev->present) | 6952 | if (!gspca_dev->present) |
6821 | return; | 6953 | return; |
6822 | send_unknown(gspca_dev, sd->sensor); | 6954 | send_unknown(gspca_dev, sd->sensor); |
@@ -6893,19 +7025,33 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, | |||
6893 | return -EINVAL; | 7025 | return -EINVAL; |
6894 | } | 7026 | } |
6895 | 7027 | ||
7028 | static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val) | ||
7029 | { | ||
7030 | struct sd *sd = (struct sd *) gspca_dev; | ||
7031 | int i; | ||
7032 | |||
7033 | for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) { | ||
7034 | if (val <= jpeg_qual[i]) | ||
7035 | break; | ||
7036 | } | ||
7037 | if (i > 0 | ||
7038 | && i == sd->reg08 | ||
7039 | && val < jpeg_qual[sd->reg08]) | ||
7040 | i--; | ||
7041 | sd->reg08 = i; | ||
7042 | sd->ctrls[QUALITY].val = jpeg_qual[i]; | ||
7043 | if (gspca_dev->streaming) | ||
7044 | jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); | ||
7045 | return gspca_dev->usb_err; | ||
7046 | } | ||
7047 | |||
6896 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, | 7048 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, |
6897 | struct v4l2_jpegcompression *jcomp) | 7049 | struct v4l2_jpegcompression *jcomp) |
6898 | { | 7050 | { |
6899 | struct sd *sd = (struct sd *) gspca_dev; | 7051 | struct sd *sd = (struct sd *) gspca_dev; |
6900 | 7052 | ||
6901 | if (jcomp->quality < QUALITY_MIN) | 7053 | sd_setquality(gspca_dev, jcomp->quality); |
6902 | sd->quality = QUALITY_MIN; | 7054 | jcomp->quality = sd->ctrls[QUALITY].val; |
6903 | else if (jcomp->quality > QUALITY_MAX) | ||
6904 | sd->quality = QUALITY_MAX; | ||
6905 | else | ||
6906 | sd->quality = jcomp->quality; | ||
6907 | if (gspca_dev->streaming) | ||
6908 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | ||
6909 | return gspca_dev->usb_err; | 7055 | return gspca_dev->usb_err; |
6910 | } | 7056 | } |
6911 | 7057 | ||
@@ -6915,7 +7061,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, | |||
6915 | struct sd *sd = (struct sd *) gspca_dev; | 7061 | struct sd *sd = (struct sd *) gspca_dev; |
6916 | 7062 | ||
6917 | memset(jcomp, 0, sizeof *jcomp); | 7063 | memset(jcomp, 0, sizeof *jcomp); |
6918 | jcomp->quality = sd->quality; | 7064 | jcomp->quality = sd->ctrls[QUALITY].val; |
6919 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | 7065 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT |
6920 | | V4L2_JPEG_MARKER_DQT; | 7066 | | V4L2_JPEG_MARKER_DQT; |
6921 | return 0; | 7067 | return 0; |
@@ -6938,7 +7084,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, | |||
6938 | #endif | 7084 | #endif |
6939 | 7085 | ||
6940 | static const struct sd_desc sd_desc = { | 7086 | static const struct sd_desc sd_desc = { |
6941 | .name = MODULE_NAME, | 7087 | .name = KBUILD_MODNAME, |
6942 | .ctrls = sd_ctrls, | 7088 | .ctrls = sd_ctrls, |
6943 | .nctrls = ARRAY_SIZE(sd_ctrls), | 7089 | .nctrls = ARRAY_SIZE(sd_ctrls), |
6944 | .config = sd_config, | 7090 | .config = sd_config, |
@@ -7023,7 +7169,7 @@ static int sd_probe(struct usb_interface *intf, | |||
7023 | 7169 | ||
7024 | /* USB driver */ | 7170 | /* USB driver */ |
7025 | static struct usb_driver sd_driver = { | 7171 | static struct usb_driver sd_driver = { |
7026 | .name = MODULE_NAME, | 7172 | .name = KBUILD_MODNAME, |
7027 | .id_table = device_table, | 7173 | .id_table = device_table, |
7028 | .probe = sd_probe, | 7174 | .probe = sd_probe, |
7029 | .disconnect = gspca_disconnect, | 7175 | .disconnect = gspca_disconnect, |
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index eec75bb57203..351e9bafe8fe 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c | |||
@@ -468,18 +468,7 @@ static struct i2c_driver imx074_i2c_driver = { | |||
468 | .id_table = imx074_id, | 468 | .id_table = imx074_id, |
469 | }; | 469 | }; |
470 | 470 | ||
471 | static int __init imx074_mod_init(void) | 471 | module_i2c_driver(imx074_i2c_driver); |
472 | { | ||
473 | return i2c_add_driver(&imx074_i2c_driver); | ||
474 | } | ||
475 | |||
476 | static void __exit imx074_mod_exit(void) | ||
477 | { | ||
478 | i2c_del_driver(&imx074_i2c_driver); | ||
479 | } | ||
480 | |||
481 | module_init(imx074_mod_init); | ||
482 | module_exit(imx074_mod_exit); | ||
483 | 472 | ||
484 | MODULE_DESCRIPTION("Sony IMX074 Camera driver"); | 473 | MODULE_DESCRIPTION("Sony IMX074 Camera driver"); |
485 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | 474 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); |
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c index e5ed4db32e7b..548236333cce 100644 --- a/drivers/media/video/indycam.c +++ b/drivers/media/video/indycam.c | |||
@@ -387,15 +387,4 @@ static struct i2c_driver indycam_driver = { | |||
387 | .id_table = indycam_id, | 387 | .id_table = indycam_id, |
388 | }; | 388 | }; |
389 | 389 | ||
390 | static __init int init_indycam(void) | 390 | module_i2c_driver(indycam_driver); |
391 | { | ||
392 | return i2c_add_driver(&indycam_driver); | ||
393 | } | ||
394 | |||
395 | static __exit void exit_indycam(void) | ||
396 | { | ||
397 | i2c_del_driver(&indycam_driver); | ||
398 | } | ||
399 | |||
400 | module_init(init_indycam); | ||
401 | module_exit(exit_indycam); | ||
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index a7c41d32f414..04f192a0398a 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c | |||
@@ -471,7 +471,7 @@ static const struct i2c_device_id ir_kbd_id[] = { | |||
471 | { } | 471 | { } |
472 | }; | 472 | }; |
473 | 473 | ||
474 | static struct i2c_driver driver = { | 474 | static struct i2c_driver ir_kbd_driver = { |
475 | .driver = { | 475 | .driver = { |
476 | .name = "ir-kbd-i2c", | 476 | .name = "ir-kbd-i2c", |
477 | }, | 477 | }, |
@@ -480,21 +480,10 @@ static struct i2c_driver driver = { | |||
480 | .id_table = ir_kbd_id, | 480 | .id_table = ir_kbd_id, |
481 | }; | 481 | }; |
482 | 482 | ||
483 | module_i2c_driver(ir_kbd_driver); | ||
484 | |||
483 | /* ----------------------------------------------------------------------- */ | 485 | /* ----------------------------------------------------------------------- */ |
484 | 486 | ||
485 | MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); | 487 | MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); |
486 | MODULE_DESCRIPTION("input driver for i2c IR remote controls"); | 488 | MODULE_DESCRIPTION("input driver for i2c IR remote controls"); |
487 | MODULE_LICENSE("GPL"); | 489 | MODULE_LICENSE("GPL"); |
488 | |||
489 | static int __init ir_init(void) | ||
490 | { | ||
491 | return i2c_add_driver(&driver); | ||
492 | } | ||
493 | |||
494 | static void __exit ir_fini(void) | ||
495 | { | ||
496 | i2c_del_driver(&driver); | ||
497 | } | ||
498 | |||
499 | module_init(ir_init); | ||
500 | module_exit(ir_fini); | ||
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 71ab76a5ab26..77de8a45b46f 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile | |||
@@ -7,8 +7,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ | |||
7 | obj-$(CONFIG_VIDEO_IVTV) += ivtv.o | 7 | obj-$(CONFIG_VIDEO_IVTV) += ivtv.o |
8 | obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o | 8 | obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o |
9 | 9 | ||
10 | ccflags-y += -Idrivers/media/video | 10 | ccflags-y += -I$(srctree)/drivers/media/video |
11 | ccflags-y += -Idrivers/media/common/tuners | 11 | ccflags-y += -I$(srctree)/drivers/media/common/tuners |
12 | ccflags-y += -Idrivers/media/dvb/dvb-core | 12 | ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core |
13 | ccflags-y += -Idrivers/media/dvb/frontends | 13 | ccflags-y += -I$(srctree)/drivers/media/dvb/frontends |
14 | 14 | ||
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index b31ee1bceef8..c60424601cb9 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "ivtv-driver.h" | 21 | #include "ivtv-driver.h" |
22 | #include "ivtv-ioctl.h" | 22 | #include "ivtv-ioctl.h" |
23 | #include "ivtv-controls.h" | 23 | #include "ivtv-controls.h" |
24 | #include "ivtv-mailbox.h" | ||
24 | 25 | ||
25 | static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) | 26 | static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) |
26 | { | 27 | { |
@@ -99,3 +100,64 @@ struct cx2341x_handler_ops ivtv_cxhdl_ops = { | |||
99 | .s_video_encoding = ivtv_s_video_encoding, | 100 | .s_video_encoding = ivtv_s_video_encoding, |
100 | .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt, | 101 | .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt, |
101 | }; | 102 | }; |
103 | |||
104 | int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame) | ||
105 | { | ||
106 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
107 | |||
108 | if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { | ||
109 | *pts = (s64)((u64)itv->last_dec_timing[2] << 32) | | ||
110 | (u64)itv->last_dec_timing[1]; | ||
111 | *frame = itv->last_dec_timing[0]; | ||
112 | return 0; | ||
113 | } | ||
114 | *pts = 0; | ||
115 | *frame = 0; | ||
116 | if (atomic_read(&itv->decoding)) { | ||
117 | if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { | ||
118 | IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); | ||
119 | return -EIO; | ||
120 | } | ||
121 | memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); | ||
122 | set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
123 | *pts = (s64)((u64) data[2] << 32) | (u64) data[1]; | ||
124 | *frame = data[0]; | ||
125 | /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ | ||
126 | } | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
131 | { | ||
132 | struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl); | ||
133 | |||
134 | switch (ctrl->id) { | ||
135 | /* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME | ||
136 | control cluster */ | ||
137 | case V4L2_CID_MPEG_VIDEO_DEC_PTS: | ||
138 | return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64, | ||
139 | &itv->ctrl_frame->val64); | ||
140 | } | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl) | ||
145 | { | ||
146 | struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl); | ||
147 | |||
148 | switch (ctrl->id) { | ||
149 | /* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK | ||
150 | control cluster */ | ||
151 | case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: | ||
152 | itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1; | ||
153 | itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1; | ||
154 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
155 | break; | ||
156 | } | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | const struct v4l2_ctrl_ops ivtv_hdl_out_ops = { | ||
161 | .s_ctrl = ivtv_s_ctrl, | ||
162 | .g_volatile_ctrl = ivtv_g_volatile_ctrl, | ||
163 | }; | ||
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h index d12893dd0183..3999e6358312 100644 --- a/drivers/media/video/ivtv/ivtv-controls.h +++ b/drivers/media/video/ivtv/ivtv-controls.h | |||
@@ -22,5 +22,7 @@ | |||
22 | #define IVTV_CONTROLS_H | 22 | #define IVTV_CONTROLS_H |
23 | 23 | ||
24 | extern struct cx2341x_handler_ops ivtv_cxhdl_ops; | 24 | extern struct cx2341x_handler_ops ivtv_cxhdl_ops; |
25 | extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops; | ||
26 | int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame); | ||
25 | 27 | ||
26 | #endif | 28 | #endif |
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 3949b7dc2368..679262ed13bc 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -55,7 +55,7 @@ | |||
55 | #include "ivtv-routing.h" | 55 | #include "ivtv-routing.h" |
56 | #include "ivtv-controls.h" | 56 | #include "ivtv-controls.h" |
57 | #include "ivtv-gpio.h" | 57 | #include "ivtv-gpio.h" |
58 | 58 | #include <linux/dma-mapping.h> | |
59 | #include <media/tveeprom.h> | 59 | #include <media/tveeprom.h> |
60 | #include <media/saa7115.h> | 60 | #include <media/saa7115.h> |
61 | #include <media/v4l2-chip-ident.h> | 61 | #include <media/v4l2-chip-ident.h> |
@@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, | |||
99 | 99 | ||
100 | static unsigned int cardtype_c = 1; | 100 | static unsigned int cardtype_c = 1; |
101 | static unsigned int tuner_c = 1; | 101 | static unsigned int tuner_c = 1; |
102 | static bool radio_c = 1; | 102 | static int radio_c = 1; |
103 | static unsigned int i2c_clock_period_c = 1; | 103 | static unsigned int i2c_clock_period_c = 1; |
104 | static char pal[] = "---"; | 104 | static char pal[] = "---"; |
105 | static char secam[] = "--"; | 105 | static char secam[] = "--"; |
@@ -139,7 +139,7 @@ static int tunertype = -1; | |||
139 | static int newi2c = -1; | 139 | static int newi2c = -1; |
140 | 140 | ||
141 | module_param_array(tuner, int, &tuner_c, 0644); | 141 | module_param_array(tuner, int, &tuner_c, 0644); |
142 | module_param_array(radio, bool, &radio_c, 0644); | 142 | module_param_array(radio, int, &radio_c, 0644); |
143 | module_param_array(cardtype, int, &cardtype_c, 0644); | 143 | module_param_array(cardtype, int, &cardtype_c, 0644); |
144 | module_param_string(pal, pal, sizeof(pal), 0644); | 144 | module_param_string(pal, pal, sizeof(pal), 0644); |
145 | module_param_string(secam, secam, sizeof(secam), 0644); | 145 | module_param_string(secam, secam, sizeof(secam), 0644); |
@@ -744,8 +744,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) | |||
744 | 744 | ||
745 | itv->cur_dma_stream = -1; | 745 | itv->cur_dma_stream = -1; |
746 | itv->cur_pio_stream = -1; | 746 | itv->cur_pio_stream = -1; |
747 | itv->audio_stereo_mode = AUDIO_STEREO; | ||
748 | itv->audio_bilingual_mode = AUDIO_MONO_LEFT; | ||
749 | 747 | ||
750 | /* Ctrls */ | 748 | /* Ctrls */ |
751 | itv->speed = 1000; | 749 | itv->speed = 1000; |
@@ -815,7 +813,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, | |||
815 | IVTV_ERR("Can't enable device!\n"); | 813 | IVTV_ERR("Can't enable device!\n"); |
816 | return -EIO; | 814 | return -EIO; |
817 | } | 815 | } |
818 | if (pci_set_dma_mask(pdev, 0xffffffff)) { | 816 | if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { |
819 | IVTV_ERR("No suitable DMA available.\n"); | 817 | IVTV_ERR("No suitable DMA available.\n"); |
820 | return -EIO; | 818 | return -EIO; |
821 | } | 819 | } |
@@ -1200,6 +1198,32 @@ static int __devinit ivtv_probe(struct pci_dev *pdev, | |||
1200 | itv->tuner_std = itv->std; | 1198 | itv->tuner_std = itv->std; |
1201 | 1199 | ||
1202 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { | 1200 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { |
1201 | struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler; | ||
1202 | |||
1203 | itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops, | ||
1204 | V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0); | ||
1205 | itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops, | ||
1206 | V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0); | ||
1207 | /* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported, | ||
1208 | mask that menu item. */ | ||
1209 | itv->ctrl_audio_playback = | ||
1210 | v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops, | ||
1211 | V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK, | ||
1212 | V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO, | ||
1213 | 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO, | ||
1214 | V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO); | ||
1215 | itv->ctrl_audio_multilingual_playback = | ||
1216 | v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops, | ||
1217 | V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK, | ||
1218 | V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO, | ||
1219 | 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO, | ||
1220 | V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT); | ||
1221 | if (hdl->error) { | ||
1222 | retval = hdl->error; | ||
1223 | goto free_i2c; | ||
1224 | } | ||
1225 | v4l2_ctrl_cluster(2, &itv->ctrl_pts); | ||
1226 | v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback); | ||
1203 | ivtv_call_all(itv, video, s_std_output, itv->std); | 1227 | ivtv_call_all(itv, video, s_std_output, itv->std); |
1204 | /* Turn off the output signal. The mpeg decoder is not yet | 1228 | /* Turn off the output signal. The mpeg decoder is not yet |
1205 | active so without this you would get a green image until the | 1229 | active so without this you would get a green image until the |
@@ -1236,6 +1260,7 @@ free_streams: | |||
1236 | free_irq: | 1260 | free_irq: |
1237 | free_irq(itv->pdev->irq, (void *)itv); | 1261 | free_irq(itv->pdev->irq, (void *)itv); |
1238 | free_i2c: | 1262 | free_i2c: |
1263 | v4l2_ctrl_handler_free(&itv->cxhdl.hdl); | ||
1239 | exit_ivtv_i2c(itv); | 1264 | exit_ivtv_i2c(itv); |
1240 | free_io: | 1265 | free_io: |
1241 | ivtv_iounmap(itv); | 1266 | ivtv_iounmap(itv); |
@@ -1375,7 +1400,7 @@ static void ivtv_remove(struct pci_dev *pdev) | |||
1375 | else | 1400 | else |
1376 | type = IVTV_DEC_STREAM_TYPE_MPG; | 1401 | type = IVTV_DEC_STREAM_TYPE_MPG; |
1377 | ivtv_stop_v4l2_decode_stream(&itv->streams[type], | 1402 | ivtv_stop_v4l2_decode_stream(&itv->streams[type], |
1378 | VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); | 1403 | V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0); |
1379 | } | 1404 | } |
1380 | ivtv_halt_firmware(itv); | 1405 | ivtv_halt_firmware(itv); |
1381 | } | 1406 | } |
@@ -1391,6 +1416,8 @@ static void ivtv_remove(struct pci_dev *pdev) | |||
1391 | ivtv_streams_cleanup(itv, 1); | 1416 | ivtv_streams_cleanup(itv, 1); |
1392 | ivtv_udma_free(itv); | 1417 | ivtv_udma_free(itv); |
1393 | 1418 | ||
1419 | v4l2_ctrl_handler_free(&itv->cxhdl.hdl); | ||
1420 | |||
1394 | exit_ivtv_i2c(itv); | 1421 | exit_ivtv_i2c(itv); |
1395 | 1422 | ||
1396 | free_irq(itv->pdev->irq, (void *)itv); | 1423 | free_irq(itv->pdev->irq, (void *)itv); |
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 06f3d78389bf..f767df943954 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h | |||
@@ -331,6 +331,7 @@ struct ivtv_stream { | |||
331 | struct ivtv *itv; /* for ease of use */ | 331 | struct ivtv *itv; /* for ease of use */ |
332 | const char *name; /* name of the stream */ | 332 | const char *name; /* name of the stream */ |
333 | int type; /* stream type */ | 333 | int type; /* stream type */ |
334 | u32 caps; /* V4L2 capabilities */ | ||
334 | 335 | ||
335 | struct v4l2_fh *fh; /* pointer to the streaming filehandle */ | 336 | struct v4l2_fh *fh; /* pointer to the streaming filehandle */ |
336 | spinlock_t qlock; /* locks access to the queues */ | 337 | spinlock_t qlock; /* locks access to the queues */ |
@@ -630,6 +631,16 @@ struct ivtv { | |||
630 | 631 | ||
631 | struct v4l2_device v4l2_dev; | 632 | struct v4l2_device v4l2_dev; |
632 | struct cx2341x_handler cxhdl; | 633 | struct cx2341x_handler cxhdl; |
634 | struct { | ||
635 | /* PTS/Frame count control cluster */ | ||
636 | struct v4l2_ctrl *ctrl_pts; | ||
637 | struct v4l2_ctrl *ctrl_frame; | ||
638 | }; | ||
639 | struct { | ||
640 | /* Audio Playback control cluster */ | ||
641 | struct v4l2_ctrl *ctrl_audio_playback; | ||
642 | struct v4l2_ctrl *ctrl_audio_multilingual_playback; | ||
643 | }; | ||
633 | struct v4l2_ctrl_handler hdl_gpio; | 644 | struct v4l2_ctrl_handler hdl_gpio; |
634 | struct v4l2_subdev sd_gpio; /* GPIO sub-device */ | 645 | struct v4l2_subdev sd_gpio; /* GPIO sub-device */ |
635 | u16 instance; | 646 | u16 instance; |
@@ -649,7 +660,6 @@ struct ivtv { | |||
649 | u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ | 660 | u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ |
650 | u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ | 661 | u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ |
651 | 662 | ||
652 | |||
653 | /* Locking */ | 663 | /* Locking */ |
654 | spinlock_t lock; /* lock access to this struct */ | 664 | spinlock_t lock; /* lock access to this struct */ |
655 | struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ | 665 | struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ |
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 2cd6c89b7d91..c9663e885b9f 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c | |||
@@ -900,7 +900,7 @@ int ivtv_v4l2_close(struct file *filp) | |||
900 | if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { | 900 | if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { |
901 | struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; | 901 | struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; |
902 | 902 | ||
903 | ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); | 903 | ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0); |
904 | 904 | ||
905 | /* If all output streams are closed, and if the user doesn't have | 905 | /* If all output streams are closed, and if the user doesn't have |
906 | IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ | 906 | IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ |
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index c4bc48143098..5452beef8e11 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c | |||
@@ -246,34 +246,40 @@ static int ivtv_validate_speed(int cur_speed, int new_speed) | |||
246 | } | 246 | } |
247 | 247 | ||
248 | static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, | 248 | static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, |
249 | struct video_command *vc, int try) | 249 | struct v4l2_decoder_cmd *dc, int try) |
250 | { | 250 | { |
251 | struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | 251 | struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; |
252 | 252 | ||
253 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | 253 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) |
254 | return -EINVAL; | 254 | return -EINVAL; |
255 | 255 | ||
256 | switch (vc->cmd) { | 256 | switch (dc->cmd) { |
257 | case VIDEO_CMD_PLAY: { | 257 | case V4L2_DEC_CMD_START: { |
258 | vc->flags = 0; | 258 | dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO; |
259 | vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); | 259 | dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed); |
260 | if (vc->play.speed < 0) | 260 | if (dc->start.speed < 0) |
261 | vc->play.format = VIDEO_PLAY_FMT_GOP; | 261 | dc->start.format = V4L2_DEC_START_FMT_GOP; |
262 | else | ||
263 | dc->start.format = V4L2_DEC_START_FMT_NONE; | ||
264 | if (dc->start.speed != 500 && dc->start.speed != 1500) | ||
265 | dc->flags = dc->start.speed == 1000 ? 0 : | ||
266 | V4L2_DEC_CMD_START_MUTE_AUDIO; | ||
262 | if (try) break; | 267 | if (try) break; |
263 | 268 | ||
269 | itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO; | ||
264 | if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) | 270 | if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) |
265 | return -EBUSY; | 271 | return -EBUSY; |
266 | if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { | 272 | if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { |
267 | /* forces ivtv_set_speed to be called */ | 273 | /* forces ivtv_set_speed to be called */ |
268 | itv->speed = 0; | 274 | itv->speed = 0; |
269 | } | 275 | } |
270 | return ivtv_start_decoding(id, vc->play.speed); | 276 | return ivtv_start_decoding(id, dc->start.speed); |
271 | } | 277 | } |
272 | 278 | ||
273 | case VIDEO_CMD_STOP: | 279 | case V4L2_DEC_CMD_STOP: |
274 | vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; | 280 | dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK; |
275 | if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) | 281 | if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) |
276 | vc->stop.pts = 0; | 282 | dc->stop.pts = 0; |
277 | if (try) break; | 283 | if (try) break; |
278 | if (atomic_read(&itv->decoding) == 0) | 284 | if (atomic_read(&itv->decoding) == 0) |
279 | return 0; | 285 | return 0; |
@@ -281,22 +287,22 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, | |||
281 | return -EBUSY; | 287 | return -EBUSY; |
282 | 288 | ||
283 | itv->output_mode = OUT_NONE; | 289 | itv->output_mode = OUT_NONE; |
284 | return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); | 290 | return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts); |
285 | 291 | ||
286 | case VIDEO_CMD_FREEZE: | 292 | case V4L2_DEC_CMD_PAUSE: |
287 | vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; | 293 | dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK; |
288 | if (try) break; | 294 | if (try) break; |
289 | if (itv->output_mode != OUT_MPG) | 295 | if (itv->output_mode != OUT_MPG) |
290 | return -EBUSY; | 296 | return -EBUSY; |
291 | if (atomic_read(&itv->decoding) > 0) { | 297 | if (atomic_read(&itv->decoding) > 0) { |
292 | ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, | 298 | ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, |
293 | (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); | 299 | (dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0); |
294 | set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); | 300 | set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); |
295 | } | 301 | } |
296 | break; | 302 | break; |
297 | 303 | ||
298 | case VIDEO_CMD_CONTINUE: | 304 | case V4L2_DEC_CMD_RESUME: |
299 | vc->flags = 0; | 305 | dc->flags = 0; |
300 | if (try) break; | 306 | if (try) break; |
301 | if (itv->output_mode != OUT_MPG) | 307 | if (itv->output_mode != OUT_MPG) |
302 | return -EBUSY; | 308 | return -EBUSY; |
@@ -754,12 +760,15 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register | |||
754 | 760 | ||
755 | static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) | 761 | static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) |
756 | { | 762 | { |
757 | struct ivtv *itv = fh2id(fh)->itv; | 763 | struct ivtv_open_id *id = fh2id(file->private_data); |
764 | struct ivtv *itv = id->itv; | ||
765 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
758 | 766 | ||
759 | strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); | 767 | strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); |
760 | strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); | 768 | strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); |
761 | snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); | 769 | snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); |
762 | vcap->capabilities = itv->v4l2_cap; /* capabilities */ | 770 | vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; |
771 | vcap->device_caps = s->caps; | ||
763 | return 0; | 772 | return 0; |
764 | } | 773 | } |
765 | 774 | ||
@@ -1476,8 +1485,6 @@ static int ivtv_log_status(struct file *file, void *fh) | |||
1476 | struct v4l2_audio audin; | 1485 | struct v4l2_audio audin; |
1477 | int i; | 1486 | int i; |
1478 | 1487 | ||
1479 | IVTV_INFO("================= START STATUS CARD #%d =================\n", | ||
1480 | itv->instance); | ||
1481 | IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); | 1488 | IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); |
1482 | if (itv->hw_flags & IVTV_HW_TVEEPROM) { | 1489 | if (itv->hw_flags & IVTV_HW_TVEEPROM) { |
1483 | struct tveeprom tv; | 1490 | struct tveeprom tv; |
@@ -1501,13 +1508,6 @@ static int ivtv_log_status(struct file *file, void *fh) | |||
1501 | "YUV Frames", | 1508 | "YUV Frames", |
1502 | "Passthrough", | 1509 | "Passthrough", |
1503 | }; | 1510 | }; |
1504 | static const char * const audio_modes[5] = { | ||
1505 | "Stereo", | ||
1506 | "Left", | ||
1507 | "Right", | ||
1508 | "Mono", | ||
1509 | "Swapped" | ||
1510 | }; | ||
1511 | static const char * const alpha_mode[4] = { | 1511 | static const char * const alpha_mode[4] = { |
1512 | "None", | 1512 | "None", |
1513 | "Global", | 1513 | "Global", |
@@ -1536,9 +1536,6 @@ static int ivtv_log_status(struct file *file, void *fh) | |||
1536 | ivtv_get_output(itv, itv->active_output, &vidout); | 1536 | ivtv_get_output(itv, itv->active_output, &vidout); |
1537 | ivtv_get_audio_output(itv, 0, &audout); | 1537 | ivtv_get_audio_output(itv, 0, &audout); |
1538 | IVTV_INFO("Video Output: %s\n", vidout.name); | 1538 | IVTV_INFO("Video Output: %s\n", vidout.name); |
1539 | IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, | ||
1540 | audio_modes[itv->audio_stereo_mode], | ||
1541 | audio_modes[itv->audio_bilingual_mode]); | ||
1542 | if (mode < 0 || mode > OUT_PASSTHROUGH) | 1539 | if (mode < 0 || mode > OUT_PASSTHROUGH) |
1543 | mode = OUT_NONE; | 1540 | mode = OUT_NONE; |
1544 | IVTV_INFO("Output Mode: %s\n", output_modes[mode]); | 1541 | IVTV_INFO("Output Mode: %s\n", output_modes[mode]); |
@@ -1566,12 +1563,27 @@ static int ivtv_log_status(struct file *file, void *fh) | |||
1566 | IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", | 1563 | IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", |
1567 | (long long)itv->mpg_data_received, | 1564 | (long long)itv->mpg_data_received, |
1568 | (long long)itv->vbi_data_inserted); | 1565 | (long long)itv->vbi_data_inserted); |
1569 | IVTV_INFO("================== END STATUS CARD #%d ==================\n", | ||
1570 | itv->instance); | ||
1571 | |||
1572 | return 0; | 1566 | return 0; |
1573 | } | 1567 | } |
1574 | 1568 | ||
1569 | static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) | ||
1570 | { | ||
1571 | struct ivtv_open_id *id = fh2id(file->private_data); | ||
1572 | struct ivtv *itv = id->itv; | ||
1573 | |||
1574 | IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd); | ||
1575 | return ivtv_video_command(itv, id, dec, false); | ||
1576 | } | ||
1577 | |||
1578 | static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) | ||
1579 | { | ||
1580 | struct ivtv_open_id *id = fh2id(file->private_data); | ||
1581 | struct ivtv *itv = id->itv; | ||
1582 | |||
1583 | IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd); | ||
1584 | return ivtv_video_command(itv, id, dec, true); | ||
1585 | } | ||
1586 | |||
1575 | static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) | 1587 | static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) |
1576 | { | 1588 | { |
1577 | struct ivtv_open_id *id = fh2id(filp->private_data); | 1589 | struct ivtv_open_id *id = fh2id(filp->private_data); |
@@ -1605,9 +1617,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) | |||
1605 | return ivtv_yuv_prep_frame(itv, args); | 1617 | return ivtv_yuv_prep_frame(itv, args); |
1606 | } | 1618 | } |
1607 | 1619 | ||
1620 | case IVTV_IOC_PASSTHROUGH_MODE: | ||
1621 | IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n"); | ||
1622 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1623 | return -EINVAL; | ||
1624 | return ivtv_passthrough_mode(itv, *(int *)arg != 0); | ||
1625 | |||
1608 | case VIDEO_GET_PTS: { | 1626 | case VIDEO_GET_PTS: { |
1609 | u32 data[CX2341X_MBOX_MAX_DATA]; | 1627 | s64 *pts = arg; |
1610 | u64 *pts = arg; | 1628 | s64 frame; |
1611 | 1629 | ||
1612 | IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); | 1630 | IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); |
1613 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { | 1631 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { |
@@ -1616,29 +1634,12 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) | |||
1616 | } | 1634 | } |
1617 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | 1635 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) |
1618 | return -EINVAL; | 1636 | return -EINVAL; |
1619 | 1637 | return ivtv_g_pts_frame(itv, pts, &frame); | |
1620 | if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { | ||
1621 | *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | | ||
1622 | (u64)itv->last_dec_timing[1]; | ||
1623 | break; | ||
1624 | } | ||
1625 | *pts = 0; | ||
1626 | if (atomic_read(&itv->decoding)) { | ||
1627 | if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { | ||
1628 | IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); | ||
1629 | return -EIO; | ||
1630 | } | ||
1631 | memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); | ||
1632 | set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
1633 | *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; | ||
1634 | /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ | ||
1635 | } | ||
1636 | break; | ||
1637 | } | 1638 | } |
1638 | 1639 | ||
1639 | case VIDEO_GET_FRAME_COUNT: { | 1640 | case VIDEO_GET_FRAME_COUNT: { |
1640 | u32 data[CX2341X_MBOX_MAX_DATA]; | 1641 | s64 *frame = arg; |
1641 | u64 *frame = arg; | 1642 | s64 pts; |
1642 | 1643 | ||
1643 | IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); | 1644 | IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); |
1644 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { | 1645 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { |
@@ -1647,71 +1648,58 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) | |||
1647 | } | 1648 | } |
1648 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | 1649 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) |
1649 | return -EINVAL; | 1650 | return -EINVAL; |
1650 | 1651 | return ivtv_g_pts_frame(itv, &pts, frame); | |
1651 | if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { | ||
1652 | *frame = itv->last_dec_timing[0]; | ||
1653 | break; | ||
1654 | } | ||
1655 | *frame = 0; | ||
1656 | if (atomic_read(&itv->decoding)) { | ||
1657 | if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { | ||
1658 | IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); | ||
1659 | return -EIO; | ||
1660 | } | ||
1661 | memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); | ||
1662 | set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
1663 | *frame = data[0]; | ||
1664 | } | ||
1665 | break; | ||
1666 | } | 1652 | } |
1667 | 1653 | ||
1668 | case VIDEO_PLAY: { | 1654 | case VIDEO_PLAY: { |
1669 | struct video_command vc; | 1655 | struct v4l2_decoder_cmd dc; |
1670 | 1656 | ||
1671 | IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); | 1657 | IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); |
1672 | memset(&vc, 0, sizeof(vc)); | 1658 | memset(&dc, 0, sizeof(dc)); |
1673 | vc.cmd = VIDEO_CMD_PLAY; | 1659 | dc.cmd = V4L2_DEC_CMD_START; |
1674 | return ivtv_video_command(itv, id, &vc, 0); | 1660 | return ivtv_video_command(itv, id, &dc, 0); |
1675 | } | 1661 | } |
1676 | 1662 | ||
1677 | case VIDEO_STOP: { | 1663 | case VIDEO_STOP: { |
1678 | struct video_command vc; | 1664 | struct v4l2_decoder_cmd dc; |
1679 | 1665 | ||
1680 | IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); | 1666 | IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); |
1681 | memset(&vc, 0, sizeof(vc)); | 1667 | memset(&dc, 0, sizeof(dc)); |
1682 | vc.cmd = VIDEO_CMD_STOP; | 1668 | dc.cmd = V4L2_DEC_CMD_STOP; |
1683 | vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; | 1669 | dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY; |
1684 | return ivtv_video_command(itv, id, &vc, 0); | 1670 | return ivtv_video_command(itv, id, &dc, 0); |
1685 | } | 1671 | } |
1686 | 1672 | ||
1687 | case VIDEO_FREEZE: { | 1673 | case VIDEO_FREEZE: { |
1688 | struct video_command vc; | 1674 | struct v4l2_decoder_cmd dc; |
1689 | 1675 | ||
1690 | IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); | 1676 | IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); |
1691 | memset(&vc, 0, sizeof(vc)); | 1677 | memset(&dc, 0, sizeof(dc)); |
1692 | vc.cmd = VIDEO_CMD_FREEZE; | 1678 | dc.cmd = V4L2_DEC_CMD_PAUSE; |
1693 | return ivtv_video_command(itv, id, &vc, 0); | 1679 | return ivtv_video_command(itv, id, &dc, 0); |
1694 | } | 1680 | } |
1695 | 1681 | ||
1696 | case VIDEO_CONTINUE: { | 1682 | case VIDEO_CONTINUE: { |
1697 | struct video_command vc; | 1683 | struct v4l2_decoder_cmd dc; |
1698 | 1684 | ||
1699 | IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); | 1685 | IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); |
1700 | memset(&vc, 0, sizeof(vc)); | 1686 | memset(&dc, 0, sizeof(dc)); |
1701 | vc.cmd = VIDEO_CMD_CONTINUE; | 1687 | dc.cmd = V4L2_DEC_CMD_RESUME; |
1702 | return ivtv_video_command(itv, id, &vc, 0); | 1688 | return ivtv_video_command(itv, id, &dc, 0); |
1703 | } | 1689 | } |
1704 | 1690 | ||
1705 | case VIDEO_COMMAND: | 1691 | case VIDEO_COMMAND: |
1706 | case VIDEO_TRY_COMMAND: { | 1692 | case VIDEO_TRY_COMMAND: { |
1707 | struct video_command *vc = arg; | 1693 | /* Note: struct v4l2_decoder_cmd has the same layout as |
1694 | struct video_command */ | ||
1695 | struct v4l2_decoder_cmd *dc = arg; | ||
1708 | int try = (cmd == VIDEO_TRY_COMMAND); | 1696 | int try = (cmd == VIDEO_TRY_COMMAND); |
1709 | 1697 | ||
1710 | if (try) | 1698 | if (try) |
1711 | IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); | 1699 | IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd); |
1712 | else | 1700 | else |
1713 | IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); | 1701 | IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd); |
1714 | return ivtv_video_command(itv, id, vc, try); | 1702 | return ivtv_video_command(itv, id, dc, try); |
1715 | } | 1703 | } |
1716 | 1704 | ||
1717 | case VIDEO_GET_EVENT: { | 1705 | case VIDEO_GET_EVENT: { |
@@ -1775,17 +1763,13 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) | |||
1775 | IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); | 1763 | IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); |
1776 | if (iarg > AUDIO_STEREO_SWAPPED) | 1764 | if (iarg > AUDIO_STEREO_SWAPPED) |
1777 | return -EINVAL; | 1765 | return -EINVAL; |
1778 | itv->audio_stereo_mode = iarg; | 1766 | return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg); |
1779 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
1780 | return 0; | ||
1781 | 1767 | ||
1782 | case AUDIO_BILINGUAL_CHANNEL_SELECT: | 1768 | case AUDIO_BILINGUAL_CHANNEL_SELECT: |
1783 | IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); | 1769 | IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); |
1784 | if (iarg > AUDIO_STEREO_SWAPPED) | 1770 | if (iarg > AUDIO_STEREO_SWAPPED) |
1785 | return -EINVAL; | 1771 | return -EINVAL; |
1786 | itv->audio_bilingual_mode = iarg; | 1772 | return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg); |
1787 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
1788 | return 0; | ||
1789 | 1773 | ||
1790 | default: | 1774 | default: |
1791 | return -EINVAL; | 1775 | return -EINVAL; |
@@ -1800,6 +1784,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio, | |||
1800 | 1784 | ||
1801 | if (!valid_prio) { | 1785 | if (!valid_prio) { |
1802 | switch (cmd) { | 1786 | switch (cmd) { |
1787 | case IVTV_IOC_PASSTHROUGH_MODE: | ||
1803 | case VIDEO_PLAY: | 1788 | case VIDEO_PLAY: |
1804 | case VIDEO_STOP: | 1789 | case VIDEO_STOP: |
1805 | case VIDEO_FREEZE: | 1790 | case VIDEO_FREEZE: |
@@ -1825,6 +1810,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio, | |||
1825 | } | 1810 | } |
1826 | 1811 | ||
1827 | case IVTV_IOC_DMA_FRAME: | 1812 | case IVTV_IOC_DMA_FRAME: |
1813 | case IVTV_IOC_PASSTHROUGH_MODE: | ||
1828 | case VIDEO_GET_PTS: | 1814 | case VIDEO_GET_PTS: |
1829 | case VIDEO_GET_FRAME_COUNT: | 1815 | case VIDEO_GET_FRAME_COUNT: |
1830 | case VIDEO_GET_EVENT: | 1816 | case VIDEO_GET_EVENT: |
@@ -1889,6 +1875,8 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { | |||
1889 | .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, | 1875 | .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, |
1890 | .vidioc_encoder_cmd = ivtv_encoder_cmd, | 1876 | .vidioc_encoder_cmd = ivtv_encoder_cmd, |
1891 | .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, | 1877 | .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, |
1878 | .vidioc_decoder_cmd = ivtv_decoder_cmd, | ||
1879 | .vidioc_try_decoder_cmd = ivtv_try_decoder_cmd, | ||
1892 | .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, | 1880 | .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, |
1893 | .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, | 1881 | .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, |
1894 | .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, | 1882 | .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, |
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index c6e28b4ebbed..7ea5ca7f012b 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -78,60 +78,73 @@ static struct { | |||
78 | int num_offset; | 78 | int num_offset; |
79 | int dma, pio; | 79 | int dma, pio; |
80 | enum v4l2_buf_type buf_type; | 80 | enum v4l2_buf_type buf_type; |
81 | u32 v4l2_caps; | ||
81 | const struct v4l2_file_operations *fops; | 82 | const struct v4l2_file_operations *fops; |
82 | } ivtv_stream_info[] = { | 83 | } ivtv_stream_info[] = { |
83 | { /* IVTV_ENC_STREAM_TYPE_MPG */ | 84 | { /* IVTV_ENC_STREAM_TYPE_MPG */ |
84 | "encoder MPG", | 85 | "encoder MPG", |
85 | VFL_TYPE_GRABBER, 0, | 86 | VFL_TYPE_GRABBER, 0, |
86 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, | 87 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, |
88 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | | ||
89 | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, | ||
87 | &ivtv_v4l2_enc_fops | 90 | &ivtv_v4l2_enc_fops |
88 | }, | 91 | }, |
89 | { /* IVTV_ENC_STREAM_TYPE_YUV */ | 92 | { /* IVTV_ENC_STREAM_TYPE_YUV */ |
90 | "encoder YUV", | 93 | "encoder YUV", |
91 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, | 94 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, |
92 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, | 95 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, |
96 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | | ||
97 | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, | ||
93 | &ivtv_v4l2_enc_fops | 98 | &ivtv_v4l2_enc_fops |
94 | }, | 99 | }, |
95 | { /* IVTV_ENC_STREAM_TYPE_VBI */ | 100 | { /* IVTV_ENC_STREAM_TYPE_VBI */ |
96 | "encoder VBI", | 101 | "encoder VBI", |
97 | VFL_TYPE_VBI, 0, | 102 | VFL_TYPE_VBI, 0, |
98 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, | 103 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, |
104 | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER | | ||
105 | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, | ||
99 | &ivtv_v4l2_enc_fops | 106 | &ivtv_v4l2_enc_fops |
100 | }, | 107 | }, |
101 | { /* IVTV_ENC_STREAM_TYPE_PCM */ | 108 | { /* IVTV_ENC_STREAM_TYPE_PCM */ |
102 | "encoder PCM", | 109 | "encoder PCM", |
103 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, | 110 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, |
104 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, | 111 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, |
112 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, | ||
105 | &ivtv_v4l2_enc_fops | 113 | &ivtv_v4l2_enc_fops |
106 | }, | 114 | }, |
107 | { /* IVTV_ENC_STREAM_TYPE_RAD */ | 115 | { /* IVTV_ENC_STREAM_TYPE_RAD */ |
108 | "encoder radio", | 116 | "encoder radio", |
109 | VFL_TYPE_RADIO, 0, | 117 | VFL_TYPE_RADIO, 0, |
110 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, | 118 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, |
119 | V4L2_CAP_RADIO | V4L2_CAP_TUNER, | ||
111 | &ivtv_v4l2_enc_fops | 120 | &ivtv_v4l2_enc_fops |
112 | }, | 121 | }, |
113 | { /* IVTV_DEC_STREAM_TYPE_MPG */ | 122 | { /* IVTV_DEC_STREAM_TYPE_MPG */ |
114 | "decoder MPG", | 123 | "decoder MPG", |
115 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, | 124 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, |
116 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, | 125 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, |
126 | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, | ||
117 | &ivtv_v4l2_dec_fops | 127 | &ivtv_v4l2_dec_fops |
118 | }, | 128 | }, |
119 | { /* IVTV_DEC_STREAM_TYPE_VBI */ | 129 | { /* IVTV_DEC_STREAM_TYPE_VBI */ |
120 | "decoder VBI", | 130 | "decoder VBI", |
121 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, | 131 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, |
122 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, | 132 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, |
133 | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE, | ||
123 | &ivtv_v4l2_enc_fops | 134 | &ivtv_v4l2_enc_fops |
124 | }, | 135 | }, |
125 | { /* IVTV_DEC_STREAM_TYPE_VOUT */ | 136 | { /* IVTV_DEC_STREAM_TYPE_VOUT */ |
126 | "decoder VOUT", | 137 | "decoder VOUT", |
127 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, | 138 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, |
128 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, | 139 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, |
140 | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, | ||
129 | &ivtv_v4l2_dec_fops | 141 | &ivtv_v4l2_dec_fops |
130 | }, | 142 | }, |
131 | { /* IVTV_DEC_STREAM_TYPE_YUV */ | 143 | { /* IVTV_DEC_STREAM_TYPE_YUV */ |
132 | "decoder YUV", | 144 | "decoder YUV", |
133 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, | 145 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, |
134 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, | 146 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, |
147 | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, | ||
135 | &ivtv_v4l2_dec_fops | 148 | &ivtv_v4l2_dec_fops |
136 | } | 149 | } |
137 | }; | 150 | }; |
@@ -149,6 +162,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) | |||
149 | s->itv = itv; | 162 | s->itv = itv; |
150 | s->type = type; | 163 | s->type = type; |
151 | s->name = ivtv_stream_info[type].name; | 164 | s->name = ivtv_stream_info[type].name; |
165 | s->caps = ivtv_stream_info[type].v4l2_caps; | ||
152 | 166 | ||
153 | if (ivtv_stream_info[type].pio) | 167 | if (ivtv_stream_info[type].pio) |
154 | s->dma = PCI_DMA_NONE; | 168 | s->dma = PCI_DMA_NONE; |
@@ -209,8 +223,8 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) | |||
209 | 223 | ||
210 | s->vdev->num = num; | 224 | s->vdev->num = num; |
211 | s->vdev->v4l2_dev = &itv->v4l2_dev; | 225 | s->vdev->v4l2_dev = &itv->v4l2_dev; |
212 | s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; | ||
213 | s->vdev->fops = ivtv_stream_info[type].fops; | 226 | s->vdev->fops = ivtv_stream_info[type].fops; |
227 | s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; | ||
214 | s->vdev->release = video_device_release; | 228 | s->vdev->release = video_device_release; |
215 | s->vdev->tvnorms = V4L2_STD_ALL; | 229 | s->vdev->tvnorms = V4L2_STD_ALL; |
216 | s->vdev->lock = &itv->serialize_lock; | 230 | s->vdev->lock = &itv->serialize_lock; |
@@ -891,7 +905,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) | |||
891 | IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags); | 905 | IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags); |
892 | 906 | ||
893 | /* Stop Decoder */ | 907 | /* Stop Decoder */ |
894 | if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { | 908 | if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) { |
895 | u32 tmp = 0; | 909 | u32 tmp = 0; |
896 | 910 | ||
897 | /* Wait until the decoder is no longer running */ | 911 | /* Wait until the decoder is no longer running */ |
@@ -911,7 +925,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) | |||
911 | break; | 925 | break; |
912 | } | 926 | } |
913 | } | 927 | } |
914 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); | 928 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0); |
915 | 929 | ||
916 | /* turn off notification of dual/stereo mode change */ | 930 | /* turn off notification of dual/stereo mode change */ |
917 | ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); | 931 | ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); |
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c index afa91182b448..ee7ca2dcca2f 100644 --- a/drivers/media/video/ks0127.c +++ b/drivers/media/video/ks0127.c | |||
@@ -721,15 +721,4 @@ static struct i2c_driver ks0127_driver = { | |||
721 | .id_table = ks0127_id, | 721 | .id_table = ks0127_id, |
722 | }; | 722 | }; |
723 | 723 | ||
724 | static __init int init_ks0127(void) | 724 | module_i2c_driver(ks0127_driver); |
725 | { | ||
726 | return i2c_add_driver(&ks0127_driver); | ||
727 | } | ||
728 | |||
729 | static __exit void exit_ks0127(void) | ||
730 | { | ||
731 | i2c_del_driver(&ks0127_driver); | ||
732 | } | ||
733 | |||
734 | module_init(init_ks0127); | ||
735 | module_exit(exit_ks0127); | ||
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 303ffa7df4ac..0991576f4c82 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c | |||
@@ -213,15 +213,4 @@ static struct i2c_driver m52790_driver = { | |||
213 | .id_table = m52790_id, | 213 | .id_table = m52790_id, |
214 | }; | 214 | }; |
215 | 215 | ||
216 | static __init int init_m52790(void) | 216 | module_i2c_driver(m52790_driver); |
217 | { | ||
218 | return i2c_add_driver(&m52790_driver); | ||
219 | } | ||
220 | |||
221 | static __exit void exit_m52790(void) | ||
222 | { | ||
223 | i2c_del_driver(&m52790_driver); | ||
224 | } | ||
225 | |||
226 | module_init(init_m52790); | ||
227 | module_exit(exit_m52790); | ||
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index 93d768db9f33..d718aee01c77 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c | |||
@@ -982,8 +982,8 @@ static int __devinit m5mols_probe(struct i2c_client *client, | |||
982 | } | 982 | } |
983 | 983 | ||
984 | sd = &info->sd; | 984 | sd = &info->sd; |
985 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
986 | v4l2_i2c_subdev_init(sd, client, &m5mols_ops); | 985 | v4l2_i2c_subdev_init(sd, client, &m5mols_ops); |
986 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
987 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 987 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
988 | 988 | ||
989 | sd->internal_ops = &m5mols_subdev_internal_ops; | 989 | sd->internal_ops = &m5mols_subdev_internal_ops; |
@@ -1057,18 +1057,7 @@ static struct i2c_driver m5mols_i2c_driver = { | |||
1057 | .id_table = m5mols_id, | 1057 | .id_table = m5mols_id, |
1058 | }; | 1058 | }; |
1059 | 1059 | ||
1060 | static int __init m5mols_mod_init(void) | 1060 | module_i2c_driver(m5mols_i2c_driver); |
1061 | { | ||
1062 | return i2c_add_driver(&m5mols_i2c_driver); | ||
1063 | } | ||
1064 | |||
1065 | static void __exit m5mols_mod_exit(void) | ||
1066 | { | ||
1067 | i2c_del_driver(&m5mols_i2c_driver); | ||
1068 | } | ||
1069 | |||
1070 | module_init(m5mols_mod_init); | ||
1071 | module_exit(m5mols_mod_exit); | ||
1072 | 1061 | ||
1073 | MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); | 1062 | MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); |
1074 | MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); | 1063 | MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); |
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 37d20e73908a..996ac34d9a89 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c | |||
@@ -509,11 +509,17 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam) | |||
509 | 509 | ||
510 | buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); | 510 | buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); |
511 | list_del_init(&buf->queue); | 511 | list_del_init(&buf->queue); |
512 | /* | ||
513 | * Very Bad Not Good Things happen if you don't clear | ||
514 | * C1_DESC_ENA before making any descriptor changes. | ||
515 | */ | ||
516 | mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); | ||
512 | mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); | 517 | mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); |
513 | mcam_reg_write(cam, REG_DESC_LEN_Y, | 518 | mcam_reg_write(cam, REG_DESC_LEN_Y, |
514 | buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); | 519 | buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); |
515 | mcam_reg_write(cam, REG_DESC_LEN_U, 0); | 520 | mcam_reg_write(cam, REG_DESC_LEN_U, 0); |
516 | mcam_reg_write(cam, REG_DESC_LEN_V, 0); | 521 | mcam_reg_write(cam, REG_DESC_LEN_V, 0); |
522 | mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); | ||
517 | cam->vb_bufs[0] = buf; | 523 | cam->vb_bufs[0] = buf; |
518 | } | 524 | } |
519 | 525 | ||
@@ -533,7 +539,6 @@ static void mcam_ctlr_dma_sg(struct mcam_camera *cam) | |||
533 | 539 | ||
534 | mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); | 540 | mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); |
535 | mcam_sg_next_buffer(cam); | 541 | mcam_sg_next_buffer(cam); |
536 | mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); | ||
537 | cam->nbufs = 3; | 542 | cam->nbufs = 3; |
538 | } | 543 | } |
539 | 544 | ||
@@ -556,17 +561,16 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame) | |||
556 | struct mcam_vb_buffer *buf = cam->vb_bufs[0]; | 561 | struct mcam_vb_buffer *buf = cam->vb_bufs[0]; |
557 | 562 | ||
558 | /* | 563 | /* |
559 | * Very Bad Not Good Things happen if you don't clear | 564 | * If we're no longer supposed to be streaming, don't do anything. |
560 | * C1_DESC_ENA before making any descriptor changes. | ||
561 | */ | 565 | */ |
562 | mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); | 566 | if (cam->state != S_STREAMING) |
567 | return; | ||
563 | /* | 568 | /* |
564 | * If we have another buffer available, put it in and | 569 | * If we have another buffer available, put it in and |
565 | * restart the engine. | 570 | * restart the engine. |
566 | */ | 571 | */ |
567 | if (!list_empty(&cam->buffers)) { | 572 | if (!list_empty(&cam->buffers)) { |
568 | mcam_sg_next_buffer(cam); | 573 | mcam_sg_next_buffer(cam); |
569 | mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); | ||
570 | mcam_ctlr_start(cam); | 574 | mcam_ctlr_start(cam); |
571 | /* | 575 | /* |
572 | * Otherwise set CF_SG_RESTART and the controller will | 576 | * Otherwise set CF_SG_RESTART and the controller will |
@@ -737,7 +741,14 @@ static void mcam_ctlr_stop_dma(struct mcam_camera *cam) | |||
737 | mcam_ctlr_stop(cam); | 741 | mcam_ctlr_stop(cam); |
738 | cam->state = S_IDLE; | 742 | cam->state = S_IDLE; |
739 | spin_unlock_irqrestore(&cam->dev_lock, flags); | 743 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
740 | msleep(40); | 744 | /* |
745 | * This is a brutally long sleep, but experience shows that | ||
746 | * it can take the controller a while to get the message that | ||
747 | * it needs to stop grabbing frames. In particular, we can | ||
748 | * sometimes (on mmp) get a frame at the end WITHOUT the | ||
749 | * start-of-frame indication. | ||
750 | */ | ||
751 | msleep(150); | ||
741 | if (test_bit(CF_DMA_ACTIVE, &cam->flags)) | 752 | if (test_bit(CF_DMA_ACTIVE, &cam->flags)) |
742 | cam_err(cam, "Timeout waiting for DMA to end\n"); | 753 | cam_err(cam, "Timeout waiting for DMA to end\n"); |
743 | /* This would be bad news - what now? */ | 754 | /* This would be bad news - what now? */ |
@@ -880,6 +891,7 @@ static int mcam_read_setup(struct mcam_camera *cam) | |||
880 | * Turn it loose. | 891 | * Turn it loose. |
881 | */ | 892 | */ |
882 | spin_lock_irqsave(&cam->dev_lock, flags); | 893 | spin_lock_irqsave(&cam->dev_lock, flags); |
894 | clear_bit(CF_DMA_ACTIVE, &cam->flags); | ||
883 | mcam_reset_buffers(cam); | 895 | mcam_reset_buffers(cam); |
884 | mcam_ctlr_irq_enable(cam); | 896 | mcam_ctlr_irq_enable(cam); |
885 | cam->state = S_STREAMING; | 897 | cam->state = S_STREAMING; |
@@ -922,7 +934,7 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb) | |||
922 | spin_lock_irqsave(&cam->dev_lock, flags); | 934 | spin_lock_irqsave(&cam->dev_lock, flags); |
923 | start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers); | 935 | start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers); |
924 | list_add(&mvb->queue, &cam->buffers); | 936 | list_add(&mvb->queue, &cam->buffers); |
925 | if (test_bit(CF_SG_RESTART, &cam->flags)) | 937 | if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags)) |
926 | mcam_sg_restart(cam); | 938 | mcam_sg_restart(cam); |
927 | spin_unlock_irqrestore(&cam->dev_lock, flags); | 939 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
928 | if (start) | 940 | if (start) |
@@ -1555,15 +1567,12 @@ static int mcam_v4l_release(struct file *filp) | |||
1555 | { | 1567 | { |
1556 | struct mcam_camera *cam = filp->private_data; | 1568 | struct mcam_camera *cam = filp->private_data; |
1557 | 1569 | ||
1558 | cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames, | 1570 | cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames, |
1559 | singles, delivered); | 1571 | singles, delivered); |
1560 | mutex_lock(&cam->s_mutex); | 1572 | mutex_lock(&cam->s_mutex); |
1561 | (cam->users)--; | 1573 | (cam->users)--; |
1562 | if (filp == cam->owner) { | ||
1563 | mcam_ctlr_stop_dma(cam); | ||
1564 | cam->owner = NULL; | ||
1565 | } | ||
1566 | if (cam->users == 0) { | 1574 | if (cam->users == 0) { |
1575 | mcam_ctlr_stop_dma(cam); | ||
1567 | mcam_cleanup_vb2(cam); | 1576 | mcam_cleanup_vb2(cam); |
1568 | mcam_ctlr_power_down(cam); | 1577 | mcam_ctlr_power_down(cam); |
1569 | if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) | 1578 | if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) |
@@ -1688,6 +1697,8 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs) | |||
1688 | if (irqs & (IRQ_EOF0 << frame)) { | 1697 | if (irqs & (IRQ_EOF0 << frame)) { |
1689 | mcam_frame_complete(cam, frame); | 1698 | mcam_frame_complete(cam, frame); |
1690 | handled = 1; | 1699 | handled = 1; |
1700 | if (cam->buffer_mode == B_DMA_sg) | ||
1701 | break; | ||
1691 | } | 1702 | } |
1692 | /* | 1703 | /* |
1693 | * If a frame starts, note that we have DMA active. This | 1704 | * If a frame starts, note that we have DMA active. This |
diff --git a/drivers/media/video/marvell-ccic/mcam-core.h b/drivers/media/video/marvell-ccic/mcam-core.h index 917200e63255..bd6acba9fb37 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.h +++ b/drivers/media/video/marvell-ccic/mcam-core.h | |||
@@ -107,7 +107,6 @@ struct mcam_camera { | |||
107 | enum mcam_state state; | 107 | enum mcam_state state; |
108 | unsigned long flags; /* Buffer status, mainly (dev_lock) */ | 108 | unsigned long flags; /* Buffer status, mainly (dev_lock) */ |
109 | int users; /* How many open FDs */ | 109 | int users; /* How many open FDs */ |
110 | struct file *owner; /* Who has data access (v4l2) */ | ||
111 | 110 | ||
112 | /* | 111 | /* |
113 | * Subsystem structures. | 112 | * Subsystem structures. |
diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c index 0d64e2d7474a..d23552323f45 100644 --- a/drivers/media/video/marvell-ccic/mmp-driver.c +++ b/drivers/media/video/marvell-ccic/mmp-driver.c | |||
@@ -106,6 +106,13 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev) | |||
106 | /* | 106 | /* |
107 | * Power control. | 107 | * Power control. |
108 | */ | 108 | */ |
109 | static void mmpcam_power_up_ctlr(struct mmp_camera *cam) | ||
110 | { | ||
111 | iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); | ||
112 | iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); | ||
113 | mdelay(1); | ||
114 | } | ||
115 | |||
109 | static void mmpcam_power_up(struct mcam_camera *mcam) | 116 | static void mmpcam_power_up(struct mcam_camera *mcam) |
110 | { | 117 | { |
111 | struct mmp_camera *cam = mcam_to_cam(mcam); | 118 | struct mmp_camera *cam = mcam_to_cam(mcam); |
@@ -113,9 +120,7 @@ static void mmpcam_power_up(struct mcam_camera *mcam) | |||
113 | /* | 120 | /* |
114 | * Turn on power and clocks to the controller. | 121 | * Turn on power and clocks to the controller. |
115 | */ | 122 | */ |
116 | iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); | 123 | mmpcam_power_up_ctlr(cam); |
117 | iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); | ||
118 | mdelay(1); | ||
119 | /* | 124 | /* |
120 | * Provide power to the sensor. | 125 | * Provide power to the sensor. |
121 | */ | 126 | */ |
@@ -335,7 +340,7 @@ static int mmpcam_resume(struct platform_device *pdev) | |||
335 | * touch a register even if nothing was active before; trust | 340 | * touch a register even if nothing was active before; trust |
336 | * me, it's better this way. | 341 | * me, it's better this way. |
337 | */ | 342 | */ |
338 | mmpcam_power_up(&cam->mcam); | 343 | mmpcam_power_up_ctlr(cam); |
339 | return mccic_resume(&cam->mcam); | 344 | return mccic_resume(&cam->mcam); |
340 | } | 345 | } |
341 | 346 | ||
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index d7cd0f633f63..82ce50721de3 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -881,18 +881,7 @@ static struct i2c_driver msp_driver = { | |||
881 | .id_table = msp_id, | 881 | .id_table = msp_id, |
882 | }; | 882 | }; |
883 | 883 | ||
884 | static __init int init_msp(void) | 884 | module_i2c_driver(msp_driver); |
885 | { | ||
886 | return i2c_add_driver(&msp_driver); | ||
887 | } | ||
888 | |||
889 | static __exit void exit_msp(void) | ||
890 | { | ||
891 | i2c_del_driver(&msp_driver); | ||
892 | } | ||
893 | |||
894 | module_init(init_msp); | ||
895 | module_exit(exit_msp); | ||
896 | 885 | ||
897 | /* | 886 | /* |
898 | * Overrides for Emacs so that we follow Linus's tabbing style. | 887 | * Overrides for Emacs so that we follow Linus's tabbing style. |
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 097c9d3d04a8..7e648183f157 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c | |||
@@ -730,18 +730,7 @@ static struct i2c_driver mt9m001_i2c_driver = { | |||
730 | .id_table = mt9m001_id, | 730 | .id_table = mt9m001_id, |
731 | }; | 731 | }; |
732 | 732 | ||
733 | static int __init mt9m001_mod_init(void) | 733 | module_i2c_driver(mt9m001_i2c_driver); |
734 | { | ||
735 | return i2c_add_driver(&mt9m001_i2c_driver); | ||
736 | } | ||
737 | |||
738 | static void __exit mt9m001_mod_exit(void) | ||
739 | { | ||
740 | i2c_del_driver(&mt9m001_i2c_driver); | ||
741 | } | ||
742 | |||
743 | module_init(mt9m001_mod_init); | ||
744 | module_exit(mt9m001_mod_exit); | ||
745 | 734 | ||
746 | MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); | 735 | MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); |
747 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | 736 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); |
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c new file mode 100644 index 000000000000..7636672c3548 --- /dev/null +++ b/drivers/media/video/mt9m032.c | |||
@@ -0,0 +1,868 @@ | |||
1 | /* | ||
2 | * Driver for MT9M032 CMOS Image Sensor from Micron | ||
3 | * | ||
4 | * Copyright (C) 2010-2011 Lund Engineering | ||
5 | * Contact: Gil Lund <gwlund@lundeng.com> | ||
6 | * Author: Martin Hostettler <martin@neutronstar.dyndns.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/delay.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/math64.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/v4l2-mediabus.h> | ||
32 | |||
33 | #include <media/media-entity.h> | ||
34 | #include <media/mt9m032.h> | ||
35 | #include <media/v4l2-ctrls.h> | ||
36 | #include <media/v4l2-device.h> | ||
37 | #include <media/v4l2-subdev.h> | ||
38 | |||
39 | #include "aptina-pll.h" | ||
40 | |||
41 | /* | ||
42 | * width and height include active boundary and black parts | ||
43 | * | ||
44 | * column 0- 15 active boundary | ||
45 | * column 16-1455 image | ||
46 | * column 1456-1471 active boundary | ||
47 | * column 1472-1599 black | ||
48 | * | ||
49 | * row 0- 51 black | ||
50 | * row 53- 59 active boundary | ||
51 | * row 60-1139 image | ||
52 | * row 1140-1147 active boundary | ||
53 | * row 1148-1151 black | ||
54 | */ | ||
55 | |||
56 | #define MT9M032_PIXEL_ARRAY_WIDTH 1600 | ||
57 | #define MT9M032_PIXEL_ARRAY_HEIGHT 1152 | ||
58 | |||
59 | #define MT9M032_CHIP_VERSION 0x00 | ||
60 | #define MT9M032_CHIP_VERSION_VALUE 0x1402 | ||
61 | #define MT9M032_ROW_START 0x01 | ||
62 | #define MT9M032_ROW_START_MIN 0 | ||
63 | #define MT9M032_ROW_START_MAX 1152 | ||
64 | #define MT9M032_ROW_START_DEF 60 | ||
65 | #define MT9M032_COLUMN_START 0x02 | ||
66 | #define MT9M032_COLUMN_START_MIN 0 | ||
67 | #define MT9M032_COLUMN_START_MAX 1600 | ||
68 | #define MT9M032_COLUMN_START_DEF 16 | ||
69 | #define MT9M032_ROW_SIZE 0x03 | ||
70 | #define MT9M032_ROW_SIZE_MIN 32 | ||
71 | #define MT9M032_ROW_SIZE_MAX 1152 | ||
72 | #define MT9M032_ROW_SIZE_DEF 1080 | ||
73 | #define MT9M032_COLUMN_SIZE 0x04 | ||
74 | #define MT9M032_COLUMN_SIZE_MIN 32 | ||
75 | #define MT9M032_COLUMN_SIZE_MAX 1600 | ||
76 | #define MT9M032_COLUMN_SIZE_DEF 1440 | ||
77 | #define MT9M032_HBLANK 0x05 | ||
78 | #define MT9M032_VBLANK 0x06 | ||
79 | #define MT9M032_VBLANK_MAX 0x7ff | ||
80 | #define MT9M032_SHUTTER_WIDTH_HIGH 0x08 | ||
81 | #define MT9M032_SHUTTER_WIDTH_LOW 0x09 | ||
82 | #define MT9M032_SHUTTER_WIDTH_MIN 1 | ||
83 | #define MT9M032_SHUTTER_WIDTH_MAX 1048575 | ||
84 | #define MT9M032_SHUTTER_WIDTH_DEF 1943 | ||
85 | #define MT9M032_PIX_CLK_CTRL 0x0a | ||
86 | #define MT9M032_PIX_CLK_CTRL_INV_PIXCLK 0x8000 | ||
87 | #define MT9M032_RESTART 0x0b | ||
88 | #define MT9M032_RESET 0x0d | ||
89 | #define MT9M032_PLL_CONFIG1 0x11 | ||
90 | #define MT9M032_PLL_CONFIG1_OUTDIV_MASK 0x3f | ||
91 | #define MT9M032_PLL_CONFIG1_MUL_SHIFT 8 | ||
92 | #define MT9M032_READ_MODE1 0x1e | ||
93 | #define MT9M032_READ_MODE2 0x20 | ||
94 | #define MT9M032_READ_MODE2_VFLIP_SHIFT 15 | ||
95 | #define MT9M032_READ_MODE2_HFLIP_SHIFT 14 | ||
96 | #define MT9M032_READ_MODE2_ROW_BLC 0x40 | ||
97 | #define MT9M032_GAIN_GREEN1 0x2b | ||
98 | #define MT9M032_GAIN_BLUE 0x2c | ||
99 | #define MT9M032_GAIN_RED 0x2d | ||
100 | #define MT9M032_GAIN_GREEN2 0x2e | ||
101 | |||
102 | /* write only */ | ||
103 | #define MT9M032_GAIN_ALL 0x35 | ||
104 | #define MT9M032_GAIN_DIGITAL_MASK 0x7f | ||
105 | #define MT9M032_GAIN_DIGITAL_SHIFT 8 | ||
106 | #define MT9M032_GAIN_AMUL_SHIFT 6 | ||
107 | #define MT9M032_GAIN_ANALOG_MASK 0x3f | ||
108 | #define MT9M032_FORMATTER1 0x9e | ||
109 | #define MT9M032_FORMATTER2 0x9f | ||
110 | #define MT9M032_FORMATTER2_DOUT_EN 0x1000 | ||
111 | #define MT9M032_FORMATTER2_PIXCLK_EN 0x2000 | ||
112 | |||
113 | /* | ||
114 | * The available MT9M032 datasheet is missing documentation for register 0x10 | ||
115 | * MT9P031 seems to be close enough, so use constants from that datasheet for | ||
116 | * now. | ||
117 | * But keep the name MT9P031 to remind us, that this isn't really confirmed | ||
118 | * for this sensor. | ||
119 | */ | ||
120 | #define MT9P031_PLL_CONTROL 0x10 | ||
121 | #define MT9P031_PLL_CONTROL_PWROFF 0x0050 | ||
122 | #define MT9P031_PLL_CONTROL_PWRON 0x0051 | ||
123 | #define MT9P031_PLL_CONTROL_USEPLL 0x0052 | ||
124 | #define MT9P031_PLL_CONFIG2 0x11 | ||
125 | #define MT9P031_PLL_CONFIG2_P1_DIV_MASK 0x1f | ||
126 | |||
127 | struct mt9m032 { | ||
128 | struct v4l2_subdev subdev; | ||
129 | struct media_pad pad; | ||
130 | struct mt9m032_platform_data *pdata; | ||
131 | |||
132 | unsigned int pix_clock; | ||
133 | |||
134 | struct v4l2_ctrl_handler ctrls; | ||
135 | struct { | ||
136 | struct v4l2_ctrl *hflip; | ||
137 | struct v4l2_ctrl *vflip; | ||
138 | }; | ||
139 | |||
140 | struct mutex lock; /* Protects streaming, format, interval and crop */ | ||
141 | |||
142 | bool streaming; | ||
143 | |||
144 | struct v4l2_mbus_framefmt format; | ||
145 | struct v4l2_rect crop; | ||
146 | struct v4l2_fract frame_interval; | ||
147 | }; | ||
148 | |||
149 | #define to_mt9m032(sd) container_of(sd, struct mt9m032, subdev) | ||
150 | #define to_dev(sensor) \ | ||
151 | (&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev) | ||
152 | |||
153 | static int mt9m032_read(struct i2c_client *client, u8 reg) | ||
154 | { | ||
155 | return i2c_smbus_read_word_swapped(client, reg); | ||
156 | } | ||
157 | |||
158 | static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data) | ||
159 | { | ||
160 | return i2c_smbus_write_word_swapped(client, reg, data); | ||
161 | } | ||
162 | |||
163 | static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width) | ||
164 | { | ||
165 | unsigned int effective_width; | ||
166 | u32 ns; | ||
167 | |||
168 | effective_width = width + 716; /* empirical value */ | ||
169 | ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock); | ||
170 | dev_dbg(to_dev(sensor), "MT9M032 line time: %u ns\n", ns); | ||
171 | return ns; | ||
172 | } | ||
173 | |||
174 | static int mt9m032_update_timing(struct mt9m032 *sensor, | ||
175 | struct v4l2_fract *interval) | ||
176 | { | ||
177 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
178 | struct v4l2_rect *crop = &sensor->crop; | ||
179 | unsigned int min_vblank; | ||
180 | unsigned int vblank; | ||
181 | u32 row_time; | ||
182 | |||
183 | if (!interval) | ||
184 | interval = &sensor->frame_interval; | ||
185 | |||
186 | row_time = mt9m032_row_time(sensor, crop->width); | ||
187 | |||
188 | vblank = div_u64(1000000000ULL * interval->numerator, | ||
189 | (u64)row_time * interval->denominator) | ||
190 | - crop->height; | ||
191 | |||
192 | if (vblank > MT9M032_VBLANK_MAX) { | ||
193 | /* hardware limits to 11 bit values */ | ||
194 | interval->denominator = 1000; | ||
195 | interval->numerator = | ||
196 | div_u64((crop->height + MT9M032_VBLANK_MAX) * | ||
197 | (u64)row_time * interval->denominator, | ||
198 | 1000000000ULL); | ||
199 | vblank = div_u64(1000000000ULL * interval->numerator, | ||
200 | (u64)row_time * interval->denominator) | ||
201 | - crop->height; | ||
202 | } | ||
203 | /* enforce minimal 1.6ms blanking time. */ | ||
204 | min_vblank = 1600000 / row_time; | ||
205 | vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX); | ||
206 | |||
207 | return mt9m032_write(client, MT9M032_VBLANK, vblank); | ||
208 | } | ||
209 | |||
210 | static int mt9m032_update_geom_timing(struct mt9m032 *sensor) | ||
211 | { | ||
212 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
213 | int ret; | ||
214 | |||
215 | ret = mt9m032_write(client, MT9M032_COLUMN_SIZE, | ||
216 | sensor->crop.width - 1); | ||
217 | if (!ret) | ||
218 | ret = mt9m032_write(client, MT9M032_ROW_SIZE, | ||
219 | sensor->crop.height - 1); | ||
220 | if (!ret) | ||
221 | ret = mt9m032_write(client, MT9M032_COLUMN_START, | ||
222 | sensor->crop.left); | ||
223 | if (!ret) | ||
224 | ret = mt9m032_write(client, MT9M032_ROW_START, | ||
225 | sensor->crop.top); | ||
226 | if (!ret) | ||
227 | ret = mt9m032_update_timing(sensor, NULL); | ||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | static int update_formatter2(struct mt9m032 *sensor, bool streaming) | ||
232 | { | ||
233 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
234 | u16 reg_val = MT9M032_FORMATTER2_DOUT_EN | ||
235 | | 0x0070; /* parts reserved! */ | ||
236 | /* possibly for changing to 14-bit mode */ | ||
237 | |||
238 | if (streaming) | ||
239 | reg_val |= MT9M032_FORMATTER2_PIXCLK_EN; /* pixclock enable */ | ||
240 | |||
241 | return mt9m032_write(client, MT9M032_FORMATTER2, reg_val); | ||
242 | } | ||
243 | |||
244 | static int mt9m032_setup_pll(struct mt9m032 *sensor) | ||
245 | { | ||
246 | static const struct aptina_pll_limits limits = { | ||
247 | .ext_clock_min = 8000000, | ||
248 | .ext_clock_max = 16500000, | ||
249 | .int_clock_min = 2000000, | ||
250 | .int_clock_max = 24000000, | ||
251 | .out_clock_min = 322000000, | ||
252 | .out_clock_max = 693000000, | ||
253 | .pix_clock_max = 99000000, | ||
254 | .n_min = 1, | ||
255 | .n_max = 64, | ||
256 | .m_min = 16, | ||
257 | .m_max = 255, | ||
258 | .p1_min = 1, | ||
259 | .p1_max = 128, | ||
260 | }; | ||
261 | |||
262 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
263 | struct mt9m032_platform_data *pdata = sensor->pdata; | ||
264 | struct aptina_pll pll; | ||
265 | int ret; | ||
266 | |||
267 | pll.ext_clock = pdata->ext_clock; | ||
268 | pll.pix_clock = pdata->pix_clock; | ||
269 | |||
270 | ret = aptina_pll_calculate(&client->dev, &limits, &pll); | ||
271 | if (ret < 0) | ||
272 | return ret; | ||
273 | |||
274 | sensor->pix_clock = pdata->pix_clock; | ||
275 | |||
276 | ret = mt9m032_write(client, MT9M032_PLL_CONFIG1, | ||
277 | (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) | ||
278 | | (pll.p1 - 1)); | ||
279 | if (!ret) | ||
280 | ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1); | ||
281 | if (!ret) | ||
282 | ret = mt9m032_write(client, MT9P031_PLL_CONTROL, | ||
283 | MT9P031_PLL_CONTROL_PWRON | | ||
284 | MT9P031_PLL_CONTROL_USEPLL); | ||
285 | if (!ret) /* more reserved, Continuous, Master Mode */ | ||
286 | ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006); | ||
287 | if (!ret) /* Set 14-bit mode, select 7 divider */ | ||
288 | ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e); | ||
289 | |||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | /* ----------------------------------------------------------------------------- | ||
294 | * Subdev pad operations | ||
295 | */ | ||
296 | |||
297 | static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, | ||
298 | struct v4l2_subdev_fh *fh, | ||
299 | struct v4l2_subdev_mbus_code_enum *code) | ||
300 | { | ||
301 | if (code->index != 0) | ||
302 | return -EINVAL; | ||
303 | |||
304 | code->code = V4L2_MBUS_FMT_Y8_1X8; | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, | ||
309 | struct v4l2_subdev_fh *fh, | ||
310 | struct v4l2_subdev_frame_size_enum *fse) | ||
311 | { | ||
312 | if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8) | ||
313 | return -EINVAL; | ||
314 | |||
315 | fse->min_width = MT9M032_COLUMN_SIZE_DEF; | ||
316 | fse->max_width = MT9M032_COLUMN_SIZE_DEF; | ||
317 | fse->min_height = MT9M032_ROW_SIZE_DEF; | ||
318 | fse->max_height = MT9M032_ROW_SIZE_DEF; | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * __mt9m032_get_pad_crop() - get crop rect | ||
325 | * @sensor: pointer to the sensor struct | ||
326 | * @fh: file handle for getting the try crop rect from | ||
327 | * @which: select try or active crop rect | ||
328 | * | ||
329 | * Returns a pointer the current active or fh relative try crop rect | ||
330 | */ | ||
331 | static struct v4l2_rect * | ||
332 | __mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, | ||
333 | enum v4l2_subdev_format_whence which) | ||
334 | { | ||
335 | switch (which) { | ||
336 | case V4L2_SUBDEV_FORMAT_TRY: | ||
337 | return v4l2_subdev_get_try_crop(fh, 0); | ||
338 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
339 | return &sensor->crop; | ||
340 | default: | ||
341 | return NULL; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | /** | ||
346 | * __mt9m032_get_pad_format() - get format | ||
347 | * @sensor: pointer to the sensor struct | ||
348 | * @fh: file handle for getting the try format from | ||
349 | * @which: select try or active format | ||
350 | * | ||
351 | * Returns a pointer the current active or fh relative try format | ||
352 | */ | ||
353 | static struct v4l2_mbus_framefmt * | ||
354 | __mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, | ||
355 | enum v4l2_subdev_format_whence which) | ||
356 | { | ||
357 | switch (which) { | ||
358 | case V4L2_SUBDEV_FORMAT_TRY: | ||
359 | return v4l2_subdev_get_try_format(fh, 0); | ||
360 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
361 | return &sensor->format; | ||
362 | default: | ||
363 | return NULL; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | static int mt9m032_get_pad_format(struct v4l2_subdev *subdev, | ||
368 | struct v4l2_subdev_fh *fh, | ||
369 | struct v4l2_subdev_format *fmt) | ||
370 | { | ||
371 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
372 | |||
373 | mutex_lock(&sensor->lock); | ||
374 | fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which); | ||
375 | mutex_unlock(&sensor->lock); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, | ||
381 | struct v4l2_subdev_fh *fh, | ||
382 | struct v4l2_subdev_format *fmt) | ||
383 | { | ||
384 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
385 | int ret; | ||
386 | |||
387 | mutex_lock(&sensor->lock); | ||
388 | |||
389 | if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
390 | ret = -EBUSY; | ||
391 | goto done; | ||
392 | } | ||
393 | |||
394 | /* Scaling is not supported, the format is thus fixed. */ | ||
395 | ret = mt9m032_get_pad_format(subdev, fh, fmt); | ||
396 | |||
397 | done: | ||
398 | mutex_lock(&sensor->lock); | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev, | ||
403 | struct v4l2_subdev_fh *fh, | ||
404 | struct v4l2_subdev_crop *crop) | ||
405 | { | ||
406 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
407 | |||
408 | mutex_lock(&sensor->lock); | ||
409 | crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which); | ||
410 | mutex_unlock(&sensor->lock); | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, | ||
416 | struct v4l2_subdev_fh *fh, | ||
417 | struct v4l2_subdev_crop *crop) | ||
418 | { | ||
419 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
420 | struct v4l2_mbus_framefmt *format; | ||
421 | struct v4l2_rect *__crop; | ||
422 | struct v4l2_rect rect; | ||
423 | int ret = 0; | ||
424 | |||
425 | mutex_lock(&sensor->lock); | ||
426 | |||
427 | if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
428 | ret = -EBUSY; | ||
429 | goto done; | ||
430 | } | ||
431 | |||
432 | /* Clamp the crop rectangle boundaries and align them to a multiple of 2 | ||
433 | * pixels to ensure a GRBG Bayer pattern. | ||
434 | */ | ||
435 | rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN, | ||
436 | MT9M032_COLUMN_START_MAX); | ||
437 | rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN, | ||
438 | MT9M032_ROW_START_MAX); | ||
439 | rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN, | ||
440 | MT9M032_COLUMN_SIZE_MAX); | ||
441 | rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN, | ||
442 | MT9M032_ROW_SIZE_MAX); | ||
443 | |||
444 | rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left); | ||
445 | rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); | ||
446 | |||
447 | __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which); | ||
448 | |||
449 | if (rect.width != __crop->width || rect.height != __crop->height) { | ||
450 | /* Reset the output image size if the crop rectangle size has | ||
451 | * been modified. | ||
452 | */ | ||
453 | format = __mt9m032_get_pad_format(sensor, fh, crop->which); | ||
454 | format->width = rect.width; | ||
455 | format->height = rect.height; | ||
456 | } | ||
457 | |||
458 | *__crop = rect; | ||
459 | crop->rect = rect; | ||
460 | |||
461 | if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
462 | ret = mt9m032_update_geom_timing(sensor); | ||
463 | |||
464 | done: | ||
465 | mutex_unlock(&sensor->lock); | ||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev, | ||
470 | struct v4l2_subdev_frame_interval *fi) | ||
471 | { | ||
472 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
473 | |||
474 | mutex_lock(&sensor->lock); | ||
475 | memset(fi, 0, sizeof(*fi)); | ||
476 | fi->interval = sensor->frame_interval; | ||
477 | mutex_unlock(&sensor->lock); | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev, | ||
483 | struct v4l2_subdev_frame_interval *fi) | ||
484 | { | ||
485 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
486 | int ret; | ||
487 | |||
488 | mutex_lock(&sensor->lock); | ||
489 | |||
490 | if (sensor->streaming) { | ||
491 | ret = -EBUSY; | ||
492 | goto done; | ||
493 | } | ||
494 | |||
495 | /* Avoid divisions by 0. */ | ||
496 | if (fi->interval.denominator == 0) | ||
497 | fi->interval.denominator = 1; | ||
498 | |||
499 | ret = mt9m032_update_timing(sensor, &fi->interval); | ||
500 | if (!ret) | ||
501 | sensor->frame_interval = fi->interval; | ||
502 | |||
503 | done: | ||
504 | mutex_unlock(&sensor->lock); | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming) | ||
509 | { | ||
510 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
511 | int ret; | ||
512 | |||
513 | mutex_lock(&sensor->lock); | ||
514 | ret = update_formatter2(sensor, streaming); | ||
515 | if (!ret) | ||
516 | sensor->streaming = streaming; | ||
517 | mutex_unlock(&sensor->lock); | ||
518 | |||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | /* ----------------------------------------------------------------------------- | ||
523 | * V4L2 subdev core operations | ||
524 | */ | ||
525 | |||
526 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
527 | static int mt9m032_g_register(struct v4l2_subdev *sd, | ||
528 | struct v4l2_dbg_register *reg) | ||
529 | { | ||
530 | struct mt9m032 *sensor = to_mt9m032(sd); | ||
531 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
532 | int val; | ||
533 | |||
534 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | ||
535 | return -EINVAL; | ||
536 | if (reg->match.addr != client->addr) | ||
537 | return -ENODEV; | ||
538 | |||
539 | val = mt9m032_read(client, reg->reg); | ||
540 | if (val < 0) | ||
541 | return -EIO; | ||
542 | |||
543 | reg->size = 2; | ||
544 | reg->val = val; | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int mt9m032_s_register(struct v4l2_subdev *sd, | ||
550 | struct v4l2_dbg_register *reg) | ||
551 | { | ||
552 | struct mt9m032 *sensor = to_mt9m032(sd); | ||
553 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
554 | |||
555 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | ||
556 | return -EINVAL; | ||
557 | |||
558 | if (reg->match.addr != client->addr) | ||
559 | return -ENODEV; | ||
560 | |||
561 | return mt9m032_write(client, reg->reg, reg->val); | ||
562 | } | ||
563 | #endif | ||
564 | |||
565 | /* ----------------------------------------------------------------------------- | ||
566 | * V4L2 subdev control operations | ||
567 | */ | ||
568 | |||
569 | static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip) | ||
570 | { | ||
571 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
572 | int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT) | ||
573 | | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT) | ||
574 | | MT9M032_READ_MODE2_ROW_BLC | ||
575 | | 0x0007; | ||
576 | |||
577 | return mt9m032_write(client, MT9M032_READ_MODE2, reg_val); | ||
578 | } | ||
579 | |||
580 | static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val) | ||
581 | { | ||
582 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
583 | int digital_gain_val; /* in 1/8th (0..127) */ | ||
584 | int analog_mul; /* 0 or 1 */ | ||
585 | int analog_gain_val; /* in 1/16th. (0..63) */ | ||
586 | u16 reg_val; | ||
587 | |||
588 | digital_gain_val = 51; /* from setup example */ | ||
589 | |||
590 | if (val < 63) { | ||
591 | analog_mul = 0; | ||
592 | analog_gain_val = val; | ||
593 | } else { | ||
594 | analog_mul = 1; | ||
595 | analog_gain_val = val / 2; | ||
596 | } | ||
597 | |||
598 | /* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */ | ||
599 | /* overall_gain = a_gain * (1 + digital_gain_val / 8) */ | ||
600 | |||
601 | reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK) | ||
602 | << MT9M032_GAIN_DIGITAL_SHIFT) | ||
603 | | ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT) | ||
604 | | (analog_gain_val & MT9M032_GAIN_ANALOG_MASK); | ||
605 | |||
606 | return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val); | ||
607 | } | ||
608 | |||
609 | static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl) | ||
610 | { | ||
611 | if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) { | ||
612 | /* round because of multiplier used for values >= 63 */ | ||
613 | ctrl->val &= ~1; | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl) | ||
620 | { | ||
621 | struct mt9m032 *sensor = | ||
622 | container_of(ctrl->handler, struct mt9m032, ctrls); | ||
623 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | ||
624 | int ret; | ||
625 | |||
626 | switch (ctrl->id) { | ||
627 | case V4L2_CID_GAIN: | ||
628 | return mt9m032_set_gain(sensor, ctrl->val); | ||
629 | |||
630 | case V4L2_CID_HFLIP: | ||
631 | /* case V4L2_CID_VFLIP: -- In the same cluster */ | ||
632 | return update_read_mode2(sensor, sensor->vflip->val, | ||
633 | sensor->hflip->val); | ||
634 | |||
635 | case V4L2_CID_EXPOSURE: | ||
636 | ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH, | ||
637 | (ctrl->val >> 16) & 0xffff); | ||
638 | if (ret < 0) | ||
639 | return ret; | ||
640 | |||
641 | return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW, | ||
642 | ctrl->val & 0xffff); | ||
643 | } | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static struct v4l2_ctrl_ops mt9m032_ctrl_ops = { | ||
649 | .s_ctrl = mt9m032_set_ctrl, | ||
650 | .try_ctrl = mt9m032_try_ctrl, | ||
651 | }; | ||
652 | |||
653 | /* -------------------------------------------------------------------------- */ | ||
654 | |||
655 | static const struct v4l2_subdev_core_ops mt9m032_core_ops = { | ||
656 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
657 | .g_register = mt9m032_g_register, | ||
658 | .s_register = mt9m032_s_register, | ||
659 | #endif | ||
660 | }; | ||
661 | |||
662 | static const struct v4l2_subdev_video_ops mt9m032_video_ops = { | ||
663 | .s_stream = mt9m032_s_stream, | ||
664 | .g_frame_interval = mt9m032_get_frame_interval, | ||
665 | .s_frame_interval = mt9m032_set_frame_interval, | ||
666 | }; | ||
667 | |||
668 | static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = { | ||
669 | .enum_mbus_code = mt9m032_enum_mbus_code, | ||
670 | .enum_frame_size = mt9m032_enum_frame_size, | ||
671 | .get_fmt = mt9m032_get_pad_format, | ||
672 | .set_fmt = mt9m032_set_pad_format, | ||
673 | .set_crop = mt9m032_set_pad_crop, | ||
674 | .get_crop = mt9m032_get_pad_crop, | ||
675 | }; | ||
676 | |||
677 | static const struct v4l2_subdev_ops mt9m032_ops = { | ||
678 | .core = &mt9m032_core_ops, | ||
679 | .video = &mt9m032_video_ops, | ||
680 | .pad = &mt9m032_pad_ops, | ||
681 | }; | ||
682 | |||
683 | /* ----------------------------------------------------------------------------- | ||
684 | * Driver initialization and probing | ||
685 | */ | ||
686 | |||
687 | static int mt9m032_probe(struct i2c_client *client, | ||
688 | const struct i2c_device_id *devid) | ||
689 | { | ||
690 | struct i2c_adapter *adapter = client->adapter; | ||
691 | struct mt9m032 *sensor; | ||
692 | int chip_version; | ||
693 | int ret; | ||
694 | |||
695 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | ||
696 | dev_warn(&client->dev, | ||
697 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | ||
698 | return -EIO; | ||
699 | } | ||
700 | |||
701 | if (!client->dev.platform_data) | ||
702 | return -ENODEV; | ||
703 | |||
704 | sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); | ||
705 | if (sensor == NULL) | ||
706 | return -ENOMEM; | ||
707 | |||
708 | mutex_init(&sensor->lock); | ||
709 | |||
710 | sensor->pdata = client->dev.platform_data; | ||
711 | |||
712 | v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops); | ||
713 | sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
714 | |||
715 | chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION); | ||
716 | if (chip_version != MT9M032_CHIP_VERSION_VALUE) { | ||
717 | dev_err(&client->dev, "MT9M032 not detected, wrong version " | ||
718 | "0x%04x\n", chip_version); | ||
719 | ret = -ENODEV; | ||
720 | goto error_sensor; | ||
721 | } | ||
722 | |||
723 | dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n", | ||
724 | client->addr); | ||
725 | |||
726 | sensor->frame_interval.numerator = 1; | ||
727 | sensor->frame_interval.denominator = 30; | ||
728 | |||
729 | sensor->crop.left = MT9M032_COLUMN_START_DEF; | ||
730 | sensor->crop.top = MT9M032_ROW_START_DEF; | ||
731 | sensor->crop.width = MT9M032_COLUMN_SIZE_DEF; | ||
732 | sensor->crop.height = MT9M032_ROW_SIZE_DEF; | ||
733 | |||
734 | sensor->format.width = sensor->crop.width; | ||
735 | sensor->format.height = sensor->crop.height; | ||
736 | sensor->format.code = V4L2_MBUS_FMT_Y8_1X8; | ||
737 | sensor->format.field = V4L2_FIELD_NONE; | ||
738 | sensor->format.colorspace = V4L2_COLORSPACE_SRGB; | ||
739 | |||
740 | v4l2_ctrl_handler_init(&sensor->ctrls, 4); | ||
741 | |||
742 | v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, | ||
743 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
744 | |||
745 | sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, | ||
746 | &mt9m032_ctrl_ops, | ||
747 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
748 | sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, | ||
749 | &mt9m032_ctrl_ops, | ||
750 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
751 | |||
752 | v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, | ||
753 | V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN, | ||
754 | MT9M032_SHUTTER_WIDTH_MAX, 1, | ||
755 | MT9M032_SHUTTER_WIDTH_DEF); | ||
756 | |||
757 | if (sensor->ctrls.error) { | ||
758 | ret = sensor->ctrls.error; | ||
759 | dev_err(&client->dev, "control initialization error %d\n", ret); | ||
760 | goto error_ctrl; | ||
761 | } | ||
762 | |||
763 | v4l2_ctrl_cluster(2, &sensor->hflip); | ||
764 | |||
765 | sensor->subdev.ctrl_handler = &sensor->ctrls; | ||
766 | sensor->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
767 | ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0); | ||
768 | if (ret < 0) | ||
769 | goto error_ctrl; | ||
770 | |||
771 | ret = mt9m032_write(client, MT9M032_RESET, 1); /* reset on */ | ||
772 | if (ret < 0) | ||
773 | goto error_entity; | ||
774 | mt9m032_write(client, MT9M032_RESET, 0); /* reset off */ | ||
775 | if (ret < 0) | ||
776 | goto error_entity; | ||
777 | |||
778 | ret = mt9m032_setup_pll(sensor); | ||
779 | if (ret < 0) | ||
780 | goto error_entity; | ||
781 | usleep_range(10000, 11000); | ||
782 | |||
783 | ret = v4l2_ctrl_handler_setup(&sensor->ctrls); | ||
784 | if (ret < 0) | ||
785 | goto error_entity; | ||
786 | |||
787 | /* SIZE */ | ||
788 | ret = mt9m032_update_geom_timing(sensor); | ||
789 | if (ret < 0) | ||
790 | goto error_entity; | ||
791 | |||
792 | ret = mt9m032_write(client, 0x41, 0x0000); /* reserved !!! */ | ||
793 | if (ret < 0) | ||
794 | goto error_entity; | ||
795 | ret = mt9m032_write(client, 0x42, 0x0003); /* reserved !!! */ | ||
796 | if (ret < 0) | ||
797 | goto error_entity; | ||
798 | ret = mt9m032_write(client, 0x43, 0x0003); /* reserved !!! */ | ||
799 | if (ret < 0) | ||
800 | goto error_entity; | ||
801 | ret = mt9m032_write(client, 0x7f, 0x0000); /* reserved !!! */ | ||
802 | if (ret < 0) | ||
803 | goto error_entity; | ||
804 | if (sensor->pdata->invert_pixclock) { | ||
805 | ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL, | ||
806 | MT9M032_PIX_CLK_CTRL_INV_PIXCLK); | ||
807 | if (ret < 0) | ||
808 | goto error_entity; | ||
809 | } | ||
810 | |||
811 | ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */ | ||
812 | if (ret < 0) | ||
813 | goto error_entity; | ||
814 | msleep(100); | ||
815 | ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */ | ||
816 | if (ret < 0) | ||
817 | goto error_entity; | ||
818 | msleep(100); | ||
819 | ret = update_formatter2(sensor, false); | ||
820 | if (ret < 0) | ||
821 | goto error_entity; | ||
822 | |||
823 | return ret; | ||
824 | |||
825 | error_entity: | ||
826 | media_entity_cleanup(&sensor->subdev.entity); | ||
827 | error_ctrl: | ||
828 | v4l2_ctrl_handler_free(&sensor->ctrls); | ||
829 | error_sensor: | ||
830 | mutex_destroy(&sensor->lock); | ||
831 | kfree(sensor); | ||
832 | return ret; | ||
833 | } | ||
834 | |||
835 | static int mt9m032_remove(struct i2c_client *client) | ||
836 | { | ||
837 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
838 | struct mt9m032 *sensor = to_mt9m032(subdev); | ||
839 | |||
840 | v4l2_device_unregister_subdev(&sensor->subdev); | ||
841 | v4l2_ctrl_handler_free(&sensor->ctrls); | ||
842 | media_entity_cleanup(&sensor->subdev.entity); | ||
843 | mutex_destroy(&sensor->lock); | ||
844 | kfree(sensor); | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | static const struct i2c_device_id mt9m032_id_table[] = { | ||
849 | { MT9M032_NAME, 0 }, | ||
850 | { } | ||
851 | }; | ||
852 | |||
853 | MODULE_DEVICE_TABLE(i2c, mt9m032_id_table); | ||
854 | |||
855 | static struct i2c_driver mt9m032_i2c_driver = { | ||
856 | .driver = { | ||
857 | .name = MT9M032_NAME, | ||
858 | }, | ||
859 | .probe = mt9m032_probe, | ||
860 | .remove = mt9m032_remove, | ||
861 | .id_table = mt9m032_id_table, | ||
862 | }; | ||
863 | |||
864 | module_i2c_driver(mt9m032_i2c_driver); | ||
865 | |||
866 | MODULE_AUTHOR("Martin Hostettler <martin@neutronstar.dyndns.org>"); | ||
867 | MODULE_DESCRIPTION("MT9M032 camera sensor driver"); | ||
868 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index bee65bff46e8..b0c529964329 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -1008,18 +1008,7 @@ static struct i2c_driver mt9m111_i2c_driver = { | |||
1008 | .id_table = mt9m111_id, | 1008 | .id_table = mt9m111_id, |
1009 | }; | 1009 | }; |
1010 | 1010 | ||
1011 | static int __init mt9m111_mod_init(void) | 1011 | module_i2c_driver(mt9m111_i2c_driver); |
1012 | { | ||
1013 | return i2c_add_driver(&mt9m111_i2c_driver); | ||
1014 | } | ||
1015 | |||
1016 | static void __exit mt9m111_mod_exit(void) | ||
1017 | { | ||
1018 | i2c_del_driver(&mt9m111_i2c_driver); | ||
1019 | } | ||
1020 | |||
1021 | module_init(mt9m111_mod_init); | ||
1022 | module_exit(mt9m111_mod_exit); | ||
1023 | 1012 | ||
1024 | MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver"); | 1013 | MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver"); |
1025 | MODULE_AUTHOR("Robert Jarzmik"); | 1014 | MODULE_AUTHOR("Robert Jarzmik"); |
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c index 93c3ec7426e8..c81eaf4fbe01 100644 --- a/drivers/media/video/mt9p031.c +++ b/drivers/media/video/mt9p031.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/log2.h> | 19 | #include <linux/log2.h> |
20 | #include <linux/pm.h> | 20 | #include <linux/pm.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <media/v4l2-subdev.h> | ||
23 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
24 | 23 | ||
25 | #include <media/mt9p031.h> | 24 | #include <media/mt9p031.h> |
@@ -28,6 +27,8 @@ | |||
28 | #include <media/v4l2-device.h> | 27 | #include <media/v4l2-device.h> |
29 | #include <media/v4l2-subdev.h> | 28 | #include <media/v4l2-subdev.h> |
30 | 29 | ||
30 | #include "aptina-pll.h" | ||
31 | |||
31 | #define MT9P031_PIXEL_ARRAY_WIDTH 2752 | 32 | #define MT9P031_PIXEL_ARRAY_WIDTH 2752 |
32 | #define MT9P031_PIXEL_ARRAY_HEIGHT 2004 | 33 | #define MT9P031_PIXEL_ARRAY_HEIGHT 2004 |
33 | 34 | ||
@@ -98,14 +99,6 @@ | |||
98 | #define MT9P031_TEST_PATTERN_RED 0xa2 | 99 | #define MT9P031_TEST_PATTERN_RED 0xa2 |
99 | #define MT9P031_TEST_PATTERN_BLUE 0xa3 | 100 | #define MT9P031_TEST_PATTERN_BLUE 0xa3 |
100 | 101 | ||
101 | struct mt9p031_pll_divs { | ||
102 | u32 ext_freq; | ||
103 | u32 target_freq; | ||
104 | u8 m; | ||
105 | u8 n; | ||
106 | u8 p1; | ||
107 | }; | ||
108 | |||
109 | struct mt9p031 { | 102 | struct mt9p031 { |
110 | struct v4l2_subdev subdev; | 103 | struct v4l2_subdev subdev; |
111 | struct media_pad pad; | 104 | struct media_pad pad; |
@@ -115,10 +108,8 @@ struct mt9p031 { | |||
115 | struct mt9p031_platform_data *pdata; | 108 | struct mt9p031_platform_data *pdata; |
116 | struct mutex power_lock; /* lock to protect power_count */ | 109 | struct mutex power_lock; /* lock to protect power_count */ |
117 | int power_count; | 110 | int power_count; |
118 | u16 xskip; | ||
119 | u16 yskip; | ||
120 | 111 | ||
121 | const struct mt9p031_pll_divs *pll; | 112 | struct aptina_pll pll; |
122 | 113 | ||
123 | /* Registers cache */ | 114 | /* Registers cache */ |
124 | u16 output_control; | 115 | u16 output_control; |
@@ -186,33 +177,31 @@ static int mt9p031_reset(struct mt9p031 *mt9p031) | |||
186 | 0); | 177 | 0); |
187 | } | 178 | } |
188 | 179 | ||
189 | /* | 180 | static int mt9p031_pll_setup(struct mt9p031 *mt9p031) |
190 | * This static table uses ext_freq and vdd_io values to select suitable | ||
191 | * PLL dividers m, n and p1 which have been calculated as specifiec in p36 | ||
192 | * of Aptina's mt9p031 datasheet. New values should be added here. | ||
193 | */ | ||
194 | static const struct mt9p031_pll_divs mt9p031_divs[] = { | ||
195 | /* ext_freq target_freq m n p1 */ | ||
196 | {21000000, 48000000, 26, 2, 6} | ||
197 | }; | ||
198 | |||
199 | static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031) | ||
200 | { | 181 | { |
182 | static const struct aptina_pll_limits limits = { | ||
183 | .ext_clock_min = 6000000, | ||
184 | .ext_clock_max = 27000000, | ||
185 | .int_clock_min = 2000000, | ||
186 | .int_clock_max = 13500000, | ||
187 | .out_clock_min = 180000000, | ||
188 | .out_clock_max = 360000000, | ||
189 | .pix_clock_max = 96000000, | ||
190 | .n_min = 1, | ||
191 | .n_max = 64, | ||
192 | .m_min = 16, | ||
193 | .m_max = 255, | ||
194 | .p1_min = 1, | ||
195 | .p1_max = 128, | ||
196 | }; | ||
197 | |||
201 | struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); | 198 | struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); |
202 | int i; | 199 | struct mt9p031_platform_data *pdata = mt9p031->pdata; |
203 | 200 | ||
204 | for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) { | 201 | mt9p031->pll.ext_clock = pdata->ext_freq; |
205 | if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq && | 202 | mt9p031->pll.pix_clock = pdata->target_freq; |
206 | mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) { | ||
207 | mt9p031->pll = &mt9p031_divs[i]; | ||
208 | return 0; | ||
209 | } | ||
210 | } | ||
211 | 203 | ||
212 | dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, " | 204 | return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll); |
213 | "target_freq = %d\n", mt9p031->pdata->ext_freq, | ||
214 | mt9p031->pdata->target_freq); | ||
215 | return -EINVAL; | ||
216 | } | 205 | } |
217 | 206 | ||
218 | static int mt9p031_pll_enable(struct mt9p031 *mt9p031) | 207 | static int mt9p031_pll_enable(struct mt9p031 *mt9p031) |
@@ -226,11 +215,11 @@ static int mt9p031_pll_enable(struct mt9p031 *mt9p031) | |||
226 | return ret; | 215 | return ret; |
227 | 216 | ||
228 | ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1, | 217 | ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1, |
229 | (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1)); | 218 | (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1)); |
230 | if (ret < 0) | 219 | if (ret < 0) |
231 | return ret; | 220 | return ret; |
232 | 221 | ||
233 | ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1); | 222 | ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1); |
234 | if (ret < 0) | 223 | if (ret < 0) |
235 | return ret; | 224 | return ret; |
236 | 225 | ||
@@ -785,8 +774,6 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | |||
785 | format->field = V4L2_FIELD_NONE; | 774 | format->field = V4L2_FIELD_NONE; |
786 | format->colorspace = V4L2_COLORSPACE_SRGB; | 775 | format->colorspace = V4L2_COLORSPACE_SRGB; |
787 | 776 | ||
788 | mt9p031->xskip = 1; | ||
789 | mt9p031->yskip = 1; | ||
790 | return mt9p031_set_power(subdev, 1); | 777 | return mt9p031_set_power(subdev, 1); |
791 | } | 778 | } |
792 | 779 | ||
@@ -905,7 +892,7 @@ static int mt9p031_probe(struct i2c_client *client, | |||
905 | mt9p031->format.field = V4L2_FIELD_NONE; | 892 | mt9p031->format.field = V4L2_FIELD_NONE; |
906 | mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; | 893 | mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; |
907 | 894 | ||
908 | ret = mt9p031_pll_get_divs(mt9p031); | 895 | ret = mt9p031_pll_setup(mt9p031); |
909 | 896 | ||
910 | done: | 897 | done: |
911 | if (ret < 0) { | 898 | if (ret < 0) { |
@@ -945,18 +932,7 @@ static struct i2c_driver mt9p031_i2c_driver = { | |||
945 | .id_table = mt9p031_id, | 932 | .id_table = mt9p031_id, |
946 | }; | 933 | }; |
947 | 934 | ||
948 | static int __init mt9p031_mod_init(void) | 935 | module_i2c_driver(mt9p031_i2c_driver); |
949 | { | ||
950 | return i2c_add_driver(&mt9p031_i2c_driver); | ||
951 | } | ||
952 | |||
953 | static void __exit mt9p031_mod_exit(void) | ||
954 | { | ||
955 | i2c_del_driver(&mt9p031_i2c_driver); | ||
956 | } | ||
957 | |||
958 | module_init(mt9p031_mod_init); | ||
959 | module_exit(mt9p031_mod_exit); | ||
960 | 936 | ||
961 | MODULE_DESCRIPTION("Aptina MT9P031 Camera driver"); | 937 | MODULE_DESCRIPTION("Aptina MT9P031 Camera driver"); |
962 | MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>"); | 938 | MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>"); |
diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c index cd81d04a529e..49ca3cbfc6f1 100644 --- a/drivers/media/video/mt9t001.c +++ b/drivers/media/video/mt9t001.c | |||
@@ -817,18 +817,7 @@ static struct i2c_driver mt9t001_driver = { | |||
817 | .id_table = mt9t001_id, | 817 | .id_table = mt9t001_id, |
818 | }; | 818 | }; |
819 | 819 | ||
820 | static int __init mt9t001_init(void) | 820 | module_i2c_driver(mt9t001_driver); |
821 | { | ||
822 | return i2c_add_driver(&mt9t001_driver); | ||
823 | } | ||
824 | |||
825 | static void __exit mt9t001_exit(void) | ||
826 | { | ||
827 | i2c_del_driver(&mt9t001_driver); | ||
828 | } | ||
829 | |||
830 | module_init(mt9t001_init); | ||
831 | module_exit(mt9t001_exit); | ||
832 | 821 | ||
833 | MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver"); | 822 | MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver"); |
834 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | 823 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); |
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 84add1aef139..1415074138a5 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -850,18 +850,7 @@ static struct i2c_driver mt9t031_i2c_driver = { | |||
850 | .id_table = mt9t031_id, | 850 | .id_table = mt9t031_id, |
851 | }; | 851 | }; |
852 | 852 | ||
853 | static int __init mt9t031_mod_init(void) | 853 | module_i2c_driver(mt9t031_i2c_driver); |
854 | { | ||
855 | return i2c_add_driver(&mt9t031_i2c_driver); | ||
856 | } | ||
857 | |||
858 | static void __exit mt9t031_mod_exit(void) | ||
859 | { | ||
860 | i2c_del_driver(&mt9t031_i2c_driver); | ||
861 | } | ||
862 | |||
863 | module_init(mt9t031_mod_init); | ||
864 | module_exit(mt9t031_mod_exit); | ||
865 | 854 | ||
866 | MODULE_DESCRIPTION("Micron MT9T031 Camera driver"); | 855 | MODULE_DESCRIPTION("Micron MT9T031 Camera driver"); |
867 | MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); | 856 | MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); |
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 7b34b11daf24..8d1445f12708 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c | |||
@@ -1117,21 +1117,7 @@ static struct i2c_driver mt9t112_i2c_driver = { | |||
1117 | .id_table = mt9t112_id, | 1117 | .id_table = mt9t112_id, |
1118 | }; | 1118 | }; |
1119 | 1119 | ||
1120 | /************************************************************************ | 1120 | module_i2c_driver(mt9t112_i2c_driver); |
1121 | module function | ||
1122 | ************************************************************************/ | ||
1123 | static int __init mt9t112_module_init(void) | ||
1124 | { | ||
1125 | return i2c_add_driver(&mt9t112_i2c_driver); | ||
1126 | } | ||
1127 | |||
1128 | static void __exit mt9t112_module_exit(void) | ||
1129 | { | ||
1130 | i2c_del_driver(&mt9t112_i2c_driver); | ||
1131 | } | ||
1132 | |||
1133 | module_init(mt9t112_module_init); | ||
1134 | module_exit(mt9t112_module_exit); | ||
1135 | 1121 | ||
1136 | MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); | 1122 | MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); |
1137 | MODULE_AUTHOR("Kuninori Morimoto"); | 1123 | MODULE_AUTHOR("Kuninori Morimoto"); |
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index db74dd27c722..6bf01ad62765 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c | |||
@@ -709,15 +709,4 @@ static struct i2c_driver mt9v011_driver = { | |||
709 | .id_table = mt9v011_id, | 709 | .id_table = mt9v011_id, |
710 | }; | 710 | }; |
711 | 711 | ||
712 | static __init int init_mt9v011(void) | 712 | module_i2c_driver(mt9v011_driver); |
713 | { | ||
714 | return i2c_add_driver(&mt9v011_driver); | ||
715 | } | ||
716 | |||
717 | static __exit void exit_mt9v011(void) | ||
718 | { | ||
719 | i2c_del_driver(&mt9v011_driver); | ||
720 | } | ||
721 | |||
722 | module_init(init_mt9v011); | ||
723 | module_exit(exit_mt9v011); | ||
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 944940758fa3..bf63417adb8f 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -872,18 +872,7 @@ static struct i2c_driver mt9v022_i2c_driver = { | |||
872 | .id_table = mt9v022_id, | 872 | .id_table = mt9v022_id, |
873 | }; | 873 | }; |
874 | 874 | ||
875 | static int __init mt9v022_mod_init(void) | 875 | module_i2c_driver(mt9v022_i2c_driver); |
876 | { | ||
877 | return i2c_add_driver(&mt9v022_i2c_driver); | ||
878 | } | ||
879 | |||
880 | static void __exit mt9v022_mod_exit(void) | ||
881 | { | ||
882 | i2c_del_driver(&mt9v022_i2c_driver); | ||
883 | } | ||
884 | |||
885 | module_init(mt9v022_mod_init); | ||
886 | module_exit(mt9v022_mod_exit); | ||
887 | 876 | ||
888 | MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); | 877 | MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); |
889 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | 878 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); |
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c index d90b982cc218..75e253a343c5 100644 --- a/drivers/media/video/mt9v032.c +++ b/drivers/media/video/mt9v032.c | |||
@@ -756,18 +756,7 @@ static struct i2c_driver mt9v032_driver = { | |||
756 | .id_table = mt9v032_id, | 756 | .id_table = mt9v032_id, |
757 | }; | 757 | }; |
758 | 758 | ||
759 | static int __init mt9v032_init(void) | 759 | module_i2c_driver(mt9v032_driver); |
760 | { | ||
761 | return i2c_add_driver(&mt9v032_driver); | ||
762 | } | ||
763 | |||
764 | static void __exit mt9v032_exit(void) | ||
765 | { | ||
766 | i2c_del_driver(&mt9v032_driver); | ||
767 | } | ||
768 | |||
769 | module_init(mt9v032_init); | ||
770 | module_exit(mt9v032_exit); | ||
771 | 760 | ||
772 | MODULE_DESCRIPTION("Aptina MT9V032 Camera driver"); | 761 | MODULE_DESCRIPTION("Aptina MT9V032 Camera driver"); |
773 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | 762 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); |
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index 04aab0c538aa..18afaeeadb7b 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2008, Sascha Hauer, Pengutronix | 4 | * Copyright (C) 2008, Sascha Hauer, Pengutronix |
5 | * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography | 5 | * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography |
6 | * Copyright (C) 2012, Javier Martin, Vista Silicon S.L. | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -18,6 +19,7 @@ | |||
18 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
19 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/gcd.h> | ||
21 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
22 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
23 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
@@ -30,17 +32,14 @@ | |||
30 | 32 | ||
31 | #include <media/v4l2-common.h> | 33 | #include <media/v4l2-common.h> |
32 | #include <media/v4l2-dev.h> | 34 | #include <media/v4l2-dev.h> |
33 | #include <media/videobuf-core.h> | 35 | #include <media/videobuf2-core.h> |
34 | #include <media/videobuf-dma-contig.h> | 36 | #include <media/videobuf2-dma-contig.h> |
35 | #include <media/soc_camera.h> | 37 | #include <media/soc_camera.h> |
36 | #include <media/soc_mediabus.h> | 38 | #include <media/soc_mediabus.h> |
37 | 39 | ||
38 | #include <linux/videodev2.h> | 40 | #include <linux/videodev2.h> |
39 | 41 | ||
40 | #include <mach/mx2_cam.h> | 42 | #include <mach/mx2_cam.h> |
41 | #ifdef CONFIG_MACH_MX27 | ||
42 | #include <mach/dma-mx1-mx2.h> | ||
43 | #endif | ||
44 | #include <mach/hardware.h> | 43 | #include <mach/hardware.h> |
45 | 44 | ||
46 | #include <asm/dma.h> | 45 | #include <asm/dma.h> |
@@ -206,10 +205,23 @@ | |||
206 | #define PRP_INTR_LBOVF (1 << 7) | 205 | #define PRP_INTR_LBOVF (1 << 7) |
207 | #define PRP_INTR_CH2OVF (1 << 8) | 206 | #define PRP_INTR_CH2OVF (1 << 8) |
208 | 207 | ||
209 | #define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma) | 208 | /* Resizing registers */ |
209 | #define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24) | ||
210 | #define PRP_RZ_VALID_BILINEAR (1 << 31) | ||
210 | 211 | ||
211 | #define MAX_VIDEO_MEM 16 | 212 | #define MAX_VIDEO_MEM 16 |
212 | 213 | ||
214 | #define RESIZE_NUM_MIN 1 | ||
215 | #define RESIZE_NUM_MAX 20 | ||
216 | #define BC_COEF 3 | ||
217 | #define SZ_COEF (1 << BC_COEF) | ||
218 | |||
219 | #define RESIZE_DIR_H 0 | ||
220 | #define RESIZE_DIR_V 1 | ||
221 | |||
222 | #define RESIZE_ALGO_BILINEAR 0 | ||
223 | #define RESIZE_ALGO_AVERAGING 1 | ||
224 | |||
213 | struct mx2_prp_cfg { | 225 | struct mx2_prp_cfg { |
214 | int channel; | 226 | int channel; |
215 | u32 in_fmt; | 227 | u32 in_fmt; |
@@ -219,6 +231,13 @@ struct mx2_prp_cfg { | |||
219 | u32 irq_flags; | 231 | u32 irq_flags; |
220 | }; | 232 | }; |
221 | 233 | ||
234 | /* prp resizing parameters */ | ||
235 | struct emma_prp_resize { | ||
236 | int algo; /* type of algorithm used */ | ||
237 | int len; /* number of coefficients */ | ||
238 | unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */ | ||
239 | }; | ||
240 | |||
222 | /* prp configuration for a client-host fmt pair */ | 241 | /* prp configuration for a client-host fmt pair */ |
223 | struct mx2_fmt_cfg { | 242 | struct mx2_fmt_cfg { |
224 | enum v4l2_mbus_pixelcode in_fmt; | 243 | enum v4l2_mbus_pixelcode in_fmt; |
@@ -226,6 +245,26 @@ struct mx2_fmt_cfg { | |||
226 | struct mx2_prp_cfg cfg; | 245 | struct mx2_prp_cfg cfg; |
227 | }; | 246 | }; |
228 | 247 | ||
248 | enum mx2_buffer_state { | ||
249 | MX2_STATE_QUEUED, | ||
250 | MX2_STATE_ACTIVE, | ||
251 | MX2_STATE_DONE, | ||
252 | }; | ||
253 | |||
254 | struct mx2_buf_internal { | ||
255 | struct list_head queue; | ||
256 | int bufnum; | ||
257 | bool discard; | ||
258 | }; | ||
259 | |||
260 | /* buffer for one video frame */ | ||
261 | struct mx2_buffer { | ||
262 | /* common v4l buffer stuff -- must be first */ | ||
263 | struct vb2_buffer vb; | ||
264 | enum mx2_buffer_state state; | ||
265 | struct mx2_buf_internal internal; | ||
266 | }; | ||
267 | |||
229 | struct mx2_camera_dev { | 268 | struct mx2_camera_dev { |
230 | struct device *dev; | 269 | struct device *dev; |
231 | struct soc_camera_host soc_host; | 270 | struct soc_camera_host soc_host; |
@@ -242,6 +281,7 @@ struct mx2_camera_dev { | |||
242 | 281 | ||
243 | struct list_head capture; | 282 | struct list_head capture; |
244 | struct list_head active_bufs; | 283 | struct list_head active_bufs; |
284 | struct list_head discard; | ||
245 | 285 | ||
246 | spinlock_t lock; | 286 | spinlock_t lock; |
247 | 287 | ||
@@ -250,26 +290,23 @@ struct mx2_camera_dev { | |||
250 | struct mx2_buffer *fb1_active; | 290 | struct mx2_buffer *fb1_active; |
251 | struct mx2_buffer *fb2_active; | 291 | struct mx2_buffer *fb2_active; |
252 | 292 | ||
253 | int use_emma; | ||
254 | |||
255 | u32 csicr1; | 293 | u32 csicr1; |
256 | 294 | ||
295 | struct mx2_buf_internal buf_discard[2]; | ||
257 | void *discard_buffer; | 296 | void *discard_buffer; |
258 | dma_addr_t discard_buffer_dma; | 297 | dma_addr_t discard_buffer_dma; |
259 | size_t discard_size; | 298 | size_t discard_size; |
260 | struct mx2_fmt_cfg *emma_prp; | 299 | struct mx2_fmt_cfg *emma_prp; |
300 | struct emma_prp_resize resizing[2]; | ||
301 | unsigned int s_width, s_height; | ||
261 | u32 frame_count; | 302 | u32 frame_count; |
303 | struct vb2_alloc_ctx *alloc_ctx; | ||
262 | }; | 304 | }; |
263 | 305 | ||
264 | /* buffer for one video frame */ | 306 | static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) |
265 | struct mx2_buffer { | 307 | { |
266 | /* common v4l buffer stuff -- must be first */ | 308 | return container_of(int_buf, struct mx2_buffer, internal); |
267 | struct videobuf_buffer vb; | 309 | } |
268 | |||
269 | enum v4l2_mbus_pixelcode code; | ||
270 | |||
271 | int bufnum; | ||
272 | }; | ||
273 | 310 | ||
274 | static struct mx2_fmt_cfg mx27_emma_prp_table[] = { | 311 | static struct mx2_fmt_cfg mx27_emma_prp_table[] = { |
275 | /* | 312 | /* |
@@ -324,13 +361,36 @@ static struct mx2_fmt_cfg *mx27_emma_prp_get_format( | |||
324 | return &mx27_emma_prp_table[0]; | 361 | return &mx27_emma_prp_table[0]; |
325 | }; | 362 | }; |
326 | 363 | ||
364 | static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev, | ||
365 | unsigned long phys, int bufnum) | ||
366 | { | ||
367 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
368 | |||
369 | if (prp->cfg.channel == 1) { | ||
370 | writel(phys, pcdev->base_emma + | ||
371 | PRP_DEST_RGB1_PTR + 4 * bufnum); | ||
372 | } else { | ||
373 | writel(phys, pcdev->base_emma + | ||
374 | PRP_DEST_Y_PTR - 0x14 * bufnum); | ||
375 | if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { | ||
376 | u32 imgsize = pcdev->icd->user_height * | ||
377 | pcdev->icd->user_width; | ||
378 | |||
379 | writel(phys + imgsize, pcdev->base_emma + | ||
380 | PRP_DEST_CB_PTR - 0x14 * bufnum); | ||
381 | writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + | ||
382 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
327 | static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) | 387 | static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) |
328 | { | 388 | { |
329 | unsigned long flags; | 389 | unsigned long flags; |
330 | 390 | ||
331 | clk_disable(pcdev->clk_csi); | 391 | clk_disable(pcdev->clk_csi); |
332 | writel(0, pcdev->base_csi + CSICR1); | 392 | writel(0, pcdev->base_csi + CSICR1); |
333 | if (mx27_camera_emma(pcdev)) { | 393 | if (cpu_is_mx27()) { |
334 | writel(0, pcdev->base_emma + PRP_CNTL); | 394 | writel(0, pcdev->base_emma + PRP_CNTL); |
335 | } else if (cpu_is_mx25()) { | 395 | } else if (cpu_is_mx25()) { |
336 | spin_lock_irqsave(&pcdev->lock, flags); | 396 | spin_lock_irqsave(&pcdev->lock, flags); |
@@ -362,7 +422,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) | |||
362 | 422 | ||
363 | csicr1 = CSICR1_MCLKEN; | 423 | csicr1 = CSICR1_MCLKEN; |
364 | 424 | ||
365 | if (mx27_camera_emma(pcdev)) { | 425 | if (cpu_is_mx27()) { |
366 | csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | | 426 | csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | |
367 | CSICR1_RXFF_LEVEL(0); | 427 | CSICR1_RXFF_LEVEL(0); |
368 | } else if (cpu_is_mx27()) | 428 | } else if (cpu_is_mx27()) |
@@ -392,56 +452,13 @@ static void mx2_camera_remove_device(struct soc_camera_device *icd) | |||
392 | 452 | ||
393 | mx2_camera_deactivate(pcdev); | 453 | mx2_camera_deactivate(pcdev); |
394 | 454 | ||
395 | if (pcdev->discard_buffer) { | ||
396 | dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size, | ||
397 | pcdev->discard_buffer, | ||
398 | pcdev->discard_buffer_dma); | ||
399 | pcdev->discard_buffer = NULL; | ||
400 | } | ||
401 | |||
402 | pcdev->icd = NULL; | 455 | pcdev->icd = NULL; |
403 | } | 456 | } |
404 | 457 | ||
405 | #ifdef CONFIG_MACH_MX27 | ||
406 | static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev) | ||
407 | { | ||
408 | u32 tmp; | ||
409 | |||
410 | imx_dma_enable(pcdev->dma); | ||
411 | |||
412 | tmp = readl(pcdev->base_csi + CSICR1); | ||
413 | tmp |= CSICR1_RF_OR_INTEN; | ||
414 | writel(tmp, pcdev->base_csi + CSICR1); | ||
415 | } | ||
416 | |||
417 | static irqreturn_t mx27_camera_irq(int irq_csi, void *data) | ||
418 | { | ||
419 | struct mx2_camera_dev *pcdev = data; | ||
420 | u32 status = readl(pcdev->base_csi + CSISR); | ||
421 | |||
422 | if (status & CSISR_SOF_INT && pcdev->active) { | ||
423 | u32 tmp; | ||
424 | |||
425 | tmp = readl(pcdev->base_csi + CSICR1); | ||
426 | writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1); | ||
427 | mx27_camera_dma_enable(pcdev); | ||
428 | } | ||
429 | |||
430 | writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR); | ||
431 | |||
432 | return IRQ_HANDLED; | ||
433 | } | ||
434 | #else | ||
435 | static irqreturn_t mx27_camera_irq(int irq_csi, void *data) | ||
436 | { | ||
437 | return IRQ_NONE; | ||
438 | } | ||
439 | #endif /* CONFIG_MACH_MX27 */ | ||
440 | |||
441 | static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, | 458 | static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, |
442 | int state) | 459 | int state) |
443 | { | 460 | { |
444 | struct videobuf_buffer *vb; | 461 | struct vb2_buffer *vb; |
445 | struct mx2_buffer *buf; | 462 | struct mx2_buffer *buf; |
446 | struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : | 463 | struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : |
447 | &pcdev->fb2_active; | 464 | &pcdev->fb2_active; |
@@ -454,25 +471,24 @@ static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, | |||
454 | goto out; | 471 | goto out; |
455 | 472 | ||
456 | vb = &(*fb_active)->vb; | 473 | vb = &(*fb_active)->vb; |
457 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 474 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
458 | vb, vb->baddr, vb->bsize); | 475 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
459 | 476 | ||
460 | vb->state = state; | 477 | do_gettimeofday(&vb->v4l2_buf.timestamp); |
461 | do_gettimeofday(&vb->ts); | 478 | vb->v4l2_buf.sequence++; |
462 | vb->field_count++; | 479 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); |
463 | |||
464 | wake_up(&vb->done); | ||
465 | 480 | ||
466 | if (list_empty(&pcdev->capture)) { | 481 | if (list_empty(&pcdev->capture)) { |
467 | buf = NULL; | 482 | buf = NULL; |
468 | writel(0, pcdev->base_csi + fb_reg); | 483 | writel(0, pcdev->base_csi + fb_reg); |
469 | } else { | 484 | } else { |
470 | buf = list_entry(pcdev->capture.next, struct mx2_buffer, | 485 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, |
471 | vb.queue); | 486 | internal.queue); |
472 | vb = &buf->vb; | 487 | vb = &buf->vb; |
473 | list_del(&vb->queue); | 488 | list_del(&buf->internal.queue); |
474 | vb->state = VIDEOBUF_ACTIVE; | 489 | buf->state = MX2_STATE_ACTIVE; |
475 | writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg); | 490 | writel(vb2_dma_contig_plane_dma_addr(vb, 0), |
491 | pcdev->base_csi + fb_reg); | ||
476 | } | 492 | } |
477 | 493 | ||
478 | *fb_active = buf; | 494 | *fb_active = buf; |
@@ -487,9 +503,9 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data) | |||
487 | u32 status = readl(pcdev->base_csi + CSISR); | 503 | u32 status = readl(pcdev->base_csi + CSISR); |
488 | 504 | ||
489 | if (status & CSISR_DMA_TSF_FB1_INT) | 505 | if (status & CSISR_DMA_TSF_FB1_INT) |
490 | mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE); | 506 | mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE); |
491 | else if (status & CSISR_DMA_TSF_FB2_INT) | 507 | else if (status & CSISR_DMA_TSF_FB2_INT) |
492 | mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE); | 508 | mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE); |
493 | 509 | ||
494 | /* FIXME: handle CSISR_RFF_OR_INT */ | 510 | /* FIXME: handle CSISR_RFF_OR_INT */ |
495 | 511 | ||
@@ -501,59 +517,50 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data) | |||
501 | /* | 517 | /* |
502 | * Videobuf operations | 518 | * Videobuf operations |
503 | */ | 519 | */ |
504 | static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | 520 | static int mx2_videobuf_setup(struct vb2_queue *vq, |
505 | unsigned int *size) | 521 | const struct v4l2_format *fmt, |
522 | unsigned int *count, unsigned int *num_planes, | ||
523 | unsigned int sizes[], void *alloc_ctxs[]) | ||
506 | { | 524 | { |
507 | struct soc_camera_device *icd = vq->priv_data; | 525 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); |
526 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
527 | struct mx2_camera_dev *pcdev = ici->priv; | ||
508 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 528 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
509 | icd->current_fmt->host_fmt); | 529 | icd->current_fmt->host_fmt); |
510 | 530 | ||
511 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); | 531 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); |
532 | |||
533 | /* TODO: support for VIDIOC_CREATE_BUFS not ready */ | ||
534 | if (fmt != NULL) | ||
535 | return -ENOTTY; | ||
512 | 536 | ||
513 | if (bytes_per_line < 0) | 537 | if (bytes_per_line < 0) |
514 | return bytes_per_line; | 538 | return bytes_per_line; |
515 | 539 | ||
516 | *size = bytes_per_line * icd->user_height; | 540 | alloc_ctxs[0] = pcdev->alloc_ctx; |
541 | |||
542 | sizes[0] = bytes_per_line * icd->user_height; | ||
517 | 543 | ||
518 | if (0 == *count) | 544 | if (0 == *count) |
519 | *count = 32; | 545 | *count = 32; |
520 | if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) | 546 | if (!*num_planes && |
521 | *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; | 547 | sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) |
548 | *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; | ||
522 | 549 | ||
523 | return 0; | 550 | *num_planes = 1; |
524 | } | ||
525 | 551 | ||
526 | static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) | 552 | return 0; |
527 | { | ||
528 | struct soc_camera_device *icd = vq->priv_data; | ||
529 | struct videobuf_buffer *vb = &buf->vb; | ||
530 | |||
531 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
532 | vb, vb->baddr, vb->bsize); | ||
533 | |||
534 | /* | ||
535 | * This waits until this buffer is out of danger, i.e., until it is no | ||
536 | * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE | ||
537 | */ | ||
538 | videobuf_waiton(vq, vb, 0, 0); | ||
539 | |||
540 | videobuf_dma_contig_free(vq, vb); | ||
541 | dev_dbg(icd->parent, "%s freed\n", __func__); | ||
542 | |||
543 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
544 | } | 553 | } |
545 | 554 | ||
546 | static int mx2_videobuf_prepare(struct videobuf_queue *vq, | 555 | static int mx2_videobuf_prepare(struct vb2_buffer *vb) |
547 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
548 | { | 556 | { |
549 | struct soc_camera_device *icd = vq->priv_data; | 557 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); |
550 | struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); | ||
551 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 558 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
552 | icd->current_fmt->host_fmt); | 559 | icd->current_fmt->host_fmt); |
553 | int ret = 0; | 560 | int ret = 0; |
554 | 561 | ||
555 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 562 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
556 | vb, vb->baddr, vb->bsize); | 563 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
557 | 564 | ||
558 | if (bytes_per_line < 0) | 565 | if (bytes_per_line < 0) |
559 | return bytes_per_line; | 566 | return bytes_per_line; |
@@ -563,99 +570,58 @@ static int mx2_videobuf_prepare(struct videobuf_queue *vq, | |||
563 | * This can be useful if you want to see if we actually fill | 570 | * This can be useful if you want to see if we actually fill |
564 | * the buffer with something | 571 | * the buffer with something |
565 | */ | 572 | */ |
566 | memset((void *)vb->baddr, 0xaa, vb->bsize); | 573 | memset((void *)vb2_plane_vaddr(vb, 0), |
574 | 0xaa, vb2_get_plane_payload(vb, 0)); | ||
567 | #endif | 575 | #endif |
568 | 576 | ||
569 | if (buf->code != icd->current_fmt->code || | 577 | vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height); |
570 | vb->width != icd->user_width || | 578 | if (vb2_plane_vaddr(vb, 0) && |
571 | vb->height != icd->user_height || | 579 | vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { |
572 | vb->field != field) { | ||
573 | buf->code = icd->current_fmt->code; | ||
574 | vb->width = icd->user_width; | ||
575 | vb->height = icd->user_height; | ||
576 | vb->field = field; | ||
577 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
578 | } | ||
579 | |||
580 | vb->size = bytes_per_line * vb->height; | ||
581 | if (vb->baddr && vb->bsize < vb->size) { | ||
582 | ret = -EINVAL; | 580 | ret = -EINVAL; |
583 | goto out; | 581 | goto out; |
584 | } | 582 | } |
585 | 583 | ||
586 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
587 | ret = videobuf_iolock(vq, vb, NULL); | ||
588 | if (ret) | ||
589 | goto fail; | ||
590 | |||
591 | vb->state = VIDEOBUF_PREPARED; | ||
592 | } | ||
593 | |||
594 | return 0; | 584 | return 0; |
595 | 585 | ||
596 | fail: | ||
597 | free_buffer(vq, buf); | ||
598 | out: | 586 | out: |
599 | return ret; | 587 | return ret; |
600 | } | 588 | } |
601 | 589 | ||
602 | static void mx2_videobuf_queue(struct videobuf_queue *vq, | 590 | static void mx2_videobuf_queue(struct vb2_buffer *vb) |
603 | struct videobuf_buffer *vb) | ||
604 | { | 591 | { |
605 | struct soc_camera_device *icd = vq->priv_data; | 592 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); |
606 | struct soc_camera_host *ici = | 593 | struct soc_camera_host *ici = |
607 | to_soc_camera_host(icd->parent); | 594 | to_soc_camera_host(icd->parent); |
608 | struct mx2_camera_dev *pcdev = ici->priv; | 595 | struct mx2_camera_dev *pcdev = ici->priv; |
609 | struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); | 596 | struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); |
610 | unsigned long flags; | 597 | unsigned long flags; |
611 | 598 | ||
612 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 599 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
613 | vb, vb->baddr, vb->bsize); | 600 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
614 | 601 | ||
615 | spin_lock_irqsave(&pcdev->lock, flags); | 602 | spin_lock_irqsave(&pcdev->lock, flags); |
616 | 603 | ||
617 | vb->state = VIDEOBUF_QUEUED; | 604 | buf->state = MX2_STATE_QUEUED; |
618 | list_add_tail(&vb->queue, &pcdev->capture); | 605 | list_add_tail(&buf->internal.queue, &pcdev->capture); |
619 | 606 | ||
620 | if (mx27_camera_emma(pcdev)) { | 607 | if (cpu_is_mx25()) { |
621 | goto out; | ||
622 | #ifdef CONFIG_MACH_MX27 | ||
623 | } else if (cpu_is_mx27()) { | ||
624 | int ret; | ||
625 | |||
626 | if (pcdev->active == NULL) { | ||
627 | ret = imx_dma_setup_single(pcdev->dma, | ||
628 | videobuf_to_dma_contig(vb), vb->size, | ||
629 | (u32)pcdev->base_dma + 0x10, | ||
630 | DMA_MODE_READ); | ||
631 | if (ret) { | ||
632 | vb->state = VIDEOBUF_ERROR; | ||
633 | wake_up(&vb->done); | ||
634 | goto out; | ||
635 | } | ||
636 | |||
637 | vb->state = VIDEOBUF_ACTIVE; | ||
638 | pcdev->active = buf; | ||
639 | } | ||
640 | #endif | ||
641 | } else { /* cpu_is_mx25() */ | ||
642 | u32 csicr3, dma_inten = 0; | 608 | u32 csicr3, dma_inten = 0; |
643 | 609 | ||
644 | if (pcdev->fb1_active == NULL) { | 610 | if (pcdev->fb1_active == NULL) { |
645 | writel(videobuf_to_dma_contig(vb), | 611 | writel(vb2_dma_contig_plane_dma_addr(vb, 0), |
646 | pcdev->base_csi + CSIDMASA_FB1); | 612 | pcdev->base_csi + CSIDMASA_FB1); |
647 | pcdev->fb1_active = buf; | 613 | pcdev->fb1_active = buf; |
648 | dma_inten = CSICR1_FB1_DMA_INTEN; | 614 | dma_inten = CSICR1_FB1_DMA_INTEN; |
649 | } else if (pcdev->fb2_active == NULL) { | 615 | } else if (pcdev->fb2_active == NULL) { |
650 | writel(videobuf_to_dma_contig(vb), | 616 | writel(vb2_dma_contig_plane_dma_addr(vb, 0), |
651 | pcdev->base_csi + CSIDMASA_FB2); | 617 | pcdev->base_csi + CSIDMASA_FB2); |
652 | pcdev->fb2_active = buf; | 618 | pcdev->fb2_active = buf; |
653 | dma_inten = CSICR1_FB2_DMA_INTEN; | 619 | dma_inten = CSICR1_FB2_DMA_INTEN; |
654 | } | 620 | } |
655 | 621 | ||
656 | if (dma_inten) { | 622 | if (dma_inten) { |
657 | list_del(&vb->queue); | 623 | list_del(&buf->internal.queue); |
658 | vb->state = VIDEOBUF_ACTIVE; | 624 | buf->state = MX2_STATE_ACTIVE; |
659 | 625 | ||
660 | csicr3 = readl(pcdev->base_csi + CSICR3); | 626 | csicr3 = readl(pcdev->base_csi + CSICR3); |
661 | 627 | ||
@@ -674,36 +640,31 @@ static void mx2_videobuf_queue(struct videobuf_queue *vq, | |||
674 | } | 640 | } |
675 | } | 641 | } |
676 | 642 | ||
677 | out: | ||
678 | spin_unlock_irqrestore(&pcdev->lock, flags); | 643 | spin_unlock_irqrestore(&pcdev->lock, flags); |
679 | } | 644 | } |
680 | 645 | ||
681 | static void mx2_videobuf_release(struct videobuf_queue *vq, | 646 | static void mx2_videobuf_release(struct vb2_buffer *vb) |
682 | struct videobuf_buffer *vb) | ||
683 | { | 647 | { |
684 | struct soc_camera_device *icd = vq->priv_data; | 648 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); |
685 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 649 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
686 | struct mx2_camera_dev *pcdev = ici->priv; | 650 | struct mx2_camera_dev *pcdev = ici->priv; |
687 | struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); | 651 | struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); |
688 | unsigned long flags; | 652 | unsigned long flags; |
689 | 653 | ||
690 | #ifdef DEBUG | 654 | #ifdef DEBUG |
691 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 655 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
692 | vb, vb->baddr, vb->bsize); | 656 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
693 | 657 | ||
694 | switch (vb->state) { | 658 | switch (buf->state) { |
695 | case VIDEOBUF_ACTIVE: | 659 | case MX2_STATE_ACTIVE: |
696 | dev_info(icd->parent, "%s (active)\n", __func__); | 660 | dev_info(icd->parent, "%s (active)\n", __func__); |
697 | break; | 661 | break; |
698 | case VIDEOBUF_QUEUED: | 662 | case MX2_STATE_QUEUED: |
699 | dev_info(icd->parent, "%s (queued)\n", __func__); | 663 | dev_info(icd->parent, "%s (queued)\n", __func__); |
700 | break; | 664 | break; |
701 | case VIDEOBUF_PREPARED: | ||
702 | dev_info(icd->parent, "%s (prepared)\n", __func__); | ||
703 | break; | ||
704 | default: | 665 | default: |
705 | dev_info(icd->parent, "%s (unknown) %d\n", __func__, | 666 | dev_info(icd->parent, "%s (unknown) %d\n", __func__, |
706 | vb->state); | 667 | buf->state); |
707 | break; | 668 | break; |
708 | } | 669 | } |
709 | #endif | 670 | #endif |
@@ -717,11 +678,9 @@ static void mx2_videobuf_release(struct videobuf_queue *vq, | |||
717 | * state. This requires a specific handling for each of the these DMA | 678 | * state. This requires a specific handling for each of the these DMA |
718 | * types. | 679 | * types. |
719 | */ | 680 | */ |
681 | |||
720 | spin_lock_irqsave(&pcdev->lock, flags); | 682 | spin_lock_irqsave(&pcdev->lock, flags); |
721 | if (vb->state == VIDEOBUF_QUEUED) { | 683 | if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { |
722 | list_del(&vb->queue); | ||
723 | vb->state = VIDEOBUF_ERROR; | ||
724 | } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) { | ||
725 | if (pcdev->fb1_active == buf) { | 684 | if (pcdev->fb1_active == buf) { |
726 | pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; | 685 | pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; |
727 | writel(0, pcdev->base_csi + CSIDMASA_FB1); | 686 | writel(0, pcdev->base_csi + CSIDMASA_FB1); |
@@ -732,75 +691,178 @@ static void mx2_videobuf_release(struct videobuf_queue *vq, | |||
732 | pcdev->fb2_active = NULL; | 691 | pcdev->fb2_active = NULL; |
733 | } | 692 | } |
734 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | 693 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); |
735 | vb->state = VIDEOBUF_ERROR; | ||
736 | } | 694 | } |
737 | spin_unlock_irqrestore(&pcdev->lock, flags); | 695 | spin_unlock_irqrestore(&pcdev->lock, flags); |
738 | |||
739 | free_buffer(vq, buf); | ||
740 | } | 696 | } |
741 | 697 | ||
742 | static struct videobuf_queue_ops mx2_videobuf_ops = { | 698 | static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, |
743 | .buf_setup = mx2_videobuf_setup, | 699 | int bytesperline) |
744 | .buf_prepare = mx2_videobuf_prepare, | ||
745 | .buf_queue = mx2_videobuf_queue, | ||
746 | .buf_release = mx2_videobuf_release, | ||
747 | }; | ||
748 | |||
749 | static void mx2_camera_init_videobuf(struct videobuf_queue *q, | ||
750 | struct soc_camera_device *icd) | ||
751 | { | 700 | { |
752 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 701 | struct soc_camera_host *ici = |
702 | to_soc_camera_host(icd->parent); | ||
753 | struct mx2_camera_dev *pcdev = ici->priv; | 703 | struct mx2_camera_dev *pcdev = ici->priv; |
704 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
754 | 705 | ||
755 | videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev, | 706 | writel((pcdev->s_width << 16) | pcdev->s_height, |
756 | &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, | 707 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); |
757 | V4L2_FIELD_NONE, sizeof(struct mx2_buffer), | 708 | writel(prp->cfg.src_pixel, |
758 | icd, &icd->video_lock); | 709 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); |
759 | } | 710 | if (prp->cfg.channel == 1) { |
711 | writel((icd->user_width << 16) | icd->user_height, | ||
712 | pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); | ||
713 | writel(bytesperline, | ||
714 | pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); | ||
715 | writel(prp->cfg.ch1_pixel, | ||
716 | pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); | ||
717 | } else { /* channel 2 */ | ||
718 | writel((icd->user_width << 16) | icd->user_height, | ||
719 | pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); | ||
720 | } | ||
760 | 721 | ||
761 | #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ | 722 | /* Enable interrupts */ |
762 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | 723 | writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); |
763 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | 724 | } |
764 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
765 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
766 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
767 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
768 | V4L2_MBUS_DATA_ACTIVE_HIGH | \ | ||
769 | V4L2_MBUS_DATA_ACTIVE_LOW) | ||
770 | 725 | ||
771 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) | 726 | static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev) |
772 | { | 727 | { |
773 | u32 cntl; | 728 | int dir; |
774 | int count = 0; | ||
775 | 729 | ||
776 | cntl = readl(pcdev->base_emma + PRP_CNTL); | 730 | for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { |
777 | writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); | 731 | unsigned char *s = pcdev->resizing[dir].s; |
778 | while (count++ < 100) { | 732 | int len = pcdev->resizing[dir].len; |
779 | if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) | 733 | unsigned int coeff[2] = {0, 0}; |
780 | return 0; | 734 | unsigned int valid = 0; |
781 | barrier(); | 735 | int i; |
782 | udelay(1); | ||
783 | } | ||
784 | 736 | ||
785 | return -ETIMEDOUT; | 737 | if (len == 0) |
738 | continue; | ||
739 | |||
740 | for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) { | ||
741 | int j; | ||
742 | |||
743 | j = i > 9 ? 1 : 0; | ||
744 | coeff[j] = (coeff[j] << BC_COEF) | | ||
745 | (s[i] & (SZ_COEF - 1)); | ||
746 | |||
747 | if (i == 5 || i == 15) | ||
748 | coeff[j] <<= 1; | ||
749 | |||
750 | valid = (valid << 1) | (s[i] >> BC_COEF); | ||
751 | } | ||
752 | |||
753 | valid |= PRP_RZ_VALID_TBL_LEN(len); | ||
754 | |||
755 | if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR) | ||
756 | valid |= PRP_RZ_VALID_BILINEAR; | ||
757 | |||
758 | if (pcdev->emma_prp->cfg.channel == 1) { | ||
759 | if (dir == RESIZE_DIR_H) { | ||
760 | writel(coeff[0], pcdev->base_emma + | ||
761 | PRP_CH1_RZ_HORI_COEF1); | ||
762 | writel(coeff[1], pcdev->base_emma + | ||
763 | PRP_CH1_RZ_HORI_COEF2); | ||
764 | writel(valid, pcdev->base_emma + | ||
765 | PRP_CH1_RZ_HORI_VALID); | ||
766 | } else { | ||
767 | writel(coeff[0], pcdev->base_emma + | ||
768 | PRP_CH1_RZ_VERT_COEF1); | ||
769 | writel(coeff[1], pcdev->base_emma + | ||
770 | PRP_CH1_RZ_VERT_COEF2); | ||
771 | writel(valid, pcdev->base_emma + | ||
772 | PRP_CH1_RZ_VERT_VALID); | ||
773 | } | ||
774 | } else { | ||
775 | if (dir == RESIZE_DIR_H) { | ||
776 | writel(coeff[0], pcdev->base_emma + | ||
777 | PRP_CH2_RZ_HORI_COEF1); | ||
778 | writel(coeff[1], pcdev->base_emma + | ||
779 | PRP_CH2_RZ_HORI_COEF2); | ||
780 | writel(valid, pcdev->base_emma + | ||
781 | PRP_CH2_RZ_HORI_VALID); | ||
782 | } else { | ||
783 | writel(coeff[0], pcdev->base_emma + | ||
784 | PRP_CH2_RZ_VERT_COEF1); | ||
785 | writel(coeff[1], pcdev->base_emma + | ||
786 | PRP_CH2_RZ_VERT_COEF2); | ||
787 | writel(valid, pcdev->base_emma + | ||
788 | PRP_CH2_RZ_VERT_VALID); | ||
789 | } | ||
790 | } | ||
791 | } | ||
786 | } | 792 | } |
787 | 793 | ||
788 | static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | 794 | static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) |
789 | int bytesperline) | ||
790 | { | 795 | { |
796 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
791 | struct soc_camera_host *ici = | 797 | struct soc_camera_host *ici = |
792 | to_soc_camera_host(icd->parent); | 798 | to_soc_camera_host(icd->parent); |
793 | struct mx2_camera_dev *pcdev = ici->priv; | 799 | struct mx2_camera_dev *pcdev = ici->priv; |
794 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | 800 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; |
795 | u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; | 801 | struct vb2_buffer *vb; |
802 | struct mx2_buffer *buf; | ||
803 | unsigned long phys; | ||
804 | int bytesperline; | ||
796 | 805 | ||
797 | if (prp->cfg.channel == 1) { | 806 | if (cpu_is_mx27()) { |
798 | writel(pcdev->discard_buffer_dma, | 807 | unsigned long flags; |
799 | pcdev->base_emma + PRP_DEST_RGB1_PTR); | 808 | if (count < 2) |
800 | writel(pcdev->discard_buffer_dma, | 809 | return -EINVAL; |
801 | pcdev->base_emma + PRP_DEST_RGB2_PTR); | 810 | |
811 | spin_lock_irqsave(&pcdev->lock, flags); | ||
812 | |||
813 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
814 | internal.queue); | ||
815 | buf->internal.bufnum = 0; | ||
816 | vb = &buf->vb; | ||
817 | buf->state = MX2_STATE_ACTIVE; | ||
818 | |||
819 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
820 | mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); | ||
821 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
822 | |||
823 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
824 | internal.queue); | ||
825 | buf->internal.bufnum = 1; | ||
826 | vb = &buf->vb; | ||
827 | buf->state = MX2_STATE_ACTIVE; | ||
802 | 828 | ||
803 | writel(PRP_CNTL_CH1EN | | 829 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); |
830 | mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); | ||
831 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
832 | |||
833 | bytesperline = soc_mbus_bytes_per_line(icd->user_width, | ||
834 | icd->current_fmt->host_fmt); | ||
835 | if (bytesperline < 0) | ||
836 | return bytesperline; | ||
837 | |||
838 | /* | ||
839 | * I didn't manage to properly enable/disable the prp | ||
840 | * on a per frame basis during running transfers, | ||
841 | * thus we allocate a buffer here and use it to | ||
842 | * discard frames when no buffer is available. | ||
843 | * Feel free to work on this ;) | ||
844 | */ | ||
845 | pcdev->discard_size = icd->user_height * bytesperline; | ||
846 | pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, | ||
847 | pcdev->discard_size, &pcdev->discard_buffer_dma, | ||
848 | GFP_KERNEL); | ||
849 | if (!pcdev->discard_buffer) | ||
850 | return -ENOMEM; | ||
851 | |||
852 | pcdev->buf_discard[0].discard = true; | ||
853 | list_add_tail(&pcdev->buf_discard[0].queue, | ||
854 | &pcdev->discard); | ||
855 | |||
856 | pcdev->buf_discard[1].discard = true; | ||
857 | list_add_tail(&pcdev->buf_discard[1].queue, | ||
858 | &pcdev->discard); | ||
859 | |||
860 | mx2_prp_resize_commit(pcdev); | ||
861 | |||
862 | mx27_camera_emma_buf_init(icd, bytesperline); | ||
863 | |||
864 | if (prp->cfg.channel == 1) { | ||
865 | writel(PRP_CNTL_CH1EN | | ||
804 | PRP_CNTL_CSIEN | | 866 | PRP_CNTL_CSIEN | |
805 | prp->cfg.in_fmt | | 867 | prp->cfg.in_fmt | |
806 | prp->cfg.out_fmt | | 868 | prp->cfg.out_fmt | |
@@ -809,56 +871,107 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | |||
809 | PRP_CNTL_CH1_TSKIP(0) | | 871 | PRP_CNTL_CH1_TSKIP(0) | |
810 | PRP_CNTL_IN_TSKIP(0), | 872 | PRP_CNTL_IN_TSKIP(0), |
811 | pcdev->base_emma + PRP_CNTL); | 873 | pcdev->base_emma + PRP_CNTL); |
874 | } else { | ||
875 | writel(PRP_CNTL_CH2EN | | ||
876 | PRP_CNTL_CSIEN | | ||
877 | prp->cfg.in_fmt | | ||
878 | prp->cfg.out_fmt | | ||
879 | PRP_CNTL_CH2_LEN | | ||
880 | PRP_CNTL_CH2_TSKIP(0) | | ||
881 | PRP_CNTL_IN_TSKIP(0), | ||
882 | pcdev->base_emma + PRP_CNTL); | ||
883 | } | ||
884 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
885 | } | ||
812 | 886 | ||
813 | writel((icd->user_width << 16) | icd->user_height, | 887 | return 0; |
814 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | 888 | } |
815 | writel((icd->user_width << 16) | icd->user_height, | 889 | |
816 | pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); | 890 | static int mx2_stop_streaming(struct vb2_queue *q) |
817 | writel(bytesperline, | 891 | { |
818 | pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); | 892 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); |
819 | writel(prp->cfg.src_pixel, | 893 | struct soc_camera_host *ici = |
820 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); | 894 | to_soc_camera_host(icd->parent); |
821 | writel(prp->cfg.ch1_pixel, | 895 | struct mx2_camera_dev *pcdev = ici->priv; |
822 | pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); | 896 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; |
823 | } else { /* channel 2 */ | 897 | unsigned long flags; |
824 | writel(pcdev->discard_buffer_dma, | 898 | void *b; |
825 | pcdev->base_emma + PRP_DEST_Y_PTR); | 899 | u32 cntl; |
826 | writel(pcdev->discard_buffer_dma, | 900 | |
827 | pcdev->base_emma + PRP_SOURCE_Y_PTR); | 901 | if (cpu_is_mx27()) { |
828 | 902 | spin_lock_irqsave(&pcdev->lock, flags); | |
829 | if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { | 903 | |
830 | writel(pcdev->discard_buffer_dma + imgsize, | 904 | cntl = readl(pcdev->base_emma + PRP_CNTL); |
831 | pcdev->base_emma + PRP_DEST_CB_PTR); | 905 | if (prp->cfg.channel == 1) { |
832 | writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), | 906 | writel(cntl & ~PRP_CNTL_CH1EN, |
833 | pcdev->base_emma + PRP_DEST_CR_PTR); | 907 | pcdev->base_emma + PRP_CNTL); |
834 | writel(pcdev->discard_buffer_dma + imgsize, | 908 | } else { |
835 | pcdev->base_emma + PRP_SOURCE_CB_PTR); | 909 | writel(cntl & ~PRP_CNTL_CH2EN, |
836 | writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), | 910 | pcdev->base_emma + PRP_CNTL); |
837 | pcdev->base_emma + PRP_SOURCE_CR_PTR); | ||
838 | } | 911 | } |
912 | INIT_LIST_HEAD(&pcdev->capture); | ||
913 | INIT_LIST_HEAD(&pcdev->active_bufs); | ||
914 | INIT_LIST_HEAD(&pcdev->discard); | ||
839 | 915 | ||
840 | writel(PRP_CNTL_CH2EN | | 916 | b = pcdev->discard_buffer; |
841 | PRP_CNTL_CSIEN | | 917 | pcdev->discard_buffer = NULL; |
842 | prp->cfg.in_fmt | | ||
843 | prp->cfg.out_fmt | | ||
844 | PRP_CNTL_CH2_LEN | | ||
845 | PRP_CNTL_CH2_TSKIP(0) | | ||
846 | PRP_CNTL_IN_TSKIP(0), | ||
847 | pcdev->base_emma + PRP_CNTL); | ||
848 | 918 | ||
849 | writel((icd->user_width << 16) | icd->user_height, | 919 | spin_unlock_irqrestore(&pcdev->lock, flags); |
850 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | ||
851 | 920 | ||
852 | writel((icd->user_width << 16) | icd->user_height, | 921 | dma_free_coherent(ici->v4l2_dev.dev, |
853 | pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); | 922 | pcdev->discard_size, b, pcdev->discard_buffer_dma); |
923 | } | ||
854 | 924 | ||
855 | writel(prp->cfg.src_pixel, | 925 | return 0; |
856 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); | 926 | } |
927 | |||
928 | static struct vb2_ops mx2_videobuf_ops = { | ||
929 | .queue_setup = mx2_videobuf_setup, | ||
930 | .buf_prepare = mx2_videobuf_prepare, | ||
931 | .buf_queue = mx2_videobuf_queue, | ||
932 | .buf_cleanup = mx2_videobuf_release, | ||
933 | .start_streaming = mx2_start_streaming, | ||
934 | .stop_streaming = mx2_stop_streaming, | ||
935 | }; | ||
936 | |||
937 | static int mx2_camera_init_videobuf(struct vb2_queue *q, | ||
938 | struct soc_camera_device *icd) | ||
939 | { | ||
940 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
941 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
942 | q->drv_priv = icd; | ||
943 | q->ops = &mx2_videobuf_ops; | ||
944 | q->mem_ops = &vb2_dma_contig_memops; | ||
945 | q->buf_struct_size = sizeof(struct mx2_buffer); | ||
946 | |||
947 | return vb2_queue_init(q); | ||
948 | } | ||
857 | 949 | ||
950 | #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
951 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
952 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
953 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
954 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
955 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
956 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
957 | V4L2_MBUS_DATA_ACTIVE_HIGH | \ | ||
958 | V4L2_MBUS_DATA_ACTIVE_LOW) | ||
959 | |||
960 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) | ||
961 | { | ||
962 | u32 cntl; | ||
963 | int count = 0; | ||
964 | |||
965 | cntl = readl(pcdev->base_emma + PRP_CNTL); | ||
966 | writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); | ||
967 | while (count++ < 100) { | ||
968 | if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) | ||
969 | return 0; | ||
970 | barrier(); | ||
971 | udelay(1); | ||
858 | } | 972 | } |
859 | 973 | ||
860 | /* Enable interrupts */ | 974 | return -ETIMEDOUT; |
861 | writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); | ||
862 | } | 975 | } |
863 | 976 | ||
864 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | 977 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd) |
@@ -939,31 +1052,10 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | |||
939 | if (bytesperline < 0) | 1052 | if (bytesperline < 0) |
940 | return bytesperline; | 1053 | return bytesperline; |
941 | 1054 | ||
942 | if (mx27_camera_emma(pcdev)) { | 1055 | if (cpu_is_mx27()) { |
943 | ret = mx27_camera_emma_prp_reset(pcdev); | 1056 | ret = mx27_camera_emma_prp_reset(pcdev); |
944 | if (ret) | 1057 | if (ret) |
945 | return ret; | 1058 | return ret; |
946 | |||
947 | if (pcdev->discard_buffer) | ||
948 | dma_free_coherent(ici->v4l2_dev.dev, | ||
949 | pcdev->discard_size, pcdev->discard_buffer, | ||
950 | pcdev->discard_buffer_dma); | ||
951 | |||
952 | /* | ||
953 | * I didn't manage to properly enable/disable the prp | ||
954 | * on a per frame basis during running transfers, | ||
955 | * thus we allocate a buffer here and use it to | ||
956 | * discard frames when no buffer is available. | ||
957 | * Feel free to work on this ;) | ||
958 | */ | ||
959 | pcdev->discard_size = icd->user_height * bytesperline; | ||
960 | pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, | ||
961 | pcdev->discard_size, &pcdev->discard_buffer_dma, | ||
962 | GFP_KERNEL); | ||
963 | if (!pcdev->discard_buffer) | ||
964 | return -ENOMEM; | ||
965 | |||
966 | mx27_camera_emma_buf_init(icd, bytesperline); | ||
967 | } else if (cpu_is_mx25()) { | 1059 | } else if (cpu_is_mx25()) { |
968 | writel((bytesperline * icd->user_height) >> 2, | 1060 | writel((bytesperline * icd->user_height) >> 2, |
969 | pcdev->base_csi + CSIRXCNT); | 1061 | pcdev->base_csi + CSIRXCNT); |
@@ -1052,6 +1144,123 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, | |||
1052 | return formats; | 1144 | return formats; |
1053 | } | 1145 | } |
1054 | 1146 | ||
1147 | static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev, | ||
1148 | struct v4l2_mbus_framefmt *mf_in, | ||
1149 | struct v4l2_pix_format *pix_out, bool apply) | ||
1150 | { | ||
1151 | int num, den; | ||
1152 | unsigned long m; | ||
1153 | int i, dir; | ||
1154 | |||
1155 | for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { | ||
1156 | struct emma_prp_resize tmprsz; | ||
1157 | unsigned char *s = tmprsz.s; | ||
1158 | int len = 0; | ||
1159 | int in, out; | ||
1160 | |||
1161 | if (dir == RESIZE_DIR_H) { | ||
1162 | in = mf_in->width; | ||
1163 | out = pix_out->width; | ||
1164 | } else { | ||
1165 | in = mf_in->height; | ||
1166 | out = pix_out->height; | ||
1167 | } | ||
1168 | |||
1169 | if (in < out) | ||
1170 | return -EINVAL; | ||
1171 | else if (in == out) | ||
1172 | continue; | ||
1173 | |||
1174 | /* Calculate ratio */ | ||
1175 | m = gcd(in, out); | ||
1176 | num = in / m; | ||
1177 | den = out / m; | ||
1178 | if (num > RESIZE_NUM_MAX) | ||
1179 | return -EINVAL; | ||
1180 | |||
1181 | if ((num >= 2 * den) && (den == 1) && | ||
1182 | (num < 9) && (!(num & 0x01))) { | ||
1183 | int sum = 0; | ||
1184 | int j; | ||
1185 | |||
1186 | /* Average scaling for >= 2:1 ratios */ | ||
1187 | /* Support can be added for num >=9 and odd values */ | ||
1188 | |||
1189 | tmprsz.algo = RESIZE_ALGO_AVERAGING; | ||
1190 | len = num; | ||
1191 | |||
1192 | for (i = 0; i < (len / 2); i++) | ||
1193 | s[i] = 8; | ||
1194 | |||
1195 | do { | ||
1196 | for (i = 0; i < (len / 2); i++) { | ||
1197 | s[i] = s[i] >> 1; | ||
1198 | sum = 0; | ||
1199 | for (j = 0; j < (len / 2); j++) | ||
1200 | sum += s[j]; | ||
1201 | if (sum == 4) | ||
1202 | break; | ||
1203 | } | ||
1204 | } while (sum != 4); | ||
1205 | |||
1206 | for (i = (len / 2); i < len; i++) | ||
1207 | s[i] = s[len - i - 1]; | ||
1208 | |||
1209 | s[len - 1] |= SZ_COEF; | ||
1210 | } else { | ||
1211 | /* bilinear scaling for < 2:1 ratios */ | ||
1212 | int v; /* overflow counter */ | ||
1213 | int coeff, nxt; /* table output */ | ||
1214 | int in_pos_inc = 2 * den; | ||
1215 | int out_pos = num; | ||
1216 | int out_pos_inc = 2 * num; | ||
1217 | int init_carry = num - den; | ||
1218 | int carry = init_carry; | ||
1219 | |||
1220 | tmprsz.algo = RESIZE_ALGO_BILINEAR; | ||
1221 | v = den + in_pos_inc; | ||
1222 | do { | ||
1223 | coeff = v - out_pos; | ||
1224 | out_pos += out_pos_inc; | ||
1225 | carry += out_pos_inc; | ||
1226 | for (nxt = 0; v < out_pos; nxt++) { | ||
1227 | v += in_pos_inc; | ||
1228 | carry -= in_pos_inc; | ||
1229 | } | ||
1230 | |||
1231 | if (len > RESIZE_NUM_MAX) | ||
1232 | return -EINVAL; | ||
1233 | |||
1234 | coeff = ((coeff << BC_COEF) + | ||
1235 | (in_pos_inc >> 1)) / in_pos_inc; | ||
1236 | |||
1237 | if (coeff >= (SZ_COEF - 1)) | ||
1238 | coeff--; | ||
1239 | |||
1240 | coeff |= SZ_COEF; | ||
1241 | s[len] = (unsigned char)coeff; | ||
1242 | len++; | ||
1243 | |||
1244 | for (i = 1; i < nxt; i++) { | ||
1245 | if (len >= RESIZE_NUM_MAX) | ||
1246 | return -EINVAL; | ||
1247 | s[len] = 0; | ||
1248 | len++; | ||
1249 | } | ||
1250 | } while (carry != init_carry); | ||
1251 | } | ||
1252 | tmprsz.len = len; | ||
1253 | if (dir == RESIZE_DIR_H) | ||
1254 | mf_in->width = pix_out->width; | ||
1255 | else | ||
1256 | mf_in->height = pix_out->height; | ||
1257 | |||
1258 | if (apply) | ||
1259 | memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz)); | ||
1260 | } | ||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1055 | static int mx2_camera_set_fmt(struct soc_camera_device *icd, | 1264 | static int mx2_camera_set_fmt(struct soc_camera_device *icd, |
1056 | struct v4l2_format *f) | 1265 | struct v4l2_format *f) |
1057 | { | 1266 | { |
@@ -1063,6 +1272,9 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, | |||
1063 | struct v4l2_mbus_framefmt mf; | 1272 | struct v4l2_mbus_framefmt mf; |
1064 | int ret; | 1273 | int ret; |
1065 | 1274 | ||
1275 | dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", | ||
1276 | __func__, pix->width, pix->height); | ||
1277 | |||
1066 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 1278 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
1067 | if (!xlate) { | 1279 | if (!xlate) { |
1068 | dev_warn(icd->parent, "Format %x not found\n", | 1280 | dev_warn(icd->parent, "Format %x not found\n", |
@@ -1080,6 +1292,22 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, | |||
1080 | if (ret < 0 && ret != -ENOIOCTLCMD) | 1292 | if (ret < 0 && ret != -ENOIOCTLCMD) |
1081 | return ret; | 1293 | return ret; |
1082 | 1294 | ||
1295 | /* Store width and height returned by the sensor for resizing */ | ||
1296 | pcdev->s_width = mf.width; | ||
1297 | pcdev->s_height = mf.height; | ||
1298 | dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", | ||
1299 | __func__, pcdev->s_width, pcdev->s_height); | ||
1300 | |||
1301 | pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, | ||
1302 | xlate->host_fmt->fourcc); | ||
1303 | |||
1304 | memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); | ||
1305 | if ((mf.width != pix->width || mf.height != pix->height) && | ||
1306 | pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { | ||
1307 | if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0) | ||
1308 | dev_dbg(icd->parent, "%s: can't resize\n", __func__); | ||
1309 | } | ||
1310 | |||
1083 | if (mf.code != xlate->code) | 1311 | if (mf.code != xlate->code) |
1084 | return -EINVAL; | 1312 | return -EINVAL; |
1085 | 1313 | ||
@@ -1089,9 +1317,8 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, | |||
1089 | pix->colorspace = mf.colorspace; | 1317 | pix->colorspace = mf.colorspace; |
1090 | icd->current_fmt = xlate; | 1318 | icd->current_fmt = xlate; |
1091 | 1319 | ||
1092 | if (mx27_camera_emma(pcdev)) | 1320 | dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", |
1093 | pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, | 1321 | __func__, pix->width, pix->height); |
1094 | xlate->host_fmt->fourcc); | ||
1095 | 1322 | ||
1096 | return 0; | 1323 | return 0; |
1097 | } | 1324 | } |
@@ -1104,9 +1331,14 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, | |||
1104 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1331 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1105 | struct v4l2_mbus_framefmt mf; | 1332 | struct v4l2_mbus_framefmt mf; |
1106 | __u32 pixfmt = pix->pixelformat; | 1333 | __u32 pixfmt = pix->pixelformat; |
1334 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1335 | struct mx2_camera_dev *pcdev = ici->priv; | ||
1107 | unsigned int width_limit; | 1336 | unsigned int width_limit; |
1108 | int ret; | 1337 | int ret; |
1109 | 1338 | ||
1339 | dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", | ||
1340 | __func__, pix->width, pix->height); | ||
1341 | |||
1110 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1342 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
1111 | if (pixfmt && !xlate) { | 1343 | if (pixfmt && !xlate) { |
1112 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | 1344 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); |
@@ -1156,6 +1388,20 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, | |||
1156 | if (ret < 0) | 1388 | if (ret < 0) |
1157 | return ret; | 1389 | return ret; |
1158 | 1390 | ||
1391 | dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", | ||
1392 | __func__, pcdev->s_width, pcdev->s_height); | ||
1393 | |||
1394 | /* If the sensor does not support image size try PrP resizing */ | ||
1395 | pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, | ||
1396 | xlate->host_fmt->fourcc); | ||
1397 | |||
1398 | memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); | ||
1399 | if ((mf.width != pix->width || mf.height != pix->height) && | ||
1400 | pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { | ||
1401 | if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) | ||
1402 | dev_dbg(icd->parent, "%s: can't resize\n", __func__); | ||
1403 | } | ||
1404 | |||
1159 | if (mf.field == V4L2_FIELD_ANY) | 1405 | if (mf.field == V4L2_FIELD_ANY) |
1160 | mf.field = V4L2_FIELD_NONE; | 1406 | mf.field = V4L2_FIELD_NONE; |
1161 | /* | 1407 | /* |
@@ -1174,6 +1420,9 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, | |||
1174 | pix->field = mf.field; | 1420 | pix->field = mf.field; |
1175 | pix->colorspace = mf.colorspace; | 1421 | pix->colorspace = mf.colorspace; |
1176 | 1422 | ||
1423 | dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", | ||
1424 | __func__, pix->width, pix->height); | ||
1425 | |||
1177 | return 0; | 1426 | return 0; |
1178 | } | 1427 | } |
1179 | 1428 | ||
@@ -1187,136 +1436,11 @@ static int mx2_camera_querycap(struct soc_camera_host *ici, | |||
1187 | return 0; | 1436 | return 0; |
1188 | } | 1437 | } |
1189 | 1438 | ||
1190 | static int mx2_camera_reqbufs(struct soc_camera_device *icd, | ||
1191 | struct v4l2_requestbuffers *p) | ||
1192 | { | ||
1193 | int i; | ||
1194 | |||
1195 | for (i = 0; i < p->count; i++) { | ||
1196 | struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i], | ||
1197 | struct mx2_buffer, vb); | ||
1198 | INIT_LIST_HEAD(&buf->vb.queue); | ||
1199 | } | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | #ifdef CONFIG_MACH_MX27 | ||
1205 | static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state) | ||
1206 | { | ||
1207 | struct videobuf_buffer *vb; | ||
1208 | struct mx2_buffer *buf; | ||
1209 | unsigned long flags; | ||
1210 | int ret; | ||
1211 | |||
1212 | spin_lock_irqsave(&pcdev->lock, flags); | ||
1213 | |||
1214 | if (!pcdev->active) { | ||
1215 | dev_err(pcdev->dev, "%s called with no active buffer!\n", | ||
1216 | __func__); | ||
1217 | goto out; | ||
1218 | } | ||
1219 | |||
1220 | vb = &pcdev->active->vb; | ||
1221 | buf = container_of(vb, struct mx2_buffer, vb); | ||
1222 | WARN_ON(list_empty(&vb->queue)); | ||
1223 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
1224 | vb, vb->baddr, vb->bsize); | ||
1225 | |||
1226 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ | ||
1227 | list_del_init(&vb->queue); | ||
1228 | vb->state = state; | ||
1229 | do_gettimeofday(&vb->ts); | ||
1230 | vb->field_count++; | ||
1231 | |||
1232 | wake_up(&vb->done); | ||
1233 | |||
1234 | if (list_empty(&pcdev->capture)) { | ||
1235 | pcdev->active = NULL; | ||
1236 | goto out; | ||
1237 | } | ||
1238 | |||
1239 | pcdev->active = list_entry(pcdev->capture.next, | ||
1240 | struct mx2_buffer, vb.queue); | ||
1241 | |||
1242 | vb = &pcdev->active->vb; | ||
1243 | vb->state = VIDEOBUF_ACTIVE; | ||
1244 | |||
1245 | ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb), | ||
1246 | vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ); | ||
1247 | |||
1248 | if (ret) { | ||
1249 | vb->state = VIDEOBUF_ERROR; | ||
1250 | pcdev->active = NULL; | ||
1251 | wake_up(&vb->done); | ||
1252 | } | ||
1253 | |||
1254 | out: | ||
1255 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
1256 | } | ||
1257 | |||
1258 | static void mx27_camera_dma_err_callback(int channel, void *data, int err) | ||
1259 | { | ||
1260 | struct mx2_camera_dev *pcdev = data; | ||
1261 | |||
1262 | mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR); | ||
1263 | } | ||
1264 | |||
1265 | static void mx27_camera_dma_callback(int channel, void *data) | ||
1266 | { | ||
1267 | struct mx2_camera_dev *pcdev = data; | ||
1268 | |||
1269 | mx27_camera_frame_done(pcdev, VIDEOBUF_DONE); | ||
1270 | } | ||
1271 | |||
1272 | #define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */ | ||
1273 | |||
1274 | static int __devinit mx27_camera_dma_init(struct platform_device *pdev, | ||
1275 | struct mx2_camera_dev *pcdev) | ||
1276 | { | ||
1277 | int err; | ||
1278 | |||
1279 | pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH); | ||
1280 | if (pcdev->dma < 0) { | ||
1281 | dev_err(&pdev->dev, "%s failed to request DMA channel\n", | ||
1282 | __func__); | ||
1283 | return pcdev->dma; | ||
1284 | } | ||
1285 | |||
1286 | err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback, | ||
1287 | mx27_camera_dma_err_callback, pcdev); | ||
1288 | if (err) { | ||
1289 | dev_err(&pdev->dev, "%s failed to set DMA callback\n", | ||
1290 | __func__); | ||
1291 | goto err_out; | ||
1292 | } | ||
1293 | |||
1294 | err = imx_dma_config_channel(pcdev->dma, | ||
1295 | IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, | ||
1296 | IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
1297 | DMA_REQ_CSI_RX, 1); | ||
1298 | if (err) { | ||
1299 | dev_err(&pdev->dev, "%s failed to config DMA channel\n", | ||
1300 | __func__); | ||
1301 | goto err_out; | ||
1302 | } | ||
1303 | |||
1304 | imx_dma_config_burstlen(pcdev->dma, 64); | ||
1305 | |||
1306 | return 0; | ||
1307 | |||
1308 | err_out: | ||
1309 | imx_dma_free(pcdev->dma); | ||
1310 | |||
1311 | return err; | ||
1312 | } | ||
1313 | #endif /* CONFIG_MACH_MX27 */ | ||
1314 | |||
1315 | static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) | 1439 | static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) |
1316 | { | 1440 | { |
1317 | struct soc_camera_device *icd = file->private_data; | 1441 | struct soc_camera_device *icd = file->private_data; |
1318 | 1442 | ||
1319 | return videobuf_poll_stream(file, &icd->vb_vidq, pt); | 1443 | return vb2_poll(&icd->vb2_vidq, file, pt); |
1320 | } | 1444 | } |
1321 | 1445 | ||
1322 | static struct soc_camera_host_ops mx2_soc_camera_host_ops = { | 1446 | static struct soc_camera_host_ops mx2_soc_camera_host_ops = { |
@@ -1327,144 +1451,148 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = { | |||
1327 | .set_crop = mx2_camera_set_crop, | 1451 | .set_crop = mx2_camera_set_crop, |
1328 | .get_formats = mx2_camera_get_formats, | 1452 | .get_formats = mx2_camera_get_formats, |
1329 | .try_fmt = mx2_camera_try_fmt, | 1453 | .try_fmt = mx2_camera_try_fmt, |
1330 | .init_videobuf = mx2_camera_init_videobuf, | 1454 | .init_videobuf2 = mx2_camera_init_videobuf, |
1331 | .reqbufs = mx2_camera_reqbufs, | ||
1332 | .poll = mx2_camera_poll, | 1455 | .poll = mx2_camera_poll, |
1333 | .querycap = mx2_camera_querycap, | 1456 | .querycap = mx2_camera_querycap, |
1334 | .set_bus_param = mx2_camera_set_bus_param, | 1457 | .set_bus_param = mx2_camera_set_bus_param, |
1335 | }; | 1458 | }; |
1336 | 1459 | ||
1337 | static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, | 1460 | static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, |
1338 | int bufnum, int state) | 1461 | int bufnum, bool err) |
1339 | { | 1462 | { |
1340 | u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; | 1463 | #ifdef DEBUG |
1341 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | 1464 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; |
1465 | #endif | ||
1466 | struct mx2_buf_internal *ibuf; | ||
1342 | struct mx2_buffer *buf; | 1467 | struct mx2_buffer *buf; |
1343 | struct videobuf_buffer *vb; | 1468 | struct vb2_buffer *vb; |
1344 | unsigned long phys; | 1469 | unsigned long phys; |
1345 | 1470 | ||
1346 | if (!list_empty(&pcdev->active_bufs)) { | 1471 | ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal, |
1347 | buf = list_entry(pcdev->active_bufs.next, | 1472 | queue); |
1348 | struct mx2_buffer, vb.queue); | 1473 | |
1474 | BUG_ON(ibuf->bufnum != bufnum); | ||
1349 | 1475 | ||
1350 | BUG_ON(buf->bufnum != bufnum); | 1476 | if (ibuf->discard) { |
1477 | /* | ||
1478 | * Discard buffer must not be returned to user space. | ||
1479 | * Just return it to the discard queue. | ||
1480 | */ | ||
1481 | list_move_tail(pcdev->active_bufs.next, &pcdev->discard); | ||
1482 | } else { | ||
1483 | buf = mx2_ibuf_to_buf(ibuf); | ||
1351 | 1484 | ||
1352 | vb = &buf->vb; | 1485 | vb = &buf->vb; |
1353 | #ifdef DEBUG | 1486 | #ifdef DEBUG |
1354 | phys = videobuf_to_dma_contig(vb); | 1487 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); |
1355 | if (prp->cfg.channel == 1) { | 1488 | if (prp->cfg.channel == 1) { |
1356 | if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + | 1489 | if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + |
1357 | 4 * bufnum) != phys) { | 1490 | 4 * bufnum) != phys) { |
1358 | dev_err(pcdev->dev, "%p != %p\n", phys, | 1491 | dev_err(pcdev->dev, "%lx != %x\n", phys, |
1359 | readl(pcdev->base_emma + | 1492 | readl(pcdev->base_emma + |
1360 | PRP_DEST_RGB1_PTR + | 1493 | PRP_DEST_RGB1_PTR + 4 * bufnum)); |
1361 | 4 * bufnum)); | ||
1362 | } | 1494 | } |
1363 | } else { | 1495 | } else { |
1364 | if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - | 1496 | if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - |
1365 | 0x14 * bufnum) != phys) { | 1497 | 0x14 * bufnum) != phys) { |
1366 | dev_err(pcdev->dev, "%p != %p\n", phys, | 1498 | dev_err(pcdev->dev, "%lx != %x\n", phys, |
1367 | readl(pcdev->base_emma + | 1499 | readl(pcdev->base_emma + |
1368 | PRP_DEST_Y_PTR - | 1500 | PRP_DEST_Y_PTR - 0x14 * bufnum)); |
1369 | 0x14 * bufnum)); | ||
1370 | } | 1501 | } |
1371 | } | 1502 | } |
1372 | #endif | 1503 | #endif |
1373 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, | 1504 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, |
1374 | vb->baddr, vb->bsize); | 1505 | vb2_plane_vaddr(vb, 0), |
1506 | vb2_get_plane_payload(vb, 0)); | ||
1375 | 1507 | ||
1376 | list_del(&vb->queue); | 1508 | list_del_init(&buf->internal.queue); |
1377 | vb->state = state; | 1509 | do_gettimeofday(&vb->v4l2_buf.timestamp); |
1378 | do_gettimeofday(&vb->ts); | 1510 | vb->v4l2_buf.sequence = pcdev->frame_count; |
1379 | vb->field_count = pcdev->frame_count * 2; | 1511 | if (err) |
1380 | pcdev->frame_count++; | 1512 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); |
1381 | 1513 | else | |
1382 | wake_up(&vb->done); | 1514 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); |
1383 | } | 1515 | } |
1384 | 1516 | ||
1517 | pcdev->frame_count++; | ||
1518 | |||
1385 | if (list_empty(&pcdev->capture)) { | 1519 | if (list_empty(&pcdev->capture)) { |
1386 | if (prp->cfg.channel == 1) { | 1520 | if (list_empty(&pcdev->discard)) { |
1387 | writel(pcdev->discard_buffer_dma, pcdev->base_emma + | 1521 | dev_warn(pcdev->dev, "%s: trying to access empty discard list\n", |
1388 | PRP_DEST_RGB1_PTR + 4 * bufnum); | 1522 | __func__); |
1389 | } else { | 1523 | return; |
1390 | writel(pcdev->discard_buffer_dma, pcdev->base_emma + | ||
1391 | PRP_DEST_Y_PTR - | ||
1392 | 0x14 * bufnum); | ||
1393 | if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { | ||
1394 | writel(pcdev->discard_buffer_dma + imgsize, | ||
1395 | pcdev->base_emma + PRP_DEST_CB_PTR - | ||
1396 | 0x14 * bufnum); | ||
1397 | writel(pcdev->discard_buffer_dma + | ||
1398 | ((5 * imgsize) / 4), pcdev->base_emma + | ||
1399 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
1400 | } | ||
1401 | } | 1524 | } |
1525 | |||
1526 | ibuf = list_first_entry(&pcdev->discard, | ||
1527 | struct mx2_buf_internal, queue); | ||
1528 | ibuf->bufnum = bufnum; | ||
1529 | |||
1530 | list_move_tail(pcdev->discard.next, &pcdev->active_bufs); | ||
1531 | mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum); | ||
1402 | return; | 1532 | return; |
1403 | } | 1533 | } |
1404 | 1534 | ||
1405 | buf = list_entry(pcdev->capture.next, | 1535 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, |
1406 | struct mx2_buffer, vb.queue); | 1536 | internal.queue); |
1407 | 1537 | ||
1408 | buf->bufnum = !bufnum; | 1538 | buf->internal.bufnum = bufnum; |
1409 | 1539 | ||
1410 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | 1540 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); |
1411 | 1541 | ||
1412 | vb = &buf->vb; | 1542 | vb = &buf->vb; |
1413 | vb->state = VIDEOBUF_ACTIVE; | 1543 | buf->state = MX2_STATE_ACTIVE; |
1414 | 1544 | ||
1415 | phys = videobuf_to_dma_contig(vb); | 1545 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); |
1416 | if (prp->cfg.channel == 1) { | 1546 | mx27_update_emma_buf(pcdev, phys, bufnum); |
1417 | writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); | ||
1418 | } else { | ||
1419 | writel(phys, pcdev->base_emma + | ||
1420 | PRP_DEST_Y_PTR - 0x14 * bufnum); | ||
1421 | if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { | ||
1422 | writel(phys + imgsize, pcdev->base_emma + | ||
1423 | PRP_DEST_CB_PTR - 0x14 * bufnum); | ||
1424 | writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + | ||
1425 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
1426 | } | ||
1427 | } | ||
1428 | } | 1547 | } |
1429 | 1548 | ||
1430 | static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) | 1549 | static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) |
1431 | { | 1550 | { |
1432 | struct mx2_camera_dev *pcdev = data; | 1551 | struct mx2_camera_dev *pcdev = data; |
1433 | unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); | 1552 | unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); |
1434 | struct mx2_buffer *buf; | 1553 | struct mx2_buf_internal *ibuf; |
1554 | |||
1555 | spin_lock(&pcdev->lock); | ||
1556 | |||
1557 | if (list_empty(&pcdev->active_bufs)) { | ||
1558 | dev_warn(pcdev->dev, "%s: called while active list is empty\n", | ||
1559 | __func__); | ||
1560 | |||
1561 | if (!status) { | ||
1562 | spin_unlock(&pcdev->lock); | ||
1563 | return IRQ_NONE; | ||
1564 | } | ||
1565 | } | ||
1435 | 1566 | ||
1436 | if (status & (1 << 7)) { /* overflow */ | 1567 | if (status & (1 << 7)) { /* overflow */ |
1437 | u32 cntl; | 1568 | u32 cntl = readl(pcdev->base_emma + PRP_CNTL); |
1438 | /* | ||
1439 | * We only disable channel 1 here since this is the only | ||
1440 | * enabled channel | ||
1441 | * | ||
1442 | * FIXME: the correct DMA overflow handling should be resetting | ||
1443 | * the buffer, returning an error frame, and continuing with | ||
1444 | * the next one. | ||
1445 | */ | ||
1446 | cntl = readl(pcdev->base_emma + PRP_CNTL); | ||
1447 | writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), | 1569 | writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), |
1448 | pcdev->base_emma + PRP_CNTL); | 1570 | pcdev->base_emma + PRP_CNTL); |
1449 | writel(cntl, pcdev->base_emma + PRP_CNTL); | 1571 | writel(cntl, pcdev->base_emma + PRP_CNTL); |
1450 | } | 1572 | |
1451 | if ((((status & (3 << 5)) == (3 << 5)) || | 1573 | ibuf = list_first_entry(&pcdev->active_bufs, |
1452 | ((status & (3 << 3)) == (3 << 3))) | 1574 | struct mx2_buf_internal, queue); |
1453 | && !list_empty(&pcdev->active_bufs)) { | 1575 | mx27_camera_frame_done_emma(pcdev, |
1576 | ibuf->bufnum, true); | ||
1577 | |||
1578 | status &= ~(1 << 7); | ||
1579 | } else if (((status & (3 << 5)) == (3 << 5)) || | ||
1580 | ((status & (3 << 3)) == (3 << 3))) { | ||
1454 | /* | 1581 | /* |
1455 | * Both buffers have triggered, process the one we're expecting | 1582 | * Both buffers have triggered, process the one we're expecting |
1456 | * to first | 1583 | * to first |
1457 | */ | 1584 | */ |
1458 | buf = list_entry(pcdev->active_bufs.next, | 1585 | ibuf = list_first_entry(&pcdev->active_bufs, |
1459 | struct mx2_buffer, vb.queue); | 1586 | struct mx2_buf_internal, queue); |
1460 | mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); | 1587 | mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false); |
1461 | status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ | 1588 | status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */ |
1589 | } else if ((status & (1 << 6)) || (status & (1 << 4))) { | ||
1590 | mx27_camera_frame_done_emma(pcdev, 0, false); | ||
1591 | } else if ((status & (1 << 5)) || (status & (1 << 3))) { | ||
1592 | mx27_camera_frame_done_emma(pcdev, 1, false); | ||
1462 | } | 1593 | } |
1463 | if ((status & (1 << 6)) || (status & (1 << 4))) | ||
1464 | mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); | ||
1465 | if ((status & (1 << 5)) || (status & (1 << 3))) | ||
1466 | mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); | ||
1467 | 1594 | ||
1595 | spin_unlock(&pcdev->lock); | ||
1468 | writel(status, pcdev->base_emma + PRP_INTRSTATUS); | 1596 | writel(status, pcdev->base_emma + PRP_INTRSTATUS); |
1469 | 1597 | ||
1470 | return IRQ_HANDLED; | 1598 | return IRQ_HANDLED; |
@@ -1527,8 +1655,6 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1527 | struct resource *res_csi, *res_emma; | 1655 | struct resource *res_csi, *res_emma; |
1528 | void __iomem *base_csi; | 1656 | void __iomem *base_csi; |
1529 | int irq_csi, irq_emma; | 1657 | int irq_csi, irq_emma; |
1530 | irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq | ||
1531 | : mx27_camera_irq; | ||
1532 | int err = 0; | 1658 | int err = 0; |
1533 | 1659 | ||
1534 | dev_dbg(&pdev->dev, "initialising\n"); | 1660 | dev_dbg(&pdev->dev, "initialising\n"); |
@@ -1550,22 +1676,11 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1550 | 1676 | ||
1551 | pcdev->clk_csi = clk_get(&pdev->dev, NULL); | 1677 | pcdev->clk_csi = clk_get(&pdev->dev, NULL); |
1552 | if (IS_ERR(pcdev->clk_csi)) { | 1678 | if (IS_ERR(pcdev->clk_csi)) { |
1679 | dev_err(&pdev->dev, "Could not get csi clock\n"); | ||
1553 | err = PTR_ERR(pcdev->clk_csi); | 1680 | err = PTR_ERR(pcdev->clk_csi); |
1554 | goto exit_kfree; | 1681 | goto exit_kfree; |
1555 | } | 1682 | } |
1556 | 1683 | ||
1557 | dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n", | ||
1558 | clk_get_rate(pcdev->clk_csi)); | ||
1559 | |||
1560 | /* Initialize DMA */ | ||
1561 | #ifdef CONFIG_MACH_MX27 | ||
1562 | if (cpu_is_mx27()) { | ||
1563 | err = mx27_camera_dma_init(pdev, pcdev); | ||
1564 | if (err) | ||
1565 | goto exit_clk_put; | ||
1566 | } | ||
1567 | #endif /* CONFIG_MACH_MX27 */ | ||
1568 | |||
1569 | pcdev->res_csi = res_csi; | 1684 | pcdev->res_csi = res_csi; |
1570 | pcdev->pdata = pdev->dev.platform_data; | 1685 | pcdev->pdata = pdev->dev.platform_data; |
1571 | if (pcdev->pdata) { | 1686 | if (pcdev->pdata) { |
@@ -1585,6 +1700,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1585 | 1700 | ||
1586 | INIT_LIST_HEAD(&pcdev->capture); | 1701 | INIT_LIST_HEAD(&pcdev->capture); |
1587 | INIT_LIST_HEAD(&pcdev->active_bufs); | 1702 | INIT_LIST_HEAD(&pcdev->active_bufs); |
1703 | INIT_LIST_HEAD(&pcdev->discard); | ||
1588 | spin_lock_init(&pcdev->lock); | 1704 | spin_lock_init(&pcdev->lock); |
1589 | 1705 | ||
1590 | /* | 1706 | /* |
@@ -1606,11 +1722,13 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1606 | pcdev->base_dma = res_csi->start; | 1722 | pcdev->base_dma = res_csi->start; |
1607 | pcdev->dev = &pdev->dev; | 1723 | pcdev->dev = &pdev->dev; |
1608 | 1724 | ||
1609 | err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0, | 1725 | if (cpu_is_mx25()) { |
1610 | MX2_CAM_DRV_NAME, pcdev); | 1726 | err = request_irq(pcdev->irq_csi, mx25_camera_irq, 0, |
1611 | if (err) { | 1727 | MX2_CAM_DRV_NAME, pcdev); |
1612 | dev_err(pcdev->dev, "Camera interrupt register failed \n"); | 1728 | if (err) { |
1613 | goto exit_iounmap; | 1729 | dev_err(pcdev->dev, "Camera interrupt register failed \n"); |
1730 | goto exit_iounmap; | ||
1731 | } | ||
1614 | } | 1732 | } |
1615 | 1733 | ||
1616 | if (cpu_is_mx27()) { | 1734 | if (cpu_is_mx27()) { |
@@ -1618,14 +1736,15 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1618 | res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 1736 | res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
1619 | irq_emma = platform_get_irq(pdev, 1); | 1737 | irq_emma = platform_get_irq(pdev, 1); |
1620 | 1738 | ||
1621 | if (res_emma && irq_emma >= 0) { | 1739 | if (!res_emma || !irq_emma) { |
1622 | dev_info(&pdev->dev, "Using EMMA\n"); | 1740 | dev_err(&pdev->dev, "no EMMA resources\n"); |
1623 | pcdev->use_emma = 1; | 1741 | goto exit_free_irq; |
1624 | pcdev->res_emma = res_emma; | ||
1625 | pcdev->irq_emma = irq_emma; | ||
1626 | if (mx27_camera_emma_init(pcdev)) | ||
1627 | goto exit_free_irq; | ||
1628 | } | 1742 | } |
1743 | |||
1744 | pcdev->res_emma = res_emma; | ||
1745 | pcdev->irq_emma = irq_emma; | ||
1746 | if (mx27_camera_emma_init(pcdev)) | ||
1747 | goto exit_free_irq; | ||
1629 | } | 1748 | } |
1630 | 1749 | ||
1631 | pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, | 1750 | pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, |
@@ -1633,6 +1752,12 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1633 | pcdev->soc_host.priv = pcdev; | 1752 | pcdev->soc_host.priv = pcdev; |
1634 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | 1753 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; |
1635 | pcdev->soc_host.nr = pdev->id; | 1754 | pcdev->soc_host.nr = pdev->id; |
1755 | |||
1756 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
1757 | if (IS_ERR(pcdev->alloc_ctx)) { | ||
1758 | err = PTR_ERR(pcdev->alloc_ctx); | ||
1759 | goto eallocctx; | ||
1760 | } | ||
1636 | err = soc_camera_host_register(&pcdev->soc_host); | 1761 | err = soc_camera_host_register(&pcdev->soc_host); |
1637 | if (err) | 1762 | if (err) |
1638 | goto exit_free_emma; | 1763 | goto exit_free_emma; |
@@ -1643,26 +1768,24 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1643 | return 0; | 1768 | return 0; |
1644 | 1769 | ||
1645 | exit_free_emma: | 1770 | exit_free_emma: |
1646 | if (mx27_camera_emma(pcdev)) { | 1771 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); |
1772 | eallocctx: | ||
1773 | if (cpu_is_mx27()) { | ||
1647 | free_irq(pcdev->irq_emma, pcdev); | 1774 | free_irq(pcdev->irq_emma, pcdev); |
1648 | clk_disable(pcdev->clk_emma); | 1775 | clk_disable(pcdev->clk_emma); |
1649 | clk_put(pcdev->clk_emma); | 1776 | clk_put(pcdev->clk_emma); |
1650 | iounmap(pcdev->base_emma); | 1777 | iounmap(pcdev->base_emma); |
1651 | release_mem_region(res_emma->start, resource_size(res_emma)); | 1778 | release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma)); |
1652 | } | 1779 | } |
1653 | exit_free_irq: | 1780 | exit_free_irq: |
1654 | free_irq(pcdev->irq_csi, pcdev); | 1781 | if (cpu_is_mx25()) |
1782 | free_irq(pcdev->irq_csi, pcdev); | ||
1655 | exit_iounmap: | 1783 | exit_iounmap: |
1656 | iounmap(base_csi); | 1784 | iounmap(base_csi); |
1657 | exit_release: | 1785 | exit_release: |
1658 | release_mem_region(res_csi->start, resource_size(res_csi)); | 1786 | release_mem_region(res_csi->start, resource_size(res_csi)); |
1659 | exit_dma_free: | 1787 | exit_dma_free: |
1660 | #ifdef CONFIG_MACH_MX27 | ||
1661 | if (cpu_is_mx27()) | ||
1662 | imx_dma_free(pcdev->dma); | ||
1663 | exit_clk_put: | ||
1664 | clk_put(pcdev->clk_csi); | 1788 | clk_put(pcdev->clk_csi); |
1665 | #endif /* CONFIG_MACH_MX27 */ | ||
1666 | exit_kfree: | 1789 | exit_kfree: |
1667 | kfree(pcdev); | 1790 | kfree(pcdev); |
1668 | exit: | 1791 | exit: |
@@ -1677,19 +1800,18 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev) | |||
1677 | struct resource *res; | 1800 | struct resource *res; |
1678 | 1801 | ||
1679 | clk_put(pcdev->clk_csi); | 1802 | clk_put(pcdev->clk_csi); |
1680 | #ifdef CONFIG_MACH_MX27 | 1803 | if (cpu_is_mx25()) |
1804 | free_irq(pcdev->irq_csi, pcdev); | ||
1681 | if (cpu_is_mx27()) | 1805 | if (cpu_is_mx27()) |
1682 | imx_dma_free(pcdev->dma); | ||
1683 | #endif /* CONFIG_MACH_MX27 */ | ||
1684 | free_irq(pcdev->irq_csi, pcdev); | ||
1685 | if (mx27_camera_emma(pcdev)) | ||
1686 | free_irq(pcdev->irq_emma, pcdev); | 1806 | free_irq(pcdev->irq_emma, pcdev); |
1687 | 1807 | ||
1688 | soc_camera_host_unregister(&pcdev->soc_host); | 1808 | soc_camera_host_unregister(&pcdev->soc_host); |
1689 | 1809 | ||
1810 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
1811 | |||
1690 | iounmap(pcdev->base_csi); | 1812 | iounmap(pcdev->base_csi); |
1691 | 1813 | ||
1692 | if (mx27_camera_emma(pcdev)) { | 1814 | if (cpu_is_mx27()) { |
1693 | clk_disable(pcdev->clk_emma); | 1815 | clk_disable(pcdev->clk_emma); |
1694 | clk_put(pcdev->clk_emma); | 1816 | clk_put(pcdev->clk_emma); |
1695 | iounmap(pcdev->base_emma); | 1817 | iounmap(pcdev->base_emma); |
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c new file mode 100644 index 000000000000..ba89a7401c8c --- /dev/null +++ b/drivers/media/video/mx2_emmaprp.c | |||
@@ -0,0 +1,1008 @@ | |||
1 | /* | ||
2 | * Support eMMa-PrP through mem2mem framework. | ||
3 | * | ||
4 | * eMMa-PrP is a piece of HW that allows fetching buffers | ||
5 | * from one memory location and do several operations on | ||
6 | * them such as scaling or format conversion giving, as a result | ||
7 | * a new processed buffer in another memory location. | ||
8 | * | ||
9 | * Based on mem2mem_testdev.c by Pawel Osciak. | ||
10 | * | ||
11 | * Copyright (c) 2011 Vista Silicon S.L. | ||
12 | * Javier Martin <javier.martin@vista-silicon.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by the | ||
16 | * Free Software Foundation; either version 2 of the | ||
17 | * License, or (at your option) any later version | ||
18 | */ | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/io.h> | ||
24 | |||
25 | #include <linux/platform_device.h> | ||
26 | #include <media/v4l2-mem2mem.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-ioctl.h> | ||
29 | #include <media/videobuf2-dma-contig.h> | ||
30 | #include <asm/sizes.h> | ||
31 | |||
32 | #define EMMAPRP_MODULE_NAME "mem2mem-emmaprp" | ||
33 | |||
34 | MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs"); | ||
35 | MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | MODULE_VERSION("0.0.1"); | ||
38 | |||
39 | static bool debug; | ||
40 | module_param(debug, bool, 0644); | ||
41 | |||
42 | #define MIN_W 32 | ||
43 | #define MIN_H 32 | ||
44 | #define MAX_W 2040 | ||
45 | #define MAX_H 2046 | ||
46 | |||
47 | #define S_ALIGN 1 /* multiple of 2 */ | ||
48 | #define W_ALIGN_YUV420 3 /* multiple of 8 */ | ||
49 | #define W_ALIGN_OTHERS 2 /* multiple of 4 */ | ||
50 | #define H_ALIGN 1 /* multiple of 2 */ | ||
51 | |||
52 | /* Flags that indicate a format can be used for capture/output */ | ||
53 | #define MEM2MEM_CAPTURE (1 << 0) | ||
54 | #define MEM2MEM_OUTPUT (1 << 1) | ||
55 | |||
56 | #define MEM2MEM_NAME "m2m-emmaprp" | ||
57 | |||
58 | /* In bytes, per queue */ | ||
59 | #define MEM2MEM_VID_MEM_LIMIT SZ_16M | ||
60 | |||
61 | #define dprintk(dev, fmt, arg...) \ | ||
62 | v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) | ||
63 | |||
64 | /* EMMA PrP */ | ||
65 | #define PRP_CNTL 0x00 | ||
66 | #define PRP_INTR_CNTL 0x04 | ||
67 | #define PRP_INTRSTATUS 0x08 | ||
68 | #define PRP_SOURCE_Y_PTR 0x0c | ||
69 | #define PRP_SOURCE_CB_PTR 0x10 | ||
70 | #define PRP_SOURCE_CR_PTR 0x14 | ||
71 | #define PRP_DEST_RGB1_PTR 0x18 | ||
72 | #define PRP_DEST_RGB2_PTR 0x1c | ||
73 | #define PRP_DEST_Y_PTR 0x20 | ||
74 | #define PRP_DEST_CB_PTR 0x24 | ||
75 | #define PRP_DEST_CR_PTR 0x28 | ||
76 | #define PRP_SRC_FRAME_SIZE 0x2c | ||
77 | #define PRP_DEST_CH1_LINE_STRIDE 0x30 | ||
78 | #define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 | ||
79 | #define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 | ||
80 | #define PRP_CH1_OUT_IMAGE_SIZE 0x3c | ||
81 | #define PRP_CH2_OUT_IMAGE_SIZE 0x40 | ||
82 | #define PRP_SRC_LINE_STRIDE 0x44 | ||
83 | #define PRP_CSC_COEF_012 0x48 | ||
84 | #define PRP_CSC_COEF_345 0x4c | ||
85 | #define PRP_CSC_COEF_678 0x50 | ||
86 | #define PRP_CH1_RZ_HORI_COEF1 0x54 | ||
87 | #define PRP_CH1_RZ_HORI_COEF2 0x58 | ||
88 | #define PRP_CH1_RZ_HORI_VALID 0x5c | ||
89 | #define PRP_CH1_RZ_VERT_COEF1 0x60 | ||
90 | #define PRP_CH1_RZ_VERT_COEF2 0x64 | ||
91 | #define PRP_CH1_RZ_VERT_VALID 0x68 | ||
92 | #define PRP_CH2_RZ_HORI_COEF1 0x6c | ||
93 | #define PRP_CH2_RZ_HORI_COEF2 0x70 | ||
94 | #define PRP_CH2_RZ_HORI_VALID 0x74 | ||
95 | #define PRP_CH2_RZ_VERT_COEF1 0x78 | ||
96 | #define PRP_CH2_RZ_VERT_COEF2 0x7c | ||
97 | #define PRP_CH2_RZ_VERT_VALID 0x80 | ||
98 | |||
99 | #define PRP_CNTL_CH1EN (1 << 0) | ||
100 | #define PRP_CNTL_CH2EN (1 << 1) | ||
101 | #define PRP_CNTL_CSIEN (1 << 2) | ||
102 | #define PRP_CNTL_DATA_IN_YUV420 (0 << 3) | ||
103 | #define PRP_CNTL_DATA_IN_YUV422 (1 << 3) | ||
104 | #define PRP_CNTL_DATA_IN_RGB16 (2 << 3) | ||
105 | #define PRP_CNTL_DATA_IN_RGB32 (3 << 3) | ||
106 | #define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) | ||
107 | #define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) | ||
108 | #define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) | ||
109 | #define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) | ||
110 | #define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) | ||
111 | #define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) | ||
112 | #define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) | ||
113 | #define PRP_CNTL_CH1_LEN (1 << 9) | ||
114 | #define PRP_CNTL_CH2_LEN (1 << 10) | ||
115 | #define PRP_CNTL_SKIP_FRAME (1 << 11) | ||
116 | #define PRP_CNTL_SWRST (1 << 12) | ||
117 | #define PRP_CNTL_CLKEN (1 << 13) | ||
118 | #define PRP_CNTL_WEN (1 << 14) | ||
119 | #define PRP_CNTL_CH1BYP (1 << 15) | ||
120 | #define PRP_CNTL_IN_TSKIP(x) ((x) << 16) | ||
121 | #define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) | ||
122 | #define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) | ||
123 | #define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) | ||
124 | #define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) | ||
125 | #define PRP_CNTL_CH2B1EN (1 << 29) | ||
126 | #define PRP_CNTL_CH2B2EN (1 << 30) | ||
127 | #define PRP_CNTL_CH2FEN (1 << 31) | ||
128 | |||
129 | #define PRP_SIZE_HEIGHT(x) (x) | ||
130 | #define PRP_SIZE_WIDTH(x) ((x) << 16) | ||
131 | |||
132 | /* IRQ Enable and status register */ | ||
133 | #define PRP_INTR_RDERR (1 << 0) | ||
134 | #define PRP_INTR_CH1WERR (1 << 1) | ||
135 | #define PRP_INTR_CH2WERR (1 << 2) | ||
136 | #define PRP_INTR_CH1FC (1 << 3) | ||
137 | #define PRP_INTR_CH2FC (1 << 5) | ||
138 | #define PRP_INTR_LBOVF (1 << 7) | ||
139 | #define PRP_INTR_CH2OVF (1 << 8) | ||
140 | |||
141 | #define PRP_INTR_ST_RDERR (1 << 0) | ||
142 | #define PRP_INTR_ST_CH1WERR (1 << 1) | ||
143 | #define PRP_INTR_ST_CH2WERR (1 << 2) | ||
144 | #define PRP_INTR_ST_CH2B2CI (1 << 3) | ||
145 | #define PRP_INTR_ST_CH2B1CI (1 << 4) | ||
146 | #define PRP_INTR_ST_CH1B2CI (1 << 5) | ||
147 | #define PRP_INTR_ST_CH1B1CI (1 << 6) | ||
148 | #define PRP_INTR_ST_LBOVF (1 << 7) | ||
149 | #define PRP_INTR_ST_CH2OVF (1 << 8) | ||
150 | |||
151 | struct emmaprp_fmt { | ||
152 | char *name; | ||
153 | u32 fourcc; | ||
154 | /* Types the format can be used for */ | ||
155 | u32 types; | ||
156 | }; | ||
157 | |||
158 | static struct emmaprp_fmt formats[] = { | ||
159 | { | ||
160 | .name = "YUV 4:2:0 Planar", | ||
161 | .fourcc = V4L2_PIX_FMT_YUV420, | ||
162 | .types = MEM2MEM_CAPTURE, | ||
163 | }, | ||
164 | { | ||
165 | .name = "4:2:2, packed, YUYV", | ||
166 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
167 | .types = MEM2MEM_OUTPUT, | ||
168 | }, | ||
169 | }; | ||
170 | |||
171 | /* Per-queue, driver-specific private data */ | ||
172 | struct emmaprp_q_data { | ||
173 | unsigned int width; | ||
174 | unsigned int height; | ||
175 | unsigned int sizeimage; | ||
176 | struct emmaprp_fmt *fmt; | ||
177 | }; | ||
178 | |||
179 | enum { | ||
180 | V4L2_M2M_SRC = 0, | ||
181 | V4L2_M2M_DST = 1, | ||
182 | }; | ||
183 | |||
184 | #define NUM_FORMATS ARRAY_SIZE(formats) | ||
185 | |||
186 | static struct emmaprp_fmt *find_format(struct v4l2_format *f) | ||
187 | { | ||
188 | struct emmaprp_fmt *fmt; | ||
189 | unsigned int k; | ||
190 | |||
191 | for (k = 0; k < NUM_FORMATS; k++) { | ||
192 | fmt = &formats[k]; | ||
193 | if (fmt->fourcc == f->fmt.pix.pixelformat) | ||
194 | break; | ||
195 | } | ||
196 | |||
197 | if (k == NUM_FORMATS) | ||
198 | return NULL; | ||
199 | |||
200 | return &formats[k]; | ||
201 | } | ||
202 | |||
203 | struct emmaprp_dev { | ||
204 | struct v4l2_device v4l2_dev; | ||
205 | struct video_device *vfd; | ||
206 | |||
207 | struct mutex dev_mutex; | ||
208 | spinlock_t irqlock; | ||
209 | |||
210 | int irq_emma; | ||
211 | void __iomem *base_emma; | ||
212 | struct clk *clk_emma; | ||
213 | struct resource *res_emma; | ||
214 | |||
215 | struct v4l2_m2m_dev *m2m_dev; | ||
216 | struct vb2_alloc_ctx *alloc_ctx; | ||
217 | }; | ||
218 | |||
219 | struct emmaprp_ctx { | ||
220 | struct emmaprp_dev *dev; | ||
221 | /* Abort requested by m2m */ | ||
222 | int aborting; | ||
223 | struct emmaprp_q_data q_data[2]; | ||
224 | struct v4l2_m2m_ctx *m2m_ctx; | ||
225 | }; | ||
226 | |||
227 | static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, | ||
228 | enum v4l2_buf_type type) | ||
229 | { | ||
230 | switch (type) { | ||
231 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
232 | return &(ctx->q_data[V4L2_M2M_SRC]); | ||
233 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
234 | return &(ctx->q_data[V4L2_M2M_DST]); | ||
235 | default: | ||
236 | BUG(); | ||
237 | } | ||
238 | return NULL; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * mem2mem callbacks | ||
243 | */ | ||
244 | static void emmaprp_job_abort(void *priv) | ||
245 | { | ||
246 | struct emmaprp_ctx *ctx = priv; | ||
247 | struct emmaprp_dev *pcdev = ctx->dev; | ||
248 | |||
249 | ctx->aborting = 1; | ||
250 | |||
251 | dprintk(pcdev, "Aborting task\n"); | ||
252 | |||
253 | v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); | ||
254 | } | ||
255 | |||
256 | static void emmaprp_lock(void *priv) | ||
257 | { | ||
258 | struct emmaprp_ctx *ctx = priv; | ||
259 | struct emmaprp_dev *pcdev = ctx->dev; | ||
260 | mutex_lock(&pcdev->dev_mutex); | ||
261 | } | ||
262 | |||
263 | static void emmaprp_unlock(void *priv) | ||
264 | { | ||
265 | struct emmaprp_ctx *ctx = priv; | ||
266 | struct emmaprp_dev *pcdev = ctx->dev; | ||
267 | mutex_unlock(&pcdev->dev_mutex); | ||
268 | } | ||
269 | |||
270 | static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev) | ||
271 | { | ||
272 | dprintk(pcdev, | ||
273 | "eMMa-PrP Registers:\n" | ||
274 | " SOURCE_Y_PTR = 0x%08X\n" | ||
275 | " SRC_FRAME_SIZE = 0x%08X\n" | ||
276 | " DEST_Y_PTR = 0x%08X\n" | ||
277 | " DEST_CR_PTR = 0x%08X\n" | ||
278 | " DEST_CB_PTR = 0x%08X\n" | ||
279 | " CH2_OUT_IMAGE_SIZE = 0x%08X\n" | ||
280 | " CNTL = 0x%08X\n", | ||
281 | readl(pcdev->base_emma + PRP_SOURCE_Y_PTR), | ||
282 | readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE), | ||
283 | readl(pcdev->base_emma + PRP_DEST_Y_PTR), | ||
284 | readl(pcdev->base_emma + PRP_DEST_CR_PTR), | ||
285 | readl(pcdev->base_emma + PRP_DEST_CB_PTR), | ||
286 | readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE), | ||
287 | readl(pcdev->base_emma + PRP_CNTL)); | ||
288 | } | ||
289 | |||
290 | static void emmaprp_device_run(void *priv) | ||
291 | { | ||
292 | struct emmaprp_ctx *ctx = priv; | ||
293 | struct emmaprp_q_data *s_q_data, *d_q_data; | ||
294 | struct vb2_buffer *src_buf, *dst_buf; | ||
295 | struct emmaprp_dev *pcdev = ctx->dev; | ||
296 | unsigned int s_width, s_height; | ||
297 | unsigned int d_width, d_height; | ||
298 | unsigned int d_size; | ||
299 | dma_addr_t p_in, p_out; | ||
300 | u32 tmp; | ||
301 | |||
302 | src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); | ||
303 | dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); | ||
304 | |||
305 | s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
306 | s_width = s_q_data->width; | ||
307 | s_height = s_q_data->height; | ||
308 | |||
309 | d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | ||
310 | d_width = d_q_data->width; | ||
311 | d_height = d_q_data->height; | ||
312 | d_size = d_width * d_height; | ||
313 | |||
314 | p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0); | ||
315 | p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0); | ||
316 | if (!p_in || !p_out) { | ||
317 | v4l2_err(&pcdev->v4l2_dev, | ||
318 | "Acquiring kernel pointers to buffers failed\n"); | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | /* Input frame parameters */ | ||
323 | writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR); | ||
324 | writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height), | ||
325 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | ||
326 | |||
327 | /* Output frame parameters */ | ||
328 | writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR); | ||
329 | writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR); | ||
330 | writel(p_out + d_size + (d_size >> 2), | ||
331 | pcdev->base_emma + PRP_DEST_CR_PTR); | ||
332 | writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height), | ||
333 | pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); | ||
334 | |||
335 | /* IRQ configuration */ | ||
336 | tmp = readl(pcdev->base_emma + PRP_INTR_CNTL); | ||
337 | writel(tmp | PRP_INTR_RDERR | | ||
338 | PRP_INTR_CH2WERR | | ||
339 | PRP_INTR_CH2FC, | ||
340 | pcdev->base_emma + PRP_INTR_CNTL); | ||
341 | |||
342 | emmaprp_dump_regs(pcdev); | ||
343 | |||
344 | /* Enable transfer */ | ||
345 | tmp = readl(pcdev->base_emma + PRP_CNTL); | ||
346 | writel(tmp | PRP_CNTL_CH2_OUT_YUV420 | | ||
347 | PRP_CNTL_DATA_IN_YUV422 | | ||
348 | PRP_CNTL_CH2EN, | ||
349 | pcdev->base_emma + PRP_CNTL); | ||
350 | } | ||
351 | |||
352 | static irqreturn_t emmaprp_irq(int irq_emma, void *data) | ||
353 | { | ||
354 | struct emmaprp_dev *pcdev = data; | ||
355 | struct emmaprp_ctx *curr_ctx; | ||
356 | struct vb2_buffer *src_vb, *dst_vb; | ||
357 | unsigned long flags; | ||
358 | u32 irqst; | ||
359 | |||
360 | /* Check irq flags and clear irq */ | ||
361 | irqst = readl(pcdev->base_emma + PRP_INTRSTATUS); | ||
362 | writel(irqst, pcdev->base_emma + PRP_INTRSTATUS); | ||
363 | dprintk(pcdev, "irqst = 0x%08x\n", irqst); | ||
364 | |||
365 | curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev); | ||
366 | if (curr_ctx == NULL) { | ||
367 | pr_err("Instance released before the end of transaction\n"); | ||
368 | return IRQ_HANDLED; | ||
369 | } | ||
370 | |||
371 | if (!curr_ctx->aborting) { | ||
372 | if ((irqst & PRP_INTR_ST_RDERR) || | ||
373 | (irqst & PRP_INTR_ST_CH2WERR)) { | ||
374 | pr_err("PrP bus error ocurred, this transfer is probably corrupted\n"); | ||
375 | writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); | ||
376 | } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */ | ||
377 | src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); | ||
378 | dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); | ||
379 | |||
380 | spin_lock_irqsave(&pcdev->irqlock, flags); | ||
381 | v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); | ||
382 | v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); | ||
383 | spin_unlock_irqrestore(&pcdev->irqlock, flags); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); | ||
388 | return IRQ_HANDLED; | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * video ioctls | ||
393 | */ | ||
394 | static int vidioc_querycap(struct file *file, void *priv, | ||
395 | struct v4l2_capability *cap) | ||
396 | { | ||
397 | strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); | ||
398 | strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); | ||
399 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | ||
400 | | V4L2_CAP_STREAMING; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) | ||
406 | { | ||
407 | int i, num; | ||
408 | struct emmaprp_fmt *fmt; | ||
409 | |||
410 | num = 0; | ||
411 | |||
412 | for (i = 0; i < NUM_FORMATS; ++i) { | ||
413 | if (formats[i].types & type) { | ||
414 | /* index-th format of type type found ? */ | ||
415 | if (num == f->index) | ||
416 | break; | ||
417 | /* Correct type but haven't reached our index yet, | ||
418 | * just increment per-type index */ | ||
419 | ++num; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | if (i < NUM_FORMATS) { | ||
424 | /* Format found */ | ||
425 | fmt = &formats[i]; | ||
426 | strlcpy(f->description, fmt->name, sizeof(f->description) - 1); | ||
427 | f->pixelformat = fmt->fourcc; | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | /* Format not found */ | ||
432 | return -EINVAL; | ||
433 | } | ||
434 | |||
435 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
436 | struct v4l2_fmtdesc *f) | ||
437 | { | ||
438 | return enum_fmt(f, MEM2MEM_CAPTURE); | ||
439 | } | ||
440 | |||
441 | static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, | ||
442 | struct v4l2_fmtdesc *f) | ||
443 | { | ||
444 | return enum_fmt(f, MEM2MEM_OUTPUT); | ||
445 | } | ||
446 | |||
447 | static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) | ||
448 | { | ||
449 | struct vb2_queue *vq; | ||
450 | struct emmaprp_q_data *q_data; | ||
451 | |||
452 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | ||
453 | if (!vq) | ||
454 | return -EINVAL; | ||
455 | |||
456 | q_data = get_q_data(ctx, f->type); | ||
457 | |||
458 | f->fmt.pix.width = q_data->width; | ||
459 | f->fmt.pix.height = q_data->height; | ||
460 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
461 | f->fmt.pix.pixelformat = q_data->fmt->fourcc; | ||
462 | if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) | ||
463 | f->fmt.pix.bytesperline = q_data->width * 3 / 2; | ||
464 | else /* YUYV */ | ||
465 | f->fmt.pix.bytesperline = q_data->width * 2; | ||
466 | f->fmt.pix.sizeimage = q_data->sizeimage; | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int vidioc_g_fmt_vid_out(struct file *file, void *priv, | ||
472 | struct v4l2_format *f) | ||
473 | { | ||
474 | return vidioc_g_fmt(priv, f); | ||
475 | } | ||
476 | |||
477 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
478 | struct v4l2_format *f) | ||
479 | { | ||
480 | return vidioc_g_fmt(priv, f); | ||
481 | } | ||
482 | |||
483 | static int vidioc_try_fmt(struct v4l2_format *f) | ||
484 | { | ||
485 | enum v4l2_field field; | ||
486 | |||
487 | |||
488 | if (!find_format(f)) | ||
489 | return -EINVAL; | ||
490 | |||
491 | field = f->fmt.pix.field; | ||
492 | if (field == V4L2_FIELD_ANY) | ||
493 | field = V4L2_FIELD_NONE; | ||
494 | else if (V4L2_FIELD_NONE != field) | ||
495 | return -EINVAL; | ||
496 | |||
497 | /* V4L2 specification suggests the driver corrects the format struct | ||
498 | * if any of the dimensions is unsupported */ | ||
499 | f->fmt.pix.field = field; | ||
500 | |||
501 | if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) { | ||
502 | v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, | ||
503 | W_ALIGN_YUV420, &f->fmt.pix.height, | ||
504 | MIN_H, MAX_H, H_ALIGN, S_ALIGN); | ||
505 | f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2; | ||
506 | } else { | ||
507 | v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, | ||
508 | W_ALIGN_OTHERS, &f->fmt.pix.height, | ||
509 | MIN_H, MAX_H, H_ALIGN, S_ALIGN); | ||
510 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; | ||
511 | } | ||
512 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
518 | struct v4l2_format *f) | ||
519 | { | ||
520 | struct emmaprp_fmt *fmt; | ||
521 | struct emmaprp_ctx *ctx = priv; | ||
522 | |||
523 | fmt = find_format(f); | ||
524 | if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { | ||
525 | v4l2_err(&ctx->dev->v4l2_dev, | ||
526 | "Fourcc format (0x%08x) invalid.\n", | ||
527 | f->fmt.pix.pixelformat); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | |||
531 | return vidioc_try_fmt(f); | ||
532 | } | ||
533 | |||
534 | static int vidioc_try_fmt_vid_out(struct file *file, void *priv, | ||
535 | struct v4l2_format *f) | ||
536 | { | ||
537 | struct emmaprp_fmt *fmt; | ||
538 | struct emmaprp_ctx *ctx = priv; | ||
539 | |||
540 | fmt = find_format(f); | ||
541 | if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { | ||
542 | v4l2_err(&ctx->dev->v4l2_dev, | ||
543 | "Fourcc format (0x%08x) invalid.\n", | ||
544 | f->fmt.pix.pixelformat); | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | |||
548 | return vidioc_try_fmt(f); | ||
549 | } | ||
550 | |||
551 | static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) | ||
552 | { | ||
553 | struct emmaprp_q_data *q_data; | ||
554 | struct vb2_queue *vq; | ||
555 | int ret; | ||
556 | |||
557 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | ||
558 | if (!vq) | ||
559 | return -EINVAL; | ||
560 | |||
561 | q_data = get_q_data(ctx, f->type); | ||
562 | if (!q_data) | ||
563 | return -EINVAL; | ||
564 | |||
565 | if (vb2_is_busy(vq)) { | ||
566 | v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); | ||
567 | return -EBUSY; | ||
568 | } | ||
569 | |||
570 | ret = vidioc_try_fmt(f); | ||
571 | if (ret) | ||
572 | return ret; | ||
573 | |||
574 | q_data->fmt = find_format(f); | ||
575 | q_data->width = f->fmt.pix.width; | ||
576 | q_data->height = f->fmt.pix.height; | ||
577 | if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) | ||
578 | q_data->sizeimage = q_data->width * q_data->height * 3 / 2; | ||
579 | else /* YUYV */ | ||
580 | q_data->sizeimage = q_data->width * q_data->height * 2; | ||
581 | |||
582 | dprintk(ctx->dev, | ||
583 | "Setting format for type %d, wxh: %dx%d, fmt: %d\n", | ||
584 | f->type, q_data->width, q_data->height, q_data->fmt->fourcc); | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
590 | struct v4l2_format *f) | ||
591 | { | ||
592 | int ret; | ||
593 | |||
594 | ret = vidioc_try_fmt_vid_cap(file, priv, f); | ||
595 | if (ret) | ||
596 | return ret; | ||
597 | |||
598 | return vidioc_s_fmt(priv, f); | ||
599 | } | ||
600 | |||
601 | static int vidioc_s_fmt_vid_out(struct file *file, void *priv, | ||
602 | struct v4l2_format *f) | ||
603 | { | ||
604 | int ret; | ||
605 | |||
606 | ret = vidioc_try_fmt_vid_out(file, priv, f); | ||
607 | if (ret) | ||
608 | return ret; | ||
609 | |||
610 | return vidioc_s_fmt(priv, f); | ||
611 | } | ||
612 | |||
613 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
614 | struct v4l2_requestbuffers *reqbufs) | ||
615 | { | ||
616 | struct emmaprp_ctx *ctx = priv; | ||
617 | |||
618 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | ||
619 | } | ||
620 | |||
621 | static int vidioc_querybuf(struct file *file, void *priv, | ||
622 | struct v4l2_buffer *buf) | ||
623 | { | ||
624 | struct emmaprp_ctx *ctx = priv; | ||
625 | |||
626 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); | ||
627 | } | ||
628 | |||
629 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
630 | { | ||
631 | struct emmaprp_ctx *ctx = priv; | ||
632 | |||
633 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | ||
634 | } | ||
635 | |||
636 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
637 | { | ||
638 | struct emmaprp_ctx *ctx = priv; | ||
639 | |||
640 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | ||
641 | } | ||
642 | |||
643 | static int vidioc_streamon(struct file *file, void *priv, | ||
644 | enum v4l2_buf_type type) | ||
645 | { | ||
646 | struct emmaprp_ctx *ctx = priv; | ||
647 | |||
648 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); | ||
649 | } | ||
650 | |||
651 | static int vidioc_streamoff(struct file *file, void *priv, | ||
652 | enum v4l2_buf_type type) | ||
653 | { | ||
654 | struct emmaprp_ctx *ctx = priv; | ||
655 | |||
656 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | ||
657 | } | ||
658 | |||
659 | static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { | ||
660 | .vidioc_querycap = vidioc_querycap, | ||
661 | |||
662 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
663 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
664 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
665 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
666 | |||
667 | .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, | ||
668 | .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, | ||
669 | .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, | ||
670 | .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, | ||
671 | |||
672 | .vidioc_reqbufs = vidioc_reqbufs, | ||
673 | .vidioc_querybuf = vidioc_querybuf, | ||
674 | |||
675 | .vidioc_qbuf = vidioc_qbuf, | ||
676 | .vidioc_dqbuf = vidioc_dqbuf, | ||
677 | |||
678 | .vidioc_streamon = vidioc_streamon, | ||
679 | .vidioc_streamoff = vidioc_streamoff, | ||
680 | }; | ||
681 | |||
682 | |||
683 | /* | ||
684 | * Queue operations | ||
685 | */ | ||
686 | static int emmaprp_queue_setup(struct vb2_queue *vq, | ||
687 | const struct v4l2_format *fmt, | ||
688 | unsigned int *nbuffers, unsigned int *nplanes, | ||
689 | unsigned int sizes[], void *alloc_ctxs[]) | ||
690 | { | ||
691 | struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq); | ||
692 | struct emmaprp_q_data *q_data; | ||
693 | unsigned int size, count = *nbuffers; | ||
694 | |||
695 | q_data = get_q_data(ctx, vq->type); | ||
696 | |||
697 | if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) | ||
698 | size = q_data->width * q_data->height * 3 / 2; | ||
699 | else | ||
700 | size = q_data->width * q_data->height * 2; | ||
701 | |||
702 | while (size * count > MEM2MEM_VID_MEM_LIMIT) | ||
703 | (count)--; | ||
704 | |||
705 | *nplanes = 1; | ||
706 | *nbuffers = count; | ||
707 | sizes[0] = size; | ||
708 | |||
709 | alloc_ctxs[0] = ctx->dev->alloc_ctx; | ||
710 | |||
711 | dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int emmaprp_buf_prepare(struct vb2_buffer *vb) | ||
717 | { | ||
718 | struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
719 | struct emmaprp_q_data *q_data; | ||
720 | |||
721 | dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); | ||
722 | |||
723 | q_data = get_q_data(ctx, vb->vb2_queue->type); | ||
724 | |||
725 | if (vb2_plane_size(vb, 0) < q_data->sizeimage) { | ||
726 | dprintk(ctx->dev, "%s data will not fit into plane" | ||
727 | "(%lu < %lu)\n", __func__, | ||
728 | vb2_plane_size(vb, 0), | ||
729 | (long)q_data->sizeimage); | ||
730 | return -EINVAL; | ||
731 | } | ||
732 | |||
733 | vb2_set_plane_payload(vb, 0, q_data->sizeimage); | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static void emmaprp_buf_queue(struct vb2_buffer *vb) | ||
739 | { | ||
740 | struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
741 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); | ||
742 | } | ||
743 | |||
744 | static struct vb2_ops emmaprp_qops = { | ||
745 | .queue_setup = emmaprp_queue_setup, | ||
746 | .buf_prepare = emmaprp_buf_prepare, | ||
747 | .buf_queue = emmaprp_buf_queue, | ||
748 | }; | ||
749 | |||
750 | static int queue_init(void *priv, struct vb2_queue *src_vq, | ||
751 | struct vb2_queue *dst_vq) | ||
752 | { | ||
753 | struct emmaprp_ctx *ctx = priv; | ||
754 | int ret; | ||
755 | |||
756 | memset(src_vq, 0, sizeof(*src_vq)); | ||
757 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
758 | src_vq->io_modes = VB2_MMAP; | ||
759 | src_vq->drv_priv = ctx; | ||
760 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | ||
761 | src_vq->ops = &emmaprp_qops; | ||
762 | src_vq->mem_ops = &vb2_dma_contig_memops; | ||
763 | |||
764 | ret = vb2_queue_init(src_vq); | ||
765 | if (ret) | ||
766 | return ret; | ||
767 | |||
768 | memset(dst_vq, 0, sizeof(*dst_vq)); | ||
769 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
770 | dst_vq->io_modes = VB2_MMAP; | ||
771 | dst_vq->drv_priv = ctx; | ||
772 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | ||
773 | dst_vq->ops = &emmaprp_qops; | ||
774 | dst_vq->mem_ops = &vb2_dma_contig_memops; | ||
775 | |||
776 | return vb2_queue_init(dst_vq); | ||
777 | } | ||
778 | |||
779 | /* | ||
780 | * File operations | ||
781 | */ | ||
782 | static int emmaprp_open(struct file *file) | ||
783 | { | ||
784 | struct emmaprp_dev *pcdev = video_drvdata(file); | ||
785 | struct emmaprp_ctx *ctx; | ||
786 | |||
787 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); | ||
788 | if (!ctx) | ||
789 | return -ENOMEM; | ||
790 | |||
791 | file->private_data = ctx; | ||
792 | ctx->dev = pcdev; | ||
793 | |||
794 | ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); | ||
795 | |||
796 | if (IS_ERR(ctx->m2m_ctx)) { | ||
797 | int ret = PTR_ERR(ctx->m2m_ctx); | ||
798 | |||
799 | kfree(ctx); | ||
800 | return ret; | ||
801 | } | ||
802 | |||
803 | clk_enable(pcdev->clk_emma); | ||
804 | ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; | ||
805 | ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; | ||
806 | |||
807 | dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static int emmaprp_release(struct file *file) | ||
813 | { | ||
814 | struct emmaprp_dev *pcdev = video_drvdata(file); | ||
815 | struct emmaprp_ctx *ctx = file->private_data; | ||
816 | |||
817 | dprintk(pcdev, "Releasing instance %p\n", ctx); | ||
818 | |||
819 | clk_disable(pcdev->clk_emma); | ||
820 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | ||
821 | kfree(ctx); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static unsigned int emmaprp_poll(struct file *file, | ||
827 | struct poll_table_struct *wait) | ||
828 | { | ||
829 | struct emmaprp_ctx *ctx = file->private_data; | ||
830 | |||
831 | return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | ||
832 | } | ||
833 | |||
834 | static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma) | ||
835 | { | ||
836 | struct emmaprp_ctx *ctx = file->private_data; | ||
837 | |||
838 | return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | ||
839 | } | ||
840 | |||
841 | static const struct v4l2_file_operations emmaprp_fops = { | ||
842 | .owner = THIS_MODULE, | ||
843 | .open = emmaprp_open, | ||
844 | .release = emmaprp_release, | ||
845 | .poll = emmaprp_poll, | ||
846 | .unlocked_ioctl = video_ioctl2, | ||
847 | .mmap = emmaprp_mmap, | ||
848 | }; | ||
849 | |||
850 | static struct video_device emmaprp_videodev = { | ||
851 | .name = MEM2MEM_NAME, | ||
852 | .fops = &emmaprp_fops, | ||
853 | .ioctl_ops = &emmaprp_ioctl_ops, | ||
854 | .minor = -1, | ||
855 | .release = video_device_release, | ||
856 | }; | ||
857 | |||
858 | static struct v4l2_m2m_ops m2m_ops = { | ||
859 | .device_run = emmaprp_device_run, | ||
860 | .job_abort = emmaprp_job_abort, | ||
861 | .lock = emmaprp_lock, | ||
862 | .unlock = emmaprp_unlock, | ||
863 | }; | ||
864 | |||
865 | static int emmaprp_probe(struct platform_device *pdev) | ||
866 | { | ||
867 | struct emmaprp_dev *pcdev; | ||
868 | struct video_device *vfd; | ||
869 | struct resource *res_emma; | ||
870 | int irq_emma; | ||
871 | int ret; | ||
872 | |||
873 | pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL); | ||
874 | if (!pcdev) | ||
875 | return -ENOMEM; | ||
876 | |||
877 | spin_lock_init(&pcdev->irqlock); | ||
878 | |||
879 | pcdev->clk_emma = clk_get(&pdev->dev, NULL); | ||
880 | if (IS_ERR(pcdev->clk_emma)) { | ||
881 | ret = PTR_ERR(pcdev->clk_emma); | ||
882 | goto free_dev; | ||
883 | } | ||
884 | |||
885 | irq_emma = platform_get_irq(pdev, 0); | ||
886 | res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
887 | if (irq_emma < 0 || res_emma == NULL) { | ||
888 | dev_err(&pdev->dev, "Missing platform resources data\n"); | ||
889 | ret = -ENODEV; | ||
890 | goto free_clk; | ||
891 | } | ||
892 | |||
893 | ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); | ||
894 | if (ret) | ||
895 | goto free_clk; | ||
896 | |||
897 | mutex_init(&pcdev->dev_mutex); | ||
898 | |||
899 | vfd = video_device_alloc(); | ||
900 | if (!vfd) { | ||
901 | v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n"); | ||
902 | ret = -ENOMEM; | ||
903 | goto unreg_dev; | ||
904 | } | ||
905 | |||
906 | *vfd = emmaprp_videodev; | ||
907 | vfd->lock = &pcdev->dev_mutex; | ||
908 | |||
909 | video_set_drvdata(vfd, pcdev); | ||
910 | snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name); | ||
911 | pcdev->vfd = vfd; | ||
912 | v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME | ||
913 | " Device registered as /dev/video%d\n", vfd->num); | ||
914 | |||
915 | platform_set_drvdata(pdev, pcdev); | ||
916 | |||
917 | if (devm_request_mem_region(&pdev->dev, res_emma->start, | ||
918 | resource_size(res_emma), MEM2MEM_NAME) == NULL) | ||
919 | goto rel_vdev; | ||
920 | |||
921 | pcdev->base_emma = devm_ioremap(&pdev->dev, res_emma->start, | ||
922 | resource_size(res_emma)); | ||
923 | if (!pcdev->base_emma) | ||
924 | goto rel_vdev; | ||
925 | |||
926 | pcdev->irq_emma = irq_emma; | ||
927 | pcdev->res_emma = res_emma; | ||
928 | |||
929 | if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq, | ||
930 | 0, MEM2MEM_NAME, pcdev) < 0) | ||
931 | goto rel_vdev; | ||
932 | |||
933 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
934 | if (IS_ERR(pcdev->alloc_ctx)) { | ||
935 | v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n"); | ||
936 | ret = PTR_ERR(pcdev->alloc_ctx); | ||
937 | goto rel_vdev; | ||
938 | } | ||
939 | |||
940 | pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops); | ||
941 | if (IS_ERR(pcdev->m2m_dev)) { | ||
942 | v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n"); | ||
943 | ret = PTR_ERR(pcdev->m2m_dev); | ||
944 | goto rel_ctx; | ||
945 | } | ||
946 | |||
947 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | ||
948 | if (ret) { | ||
949 | v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); | ||
950 | goto rel_m2m; | ||
951 | } | ||
952 | |||
953 | return 0; | ||
954 | |||
955 | |||
956 | rel_m2m: | ||
957 | v4l2_m2m_release(pcdev->m2m_dev); | ||
958 | rel_ctx: | ||
959 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
960 | rel_vdev: | ||
961 | video_device_release(vfd); | ||
962 | unreg_dev: | ||
963 | v4l2_device_unregister(&pcdev->v4l2_dev); | ||
964 | free_clk: | ||
965 | clk_put(pcdev->clk_emma); | ||
966 | free_dev: | ||
967 | kfree(pcdev); | ||
968 | |||
969 | return ret; | ||
970 | } | ||
971 | |||
972 | static int emmaprp_remove(struct platform_device *pdev) | ||
973 | { | ||
974 | struct emmaprp_dev *pcdev = platform_get_drvdata(pdev); | ||
975 | |||
976 | v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME); | ||
977 | |||
978 | video_unregister_device(pcdev->vfd); | ||
979 | v4l2_m2m_release(pcdev->m2m_dev); | ||
980 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
981 | v4l2_device_unregister(&pcdev->v4l2_dev); | ||
982 | clk_put(pcdev->clk_emma); | ||
983 | kfree(pcdev); | ||
984 | |||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | static struct platform_driver emmaprp_pdrv = { | ||
989 | .probe = emmaprp_probe, | ||
990 | .remove = emmaprp_remove, | ||
991 | .driver = { | ||
992 | .name = MEM2MEM_NAME, | ||
993 | .owner = THIS_MODULE, | ||
994 | }, | ||
995 | }; | ||
996 | |||
997 | static void __exit emmaprp_exit(void) | ||
998 | { | ||
999 | platform_driver_unregister(&emmaprp_pdrv); | ||
1000 | } | ||
1001 | |||
1002 | static int __init emmaprp_init(void) | ||
1003 | { | ||
1004 | return platform_driver_register(&emmaprp_pdrv); | ||
1005 | } | ||
1006 | |||
1007 | module_init(emmaprp_init); | ||
1008 | module_exit(emmaprp_exit); | ||
diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c index 50838bf84204..440c12962bae 100644 --- a/drivers/media/video/noon010pc30.c +++ b/drivers/media/video/noon010pc30.c | |||
@@ -725,8 +725,8 @@ static int noon010_probe(struct i2c_client *client, | |||
725 | 725 | ||
726 | mutex_init(&info->lock); | 726 | mutex_init(&info->lock); |
727 | sd = &info->sd; | 727 | sd = &info->sd; |
728 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
729 | v4l2_i2c_subdev_init(sd, client, &noon010_ops); | 728 | v4l2_i2c_subdev_init(sd, client, &noon010_ops); |
729 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
730 | 730 | ||
731 | sd->internal_ops = &noon010_subdev_internal_ops; | 731 | sd->internal_ops = &noon010_subdev_internal_ops; |
732 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 732 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
@@ -844,18 +844,7 @@ static struct i2c_driver noon010_i2c_driver = { | |||
844 | .id_table = noon010_id, | 844 | .id_table = noon010_id, |
845 | }; | 845 | }; |
846 | 846 | ||
847 | static int __init noon010_init(void) | 847 | module_i2c_driver(noon010_i2c_driver); |
848 | { | ||
849 | return i2c_add_driver(&noon010_i2c_driver); | ||
850 | } | ||
851 | |||
852 | static void __exit noon010_exit(void) | ||
853 | { | ||
854 | i2c_del_driver(&noon010_i2c_driver); | ||
855 | } | ||
856 | |||
857 | module_init(noon010_init); | ||
858 | module_exit(noon010_exit); | ||
859 | 848 | ||
860 | MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); | 849 | MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); |
861 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | 850 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); |
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 1fb7d5bd5ec2..88cf9d952631 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c | |||
@@ -2268,13 +2268,12 @@ static struct platform_driver omap_vout_driver = { | |||
2268 | .driver = { | 2268 | .driver = { |
2269 | .name = VOUT_NAME, | 2269 | .name = VOUT_NAME, |
2270 | }, | 2270 | }, |
2271 | .probe = omap_vout_probe, | ||
2272 | .remove = omap_vout_remove, | 2271 | .remove = omap_vout_remove, |
2273 | }; | 2272 | }; |
2274 | 2273 | ||
2275 | static int __init omap_vout_init(void) | 2274 | static int __init omap_vout_init(void) |
2276 | { | 2275 | { |
2277 | if (platform_driver_register(&omap_vout_driver) != 0) { | 2276 | if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) { |
2278 | printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); | 2277 | printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); |
2279 | return -EINVAL; | 2278 | return -EINVAL; |
2280 | } | 2279 | } |
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index b5247cb64fde..3c2c5d3bcc6b 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c | |||
@@ -1103,21 +1103,7 @@ static struct i2c_driver ov2640_i2c_driver = { | |||
1103 | .id_table = ov2640_id, | 1103 | .id_table = ov2640_id, |
1104 | }; | 1104 | }; |
1105 | 1105 | ||
1106 | /* | 1106 | module_i2c_driver(ov2640_i2c_driver); |
1107 | * Module functions | ||
1108 | */ | ||
1109 | static int __init ov2640_module_init(void) | ||
1110 | { | ||
1111 | return i2c_add_driver(&ov2640_i2c_driver); | ||
1112 | } | ||
1113 | |||
1114 | static void __exit ov2640_module_exit(void) | ||
1115 | { | ||
1116 | i2c_del_driver(&ov2640_i2c_driver); | ||
1117 | } | ||
1118 | |||
1119 | module_init(ov2640_module_init); | ||
1120 | module_exit(ov2640_module_exit); | ||
1121 | 1107 | ||
1122 | MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); | 1108 | MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); |
1123 | MODULE_AUTHOR("Alberto Panizzo"); | 1109 | MODULE_AUTHOR("Alberto Panizzo"); |
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index bb37ec80f274..80e07794ac8e 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c | |||
@@ -1068,18 +1068,7 @@ static struct i2c_driver ov5642_i2c_driver = { | |||
1068 | .id_table = ov5642_id, | 1068 | .id_table = ov5642_id, |
1069 | }; | 1069 | }; |
1070 | 1070 | ||
1071 | static int __init ov5642_mod_init(void) | 1071 | module_i2c_driver(ov5642_i2c_driver); |
1072 | { | ||
1073 | return i2c_add_driver(&ov5642_i2c_driver); | ||
1074 | } | ||
1075 | |||
1076 | static void __exit ov5642_mod_exit(void) | ||
1077 | { | ||
1078 | i2c_del_driver(&ov5642_i2c_driver); | ||
1079 | } | ||
1080 | |||
1081 | module_init(ov5642_mod_init); | ||
1082 | module_exit(ov5642_mod_exit); | ||
1083 | 1072 | ||
1084 | MODULE_DESCRIPTION("Omnivision OV5642 Camera driver"); | 1073 | MODULE_DESCRIPTION("Omnivision OV5642 Camera driver"); |
1085 | MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>"); | 1074 | MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>"); |
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 3627f3225bbb..3e028b1970dd 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c | |||
@@ -1046,18 +1046,7 @@ static struct i2c_driver ov6650_i2c_driver = { | |||
1046 | .id_table = ov6650_id, | 1046 | .id_table = ov6650_id, |
1047 | }; | 1047 | }; |
1048 | 1048 | ||
1049 | static int __init ov6650_module_init(void) | 1049 | module_i2c_driver(ov6650_i2c_driver); |
1050 | { | ||
1051 | return i2c_add_driver(&ov6650_i2c_driver); | ||
1052 | } | ||
1053 | |||
1054 | static void __exit ov6650_module_exit(void) | ||
1055 | { | ||
1056 | i2c_del_driver(&ov6650_i2c_driver); | ||
1057 | } | ||
1058 | |||
1059 | module_init(ov6650_module_init); | ||
1060 | module_exit(ov6650_module_exit); | ||
1061 | 1050 | ||
1062 | MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); | 1051 | MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); |
1063 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); | 1052 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); |
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 6a564964853a..e7c82b297514 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c | |||
@@ -1583,15 +1583,4 @@ static struct i2c_driver ov7670_driver = { | |||
1583 | .id_table = ov7670_id, | 1583 | .id_table = ov7670_id, |
1584 | }; | 1584 | }; |
1585 | 1585 | ||
1586 | static __init int init_ov7670(void) | 1586 | module_i2c_driver(ov7670_driver); |
1587 | { | ||
1588 | return i2c_add_driver(&ov7670_driver); | ||
1589 | } | ||
1590 | |||
1591 | static __exit void exit_ov7670(void) | ||
1592 | { | ||
1593 | i2c_del_driver(&ov7670_driver); | ||
1594 | } | ||
1595 | |||
1596 | module_init(init_ov7670); | ||
1597 | module_exit(exit_ov7670); | ||
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 9f6ce3d8a29e..74e77d327ed8 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c | |||
@@ -1123,22 +1123,7 @@ static struct i2c_driver ov772x_i2c_driver = { | |||
1123 | .id_table = ov772x_id, | 1123 | .id_table = ov772x_id, |
1124 | }; | 1124 | }; |
1125 | 1125 | ||
1126 | /* | 1126 | module_i2c_driver(ov772x_i2c_driver); |
1127 | * module function | ||
1128 | */ | ||
1129 | |||
1130 | static int __init ov772x_module_init(void) | ||
1131 | { | ||
1132 | return i2c_add_driver(&ov772x_i2c_driver); | ||
1133 | } | ||
1134 | |||
1135 | static void __exit ov772x_module_exit(void) | ||
1136 | { | ||
1137 | i2c_del_driver(&ov772x_i2c_driver); | ||
1138 | } | ||
1139 | |||
1140 | module_init(ov772x_module_init); | ||
1141 | module_exit(ov772x_module_exit); | ||
1142 | 1127 | ||
1143 | MODULE_DESCRIPTION("SoC Camera driver for ov772x"); | 1128 | MODULE_DESCRIPTION("SoC Camera driver for ov772x"); |
1144 | MODULE_AUTHOR("Kuninori Morimoto"); | 1129 | MODULE_AUTHOR("Kuninori Morimoto"); |
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index a4f99797eb56..23412debb36b 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c | |||
@@ -738,18 +738,7 @@ static struct i2c_driver ov9640_i2c_driver = { | |||
738 | .id_table = ov9640_id, | 738 | .id_table = ov9640_id, |
739 | }; | 739 | }; |
740 | 740 | ||
741 | static int __init ov9640_module_init(void) | 741 | module_i2c_driver(ov9640_i2c_driver); |
742 | { | ||
743 | return i2c_add_driver(&ov9640_i2c_driver); | ||
744 | } | ||
745 | |||
746 | static void __exit ov9640_module_exit(void) | ||
747 | { | ||
748 | i2c_del_driver(&ov9640_i2c_driver); | ||
749 | } | ||
750 | |||
751 | module_init(ov9640_module_init); | ||
752 | module_exit(ov9640_module_exit); | ||
753 | 742 | ||
754 | MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); | 743 | MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); |
755 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | 744 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); |
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index d9a9f7174f7a..3eb07c22516e 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c | |||
@@ -998,18 +998,7 @@ static struct i2c_driver ov9740_i2c_driver = { | |||
998 | .id_table = ov9740_id, | 998 | .id_table = ov9740_id, |
999 | }; | 999 | }; |
1000 | 1000 | ||
1001 | static int __init ov9740_module_init(void) | 1001 | module_i2c_driver(ov9740_i2c_driver); |
1002 | { | ||
1003 | return i2c_add_driver(&ov9740_i2c_driver); | ||
1004 | } | ||
1005 | |||
1006 | static void __exit ov9740_module_exit(void) | ||
1007 | { | ||
1008 | i2c_del_driver(&ov9740_i2c_driver); | ||
1009 | } | ||
1010 | |||
1011 | module_init(ov9740_module_init); | ||
1012 | module_exit(ov9740_module_exit); | ||
1013 | 1002 | ||
1014 | MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740"); | 1003 | MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740"); |
1015 | MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>"); | 1004 | MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>"); |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index c6da8f77e1a2..d8c898278e8c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c | |||
@@ -320,7 +320,17 @@ static struct tda829x_config tda829x_no_probe = { | |||
320 | .probe_tuner = TDA829X_DONT_PROBE, | 320 | .probe_tuner = TDA829X_DONT_PROBE, |
321 | }; | 321 | }; |
322 | 322 | ||
323 | static struct tda18271_std_map hauppauge_tda18271_dvbt_std_map = { | ||
324 | .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, | ||
325 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
326 | .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, | ||
327 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
328 | .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, | ||
329 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
330 | }; | ||
331 | |||
323 | static struct tda18271_config hauppauge_tda18271_dvb_config = { | 332 | static struct tda18271_config hauppauge_tda18271_dvb_config = { |
333 | .std_map = &hauppauge_tda18271_dvbt_std_map, | ||
324 | .gate = TDA18271_GATE_ANALOG, | 334 | .gate = TDA18271_GATE_ANALOG, |
325 | .output_opt = TDA18271_OUTPUT_LT_OFF, | 335 | .output_opt = TDA18271_OUTPUT_LT_OFF, |
326 | }; | 336 | }; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 6d666174dbb4..e1111d968a3d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -96,7 +96,6 @@ static struct v4l2_capability pvr_capability ={ | |||
96 | .capabilities = (V4L2_CAP_VIDEO_CAPTURE | | 96 | .capabilities = (V4L2_CAP_VIDEO_CAPTURE | |
97 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | | 97 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | |
98 | V4L2_CAP_READWRITE), | 98 | V4L2_CAP_READWRITE), |
99 | .reserved = {0,0,0,0} | ||
100 | }; | 99 | }; |
101 | 100 | ||
102 | static struct v4l2_fmtdesc pvr_fmtdesc [] = { | 101 | static struct v4l2_fmtdesc pvr_fmtdesc [] = { |
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index f495eeb5403a..2834e3e65b39 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -1146,14 +1146,6 @@ leave: | |||
1146 | return ret; | 1146 | return ret; |
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | static int pwc_log_status(struct file *file, void *priv) | ||
1150 | { | ||
1151 | struct pwc_device *pdev = video_drvdata(file); | ||
1152 | |||
1153 | v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME); | ||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | const struct v4l2_ioctl_ops pwc_ioctl_ops = { | 1149 | const struct v4l2_ioctl_ops pwc_ioctl_ops = { |
1158 | .vidioc_querycap = pwc_querycap, | 1150 | .vidioc_querycap = pwc_querycap, |
1159 | .vidioc_enum_input = pwc_enum_input, | 1151 | .vidioc_enum_input = pwc_enum_input, |
@@ -1169,7 +1161,7 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { | |||
1169 | .vidioc_dqbuf = pwc_dqbuf, | 1161 | .vidioc_dqbuf = pwc_dqbuf, |
1170 | .vidioc_streamon = pwc_streamon, | 1162 | .vidioc_streamon = pwc_streamon, |
1171 | .vidioc_streamoff = pwc_streamoff, | 1163 | .vidioc_streamoff = pwc_streamoff, |
1172 | .vidioc_log_status = pwc_log_status, | 1164 | .vidioc_log_status = v4l2_ctrl_log_status, |
1173 | .vidioc_enum_framesizes = pwc_enum_framesizes, | 1165 | .vidioc_enum_framesizes = pwc_enum_framesizes, |
1174 | .vidioc_enum_frameintervals = pwc_enum_frameintervals, | 1166 | .vidioc_enum_frameintervals = pwc_enum_frameintervals, |
1175 | .vidioc_g_parm = pwc_g_parm, | 1167 | .vidioc_g_parm = pwc_g_parm, |
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 0bd7da26d018..5a413f4427e0 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -921,12 +921,12 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) | |||
921 | /* "Safe default" - 13MHz */ | 921 | /* "Safe default" - 13MHz */ |
922 | recalculate_fifo_timeout(pcdev, 13000000); | 922 | recalculate_fifo_timeout(pcdev, 13000000); |
923 | 923 | ||
924 | clk_enable(pcdev->clk); | 924 | clk_prepare_enable(pcdev->clk); |
925 | } | 925 | } |
926 | 926 | ||
927 | static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) | 927 | static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) |
928 | { | 928 | { |
929 | clk_disable(pcdev->clk); | 929 | clk_disable_unprepare(pcdev->clk); |
930 | } | 930 | } |
931 | 931 | ||
932 | static irqreturn_t pxa_camera_irq(int irq, void *data) | 932 | static irqreturn_t pxa_camera_irq(int irq, void *data) |
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 9937386a3bae..f6419b22c258 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c | |||
@@ -1407,18 +1407,7 @@ static struct i2c_driver rj54n1_i2c_driver = { | |||
1407 | .id_table = rj54n1_id, | 1407 | .id_table = rj54n1_id, |
1408 | }; | 1408 | }; |
1409 | 1409 | ||
1410 | static int __init rj54n1_mod_init(void) | 1410 | module_i2c_driver(rj54n1_i2c_driver); |
1411 | { | ||
1412 | return i2c_add_driver(&rj54n1_i2c_driver); | ||
1413 | } | ||
1414 | |||
1415 | static void __exit rj54n1_mod_exit(void) | ||
1416 | { | ||
1417 | i2c_del_driver(&rj54n1_i2c_driver); | ||
1418 | } | ||
1419 | |||
1420 | module_init(rj54n1_mod_init); | ||
1421 | module_exit(rj54n1_mod_exit); | ||
1422 | 1411 | ||
1423 | MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver"); | 1412 | MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver"); |
1424 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | 1413 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); |
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index c1bef6187661..4894cbb1c547 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c | |||
@@ -134,7 +134,7 @@ | |||
134 | 134 | ||
135 | /* usb config commands */ | 135 | /* usb config commands */ |
136 | #define IN_DATA_TOKEN cpu_to_le32(0x2255c0de) | 136 | #define IN_DATA_TOKEN cpu_to_le32(0x2255c0de) |
137 | #define CMD_2255 cpu_to_le32(0xc2255000) | 137 | #define CMD_2255 0xc2255000 |
138 | #define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10)) | 138 | #define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10)) |
139 | #define CMD_START cpu_to_le32((CMD_2255 | 0x20)) | 139 | #define CMD_START cpu_to_le32((CMD_2255 | 0x20)) |
140 | #define CMD_STOP cpu_to_le32((CMD_2255 | 0x30)) | 140 | #define CMD_STOP cpu_to_le32((CMD_2255 | 0x30)) |
@@ -852,15 +852,13 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
852 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | 852 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, |
853 | struct v4l2_fmtdesc *f) | 853 | struct v4l2_fmtdesc *f) |
854 | { | 854 | { |
855 | int index = 0; | 855 | int index = f->index; |
856 | if (f) | ||
857 | index = f->index; | ||
858 | 856 | ||
859 | if (index >= ARRAY_SIZE(formats)) | 857 | if (index >= ARRAY_SIZE(formats)) |
860 | return -EINVAL; | 858 | return -EINVAL; |
861 | if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || | 859 | if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || |
862 | (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) | 860 | (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) |
863 | return -EINVAL; | 861 | return -EINVAL; |
864 | dprintk(4, "name %s\n", formats[index].name); | 862 | dprintk(4, "name %s\n", formats[index].name); |
865 | strlcpy(f->description, formats[index].name, sizeof(f->description)); | 863 | strlcpy(f->description, formats[index].name, sizeof(f->description)); |
866 | f->pixelformat = formats[index].fourcc; | 864 | f->pixelformat = formats[index].fourcc; |
@@ -2027,7 +2025,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) | |||
2027 | pdata[1]); | 2025 | pdata[1]); |
2028 | offset = jj + PREFIX_SIZE; | 2026 | offset = jj + PREFIX_SIZE; |
2029 | bframe = 1; | 2027 | bframe = 1; |
2030 | cc = pdword[1]; | 2028 | cc = le32_to_cpu(pdword[1]); |
2031 | if (cc >= MAX_CHANNELS) { | 2029 | if (cc >= MAX_CHANNELS) { |
2032 | printk(KERN_ERR | 2030 | printk(KERN_ERR |
2033 | "bad channel\n"); | 2031 | "bad channel\n"); |
@@ -2036,22 +2034,22 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) | |||
2036 | /* reverse it */ | 2034 | /* reverse it */ |
2037 | dev->cc = G_chnmap[cc]; | 2035 | dev->cc = G_chnmap[cc]; |
2038 | channel = &dev->channel[dev->cc]; | 2036 | channel = &dev->channel[dev->cc]; |
2039 | payload = pdword[3]; | 2037 | payload = le32_to_cpu(pdword[3]); |
2040 | if (payload > channel->req_image_size) { | 2038 | if (payload > channel->req_image_size) { |
2041 | channel->bad_payload++; | 2039 | channel->bad_payload++; |
2042 | /* discard the bad frame */ | 2040 | /* discard the bad frame */ |
2043 | return -EINVAL; | 2041 | return -EINVAL; |
2044 | } | 2042 | } |
2045 | channel->pkt_size = payload; | 2043 | channel->pkt_size = payload; |
2046 | channel->jpg_size = pdword[4]; | 2044 | channel->jpg_size = le32_to_cpu(pdword[4]); |
2047 | break; | 2045 | break; |
2048 | case S2255_MARKER_RESPONSE: | 2046 | case S2255_MARKER_RESPONSE: |
2049 | 2047 | ||
2050 | pdata += DEF_USB_BLOCK; | 2048 | pdata += DEF_USB_BLOCK; |
2051 | jj += DEF_USB_BLOCK; | 2049 | jj += DEF_USB_BLOCK; |
2052 | if (pdword[1] >= MAX_CHANNELS) | 2050 | if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS) |
2053 | break; | 2051 | break; |
2054 | cc = G_chnmap[pdword[1]]; | 2052 | cc = G_chnmap[le32_to_cpu(pdword[1])]; |
2055 | if (cc >= MAX_CHANNELS) | 2053 | if (cc >= MAX_CHANNELS) |
2056 | break; | 2054 | break; |
2057 | channel = &dev->channel[cc]; | 2055 | channel = &dev->channel[cc]; |
@@ -2074,11 +2072,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) | |||
2074 | wake_up(&dev->fw_data->wait_fw); | 2072 | wake_up(&dev->fw_data->wait_fw); |
2075 | break; | 2073 | break; |
2076 | case S2255_RESPONSE_STATUS: | 2074 | case S2255_RESPONSE_STATUS: |
2077 | channel->vidstatus = pdword[3]; | 2075 | channel->vidstatus = le32_to_cpu(pdword[3]); |
2078 | channel->vidstatus_ready = 1; | 2076 | channel->vidstatus_ready = 1; |
2079 | wake_up(&channel->wait_vidstatus); | 2077 | wake_up(&channel->wait_vidstatus); |
2080 | dprintk(5, "got vidstatus %x chan %d\n", | 2078 | dprintk(5, "got vidstatus %x chan %d\n", |
2081 | pdword[3], cc); | 2079 | le32_to_cpu(pdword[3]), cc); |
2082 | break; | 2080 | break; |
2083 | default: | 2081 | default: |
2084 | printk(KERN_INFO "s2255 unknown resp\n"); | 2082 | printk(KERN_INFO "s2255 unknown resp\n"); |
@@ -2605,10 +2603,11 @@ static int s2255_probe(struct usb_interface *interface, | |||
2605 | __le32 *pRel; | 2603 | __le32 *pRel; |
2606 | pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; | 2604 | pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; |
2607 | printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); | 2605 | printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); |
2608 | dev->dsp_fw_ver = *pRel; | 2606 | dev->dsp_fw_ver = le32_to_cpu(*pRel); |
2609 | if (*pRel < S2255_CUR_DSP_FWVER) | 2607 | if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) |
2610 | printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); | 2608 | printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); |
2611 | if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER) | 2609 | if (dev->pid == 0x2257 && |
2610 | dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) | ||
2612 | printk(KERN_WARNING "s2255: 2257 requires firmware %d" | 2611 | printk(KERN_WARNING "s2255: 2257 requires firmware %d" |
2613 | " or above.\n", S2255_MIN_DSP_COLORFILTER); | 2612 | " or above.\n", S2255_MIN_DSP_COLORFILTER); |
2614 | } | 2613 | } |
diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c index 0df7f2a41814..6625e46a4638 100644 --- a/drivers/media/video/s5k6aa.c +++ b/drivers/media/video/s5k6aa.c | |||
@@ -1582,8 +1582,8 @@ static int s5k6aa_probe(struct i2c_client *client, | |||
1582 | s5k6aa->inv_vflip = pdata->vert_flip; | 1582 | s5k6aa->inv_vflip = pdata->vert_flip; |
1583 | 1583 | ||
1584 | sd = &s5k6aa->sd; | 1584 | sd = &s5k6aa->sd; |
1585 | strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); | ||
1586 | v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); | 1585 | v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); |
1586 | strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); | ||
1587 | 1587 | ||
1588 | sd->internal_ops = &s5k6aa_subdev_internal_ops; | 1588 | sd->internal_ops = &s5k6aa_subdev_internal_ops; |
1589 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 1589 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
@@ -1663,18 +1663,7 @@ static struct i2c_driver s5k6aa_i2c_driver = { | |||
1663 | .id_table = s5k6aa_id, | 1663 | .id_table = s5k6aa_id, |
1664 | }; | 1664 | }; |
1665 | 1665 | ||
1666 | static int __init s5k6aa_init(void) | 1666 | module_i2c_driver(s5k6aa_i2c_driver); |
1667 | { | ||
1668 | return i2c_add_driver(&s5k6aa_i2c_driver); | ||
1669 | } | ||
1670 | |||
1671 | static void __exit s5k6aa_exit(void) | ||
1672 | { | ||
1673 | i2c_del_driver(&s5k6aa_i2c_driver); | ||
1674 | } | ||
1675 | |||
1676 | module_init(s5k6aa_init); | ||
1677 | module_exit(s5k6aa_exit); | ||
1678 | 1667 | ||
1679 | MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); | 1668 | MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); |
1680 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | 1669 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); |
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index a9e9653beeb4..b06efd208328 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
@@ -1019,52 +1019,117 @@ static int fimc_cap_dqbuf(struct file *file, void *priv, | |||
1019 | return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); | 1019 | return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); |
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | static int fimc_cap_cropcap(struct file *file, void *fh, | 1022 | static int fimc_cap_create_bufs(struct file *file, void *priv, |
1023 | struct v4l2_cropcap *cr) | 1023 | struct v4l2_create_buffers *create) |
1024 | { | 1024 | { |
1025 | struct fimc_dev *fimc = video_drvdata(file); | 1025 | struct fimc_dev *fimc = video_drvdata(file); |
1026 | struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; | ||
1027 | 1026 | ||
1028 | if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | 1027 | return vb2_create_bufs(&fimc->vid_cap.vbq, create); |
1029 | return -EINVAL; | 1028 | } |
1030 | 1029 | ||
1031 | cr->bounds.left = 0; | 1030 | static int fimc_cap_prepare_buf(struct file *file, void *priv, |
1032 | cr->bounds.top = 0; | 1031 | struct v4l2_buffer *b) |
1033 | cr->bounds.width = f->o_width; | 1032 | { |
1034 | cr->bounds.height = f->o_height; | 1033 | struct fimc_dev *fimc = video_drvdata(file); |
1035 | cr->defrect = cr->bounds; | ||
1036 | 1034 | ||
1037 | return 0; | 1035 | return vb2_prepare_buf(&fimc->vid_cap.vbq, b); |
1038 | } | 1036 | } |
1039 | 1037 | ||
1040 | static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) | 1038 | static int fimc_cap_g_selection(struct file *file, void *fh, |
1039 | struct v4l2_selection *s) | ||
1041 | { | 1040 | { |
1042 | struct fimc_dev *fimc = video_drvdata(file); | 1041 | struct fimc_dev *fimc = video_drvdata(file); |
1043 | struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; | 1042 | struct fimc_ctx *ctx = fimc->vid_cap.ctx; |
1043 | struct fimc_frame *f = &ctx->s_frame; | ||
1044 | 1044 | ||
1045 | cr->c.left = f->offs_h; | 1045 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
1046 | cr->c.top = f->offs_v; | 1046 | return -EINVAL; |
1047 | cr->c.width = f->width; | ||
1048 | cr->c.height = f->height; | ||
1049 | 1047 | ||
1050 | return 0; | 1048 | switch (s->target) { |
1049 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
1050 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
1051 | f = &ctx->d_frame; | ||
1052 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1053 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
1054 | s->r.left = 0; | ||
1055 | s->r.top = 0; | ||
1056 | s->r.width = f->o_width; | ||
1057 | s->r.height = f->o_height; | ||
1058 | return 0; | ||
1059 | |||
1060 | case V4L2_SEL_TGT_COMPOSE_ACTIVE: | ||
1061 | f = &ctx->d_frame; | ||
1062 | case V4L2_SEL_TGT_CROP_ACTIVE: | ||
1063 | s->r.left = f->offs_h; | ||
1064 | s->r.top = f->offs_v; | ||
1065 | s->r.width = f->width; | ||
1066 | s->r.height = f->height; | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | return -EINVAL; | ||
1051 | } | 1071 | } |
1052 | 1072 | ||
1053 | static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | 1073 | /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ |
1074 | int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) | ||
1075 | { | ||
1076 | if (a->left < b->left || a->top < b->top) | ||
1077 | return 0; | ||
1078 | if (a->left + a->width > b->left + b->width) | ||
1079 | return 0; | ||
1080 | if (a->top + a->height > b->top + b->height) | ||
1081 | return 0; | ||
1082 | |||
1083 | return 1; | ||
1084 | } | ||
1085 | |||
1086 | static int fimc_cap_s_selection(struct file *file, void *fh, | ||
1087 | struct v4l2_selection *s) | ||
1054 | { | 1088 | { |
1055 | struct fimc_dev *fimc = video_drvdata(file); | 1089 | struct fimc_dev *fimc = video_drvdata(file); |
1056 | struct fimc_ctx *ctx = fimc->vid_cap.ctx; | 1090 | struct fimc_ctx *ctx = fimc->vid_cap.ctx; |
1057 | struct fimc_frame *ff; | 1091 | struct v4l2_rect rect = s->r; |
1092 | struct fimc_frame *f; | ||
1058 | unsigned long flags; | 1093 | unsigned long flags; |
1094 | unsigned int pad; | ||
1059 | 1095 | ||
1060 | fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK); | 1096 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
1061 | ff = &ctx->s_frame; | 1097 | return -EINVAL; |
1062 | 1098 | ||
1099 | switch (s->target) { | ||
1100 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
1101 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
1102 | case V4L2_SEL_TGT_COMPOSE_ACTIVE: | ||
1103 | f = &ctx->d_frame; | ||
1104 | pad = FIMC_SD_PAD_SOURCE; | ||
1105 | break; | ||
1106 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1107 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
1108 | case V4L2_SEL_TGT_CROP_ACTIVE: | ||
1109 | f = &ctx->s_frame; | ||
1110 | pad = FIMC_SD_PAD_SINK; | ||
1111 | break; | ||
1112 | default: | ||
1113 | return -EINVAL; | ||
1114 | } | ||
1115 | |||
1116 | fimc_capture_try_crop(ctx, &rect, pad); | ||
1117 | |||
1118 | if (s->flags & V4L2_SEL_FLAG_LE && | ||
1119 | !enclosed_rectangle(&rect, &s->r)) | ||
1120 | return -ERANGE; | ||
1121 | |||
1122 | if (s->flags & V4L2_SEL_FLAG_GE && | ||
1123 | !enclosed_rectangle(&s->r, &rect)) | ||
1124 | return -ERANGE; | ||
1125 | |||
1126 | s->r = rect; | ||
1063 | spin_lock_irqsave(&fimc->slock, flags); | 1127 | spin_lock_irqsave(&fimc->slock, flags); |
1064 | set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height); | 1128 | set_frame_crop(f, s->r.left, s->r.top, s->r.width, |
1065 | set_bit(ST_CAPT_APPLY_CFG, &fimc->state); | 1129 | s->r.height); |
1066 | spin_unlock_irqrestore(&fimc->slock, flags); | 1130 | spin_unlock_irqrestore(&fimc->slock, flags); |
1067 | 1131 | ||
1132 | set_bit(ST_CAPT_APPLY_CFG, &fimc->state); | ||
1068 | return 0; | 1133 | return 0; |
1069 | } | 1134 | } |
1070 | 1135 | ||
@@ -1082,12 +1147,14 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { | |||
1082 | .vidioc_qbuf = fimc_cap_qbuf, | 1147 | .vidioc_qbuf = fimc_cap_qbuf, |
1083 | .vidioc_dqbuf = fimc_cap_dqbuf, | 1148 | .vidioc_dqbuf = fimc_cap_dqbuf, |
1084 | 1149 | ||
1150 | .vidioc_prepare_buf = fimc_cap_prepare_buf, | ||
1151 | .vidioc_create_bufs = fimc_cap_create_bufs, | ||
1152 | |||
1085 | .vidioc_streamon = fimc_cap_streamon, | 1153 | .vidioc_streamon = fimc_cap_streamon, |
1086 | .vidioc_streamoff = fimc_cap_streamoff, | 1154 | .vidioc_streamoff = fimc_cap_streamoff, |
1087 | 1155 | ||
1088 | .vidioc_g_crop = fimc_cap_g_crop, | 1156 | .vidioc_g_selection = fimc_cap_g_selection, |
1089 | .vidioc_s_crop = fimc_cap_s_crop, | 1157 | .vidioc_s_selection = fimc_cap_s_selection, |
1090 | .vidioc_cropcap = fimc_cap_cropcap, | ||
1091 | 1158 | ||
1092 | .vidioc_enum_input = fimc_cap_enum_input, | 1159 | .vidioc_enum_input = fimc_cap_enum_input, |
1093 | .vidioc_s_input = fimc_cap_s_input, | 1160 | .vidioc_s_input = fimc_cap_s_input, |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 81bcbb9492ea..e184e650022a 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
@@ -1602,24 +1602,35 @@ static void fimc_clk_put(struct fimc_dev *fimc) | |||
1602 | { | 1602 | { |
1603 | int i; | 1603 | int i; |
1604 | for (i = 0; i < fimc->num_clocks; i++) { | 1604 | for (i = 0; i < fimc->num_clocks; i++) { |
1605 | if (fimc->clock[i]) | 1605 | if (IS_ERR_OR_NULL(fimc->clock[i])) |
1606 | clk_put(fimc->clock[i]); | 1606 | continue; |
1607 | clk_unprepare(fimc->clock[i]); | ||
1608 | clk_put(fimc->clock[i]); | ||
1609 | fimc->clock[i] = NULL; | ||
1607 | } | 1610 | } |
1608 | } | 1611 | } |
1609 | 1612 | ||
1610 | static int fimc_clk_get(struct fimc_dev *fimc) | 1613 | static int fimc_clk_get(struct fimc_dev *fimc) |
1611 | { | 1614 | { |
1612 | int i; | 1615 | int i, ret; |
1616 | |||
1613 | for (i = 0; i < fimc->num_clocks; i++) { | 1617 | for (i = 0; i < fimc->num_clocks; i++) { |
1614 | fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); | 1618 | fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); |
1615 | if (!IS_ERR_OR_NULL(fimc->clock[i])) | 1619 | if (IS_ERR(fimc->clock[i])) |
1616 | continue; | 1620 | goto err; |
1617 | dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", | 1621 | ret = clk_prepare(fimc->clock[i]); |
1618 | fimc_clocks[i]); | 1622 | if (ret < 0) { |
1619 | return -ENXIO; | 1623 | clk_put(fimc->clock[i]); |
1624 | fimc->clock[i] = NULL; | ||
1625 | goto err; | ||
1626 | } | ||
1620 | } | 1627 | } |
1621 | |||
1622 | return 0; | 1628 | return 0; |
1629 | err: | ||
1630 | fimc_clk_put(fimc); | ||
1631 | dev_err(&fimc->pdev->dev, "failed to get clock: %s\n", | ||
1632 | fimc_clocks[i]); | ||
1633 | return -ENXIO; | ||
1623 | } | 1634 | } |
1624 | 1635 | ||
1625 | static int fimc_m2m_suspend(struct fimc_dev *fimc) | 1636 | static int fimc_m2m_suspend(struct fimc_dev *fimc) |
@@ -1667,8 +1678,6 @@ static int fimc_probe(struct platform_device *pdev) | |||
1667 | struct s5p_platform_fimc *pdata; | 1678 | struct s5p_platform_fimc *pdata; |
1668 | int ret = 0; | 1679 | int ret = 0; |
1669 | 1680 | ||
1670 | dev_dbg(&pdev->dev, "%s():\n", __func__); | ||
1671 | |||
1672 | drv_data = (struct samsung_fimc_driverdata *) | 1681 | drv_data = (struct samsung_fimc_driverdata *) |
1673 | platform_get_device_id(pdev)->driver_data; | 1682 | platform_get_device_id(pdev)->driver_data; |
1674 | 1683 | ||
@@ -1678,7 +1687,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1678 | return -EINVAL; | 1687 | return -EINVAL; |
1679 | } | 1688 | } |
1680 | 1689 | ||
1681 | fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL); | 1690 | fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL); |
1682 | if (!fimc) | 1691 | if (!fimc) |
1683 | return -ENOMEM; | 1692 | return -ENOMEM; |
1684 | 1693 | ||
@@ -1689,51 +1698,35 @@ static int fimc_probe(struct platform_device *pdev) | |||
1689 | pdata = pdev->dev.platform_data; | 1698 | pdata = pdev->dev.platform_data; |
1690 | fimc->pdata = pdata; | 1699 | fimc->pdata = pdata; |
1691 | 1700 | ||
1692 | |||
1693 | init_waitqueue_head(&fimc->irq_queue); | 1701 | init_waitqueue_head(&fimc->irq_queue); |
1694 | spin_lock_init(&fimc->slock); | 1702 | spin_lock_init(&fimc->slock); |
1695 | mutex_init(&fimc->lock); | 1703 | mutex_init(&fimc->lock); |
1696 | 1704 | ||
1697 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1705 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1698 | if (!res) { | 1706 | fimc->regs = devm_request_and_ioremap(&pdev->dev, res); |
1699 | dev_err(&pdev->dev, "failed to find the registers\n"); | 1707 | if (fimc->regs == NULL) { |
1700 | ret = -ENOENT; | 1708 | dev_err(&pdev->dev, "Failed to obtain io memory\n"); |
1701 | goto err_info; | 1709 | return -ENOENT; |
1702 | } | ||
1703 | |||
1704 | fimc->regs_res = request_mem_region(res->start, resource_size(res), | ||
1705 | dev_name(&pdev->dev)); | ||
1706 | if (!fimc->regs_res) { | ||
1707 | dev_err(&pdev->dev, "failed to obtain register region\n"); | ||
1708 | ret = -ENOENT; | ||
1709 | goto err_info; | ||
1710 | } | ||
1711 | |||
1712 | fimc->regs = ioremap(res->start, resource_size(res)); | ||
1713 | if (!fimc->regs) { | ||
1714 | dev_err(&pdev->dev, "failed to map registers\n"); | ||
1715 | ret = -ENXIO; | ||
1716 | goto err_req_region; | ||
1717 | } | 1710 | } |
1718 | 1711 | ||
1719 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1712 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1720 | if (!res) { | 1713 | if (res == NULL) { |
1721 | dev_err(&pdev->dev, "failed to get IRQ resource\n"); | 1714 | dev_err(&pdev->dev, "Failed to get IRQ resource\n"); |
1722 | ret = -ENXIO; | 1715 | return -ENXIO; |
1723 | goto err_regs_unmap; | ||
1724 | } | 1716 | } |
1725 | fimc->irq = res->start; | 1717 | fimc->irq = res->start; |
1726 | 1718 | ||
1727 | fimc->num_clocks = MAX_FIMC_CLOCKS; | 1719 | fimc->num_clocks = MAX_FIMC_CLOCKS; |
1728 | ret = fimc_clk_get(fimc); | 1720 | ret = fimc_clk_get(fimc); |
1729 | if (ret) | 1721 | if (ret) |
1730 | goto err_regs_unmap; | 1722 | return ret; |
1731 | clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); | 1723 | clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); |
1732 | clk_enable(fimc->clock[CLK_BUS]); | 1724 | clk_enable(fimc->clock[CLK_BUS]); |
1733 | 1725 | ||
1734 | platform_set_drvdata(pdev, fimc); | 1726 | platform_set_drvdata(pdev, fimc); |
1735 | 1727 | ||
1736 | ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc); | 1728 | ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler, |
1729 | 0, pdev->name, fimc); | ||
1737 | if (ret) { | 1730 | if (ret) { |
1738 | dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); | 1731 | dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); |
1739 | goto err_clk; | 1732 | goto err_clk; |
@@ -1742,7 +1735,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1742 | pm_runtime_enable(&pdev->dev); | 1735 | pm_runtime_enable(&pdev->dev); |
1743 | ret = pm_runtime_get_sync(&pdev->dev); | 1736 | ret = pm_runtime_get_sync(&pdev->dev); |
1744 | if (ret < 0) | 1737 | if (ret < 0) |
1745 | goto err_irq; | 1738 | goto err_clk; |
1746 | /* Initialize contiguous memory allocator */ | 1739 | /* Initialize contiguous memory allocator */ |
1747 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | 1740 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); |
1748 | if (IS_ERR(fimc->alloc_ctx)) { | 1741 | if (IS_ERR(fimc->alloc_ctx)) { |
@@ -1757,17 +1750,8 @@ static int fimc_probe(struct platform_device *pdev) | |||
1757 | 1750 | ||
1758 | err_pm: | 1751 | err_pm: |
1759 | pm_runtime_put(&pdev->dev); | 1752 | pm_runtime_put(&pdev->dev); |
1760 | err_irq: | ||
1761 | free_irq(fimc->irq, fimc); | ||
1762 | err_clk: | 1753 | err_clk: |
1763 | fimc_clk_put(fimc); | 1754 | fimc_clk_put(fimc); |
1764 | err_regs_unmap: | ||
1765 | iounmap(fimc->regs); | ||
1766 | err_req_region: | ||
1767 | release_resource(fimc->regs_res); | ||
1768 | kfree(fimc->regs_res); | ||
1769 | err_info: | ||
1770 | kfree(fimc); | ||
1771 | return ret; | 1755 | return ret; |
1772 | } | 1756 | } |
1773 | 1757 | ||
@@ -1854,11 +1838,6 @@ static int __devexit fimc_remove(struct platform_device *pdev) | |||
1854 | 1838 | ||
1855 | clk_disable(fimc->clock[CLK_BUS]); | 1839 | clk_disable(fimc->clock[CLK_BUS]); |
1856 | fimc_clk_put(fimc); | 1840 | fimc_clk_put(fimc); |
1857 | free_irq(fimc->irq, fimc); | ||
1858 | iounmap(fimc->regs); | ||
1859 | release_resource(fimc->regs_res); | ||
1860 | kfree(fimc->regs_res); | ||
1861 | kfree(fimc); | ||
1862 | 1841 | ||
1863 | dev_info(&pdev->dev, "driver unloaded\n"); | 1842 | dev_info(&pdev->dev, "driver unloaded\n"); |
1864 | return 0; | 1843 | return 0; |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 4e20560c73d4..a18291e648e2 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h | |||
@@ -434,7 +434,6 @@ struct fimc_ctx; | |||
434 | * @num_clocks: the number of clocks managed by this device instance | 434 | * @num_clocks: the number of clocks managed by this device instance |
435 | * @clock: clocks required for FIMC operation | 435 | * @clock: clocks required for FIMC operation |
436 | * @regs: the mapped hardware registers | 436 | * @regs: the mapped hardware registers |
437 | * @regs_res: the resource claimed for IO registers | ||
438 | * @irq: FIMC interrupt number | 437 | * @irq: FIMC interrupt number |
439 | * @irq_queue: interrupt handler waitqueue | 438 | * @irq_queue: interrupt handler waitqueue |
440 | * @v4l2_dev: root v4l2_device | 439 | * @v4l2_dev: root v4l2_device |
@@ -454,7 +453,6 @@ struct fimc_dev { | |||
454 | u16 num_clocks; | 453 | u16 num_clocks; |
455 | struct clk *clock[MAX_FIMC_CLOCKS]; | 454 | struct clk *clock[MAX_FIMC_CLOCKS]; |
456 | void __iomem *regs; | 455 | void __iomem *regs; |
457 | struct resource *regs_res; | ||
458 | int irq; | 456 | int irq; |
459 | wait_queue_head_t irq_queue; | 457 | wait_queue_head_t irq_queue; |
460 | struct v4l2_device *v4l2_dev; | 458 | struct v4l2_device *v4l2_dev; |
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 63eccb55728f..62ed37e40149 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c | |||
@@ -750,7 +750,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) | |||
750 | struct fimc_md *fmd; | 750 | struct fimc_md *fmd; |
751 | int ret; | 751 | int ret; |
752 | 752 | ||
753 | fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL); | 753 | fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL); |
754 | if (!fmd) | 754 | if (!fmd) |
755 | return -ENOMEM; | 755 | return -ENOMEM; |
756 | 756 | ||
@@ -771,7 +771,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) | |||
771 | ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); | 771 | ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); |
772 | if (ret < 0) { | 772 | if (ret < 0) { |
773 | v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); | 773 | v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); |
774 | goto err1; | 774 | return ret; |
775 | } | 775 | } |
776 | ret = media_device_register(&fmd->media_dev); | 776 | ret = media_device_register(&fmd->media_dev); |
777 | if (ret < 0) { | 777 | if (ret < 0) { |
@@ -813,8 +813,6 @@ err3: | |||
813 | fimc_md_unregister_entities(fmd); | 813 | fimc_md_unregister_entities(fmd); |
814 | err2: | 814 | err2: |
815 | v4l2_device_unregister(&fmd->v4l2_dev); | 815 | v4l2_device_unregister(&fmd->v4l2_dev); |
816 | err1: | ||
817 | kfree(fmd); | ||
818 | return ret; | 816 | return ret; |
819 | } | 817 | } |
820 | 818 | ||
@@ -828,7 +826,6 @@ static int __devexit fimc_md_remove(struct platform_device *pdev) | |||
828 | fimc_md_unregister_entities(fmd); | 826 | fimc_md_unregister_entities(fmd); |
829 | media_device_unregister(&fmd->media_dev); | 827 | media_device_unregister(&fmd->media_dev); |
830 | fimc_md_put_clocks(fmd); | 828 | fimc_md_put_clocks(fmd); |
831 | kfree(fmd); | ||
832 | return 0; | 829 | return 0; |
833 | } | 830 | } |
834 | 831 | ||
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c index 130335cf62fd..f44f690397f7 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.c +++ b/drivers/media/video/s5p-fimc/mipi-csis.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver | 2 | * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | 4 | * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. |
5 | * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com> | 5 | * Sylwester Nawrocki, <s.nawrocki@samsung.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -100,7 +100,6 @@ enum { | |||
100 | * @pads: CSIS pads array | 100 | * @pads: CSIS pads array |
101 | * @sd: v4l2_subdev associated with CSIS device instance | 101 | * @sd: v4l2_subdev associated with CSIS device instance |
102 | * @pdev: CSIS platform device | 102 | * @pdev: CSIS platform device |
103 | * @regs_res: requested I/O register memory resource | ||
104 | * @regs: mmaped I/O registers memory | 103 | * @regs: mmaped I/O registers memory |
105 | * @clock: CSIS clocks | 104 | * @clock: CSIS clocks |
106 | * @irq: requested s5p-mipi-csis irq number | 105 | * @irq: requested s5p-mipi-csis irq number |
@@ -113,7 +112,6 @@ struct csis_state { | |||
113 | struct media_pad pads[CSIS_PADS_NUM]; | 112 | struct media_pad pads[CSIS_PADS_NUM]; |
114 | struct v4l2_subdev sd; | 113 | struct v4l2_subdev sd; |
115 | struct platform_device *pdev; | 114 | struct platform_device *pdev; |
116 | struct resource *regs_res; | ||
117 | void __iomem *regs; | 115 | void __iomem *regs; |
118 | struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; | 116 | struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; |
119 | struct clk *clock[NUM_CSIS_CLOCKS]; | 117 | struct clk *clock[NUM_CSIS_CLOCKS]; |
@@ -258,26 +256,36 @@ static void s5pcsis_clk_put(struct csis_state *state) | |||
258 | { | 256 | { |
259 | int i; | 257 | int i; |
260 | 258 | ||
261 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) | 259 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) { |
262 | if (!IS_ERR_OR_NULL(state->clock[i])) | 260 | if (IS_ERR_OR_NULL(state->clock[i])) |
263 | clk_put(state->clock[i]); | 261 | continue; |
262 | clk_unprepare(state->clock[i]); | ||
263 | clk_put(state->clock[i]); | ||
264 | state->clock[i] = NULL; | ||
265 | } | ||
264 | } | 266 | } |
265 | 267 | ||
266 | static int s5pcsis_clk_get(struct csis_state *state) | 268 | static int s5pcsis_clk_get(struct csis_state *state) |
267 | { | 269 | { |
268 | struct device *dev = &state->pdev->dev; | 270 | struct device *dev = &state->pdev->dev; |
269 | int i; | 271 | int i, ret; |
270 | 272 | ||
271 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) { | 273 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) { |
272 | state->clock[i] = clk_get(dev, csi_clock_name[i]); | 274 | state->clock[i] = clk_get(dev, csi_clock_name[i]); |
273 | if (IS_ERR(state->clock[i])) { | 275 | if (IS_ERR(state->clock[i])) |
274 | s5pcsis_clk_put(state); | 276 | goto err; |
275 | dev_err(dev, "failed to get clock: %s\n", | 277 | ret = clk_prepare(state->clock[i]); |
276 | csi_clock_name[i]); | 278 | if (ret < 0) { |
277 | return -ENXIO; | 279 | clk_put(state->clock[i]); |
280 | state->clock[i] = NULL; | ||
281 | goto err; | ||
278 | } | 282 | } |
279 | } | 283 | } |
280 | return 0; | 284 | return 0; |
285 | err: | ||
286 | s5pcsis_clk_put(state); | ||
287 | dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); | ||
288 | return -ENXIO; | ||
281 | } | 289 | } |
282 | 290 | ||
283 | static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) | 291 | static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) |
@@ -480,12 +488,11 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
480 | { | 488 | { |
481 | struct s5p_platform_mipi_csis *pdata; | 489 | struct s5p_platform_mipi_csis *pdata; |
482 | struct resource *mem_res; | 490 | struct resource *mem_res; |
483 | struct resource *regs_res; | ||
484 | struct csis_state *state; | 491 | struct csis_state *state; |
485 | int ret = -ENOMEM; | 492 | int ret = -ENOMEM; |
486 | int i; | 493 | int i; |
487 | 494 | ||
488 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 495 | state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); |
489 | if (!state) | 496 | if (!state) |
490 | return -ENOMEM; | 497 | return -ENOMEM; |
491 | 498 | ||
@@ -495,52 +502,27 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
495 | pdata = pdev->dev.platform_data; | 502 | pdata = pdev->dev.platform_data; |
496 | if (pdata == NULL || pdata->phy_enable == NULL) { | 503 | if (pdata == NULL || pdata->phy_enable == NULL) { |
497 | dev_err(&pdev->dev, "Platform data not fully specified\n"); | 504 | dev_err(&pdev->dev, "Platform data not fully specified\n"); |
498 | goto e_free; | 505 | return -EINVAL; |
499 | } | 506 | } |
500 | 507 | ||
501 | if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || | 508 | if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || |
502 | pdata->lanes > CSIS0_MAX_LANES) { | 509 | pdata->lanes > CSIS0_MAX_LANES) { |
503 | ret = -EINVAL; | ||
504 | dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", | 510 | dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", |
505 | pdata->lanes); | 511 | pdata->lanes); |
506 | goto e_free; | 512 | return -EINVAL; |
507 | } | 513 | } |
508 | 514 | ||
509 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 515 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
510 | if (!mem_res) { | 516 | state->regs = devm_request_and_ioremap(&pdev->dev, mem_res); |
511 | dev_err(&pdev->dev, "Failed to get IO memory region\n"); | 517 | if (state->regs == NULL) { |
512 | goto e_free; | 518 | dev_err(&pdev->dev, "Failed to request and remap io memory\n"); |
519 | return -ENXIO; | ||
513 | } | 520 | } |
514 | 521 | ||
515 | regs_res = request_mem_region(mem_res->start, resource_size(mem_res), | ||
516 | pdev->name); | ||
517 | if (!regs_res) { | ||
518 | dev_err(&pdev->dev, "Failed to request IO memory region\n"); | ||
519 | goto e_free; | ||
520 | } | ||
521 | state->regs_res = regs_res; | ||
522 | |||
523 | state->regs = ioremap(mem_res->start, resource_size(mem_res)); | ||
524 | if (!state->regs) { | ||
525 | dev_err(&pdev->dev, "Failed to remap IO region\n"); | ||
526 | goto e_reqmem; | ||
527 | } | ||
528 | |||
529 | ret = s5pcsis_clk_get(state); | ||
530 | if (ret) | ||
531 | goto e_unmap; | ||
532 | |||
533 | clk_enable(state->clock[CSIS_CLK_MUX]); | ||
534 | if (pdata->clk_rate) | ||
535 | clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); | ||
536 | else | ||
537 | dev_WARN(&pdev->dev, "No clock frequency specified!\n"); | ||
538 | |||
539 | state->irq = platform_get_irq(pdev, 0); | 522 | state->irq = platform_get_irq(pdev, 0); |
540 | if (state->irq < 0) { | 523 | if (state->irq < 0) { |
541 | ret = state->irq; | ||
542 | dev_err(&pdev->dev, "Failed to get irq\n"); | 524 | dev_err(&pdev->dev, "Failed to get irq\n"); |
543 | goto e_clkput; | 525 | return state->irq; |
544 | } | 526 | } |
545 | 527 | ||
546 | for (i = 0; i < CSIS_NUM_SUPPLIES; i++) | 528 | for (i = 0; i < CSIS_NUM_SUPPLIES; i++) |
@@ -549,12 +531,22 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
549 | ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, | 531 | ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, |
550 | state->supplies); | 532 | state->supplies); |
551 | if (ret) | 533 | if (ret) |
534 | return ret; | ||
535 | |||
536 | ret = s5pcsis_clk_get(state); | ||
537 | if (ret) | ||
552 | goto e_clkput; | 538 | goto e_clkput; |
553 | 539 | ||
554 | ret = request_irq(state->irq, s5pcsis_irq_handler, 0, | 540 | clk_enable(state->clock[CSIS_CLK_MUX]); |
555 | dev_name(&pdev->dev), state); | 541 | if (pdata->clk_rate) |
542 | clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); | ||
543 | else | ||
544 | dev_WARN(&pdev->dev, "No clock frequency specified!\n"); | ||
545 | |||
546 | ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, | ||
547 | 0, dev_name(&pdev->dev), state); | ||
556 | if (ret) { | 548 | if (ret) { |
557 | dev_err(&pdev->dev, "request_irq failed\n"); | 549 | dev_err(&pdev->dev, "Interrupt request failed\n"); |
558 | goto e_regput; | 550 | goto e_regput; |
559 | } | 551 | } |
560 | 552 | ||
@@ -573,7 +565,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
573 | ret = media_entity_init(&state->sd.entity, | 565 | ret = media_entity_init(&state->sd.entity, |
574 | CSIS_PADS_NUM, state->pads, 0); | 566 | CSIS_PADS_NUM, state->pads, 0); |
575 | if (ret < 0) | 567 | if (ret < 0) |
576 | goto e_irqfree; | 568 | goto e_clkput; |
577 | 569 | ||
578 | /* This allows to retrieve the platform device id by the host driver */ | 570 | /* This allows to retrieve the platform device id by the host driver */ |
579 | v4l2_set_subdevdata(&state->sd, pdev); | 571 | v4l2_set_subdevdata(&state->sd, pdev); |
@@ -582,22 +574,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
582 | platform_set_drvdata(pdev, &state->sd); | 574 | platform_set_drvdata(pdev, &state->sd); |
583 | 575 | ||
584 | pm_runtime_enable(&pdev->dev); | 576 | pm_runtime_enable(&pdev->dev); |
585 | |||
586 | return 0; | 577 | return 0; |
587 | 578 | ||
588 | e_irqfree: | ||
589 | free_irq(state->irq, state); | ||
590 | e_regput: | 579 | e_regput: |
591 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); | 580 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); |
592 | e_clkput: | 581 | e_clkput: |
593 | clk_disable(state->clock[CSIS_CLK_MUX]); | 582 | clk_disable(state->clock[CSIS_CLK_MUX]); |
594 | s5pcsis_clk_put(state); | 583 | s5pcsis_clk_put(state); |
595 | e_unmap: | ||
596 | iounmap(state->regs); | ||
597 | e_reqmem: | ||
598 | release_mem_region(regs_res->start, resource_size(regs_res)); | ||
599 | e_free: | ||
600 | kfree(state); | ||
601 | return ret; | 584 | return ret; |
602 | } | 585 | } |
603 | 586 | ||
@@ -699,21 +682,15 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev) | |||
699 | { | 682 | { |
700 | struct v4l2_subdev *sd = platform_get_drvdata(pdev); | 683 | struct v4l2_subdev *sd = platform_get_drvdata(pdev); |
701 | struct csis_state *state = sd_to_csis_state(sd); | 684 | struct csis_state *state = sd_to_csis_state(sd); |
702 | struct resource *res = state->regs_res; | ||
703 | 685 | ||
704 | pm_runtime_disable(&pdev->dev); | 686 | pm_runtime_disable(&pdev->dev); |
705 | s5pcsis_suspend(&pdev->dev); | 687 | s5pcsis_pm_suspend(&pdev->dev, false); |
706 | clk_disable(state->clock[CSIS_CLK_MUX]); | 688 | clk_disable(state->clock[CSIS_CLK_MUX]); |
707 | pm_runtime_set_suspended(&pdev->dev); | 689 | pm_runtime_set_suspended(&pdev->dev); |
708 | |||
709 | s5pcsis_clk_put(state); | 690 | s5pcsis_clk_put(state); |
710 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); | 691 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); |
711 | 692 | ||
712 | media_entity_cleanup(&state->sd.entity); | 693 | media_entity_cleanup(&state->sd.entity); |
713 | free_irq(state->irq, state); | ||
714 | iounmap(state->regs); | ||
715 | release_mem_region(res->start, resource_size(res)); | ||
716 | kfree(state); | ||
717 | 694 | ||
718 | return 0; | 695 | return 0; |
719 | } | 696 | } |
diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c b/drivers/media/video/s5p-g2d/g2d-hw.c index 39937cf03c88..5b86cbe408e2 100644 --- a/drivers/media/video/s5p-g2d/g2d-hw.c +++ b/drivers/media/video/s5p-g2d/g2d-hw.c | |||
@@ -77,6 +77,11 @@ void g2d_set_rop4(struct g2d_dev *d, u32 r) | |||
77 | w(r, ROP4_REG); | 77 | w(r, ROP4_REG); |
78 | } | 78 | } |
79 | 79 | ||
80 | void g2d_set_flip(struct g2d_dev *d, u32 r) | ||
81 | { | ||
82 | w(r, SRC_MSK_DIRECT_REG); | ||
83 | } | ||
84 | |||
80 | u32 g2d_cmd_stretch(u32 e) | 85 | u32 g2d_cmd_stretch(u32 e) |
81 | { | 86 | { |
82 | e &= 1; | 87 | e &= 1; |
diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c index febaa673d363..789de74014e5 100644 --- a/drivers/media/video/s5p-g2d/g2d.c +++ b/drivers/media/video/s5p-g2d/g2d.c | |||
@@ -178,6 +178,9 @@ static int g2d_s_ctrl(struct v4l2_ctrl *ctrl) | |||
178 | { | 178 | { |
179 | struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, | 179 | struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, |
180 | ctrl_handler); | 180 | ctrl_handler); |
181 | unsigned long flags; | ||
182 | |||
183 | spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); | ||
181 | switch (ctrl->id) { | 184 | switch (ctrl->id) { |
182 | case V4L2_CID_COLORFX: | 185 | case V4L2_CID_COLORFX: |
183 | if (ctrl->val == V4L2_COLORFX_NEGATIVE) | 186 | if (ctrl->val == V4L2_COLORFX_NEGATIVE) |
@@ -185,10 +188,13 @@ static int g2d_s_ctrl(struct v4l2_ctrl *ctrl) | |||
185 | else | 188 | else |
186 | ctx->rop = ROP4_COPY; | 189 | ctx->rop = ROP4_COPY; |
187 | break; | 190 | break; |
188 | default: | 191 | |
189 | v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n"); | 192 | case V4L2_CID_HFLIP: |
190 | return -EINVAL; | 193 | ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1); |
194 | break; | ||
195 | |||
191 | } | 196 | } |
197 | spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); | ||
192 | return 0; | 198 | return 0; |
193 | } | 199 | } |
194 | 200 | ||
@@ -200,11 +206,13 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx) | |||
200 | { | 206 | { |
201 | struct g2d_dev *dev = ctx->dev; | 207 | struct g2d_dev *dev = ctx->dev; |
202 | 208 | ||
203 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); | 209 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); |
204 | if (ctx->ctrl_handler.error) { | 210 | |
205 | v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); | 211 | ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, |
206 | return ctx->ctrl_handler.error; | 212 | V4L2_CID_HFLIP, 0, 1, 1, 0); |
207 | } | 213 | |
214 | ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, | ||
215 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
208 | 216 | ||
209 | v4l2_ctrl_new_std_menu( | 217 | v4l2_ctrl_new_std_menu( |
210 | &ctx->ctrl_handler, | 218 | &ctx->ctrl_handler, |
@@ -215,10 +223,14 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx) | |||
215 | V4L2_COLORFX_NONE); | 223 | V4L2_COLORFX_NONE); |
216 | 224 | ||
217 | if (ctx->ctrl_handler.error) { | 225 | if (ctx->ctrl_handler.error) { |
218 | v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); | 226 | int err = ctx->ctrl_handler.error; |
219 | return ctx->ctrl_handler.error; | 227 | v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n"); |
228 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
229 | return err; | ||
220 | } | 230 | } |
221 | 231 | ||
232 | v4l2_ctrl_cluster(2, &ctx->ctrl_hflip); | ||
233 | |||
222 | return 0; | 234 | return 0; |
223 | } | 235 | } |
224 | 236 | ||
@@ -547,6 +559,7 @@ static void device_run(void *prv) | |||
547 | struct g2d_ctx *ctx = prv; | 559 | struct g2d_ctx *ctx = prv; |
548 | struct g2d_dev *dev = ctx->dev; | 560 | struct g2d_dev *dev = ctx->dev; |
549 | struct vb2_buffer *src, *dst; | 561 | struct vb2_buffer *src, *dst; |
562 | unsigned long flags; | ||
550 | u32 cmd = 0; | 563 | u32 cmd = 0; |
551 | 564 | ||
552 | dev->curr = ctx; | 565 | dev->curr = ctx; |
@@ -557,6 +570,8 @@ static void device_run(void *prv) | |||
557 | clk_enable(dev->gate); | 570 | clk_enable(dev->gate); |
558 | g2d_reset(dev); | 571 | g2d_reset(dev); |
559 | 572 | ||
573 | spin_lock_irqsave(&dev->ctrl_lock, flags); | ||
574 | |||
560 | g2d_set_src_size(dev, &ctx->in); | 575 | g2d_set_src_size(dev, &ctx->in); |
561 | g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0)); | 576 | g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0)); |
562 | 577 | ||
@@ -564,11 +579,15 @@ static void device_run(void *prv) | |||
564 | g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); | 579 | g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); |
565 | 580 | ||
566 | g2d_set_rop4(dev, ctx->rop); | 581 | g2d_set_rop4(dev, ctx->rop); |
582 | g2d_set_flip(dev, ctx->flip); | ||
583 | |||
567 | if (ctx->in.c_width != ctx->out.c_width || | 584 | if (ctx->in.c_width != ctx->out.c_width || |
568 | ctx->in.c_height != ctx->out.c_height) | 585 | ctx->in.c_height != ctx->out.c_height) |
569 | cmd |= g2d_cmd_stretch(1); | 586 | cmd |= g2d_cmd_stretch(1); |
570 | g2d_set_cmd(dev, cmd); | 587 | g2d_set_cmd(dev, cmd); |
571 | g2d_start(dev); | 588 | g2d_start(dev); |
589 | |||
590 | spin_unlock_irqrestore(&dev->ctrl_lock, flags); | ||
572 | } | 591 | } |
573 | 592 | ||
574 | static irqreturn_t g2d_isr(int irq, void *prv) | 593 | static irqreturn_t g2d_isr(int irq, void *prv) |
@@ -658,7 +677,7 @@ static int g2d_probe(struct platform_device *pdev) | |||
658 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 677 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
659 | if (!dev) | 678 | if (!dev) |
660 | return -ENOMEM; | 679 | return -ENOMEM; |
661 | spin_lock_init(&dev->irqlock); | 680 | spin_lock_init(&dev->ctrl_lock); |
662 | mutex_init(&dev->mutex); | 681 | mutex_init(&dev->mutex); |
663 | atomic_set(&dev->num_inst, 0); | 682 | atomic_set(&dev->num_inst, 0); |
664 | init_waitqueue_head(&dev->irq_queue); | 683 | init_waitqueue_head(&dev->irq_queue); |
@@ -693,18 +712,30 @@ static int g2d_probe(struct platform_device *pdev) | |||
693 | goto unmap_regs; | 712 | goto unmap_regs; |
694 | } | 713 | } |
695 | 714 | ||
715 | ret = clk_prepare(dev->clk); | ||
716 | if (ret) { | ||
717 | dev_err(&pdev->dev, "failed to prepare g2d clock\n"); | ||
718 | goto put_clk; | ||
719 | } | ||
720 | |||
696 | dev->gate = clk_get(&pdev->dev, "fimg2d"); | 721 | dev->gate = clk_get(&pdev->dev, "fimg2d"); |
697 | if (IS_ERR_OR_NULL(dev->gate)) { | 722 | if (IS_ERR_OR_NULL(dev->gate)) { |
698 | dev_err(&pdev->dev, "failed to get g2d clock gate\n"); | 723 | dev_err(&pdev->dev, "failed to get g2d clock gate\n"); |
699 | ret = -ENXIO; | 724 | ret = -ENXIO; |
700 | goto put_clk; | 725 | goto unprep_clk; |
726 | } | ||
727 | |||
728 | ret = clk_prepare(dev->gate); | ||
729 | if (ret) { | ||
730 | dev_err(&pdev->dev, "failed to prepare g2d clock gate\n"); | ||
731 | goto put_clk_gate; | ||
701 | } | 732 | } |
702 | 733 | ||
703 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 734 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
704 | if (!res) { | 735 | if (!res) { |
705 | dev_err(&pdev->dev, "failed to find IRQ\n"); | 736 | dev_err(&pdev->dev, "failed to find IRQ\n"); |
706 | ret = -ENXIO; | 737 | ret = -ENXIO; |
707 | goto put_clk_gate; | 738 | goto unprep_clk_gate; |
708 | } | 739 | } |
709 | 740 | ||
710 | dev->irq = res->start; | 741 | dev->irq = res->start; |
@@ -764,8 +795,12 @@ alloc_ctx_cleanup: | |||
764 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | 795 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); |
765 | rel_irq: | 796 | rel_irq: |
766 | free_irq(dev->irq, dev); | 797 | free_irq(dev->irq, dev); |
798 | unprep_clk_gate: | ||
799 | clk_unprepare(dev->gate); | ||
767 | put_clk_gate: | 800 | put_clk_gate: |
768 | clk_put(dev->gate); | 801 | clk_put(dev->gate); |
802 | unprep_clk: | ||
803 | clk_unprepare(dev->clk); | ||
769 | put_clk: | 804 | put_clk: |
770 | clk_put(dev->clk); | 805 | clk_put(dev->clk); |
771 | unmap_regs: | 806 | unmap_regs: |
@@ -787,7 +822,9 @@ static int g2d_remove(struct platform_device *pdev) | |||
787 | v4l2_device_unregister(&dev->v4l2_dev); | 822 | v4l2_device_unregister(&dev->v4l2_dev); |
788 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | 823 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); |
789 | free_irq(dev->irq, dev); | 824 | free_irq(dev->irq, dev); |
825 | clk_unprepare(dev->gate); | ||
790 | clk_put(dev->gate); | 826 | clk_put(dev->gate); |
827 | clk_unprepare(dev->clk); | ||
791 | clk_put(dev->clk); | 828 | clk_put(dev->clk); |
792 | iounmap(dev->regs); | 829 | iounmap(dev->regs); |
793 | release_resource(dev->res_regs); | 830 | release_resource(dev->res_regs); |
diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h index 5eae90107bf8..1b82065aeaef 100644 --- a/drivers/media/video/s5p-g2d/g2d.h +++ b/drivers/media/video/s5p-g2d/g2d.h | |||
@@ -20,7 +20,7 @@ struct g2d_dev { | |||
20 | struct v4l2_m2m_dev *m2m_dev; | 20 | struct v4l2_m2m_dev *m2m_dev; |
21 | struct video_device *vfd; | 21 | struct video_device *vfd; |
22 | struct mutex mutex; | 22 | struct mutex mutex; |
23 | spinlock_t irqlock; | 23 | spinlock_t ctrl_lock; |
24 | atomic_t num_inst; | 24 | atomic_t num_inst; |
25 | struct vb2_alloc_ctx *alloc_ctx; | 25 | struct vb2_alloc_ctx *alloc_ctx; |
26 | struct resource *res_regs; | 26 | struct resource *res_regs; |
@@ -57,8 +57,11 @@ struct g2d_ctx { | |||
57 | struct v4l2_m2m_ctx *m2m_ctx; | 57 | struct v4l2_m2m_ctx *m2m_ctx; |
58 | struct g2d_frame in; | 58 | struct g2d_frame in; |
59 | struct g2d_frame out; | 59 | struct g2d_frame out; |
60 | struct v4l2_ctrl *ctrl_hflip; | ||
61 | struct v4l2_ctrl *ctrl_vflip; | ||
60 | struct v4l2_ctrl_handler ctrl_handler; | 62 | struct v4l2_ctrl_handler ctrl_handler; |
61 | u32 rop; | 63 | u32 rop; |
64 | u32 flip; | ||
62 | }; | 65 | }; |
63 | 66 | ||
64 | struct g2d_fmt { | 67 | struct g2d_fmt { |
@@ -77,6 +80,7 @@ void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a); | |||
77 | void g2d_start(struct g2d_dev *d); | 80 | void g2d_start(struct g2d_dev *d); |
78 | void g2d_clear_int(struct g2d_dev *d); | 81 | void g2d_clear_int(struct g2d_dev *d); |
79 | void g2d_set_rop4(struct g2d_dev *d, u32 r); | 82 | void g2d_set_rop4(struct g2d_dev *d, u32 r); |
83 | void g2d_set_flip(struct g2d_dev *d, u32 r); | ||
80 | u32 g2d_cmd_stretch(u32 e); | 84 | u32 g2d_cmd_stretch(u32 e); |
81 | void g2d_set_cmd(struct g2d_dev *d, u32 c); | 85 | void g2d_set_cmd(struct g2d_dev *d, u32 c); |
82 | 86 | ||
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c index 1105a8749c8b..5a49c307f9c1 100644 --- a/drivers/media/video/s5p-jpeg/jpeg-core.c +++ b/drivers/media/video/s5p-jpeg/jpeg-core.c | |||
@@ -32,10 +32,9 @@ | |||
32 | 32 | ||
33 | static struct s5p_jpeg_fmt formats_enc[] = { | 33 | static struct s5p_jpeg_fmt formats_enc[] = { |
34 | { | 34 | { |
35 | .name = "YUV 4:2:0 planar, YCbCr", | 35 | .name = "JPEG JFIF", |
36 | .fourcc = V4L2_PIX_FMT_YUV420, | 36 | .fourcc = V4L2_PIX_FMT_JPEG, |
37 | .depth = 12, | 37 | .colplanes = 1, |
38 | .colplanes = 3, | ||
39 | .types = MEM2MEM_CAPTURE, | 38 | .types = MEM2MEM_CAPTURE, |
40 | }, | 39 | }, |
41 | { | 40 | { |
@@ -43,7 +42,7 @@ static struct s5p_jpeg_fmt formats_enc[] = { | |||
43 | .fourcc = V4L2_PIX_FMT_YUYV, | 42 | .fourcc = V4L2_PIX_FMT_YUYV, |
44 | .depth = 16, | 43 | .depth = 16, |
45 | .colplanes = 1, | 44 | .colplanes = 1, |
46 | .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, | 45 | .types = MEM2MEM_OUTPUT, |
47 | }, | 46 | }, |
48 | { | 47 | { |
49 | .name = "RGB565", | 48 | .name = "RGB565", |
@@ -203,6 +202,16 @@ static const unsigned char hactblg0[162] = { | |||
203 | 0xf9, 0xfa | 202 | 0xf9, 0xfa |
204 | }; | 203 | }; |
205 | 204 | ||
205 | static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) | ||
206 | { | ||
207 | return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler); | ||
208 | } | ||
209 | |||
210 | static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) | ||
211 | { | ||
212 | return container_of(fh, struct s5p_jpeg_ctx, fh); | ||
213 | } | ||
214 | |||
206 | static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, | 215 | static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, |
207 | unsigned long tab, int len) | 216 | unsigned long tab, int len) |
208 | { | 217 | { |
@@ -269,6 +278,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, | |||
269 | struct vb2_queue *dst_vq); | 278 | struct vb2_queue *dst_vq); |
270 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, | 279 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, |
271 | __u32 pixelformat); | 280 | __u32 pixelformat); |
281 | static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx); | ||
272 | 282 | ||
273 | static int s5p_jpeg_open(struct file *file) | 283 | static int s5p_jpeg_open(struct file *file) |
274 | { | 284 | { |
@@ -276,12 +286,18 @@ static int s5p_jpeg_open(struct file *file) | |||
276 | struct video_device *vfd = video_devdata(file); | 286 | struct video_device *vfd = video_devdata(file); |
277 | struct s5p_jpeg_ctx *ctx; | 287 | struct s5p_jpeg_ctx *ctx; |
278 | struct s5p_jpeg_fmt *out_fmt; | 288 | struct s5p_jpeg_fmt *out_fmt; |
289 | int ret = 0; | ||
279 | 290 | ||
280 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); | 291 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); |
281 | if (!ctx) | 292 | if (!ctx) |
282 | return -ENOMEM; | 293 | return -ENOMEM; |
283 | 294 | ||
284 | file->private_data = ctx; | 295 | v4l2_fh_init(&ctx->fh, vfd); |
296 | /* Use separate control handler per file handle */ | ||
297 | ctx->fh.ctrl_handler = &ctx->ctrl_handler; | ||
298 | file->private_data = &ctx->fh; | ||
299 | v4l2_fh_add(&ctx->fh); | ||
300 | |||
285 | ctx->jpeg = jpeg; | 301 | ctx->jpeg = jpeg; |
286 | if (vfd == jpeg->vfd_encoder) { | 302 | if (vfd == jpeg->vfd_encoder) { |
287 | ctx->mode = S5P_JPEG_ENCODE; | 303 | ctx->mode = S5P_JPEG_ENCODE; |
@@ -291,24 +307,35 @@ static int s5p_jpeg_open(struct file *file) | |||
291 | out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); | 307 | out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); |
292 | } | 308 | } |
293 | 309 | ||
310 | ret = s5p_jpeg_controls_create(ctx); | ||
311 | if (ret < 0) | ||
312 | goto error; | ||
313 | |||
294 | ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); | 314 | ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); |
295 | if (IS_ERR(ctx->m2m_ctx)) { | 315 | if (IS_ERR(ctx->m2m_ctx)) { |
296 | int err = PTR_ERR(ctx->m2m_ctx); | 316 | ret = PTR_ERR(ctx->m2m_ctx); |
297 | kfree(ctx); | 317 | goto error; |
298 | return err; | ||
299 | } | 318 | } |
300 | 319 | ||
301 | ctx->out_q.fmt = out_fmt; | 320 | ctx->out_q.fmt = out_fmt; |
302 | ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); | 321 | ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); |
303 | |||
304 | return 0; | 322 | return 0; |
323 | |||
324 | error: | ||
325 | v4l2_fh_del(&ctx->fh); | ||
326 | v4l2_fh_exit(&ctx->fh); | ||
327 | kfree(ctx); | ||
328 | return ret; | ||
305 | } | 329 | } |
306 | 330 | ||
307 | static int s5p_jpeg_release(struct file *file) | 331 | static int s5p_jpeg_release(struct file *file) |
308 | { | 332 | { |
309 | struct s5p_jpeg_ctx *ctx = file->private_data; | 333 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); |
310 | 334 | ||
311 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | 335 | v4l2_m2m_ctx_release(ctx->m2m_ctx); |
336 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
337 | v4l2_fh_del(&ctx->fh); | ||
338 | v4l2_fh_exit(&ctx->fh); | ||
312 | kfree(ctx); | 339 | kfree(ctx); |
313 | 340 | ||
314 | return 0; | 341 | return 0; |
@@ -317,14 +344,14 @@ static int s5p_jpeg_release(struct file *file) | |||
317 | static unsigned int s5p_jpeg_poll(struct file *file, | 344 | static unsigned int s5p_jpeg_poll(struct file *file, |
318 | struct poll_table_struct *wait) | 345 | struct poll_table_struct *wait) |
319 | { | 346 | { |
320 | struct s5p_jpeg_ctx *ctx = file->private_data; | 347 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); |
321 | 348 | ||
322 | return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | 349 | return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); |
323 | } | 350 | } |
324 | 351 | ||
325 | static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) | 352 | static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) |
326 | { | 353 | { |
327 | struct s5p_jpeg_ctx *ctx = file->private_data; | 354 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); |
328 | 355 | ||
329 | return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | 356 | return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); |
330 | } | 357 | } |
@@ -448,7 +475,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, | |||
448 | static int s5p_jpeg_querycap(struct file *file, void *priv, | 475 | static int s5p_jpeg_querycap(struct file *file, void *priv, |
449 | struct v4l2_capability *cap) | 476 | struct v4l2_capability *cap) |
450 | { | 477 | { |
451 | struct s5p_jpeg_ctx *ctx = priv; | 478 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
452 | 479 | ||
453 | if (ctx->mode == S5P_JPEG_ENCODE) { | 480 | if (ctx->mode == S5P_JPEG_ENCODE) { |
454 | strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", | 481 | strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", |
@@ -497,9 +524,7 @@ static int enum_fmt(struct s5p_jpeg_fmt *formats, int n, | |||
497 | static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, | 524 | static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, |
498 | struct v4l2_fmtdesc *f) | 525 | struct v4l2_fmtdesc *f) |
499 | { | 526 | { |
500 | struct s5p_jpeg_ctx *ctx; | 527 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
501 | |||
502 | ctx = priv; | ||
503 | 528 | ||
504 | if (ctx->mode == S5P_JPEG_ENCODE) | 529 | if (ctx->mode == S5P_JPEG_ENCODE) |
505 | return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, | 530 | return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, |
@@ -511,9 +536,7 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, | |||
511 | static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, | 536 | static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, |
512 | struct v4l2_fmtdesc *f) | 537 | struct v4l2_fmtdesc *f) |
513 | { | 538 | { |
514 | struct s5p_jpeg_ctx *ctx; | 539 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
515 | |||
516 | ctx = priv; | ||
517 | 540 | ||
518 | if (ctx->mode == S5P_JPEG_ENCODE) | 541 | if (ctx->mode == S5P_JPEG_ENCODE) |
519 | return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, | 542 | return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, |
@@ -538,7 +561,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
538 | struct vb2_queue *vq; | 561 | struct vb2_queue *vq; |
539 | struct s5p_jpeg_q_data *q_data = NULL; | 562 | struct s5p_jpeg_q_data *q_data = NULL; |
540 | struct v4l2_pix_format *pix = &f->fmt.pix; | 563 | struct v4l2_pix_format *pix = &f->fmt.pix; |
541 | struct s5p_jpeg_ctx *ct = priv; | 564 | struct s5p_jpeg_ctx *ct = fh_to_ctx(priv); |
542 | 565 | ||
543 | vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); | 566 | vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); |
544 | if (!vq) | 567 | if (!vq) |
@@ -659,8 +682,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, | |||
659 | static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, | 682 | static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, |
660 | struct v4l2_format *f) | 683 | struct v4l2_format *f) |
661 | { | 684 | { |
685 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
662 | struct s5p_jpeg_fmt *fmt; | 686 | struct s5p_jpeg_fmt *fmt; |
663 | struct s5p_jpeg_ctx *ctx = priv; | ||
664 | 687 | ||
665 | fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); | 688 | fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); |
666 | if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { | 689 | if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { |
@@ -676,8 +699,8 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, | |||
676 | static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, | 699 | static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, |
677 | struct v4l2_format *f) | 700 | struct v4l2_format *f) |
678 | { | 701 | { |
702 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
679 | struct s5p_jpeg_fmt *fmt; | 703 | struct s5p_jpeg_fmt *fmt; |
680 | struct s5p_jpeg_ctx *ctx = priv; | ||
681 | 704 | ||
682 | fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); | 705 | fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); |
683 | if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { | 706 | if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { |
@@ -728,7 +751,7 @@ static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv, | |||
728 | if (ret) | 751 | if (ret) |
729 | return ret; | 752 | return ret; |
730 | 753 | ||
731 | return s5p_jpeg_s_fmt(priv, f); | 754 | return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); |
732 | } | 755 | } |
733 | 756 | ||
734 | static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, | 757 | static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, |
@@ -740,13 +763,13 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, | |||
740 | if (ret) | 763 | if (ret) |
741 | return ret; | 764 | return ret; |
742 | 765 | ||
743 | return s5p_jpeg_s_fmt(priv, f); | 766 | return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); |
744 | } | 767 | } |
745 | 768 | ||
746 | static int s5p_jpeg_reqbufs(struct file *file, void *priv, | 769 | static int s5p_jpeg_reqbufs(struct file *file, void *priv, |
747 | struct v4l2_requestbuffers *reqbufs) | 770 | struct v4l2_requestbuffers *reqbufs) |
748 | { | 771 | { |
749 | struct s5p_jpeg_ctx *ctx = priv; | 772 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
750 | 773 | ||
751 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | 774 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); |
752 | } | 775 | } |
@@ -754,14 +777,14 @@ static int s5p_jpeg_reqbufs(struct file *file, void *priv, | |||
754 | static int s5p_jpeg_querybuf(struct file *file, void *priv, | 777 | static int s5p_jpeg_querybuf(struct file *file, void *priv, |
755 | struct v4l2_buffer *buf) | 778 | struct v4l2_buffer *buf) |
756 | { | 779 | { |
757 | struct s5p_jpeg_ctx *ctx = priv; | 780 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
758 | 781 | ||
759 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); | 782 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); |
760 | } | 783 | } |
761 | 784 | ||
762 | static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | 785 | static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) |
763 | { | 786 | { |
764 | struct s5p_jpeg_ctx *ctx = priv; | 787 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
765 | 788 | ||
766 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | 789 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); |
767 | } | 790 | } |
@@ -769,7 +792,7 @@ static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | |||
769 | static int s5p_jpeg_dqbuf(struct file *file, void *priv, | 792 | static int s5p_jpeg_dqbuf(struct file *file, void *priv, |
770 | struct v4l2_buffer *buf) | 793 | struct v4l2_buffer *buf) |
771 | { | 794 | { |
772 | struct s5p_jpeg_ctx *ctx = priv; | 795 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
773 | 796 | ||
774 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | 797 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); |
775 | } | 798 | } |
@@ -777,7 +800,7 @@ static int s5p_jpeg_dqbuf(struct file *file, void *priv, | |||
777 | static int s5p_jpeg_streamon(struct file *file, void *priv, | 800 | static int s5p_jpeg_streamon(struct file *file, void *priv, |
778 | enum v4l2_buf_type type) | 801 | enum v4l2_buf_type type) |
779 | { | 802 | { |
780 | struct s5p_jpeg_ctx *ctx = priv; | 803 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
781 | 804 | ||
782 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); | 805 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); |
783 | } | 806 | } |
@@ -785,7 +808,7 @@ static int s5p_jpeg_streamon(struct file *file, void *priv, | |||
785 | static int s5p_jpeg_streamoff(struct file *file, void *priv, | 808 | static int s5p_jpeg_streamoff(struct file *file, void *priv, |
786 | enum v4l2_buf_type type) | 809 | enum v4l2_buf_type type) |
787 | { | 810 | { |
788 | struct s5p_jpeg_ctx *ctx = priv; | 811 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
789 | 812 | ||
790 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | 813 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); |
791 | } | 814 | } |
@@ -793,7 +816,7 @@ static int s5p_jpeg_streamoff(struct file *file, void *priv, | |||
793 | int s5p_jpeg_g_selection(struct file *file, void *priv, | 816 | int s5p_jpeg_g_selection(struct file *file, void *priv, |
794 | struct v4l2_selection *s) | 817 | struct v4l2_selection *s) |
795 | { | 818 | { |
796 | struct s5p_jpeg_ctx *ctx = priv; | 819 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
797 | 820 | ||
798 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 821 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
799 | s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 822 | s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
@@ -822,33 +845,89 @@ int s5p_jpeg_g_selection(struct file *file, void *priv, | |||
822 | return 0; | 845 | return 0; |
823 | } | 846 | } |
824 | 847 | ||
825 | static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, | 848 | /* |
826 | struct v4l2_jpegcompression *compr) | 849 | * V4L2 controls |
850 | */ | ||
851 | |||
852 | static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
827 | { | 853 | { |
828 | struct s5p_jpeg_ctx *ctx = priv; | 854 | struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); |
855 | struct s5p_jpeg *jpeg = ctx->jpeg; | ||
856 | unsigned long flags; | ||
829 | 857 | ||
830 | if (ctx->mode == S5P_JPEG_DECODE) | 858 | switch (ctrl->id) { |
831 | return -ENOTTY; | 859 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: |
860 | spin_lock_irqsave(&jpeg->slock, flags); | ||
832 | 861 | ||
833 | memset(compr, 0, sizeof(*compr)); | 862 | WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY); |
834 | compr->quality = ctx->compr_quality; | 863 | if (ctx->subsampling > 2) |
864 | ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; | ||
865 | else | ||
866 | ctrl->val = ctx->subsampling; | ||
867 | spin_unlock_irqrestore(&jpeg->slock, flags); | ||
868 | break; | ||
869 | } | ||
835 | 870 | ||
836 | return 0; | 871 | return 0; |
837 | } | 872 | } |
838 | 873 | ||
839 | static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, | 874 | static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) |
840 | struct v4l2_jpegcompression *compr) | ||
841 | { | 875 | { |
842 | struct s5p_jpeg_ctx *ctx = priv; | 876 | struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); |
877 | unsigned long flags; | ||
843 | 878 | ||
844 | if (ctx->mode == S5P_JPEG_DECODE) | 879 | spin_lock_irqsave(&ctx->jpeg->slock, flags); |
845 | return -ENOTTY; | ||
846 | 880 | ||
847 | compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST, | 881 | switch (ctrl->id) { |
848 | S5P_JPEG_COMPR_QUAL_WORST); | 882 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: |
883 | ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val; | ||
884 | break; | ||
885 | case V4L2_CID_JPEG_RESTART_INTERVAL: | ||
886 | ctx->restart_interval = ctrl->val; | ||
887 | break; | ||
888 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: | ||
889 | ctx->subsampling = ctrl->val; | ||
890 | break; | ||
891 | } | ||
849 | 892 | ||
850 | ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality; | 893 | spin_unlock_irqrestore(&ctx->jpeg->slock, flags); |
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = { | ||
898 | .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl, | ||
899 | .s_ctrl = s5p_jpeg_s_ctrl, | ||
900 | }; | ||
851 | 901 | ||
902 | static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) | ||
903 | { | ||
904 | unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */ | ||
905 | struct v4l2_ctrl *ctrl; | ||
906 | |||
907 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); | ||
908 | |||
909 | if (ctx->mode == S5P_JPEG_ENCODE) { | ||
910 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, | ||
911 | V4L2_CID_JPEG_COMPRESSION_QUALITY, | ||
912 | 0, 3, 1, 3); | ||
913 | |||
914 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, | ||
915 | V4L2_CID_JPEG_RESTART_INTERVAL, | ||
916 | 0, 3, 0xffff, 0); | ||
917 | mask = ~0x06; /* 422, 420 */ | ||
918 | } | ||
919 | |||
920 | ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, | ||
921 | V4L2_CID_JPEG_CHROMA_SUBSAMPLING, | ||
922 | V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask, | ||
923 | V4L2_JPEG_CHROMA_SUBSAMPLING_422); | ||
924 | |||
925 | if (ctx->ctrl_handler.error) | ||
926 | return ctx->ctrl_handler.error; | ||
927 | |||
928 | if (ctx->mode == S5P_JPEG_DECODE) | ||
929 | ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | | ||
930 | V4L2_CTRL_FLAG_READ_ONLY; | ||
852 | return 0; | 931 | return 0; |
853 | } | 932 | } |
854 | 933 | ||
@@ -877,9 +956,6 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { | |||
877 | .vidioc_streamoff = s5p_jpeg_streamoff, | 956 | .vidioc_streamoff = s5p_jpeg_streamoff, |
878 | 957 | ||
879 | .vidioc_g_selection = s5p_jpeg_g_selection, | 958 | .vidioc_g_selection = s5p_jpeg_g_selection, |
880 | |||
881 | .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp, | ||
882 | .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp, | ||
883 | }; | 959 | }; |
884 | 960 | ||
885 | /* | 961 | /* |
@@ -908,13 +984,8 @@ static void s5p_jpeg_device_run(void *priv) | |||
908 | jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); | 984 | jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); |
909 | else | 985 | else |
910 | jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); | 986 | jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); |
911 | if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) | 987 | jpeg_subsampling_mode(jpeg->regs, ctx->subsampling); |
912 | jpeg_subsampling_mode(jpeg->regs, | 988 | jpeg_dri(jpeg->regs, ctx->restart_interval); |
913 | S5P_JPEG_SUBSAMPLING_422); | ||
914 | else | ||
915 | jpeg_subsampling_mode(jpeg->regs, | ||
916 | S5P_JPEG_SUBSAMPLING_420); | ||
917 | jpeg_dri(jpeg->regs, 0); | ||
918 | jpeg_x(jpeg->regs, ctx->out_q.w); | 989 | jpeg_x(jpeg->regs, ctx->out_q.w); |
919 | jpeg_y(jpeg->regs, ctx->out_q.h); | 990 | jpeg_y(jpeg->regs, ctx->out_q.h); |
920 | jpeg_imgadr(jpeg->regs, src_addr); | 991 | jpeg_imgadr(jpeg->regs, src_addr); |
@@ -953,14 +1024,18 @@ static void s5p_jpeg_device_run(void *priv) | |||
953 | jpeg_htbl_dc(jpeg->regs, 2); | 1024 | jpeg_htbl_dc(jpeg->regs, 2); |
954 | jpeg_htbl_ac(jpeg->regs, 3); | 1025 | jpeg_htbl_ac(jpeg->regs, 3); |
955 | jpeg_htbl_dc(jpeg->regs, 3); | 1026 | jpeg_htbl_dc(jpeg->regs, 3); |
956 | } else { | 1027 | } else { /* S5P_JPEG_DECODE */ |
957 | jpeg_rst_int_enable(jpeg->regs, true); | 1028 | jpeg_rst_int_enable(jpeg->regs, true); |
958 | jpeg_data_num_int_enable(jpeg->regs, true); | 1029 | jpeg_data_num_int_enable(jpeg->regs, true); |
959 | jpeg_final_mcu_num_int_enable(jpeg->regs, true); | 1030 | jpeg_final_mcu_num_int_enable(jpeg->regs, true); |
960 | jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); | 1031 | if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) |
1032 | jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); | ||
1033 | else | ||
1034 | jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420); | ||
961 | jpeg_jpgadr(jpeg->regs, src_addr); | 1035 | jpeg_jpgadr(jpeg->regs, src_addr); |
962 | jpeg_imgadr(jpeg->regs, dst_addr); | 1036 | jpeg_imgadr(jpeg->regs, dst_addr); |
963 | } | 1037 | } |
1038 | |||
964 | jpeg_start(jpeg->regs); | 1039 | jpeg_start(jpeg->regs); |
965 | } | 1040 | } |
966 | 1041 | ||
@@ -1162,6 +1237,8 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) | |||
1162 | bool timer_elapsed = false; | 1237 | bool timer_elapsed = false; |
1163 | bool op_completed = false; | 1238 | bool op_completed = false; |
1164 | 1239 | ||
1240 | spin_lock(&jpeg->slock); | ||
1241 | |||
1165 | curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); | 1242 | curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); |
1166 | 1243 | ||
1167 | src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); | 1244 | src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); |
@@ -1192,6 +1269,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) | |||
1192 | v4l2_m2m_buf_done(dst_buf, state); | 1269 | v4l2_m2m_buf_done(dst_buf, state); |
1193 | v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); | 1270 | v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); |
1194 | 1271 | ||
1272 | curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs); | ||
1273 | spin_unlock(&jpeg->slock); | ||
1274 | |||
1195 | jpeg_clear_int(jpeg->regs); | 1275 | jpeg_clear_int(jpeg->regs); |
1196 | 1276 | ||
1197 | return IRQ_HANDLED; | 1277 | return IRQ_HANDLED; |
@@ -1215,6 +1295,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
1215 | return -ENOMEM; | 1295 | return -ENOMEM; |
1216 | 1296 | ||
1217 | mutex_init(&jpeg->lock); | 1297 | mutex_init(&jpeg->lock); |
1298 | spin_lock_init(&jpeg->slock); | ||
1218 | jpeg->dev = &pdev->dev; | 1299 | jpeg->dev = &pdev->dev; |
1219 | 1300 | ||
1220 | /* memory-mapped registers */ | 1301 | /* memory-mapped registers */ |
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h index facad6114f5e..38d7367f7a6d 100644 --- a/drivers/media/video/s5p-jpeg/jpeg-core.h +++ b/drivers/media/video/s5p-jpeg/jpeg-core.h | |||
@@ -14,6 +14,8 @@ | |||
14 | #define JPEG_CORE_H_ | 14 | #define JPEG_CORE_H_ |
15 | 15 | ||
16 | #include <media/v4l2-device.h> | 16 | #include <media/v4l2-device.h> |
17 | #include <media/v4l2-fh.h> | ||
18 | #include <media/v4l2-ctrls.h> | ||
17 | 19 | ||
18 | #define S5P_JPEG_M2M_NAME "s5p-jpeg" | 20 | #define S5P_JPEG_M2M_NAME "s5p-jpeg" |
19 | 21 | ||
@@ -47,6 +49,7 @@ | |||
47 | /** | 49 | /** |
48 | * struct s5p_jpeg - JPEG IP abstraction | 50 | * struct s5p_jpeg - JPEG IP abstraction |
49 | * @lock: the mutex protecting this structure | 51 | * @lock: the mutex protecting this structure |
52 | * @slock: spinlock protecting the device contexts | ||
50 | * @v4l2_dev: v4l2 device for mem2mem mode | 53 | * @v4l2_dev: v4l2 device for mem2mem mode |
51 | * @vfd_encoder: video device node for encoder mem2mem mode | 54 | * @vfd_encoder: video device node for encoder mem2mem mode |
52 | * @vfd_decoder: video device node for decoder mem2mem mode | 55 | * @vfd_decoder: video device node for decoder mem2mem mode |
@@ -60,6 +63,7 @@ | |||
60 | */ | 63 | */ |
61 | struct s5p_jpeg { | 64 | struct s5p_jpeg { |
62 | struct mutex lock; | 65 | struct mutex lock; |
66 | struct spinlock slock; | ||
63 | 67 | ||
64 | struct v4l2_device v4l2_dev; | 68 | struct v4l2_device v4l2_dev; |
65 | struct video_device *vfd_encoder; | 69 | struct video_device *vfd_encoder; |
@@ -117,15 +121,20 @@ struct s5p_jpeg_q_data { | |||
117 | * @out_q: source (output) queue information | 121 | * @out_q: source (output) queue information |
118 | * @cap_fmt: destination (capture) queue queue information | 122 | * @cap_fmt: destination (capture) queue queue information |
119 | * @hdr_parsed: set if header has been parsed during decompression | 123 | * @hdr_parsed: set if header has been parsed during decompression |
124 | * @ctrl_handler: controls handler | ||
120 | */ | 125 | */ |
121 | struct s5p_jpeg_ctx { | 126 | struct s5p_jpeg_ctx { |
122 | struct s5p_jpeg *jpeg; | 127 | struct s5p_jpeg *jpeg; |
123 | unsigned int mode; | 128 | unsigned int mode; |
124 | unsigned int compr_quality; | 129 | unsigned short compr_quality; |
130 | unsigned short restart_interval; | ||
131 | unsigned short subsampling; | ||
125 | struct v4l2_m2m_ctx *m2m_ctx; | 132 | struct v4l2_m2m_ctx *m2m_ctx; |
126 | struct s5p_jpeg_q_data out_q; | 133 | struct s5p_jpeg_q_data out_q; |
127 | struct s5p_jpeg_q_data cap_q; | 134 | struct s5p_jpeg_q_data cap_q; |
135 | struct v4l2_fh fh; | ||
128 | bool hdr_parsed; | 136 | bool hdr_parsed; |
137 | struct v4l2_ctrl_handler ctrl_handler; | ||
129 | }; | 138 | }; |
130 | 139 | ||
131 | /** | 140 | /** |
diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h index e10c744e9f23..f12f0fdbde7c 100644 --- a/drivers/media/video/s5p-jpeg/jpeg-hw.h +++ b/drivers/media/video/s5p-jpeg/jpeg-hw.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #define JPEG_HW_H_ | 13 | #define JPEG_HW_H_ |
14 | 14 | ||
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | #include <linux/videodev2.h> | ||
16 | 17 | ||
17 | #include "jpeg-hw.h" | 18 | #include "jpeg-hw.h" |
18 | #include "jpeg-regs.h" | 19 | #include "jpeg-regs.h" |
@@ -25,8 +26,6 @@ | |||
25 | #define S5P_JPEG_DECODE 1 | 26 | #define S5P_JPEG_DECODE 1 |
26 | #define S5P_JPEG_RAW_IN_565 0 | 27 | #define S5P_JPEG_RAW_IN_565 0 |
27 | #define S5P_JPEG_RAW_IN_422 1 | 28 | #define S5P_JPEG_RAW_IN_422 1 |
28 | #define S5P_JPEG_SUBSAMPLING_422 0 | ||
29 | #define S5P_JPEG_SUBSAMPLING_420 1 | ||
30 | #define S5P_JPEG_RAW_OUT_422 0 | 29 | #define S5P_JPEG_RAW_OUT_422 0 |
31 | #define S5P_JPEG_RAW_OUT_420 1 | 30 | #define S5P_JPEG_RAW_OUT_420 1 |
32 | 31 | ||
@@ -91,21 +90,26 @@ static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode) | |||
91 | writel(reg, regs + S5P_JPGMOD); | 90 | writel(reg, regs + S5P_JPGMOD); |
92 | } | 91 | } |
93 | 92 | ||
94 | static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) | 93 | static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode) |
95 | { | 94 | { |
96 | unsigned long reg, m; | 95 | unsigned long reg, m; |
97 | 96 | ||
98 | m = S5P_SUBSAMPLING_MODE_422; | 97 | if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420) |
99 | if (mode == S5P_JPEG_SUBSAMPLING_422) | ||
100 | m = S5P_SUBSAMPLING_MODE_422; | ||
101 | else if (mode == S5P_JPEG_SUBSAMPLING_420) | ||
102 | m = S5P_SUBSAMPLING_MODE_420; | 98 | m = S5P_SUBSAMPLING_MODE_420; |
99 | else | ||
100 | m = S5P_SUBSAMPLING_MODE_422; | ||
101 | |||
103 | reg = readl(regs + S5P_JPGMOD); | 102 | reg = readl(regs + S5P_JPGMOD); |
104 | reg &= ~S5P_SUBSAMPLING_MODE_MASK; | 103 | reg &= ~S5P_SUBSAMPLING_MODE_MASK; |
105 | reg |= m; | 104 | reg |= m; |
106 | writel(reg, regs + S5P_JPGMOD); | 105 | writel(reg, regs + S5P_JPGMOD); |
107 | } | 106 | } |
108 | 107 | ||
108 | static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs) | ||
109 | { | ||
110 | return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK; | ||
111 | } | ||
112 | |||
109 | static inline void jpeg_dri(void __iomem *regs, unsigned int dri) | 113 | static inline void jpeg_dri(void __iomem *regs, unsigned int dri) |
110 | { | 114 | { |
111 | unsigned long reg; | 115 | unsigned long reg; |
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c index f6a3035c4fb7..738a607be43c 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c | |||
@@ -41,15 +41,29 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) | |||
41 | pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); | 41 | pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); |
42 | if (IS_ERR(pm->clock_gate)) { | 42 | if (IS_ERR(pm->clock_gate)) { |
43 | mfc_err("Failed to get clock-gating control\n"); | 43 | mfc_err("Failed to get clock-gating control\n"); |
44 | ret = -ENOENT; | 44 | ret = PTR_ERR(pm->clock_gate); |
45 | goto err_g_ip_clk; | 45 | goto err_g_ip_clk; |
46 | } | 46 | } |
47 | |||
48 | ret = clk_prepare(pm->clock_gate); | ||
49 | if (ret) { | ||
50 | mfc_err("Failed to preapre clock-gating control\n"); | ||
51 | goto err_p_ip_clk; | ||
52 | } | ||
53 | |||
47 | pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); | 54 | pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); |
48 | if (IS_ERR(pm->clock)) { | 55 | if (IS_ERR(pm->clock)) { |
49 | mfc_err("Failed to get MFC clock\n"); | 56 | mfc_err("Failed to get MFC clock\n"); |
50 | ret = -ENOENT; | 57 | ret = PTR_ERR(pm->clock); |
51 | goto err_g_ip_clk_2; | 58 | goto err_g_ip_clk_2; |
52 | } | 59 | } |
60 | |||
61 | ret = clk_prepare(pm->clock); | ||
62 | if (ret) { | ||
63 | mfc_err("Failed to prepare MFC clock\n"); | ||
64 | goto err_p_ip_clk_2; | ||
65 | } | ||
66 | |||
53 | atomic_set(&pm->power, 0); | 67 | atomic_set(&pm->power, 0); |
54 | #ifdef CONFIG_PM_RUNTIME | 68 | #ifdef CONFIG_PM_RUNTIME |
55 | pm->device = &dev->plat_dev->dev; | 69 | pm->device = &dev->plat_dev->dev; |
@@ -59,7 +73,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) | |||
59 | atomic_set(&clk_ref, 0); | 73 | atomic_set(&clk_ref, 0); |
60 | #endif | 74 | #endif |
61 | return 0; | 75 | return 0; |
76 | err_p_ip_clk_2: | ||
77 | clk_put(pm->clock); | ||
62 | err_g_ip_clk_2: | 78 | err_g_ip_clk_2: |
79 | clk_unprepare(pm->clock_gate); | ||
80 | err_p_ip_clk: | ||
63 | clk_put(pm->clock_gate); | 81 | clk_put(pm->clock_gate); |
64 | err_g_ip_clk: | 82 | err_g_ip_clk: |
65 | return ret; | 83 | return ret; |
@@ -67,7 +85,9 @@ err_g_ip_clk: | |||
67 | 85 | ||
68 | void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) | 86 | void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) |
69 | { | 87 | { |
88 | clk_unprepare(pm->clock_gate); | ||
70 | clk_put(pm->clock_gate); | 89 | clk_put(pm->clock_gate); |
90 | clk_unprepare(pm->clock); | ||
71 | clk_put(pm->clock); | 91 | clk_put(pm->clock); |
72 | #ifdef CONFIG_PM_RUNTIME | 92 | #ifdef CONFIG_PM_RUNTIME |
73 | pm_runtime_disable(pm->device); | 93 | pm_runtime_disable(pm->device); |
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig index f2a09779ec8f..f248b2856720 100644 --- a/drivers/media/video/s5p-tv/Kconfig +++ b/drivers/media/video/s5p-tv/Kconfig | |||
@@ -46,6 +46,16 @@ config VIDEO_SAMSUNG_S5P_HDMIPHY | |||
46 | as module. It is an I2C driver, that exposes a V4L2 | 46 | as module. It is an I2C driver, that exposes a V4L2 |
47 | subdev for use by other drivers. | 47 | subdev for use by other drivers. |
48 | 48 | ||
49 | config VIDEO_SAMSUNG_S5P_SII9234 | ||
50 | tristate "Samsung SII9234 Driver" | ||
51 | depends on VIDEO_DEV && VIDEO_V4L2 && I2C | ||
52 | depends on VIDEO_SAMSUNG_S5P_TV | ||
53 | help | ||
54 | Say Y here if you want support for the MHL interface | ||
55 | in S5P Samsung SoC. The driver can be compiled | ||
56 | as module. It is an I2C driver, that exposes a V4L2 | ||
57 | subdev for use by other drivers. | ||
58 | |||
49 | config VIDEO_SAMSUNG_S5P_SDO | 59 | config VIDEO_SAMSUNG_S5P_SDO |
50 | tristate "Samsung Analog TV Driver" | 60 | tristate "Samsung Analog TV Driver" |
51 | depends on VIDEO_DEV && VIDEO_V4L2 | 61 | depends on VIDEO_DEV && VIDEO_V4L2 |
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile index 37e4c17663b4..f49e756a2fde 100644 --- a/drivers/media/video/s5p-tv/Makefile +++ b/drivers/media/video/s5p-tv/Makefile | |||
@@ -8,6 +8,8 @@ | |||
8 | 8 | ||
9 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o | 9 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o |
10 | s5p-hdmiphy-y += hdmiphy_drv.o | 10 | s5p-hdmiphy-y += hdmiphy_drv.o |
11 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o | ||
12 | s5p-sii9234-y += sii9234_drv.o | ||
11 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o | 13 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o |
12 | s5p-hdmi-y += hdmi_drv.o | 14 | s5p-hdmi-y += hdmi_drv.o |
13 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o | 15 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o |
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c index 8b41a0410ab1..4865d25a0e57 100644 --- a/drivers/media/video/s5p-tv/hdmi_drv.c +++ b/drivers/media/video/s5p-tv/hdmi_drv.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
31 | #include <linux/regulator/consumer.h> | 31 | #include <linux/regulator/consumer.h> |
32 | 32 | ||
33 | #include <media/s5p_hdmi.h> | ||
33 | #include <media/v4l2-common.h> | 34 | #include <media/v4l2-common.h> |
34 | #include <media/v4l2-dev.h> | 35 | #include <media/v4l2-dev.h> |
35 | #include <media/v4l2-device.h> | 36 | #include <media/v4l2-device.h> |
@@ -66,6 +67,8 @@ struct hdmi_device { | |||
66 | struct v4l2_device v4l2_dev; | 67 | struct v4l2_device v4l2_dev; |
67 | /** subdev of HDMIPHY interface */ | 68 | /** subdev of HDMIPHY interface */ |
68 | struct v4l2_subdev *phy_sd; | 69 | struct v4l2_subdev *phy_sd; |
70 | /** subdev of MHL interface */ | ||
71 | struct v4l2_subdev *mhl_sd; | ||
69 | /** configuration of current graphic mode */ | 72 | /** configuration of current graphic mode */ |
70 | const struct hdmi_preset_conf *cur_conf; | 73 | const struct hdmi_preset_conf *cur_conf; |
71 | /** current preset */ | 74 | /** current preset */ |
@@ -74,10 +77,6 @@ struct hdmi_device { | |||
74 | struct hdmi_resources res; | 77 | struct hdmi_resources res; |
75 | }; | 78 | }; |
76 | 79 | ||
77 | struct hdmi_driver_data { | ||
78 | int hdmiphy_bus; | ||
79 | }; | ||
80 | |||
81 | struct hdmi_tg_regs { | 80 | struct hdmi_tg_regs { |
82 | u8 cmd; | 81 | u8 cmd; |
83 | u8 h_fsz_l; | 82 | u8 h_fsz_l; |
@@ -129,23 +128,11 @@ struct hdmi_preset_conf { | |||
129 | struct v4l2_mbus_framefmt mbus_fmt; | 128 | struct v4l2_mbus_framefmt mbus_fmt; |
130 | }; | 129 | }; |
131 | 130 | ||
132 | /* I2C module and id for HDMIPHY */ | ||
133 | static struct i2c_board_info hdmiphy_info = { | ||
134 | I2C_BOARD_INFO("hdmiphy", 0x38), | ||
135 | }; | ||
136 | |||
137 | static struct hdmi_driver_data hdmi_driver_data[] = { | ||
138 | { .hdmiphy_bus = 3 }, | ||
139 | { .hdmiphy_bus = 8 }, | ||
140 | }; | ||
141 | |||
142 | static struct platform_device_id hdmi_driver_types[] = { | 131 | static struct platform_device_id hdmi_driver_types[] = { |
143 | { | 132 | { |
144 | .name = "s5pv210-hdmi", | 133 | .name = "s5pv210-hdmi", |
145 | .driver_data = (unsigned long)&hdmi_driver_data[0], | ||
146 | }, { | 134 | }, { |
147 | .name = "exynos4-hdmi", | 135 | .name = "exynos4-hdmi", |
148 | .driver_data = (unsigned long)&hdmi_driver_data[1], | ||
149 | }, { | 136 | }, { |
150 | /* end node */ | 137 | /* end node */ |
151 | } | 138 | } |
@@ -587,7 +574,15 @@ static int hdmi_streamon(struct hdmi_device *hdev) | |||
587 | if (tries == 0) { | 574 | if (tries == 0) { |
588 | dev_err(dev, "hdmiphy's pll could not reach steady state.\n"); | 575 | dev_err(dev, "hdmiphy's pll could not reach steady state.\n"); |
589 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); | 576 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); |
590 | hdmi_dumpregs(hdev, "s_stream"); | 577 | hdmi_dumpregs(hdev, "hdmiphy - s_stream"); |
578 | return -EIO; | ||
579 | } | ||
580 | |||
581 | /* starting MHL */ | ||
582 | ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1); | ||
583 | if (hdev->mhl_sd && ret) { | ||
584 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); | ||
585 | hdmi_dumpregs(hdev, "mhl - s_stream"); | ||
591 | return -EIO; | 586 | return -EIO; |
592 | } | 587 | } |
593 | 588 | ||
@@ -618,6 +613,7 @@ static int hdmi_streamoff(struct hdmi_device *hdev) | |||
618 | clk_set_parent(res->sclk_hdmi, res->sclk_pixel); | 613 | clk_set_parent(res->sclk_hdmi, res->sclk_pixel); |
619 | clk_enable(res->sclk_hdmi); | 614 | clk_enable(res->sclk_hdmi); |
620 | 615 | ||
616 | v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0); | ||
621 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); | 617 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); |
622 | 618 | ||
623 | hdmi_dumpregs(hdev, "streamoff"); | 619 | hdmi_dumpregs(hdev, "streamoff"); |
@@ -739,6 +735,7 @@ static int hdmi_runtime_suspend(struct device *dev) | |||
739 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | 735 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); |
740 | 736 | ||
741 | dev_dbg(dev, "%s\n", __func__); | 737 | dev_dbg(dev, "%s\n", __func__); |
738 | v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0); | ||
742 | hdmi_resource_poweroff(&hdev->res); | 739 | hdmi_resource_poweroff(&hdev->res); |
743 | return 0; | 740 | return 0; |
744 | } | 741 | } |
@@ -757,6 +754,11 @@ static int hdmi_runtime_resume(struct device *dev) | |||
757 | if (ret) | 754 | if (ret) |
758 | goto fail; | 755 | goto fail; |
759 | 756 | ||
757 | /* starting MHL */ | ||
758 | ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1); | ||
759 | if (hdev->mhl_sd && ret) | ||
760 | goto fail; | ||
761 | |||
760 | dev_dbg(dev, "poweron succeed\n"); | 762 | dev_dbg(dev, "poweron succeed\n"); |
761 | 763 | ||
762 | return 0; | 764 | return 0; |
@@ -867,15 +869,21 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
867 | { | 869 | { |
868 | struct device *dev = &pdev->dev; | 870 | struct device *dev = &pdev->dev; |
869 | struct resource *res; | 871 | struct resource *res; |
870 | struct i2c_adapter *phy_adapter; | 872 | struct i2c_adapter *adapter; |
871 | struct v4l2_subdev *sd; | 873 | struct v4l2_subdev *sd; |
872 | struct hdmi_device *hdmi_dev = NULL; | 874 | struct hdmi_device *hdmi_dev = NULL; |
873 | struct hdmi_driver_data *drv_data; | 875 | struct s5p_hdmi_platform_data *pdata = dev->platform_data; |
874 | int ret; | 876 | int ret; |
875 | 877 | ||
876 | dev_dbg(dev, "probe start\n"); | 878 | dev_dbg(dev, "probe start\n"); |
877 | 879 | ||
878 | hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL); | 880 | if (!pdata) { |
881 | dev_err(dev, "platform data is missing\n"); | ||
882 | ret = -ENODEV; | ||
883 | goto fail; | ||
884 | } | ||
885 | |||
886 | hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL); | ||
879 | if (!hdmi_dev) { | 887 | if (!hdmi_dev) { |
880 | dev_err(dev, "out of memory\n"); | 888 | dev_err(dev, "out of memory\n"); |
881 | ret = -ENOMEM; | 889 | ret = -ENOMEM; |
@@ -886,7 +894,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
886 | 894 | ||
887 | ret = hdmi_resources_init(hdmi_dev); | 895 | ret = hdmi_resources_init(hdmi_dev); |
888 | if (ret) | 896 | if (ret) |
889 | goto fail_hdev; | 897 | goto fail; |
890 | 898 | ||
891 | /* mapping HDMI registers */ | 899 | /* mapping HDMI registers */ |
892 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 900 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -896,24 +904,26 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
896 | goto fail_init; | 904 | goto fail_init; |
897 | } | 905 | } |
898 | 906 | ||
899 | hdmi_dev->regs = ioremap(res->start, resource_size(res)); | 907 | hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start, |
908 | resource_size(res)); | ||
900 | if (hdmi_dev->regs == NULL) { | 909 | if (hdmi_dev->regs == NULL) { |
901 | dev_err(dev, "register mapping failed.\n"); | 910 | dev_err(dev, "register mapping failed.\n"); |
902 | ret = -ENXIO; | 911 | ret = -ENXIO; |
903 | goto fail_hdev; | 912 | goto fail_init; |
904 | } | 913 | } |
905 | 914 | ||
906 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 915 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
907 | if (res == NULL) { | 916 | if (res == NULL) { |
908 | dev_err(dev, "get interrupt resource failed.\n"); | 917 | dev_err(dev, "get interrupt resource failed.\n"); |
909 | ret = -ENXIO; | 918 | ret = -ENXIO; |
910 | goto fail_regs; | 919 | goto fail_init; |
911 | } | 920 | } |
912 | 921 | ||
913 | ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev); | 922 | ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0, |
923 | "hdmi", hdmi_dev); | ||
914 | if (ret) { | 924 | if (ret) { |
915 | dev_err(dev, "request interrupt failed.\n"); | 925 | dev_err(dev, "request interrupt failed.\n"); |
916 | goto fail_regs; | 926 | goto fail_init; |
917 | } | 927 | } |
918 | hdmi_dev->irq = res->start; | 928 | hdmi_dev->irq = res->start; |
919 | 929 | ||
@@ -924,28 +934,54 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
924 | ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev); | 934 | ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev); |
925 | if (ret) { | 935 | if (ret) { |
926 | dev_err(dev, "could not register v4l2 device.\n"); | 936 | dev_err(dev, "could not register v4l2 device.\n"); |
927 | goto fail_irq; | 937 | goto fail_init; |
928 | } | 938 | } |
929 | 939 | ||
930 | drv_data = (struct hdmi_driver_data *) | 940 | /* testing if hdmiphy info is present */ |
931 | platform_get_device_id(pdev)->driver_data; | 941 | if (!pdata->hdmiphy_info) { |
932 | phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus); | 942 | dev_err(dev, "hdmiphy info is missing in platform data\n"); |
933 | if (phy_adapter == NULL) { | 943 | ret = -ENXIO; |
934 | dev_err(dev, "adapter request failed\n"); | 944 | goto fail_vdev; |
945 | } | ||
946 | |||
947 | adapter = i2c_get_adapter(pdata->hdmiphy_bus); | ||
948 | if (adapter == NULL) { | ||
949 | dev_err(dev, "hdmiphy adapter request failed\n"); | ||
935 | ret = -ENXIO; | 950 | ret = -ENXIO; |
936 | goto fail_vdev; | 951 | goto fail_vdev; |
937 | } | 952 | } |
938 | 953 | ||
939 | hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev, | 954 | hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev, |
940 | phy_adapter, &hdmiphy_info, NULL); | 955 | adapter, pdata->hdmiphy_info, NULL); |
941 | /* on failure or not adapter is no longer useful */ | 956 | /* on failure or not adapter is no longer useful */ |
942 | i2c_put_adapter(phy_adapter); | 957 | i2c_put_adapter(adapter); |
943 | if (hdmi_dev->phy_sd == NULL) { | 958 | if (hdmi_dev->phy_sd == NULL) { |
944 | dev_err(dev, "missing subdev for hdmiphy\n"); | 959 | dev_err(dev, "missing subdev for hdmiphy\n"); |
945 | ret = -ENODEV; | 960 | ret = -ENODEV; |
946 | goto fail_vdev; | 961 | goto fail_vdev; |
947 | } | 962 | } |
948 | 963 | ||
964 | /* initialization of MHL interface if present */ | ||
965 | if (pdata->mhl_info) { | ||
966 | adapter = i2c_get_adapter(pdata->mhl_bus); | ||
967 | if (adapter == NULL) { | ||
968 | dev_err(dev, "MHL adapter request failed\n"); | ||
969 | ret = -ENXIO; | ||
970 | goto fail_vdev; | ||
971 | } | ||
972 | |||
973 | hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board( | ||
974 | &hdmi_dev->v4l2_dev, adapter, | ||
975 | pdata->mhl_info, NULL); | ||
976 | /* on failure or not adapter is no longer useful */ | ||
977 | i2c_put_adapter(adapter); | ||
978 | if (hdmi_dev->mhl_sd == NULL) { | ||
979 | dev_err(dev, "missing subdev for MHL\n"); | ||
980 | ret = -ENODEV; | ||
981 | goto fail_vdev; | ||
982 | } | ||
983 | } | ||
984 | |||
949 | clk_enable(hdmi_dev->res.hdmi); | 985 | clk_enable(hdmi_dev->res.hdmi); |
950 | 986 | ||
951 | pm_runtime_enable(dev); | 987 | pm_runtime_enable(dev); |
@@ -962,25 +998,16 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
962 | /* storing subdev for call that have only access to struct device */ | 998 | /* storing subdev for call that have only access to struct device */ |
963 | dev_set_drvdata(dev, sd); | 999 | dev_set_drvdata(dev, sd); |
964 | 1000 | ||
965 | dev_info(dev, "probe sucessful\n"); | 1001 | dev_info(dev, "probe successful\n"); |
966 | 1002 | ||
967 | return 0; | 1003 | return 0; |
968 | 1004 | ||
969 | fail_vdev: | 1005 | fail_vdev: |
970 | v4l2_device_unregister(&hdmi_dev->v4l2_dev); | 1006 | v4l2_device_unregister(&hdmi_dev->v4l2_dev); |
971 | 1007 | ||
972 | fail_irq: | ||
973 | free_irq(hdmi_dev->irq, hdmi_dev); | ||
974 | |||
975 | fail_regs: | ||
976 | iounmap(hdmi_dev->regs); | ||
977 | |||
978 | fail_init: | 1008 | fail_init: |
979 | hdmi_resources_cleanup(hdmi_dev); | 1009 | hdmi_resources_cleanup(hdmi_dev); |
980 | 1010 | ||
981 | fail_hdev: | ||
982 | kfree(hdmi_dev); | ||
983 | |||
984 | fail: | 1011 | fail: |
985 | dev_err(dev, "probe failed\n"); | 1012 | dev_err(dev, "probe failed\n"); |
986 | return ret; | 1013 | return ret; |
@@ -996,11 +1023,8 @@ static int __devexit hdmi_remove(struct platform_device *pdev) | |||
996 | clk_disable(hdmi_dev->res.hdmi); | 1023 | clk_disable(hdmi_dev->res.hdmi); |
997 | v4l2_device_unregister(&hdmi_dev->v4l2_dev); | 1024 | v4l2_device_unregister(&hdmi_dev->v4l2_dev); |
998 | disable_irq(hdmi_dev->irq); | 1025 | disable_irq(hdmi_dev->irq); |
999 | free_irq(hdmi_dev->irq, hdmi_dev); | ||
1000 | iounmap(hdmi_dev->regs); | ||
1001 | hdmi_resources_cleanup(hdmi_dev); | 1026 | hdmi_resources_cleanup(hdmi_dev); |
1002 | kfree(hdmi_dev); | 1027 | dev_info(dev, "remove successful\n"); |
1003 | dev_info(dev, "remove sucessful\n"); | ||
1004 | 1028 | ||
1005 | return 0; | 1029 | return 0; |
1006 | } | 1030 | } |
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c index 6693f4aff108..0afef77747e5 100644 --- a/drivers/media/video/s5p-tv/hdmiphy_drv.c +++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c | |||
@@ -175,14 +175,4 @@ static struct i2c_driver hdmiphy_driver = { | |||
175 | .id_table = hdmiphy_id, | 175 | .id_table = hdmiphy_id, |
176 | }; | 176 | }; |
177 | 177 | ||
178 | static int __init hdmiphy_init(void) | 178 | module_i2c_driver(hdmiphy_driver); |
179 | { | ||
180 | return i2c_add_driver(&hdmiphy_driver); | ||
181 | } | ||
182 | module_init(hdmiphy_init); | ||
183 | |||
184 | static void __exit hdmiphy_exit(void) | ||
185 | { | ||
186 | i2c_del_driver(&hdmiphy_driver); | ||
187 | } | ||
188 | module_exit(hdmiphy_exit); | ||
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c index 00643094b221..a2c0c25ad130 100644 --- a/drivers/media/video/s5p-tv/mixer_drv.c +++ b/drivers/media/video/s5p-tv/mixer_drv.c | |||
@@ -444,7 +444,7 @@ static int __devexit mxr_remove(struct platform_device *pdev) | |||
444 | 444 | ||
445 | kfree(mdev); | 445 | kfree(mdev); |
446 | 446 | ||
447 | dev_info(dev, "remove sucessful\n"); | 447 | dev_info(dev, "remove successful\n"); |
448 | return 0; | 448 | return 0; |
449 | } | 449 | } |
450 | 450 | ||
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c index 059e7749ce95..f6bca2c20e89 100644 --- a/drivers/media/video/s5p-tv/sdo_drv.c +++ b/drivers/media/video/s5p-tv/sdo_drv.c | |||
@@ -301,7 +301,7 @@ static int __devinit sdo_probe(struct platform_device *pdev) | |||
301 | struct clk *sclk_vpll; | 301 | struct clk *sclk_vpll; |
302 | 302 | ||
303 | dev_info(dev, "probe start\n"); | 303 | dev_info(dev, "probe start\n"); |
304 | sdev = kzalloc(sizeof *sdev, GFP_KERNEL); | 304 | sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL); |
305 | if (!sdev) { | 305 | if (!sdev) { |
306 | dev_err(dev, "not enough memory.\n"); | 306 | dev_err(dev, "not enough memory.\n"); |
307 | ret = -ENOMEM; | 307 | ret = -ENOMEM; |
@@ -314,14 +314,14 @@ static int __devinit sdo_probe(struct platform_device *pdev) | |||
314 | if (res == NULL) { | 314 | if (res == NULL) { |
315 | dev_err(dev, "get memory resource failed.\n"); | 315 | dev_err(dev, "get memory resource failed.\n"); |
316 | ret = -ENXIO; | 316 | ret = -ENXIO; |
317 | goto fail_sdev; | 317 | goto fail; |
318 | } | 318 | } |
319 | 319 | ||
320 | sdev->regs = ioremap(res->start, resource_size(res)); | 320 | sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); |
321 | if (sdev->regs == NULL) { | 321 | if (sdev->regs == NULL) { |
322 | dev_err(dev, "register mapping failed.\n"); | 322 | dev_err(dev, "register mapping failed.\n"); |
323 | ret = -ENXIO; | 323 | ret = -ENXIO; |
324 | goto fail_sdev; | 324 | goto fail; |
325 | } | 325 | } |
326 | 326 | ||
327 | /* acquiring interrupt */ | 327 | /* acquiring interrupt */ |
@@ -329,12 +329,13 @@ static int __devinit sdo_probe(struct platform_device *pdev) | |||
329 | if (res == NULL) { | 329 | if (res == NULL) { |
330 | dev_err(dev, "get interrupt resource failed.\n"); | 330 | dev_err(dev, "get interrupt resource failed.\n"); |
331 | ret = -ENXIO; | 331 | ret = -ENXIO; |
332 | goto fail_regs; | 332 | goto fail; |
333 | } | 333 | } |
334 | ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev); | 334 | ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0, |
335 | "s5p-sdo", sdev); | ||
335 | if (ret) { | 336 | if (ret) { |
336 | dev_err(dev, "request interrupt failed.\n"); | 337 | dev_err(dev, "request interrupt failed.\n"); |
337 | goto fail_regs; | 338 | goto fail; |
338 | } | 339 | } |
339 | sdev->irq = res->start; | 340 | sdev->irq = res->start; |
340 | 341 | ||
@@ -343,7 +344,7 @@ static int __devinit sdo_probe(struct platform_device *pdev) | |||
343 | if (IS_ERR_OR_NULL(sdev->sclk_dac)) { | 344 | if (IS_ERR_OR_NULL(sdev->sclk_dac)) { |
344 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); | 345 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); |
345 | ret = -ENXIO; | 346 | ret = -ENXIO; |
346 | goto fail_irq; | 347 | goto fail; |
347 | } | 348 | } |
348 | sdev->dac = clk_get(dev, "dac"); | 349 | sdev->dac = clk_get(dev, "dac"); |
349 | if (IS_ERR_OR_NULL(sdev->dac)) { | 350 | if (IS_ERR_OR_NULL(sdev->dac)) { |
@@ -415,12 +416,6 @@ fail_dac: | |||
415 | clk_put(sdev->dac); | 416 | clk_put(sdev->dac); |
416 | fail_sclk_dac: | 417 | fail_sclk_dac: |
417 | clk_put(sdev->sclk_dac); | 418 | clk_put(sdev->sclk_dac); |
418 | fail_irq: | ||
419 | free_irq(sdev->irq, sdev); | ||
420 | fail_regs: | ||
421 | iounmap(sdev->regs); | ||
422 | fail_sdev: | ||
423 | kfree(sdev); | ||
424 | fail: | 419 | fail: |
425 | dev_info(dev, "probe failed\n"); | 420 | dev_info(dev, "probe failed\n"); |
426 | return ret; | 421 | return ret; |
@@ -439,9 +434,6 @@ static int __devexit sdo_remove(struct platform_device *pdev) | |||
439 | clk_put(sdev->dacphy); | 434 | clk_put(sdev->dacphy); |
440 | clk_put(sdev->dac); | 435 | clk_put(sdev->dac); |
441 | clk_put(sdev->sclk_dac); | 436 | clk_put(sdev->sclk_dac); |
442 | free_irq(sdev->irq, sdev); | ||
443 | iounmap(sdev->regs); | ||
444 | kfree(sdev); | ||
445 | 437 | ||
446 | dev_info(&pdev->dev, "remove successful\n"); | 438 | dev_info(&pdev->dev, "remove successful\n"); |
447 | return 0; | 439 | return 0; |
diff --git a/drivers/media/video/s5p-tv/sii9234_drv.c b/drivers/media/video/s5p-tv/sii9234_drv.c new file mode 100644 index 000000000000..0f31eccd7b80 --- /dev/null +++ b/drivers/media/video/s5p-tv/sii9234_drv.c | |||
@@ -0,0 +1,432 @@ | |||
1 | /* | ||
2 | * Samsung MHL interface driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co.Ltd | ||
5 | * Author: Tomasz Stanislawski <t.stanislaws@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/freezer.h> | ||
16 | #include <linux/gpio.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/kthread.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <linux/regulator/machine.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include <mach/gpio.h> | ||
27 | #include <plat/gpio-cfg.h> | ||
28 | |||
29 | #include <media/sii9234.h> | ||
30 | #include <media/v4l2-subdev.h> | ||
31 | |||
32 | MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>"); | ||
33 | MODULE_DESCRIPTION("Samsung MHL interface driver"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | struct sii9234_context { | ||
37 | struct i2c_client *client; | ||
38 | struct regulator *power; | ||
39 | int gpio_n_reset; | ||
40 | struct v4l2_subdev sd; | ||
41 | }; | ||
42 | |||
43 | static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd) | ||
44 | { | ||
45 | return container_of(sd, struct sii9234_context, sd); | ||
46 | } | ||
47 | |||
48 | static inline int sii9234_readb(struct i2c_client *client, int addr) | ||
49 | { | ||
50 | return i2c_smbus_read_byte_data(client, addr); | ||
51 | } | ||
52 | |||
53 | static inline int sii9234_writeb(struct i2c_client *client, int addr, int value) | ||
54 | { | ||
55 | return i2c_smbus_write_byte_data(client, addr, value); | ||
56 | } | ||
57 | |||
58 | static inline int sii9234_writeb_mask(struct i2c_client *client, int addr, | ||
59 | int value, int mask) | ||
60 | { | ||
61 | int ret; | ||
62 | |||
63 | ret = i2c_smbus_read_byte_data(client, addr); | ||
64 | if (ret < 0) | ||
65 | return ret; | ||
66 | ret = (ret & ~mask) | (value & mask); | ||
67 | return i2c_smbus_write_byte_data(client, addr, ret); | ||
68 | } | ||
69 | |||
70 | static inline int sii9234_readb_idx(struct i2c_client *client, int addr) | ||
71 | { | ||
72 | int ret; | ||
73 | ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); | ||
77 | if (ret < 0) | ||
78 | return ret; | ||
79 | return i2c_smbus_read_byte_data(client, 0xbe); | ||
80 | } | ||
81 | |||
82 | static inline int sii9234_writeb_idx(struct i2c_client *client, int addr, | ||
83 | int value) | ||
84 | { | ||
85 | int ret; | ||
86 | ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); | ||
90 | if (ret < 0) | ||
91 | return ret; | ||
92 | ret = i2c_smbus_write_byte_data(client, 0xbe, value); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr, | ||
97 | int value, int mask) | ||
98 | { | ||
99 | int ret; | ||
100 | |||
101 | ret = sii9234_readb_idx(client, addr); | ||
102 | if (ret < 0) | ||
103 | return ret; | ||
104 | ret = (ret & ~mask) | (value & mask); | ||
105 | return sii9234_writeb_idx(client, addr, ret); | ||
106 | } | ||
107 | |||
108 | static int sii9234_reset(struct sii9234_context *ctx) | ||
109 | { | ||
110 | struct i2c_client *client = ctx->client; | ||
111 | struct device *dev = &client->dev; | ||
112 | int ret, tries; | ||
113 | |||
114 | gpio_direction_output(ctx->gpio_n_reset, 1); | ||
115 | mdelay(1); | ||
116 | gpio_direction_output(ctx->gpio_n_reset, 0); | ||
117 | mdelay(1); | ||
118 | gpio_direction_output(ctx->gpio_n_reset, 1); | ||
119 | mdelay(1); | ||
120 | |||
121 | /* going to TTPI mode */ | ||
122 | ret = sii9234_writeb(client, 0xc7, 0); | ||
123 | if (ret < 0) { | ||
124 | dev_err(dev, "failed to set TTPI mode\n"); | ||
125 | return ret; | ||
126 | } | ||
127 | for (tries = 0; tries < 100 ; ++tries) { | ||
128 | ret = sii9234_readb(client, 0x1b); | ||
129 | if (ret > 0) | ||
130 | break; | ||
131 | if (ret < 0) { | ||
132 | dev_err(dev, "failed to reset device\n"); | ||
133 | return -EIO; | ||
134 | } | ||
135 | mdelay(1); | ||
136 | } | ||
137 | if (tries == 100) { | ||
138 | dev_err(dev, "maximal number of tries reached\n"); | ||
139 | return -EIO; | ||
140 | } | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int sii9234_verify_version(struct i2c_client *client) | ||
146 | { | ||
147 | struct device *dev = &client->dev; | ||
148 | int family, rev, tpi_rev, dev_id, sub_id, hdcp, id; | ||
149 | |||
150 | family = sii9234_readb(client, 0x1b); | ||
151 | rev = sii9234_readb(client, 0x1c) & 0x0f; | ||
152 | tpi_rev = sii9234_readb(client, 0x1d) & 0x7f; | ||
153 | dev_id = sii9234_readb_idx(client, 0x0103); | ||
154 | sub_id = sii9234_readb_idx(client, 0x0102); | ||
155 | hdcp = sii9234_readb(client, 0x30); | ||
156 | |||
157 | if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 || | ||
158 | sub_id < 0 || hdcp < 0) { | ||
159 | dev_err(dev, "failed to read chip's version\n"); | ||
160 | return -EIO; | ||
161 | } | ||
162 | |||
163 | id = (dev_id << 8) | sub_id; | ||
164 | |||
165 | dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n", | ||
166 | id, family, rev); | ||
167 | dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp); | ||
168 | if (id != 0x9234) { | ||
169 | dev_err(dev, "not supported chip\n"); | ||
170 | return -ENODEV; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static u8 data[][3] = { | ||
177 | /* setup from driver created by doonsoo45.kim */ | ||
178 | { 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */ | ||
179 | { 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */ | ||
180 | { 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */ | ||
181 | { 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */ | ||
182 | { 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */ | ||
183 | { 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */ | ||
184 | { 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */ | ||
185 | { 0x01, 0x91, 0xe5 }, /* Skip RGND detection */ | ||
186 | { 0x01, 0x92, 0x46 }, /* Force MHD mode */ | ||
187 | { 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */ | ||
188 | { 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */ | ||
189 | { 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */ | ||
190 | { 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */ | ||
191 | { 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */ | ||
192 | { 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */ | ||
193 | { 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing default EB, 3x Clk Mult */ | ||
194 | { 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */ | ||
195 | { 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */ | ||
196 | { 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */ | ||
197 | { 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */ | ||
198 | { 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */ | ||
199 | { 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */ | ||
200 | { 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */ | ||
201 | { 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */ | ||
202 | { 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */ | ||
203 | { 0x03, 0x1a, 0x20 }, /* VCO Cal */ | ||
204 | { 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */ | ||
205 | { 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */ | ||
206 | { 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */ | ||
207 | { 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */ | ||
208 | { 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */ | ||
209 | { 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */ | ||
210 | { 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */ | ||
211 | { 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */ | ||
212 | { 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */ | ||
213 | { 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */ | ||
214 | { 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */ | ||
215 | { 0x03, 0x4c, 0xa0 }, /* Manual zone control */ | ||
216 | { 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */ | ||
217 | }; | ||
218 | |||
219 | static int sii9234_set_internal(struct sii9234_context *ctx) | ||
220 | { | ||
221 | struct i2c_client *client = ctx->client; | ||
222 | int i, ret; | ||
223 | |||
224 | for (i = 0; i < ARRAY_SIZE(data); ++i) { | ||
225 | int addr = (data[i][0] << 8) | data[i][1]; | ||
226 | ret = sii9234_writeb_idx(client, addr, data[i][2]); | ||
227 | if (ret < 0) | ||
228 | return ret; | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int sii9234_runtime_suspend(struct device *dev) | ||
234 | { | ||
235 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
236 | struct sii9234_context *ctx = sd_to_context(sd); | ||
237 | struct i2c_client *client = ctx->client; | ||
238 | |||
239 | dev_info(dev, "suspend start\n"); | ||
240 | |||
241 | sii9234_writeb_mask(client, 0x1e, 3, 3); | ||
242 | regulator_disable(ctx->power); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int sii9234_runtime_resume(struct device *dev) | ||
248 | { | ||
249 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
250 | struct sii9234_context *ctx = sd_to_context(sd); | ||
251 | struct i2c_client *client = ctx->client; | ||
252 | int ret; | ||
253 | |||
254 | dev_info(dev, "resume start\n"); | ||
255 | regulator_enable(ctx->power); | ||
256 | |||
257 | ret = sii9234_reset(ctx); | ||
258 | if (ret) | ||
259 | goto fail; | ||
260 | |||
261 | /* enable tpi */ | ||
262 | ret = sii9234_writeb_mask(client, 0x1e, 1, 0); | ||
263 | if (ret < 0) | ||
264 | goto fail; | ||
265 | ret = sii9234_set_internal(ctx); | ||
266 | if (ret < 0) | ||
267 | goto fail; | ||
268 | |||
269 | return 0; | ||
270 | |||
271 | fail: | ||
272 | dev_err(dev, "failed to resume\n"); | ||
273 | regulator_disable(ctx->power); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | static const struct dev_pm_ops sii9234_pm_ops = { | ||
279 | .runtime_suspend = sii9234_runtime_suspend, | ||
280 | .runtime_resume = sii9234_runtime_resume, | ||
281 | }; | ||
282 | |||
283 | static int sii9234_s_power(struct v4l2_subdev *sd, int on) | ||
284 | { | ||
285 | struct sii9234_context *ctx = sd_to_context(sd); | ||
286 | int ret; | ||
287 | |||
288 | if (on) | ||
289 | ret = pm_runtime_get_sync(&ctx->client->dev); | ||
290 | else | ||
291 | ret = pm_runtime_put(&ctx->client->dev); | ||
292 | /* only values < 0 indicate errors */ | ||
293 | return IS_ERR_VALUE(ret) ? ret : 0; | ||
294 | } | ||
295 | |||
296 | static int sii9234_s_stream(struct v4l2_subdev *sd, int enable) | ||
297 | { | ||
298 | struct sii9234_context *ctx = sd_to_context(sd); | ||
299 | |||
300 | /* (dis/en)able TDMS output */ | ||
301 | sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static const struct v4l2_subdev_core_ops sii9234_core_ops = { | ||
306 | .s_power = sii9234_s_power, | ||
307 | }; | ||
308 | |||
309 | static const struct v4l2_subdev_video_ops sii9234_video_ops = { | ||
310 | .s_stream = sii9234_s_stream, | ||
311 | }; | ||
312 | |||
313 | static const struct v4l2_subdev_ops sii9234_ops = { | ||
314 | .core = &sii9234_core_ops, | ||
315 | .video = &sii9234_video_ops, | ||
316 | }; | ||
317 | |||
318 | static int __devinit sii9234_probe(struct i2c_client *client, | ||
319 | const struct i2c_device_id *id) | ||
320 | { | ||
321 | struct device *dev = &client->dev; | ||
322 | struct sii9234_platform_data *pdata = dev->platform_data; | ||
323 | struct sii9234_context *ctx; | ||
324 | int ret; | ||
325 | |||
326 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
327 | if (!ctx) { | ||
328 | dev_err(dev, "out of memory\n"); | ||
329 | ret = -ENOMEM; | ||
330 | goto fail; | ||
331 | } | ||
332 | ctx->client = client; | ||
333 | |||
334 | ctx->power = regulator_get(dev, "hdmi-en"); | ||
335 | if (IS_ERR(ctx->power)) { | ||
336 | dev_err(dev, "failed to acquire regulator hdmi-en\n"); | ||
337 | ret = PTR_ERR(ctx->power); | ||
338 | goto fail_ctx; | ||
339 | } | ||
340 | |||
341 | ctx->gpio_n_reset = pdata->gpio_n_reset; | ||
342 | ret = gpio_request(ctx->gpio_n_reset, "MHL_RST"); | ||
343 | if (ret) { | ||
344 | dev_err(dev, "failed to acquire MHL_RST gpio\n"); | ||
345 | goto fail_power; | ||
346 | } | ||
347 | |||
348 | v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops); | ||
349 | |||
350 | pm_runtime_enable(dev); | ||
351 | |||
352 | /* enable device */ | ||
353 | ret = pm_runtime_get_sync(dev); | ||
354 | if (ret) | ||
355 | goto fail_pm; | ||
356 | |||
357 | /* verify chip version */ | ||
358 | ret = sii9234_verify_version(client); | ||
359 | if (ret) | ||
360 | goto fail_pm_get; | ||
361 | |||
362 | /* stop processing */ | ||
363 | pm_runtime_put(dev); | ||
364 | |||
365 | dev_info(dev, "probe successful\n"); | ||
366 | |||
367 | return 0; | ||
368 | |||
369 | fail_pm_get: | ||
370 | pm_runtime_put_sync(dev); | ||
371 | |||
372 | fail_pm: | ||
373 | pm_runtime_disable(dev); | ||
374 | gpio_free(ctx->gpio_n_reset); | ||
375 | |||
376 | fail_power: | ||
377 | regulator_put(ctx->power); | ||
378 | |||
379 | fail_ctx: | ||
380 | kfree(ctx); | ||
381 | |||
382 | fail: | ||
383 | dev_err(dev, "probe failed\n"); | ||
384 | |||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | static int __devexit sii9234_remove(struct i2c_client *client) | ||
389 | { | ||
390 | struct device *dev = &client->dev; | ||
391 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
392 | struct sii9234_context *ctx = sd_to_context(sd); | ||
393 | |||
394 | pm_runtime_disable(dev); | ||
395 | gpio_free(ctx->gpio_n_reset); | ||
396 | regulator_put(ctx->power); | ||
397 | kfree(ctx); | ||
398 | |||
399 | dev_info(dev, "remove successful\n"); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | |||
405 | static const struct i2c_device_id sii9234_id[] = { | ||
406 | { "SII9234", 0 }, | ||
407 | { }, | ||
408 | }; | ||
409 | |||
410 | MODULE_DEVICE_TABLE(i2c, sii9234_id); | ||
411 | static struct i2c_driver sii9234_driver = { | ||
412 | .driver = { | ||
413 | .name = "sii9234", | ||
414 | .owner = THIS_MODULE, | ||
415 | .pm = &sii9234_pm_ops, | ||
416 | }, | ||
417 | .probe = sii9234_probe, | ||
418 | .remove = __devexit_p(sii9234_remove), | ||
419 | .id_table = sii9234_id, | ||
420 | }; | ||
421 | |||
422 | static int __init sii9234_init(void) | ||
423 | { | ||
424 | return i2c_add_driver(&sii9234_driver); | ||
425 | } | ||
426 | module_init(sii9234_init); | ||
427 | |||
428 | static void __exit sii9234_exit(void) | ||
429 | { | ||
430 | i2c_del_driver(&sii9234_driver); | ||
431 | } | ||
432 | module_exit(sii9234_exit); | ||
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index 99a2ac16f9e5..0caac50d7cf4 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c | |||
@@ -539,15 +539,4 @@ static struct i2c_driver saa6588_driver = { | |||
539 | .id_table = saa6588_id, | 539 | .id_table = saa6588_id, |
540 | }; | 540 | }; |
541 | 541 | ||
542 | static __init int init_saa6588(void) | 542 | module_i2c_driver(saa6588_driver); |
543 | { | ||
544 | return i2c_add_driver(&saa6588_driver); | ||
545 | } | ||
546 | |||
547 | static __exit void exit_saa6588(void) | ||
548 | { | ||
549 | i2c_del_driver(&saa6588_driver); | ||
550 | } | ||
551 | |||
552 | module_init(init_saa6588); | ||
553 | module_exit(exit_saa6588); | ||
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 99664205ef4e..51cd4c8f0520 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c | |||
@@ -491,15 +491,4 @@ static struct i2c_driver saa7110_driver = { | |||
491 | .id_table = saa7110_id, | 491 | .id_table = saa7110_id, |
492 | }; | 492 | }; |
493 | 493 | ||
494 | static __init int init_saa7110(void) | 494 | module_i2c_driver(saa7110_driver); |
495 | { | ||
496 | return i2c_add_driver(&saa7110_driver); | ||
497 | } | ||
498 | |||
499 | static __exit void exit_saa7110(void) | ||
500 | { | ||
501 | i2c_del_driver(&saa7110_driver); | ||
502 | } | ||
503 | |||
504 | module_init(init_saa7110); | ||
505 | module_exit(exit_saa7110); | ||
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 0ef5484696b6..2107336cd836 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -1724,15 +1724,4 @@ static struct i2c_driver saa711x_driver = { | |||
1724 | .id_table = saa711x_id, | 1724 | .id_table = saa711x_id, |
1725 | }; | 1725 | }; |
1726 | 1726 | ||
1727 | static __init int init_saa711x(void) | 1727 | module_i2c_driver(saa711x_driver); |
1728 | { | ||
1729 | return i2c_add_driver(&saa711x_driver); | ||
1730 | } | ||
1731 | |||
1732 | static __exit void exit_saa711x(void) | ||
1733 | { | ||
1734 | i2c_del_driver(&saa711x_driver); | ||
1735 | } | ||
1736 | |||
1737 | module_init(init_saa711x); | ||
1738 | module_exit(exit_saa711x); | ||
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index ad964616c9d2..39c90b08eea8 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c | |||
@@ -852,15 +852,4 @@ static struct i2c_driver saa7127_driver = { | |||
852 | .id_table = saa7127_id, | 852 | .id_table = saa7127_id, |
853 | }; | 853 | }; |
854 | 854 | ||
855 | static __init int init_saa7127(void) | 855 | module_i2c_driver(saa7127_driver); |
856 | { | ||
857 | return i2c_add_driver(&saa7127_driver); | ||
858 | } | ||
859 | |||
860 | static __exit void exit_saa7127(void) | ||
861 | { | ||
862 | i2c_del_driver(&saa7127_driver); | ||
863 | } | ||
864 | |||
865 | module_init(init_saa7127); | ||
866 | module_exit(exit_saa7127); | ||
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index a646ccf51696..da3899329f52 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o | |||
10 | 10 | ||
11 | obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o | 11 | obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o |
12 | 12 | ||
13 | ccflags-y += -Idrivers/media/video | 13 | ccflags-y += -I$(srctree)/drivers/media/video |
14 | ccflags-y += -Idrivers/media/common/tuners | 14 | ccflags-y += -I$(srctree)/drivers/media/common/tuners |
15 | ccflags-y += -Idrivers/media/dvb/dvb-core | 15 | ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core |
16 | ccflags-y += -Idrivers/media/dvb/frontends | 16 | ccflags-y += -I$(srctree)/drivers/media/dvb/frontends |
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index f9f29cc93a8a..f147b05bd860 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c | |||
@@ -1001,18 +1001,7 @@ static struct i2c_driver saa6752hs_driver = { | |||
1001 | .id_table = saa6752hs_id, | 1001 | .id_table = saa6752hs_id, |
1002 | }; | 1002 | }; |
1003 | 1003 | ||
1004 | static __init int init_saa6752hs(void) | 1004 | module_i2c_driver(saa6752hs_driver); |
1005 | { | ||
1006 | return i2c_add_driver(&saa6752hs_driver); | ||
1007 | } | ||
1008 | |||
1009 | static __exit void exit_saa6752hs(void) | ||
1010 | { | ||
1011 | i2c_del_driver(&saa6752hs_driver); | ||
1012 | } | ||
1013 | |||
1014 | module_init(init_saa6752hs); | ||
1015 | module_exit(exit_saa6752hs); | ||
1016 | 1005 | ||
1017 | /* | 1006 | /* |
1018 | * Overrides for Emacs so that we follow Linus's tabbing style. | 1007 | * Overrides for Emacs so that we follow Linus's tabbing style. |
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 065d0f6be4a0..53aae5968ffb 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "tea5767.h" | 33 | #include "tea5767.h" |
34 | #include "tda18271.h" | 34 | #include "tda18271.h" |
35 | #include "xc5000.h" | 35 | #include "xc5000.h" |
36 | #include "s5h1411.h" | ||
36 | 37 | ||
37 | /* commly used strings */ | 38 | /* commly used strings */ |
38 | static char name_mute[] = "mute"; | 39 | static char name_mute[] = "mute"; |
@@ -5712,6 +5713,36 @@ struct saa7134_board saa7134_boards[] = { | |||
5712 | .amux = LINE1, | 5713 | .amux = LINE1, |
5713 | } }, | 5714 | } }, |
5714 | }, | 5715 | }, |
5716 | [SAA7134_BOARD_KWORLD_PC150U] = { | ||
5717 | .name = "Kworld PC150-U", | ||
5718 | .audio_clock = 0x00187de7, | ||
5719 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
5720 | .radio_type = UNSET, | ||
5721 | .tuner_addr = ADDR_UNSET, | ||
5722 | .radio_addr = ADDR_UNSET, | ||
5723 | .mpeg = SAA7134_MPEG_DVB, | ||
5724 | .gpiomask = 1 << 21, | ||
5725 | .ts_type = SAA7134_MPEG_TS_PARALLEL, | ||
5726 | .inputs = { { | ||
5727 | .name = name_tv, | ||
5728 | .vmux = 1, | ||
5729 | .amux = TV, | ||
5730 | .tv = 1, | ||
5731 | }, { | ||
5732 | .name = name_comp, | ||
5733 | .vmux = 3, | ||
5734 | .amux = LINE1, | ||
5735 | }, { | ||
5736 | .name = name_svideo, | ||
5737 | .vmux = 8, | ||
5738 | .amux = LINE2, | ||
5739 | } }, | ||
5740 | .radio = { | ||
5741 | .name = name_radio, | ||
5742 | .amux = TV, | ||
5743 | .gpio = 0x0000000, | ||
5744 | }, | ||
5745 | }, | ||
5715 | 5746 | ||
5716 | }; | 5747 | }; |
5717 | 5748 | ||
@@ -6306,6 +6337,12 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
6306 | .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ | 6337 | .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ |
6307 | },{ | 6338 | },{ |
6308 | .vendor = PCI_VENDOR_ID_PHILIPS, | 6339 | .vendor = PCI_VENDOR_ID_PHILIPS, |
6340 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ | ||
6341 | .subvendor = 0x17de, | ||
6342 | .subdevice = 0xa134, | ||
6343 | .driver_data = SAA7134_BOARD_KWORLD_PC150U, | ||
6344 | }, { | ||
6345 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
6309 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | 6346 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, |
6310 | .subvendor = 0x1461, | 6347 | .subvendor = 0x1461, |
6311 | .subdevice = 0x7360, | 6348 | .subdevice = 0x7360, |
@@ -7134,6 +7171,23 @@ static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev, | |||
7134 | return 0; | 7171 | return 0; |
7135 | } | 7172 | } |
7136 | 7173 | ||
7174 | static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev, | ||
7175 | enum tda18271_mode mode) | ||
7176 | { | ||
7177 | switch (mode) { | ||
7178 | case TDA18271_ANALOG: | ||
7179 | saa7134_set_gpio(dev, 18, 0); | ||
7180 | break; | ||
7181 | case TDA18271_DIGITAL: | ||
7182 | saa7134_set_gpio(dev, 18, 1); | ||
7183 | msleep(30); | ||
7184 | break; | ||
7185 | default: | ||
7186 | return -EINVAL; | ||
7187 | } | ||
7188 | return 0; | ||
7189 | } | ||
7190 | |||
7137 | static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, | 7191 | static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, |
7138 | int command, int arg) | 7192 | int command, int arg) |
7139 | { | 7193 | { |
@@ -7150,6 +7204,9 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, | |||
7150 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: | 7204 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: |
7151 | ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg); | 7205 | ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg); |
7152 | break; | 7206 | break; |
7207 | case SAA7134_BOARD_KWORLD_PC150U: | ||
7208 | ret = saa7134_kworld_pc150u_toggle_agc(dev, arg); | ||
7209 | break; | ||
7153 | default: | 7210 | default: |
7154 | break; | 7211 | break; |
7155 | } | 7212 | } |
@@ -7171,6 +7228,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, | |||
7171 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: | 7228 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: |
7172 | case SAA7134_BOARD_AVERMEDIA_M733A: | 7229 | case SAA7134_BOARD_AVERMEDIA_M733A: |
7173 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: | 7230 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: |
7231 | case SAA7134_BOARD_KWORLD_PC150U: | ||
7174 | case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: | 7232 | case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: |
7175 | /* tda8290 + tda18271 */ | 7233 | /* tda8290 + tda18271 */ |
7176 | ret = saa7134_tda8290_18271_callback(dev, command, arg); | 7234 | ret = saa7134_tda8290_18271_callback(dev, command, arg); |
@@ -7452,6 +7510,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
7452 | case SAA7134_BOARD_BEHOLD_X7: | 7510 | case SAA7134_BOARD_BEHOLD_X7: |
7453 | case SAA7134_BOARD_BEHOLD_H7: | 7511 | case SAA7134_BOARD_BEHOLD_H7: |
7454 | case SAA7134_BOARD_BEHOLD_A7: | 7512 | case SAA7134_BOARD_BEHOLD_A7: |
7513 | case SAA7134_BOARD_KWORLD_PC150U: | ||
7455 | dev->has_remote = SAA7134_REMOTE_I2C; | 7514 | dev->has_remote = SAA7134_REMOTE_I2C; |
7456 | break; | 7515 | break; |
7457 | case SAA7134_BOARD_AVERMEDIA_A169_B: | 7516 | case SAA7134_BOARD_AVERMEDIA_A169_B: |
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 089fa0fb5c94..aaa5c97a7216 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include "zl10036.h" | 61 | #include "zl10036.h" |
62 | #include "zl10039.h" | 62 | #include "zl10039.h" |
63 | #include "mt312.h" | 63 | #include "mt312.h" |
64 | #include "s5h1411.h" | ||
64 | 65 | ||
65 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 66 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
66 | MODULE_LICENSE("GPL"); | 67 | MODULE_LICENSE("GPL"); |
@@ -1158,6 +1159,33 @@ static struct tda18271_config prohdtv_pro2_tda18271_config = { | |||
1158 | .output_opt = TDA18271_OUTPUT_LT_OFF, | 1159 | .output_opt = TDA18271_OUTPUT_LT_OFF, |
1159 | }; | 1160 | }; |
1160 | 1161 | ||
1162 | static struct tda18271_std_map kworld_tda18271_std_map = { | ||
1163 | .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3, | ||
1164 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
1165 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, | ||
1166 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
1167 | }; | ||
1168 | |||
1169 | static struct tda18271_config kworld_pc150u_tda18271_config = { | ||
1170 | .std_map = &kworld_tda18271_std_map, | ||
1171 | .gate = TDA18271_GATE_ANALOG, | ||
1172 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
1173 | .config = 3, /* Use tuner callback for AGC */ | ||
1174 | .rf_cal_on_startup = 1 | ||
1175 | }; | ||
1176 | |||
1177 | static struct s5h1411_config kworld_s5h1411_config = { | ||
1178 | .output_mode = S5H1411_PARALLEL_OUTPUT, | ||
1179 | .gpio = S5H1411_GPIO_OFF, | ||
1180 | .qam_if = S5H1411_IF_4000, | ||
1181 | .vsb_if = S5H1411_IF_3250, | ||
1182 | .inversion = S5H1411_INVERSION_ON, | ||
1183 | .status_mode = S5H1411_DEMODLOCKING, | ||
1184 | .mpeg_timing = | ||
1185 | S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
1186 | }; | ||
1187 | |||
1188 | |||
1161 | /* ================================================================== | 1189 | /* ================================================================== |
1162 | * Core code | 1190 | * Core code |
1163 | */ | 1191 | */ |
@@ -1438,6 +1466,22 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1438 | &dev->i2c_adap, 0x61, | 1466 | &dev->i2c_adap, 0x61, |
1439 | TUNER_PHILIPS_TUV1236D); | 1467 | TUNER_PHILIPS_TUV1236D); |
1440 | break; | 1468 | break; |
1469 | case SAA7134_BOARD_KWORLD_PC150U: | ||
1470 | saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */ | ||
1471 | saa7134_tuner_callback(dev, 0, | ||
1472 | TDA18271_CALLBACK_CMD_AGC_ENABLE, 1); | ||
1473 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
1474 | &kworld_s5h1411_config, | ||
1475 | &dev->i2c_adap); | ||
1476 | if (fe0->dvb.frontend != NULL) { | ||
1477 | dvb_attach(tda829x_attach, fe0->dvb.frontend, | ||
1478 | &dev->i2c_adap, 0x4b, | ||
1479 | &tda829x_no_probe); | ||
1480 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
1481 | 0x60, &dev->i2c_adap, | ||
1482 | &kworld_pc150u_tda18271_config); | ||
1483 | } | ||
1484 | break; | ||
1441 | case SAA7134_BOARD_FLYDVBS_LR300: | 1485 | case SAA7134_BOARD_FLYDVBS_LR300: |
1442 | fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, | 1486 | fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, |
1443 | &dev->i2c_adap); | 1487 | &dev->i2c_adap); |
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 2d3f6d265bbf..a176ec3285e0 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c | |||
@@ -254,7 +254,9 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
254 | addr = msgs[i].addr << 1; | 254 | addr = msgs[i].addr << 1; |
255 | if (msgs[i].flags & I2C_M_RD) | 255 | if (msgs[i].flags & I2C_M_RD) |
256 | addr |= 1; | 256 | addr |= 1; |
257 | if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) { | 257 | if (i > 0 && msgs[i].flags & |
258 | I2C_M_RD && msgs[i].addr != 0x40 && | ||
259 | msgs[i].addr != 0x19) { | ||
258 | /* workaround for a saa7134 i2c bug | 260 | /* workaround for a saa7134 i2c bug |
259 | * needed to talk to the mt352 demux | 261 | * needed to talk to the mt352 demux |
260 | * thanks to pinnacle for the hint */ | 262 | * thanks to pinnacle for the hint */ |
@@ -279,6 +281,16 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
279 | d1printk("%02x", rc); | 281 | d1printk("%02x", rc); |
280 | msgs[i].buf[byte] = rc; | 282 | msgs[i].buf[byte] = rc; |
281 | } | 283 | } |
284 | /* discard mysterious extra byte when reading | ||
285 | from Samsung S5H1411. i2c bus gets error | ||
286 | if we do not. */ | ||
287 | if (0x19 == msgs[i].addr) { | ||
288 | d1printk(" ?"); | ||
289 | rc = i2c_recv_byte(dev); | ||
290 | if (rc < 0) | ||
291 | goto err; | ||
292 | d1printk("%02x", rc); | ||
293 | } | ||
282 | } else { | 294 | } else { |
283 | /* write bytes */ | 295 | /* write bytes */ |
284 | d2printk("write bytes\n"); | 296 | d2printk("write bytes\n"); |
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 22ecd7297d2d..48d2878699b7 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -210,6 +210,54 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, | |||
210 | return 1; | 210 | return 1; |
211 | } | 211 | } |
212 | 212 | ||
213 | /* copied and modified from get_key_msi_tvanywhere_plus() */ | ||
214 | static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key, | ||
215 | u32 *ir_raw) | ||
216 | { | ||
217 | unsigned char b; | ||
218 | unsigned int gpio; | ||
219 | |||
220 | /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ | ||
221 | struct saa7134_dev *dev = ir->c->adapter->algo_data; | ||
222 | if (dev == NULL) { | ||
223 | i2cdprintk("get_key_kworld_pc150u: " | ||
224 | "ir->c->adapter->algo_data is NULL!\n"); | ||
225 | return -EIO; | ||
226 | } | ||
227 | |||
228 | /* rising SAA7134_GPIO_GPRESCAN reads the status */ | ||
229 | |||
230 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
231 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
232 | |||
233 | gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); | ||
234 | |||
235 | /* GPIO&0x100 is pulsed low when a button is pressed. Don't do | ||
236 | I2C receive if gpio&0x100 is not low. */ | ||
237 | |||
238 | if (gpio & 0x100) | ||
239 | return 0; /* No button press */ | ||
240 | |||
241 | /* GPIO says there is a button press. Get it. */ | ||
242 | |||
243 | if (1 != i2c_master_recv(ir->c, &b, 1)) { | ||
244 | i2cdprintk("read error\n"); | ||
245 | return -EIO; | ||
246 | } | ||
247 | |||
248 | /* No button press */ | ||
249 | |||
250 | if (b == 0xff) | ||
251 | return 0; | ||
252 | |||
253 | /* Button pressed */ | ||
254 | |||
255 | dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b); | ||
256 | *ir_key = b; | ||
257 | *ir_raw = b; | ||
258 | return 1; | ||
259 | } | ||
260 | |||
213 | static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | 261 | static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) |
214 | { | 262 | { |
215 | unsigned char b; | 263 | unsigned char b; |
@@ -901,6 +949,21 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |||
901 | msg_msi.addr, dev->i2c_adap.name, | 949 | msg_msi.addr, dev->i2c_adap.name, |
902 | (1 == rc) ? "yes" : "no"); | 950 | (1 == rc) ? "yes" : "no"); |
903 | break; | 951 | break; |
952 | case SAA7134_BOARD_KWORLD_PC150U: | ||
953 | /* copied and modified from MSI TV@nywhere Plus */ | ||
954 | dev->init_data.name = "Kworld PC150-U"; | ||
955 | dev->init_data.get_key = get_key_kworld_pc150u; | ||
956 | dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U; | ||
957 | info.addr = 0x30; | ||
958 | /* MSI TV@nywhere Plus controller doesn't seem to | ||
959 | respond to probes unless we read something from | ||
960 | an existing device. Weird... | ||
961 | REVISIT: might no longer be needed */ | ||
962 | rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); | ||
963 | dprintk("probe 0x%02x @ %s: %s\n", | ||
964 | msg_msi.addr, dev->i2c_adap.name, | ||
965 | (1 == rc) ? "yes" : "no"); | ||
966 | break; | ||
904 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: | 967 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: |
905 | dev->init_data.name = "HVR 1110"; | 968 | dev->init_data.name = "HVR 1110"; |
906 | dev->init_data.get_key = get_key_hvr1110; | 969 | dev->init_data.get_key = get_key_hvr1110; |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 42fba4f93c72..f625060e6a0f 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -126,8 +126,8 @@ struct saa7134_card_ir { | |||
126 | unsigned users; | 126 | unsigned users; |
127 | 127 | ||
128 | u32 polling; | 128 | u32 polling; |
129 | u32 last_gpio; | 129 | u32 last_gpio; |
130 | u32 mask_keycode, mask_keydown, mask_keyup; | 130 | u32 mask_keycode, mask_keydown, mask_keyup; |
131 | 131 | ||
132 | bool running; | 132 | bool running; |
133 | bool active; | 133 | bool active; |
@@ -331,6 +331,7 @@ struct saa7134_card_ir { | |||
331 | #define SAA7134_BOARD_BEHOLD_501 186 | 331 | #define SAA7134_BOARD_BEHOLD_501 186 |
332 | #define SAA7134_BOARD_BEHOLD_503FM 187 | 332 | #define SAA7134_BOARD_BEHOLD_503FM 187 |
333 | #define SAA7134_BOARD_SENSORAY811_911 188 | 333 | #define SAA7134_BOARD_SENSORAY811_911 188 |
334 | #define SAA7134_BOARD_KWORLD_PC150U 189 | ||
334 | 335 | ||
335 | #define SAA7134_MAXBOARDS 32 | 336 | #define SAA7134_MAXBOARDS 32 |
336 | #define SAA7134_INPUT_MAX 8 | 337 | #define SAA7134_INPUT_MAX 8 |
diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile index ecd5811dc486..068443af30c8 100644 --- a/drivers/media/video/saa7164/Makefile +++ b/drivers/media/video/saa7164/Makefile | |||
@@ -4,9 +4,9 @@ saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ | |||
4 | 4 | ||
5 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o | 5 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o |
6 | 6 | ||
7 | ccflags-y += -Idrivers/media/video | 7 | ccflags-y += -I$(srctree)/drivers/media/video |
8 | ccflags-y += -Idrivers/media/common/tuners | 8 | ccflags-y += -I$(srctree)/drivers/media/common/tuners |
9 | ccflags-y += -Idrivers/media/dvb/dvb-core | 9 | ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core |
10 | ccflags-y += -Idrivers/media/dvb/frontends | 10 | ccflags-y += -I$(srctree)/drivers/media/dvb/frontends |
11 | 11 | ||
12 | ccflags-y += $(extra-cflags-y) $(extra-cflags-m) | 12 | ccflags-y += $(extra-cflags-y) $(extra-cflags-m) |
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c index 2fd38a01887f..a9ed686ad08a 100644 --- a/drivers/media/video/saa7164/saa7164-encoder.c +++ b/drivers/media/video/saa7164/saa7164-encoder.c | |||
@@ -791,11 +791,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
791 | return 0; | 791 | return 0; |
792 | } | 792 | } |
793 | 793 | ||
794 | static int vidioc_log_status(struct file *file, void *priv) | ||
795 | { | ||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | static int fill_queryctrl(struct saa7164_encoder_params *params, | 794 | static int fill_queryctrl(struct saa7164_encoder_params *params, |
800 | struct v4l2_queryctrl *c) | 795 | struct v4l2_queryctrl *c) |
801 | { | 796 | { |
@@ -1347,7 +1342,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { | |||
1347 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, | 1342 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, |
1348 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, | 1343 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, |
1349 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, | 1344 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, |
1350 | .vidioc_log_status = vidioc_log_status, | ||
1351 | .vidioc_queryctrl = vidioc_queryctrl, | 1345 | .vidioc_queryctrl = vidioc_queryctrl, |
1352 | .vidioc_g_chip_ident = saa7164_g_chip_ident, | 1346 | .vidioc_g_chip_ident = saa7164_g_chip_ident, |
1353 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1347 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c index e2e034158718..273cf807401c 100644 --- a/drivers/media/video/saa7164/saa7164-vbi.c +++ b/drivers/media/video/saa7164/saa7164-vbi.c | |||
@@ -730,11 +730,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
730 | return 0; | 730 | return 0; |
731 | } | 731 | } |
732 | 732 | ||
733 | static int vidioc_log_status(struct file *file, void *priv) | ||
734 | { | ||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static int fill_queryctrl(struct saa7164_vbi_params *params, | 733 | static int fill_queryctrl(struct saa7164_vbi_params *params, |
739 | struct v4l2_queryctrl *c) | 734 | struct v4l2_queryctrl *c) |
740 | { | 735 | { |
@@ -1256,7 +1251,6 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = { | |||
1256 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, | 1251 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, |
1257 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, | 1252 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, |
1258 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, | 1253 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, |
1259 | .vidioc_log_status = vidioc_log_status, | ||
1260 | .vidioc_queryctrl = vidioc_queryctrl, | 1254 | .vidioc_queryctrl = vidioc_queryctrl, |
1261 | #if 0 | 1255 | #if 0 |
1262 | .vidioc_g_chip_ident = saa7164_g_chip_ident, | 1256 | .vidioc_g_chip_ident = saa7164_g_chip_ident, |
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index b6172c2c517e..1e84466515aa 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c | |||
@@ -1375,15 +1375,4 @@ static struct i2c_driver saa717x_driver = { | |||
1375 | .id_table = saa717x_id, | 1375 | .id_table = saa717x_id, |
1376 | }; | 1376 | }; |
1377 | 1377 | ||
1378 | static __init int init_saa717x(void) | 1378 | module_i2c_driver(saa717x_driver); |
1379 | { | ||
1380 | return i2c_add_driver(&saa717x_driver); | ||
1381 | } | ||
1382 | |||
1383 | static __exit void exit_saa717x(void) | ||
1384 | { | ||
1385 | i2c_del_driver(&saa717x_driver); | ||
1386 | } | ||
1387 | |||
1388 | module_init(init_saa717x); | ||
1389 | module_exit(exit_saa717x); | ||
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 96f56c2f11f3..2c6b65c76e2b 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c | |||
@@ -374,15 +374,4 @@ static struct i2c_driver saa7185_driver = { | |||
374 | .id_table = saa7185_id, | 374 | .id_table = saa7185_id, |
375 | }; | 375 | }; |
376 | 376 | ||
377 | static __init int init_saa7185(void) | 377 | module_i2c_driver(saa7185_driver); |
378 | { | ||
379 | return i2c_add_driver(&saa7185_driver); | ||
380 | } | ||
381 | |||
382 | static __exit void exit_saa7185(void) | ||
383 | { | ||
384 | i2c_del_driver(&saa7185_driver); | ||
385 | } | ||
386 | |||
387 | module_init(init_saa7185); | ||
388 | module_exit(exit_saa7185); | ||
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c index 211fa25a1239..d7d1670e0ca3 100644 --- a/drivers/media/video/saa7191.c +++ b/drivers/media/video/saa7191.c | |||
@@ -656,15 +656,4 @@ static struct i2c_driver saa7191_driver = { | |||
656 | .id_table = saa7191_id, | 656 | .id_table = saa7191_id, |
657 | }; | 657 | }; |
658 | 658 | ||
659 | static __init int init_saa7191(void) | 659 | module_i2c_driver(saa7191_driver); |
660 | { | ||
661 | return i2c_add_driver(&saa7191_driver); | ||
662 | } | ||
663 | |||
664 | static __exit void exit_saa7191(void) | ||
665 | { | ||
666 | i2c_del_driver(&saa7191_driver); | ||
667 | } | ||
668 | |||
669 | module_init(init_saa7191); | ||
670 | module_exit(exit_saa7191); | ||
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index f854d85a387c..424dfacd263a 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -112,6 +112,10 @@ struct sh_mobile_ceu_dev { | |||
112 | 112 | ||
113 | u32 cflcr; | 113 | u32 cflcr; |
114 | 114 | ||
115 | /* static max sizes either from platform data or default */ | ||
116 | int max_width; | ||
117 | int max_height; | ||
118 | |||
115 | enum v4l2_field field; | 119 | enum v4l2_field field; |
116 | int sequence; | 120 | int sequence; |
117 | 121 | ||
@@ -1081,7 +1085,15 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
1081 | if (ret < 0) | 1085 | if (ret < 0) |
1082 | return ret; | 1086 | return ret; |
1083 | 1087 | ||
1084 | while ((mf.width > 2560 || mf.height > 1920) && shift < 4) { | 1088 | /* |
1089 | * All currently existing CEU implementations support 2560x1920 | ||
1090 | * or larger frames. If the sensor is proposing too big a frame, | ||
1091 | * don't bother with possibly supportred by the CEU larger | ||
1092 | * sizes, just try VGA multiples. If needed, this can be | ||
1093 | * adjusted in the future. | ||
1094 | */ | ||
1095 | while ((mf.width > pcdev->max_width || | ||
1096 | mf.height > pcdev->max_height) && shift < 4) { | ||
1085 | /* Try 2560x1920, 1280x960, 640x480, 320x240 */ | 1097 | /* Try 2560x1920, 1280x960, 640x480, 320x240 */ |
1086 | mf.width = 2560 >> shift; | 1098 | mf.width = 2560 >> shift; |
1087 | mf.height = 1920 >> shift; | 1099 | mf.height = 1920 >> shift; |
@@ -1377,6 +1389,8 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, | |||
1377 | static int client_s_fmt(struct soc_camera_device *icd, | 1389 | static int client_s_fmt(struct soc_camera_device *icd, |
1378 | struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) | 1390 | struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) |
1379 | { | 1391 | { |
1392 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1393 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1380 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1394 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1381 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1395 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1382 | struct device *dev = icd->parent; | 1396 | struct device *dev = icd->parent; |
@@ -1410,8 +1424,8 @@ static int client_s_fmt(struct soc_camera_device *icd, | |||
1410 | if (ret < 0) | 1424 | if (ret < 0) |
1411 | return ret; | 1425 | return ret; |
1412 | 1426 | ||
1413 | max_width = min(cap.bounds.width, 2560); | 1427 | max_width = min(cap.bounds.width, pcdev->max_width); |
1414 | max_height = min(cap.bounds.height, 1920); | 1428 | max_height = min(cap.bounds.height, pcdev->max_height); |
1415 | 1429 | ||
1416 | /* Camera set a format, but geometry is not precise, try to improve */ | 1430 | /* Camera set a format, but geometry is not precise, try to improve */ |
1417 | tmp_w = mf->width; | 1431 | tmp_w = mf->width; |
@@ -1551,7 +1565,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1551 | if (ret < 0) | 1565 | if (ret < 0) |
1552 | return ret; | 1566 | return ret; |
1553 | 1567 | ||
1554 | if (mf.width > 2560 || mf.height > 1920) | 1568 | if (mf.width > pcdev->max_width || mf.height > pcdev->max_height) |
1555 | return -EINVAL; | 1569 | return -EINVAL; |
1556 | 1570 | ||
1557 | /* 4. Calculate camera scales */ | 1571 | /* 4. Calculate camera scales */ |
@@ -1834,6 +1848,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1834 | static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | 1848 | static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, |
1835 | struct v4l2_format *f) | 1849 | struct v4l2_format *f) |
1836 | { | 1850 | { |
1851 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1852 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1837 | const struct soc_camera_format_xlate *xlate; | 1853 | const struct soc_camera_format_xlate *xlate; |
1838 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1854 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1839 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1855 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
@@ -1854,8 +1870,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1854 | /* FIXME: calculate using depth and bus width */ | 1870 | /* FIXME: calculate using depth and bus width */ |
1855 | 1871 | ||
1856 | /* CFSZR requires height and width to be 4-pixel aligned */ | 1872 | /* CFSZR requires height and width to be 4-pixel aligned */ |
1857 | v4l_bound_align_image(&pix->width, 2, 2560, 2, | 1873 | v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2, |
1858 | &pix->height, 4, 1920, 2, 0); | 1874 | &pix->height, 4, pcdev->max_height, 2, 0); |
1859 | 1875 | ||
1860 | width = pix->width; | 1876 | width = pix->width; |
1861 | height = pix->height; | 1877 | height = pix->height; |
@@ -1890,8 +1906,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1890 | * requested a bigger rectangle, it will not return a | 1906 | * requested a bigger rectangle, it will not return a |
1891 | * smaller one. | 1907 | * smaller one. |
1892 | */ | 1908 | */ |
1893 | mf.width = 2560; | 1909 | mf.width = pcdev->max_width; |
1894 | mf.height = 1920; | 1910 | mf.height = pcdev->max_height; |
1895 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | 1911 | ret = v4l2_device_call_until_err(sd->v4l2_dev, |
1896 | soc_camera_grp_id(icd), video, | 1912 | soc_camera_grp_id(icd), video, |
1897 | try_mbus_fmt, &mf); | 1913 | try_mbus_fmt, &mf); |
@@ -2082,6 +2098,9 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) | |||
2082 | goto exit_kfree; | 2098 | goto exit_kfree; |
2083 | } | 2099 | } |
2084 | 2100 | ||
2101 | pcdev->max_width = pcdev->pdata->max_width ? : 2560; | ||
2102 | pcdev->max_height = pcdev->pdata->max_height ? : 1920; | ||
2103 | |||
2085 | base = ioremap_nocache(res->start, resource_size(res)); | 2104 | base = ioremap_nocache(res->start, resource_size(res)); |
2086 | if (!base) { | 2105 | if (!base) { |
2087 | err = -ENXIO; | 2106 | err = -ENXIO; |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index b82710745ba8..eb25756a07af 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -526,10 +526,6 @@ static int soc_camera_open(struct file *file) | |||
526 | }, | 526 | }, |
527 | }; | 527 | }; |
528 | 528 | ||
529 | ret = soc_camera_power_on(icd, icl); | ||
530 | if (ret < 0) | ||
531 | goto epower; | ||
532 | |||
533 | /* The camera could have been already on, try to reset */ | 529 | /* The camera could have been already on, try to reset */ |
534 | if (icl->reset) | 530 | if (icl->reset) |
535 | icl->reset(icd->pdev); | 531 | icl->reset(icd->pdev); |
@@ -540,6 +536,10 @@ static int soc_camera_open(struct file *file) | |||
540 | goto eiciadd; | 536 | goto eiciadd; |
541 | } | 537 | } |
542 | 538 | ||
539 | ret = soc_camera_power_on(icd, icl); | ||
540 | if (ret < 0) | ||
541 | goto epower; | ||
542 | |||
543 | pm_runtime_enable(&icd->vdev->dev); | 543 | pm_runtime_enable(&icd->vdev->dev); |
544 | ret = pm_runtime_resume(&icd->vdev->dev); | 544 | ret = pm_runtime_resume(&icd->vdev->dev); |
545 | if (ret < 0 && ret != -ENOSYS) | 545 | if (ret < 0 && ret != -ENOSYS) |
@@ -578,10 +578,10 @@ einitvb: | |||
578 | esfmt: | 578 | esfmt: |
579 | pm_runtime_disable(&icd->vdev->dev); | 579 | pm_runtime_disable(&icd->vdev->dev); |
580 | eresume: | 580 | eresume: |
581 | ici->ops->remove(icd); | ||
582 | eiciadd: | ||
583 | soc_camera_power_off(icd, icl); | 581 | soc_camera_power_off(icd, icl); |
584 | epower: | 582 | epower: |
583 | ici->ops->remove(icd); | ||
584 | eiciadd: | ||
585 | icd->use_count--; | 585 | icd->use_count--; |
586 | module_put(ici->ops->owner); | 586 | module_put(ici->ops->owner); |
587 | 587 | ||
@@ -1050,6 +1050,14 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1050 | if (ret < 0) | 1050 | if (ret < 0) |
1051 | goto ereg; | 1051 | goto ereg; |
1052 | 1052 | ||
1053 | /* The camera could have been already on, try to reset */ | ||
1054 | if (icl->reset) | ||
1055 | icl->reset(icd->pdev); | ||
1056 | |||
1057 | ret = ici->ops->add(icd); | ||
1058 | if (ret < 0) | ||
1059 | goto eadd; | ||
1060 | |||
1053 | /* | 1061 | /* |
1054 | * This will not yet call v4l2_subdev_core_ops::s_power(1), because the | 1062 | * This will not yet call v4l2_subdev_core_ops::s_power(1), because the |
1055 | * subdevice has not been initialised yet. We'll have to call it once | 1063 | * subdevice has not been initialised yet. We'll have to call it once |
@@ -1060,14 +1068,6 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1060 | if (ret < 0) | 1068 | if (ret < 0) |
1061 | goto epower; | 1069 | goto epower; |
1062 | 1070 | ||
1063 | /* The camera could have been already on, try to reset */ | ||
1064 | if (icl->reset) | ||
1065 | icl->reset(icd->pdev); | ||
1066 | |||
1067 | ret = ici->ops->add(icd); | ||
1068 | if (ret < 0) | ||
1069 | goto eadd; | ||
1070 | |||
1071 | /* Must have icd->vdev before registering the device */ | 1071 | /* Must have icd->vdev before registering the device */ |
1072 | ret = video_dev_create(icd); | 1072 | ret = video_dev_create(icd); |
1073 | if (ret < 0) | 1073 | if (ret < 0) |
@@ -1165,10 +1165,10 @@ eadddev: | |||
1165 | video_device_release(icd->vdev); | 1165 | video_device_release(icd->vdev); |
1166 | icd->vdev = NULL; | 1166 | icd->vdev = NULL; |
1167 | evdc: | 1167 | evdc: |
1168 | ici->ops->remove(icd); | ||
1169 | eadd: | ||
1170 | soc_camera_power_off(icd, icl); | 1168 | soc_camera_power_off(icd, icl); |
1171 | epower: | 1169 | epower: |
1170 | ici->ops->remove(icd); | ||
1171 | eadd: | ||
1172 | regulator_bulk_free(icl->num_regulators, icl->regulators); | 1172 | regulator_bulk_free(icl->num_regulators, icl->regulators); |
1173 | ereg: | 1173 | ereg: |
1174 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | 1174 | v4l2_ctrl_handler_free(&icd->ctrl_handler); |
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c index d1b07aceaf94..e9d95bda2ab1 100644 --- a/drivers/media/video/sr030pc30.c +++ b/drivers/media/video/sr030pc30.c | |||
@@ -864,18 +864,7 @@ static struct i2c_driver sr030pc30_i2c_driver = { | |||
864 | .id_table = sr030pc30_id, | 864 | .id_table = sr030pc30_id, |
865 | }; | 865 | }; |
866 | 866 | ||
867 | static int __init sr030pc30_init(void) | 867 | module_i2c_driver(sr030pc30_i2c_driver); |
868 | { | ||
869 | return i2c_add_driver(&sr030pc30_i2c_driver); | ||
870 | } | ||
871 | |||
872 | static void __exit sr030pc30_exit(void) | ||
873 | { | ||
874 | i2c_del_driver(&sr030pc30_i2c_driver); | ||
875 | } | ||
876 | |||
877 | module_init(sr030pc30_init); | ||
878 | module_exit(sr030pc30_exit); | ||
879 | 868 | ||
880 | MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver"); | 869 | MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver"); |
881 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | 870 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); |
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index bd218545da9c..f7707e65761e 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c | |||
@@ -482,15 +482,4 @@ static struct i2c_driver tda7432_driver = { | |||
482 | .id_table = tda7432_id, | 482 | .id_table = tda7432_id, |
483 | }; | 483 | }; |
484 | 484 | ||
485 | static __init int init_tda7432(void) | 485 | module_i2c_driver(tda7432_driver); |
486 | { | ||
487 | return i2c_add_driver(&tda7432_driver); | ||
488 | } | ||
489 | |||
490 | static __exit void exit_tda7432(void) | ||
491 | { | ||
492 | i2c_del_driver(&tda7432_driver); | ||
493 | } | ||
494 | |||
495 | module_init(init_tda7432); | ||
496 | module_exit(exit_tda7432); | ||
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index 22fa8202d5ca..465d7086babf 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c | |||
@@ -208,15 +208,4 @@ static struct i2c_driver tda9840_driver = { | |||
208 | .id_table = tda9840_id, | 208 | .id_table = tda9840_id, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | static __init int init_tda9840(void) | 211 | module_i2c_driver(tda9840_driver); |
212 | { | ||
213 | return i2c_add_driver(&tda9840_driver); | ||
214 | } | ||
215 | |||
216 | static __exit void exit_tda9840(void) | ||
217 | { | ||
218 | i2c_del_driver(&tda9840_driver); | ||
219 | } | ||
220 | |||
221 | module_init(init_tda9840); | ||
222 | module_exit(exit_tda9840); | ||
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 827425c5b866..d1d6ea1dd273 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c | |||
@@ -184,15 +184,4 @@ static struct i2c_driver tea6415c_driver = { | |||
184 | .id_table = tea6415c_id, | 184 | .id_table = tea6415c_id, |
185 | }; | 185 | }; |
186 | 186 | ||
187 | static __init int init_tea6415c(void) | 187 | module_i2c_driver(tea6415c_driver); |
188 | { | ||
189 | return i2c_add_driver(&tea6415c_driver); | ||
190 | } | ||
191 | |||
192 | static __exit void exit_tea6415c(void) | ||
193 | { | ||
194 | i2c_del_driver(&tea6415c_driver); | ||
195 | } | ||
196 | |||
197 | module_init(init_tea6415c); | ||
198 | module_exit(exit_tea6415c); | ||
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index f350b6c24500..38757217a074 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c | |||
@@ -166,15 +166,4 @@ static struct i2c_driver tea6420_driver = { | |||
166 | .id_table = tea6420_id, | 166 | .id_table = tea6420_id, |
167 | }; | 167 | }; |
168 | 168 | ||
169 | static __init int init_tea6420(void) | 169 | module_i2c_driver(tea6420_driver); |
170 | { | ||
171 | return i2c_add_driver(&tea6420_driver); | ||
172 | } | ||
173 | |||
174 | static __exit void exit_tea6420(void) | ||
175 | { | ||
176 | i2c_del_driver(&tea6420_driver); | ||
177 | } | ||
178 | |||
179 | module_init(init_tea6420); | ||
180 | module_exit(exit_tea6420); | ||
diff --git a/drivers/media/video/ths7303.c b/drivers/media/video/ths7303.c index 61b1dd118364..e5c0eedebc58 100644 --- a/drivers/media/video/ths7303.c +++ b/drivers/media/video/ths7303.c | |||
@@ -137,16 +137,4 @@ static struct i2c_driver ths7303_driver = { | |||
137 | .id_table = ths7303_id, | 137 | .id_table = ths7303_id, |
138 | }; | 138 | }; |
139 | 139 | ||
140 | static int __init ths7303_init(void) | 140 | module_i2c_driver(ths7303_driver); |
141 | { | ||
142 | return i2c_add_driver(&ths7303_driver); | ||
143 | } | ||
144 | |||
145 | static void __exit ths7303_exit(void) | ||
146 | { | ||
147 | i2c_del_driver(&ths7303_driver); | ||
148 | } | ||
149 | |||
150 | module_init(ths7303_init); | ||
151 | module_exit(ths7303_exit); | ||
152 | |||
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index 286ec7e7062a..809a75a558ee 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c | |||
@@ -227,15 +227,4 @@ static struct i2c_driver tlv320aic23b_driver = { | |||
227 | .id_table = tlv320aic23b_id, | 227 | .id_table = tlv320aic23b_id, |
228 | }; | 228 | }; |
229 | 229 | ||
230 | static __init int init_tlv320aic23b(void) | 230 | module_i2c_driver(tlv320aic23b_driver); |
231 | { | ||
232 | return i2c_add_driver(&tlv320aic23b_driver); | ||
233 | } | ||
234 | |||
235 | static __exit void exit_tlv320aic23b(void) | ||
236 | { | ||
237 | i2c_del_driver(&tlv320aic23b_driver); | ||
238 | } | ||
239 | |||
240 | module_init(init_tlv320aic23b); | ||
241 | module_exit(exit_tlv320aic23b); | ||
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c index 7844607dd45a..859eb90e4d56 100644 --- a/drivers/media/video/tm6000/tm6000-input.c +++ b/drivers/media/video/tm6000/tm6000-input.c | |||
@@ -481,8 +481,6 @@ int tm6000_ir_fini(struct tm6000_core *dev) | |||
481 | 481 | ||
482 | dprintk(2, "%s\n",__func__); | 482 | dprintk(2, "%s\n",__func__); |
483 | 483 | ||
484 | rc_unregister_device(ir->rc); | ||
485 | |||
486 | if (!ir->polling) | 484 | if (!ir->polling) |
487 | __tm6000_ir_int_stop(ir->rc); | 485 | __tm6000_ir_int_stop(ir->rc); |
488 | 486 | ||
@@ -492,6 +490,7 @@ int tm6000_ir_fini(struct tm6000_core *dev) | |||
492 | tm6000_flash_led(dev, 0); | 490 | tm6000_flash_led(dev, 0); |
493 | ir->pwled = 0; | 491 | ir->pwled = 0; |
494 | 492 | ||
493 | rc_unregister_device(ir->rc); | ||
495 | 494 | ||
496 | kfree(ir); | 495 | kfree(ir); |
497 | dev->ir = NULL; | 496 | dev->ir = NULL; |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 4059ea178c2d..a5c6397ad591 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -380,6 +380,21 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
380 | tune_now = 0; | 380 | tune_now = 0; |
381 | break; | 381 | break; |
382 | } | 382 | } |
383 | case TUNER_XC5000C: | ||
384 | { | ||
385 | struct xc5000_config xc5000c_cfg = { | ||
386 | .i2c_address = t->i2c->addr, | ||
387 | /* if_khz will be set at dvb_attach() */ | ||
388 | .if_khz = 0, | ||
389 | .chip_id = XC5000C, | ||
390 | }; | ||
391 | |||
392 | if (!dvb_attach(xc5000_attach, | ||
393 | &t->fe, t->i2c->adapter, &xc5000c_cfg)) | ||
394 | goto attach_failed; | ||
395 | tune_now = 0; | ||
396 | break; | ||
397 | } | ||
383 | case TUNER_NXP_TDA18271: | 398 | case TUNER_NXP_TDA18271: |
384 | { | 399 | { |
385 | struct tda18271_config cfg = { | 400 | struct tda18271_config cfg = { |
@@ -1314,18 +1329,7 @@ static struct i2c_driver tuner_driver = { | |||
1314 | .id_table = tuner_id, | 1329 | .id_table = tuner_id, |
1315 | }; | 1330 | }; |
1316 | 1331 | ||
1317 | static __init int init_tuner(void) | 1332 | module_i2c_driver(tuner_driver); |
1318 | { | ||
1319 | return i2c_add_driver(&tuner_driver); | ||
1320 | } | ||
1321 | |||
1322 | static __exit void exit_tuner(void) | ||
1323 | { | ||
1324 | i2c_del_driver(&tuner_driver); | ||
1325 | } | ||
1326 | |||
1327 | module_init(init_tuner); | ||
1328 | module_exit(exit_tuner); | ||
1329 | 1333 | ||
1330 | MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); | 1334 | MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); |
1331 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | 1335 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); |
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index f22dbef9b95b..c5b1a7365e4f 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c | |||
@@ -2078,15 +2078,4 @@ static struct i2c_driver tvaudio_driver = { | |||
2078 | .id_table = tvaudio_id, | 2078 | .id_table = tvaudio_id, |
2079 | }; | 2079 | }; |
2080 | 2080 | ||
2081 | static __init int init_tvaudio(void) | 2081 | module_i2c_driver(tvaudio_driver); |
2082 | { | ||
2083 | return i2c_add_driver(&tvaudio_driver); | ||
2084 | } | ||
2085 | |||
2086 | static __exit void exit_tvaudio(void) | ||
2087 | { | ||
2088 | i2c_del_driver(&tvaudio_driver); | ||
2089 | } | ||
2090 | |||
2091 | module_init(init_tvaudio); | ||
2092 | module_exit(exit_tvaudio); | ||
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 6103d1b1081e..3b6cf034976a 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c | |||
@@ -286,8 +286,16 @@ hauppauge_tuner[] = | |||
286 | { TUNER_ABSENT, "MaxLinear 301"}, | 286 | { TUNER_ABSENT, "MaxLinear 301"}, |
287 | { TUNER_ABSENT, "Mirics MSi001"}, | 287 | { TUNER_ABSENT, "Mirics MSi001"}, |
288 | { TUNER_ABSENT, "MaxLinear MxL241SF"}, | 288 | { TUNER_ABSENT, "MaxLinear MxL241SF"}, |
289 | { TUNER_ABSENT, "Xceive XC5000C"}, | 289 | { TUNER_XC5000C, "Xceive XC5000C"}, |
290 | { TUNER_ABSENT, "Montage M68TS2020"}, | 290 | { TUNER_ABSENT, "Montage M68TS2020"}, |
291 | { TUNER_ABSENT, "Siano SMS1530"}, | ||
292 | { TUNER_ABSENT, "Dibcom 7090"}, | ||
293 | { TUNER_ABSENT, "Xceive XC5200C"}, | ||
294 | { TUNER_ABSENT, "NXP 18273"}, | ||
295 | { TUNER_ABSENT, "Montage M88TS2022"}, | ||
296 | /* 180-189 */ | ||
297 | { TUNER_ABSENT, "NXP 18272M"}, | ||
298 | { TUNER_ABSENT, "NXP 18272S"}, | ||
291 | }; | 299 | }; |
292 | 300 | ||
293 | /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are | 301 | /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are |
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index dd26cacd0556..cd615c1d6011 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c | |||
@@ -1163,15 +1163,4 @@ static struct i2c_driver tvp514x_driver = { | |||
1163 | .id_table = tvp514x_id, | 1163 | .id_table = tvp514x_id, |
1164 | }; | 1164 | }; |
1165 | 1165 | ||
1166 | static int __init tvp514x_init(void) | 1166 | module_i2c_driver(tvp514x_driver); |
1167 | { | ||
1168 | return i2c_add_driver(&tvp514x_driver); | ||
1169 | } | ||
1170 | |||
1171 | static void __exit tvp514x_exit(void) | ||
1172 | { | ||
1173 | i2c_del_driver(&tvp514x_driver); | ||
1174 | } | ||
1175 | |||
1176 | module_init(tvp514x_init); | ||
1177 | module_exit(tvp514x_exit); | ||
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 6be9910a6e24..1326e11cf4a9 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c | |||
@@ -17,6 +17,13 @@ | |||
17 | 17 | ||
18 | #include "tvp5150_reg.h" | 18 | #include "tvp5150_reg.h" |
19 | 19 | ||
20 | #define TVP5150_H_MAX 720 | ||
21 | #define TVP5150_V_MAX_525_60 480 | ||
22 | #define TVP5150_V_MAX_OTHERS 576 | ||
23 | #define TVP5150_MAX_CROP_LEFT 511 | ||
24 | #define TVP5150_MAX_CROP_TOP 127 | ||
25 | #define TVP5150_CROP_SHIFT 2 | ||
26 | |||
20 | MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); | 27 | MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); |
21 | MODULE_AUTHOR("Mauro Carvalho Chehab"); | 28 | MODULE_AUTHOR("Mauro Carvalho Chehab"); |
22 | MODULE_LICENSE("GPL"); | 29 | MODULE_LICENSE("GPL"); |
@@ -29,6 +36,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); | |||
29 | struct tvp5150 { | 36 | struct tvp5150 { |
30 | struct v4l2_subdev sd; | 37 | struct v4l2_subdev sd; |
31 | struct v4l2_ctrl_handler hdl; | 38 | struct v4l2_ctrl_handler hdl; |
39 | struct v4l2_rect rect; | ||
32 | 40 | ||
33 | v4l2_std_id norm; /* Current set standard */ | 41 | v4l2_std_id norm; /* Current set standard */ |
34 | u32 input; | 42 | u32 input; |
@@ -732,6 +740,13 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) | |||
732 | if (decoder->norm == std) | 740 | if (decoder->norm == std) |
733 | return 0; | 741 | return 0; |
734 | 742 | ||
743 | /* Change cropping height limits */ | ||
744 | if (std & V4L2_STD_525_60) | ||
745 | decoder->rect.height = TVP5150_V_MAX_525_60; | ||
746 | else | ||
747 | decoder->rect.height = TVP5150_V_MAX_OTHERS; | ||
748 | |||
749 | |||
735 | return tvp5150_set_std(sd, std); | 750 | return tvp5150_set_std(sd, std); |
736 | } | 751 | } |
737 | 752 | ||
@@ -828,11 +843,8 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd, | |||
828 | else | 843 | else |
829 | std = decoder->norm; | 844 | std = decoder->norm; |
830 | 845 | ||
831 | f->width = 720; | 846 | f->width = decoder->rect.width; |
832 | if (std & V4L2_STD_525_60) | 847 | f->height = decoder->rect.height; |
833 | f->height = 480; | ||
834 | else | ||
835 | f->height = 576; | ||
836 | 848 | ||
837 | f->code = V4L2_MBUS_FMT_YUYV8_2X8; | 849 | f->code = V4L2_MBUS_FMT_YUYV8_2X8; |
838 | f->field = V4L2_FIELD_SEQ_TB; | 850 | f->field = V4L2_FIELD_SEQ_TB; |
@@ -843,6 +855,99 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd, | |||
843 | return 0; | 855 | return 0; |
844 | } | 856 | } |
845 | 857 | ||
858 | static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
859 | { | ||
860 | struct v4l2_rect rect = a->c; | ||
861 | struct tvp5150 *decoder = to_tvp5150(sd); | ||
862 | v4l2_std_id std; | ||
863 | int hmax; | ||
864 | |||
865 | v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", | ||
866 | __func__, rect.left, rect.top, rect.width, rect.height); | ||
867 | |||
868 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
869 | return -EINVAL; | ||
870 | |||
871 | /* tvp5150 has some special limits */ | ||
872 | rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); | ||
873 | rect.width = clamp(rect.width, | ||
874 | TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, | ||
875 | TVP5150_H_MAX - rect.left); | ||
876 | rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); | ||
877 | |||
878 | /* Calculate height based on current standard */ | ||
879 | if (decoder->norm == V4L2_STD_ALL) | ||
880 | std = tvp5150_read_std(sd); | ||
881 | else | ||
882 | std = decoder->norm; | ||
883 | |||
884 | if (std & V4L2_STD_525_60) | ||
885 | hmax = TVP5150_V_MAX_525_60; | ||
886 | else | ||
887 | hmax = TVP5150_V_MAX_OTHERS; | ||
888 | |||
889 | rect.height = clamp(rect.height, | ||
890 | hmax - TVP5150_MAX_CROP_TOP - rect.top, | ||
891 | hmax - rect.top); | ||
892 | |||
893 | tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); | ||
894 | tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, | ||
895 | rect.top + rect.height - hmax); | ||
896 | tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB, | ||
897 | rect.left >> TVP5150_CROP_SHIFT); | ||
898 | tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB, | ||
899 | rect.left | (1 << TVP5150_CROP_SHIFT)); | ||
900 | tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB, | ||
901 | (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> | ||
902 | TVP5150_CROP_SHIFT); | ||
903 | tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB, | ||
904 | rect.left + rect.width - TVP5150_MAX_CROP_LEFT); | ||
905 | |||
906 | decoder->rect = rect; | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
912 | { | ||
913 | struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); | ||
914 | |||
915 | a->c = decoder->rect; | ||
916 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
922 | { | ||
923 | struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); | ||
924 | v4l2_std_id std; | ||
925 | |||
926 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
927 | return -EINVAL; | ||
928 | |||
929 | a->bounds.left = 0; | ||
930 | a->bounds.top = 0; | ||
931 | a->bounds.width = TVP5150_H_MAX; | ||
932 | |||
933 | /* Calculate height based on current standard */ | ||
934 | if (decoder->norm == V4L2_STD_ALL) | ||
935 | std = tvp5150_read_std(sd); | ||
936 | else | ||
937 | std = decoder->norm; | ||
938 | |||
939 | if (std & V4L2_STD_525_60) | ||
940 | a->bounds.height = TVP5150_V_MAX_525_60; | ||
941 | else | ||
942 | a->bounds.height = TVP5150_V_MAX_OTHERS; | ||
943 | |||
944 | a->defrect = a->bounds; | ||
945 | a->pixelaspect.numerator = 1; | ||
946 | a->pixelaspect.denominator = 1; | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
846 | /**************************************************************************** | 951 | /**************************************************************************** |
847 | I2C Command | 952 | I2C Command |
848 | ****************************************************************************/ | 953 | ****************************************************************************/ |
@@ -998,6 +1103,10 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = { | |||
998 | .enum_mbus_fmt = tvp5150_enum_mbus_fmt, | 1103 | .enum_mbus_fmt = tvp5150_enum_mbus_fmt, |
999 | .s_mbus_fmt = tvp5150_mbus_fmt, | 1104 | .s_mbus_fmt = tvp5150_mbus_fmt, |
1000 | .try_mbus_fmt = tvp5150_mbus_fmt, | 1105 | .try_mbus_fmt = tvp5150_mbus_fmt, |
1106 | .g_mbus_fmt = tvp5150_mbus_fmt, | ||
1107 | .s_crop = tvp5150_s_crop, | ||
1108 | .g_crop = tvp5150_g_crop, | ||
1109 | .cropcap = tvp5150_cropcap, | ||
1001 | }; | 1110 | }; |
1002 | 1111 | ||
1003 | static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { | 1112 | static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { |
@@ -1083,6 +1192,15 @@ static int tvp5150_probe(struct i2c_client *c, | |||
1083 | } | 1192 | } |
1084 | v4l2_ctrl_handler_setup(&core->hdl); | 1193 | v4l2_ctrl_handler_setup(&core->hdl); |
1085 | 1194 | ||
1195 | /* Default is no cropping */ | ||
1196 | core->rect.top = 0; | ||
1197 | if (tvp5150_read_std(sd) & V4L2_STD_525_60) | ||
1198 | core->rect.height = TVP5150_V_MAX_525_60; | ||
1199 | else | ||
1200 | core->rect.height = TVP5150_V_MAX_OTHERS; | ||
1201 | core->rect.left = 0; | ||
1202 | core->rect.width = TVP5150_H_MAX; | ||
1203 | |||
1086 | if (debug > 1) | 1204 | if (debug > 1) |
1087 | tvp5150_log_status(sd); | 1205 | tvp5150_log_status(sd); |
1088 | return 0; | 1206 | return 0; |
@@ -1121,15 +1239,4 @@ static struct i2c_driver tvp5150_driver = { | |||
1121 | .id_table = tvp5150_id, | 1239 | .id_table = tvp5150_id, |
1122 | }; | 1240 | }; |
1123 | 1241 | ||
1124 | static __init int init_tvp5150(void) | 1242 | module_i2c_driver(tvp5150_driver); |
1125 | { | ||
1126 | return i2c_add_driver(&tvp5150_driver); | ||
1127 | } | ||
1128 | |||
1129 | static __exit void exit_tvp5150(void) | ||
1130 | { | ||
1131 | i2c_del_driver(&tvp5150_driver); | ||
1132 | } | ||
1133 | |||
1134 | module_init(init_tvp5150); | ||
1135 | module_exit(exit_tvp5150); | ||
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index 236c559d5f51..d7676d85c4df 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c | |||
@@ -1069,27 +1069,4 @@ static struct i2c_driver tvp7002_driver = { | |||
1069 | .id_table = tvp7002_id, | 1069 | .id_table = tvp7002_id, |
1070 | }; | 1070 | }; |
1071 | 1071 | ||
1072 | /* | 1072 | module_i2c_driver(tvp7002_driver); |
1073 | * tvp7002_init - Initialize driver via I2C interface | ||
1074 | * | ||
1075 | * Register the TVP7002 driver. | ||
1076 | * Return 0 on success or error code on failure. | ||
1077 | */ | ||
1078 | static int __init tvp7002_init(void) | ||
1079 | { | ||
1080 | return i2c_add_driver(&tvp7002_driver); | ||
1081 | } | ||
1082 | |||
1083 | /* | ||
1084 | * tvp7002_exit - Remove driver via I2C interface | ||
1085 | * | ||
1086 | * Unregister the TVP7002 driver. | ||
1087 | * Returns nothing. | ||
1088 | */ | ||
1089 | static void __exit tvp7002_exit(void) | ||
1090 | { | ||
1091 | i2c_del_driver(&tvp7002_driver); | ||
1092 | } | ||
1093 | |||
1094 | module_init(tvp7002_init); | ||
1095 | module_exit(tvp7002_exit); | ||
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index a514fa61116c..8768efb8508a 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c | |||
@@ -951,21 +951,7 @@ static struct i2c_driver tw9910_i2c_driver = { | |||
951 | .id_table = tw9910_id, | 951 | .id_table = tw9910_id, |
952 | }; | 952 | }; |
953 | 953 | ||
954 | /* | 954 | module_i2c_driver(tw9910_i2c_driver); |
955 | * module function | ||
956 | */ | ||
957 | static int __init tw9910_module_init(void) | ||
958 | { | ||
959 | return i2c_add_driver(&tw9910_i2c_driver); | ||
960 | } | ||
961 | |||
962 | static void __exit tw9910_module_exit(void) | ||
963 | { | ||
964 | i2c_del_driver(&tw9910_i2c_driver); | ||
965 | } | ||
966 | |||
967 | module_init(tw9910_module_init); | ||
968 | module_exit(tw9910_module_exit); | ||
969 | 955 | ||
970 | MODULE_DESCRIPTION("SoC Camera driver for tw9910"); | 956 | MODULE_DESCRIPTION("SoC Camera driver for tw9910"); |
971 | MODULE_AUTHOR("Kuninori Morimoto"); | 957 | MODULE_AUTHOR("Kuninori Morimoto"); |
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 1aab96a88203..1e7446542091 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c | |||
@@ -271,15 +271,4 @@ static struct i2c_driver upd64031a_driver = { | |||
271 | .id_table = upd64031a_id, | 271 | .id_table = upd64031a_id, |
272 | }; | 272 | }; |
273 | 273 | ||
274 | static __init int init_upd64031a(void) | 274 | module_i2c_driver(upd64031a_driver); |
275 | { | ||
276 | return i2c_add_driver(&upd64031a_driver); | ||
277 | } | ||
278 | |||
279 | static __exit void exit_upd64031a(void) | ||
280 | { | ||
281 | i2c_del_driver(&upd64031a_driver); | ||
282 | } | ||
283 | |||
284 | module_init(init_upd64031a); | ||
285 | module_exit(exit_upd64031a); | ||
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 65d065aa6091..75d6acc62018 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c | |||
@@ -243,15 +243,4 @@ static struct i2c_driver upd64083_driver = { | |||
243 | .id_table = upd64083_id, | 243 | .id_table = upd64083_id, |
244 | }; | 244 | }; |
245 | 245 | ||
246 | static __init int init_upd64083(void) | 246 | module_i2c_driver(upd64083_driver); |
247 | { | ||
248 | return i2c_add_driver(&upd64083_driver); | ||
249 | } | ||
250 | |||
251 | static __exit void exit_upd64083(void) | ||
252 | { | ||
253 | i2c_del_driver(&upd64083_driver); | ||
254 | } | ||
255 | |||
256 | module_init(init_upd64083); | ||
257 | module_exit(exit_upd64083); | ||
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index a240d43d15d1..1d131720b6d7 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -23,6 +23,7 @@ | |||
23 | * codec can't handle MJPEG data. | 23 | * codec can't handle MJPEG data. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/atomic.h> | ||
26 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
27 | #include <linux/list.h> | 28 | #include <linux/list.h> |
28 | #include <linux/module.h> | 29 | #include <linux/module.h> |
@@ -32,7 +33,6 @@ | |||
32 | #include <linux/vmalloc.h> | 33 | #include <linux/vmalloc.h> |
33 | #include <linux/wait.h> | 34 | #include <linux/wait.h> |
34 | #include <linux/version.h> | 35 | #include <linux/version.h> |
35 | #include <asm/atomic.h> | ||
36 | #include <asm/unaligned.h> | 36 | #include <asm/unaligned.h> |
37 | 37 | ||
38 | #include <media/v4l2-common.h> | 38 | #include <media/v4l2-common.h> |
@@ -2139,6 +2139,15 @@ static struct usb_device_id uvc_ids[] = { | |||
2139 | .bInterfaceSubClass = 1, | 2139 | .bInterfaceSubClass = 1, |
2140 | .bInterfaceProtocol = 0, | 2140 | .bInterfaceProtocol = 0, |
2141 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | 2141 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, |
2142 | /* Dell XPS m1530 */ | ||
2143 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | ||
2144 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
2145 | .idVendor = 0x05a9, | ||
2146 | .idProduct = 0x2640, | ||
2147 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
2148 | .bInterfaceSubClass = 1, | ||
2149 | .bInterfaceProtocol = 0, | ||
2150 | .driver_info = UVC_QUIRK_PROBE_DEF }, | ||
2142 | /* Apple Built-In iSight */ | 2151 | /* Apple Built-In iSight */ |
2143 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 2152 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
2144 | | USB_DEVICE_ID_MATCH_INT_INFO, | 2153 | | USB_DEVICE_ID_MATCH_INT_INFO, |
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 518f77d3a4d8..8f54e24e3f35 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c | |||
@@ -126,7 +126,7 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, | |||
126 | int drop_corrupted) | 126 | int drop_corrupted) |
127 | { | 127 | { |
128 | queue->queue.type = type; | 128 | queue->queue.type = type; |
129 | queue->queue.io_modes = VB2_MMAP; | 129 | queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; |
130 | queue->queue.drv_priv = queue; | 130 | queue->queue.drv_priv = queue; |
131 | queue->queue.buf_struct_size = sizeof(struct uvc_buffer); | 131 | queue->queue.buf_struct_size = sizeof(struct uvc_buffer); |
132 | queue->queue.ops = &uvc_queue_qops; | 132 | queue->queue.ops = &uvc_queue_qops; |
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 2ae4f880ea05..ff2cdddf9bc6 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/compat.h> | ||
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/version.h> | 16 | #include <linux/version.h> |
16 | #include <linux/list.h> | 17 | #include <linux/list.h> |
@@ -1012,7 +1013,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
1012 | 1013 | ||
1013 | default: | 1014 | default: |
1014 | uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); | 1015 | uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); |
1015 | return -EINVAL; | 1016 | return -ENOTTY; |
1016 | } | 1017 | } |
1017 | 1018 | ||
1018 | return ret; | 1019 | return ret; |
@@ -1030,6 +1031,207 @@ static long uvc_v4l2_ioctl(struct file *file, | |||
1030 | return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); | 1031 | return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); |
1031 | } | 1032 | } |
1032 | 1033 | ||
1034 | #ifdef CONFIG_COMPAT | ||
1035 | struct uvc_xu_control_mapping32 { | ||
1036 | __u32 id; | ||
1037 | __u8 name[32]; | ||
1038 | __u8 entity[16]; | ||
1039 | __u8 selector; | ||
1040 | |||
1041 | __u8 size; | ||
1042 | __u8 offset; | ||
1043 | __u32 v4l2_type; | ||
1044 | __u32 data_type; | ||
1045 | |||
1046 | compat_caddr_t menu_info; | ||
1047 | __u32 menu_count; | ||
1048 | |||
1049 | __u32 reserved[4]; | ||
1050 | }; | ||
1051 | |||
1052 | static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, | ||
1053 | const struct uvc_xu_control_mapping32 __user *up) | ||
1054 | { | ||
1055 | struct uvc_menu_info __user *umenus; | ||
1056 | struct uvc_menu_info __user *kmenus; | ||
1057 | compat_caddr_t p; | ||
1058 | |||
1059 | if (!access_ok(VERIFY_READ, up, sizeof(*up)) || | ||
1060 | __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) || | ||
1061 | __get_user(kp->menu_count, &up->menu_count)) | ||
1062 | return -EFAULT; | ||
1063 | |||
1064 | memset(kp->reserved, 0, sizeof(kp->reserved)); | ||
1065 | |||
1066 | if (kp->menu_count == 0) { | ||
1067 | kp->menu_info = NULL; | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | if (__get_user(p, &up->menu_info)) | ||
1072 | return -EFAULT; | ||
1073 | umenus = compat_ptr(p); | ||
1074 | if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus))) | ||
1075 | return -EFAULT; | ||
1076 | |||
1077 | kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus)); | ||
1078 | if (kmenus == NULL) | ||
1079 | return -EFAULT; | ||
1080 | kp->menu_info = kmenus; | ||
1081 | |||
1082 | if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus))) | ||
1083 | return -EFAULT; | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, | ||
1089 | struct uvc_xu_control_mapping32 __user *up) | ||
1090 | { | ||
1091 | struct uvc_menu_info __user *umenus; | ||
1092 | struct uvc_menu_info __user *kmenus = kp->menu_info; | ||
1093 | compat_caddr_t p; | ||
1094 | |||
1095 | if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || | ||
1096 | __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) || | ||
1097 | __put_user(kp->menu_count, &up->menu_count)) | ||
1098 | return -EFAULT; | ||
1099 | |||
1100 | __clear_user(up->reserved, sizeof(up->reserved)); | ||
1101 | |||
1102 | if (kp->menu_count == 0) | ||
1103 | return 0; | ||
1104 | |||
1105 | if (get_user(p, &up->menu_info)) | ||
1106 | return -EFAULT; | ||
1107 | umenus = compat_ptr(p); | ||
1108 | if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus))) | ||
1109 | return -EFAULT; | ||
1110 | |||
1111 | if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus))) | ||
1112 | return -EFAULT; | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | struct uvc_xu_control_query32 { | ||
1118 | __u8 unit; | ||
1119 | __u8 selector; | ||
1120 | __u8 query; | ||
1121 | __u16 size; | ||
1122 | compat_caddr_t data; | ||
1123 | }; | ||
1124 | |||
1125 | static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, | ||
1126 | const struct uvc_xu_control_query32 __user *up) | ||
1127 | { | ||
1128 | u8 __user *udata; | ||
1129 | u8 __user *kdata; | ||
1130 | compat_caddr_t p; | ||
1131 | |||
1132 | if (!access_ok(VERIFY_READ, up, sizeof(*up)) || | ||
1133 | __copy_from_user(kp, up, offsetof(typeof(*up), data))) | ||
1134 | return -EFAULT; | ||
1135 | |||
1136 | if (kp->size == 0) { | ||
1137 | kp->data = NULL; | ||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1141 | if (__get_user(p, &up->data)) | ||
1142 | return -EFAULT; | ||
1143 | udata = compat_ptr(p); | ||
1144 | if (!access_ok(VERIFY_READ, udata, kp->size)) | ||
1145 | return -EFAULT; | ||
1146 | |||
1147 | kdata = compat_alloc_user_space(kp->size); | ||
1148 | if (kdata == NULL) | ||
1149 | return -EFAULT; | ||
1150 | kp->data = kdata; | ||
1151 | |||
1152 | if (copy_in_user(kdata, udata, kp->size)) | ||
1153 | return -EFAULT; | ||
1154 | |||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
1158 | static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, | ||
1159 | struct uvc_xu_control_query32 __user *up) | ||
1160 | { | ||
1161 | u8 __user *udata; | ||
1162 | u8 __user *kdata = kp->data; | ||
1163 | compat_caddr_t p; | ||
1164 | |||
1165 | if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || | ||
1166 | __copy_to_user(up, kp, offsetof(typeof(*up), data))) | ||
1167 | return -EFAULT; | ||
1168 | |||
1169 | if (kp->size == 0) | ||
1170 | return 0; | ||
1171 | |||
1172 | if (get_user(p, &up->data)) | ||
1173 | return -EFAULT; | ||
1174 | udata = compat_ptr(p); | ||
1175 | if (!access_ok(VERIFY_READ, udata, kp->size)) | ||
1176 | return -EFAULT; | ||
1177 | |||
1178 | if (copy_in_user(udata, kdata, kp->size)) | ||
1179 | return -EFAULT; | ||
1180 | |||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | #define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32) | ||
1185 | #define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32) | ||
1186 | |||
1187 | static long uvc_v4l2_compat_ioctl32(struct file *file, | ||
1188 | unsigned int cmd, unsigned long arg) | ||
1189 | { | ||
1190 | union { | ||
1191 | struct uvc_xu_control_mapping xmap; | ||
1192 | struct uvc_xu_control_query xqry; | ||
1193 | } karg; | ||
1194 | void __user *up = compat_ptr(arg); | ||
1195 | mm_segment_t old_fs; | ||
1196 | long ret; | ||
1197 | |||
1198 | switch (cmd) { | ||
1199 | case UVCIOC_CTRL_MAP32: | ||
1200 | cmd = UVCIOC_CTRL_MAP; | ||
1201 | ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); | ||
1202 | break; | ||
1203 | |||
1204 | case UVCIOC_CTRL_QUERY32: | ||
1205 | cmd = UVCIOC_CTRL_QUERY; | ||
1206 | ret = uvc_v4l2_get_xu_query(&karg.xqry, up); | ||
1207 | break; | ||
1208 | |||
1209 | default: | ||
1210 | return -ENOIOCTLCMD; | ||
1211 | } | ||
1212 | |||
1213 | old_fs = get_fs(); | ||
1214 | set_fs(KERNEL_DS); | ||
1215 | ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg); | ||
1216 | set_fs(old_fs); | ||
1217 | |||
1218 | if (ret < 0) | ||
1219 | return ret; | ||
1220 | |||
1221 | switch (cmd) { | ||
1222 | case UVCIOC_CTRL_MAP: | ||
1223 | ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); | ||
1224 | break; | ||
1225 | |||
1226 | case UVCIOC_CTRL_QUERY: | ||
1227 | ret = uvc_v4l2_put_xu_query(&karg.xqry, up); | ||
1228 | break; | ||
1229 | } | ||
1230 | |||
1231 | return ret; | ||
1232 | } | ||
1233 | #endif | ||
1234 | |||
1033 | static ssize_t uvc_v4l2_read(struct file *file, char __user *data, | 1235 | static ssize_t uvc_v4l2_read(struct file *file, char __user *data, |
1034 | size_t count, loff_t *ppos) | 1236 | size_t count, loff_t *ppos) |
1035 | { | 1237 | { |
@@ -1076,6 +1278,9 @@ const struct v4l2_file_operations uvc_fops = { | |||
1076 | .open = uvc_v4l2_open, | 1278 | .open = uvc_v4l2_open, |
1077 | .release = uvc_v4l2_release, | 1279 | .release = uvc_v4l2_release, |
1078 | .unlocked_ioctl = uvc_v4l2_ioctl, | 1280 | .unlocked_ioctl = uvc_v4l2_ioctl, |
1281 | #ifdef CONFIG_COMPAT | ||
1282 | .compat_ioctl32 = uvc_v4l2_compat_ioctl32, | ||
1283 | #endif | ||
1079 | .read = uvc_v4l2_read, | 1284 | .read = uvc_v4l2_read, |
1080 | .mmap = uvc_v4l2_mmap, | 1285 | .mmap = uvc_v4l2_mmap, |
1081 | .poll = uvc_v4l2_poll, | 1286 | .poll = uvc_v4l2_poll, |
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index af4419e6c658..2829d256e4b7 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c | |||
@@ -14,12 +14,11 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/compat.h> | 16 | #include <linux/compat.h> |
17 | #include <linux/videodev2.h> | ||
18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/videodev2.h> | ||
19 | #include <media/v4l2-dev.h> | ||
19 | #include <media/v4l2-ioctl.h> | 20 | #include <media/v4l2-ioctl.h> |
20 | 21 | ||
21 | #ifdef CONFIG_COMPAT | ||
22 | |||
23 | static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 22 | static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
24 | { | 23 | { |
25 | long ret = -ENOIOCTLCMD; | 24 | long ret = -ENOIOCTLCMD; |
@@ -937,6 +936,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
937 | 936 | ||
938 | long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | 937 | long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) |
939 | { | 938 | { |
939 | struct video_device *vdev = video_devdata(file); | ||
940 | long ret = -ENOIOCTLCMD; | 940 | long ret = -ENOIOCTLCMD; |
941 | 941 | ||
942 | if (!file->f_op->unlocked_ioctl) | 942 | if (!file->f_op->unlocked_ioctl) |
@@ -1005,6 +1005,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | |||
1005 | case VIDIOC_G_ENC_INDEX: | 1005 | case VIDIOC_G_ENC_INDEX: |
1006 | case VIDIOC_ENCODER_CMD: | 1006 | case VIDIOC_ENCODER_CMD: |
1007 | case VIDIOC_TRY_ENCODER_CMD: | 1007 | case VIDIOC_TRY_ENCODER_CMD: |
1008 | case VIDIOC_DECODER_CMD: | ||
1009 | case VIDIOC_TRY_DECODER_CMD: | ||
1008 | case VIDIOC_DBG_S_REGISTER: | 1010 | case VIDIOC_DBG_S_REGISTER: |
1009 | case VIDIOC_DBG_G_REGISTER: | 1011 | case VIDIOC_DBG_G_REGISTER: |
1010 | case VIDIOC_DBG_G_CHIP_IDENT: | 1012 | case VIDIOC_DBG_G_CHIP_IDENT: |
@@ -1025,14 +1027,16 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | |||
1025 | break; | 1027 | break; |
1026 | 1028 | ||
1027 | default: | 1029 | default: |
1028 | printk(KERN_WARNING "compat_ioctl32: " | 1030 | if (vdev->fops->compat_ioctl32) |
1029 | "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", | 1031 | ret = vdev->fops->compat_ioctl32(file, cmd, arg); |
1030 | _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd); | 1032 | |
1033 | if (ret == -ENOIOCTLCMD) | ||
1034 | printk(KERN_WARNING "compat_ioctl32: " | ||
1035 | "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", | ||
1036 | _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), | ||
1037 | cmd); | ||
1031 | break; | 1038 | break; |
1032 | } | 1039 | } |
1033 | return ret; | 1040 | return ret; |
1034 | } | 1041 | } |
1035 | EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); | 1042 | EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); |
1036 | #endif | ||
1037 | |||
1038 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index cccd42be718a..18015c0a8d31 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c | |||
@@ -175,6 +175,15 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
175 | "16-bit CRC", | 175 | "16-bit CRC", |
176 | NULL | 176 | NULL |
177 | }; | 177 | }; |
178 | static const char * const mpeg_audio_dec_playback[] = { | ||
179 | "Auto", | ||
180 | "Stereo", | ||
181 | "Left", | ||
182 | "Right", | ||
183 | "Mono", | ||
184 | "Swapped Stereo", | ||
185 | NULL | ||
186 | }; | ||
178 | static const char * const mpeg_video_encoding[] = { | 187 | static const char * const mpeg_video_encoding[] = { |
179 | "MPEG-1", | 188 | "MPEG-1", |
180 | "MPEG-2", | 189 | "MPEG-2", |
@@ -236,8 +245,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
236 | }; | 245 | }; |
237 | static const char * const tune_preemphasis[] = { | 246 | static const char * const tune_preemphasis[] = { |
238 | "No Preemphasis", | 247 | "No Preemphasis", |
239 | "50 useconds", | 248 | "50 Microseconds", |
240 | "75 useconds", | 249 | "75 Microseconds", |
241 | NULL, | 250 | NULL, |
242 | }; | 251 | }; |
243 | static const char * const header_mode[] = { | 252 | static const char * const header_mode[] = { |
@@ -334,7 +343,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
334 | }; | 343 | }; |
335 | static const char * const mpeg4_profile[] = { | 344 | static const char * const mpeg4_profile[] = { |
336 | "Simple", | 345 | "Simple", |
337 | "Adcanved Simple", | 346 | "Advanced Simple", |
338 | "Core", | 347 | "Core", |
339 | "Simple Scalable", | 348 | "Simple Scalable", |
340 | "Advanced Coding Efficency", | 349 | "Advanced Coding Efficency", |
@@ -353,6 +362,16 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
353 | NULL, | 362 | NULL, |
354 | }; | 363 | }; |
355 | 364 | ||
365 | static const char * const jpeg_chroma_subsampling[] = { | ||
366 | "4:4:4", | ||
367 | "4:2:2", | ||
368 | "4:2:0", | ||
369 | "4:1:1", | ||
370 | "4:1:0", | ||
371 | "Gray", | ||
372 | NULL, | ||
373 | }; | ||
374 | |||
356 | switch (id) { | 375 | switch (id) { |
357 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: | 376 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: |
358 | return mpeg_audio_sampling_freq; | 377 | return mpeg_audio_sampling_freq; |
@@ -374,6 +393,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
374 | return mpeg_audio_emphasis; | 393 | return mpeg_audio_emphasis; |
375 | case V4L2_CID_MPEG_AUDIO_CRC: | 394 | case V4L2_CID_MPEG_AUDIO_CRC: |
376 | return mpeg_audio_crc; | 395 | return mpeg_audio_crc; |
396 | case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: | ||
397 | case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: | ||
398 | return mpeg_audio_dec_playback; | ||
377 | case V4L2_CID_MPEG_VIDEO_ENCODING: | 399 | case V4L2_CID_MPEG_VIDEO_ENCODING: |
378 | return mpeg_video_encoding; | 400 | return mpeg_video_encoding; |
379 | case V4L2_CID_MPEG_VIDEO_ASPECT: | 401 | case V4L2_CID_MPEG_VIDEO_ASPECT: |
@@ -414,6 +436,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
414 | return mpeg_mpeg4_level; | 436 | return mpeg_mpeg4_level; |
415 | case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: | 437 | case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: |
416 | return mpeg4_profile; | 438 | return mpeg4_profile; |
439 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: | ||
440 | return jpeg_chroma_subsampling; | ||
441 | |||
417 | default: | 442 | default: |
418 | return NULL; | 443 | return NULL; |
419 | } | 444 | } |
@@ -492,6 +517,8 @@ const char *v4l2_ctrl_get_name(u32 id) | |||
492 | case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; | 517 | case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; |
493 | case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; | 518 | case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; |
494 | case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; | 519 | case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; |
520 | case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback"; | ||
521 | case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback"; | ||
495 | case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; | 522 | case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; |
496 | case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; | 523 | case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; |
497 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; | 524 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; |
@@ -546,6 +573,8 @@ const char *v4l2_ctrl_get_name(u32 id) | |||
546 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice"; | 573 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice"; |
547 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method"; | 574 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method"; |
548 | case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; | 575 | case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; |
576 | case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; | ||
577 | case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; | ||
549 | 578 | ||
550 | /* CAMERA controls */ | 579 | /* CAMERA controls */ |
551 | /* Keep the order of the 'case's the same as in videodev2.h! */ | 580 | /* Keep the order of the 'case's the same as in videodev2.h! */ |
@@ -607,6 +636,14 @@ const char *v4l2_ctrl_get_name(u32 id) | |||
607 | case V4L2_CID_FLASH_CHARGE: return "Charge"; | 636 | case V4L2_CID_FLASH_CHARGE: return "Charge"; |
608 | case V4L2_CID_FLASH_READY: return "Ready to Strobe"; | 637 | case V4L2_CID_FLASH_READY: return "Ready to Strobe"; |
609 | 638 | ||
639 | /* JPEG encoder controls */ | ||
640 | /* Keep the order of the 'case's the same as in videodev2.h! */ | ||
641 | case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls"; | ||
642 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling"; | ||
643 | case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval"; | ||
644 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality"; | ||
645 | case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers"; | ||
646 | |||
610 | default: | 647 | default: |
611 | return NULL; | 648 | return NULL; |
612 | } | 649 | } |
@@ -674,6 +711,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, | |||
674 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: | 711 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: |
675 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: | 712 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: |
676 | case V4L2_CID_MPEG_AUDIO_CRC: | 713 | case V4L2_CID_MPEG_AUDIO_CRC: |
714 | case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: | ||
715 | case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: | ||
677 | case V4L2_CID_MPEG_VIDEO_ENCODING: | 716 | case V4L2_CID_MPEG_VIDEO_ENCODING: |
678 | case V4L2_CID_MPEG_VIDEO_ASPECT: | 717 | case V4L2_CID_MPEG_VIDEO_ASPECT: |
679 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | 718 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: |
@@ -693,6 +732,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, | |||
693 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: | 732 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: |
694 | case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: | 733 | case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: |
695 | case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: | 734 | case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: |
735 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: | ||
696 | *type = V4L2_CTRL_TYPE_MENU; | 736 | *type = V4L2_CTRL_TYPE_MENU; |
697 | break; | 737 | break; |
698 | case V4L2_CID_RDS_TX_PS_NAME: | 738 | case V4L2_CID_RDS_TX_PS_NAME: |
@@ -704,6 +744,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, | |||
704 | case V4L2_CID_MPEG_CLASS: | 744 | case V4L2_CID_MPEG_CLASS: |
705 | case V4L2_CID_FM_TX_CLASS: | 745 | case V4L2_CID_FM_TX_CLASS: |
706 | case V4L2_CID_FLASH_CLASS: | 746 | case V4L2_CID_FLASH_CLASS: |
747 | case V4L2_CID_JPEG_CLASS: | ||
707 | *type = V4L2_CTRL_TYPE_CTRL_CLASS; | 748 | *type = V4L2_CTRL_TYPE_CTRL_CLASS; |
708 | /* You can neither read not write these */ | 749 | /* You can neither read not write these */ |
709 | *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; | 750 | *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; |
@@ -717,6 +758,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, | |||
717 | *max = 0xFFFFFF; | 758 | *max = 0xFFFFFF; |
718 | break; | 759 | break; |
719 | case V4L2_CID_FLASH_FAULT: | 760 | case V4L2_CID_FLASH_FAULT: |
761 | case V4L2_CID_JPEG_ACTIVE_MARKER: | ||
720 | *type = V4L2_CTRL_TYPE_BITMASK; | 762 | *type = V4L2_CTRL_TYPE_BITMASK; |
721 | break; | 763 | break; |
722 | case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: | 764 | case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: |
@@ -724,6 +766,11 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, | |||
724 | *type = V4L2_CTRL_TYPE_INTEGER; | 766 | *type = V4L2_CTRL_TYPE_INTEGER; |
725 | *flags |= V4L2_CTRL_FLAG_READ_ONLY; | 767 | *flags |= V4L2_CTRL_FLAG_READ_ONLY; |
726 | break; | 768 | break; |
769 | case V4L2_CID_MPEG_VIDEO_DEC_FRAME: | ||
770 | case V4L2_CID_MPEG_VIDEO_DEC_PTS: | ||
771 | *type = V4L2_CTRL_TYPE_INTEGER64; | ||
772 | *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE; | ||
773 | break; | ||
727 | default: | 774 | default: |
728 | *type = V4L2_CTRL_TYPE_INTEGER; | 775 | *type = V4L2_CTRL_TYPE_INTEGER; |
729 | break; | 776 | break; |
@@ -1470,7 +1517,7 @@ EXPORT_SYMBOL(v4l2_ctrl_add_ctrl); | |||
1470 | int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, | 1517 | int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, |
1471 | struct v4l2_ctrl_handler *add) | 1518 | struct v4l2_ctrl_handler *add) |
1472 | { | 1519 | { |
1473 | struct v4l2_ctrl *ctrl; | 1520 | struct v4l2_ctrl_ref *ref; |
1474 | int ret = 0; | 1521 | int ret = 0; |
1475 | 1522 | ||
1476 | /* Do nothing if either handler is NULL or if they are the same */ | 1523 | /* Do nothing if either handler is NULL or if they are the same */ |
@@ -1479,7 +1526,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, | |||
1479 | if (hdl->error) | 1526 | if (hdl->error) |
1480 | return hdl->error; | 1527 | return hdl->error; |
1481 | mutex_lock(&add->lock); | 1528 | mutex_lock(&add->lock); |
1482 | list_for_each_entry(ctrl, &add->ctrls, node) { | 1529 | list_for_each_entry(ref, &add->ctrl_refs, node) { |
1530 | struct v4l2_ctrl *ctrl = ref->ctrl; | ||
1531 | |||
1483 | /* Skip handler-private controls. */ | 1532 | /* Skip handler-private controls. */ |
1484 | if (ctrl->is_private) | 1533 | if (ctrl->is_private) |
1485 | continue; | 1534 | continue; |
@@ -2359,3 +2408,35 @@ void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl, | |||
2359 | v4l2_ctrl_unlock(ctrl); | 2408 | v4l2_ctrl_unlock(ctrl); |
2360 | } | 2409 | } |
2361 | EXPORT_SYMBOL(v4l2_ctrl_del_event); | 2410 | EXPORT_SYMBOL(v4l2_ctrl_del_event); |
2411 | |||
2412 | int v4l2_ctrl_log_status(struct file *file, void *fh) | ||
2413 | { | ||
2414 | struct video_device *vfd = video_devdata(file); | ||
2415 | struct v4l2_fh *vfh = file->private_data; | ||
2416 | |||
2417 | if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) | ||
2418 | v4l2_ctrl_handler_log_status(vfh->ctrl_handler, | ||
2419 | vfd->v4l2_dev->name); | ||
2420 | return 0; | ||
2421 | } | ||
2422 | EXPORT_SYMBOL(v4l2_ctrl_log_status); | ||
2423 | |||
2424 | int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, | ||
2425 | struct v4l2_event_subscription *sub) | ||
2426 | { | ||
2427 | if (sub->type == V4L2_EVENT_CTRL) | ||
2428 | return v4l2_event_subscribe(fh, sub, 0); | ||
2429 | return -EINVAL; | ||
2430 | } | ||
2431 | EXPORT_SYMBOL(v4l2_ctrl_subscribe_event); | ||
2432 | |||
2433 | unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) | ||
2434 | { | ||
2435 | struct v4l2_fh *fh = file->private_data; | ||
2436 | |||
2437 | if (v4l2_event_pending(fh)) | ||
2438 | return POLLPRI; | ||
2439 | poll_wait(file, &fh->wait, wait); | ||
2440 | return 0; | ||
2441 | } | ||
2442 | EXPORT_SYMBOL(v4l2_ctrl_poll); | ||
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 96e9615663e9..041804b73ebd 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -788,7 +788,7 @@ static void __exit videodev_exit(void) | |||
788 | unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); | 788 | unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); |
789 | } | 789 | } |
790 | 790 | ||
791 | module_init(videodev_init) | 791 | subsys_initcall(videodev_init); |
792 | module_exit(videodev_exit) | 792 | module_exit(videodev_exit) |
793 | 793 | ||
794 | MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>"); | 794 | MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>"); |
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 3f623859a337..5b2ec1fd2d0a 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c | |||
@@ -260,6 +260,8 @@ static const char *v4l2_ioctls[] = { | |||
260 | [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", | 260 | [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", |
261 | [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", | 261 | [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", |
262 | 262 | ||
263 | [_IOC_NR(VIDIOC_DECODER_CMD)] = "VIDIOC_DECODER_CMD", | ||
264 | [_IOC_NR(VIDIOC_TRY_DECODER_CMD)] = "VIDIOC_TRY_DECODER_CMD", | ||
263 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", | 265 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", |
264 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", | 266 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", |
265 | 267 | ||
@@ -540,10 +542,12 @@ static long __video_do_ioctl(struct file *file, | |||
540 | if (!ret) | 542 | if (!ret) |
541 | dbgarg(cmd, "driver=%s, card=%s, bus=%s, " | 543 | dbgarg(cmd, "driver=%s, card=%s, bus=%s, " |
542 | "version=0x%08x, " | 544 | "version=0x%08x, " |
543 | "capabilities=0x%08x\n", | 545 | "capabilities=0x%08x, " |
546 | "device_caps=0x%08x\n", | ||
544 | cap->driver, cap->card, cap->bus_info, | 547 | cap->driver, cap->card, cap->bus_info, |
545 | cap->version, | 548 | cap->version, |
546 | cap->capabilities); | 549 | cap->capabilities, |
550 | cap->device_caps); | ||
547 | break; | 551 | break; |
548 | } | 552 | } |
549 | 553 | ||
@@ -1762,6 +1766,32 @@ static long __video_do_ioctl(struct file *file, | |||
1762 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); | 1766 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); |
1763 | break; | 1767 | break; |
1764 | } | 1768 | } |
1769 | case VIDIOC_DECODER_CMD: | ||
1770 | { | ||
1771 | struct v4l2_decoder_cmd *p = arg; | ||
1772 | |||
1773 | if (!ops->vidioc_decoder_cmd) | ||
1774 | break; | ||
1775 | if (ret_prio) { | ||
1776 | ret = ret_prio; | ||
1777 | break; | ||
1778 | } | ||
1779 | ret = ops->vidioc_decoder_cmd(file, fh, p); | ||
1780 | if (!ret) | ||
1781 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); | ||
1782 | break; | ||
1783 | } | ||
1784 | case VIDIOC_TRY_DECODER_CMD: | ||
1785 | { | ||
1786 | struct v4l2_decoder_cmd *p = arg; | ||
1787 | |||
1788 | if (!ops->vidioc_try_decoder_cmd) | ||
1789 | break; | ||
1790 | ret = ops->vidioc_try_decoder_cmd(file, fh, p); | ||
1791 | if (!ret) | ||
1792 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); | ||
1793 | break; | ||
1794 | } | ||
1765 | case VIDIOC_G_PARM: | 1795 | case VIDIOC_G_PARM: |
1766 | { | 1796 | { |
1767 | struct v4l2_streamparm *p = arg; | 1797 | struct v4l2_streamparm *p = arg; |
@@ -1909,7 +1939,13 @@ static long __video_do_ioctl(struct file *file, | |||
1909 | { | 1939 | { |
1910 | if (!ops->vidioc_log_status) | 1940 | if (!ops->vidioc_log_status) |
1911 | break; | 1941 | break; |
1942 | if (vfd->v4l2_dev) | ||
1943 | pr_info("%s: ================= START STATUS =================\n", | ||
1944 | vfd->v4l2_dev->name); | ||
1912 | ret = ops->vidioc_log_status(file, fh); | 1945 | ret = ops->vidioc_log_status(file, fh); |
1946 | if (vfd->v4l2_dev) | ||
1947 | pr_info("%s: ================== END STATUS ==================\n", | ||
1948 | vfd->v4l2_dev->name); | ||
1913 | break; | 1949 | break; |
1914 | } | 1950 | } |
1915 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1951 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -2419,7 +2455,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | |||
2419 | /* Handles IOCTL */ | 2455 | /* Handles IOCTL */ |
2420 | err = func(file, cmd, parg); | 2456 | err = func(file, cmd, parg); |
2421 | if (err == -ENOIOCTLCMD) | 2457 | if (err == -ENOIOCTLCMD) |
2422 | err = -EINVAL; | 2458 | err = -ENOTTY; |
2423 | 2459 | ||
2424 | if (has_array_args) { | 2460 | if (has_array_args) { |
2425 | *kernel_ptr = user_ptr; | 2461 | *kernel_ptr = user_ptr; |
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 41d118ee2de6..6fe88e965a8c 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c | |||
@@ -194,8 +194,16 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
194 | } | 194 | } |
195 | #endif | 195 | #endif |
196 | 196 | ||
197 | case VIDIOC_LOG_STATUS: | 197 | case VIDIOC_LOG_STATUS: { |
198 | return v4l2_subdev_call(sd, core, log_status); | 198 | int ret; |
199 | |||
200 | pr_info("%s: ================= START STATUS =================\n", | ||
201 | sd->name); | ||
202 | ret = v4l2_subdev_call(sd, core, log_status); | ||
203 | pr_info("%s: ================== END STATUS ==================\n", | ||
204 | sd->name); | ||
205 | return ret; | ||
206 | } | ||
199 | 207 | ||
200 | #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) | 208 | #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) |
201 | case VIDIOC_SUBDEV_G_FMT: { | 209 | case VIDIOC_SUBDEV_G_FMT: { |
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c index 4e789a178f8a..6b5ca6c70a46 100644 --- a/drivers/media/video/videobuf2-vmalloc.c +++ b/drivers/media/video/videobuf2-vmalloc.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * the Free Software Foundation. | 10 | * the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/io.h> | ||
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
15 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
@@ -22,6 +23,7 @@ | |||
22 | struct vb2_vmalloc_buf { | 23 | struct vb2_vmalloc_buf { |
23 | void *vaddr; | 24 | void *vaddr; |
24 | struct page **pages; | 25 | struct page **pages; |
26 | struct vm_area_struct *vma; | ||
25 | int write; | 27 | int write; |
26 | unsigned long size; | 28 | unsigned long size; |
27 | unsigned int n_pages; | 29 | unsigned int n_pages; |
@@ -71,6 +73,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, | |||
71 | struct vb2_vmalloc_buf *buf; | 73 | struct vb2_vmalloc_buf *buf; |
72 | unsigned long first, last; | 74 | unsigned long first, last; |
73 | int n_pages, offset; | 75 | int n_pages, offset; |
76 | struct vm_area_struct *vma; | ||
77 | dma_addr_t physp; | ||
74 | 78 | ||
75 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | 79 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
76 | if (!buf) | 80 | if (!buf) |
@@ -80,23 +84,37 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, | |||
80 | offset = vaddr & ~PAGE_MASK; | 84 | offset = vaddr & ~PAGE_MASK; |
81 | buf->size = size; | 85 | buf->size = size; |
82 | 86 | ||
83 | first = vaddr >> PAGE_SHIFT; | ||
84 | last = (vaddr + size - 1) >> PAGE_SHIFT; | ||
85 | buf->n_pages = last - first + 1; | ||
86 | buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL); | ||
87 | if (!buf->pages) | ||
88 | goto fail_pages_array_alloc; | ||
89 | 87 | ||
90 | /* current->mm->mmap_sem is taken by videobuf2 core */ | 88 | vma = find_vma(current->mm, vaddr); |
91 | n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK, | 89 | if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) { |
92 | buf->n_pages, write, 1, /* force */ | 90 | if (vb2_get_contig_userptr(vaddr, size, &vma, &physp)) |
93 | buf->pages, NULL); | 91 | goto fail_pages_array_alloc; |
94 | if (n_pages != buf->n_pages) | 92 | buf->vma = vma; |
95 | goto fail_get_user_pages; | 93 | buf->vaddr = ioremap_nocache(physp, size); |
96 | 94 | if (!buf->vaddr) | |
97 | buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL); | 95 | goto fail_pages_array_alloc; |
98 | if (!buf->vaddr) | 96 | } else { |
99 | goto fail_get_user_pages; | 97 | first = vaddr >> PAGE_SHIFT; |
98 | last = (vaddr + size - 1) >> PAGE_SHIFT; | ||
99 | buf->n_pages = last - first + 1; | ||
100 | buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), | ||
101 | GFP_KERNEL); | ||
102 | if (!buf->pages) | ||
103 | goto fail_pages_array_alloc; | ||
104 | |||
105 | /* current->mm->mmap_sem is taken by videobuf2 core */ | ||
106 | n_pages = get_user_pages(current, current->mm, | ||
107 | vaddr & PAGE_MASK, buf->n_pages, | ||
108 | write, 1, /* force */ | ||
109 | buf->pages, NULL); | ||
110 | if (n_pages != buf->n_pages) | ||
111 | goto fail_get_user_pages; | ||
112 | |||
113 | buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, | ||
114 | PAGE_KERNEL); | ||
115 | if (!buf->vaddr) | ||
116 | goto fail_get_user_pages; | ||
117 | } | ||
100 | 118 | ||
101 | buf->vaddr += offset; | 119 | buf->vaddr += offset; |
102 | return buf; | 120 | return buf; |
@@ -120,14 +138,20 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) | |||
120 | unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; | 138 | unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; |
121 | unsigned int i; | 139 | unsigned int i; |
122 | 140 | ||
123 | if (vaddr) | 141 | if (buf->pages) { |
124 | vm_unmap_ram((void *)vaddr, buf->n_pages); | 142 | if (vaddr) |
125 | for (i = 0; i < buf->n_pages; ++i) { | 143 | vm_unmap_ram((void *)vaddr, buf->n_pages); |
126 | if (buf->write) | 144 | for (i = 0; i < buf->n_pages; ++i) { |
127 | set_page_dirty_lock(buf->pages[i]); | 145 | if (buf->write) |
128 | put_page(buf->pages[i]); | 146 | set_page_dirty_lock(buf->pages[i]); |
147 | put_page(buf->pages[i]); | ||
148 | } | ||
149 | kfree(buf->pages); | ||
150 | } else { | ||
151 | if (buf->vma) | ||
152 | vb2_put_vma(buf->vma); | ||
153 | iounmap(buf->vaddr); | ||
129 | } | 154 | } |
130 | kfree(buf->pages); | ||
131 | kfree(buf); | 155 | kfree(buf); |
132 | } | 156 | } |
133 | 157 | ||
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 7d754fbcccbf..5e8b0710105b 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c | |||
@@ -819,8 +819,9 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
819 | strcpy(cap->driver, "vivi"); | 819 | strcpy(cap->driver, "vivi"); |
820 | strcpy(cap->card, "vivi"); | 820 | strcpy(cap->card, "vivi"); |
821 | strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); | 821 | strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); |
822 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \ | 822 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
823 | V4L2_CAP_READWRITE; | 823 | V4L2_CAP_READWRITE; |
824 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
824 | return 0; | 825 | return 0; |
825 | } | 826 | } |
826 | 827 | ||
@@ -958,14 +959,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | |||
958 | return vb2_streamoff(&dev->vb_vidq, i); | 959 | return vb2_streamoff(&dev->vb_vidq, i); |
959 | } | 960 | } |
960 | 961 | ||
961 | static int vidioc_log_status(struct file *file, void *priv) | ||
962 | { | ||
963 | struct vivi_dev *dev = video_drvdata(file); | ||
964 | |||
965 | v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name); | ||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) | 962 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) |
970 | { | 963 | { |
971 | return 0; | 964 | return 0; |
@@ -1008,17 +1001,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | |||
1008 | return 0; | 1001 | return 0; |
1009 | } | 1002 | } |
1010 | 1003 | ||
1011 | static int vidioc_subscribe_event(struct v4l2_fh *fh, | ||
1012 | struct v4l2_event_subscription *sub) | ||
1013 | { | ||
1014 | switch (sub->type) { | ||
1015 | case V4L2_EVENT_CTRL: | ||
1016 | return v4l2_event_subscribe(fh, sub, 0); | ||
1017 | default: | ||
1018 | return -EINVAL; | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | /* --- controls ---------------------------------------------- */ | 1004 | /* --- controls ---------------------------------------------- */ |
1023 | 1005 | ||
1024 | static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | 1006 | static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
@@ -1209,8 +1191,8 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = { | |||
1209 | .vidioc_s_input = vidioc_s_input, | 1191 | .vidioc_s_input = vidioc_s_input, |
1210 | .vidioc_streamon = vidioc_streamon, | 1192 | .vidioc_streamon = vidioc_streamon, |
1211 | .vidioc_streamoff = vidioc_streamoff, | 1193 | .vidioc_streamoff = vidioc_streamoff, |
1212 | .vidioc_log_status = vidioc_log_status, | 1194 | .vidioc_log_status = v4l2_ctrl_log_status, |
1213 | .vidioc_subscribe_event = vidioc_subscribe_event, | 1195 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
1214 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | 1196 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
1215 | }; | 1197 | }; |
1216 | 1198 | ||
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index c15efb6e7771..7cfbc9d94a48 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c | |||
@@ -208,15 +208,4 @@ static struct i2c_driver vp27smpx_driver = { | |||
208 | .id_table = vp27smpx_id, | 208 | .id_table = vp27smpx_id, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | static __init int init_vp27smpx(void) | 211 | module_i2c_driver(vp27smpx_driver); |
212 | { | ||
213 | return i2c_add_driver(&vp27smpx_driver); | ||
214 | } | ||
215 | |||
216 | static __exit void exit_vp27smpx(void) | ||
217 | { | ||
218 | i2c_del_driver(&vp27smpx_driver); | ||
219 | } | ||
220 | |||
221 | module_init(init_vp27smpx); | ||
222 | module_exit(exit_vp27smpx); | ||
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index e5cad6ff64a1..2f67b4c5c823 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c | |||
@@ -588,15 +588,4 @@ static struct i2c_driver vpx3220_driver = { | |||
588 | .id_table = vpx3220_id, | 588 | .id_table = vpx3220_id, |
589 | }; | 589 | }; |
590 | 590 | ||
591 | static __init int init_vpx3220(void) | 591 | module_i2c_driver(vpx3220_driver); |
592 | { | ||
593 | return i2c_add_driver(&vpx3220_driver); | ||
594 | } | ||
595 | |||
596 | static __exit void exit_vpx3220(void) | ||
597 | { | ||
598 | i2c_del_driver(&vpx3220_driver); | ||
599 | } | ||
600 | |||
601 | module_init(init_vpx3220); | ||
602 | module_exit(exit_vpx3220); | ||
diff --git a/drivers/media/video/vs6624.c b/drivers/media/video/vs6624.c new file mode 100644 index 000000000000..42ae9dc9c574 --- /dev/null +++ b/drivers/media/video/vs6624.c | |||
@@ -0,0 +1,928 @@ | |||
1 | /* | ||
2 | * vs6624.c ST VS6624 CMOS image sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/videodev2.h> | ||
29 | |||
30 | #include <media/v4l2-chip-ident.h> | ||
31 | #include <media/v4l2-ctrls.h> | ||
32 | #include <media/v4l2-device.h> | ||
33 | #include <media/v4l2-mediabus.h> | ||
34 | |||
35 | #include "vs6624_regs.h" | ||
36 | |||
37 | #define VGA_WIDTH 640 | ||
38 | #define VGA_HEIGHT 480 | ||
39 | #define QVGA_WIDTH 320 | ||
40 | #define QVGA_HEIGHT 240 | ||
41 | #define QQVGA_WIDTH 160 | ||
42 | #define QQVGA_HEIGHT 120 | ||
43 | #define CIF_WIDTH 352 | ||
44 | #define CIF_HEIGHT 288 | ||
45 | #define QCIF_WIDTH 176 | ||
46 | #define QCIF_HEIGHT 144 | ||
47 | #define QQCIF_WIDTH 88 | ||
48 | #define QQCIF_HEIGHT 72 | ||
49 | |||
50 | #define MAX_FRAME_RATE 30 | ||
51 | |||
52 | struct vs6624 { | ||
53 | struct v4l2_subdev sd; | ||
54 | struct v4l2_ctrl_handler hdl; | ||
55 | struct v4l2_fract frame_rate; | ||
56 | struct v4l2_mbus_framefmt fmt; | ||
57 | unsigned ce_pin; | ||
58 | }; | ||
59 | |||
60 | static const struct vs6624_format { | ||
61 | enum v4l2_mbus_pixelcode mbus_code; | ||
62 | enum v4l2_colorspace colorspace; | ||
63 | } vs6624_formats[] = { | ||
64 | { | ||
65 | .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
66 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
67 | }, | ||
68 | { | ||
69 | .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
70 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
71 | }, | ||
72 | { | ||
73 | .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
74 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
75 | }, | ||
76 | }; | ||
77 | |||
78 | static struct v4l2_mbus_framefmt vs6624_default_fmt = { | ||
79 | .width = VGA_WIDTH, | ||
80 | .height = VGA_HEIGHT, | ||
81 | .code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
82 | .field = V4L2_FIELD_NONE, | ||
83 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
84 | }; | ||
85 | |||
86 | static const u16 vs6624_p1[] = { | ||
87 | 0x8104, 0x03, | ||
88 | 0x8105, 0x01, | ||
89 | 0xc900, 0x03, | ||
90 | 0xc904, 0x47, | ||
91 | 0xc905, 0x10, | ||
92 | 0xc906, 0x80, | ||
93 | 0xc907, 0x3a, | ||
94 | 0x903a, 0x02, | ||
95 | 0x903b, 0x47, | ||
96 | 0x903c, 0x15, | ||
97 | 0xc908, 0x31, | ||
98 | 0xc909, 0xdc, | ||
99 | 0xc90a, 0x80, | ||
100 | 0xc90b, 0x44, | ||
101 | 0x9044, 0x02, | ||
102 | 0x9045, 0x31, | ||
103 | 0x9046, 0xe2, | ||
104 | 0xc90c, 0x07, | ||
105 | 0xc90d, 0xe0, | ||
106 | 0xc90e, 0x80, | ||
107 | 0xc90f, 0x47, | ||
108 | 0x9047, 0x90, | ||
109 | 0x9048, 0x83, | ||
110 | 0x9049, 0x81, | ||
111 | 0x904a, 0xe0, | ||
112 | 0x904b, 0x60, | ||
113 | 0x904c, 0x08, | ||
114 | 0x904d, 0x90, | ||
115 | 0x904e, 0xc0, | ||
116 | 0x904f, 0x43, | ||
117 | 0x9050, 0x74, | ||
118 | 0x9051, 0x01, | ||
119 | 0x9052, 0xf0, | ||
120 | 0x9053, 0x80, | ||
121 | 0x9054, 0x05, | ||
122 | 0x9055, 0xE4, | ||
123 | 0x9056, 0x90, | ||
124 | 0x9057, 0xc0, | ||
125 | 0x9058, 0x43, | ||
126 | 0x9059, 0xf0, | ||
127 | 0x905a, 0x02, | ||
128 | 0x905b, 0x07, | ||
129 | 0x905c, 0xec, | ||
130 | 0xc910, 0x5d, | ||
131 | 0xc911, 0xca, | ||
132 | 0xc912, 0x80, | ||
133 | 0xc913, 0x5d, | ||
134 | 0x905d, 0xa3, | ||
135 | 0x905e, 0x04, | ||
136 | 0x905f, 0xf0, | ||
137 | 0x9060, 0xa3, | ||
138 | 0x9061, 0x04, | ||
139 | 0x9062, 0xf0, | ||
140 | 0x9063, 0x22, | ||
141 | 0xc914, 0x72, | ||
142 | 0xc915, 0x92, | ||
143 | 0xc916, 0x80, | ||
144 | 0xc917, 0x64, | ||
145 | 0x9064, 0x74, | ||
146 | 0x9065, 0x01, | ||
147 | 0x9066, 0x02, | ||
148 | 0x9067, 0x72, | ||
149 | 0x9068, 0x95, | ||
150 | 0xc918, 0x47, | ||
151 | 0xc919, 0xf2, | ||
152 | 0xc91a, 0x81, | ||
153 | 0xc91b, 0x69, | ||
154 | 0x9169, 0x74, | ||
155 | 0x916a, 0x02, | ||
156 | 0x916b, 0xf0, | ||
157 | 0x916c, 0xec, | ||
158 | 0x916d, 0xb4, | ||
159 | 0x916e, 0x10, | ||
160 | 0x916f, 0x0a, | ||
161 | 0x9170, 0x90, | ||
162 | 0x9171, 0x80, | ||
163 | 0x9172, 0x16, | ||
164 | 0x9173, 0xe0, | ||
165 | 0x9174, 0x70, | ||
166 | 0x9175, 0x04, | ||
167 | 0x9176, 0x90, | ||
168 | 0x9177, 0xd3, | ||
169 | 0x9178, 0xc4, | ||
170 | 0x9179, 0xf0, | ||
171 | 0x917a, 0x22, | ||
172 | 0xc91c, 0x0a, | ||
173 | 0xc91d, 0xbe, | ||
174 | 0xc91e, 0x80, | ||
175 | 0xc91f, 0x73, | ||
176 | 0x9073, 0xfc, | ||
177 | 0x9074, 0xa3, | ||
178 | 0x9075, 0xe0, | ||
179 | 0x9076, 0xf5, | ||
180 | 0x9077, 0x82, | ||
181 | 0x9078, 0x8c, | ||
182 | 0x9079, 0x83, | ||
183 | 0x907a, 0xa3, | ||
184 | 0x907b, 0xa3, | ||
185 | 0x907c, 0xe0, | ||
186 | 0x907d, 0xfc, | ||
187 | 0x907e, 0xa3, | ||
188 | 0x907f, 0xe0, | ||
189 | 0x9080, 0xc3, | ||
190 | 0x9081, 0x9f, | ||
191 | 0x9082, 0xff, | ||
192 | 0x9083, 0xec, | ||
193 | 0x9084, 0x9e, | ||
194 | 0x9085, 0xfe, | ||
195 | 0x9086, 0x02, | ||
196 | 0x9087, 0x0a, | ||
197 | 0x9088, 0xea, | ||
198 | 0xc920, 0x47, | ||
199 | 0xc921, 0x38, | ||
200 | 0xc922, 0x80, | ||
201 | 0xc923, 0x89, | ||
202 | 0x9089, 0xec, | ||
203 | 0x908a, 0xd3, | ||
204 | 0x908b, 0x94, | ||
205 | 0x908c, 0x20, | ||
206 | 0x908d, 0x40, | ||
207 | 0x908e, 0x01, | ||
208 | 0x908f, 0x1c, | ||
209 | 0x9090, 0x90, | ||
210 | 0x9091, 0xd3, | ||
211 | 0x9092, 0xd4, | ||
212 | 0x9093, 0xec, | ||
213 | 0x9094, 0xf0, | ||
214 | 0x9095, 0x02, | ||
215 | 0x9096, 0x47, | ||
216 | 0x9097, 0x3d, | ||
217 | 0xc924, 0x45, | ||
218 | 0xc925, 0xca, | ||
219 | 0xc926, 0x80, | ||
220 | 0xc927, 0x98, | ||
221 | 0x9098, 0x12, | ||
222 | 0x9099, 0x77, | ||
223 | 0x909a, 0xd6, | ||
224 | 0x909b, 0x02, | ||
225 | 0x909c, 0x45, | ||
226 | 0x909d, 0xcd, | ||
227 | 0xc928, 0x20, | ||
228 | 0xc929, 0xd5, | ||
229 | 0xc92a, 0x80, | ||
230 | 0xc92b, 0x9e, | ||
231 | 0x909e, 0x90, | ||
232 | 0x909f, 0x82, | ||
233 | 0x90a0, 0x18, | ||
234 | 0x90a1, 0xe0, | ||
235 | 0x90a2, 0xb4, | ||
236 | 0x90a3, 0x03, | ||
237 | 0x90a4, 0x0e, | ||
238 | 0x90a5, 0x90, | ||
239 | 0x90a6, 0x83, | ||
240 | 0x90a7, 0xbf, | ||
241 | 0x90a8, 0xe0, | ||
242 | 0x90a9, 0x60, | ||
243 | 0x90aa, 0x08, | ||
244 | 0x90ab, 0x90, | ||
245 | 0x90ac, 0x81, | ||
246 | 0x90ad, 0xfc, | ||
247 | 0x90ae, 0xe0, | ||
248 | 0x90af, 0xff, | ||
249 | 0x90b0, 0xc3, | ||
250 | 0x90b1, 0x13, | ||
251 | 0x90b2, 0xf0, | ||
252 | 0x90b3, 0x90, | ||
253 | 0x90b4, 0x81, | ||
254 | 0x90b5, 0xfc, | ||
255 | 0x90b6, 0xe0, | ||
256 | 0x90b7, 0xff, | ||
257 | 0x90b8, 0x02, | ||
258 | 0x90b9, 0x20, | ||
259 | 0x90ba, 0xda, | ||
260 | 0xc92c, 0x70, | ||
261 | 0xc92d, 0xbc, | ||
262 | 0xc92e, 0x80, | ||
263 | 0xc92f, 0xbb, | ||
264 | 0x90bb, 0x90, | ||
265 | 0x90bc, 0x82, | ||
266 | 0x90bd, 0x18, | ||
267 | 0x90be, 0xe0, | ||
268 | 0x90bf, 0xb4, | ||
269 | 0x90c0, 0x03, | ||
270 | 0x90c1, 0x06, | ||
271 | 0x90c2, 0x90, | ||
272 | 0x90c3, 0xc1, | ||
273 | 0x90c4, 0x06, | ||
274 | 0x90c5, 0x74, | ||
275 | 0x90c6, 0x05, | ||
276 | 0x90c7, 0xf0, | ||
277 | 0x90c8, 0x90, | ||
278 | 0x90c9, 0xd3, | ||
279 | 0x90ca, 0xa0, | ||
280 | 0x90cb, 0x02, | ||
281 | 0x90cc, 0x70, | ||
282 | 0x90cd, 0xbf, | ||
283 | 0xc930, 0x72, | ||
284 | 0xc931, 0x21, | ||
285 | 0xc932, 0x81, | ||
286 | 0xc933, 0x3b, | ||
287 | 0x913b, 0x7d, | ||
288 | 0x913c, 0x02, | ||
289 | 0x913d, 0x7f, | ||
290 | 0x913e, 0x7b, | ||
291 | 0x913f, 0x02, | ||
292 | 0x9140, 0x72, | ||
293 | 0x9141, 0x25, | ||
294 | 0xc934, 0x28, | ||
295 | 0xc935, 0xae, | ||
296 | 0xc936, 0x80, | ||
297 | 0xc937, 0xd2, | ||
298 | 0x90d2, 0xf0, | ||
299 | 0x90d3, 0x90, | ||
300 | 0x90d4, 0xd2, | ||
301 | 0x90d5, 0x0a, | ||
302 | 0x90d6, 0x02, | ||
303 | 0x90d7, 0x28, | ||
304 | 0x90d8, 0xb4, | ||
305 | 0xc938, 0x28, | ||
306 | 0xc939, 0xb1, | ||
307 | 0xc93a, 0x80, | ||
308 | 0xc93b, 0xd9, | ||
309 | 0x90d9, 0x90, | ||
310 | 0x90da, 0x83, | ||
311 | 0x90db, 0xba, | ||
312 | 0x90dc, 0xe0, | ||
313 | 0x90dd, 0xff, | ||
314 | 0x90de, 0x90, | ||
315 | 0x90df, 0xd2, | ||
316 | 0x90e0, 0x08, | ||
317 | 0x90e1, 0xe0, | ||
318 | 0x90e2, 0xe4, | ||
319 | 0x90e3, 0xef, | ||
320 | 0x90e4, 0xf0, | ||
321 | 0x90e5, 0xa3, | ||
322 | 0x90e6, 0xe0, | ||
323 | 0x90e7, 0x74, | ||
324 | 0x90e8, 0xff, | ||
325 | 0x90e9, 0xf0, | ||
326 | 0x90ea, 0x90, | ||
327 | 0x90eb, 0xd2, | ||
328 | 0x90ec, 0x0a, | ||
329 | 0x90ed, 0x02, | ||
330 | 0x90ee, 0x28, | ||
331 | 0x90ef, 0xb4, | ||
332 | 0xc93c, 0x29, | ||
333 | 0xc93d, 0x79, | ||
334 | 0xc93e, 0x80, | ||
335 | 0xc93f, 0xf0, | ||
336 | 0x90f0, 0xf0, | ||
337 | 0x90f1, 0x90, | ||
338 | 0x90f2, 0xd2, | ||
339 | 0x90f3, 0x0e, | ||
340 | 0x90f4, 0x02, | ||
341 | 0x90f5, 0x29, | ||
342 | 0x90f6, 0x7f, | ||
343 | 0xc940, 0x29, | ||
344 | 0xc941, 0x7c, | ||
345 | 0xc942, 0x80, | ||
346 | 0xc943, 0xf7, | ||
347 | 0x90f7, 0x90, | ||
348 | 0x90f8, 0x83, | ||
349 | 0x90f9, 0xba, | ||
350 | 0x90fa, 0xe0, | ||
351 | 0x90fb, 0xff, | ||
352 | 0x90fc, 0x90, | ||
353 | 0x90fd, 0xd2, | ||
354 | 0x90fe, 0x0c, | ||
355 | 0x90ff, 0xe0, | ||
356 | 0x9100, 0xe4, | ||
357 | 0x9101, 0xef, | ||
358 | 0x9102, 0xf0, | ||
359 | 0x9103, 0xa3, | ||
360 | 0x9104, 0xe0, | ||
361 | 0x9105, 0x74, | ||
362 | 0x9106, 0xff, | ||
363 | 0x9107, 0xf0, | ||
364 | 0x9108, 0x90, | ||
365 | 0x9109, 0xd2, | ||
366 | 0x910a, 0x0e, | ||
367 | 0x910b, 0x02, | ||
368 | 0x910c, 0x29, | ||
369 | 0x910d, 0x7f, | ||
370 | 0xc944, 0x2a, | ||
371 | 0xc945, 0x42, | ||
372 | 0xc946, 0x81, | ||
373 | 0xc947, 0x0e, | ||
374 | 0x910e, 0xf0, | ||
375 | 0x910f, 0x90, | ||
376 | 0x9110, 0xd2, | ||
377 | 0x9111, 0x12, | ||
378 | 0x9112, 0x02, | ||
379 | 0x9113, 0x2a, | ||
380 | 0x9114, 0x48, | ||
381 | 0xc948, 0x2a, | ||
382 | 0xc949, 0x45, | ||
383 | 0xc94a, 0x81, | ||
384 | 0xc94b, 0x15, | ||
385 | 0x9115, 0x90, | ||
386 | 0x9116, 0x83, | ||
387 | 0x9117, 0xba, | ||
388 | 0x9118, 0xe0, | ||
389 | 0x9119, 0xff, | ||
390 | 0x911a, 0x90, | ||
391 | 0x911b, 0xd2, | ||
392 | 0x911c, 0x10, | ||
393 | 0x911d, 0xe0, | ||
394 | 0x911e, 0xe4, | ||
395 | 0x911f, 0xef, | ||
396 | 0x9120, 0xf0, | ||
397 | 0x9121, 0xa3, | ||
398 | 0x9122, 0xe0, | ||
399 | 0x9123, 0x74, | ||
400 | 0x9124, 0xff, | ||
401 | 0x9125, 0xf0, | ||
402 | 0x9126, 0x90, | ||
403 | 0x9127, 0xd2, | ||
404 | 0x9128, 0x12, | ||
405 | 0x9129, 0x02, | ||
406 | 0x912a, 0x2a, | ||
407 | 0x912b, 0x48, | ||
408 | 0xc900, 0x01, | ||
409 | 0x0000, 0x00, | ||
410 | }; | ||
411 | |||
412 | static const u16 vs6624_p2[] = { | ||
413 | 0x806f, 0x01, | ||
414 | 0x058c, 0x01, | ||
415 | 0x0000, 0x00, | ||
416 | }; | ||
417 | |||
418 | static const u16 vs6624_run_setup[] = { | ||
419 | 0x1d18, 0x00, /* Enableconstrainedwhitebalance */ | ||
420 | VS6624_PEAK_MIN_OUT_G_MSB, 0x3c, /* Damper PeakGain Output MSB */ | ||
421 | VS6624_PEAK_MIN_OUT_G_LSB, 0x66, /* Damper PeakGain Output LSB */ | ||
422 | VS6624_CM_LOW_THR_MSB, 0x65, /* Damper Low MSB */ | ||
423 | VS6624_CM_LOW_THR_LSB, 0xd1, /* Damper Low LSB */ | ||
424 | VS6624_CM_HIGH_THR_MSB, 0x66, /* Damper High MSB */ | ||
425 | VS6624_CM_HIGH_THR_LSB, 0x62, /* Damper High LSB */ | ||
426 | VS6624_CM_MIN_OUT_MSB, 0x00, /* Damper Min output MSB */ | ||
427 | VS6624_CM_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */ | ||
428 | VS6624_NORA_DISABLE, 0x00, /* Nora fDisable */ | ||
429 | VS6624_NORA_USAGE, 0x04, /* Nora usage */ | ||
430 | VS6624_NORA_LOW_THR_MSB, 0x63, /* Damper Low MSB Changed 0x63 to 0x65 */ | ||
431 | VS6624_NORA_LOW_THR_LSB, 0xd1, /* Damper Low LSB */ | ||
432 | VS6624_NORA_HIGH_THR_MSB, 0x68, /* Damper High MSB */ | ||
433 | VS6624_NORA_HIGH_THR_LSB, 0xdd, /* Damper High LSB */ | ||
434 | VS6624_NORA_MIN_OUT_MSB, 0x3a, /* Damper Min output MSB */ | ||
435 | VS6624_NORA_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */ | ||
436 | VS6624_F2B_DISABLE, 0x00, /* Disable */ | ||
437 | 0x1d8a, 0x30, /* MAXWeightHigh */ | ||
438 | 0x1d91, 0x62, /* fpDamperLowThresholdHigh MSB */ | ||
439 | 0x1d92, 0x4a, /* fpDamperLowThresholdHigh LSB */ | ||
440 | 0x1d95, 0x65, /* fpDamperHighThresholdHigh MSB */ | ||
441 | 0x1d96, 0x0e, /* fpDamperHighThresholdHigh LSB */ | ||
442 | 0x1da1, 0x3a, /* fpMinimumDamperOutputLow MSB */ | ||
443 | 0x1da2, 0xb8, /* fpMinimumDamperOutputLow LSB */ | ||
444 | 0x1e08, 0x06, /* MAXWeightLow */ | ||
445 | 0x1e0a, 0x0a, /* MAXWeightHigh */ | ||
446 | 0x1601, 0x3a, /* Red A MSB */ | ||
447 | 0x1602, 0x14, /* Red A LSB */ | ||
448 | 0x1605, 0x3b, /* Blue A MSB */ | ||
449 | 0x1606, 0x85, /* BLue A LSB */ | ||
450 | 0x1609, 0x3b, /* RED B MSB */ | ||
451 | 0x160a, 0x85, /* RED B LSB */ | ||
452 | 0x160d, 0x3a, /* Blue B MSB */ | ||
453 | 0x160e, 0x14, /* Blue B LSB */ | ||
454 | 0x1611, 0x30, /* Max Distance from Locus MSB */ | ||
455 | 0x1612, 0x8f, /* Max Distance from Locus MSB */ | ||
456 | 0x1614, 0x01, /* Enable constrainer */ | ||
457 | 0x0000, 0x00, | ||
458 | }; | ||
459 | |||
460 | static const u16 vs6624_default[] = { | ||
461 | VS6624_CONTRAST0, 0x84, | ||
462 | VS6624_SATURATION0, 0x75, | ||
463 | VS6624_GAMMA0, 0x11, | ||
464 | VS6624_CONTRAST1, 0x84, | ||
465 | VS6624_SATURATION1, 0x75, | ||
466 | VS6624_GAMMA1, 0x11, | ||
467 | VS6624_MAN_RG, 0x80, | ||
468 | VS6624_MAN_GG, 0x80, | ||
469 | VS6624_MAN_BG, 0x80, | ||
470 | VS6624_WB_MODE, 0x1, | ||
471 | VS6624_EXPO_COMPENSATION, 0xfe, | ||
472 | VS6624_EXPO_METER, 0x0, | ||
473 | VS6624_LIGHT_FREQ, 0x64, | ||
474 | VS6624_PEAK_GAIN, 0xe, | ||
475 | VS6624_PEAK_LOW_THR, 0x28, | ||
476 | VS6624_HMIRROR0, 0x0, | ||
477 | VS6624_VFLIP0, 0x0, | ||
478 | VS6624_ZOOM_HSTEP0_MSB, 0x0, | ||
479 | VS6624_ZOOM_HSTEP0_LSB, 0x1, | ||
480 | VS6624_ZOOM_VSTEP0_MSB, 0x0, | ||
481 | VS6624_ZOOM_VSTEP0_LSB, 0x1, | ||
482 | VS6624_PAN_HSTEP0_MSB, 0x0, | ||
483 | VS6624_PAN_HSTEP0_LSB, 0xf, | ||
484 | VS6624_PAN_VSTEP0_MSB, 0x0, | ||
485 | VS6624_PAN_VSTEP0_LSB, 0xf, | ||
486 | VS6624_SENSOR_MODE, 0x1, | ||
487 | VS6624_SYNC_CODE_SETUP, 0x21, | ||
488 | VS6624_DISABLE_FR_DAMPER, 0x0, | ||
489 | VS6624_FR_DEN, 0x1, | ||
490 | VS6624_FR_NUM_LSB, 0xf, | ||
491 | VS6624_INIT_PIPE_SETUP, 0x0, | ||
492 | VS6624_IMG_FMT0, 0x0, | ||
493 | VS6624_YUV_SETUP, 0x1, | ||
494 | VS6624_IMAGE_SIZE0, 0x2, | ||
495 | 0x0000, 0x00, | ||
496 | }; | ||
497 | |||
498 | static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd) | ||
499 | { | ||
500 | return container_of(sd, struct vs6624, sd); | ||
501 | } | ||
502 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
503 | { | ||
504 | return &container_of(ctrl->handler, struct vs6624, hdl)->sd; | ||
505 | } | ||
506 | |||
507 | static int vs6624_read(struct v4l2_subdev *sd, u16 index) | ||
508 | { | ||
509 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
510 | u8 buf[2]; | ||
511 | |||
512 | buf[0] = index >> 8; | ||
513 | buf[1] = index; | ||
514 | i2c_master_send(client, buf, 2); | ||
515 | i2c_master_recv(client, buf, 1); | ||
516 | |||
517 | return buf[0]; | ||
518 | } | ||
519 | |||
520 | static int vs6624_write(struct v4l2_subdev *sd, u16 index, | ||
521 | u8 value) | ||
522 | { | ||
523 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
524 | u8 buf[3]; | ||
525 | |||
526 | buf[0] = index >> 8; | ||
527 | buf[1] = index; | ||
528 | buf[2] = value; | ||
529 | |||
530 | return i2c_master_send(client, buf, 3); | ||
531 | } | ||
532 | |||
533 | static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs) | ||
534 | { | ||
535 | u16 reg; | ||
536 | u8 data; | ||
537 | |||
538 | while (*regs != 0x00) { | ||
539 | reg = *regs++; | ||
540 | data = *regs++; | ||
541 | |||
542 | vs6624_write(sd, reg, data); | ||
543 | } | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl) | ||
548 | { | ||
549 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
550 | |||
551 | switch (ctrl->id) { | ||
552 | case V4L2_CID_CONTRAST: | ||
553 | vs6624_write(sd, VS6624_CONTRAST0, ctrl->val); | ||
554 | break; | ||
555 | case V4L2_CID_SATURATION: | ||
556 | vs6624_write(sd, VS6624_SATURATION0, ctrl->val); | ||
557 | break; | ||
558 | case V4L2_CID_HFLIP: | ||
559 | vs6624_write(sd, VS6624_HMIRROR0, ctrl->val); | ||
560 | break; | ||
561 | case V4L2_CID_VFLIP: | ||
562 | vs6624_write(sd, VS6624_VFLIP0, ctrl->val); | ||
563 | break; | ||
564 | default: | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, | ||
572 | enum v4l2_mbus_pixelcode *code) | ||
573 | { | ||
574 | if (index >= ARRAY_SIZE(vs6624_formats)) | ||
575 | return -EINVAL; | ||
576 | |||
577 | *code = vs6624_formats[index].mbus_code; | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd, | ||
582 | struct v4l2_mbus_framefmt *fmt) | ||
583 | { | ||
584 | int index; | ||
585 | |||
586 | for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++) | ||
587 | if (vs6624_formats[index].mbus_code == fmt->code) | ||
588 | break; | ||
589 | if (index >= ARRAY_SIZE(vs6624_formats)) { | ||
590 | /* default to first format */ | ||
591 | index = 0; | ||
592 | fmt->code = vs6624_formats[0].mbus_code; | ||
593 | } | ||
594 | |||
595 | /* sensor mode is VGA */ | ||
596 | if (fmt->width > VGA_WIDTH) | ||
597 | fmt->width = VGA_WIDTH; | ||
598 | if (fmt->height > VGA_HEIGHT) | ||
599 | fmt->height = VGA_HEIGHT; | ||
600 | fmt->width = fmt->width & (~3); | ||
601 | fmt->height = fmt->height & (~3); | ||
602 | fmt->field = V4L2_FIELD_NONE; | ||
603 | fmt->colorspace = vs6624_formats[index].colorspace; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd, | ||
608 | struct v4l2_mbus_framefmt *fmt) | ||
609 | { | ||
610 | struct vs6624 *sensor = to_vs6624(sd); | ||
611 | int ret; | ||
612 | |||
613 | ret = vs6624_try_mbus_fmt(sd, fmt); | ||
614 | if (ret) | ||
615 | return ret; | ||
616 | |||
617 | /* set image format */ | ||
618 | switch (fmt->code) { | ||
619 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
620 | vs6624_write(sd, VS6624_IMG_FMT0, 0x0); | ||
621 | vs6624_write(sd, VS6624_YUV_SETUP, 0x1); | ||
622 | break; | ||
623 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
624 | vs6624_write(sd, VS6624_IMG_FMT0, 0x0); | ||
625 | vs6624_write(sd, VS6624_YUV_SETUP, 0x3); | ||
626 | break; | ||
627 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
628 | vs6624_write(sd, VS6624_IMG_FMT0, 0x4); | ||
629 | vs6624_write(sd, VS6624_RGB_SETUP, 0x0); | ||
630 | break; | ||
631 | default: | ||
632 | return -EINVAL; | ||
633 | } | ||
634 | |||
635 | /* set image size */ | ||
636 | if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT)) | ||
637 | vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2); | ||
638 | else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT)) | ||
639 | vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4); | ||
640 | else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT)) | ||
641 | vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6); | ||
642 | else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT)) | ||
643 | vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3); | ||
644 | else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT)) | ||
645 | vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5); | ||
646 | else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT)) | ||
647 | vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7); | ||
648 | else { | ||
649 | vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8); | ||
650 | vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8); | ||
651 | vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF); | ||
652 | vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8); | ||
653 | vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF); | ||
654 | vs6624_write(sd, VS6624_CROP_CTRL0, 0x1); | ||
655 | } | ||
656 | |||
657 | sensor->fmt = *fmt; | ||
658 | |||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd, | ||
663 | struct v4l2_mbus_framefmt *fmt) | ||
664 | { | ||
665 | struct vs6624 *sensor = to_vs6624(sd); | ||
666 | |||
667 | *fmt = sensor->fmt; | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | ||
672 | { | ||
673 | struct vs6624 *sensor = to_vs6624(sd); | ||
674 | struct v4l2_captureparm *cp = &parms->parm.capture; | ||
675 | |||
676 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
677 | return -EINVAL; | ||
678 | |||
679 | memset(cp, 0, sizeof(*cp)); | ||
680 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
681 | cp->timeperframe.numerator = sensor->frame_rate.denominator; | ||
682 | cp->timeperframe.denominator = sensor->frame_rate.numerator; | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | ||
687 | { | ||
688 | struct vs6624 *sensor = to_vs6624(sd); | ||
689 | struct v4l2_captureparm *cp = &parms->parm.capture; | ||
690 | struct v4l2_fract *tpf = &cp->timeperframe; | ||
691 | |||
692 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
693 | return -EINVAL; | ||
694 | if (cp->extendedmode != 0) | ||
695 | return -EINVAL; | ||
696 | |||
697 | if (tpf->numerator == 0 || tpf->denominator == 0 | ||
698 | || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) { | ||
699 | /* reset to max frame rate */ | ||
700 | tpf->numerator = 1; | ||
701 | tpf->denominator = MAX_FRAME_RATE; | ||
702 | } | ||
703 | sensor->frame_rate.numerator = tpf->denominator; | ||
704 | sensor->frame_rate.denominator = tpf->numerator; | ||
705 | vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0); | ||
706 | vs6624_write(sd, VS6624_FR_NUM_MSB, | ||
707 | sensor->frame_rate.numerator >> 8); | ||
708 | vs6624_write(sd, VS6624_FR_NUM_LSB, | ||
709 | sensor->frame_rate.numerator & 0xFF); | ||
710 | vs6624_write(sd, VS6624_FR_DEN, | ||
711 | sensor->frame_rate.denominator & 0xFF); | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static int vs6624_s_stream(struct v4l2_subdev *sd, int enable) | ||
716 | { | ||
717 | if (enable) | ||
718 | vs6624_write(sd, VS6624_USER_CMD, 0x2); | ||
719 | else | ||
720 | vs6624_write(sd, VS6624_USER_CMD, 0x4); | ||
721 | udelay(100); | ||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static int vs6624_g_chip_ident(struct v4l2_subdev *sd, | ||
726 | struct v4l2_dbg_chip_ident *chip) | ||
727 | { | ||
728 | int rev; | ||
729 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
730 | |||
731 | rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8) | ||
732 | | vs6624_read(sd, VS6624_FW_VSN_MINOR); | ||
733 | |||
734 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev); | ||
735 | } | ||
736 | |||
737 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
738 | static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | ||
739 | { | ||
740 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
741 | |||
742 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
743 | return -EINVAL; | ||
744 | if (!capable(CAP_SYS_ADMIN)) | ||
745 | return -EPERM; | ||
746 | reg->val = vs6624_read(sd, reg->reg & 0xffff); | ||
747 | reg->size = 1; | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | ||
752 | { | ||
753 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
754 | |||
755 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
756 | return -EINVAL; | ||
757 | if (!capable(CAP_SYS_ADMIN)) | ||
758 | return -EPERM; | ||
759 | vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff); | ||
760 | return 0; | ||
761 | } | ||
762 | #endif | ||
763 | |||
764 | static const struct v4l2_ctrl_ops vs6624_ctrl_ops = { | ||
765 | .s_ctrl = vs6624_s_ctrl, | ||
766 | }; | ||
767 | |||
768 | static const struct v4l2_subdev_core_ops vs6624_core_ops = { | ||
769 | .g_chip_ident = vs6624_g_chip_ident, | ||
770 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
771 | .g_register = vs6624_g_register, | ||
772 | .s_register = vs6624_s_register, | ||
773 | #endif | ||
774 | }; | ||
775 | |||
776 | static const struct v4l2_subdev_video_ops vs6624_video_ops = { | ||
777 | .enum_mbus_fmt = vs6624_enum_mbus_fmt, | ||
778 | .try_mbus_fmt = vs6624_try_mbus_fmt, | ||
779 | .s_mbus_fmt = vs6624_s_mbus_fmt, | ||
780 | .g_mbus_fmt = vs6624_g_mbus_fmt, | ||
781 | .s_parm = vs6624_s_parm, | ||
782 | .g_parm = vs6624_g_parm, | ||
783 | .s_stream = vs6624_s_stream, | ||
784 | }; | ||
785 | |||
786 | static const struct v4l2_subdev_ops vs6624_ops = { | ||
787 | .core = &vs6624_core_ops, | ||
788 | .video = &vs6624_video_ops, | ||
789 | }; | ||
790 | |||
791 | static int __devinit vs6624_probe(struct i2c_client *client, | ||
792 | const struct i2c_device_id *id) | ||
793 | { | ||
794 | struct vs6624 *sensor; | ||
795 | struct v4l2_subdev *sd; | ||
796 | struct v4l2_ctrl_handler *hdl; | ||
797 | const unsigned *ce; | ||
798 | int ret; | ||
799 | |||
800 | /* Check if the adapter supports the needed features */ | ||
801 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | ||
802 | return -EIO; | ||
803 | |||
804 | ce = client->dev.platform_data; | ||
805 | if (ce == NULL) | ||
806 | return -EINVAL; | ||
807 | |||
808 | ret = gpio_request(*ce, "VS6624 Chip Enable"); | ||
809 | if (ret) { | ||
810 | v4l_err(client, "failed to request GPIO %d\n", *ce); | ||
811 | return ret; | ||
812 | } | ||
813 | gpio_direction_output(*ce, 1); | ||
814 | /* wait 100ms before any further i2c writes are performed */ | ||
815 | mdelay(100); | ||
816 | |||
817 | sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); | ||
818 | if (sensor == NULL) { | ||
819 | gpio_free(*ce); | ||
820 | return -ENOMEM; | ||
821 | } | ||
822 | |||
823 | sd = &sensor->sd; | ||
824 | v4l2_i2c_subdev_init(sd, client, &vs6624_ops); | ||
825 | |||
826 | vs6624_writeregs(sd, vs6624_p1); | ||
827 | vs6624_write(sd, VS6624_MICRO_EN, 0x2); | ||
828 | vs6624_write(sd, VS6624_DIO_EN, 0x1); | ||
829 | mdelay(10); | ||
830 | vs6624_writeregs(sd, vs6624_p2); | ||
831 | |||
832 | vs6624_writeregs(sd, vs6624_default); | ||
833 | vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF); | ||
834 | vs6624_writeregs(sd, vs6624_run_setup); | ||
835 | |||
836 | /* set frame rate */ | ||
837 | sensor->frame_rate.numerator = MAX_FRAME_RATE; | ||
838 | sensor->frame_rate.denominator = 1; | ||
839 | vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0); | ||
840 | vs6624_write(sd, VS6624_FR_NUM_MSB, | ||
841 | sensor->frame_rate.numerator >> 8); | ||
842 | vs6624_write(sd, VS6624_FR_NUM_LSB, | ||
843 | sensor->frame_rate.numerator & 0xFF); | ||
844 | vs6624_write(sd, VS6624_FR_DEN, | ||
845 | sensor->frame_rate.denominator & 0xFF); | ||
846 | |||
847 | sensor->fmt = vs6624_default_fmt; | ||
848 | sensor->ce_pin = *ce; | ||
849 | |||
850 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | ||
851 | client->addr << 1, client->adapter->name); | ||
852 | |||
853 | hdl = &sensor->hdl; | ||
854 | v4l2_ctrl_handler_init(hdl, 4); | ||
855 | v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, | ||
856 | V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87); | ||
857 | v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, | ||
858 | V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78); | ||
859 | v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, | ||
860 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
861 | v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, | ||
862 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
863 | /* hook the control handler into the driver */ | ||
864 | sd->ctrl_handler = hdl; | ||
865 | if (hdl->error) { | ||
866 | int err = hdl->error; | ||
867 | |||
868 | v4l2_ctrl_handler_free(hdl); | ||
869 | kfree(sensor); | ||
870 | gpio_free(*ce); | ||
871 | return err; | ||
872 | } | ||
873 | |||
874 | /* initialize the hardware to the default control values */ | ||
875 | ret = v4l2_ctrl_handler_setup(hdl); | ||
876 | if (ret) { | ||
877 | v4l2_ctrl_handler_free(hdl); | ||
878 | kfree(sensor); | ||
879 | gpio_free(*ce); | ||
880 | } | ||
881 | return ret; | ||
882 | } | ||
883 | |||
884 | static int __devexit vs6624_remove(struct i2c_client *client) | ||
885 | { | ||
886 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
887 | struct vs6624 *sensor = to_vs6624(sd); | ||
888 | |||
889 | v4l2_device_unregister_subdev(sd); | ||
890 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
891 | gpio_free(sensor->ce_pin); | ||
892 | kfree(sensor); | ||
893 | return 0; | ||
894 | } | ||
895 | |||
896 | static const struct i2c_device_id vs6624_id[] = { | ||
897 | {"vs6624", 0}, | ||
898 | {}, | ||
899 | }; | ||
900 | |||
901 | MODULE_DEVICE_TABLE(i2c, vs6624_id); | ||
902 | |||
903 | static struct i2c_driver vs6624_driver = { | ||
904 | .driver = { | ||
905 | .owner = THIS_MODULE, | ||
906 | .name = "vs6624", | ||
907 | }, | ||
908 | .probe = vs6624_probe, | ||
909 | .remove = __devexit_p(vs6624_remove), | ||
910 | .id_table = vs6624_id, | ||
911 | }; | ||
912 | |||
913 | static __init int vs6624_init(void) | ||
914 | { | ||
915 | return i2c_add_driver(&vs6624_driver); | ||
916 | } | ||
917 | |||
918 | static __exit void vs6624_exit(void) | ||
919 | { | ||
920 | i2c_del_driver(&vs6624_driver); | ||
921 | } | ||
922 | |||
923 | module_init(vs6624_init); | ||
924 | module_exit(vs6624_exit); | ||
925 | |||
926 | MODULE_DESCRIPTION("VS6624 sensor driver"); | ||
927 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
928 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/vs6624_regs.h b/drivers/media/video/vs6624_regs.h new file mode 100644 index 000000000000..6ba2ee25827e --- /dev/null +++ b/drivers/media/video/vs6624_regs.h | |||
@@ -0,0 +1,337 @@ | |||
1 | /* | ||
2 | * vs6624 - ST VS6624 CMOS image sensor registers | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef _VS6624_REGS_H_ | ||
21 | #define _VS6624_REGS_H_ | ||
22 | |||
23 | /* low level control registers */ | ||
24 | #define VS6624_MICRO_EN 0xC003 /* power enable for all MCU clock */ | ||
25 | #define VS6624_DIO_EN 0xC044 /* enable digital I/O */ | ||
26 | /* device parameters */ | ||
27 | #define VS6624_DEV_ID_MSB 0x0001 /* device id MSB */ | ||
28 | #define VS6624_DEV_ID_LSB 0x0002 /* device id LSB */ | ||
29 | #define VS6624_FW_VSN_MAJOR 0x0004 /* firmware version major */ | ||
30 | #define VS6624_FW_VSN_MINOR 0x0006 /* firmware version minor */ | ||
31 | #define VS6624_PATCH_VSN_MAJOR 0x0008 /* patch version major */ | ||
32 | #define VS6624_PATCH_VSN_MINOR 0x000A /* patch version minor */ | ||
33 | /* host interface manager control */ | ||
34 | #define VS6624_USER_CMD 0x0180 /* user level control of operating states */ | ||
35 | /* host interface manager status */ | ||
36 | #define VS6624_STATE 0x0202 /* current state of the mode manager */ | ||
37 | /* run mode control */ | ||
38 | #define VS6624_METER_ON 0x0280 /* if false AE and AWB are disabled */ | ||
39 | /* mode setup */ | ||
40 | #define VS6624_ACTIVE_PIPE_SETUP 0x0302 /* select the active bank for non view live mode */ | ||
41 | #define VS6624_SENSOR_MODE 0x0308 /* select the different sensor mode */ | ||
42 | /* pipe setup bank0 */ | ||
43 | #define VS6624_IMAGE_SIZE0 0x0380 /* required output dimension */ | ||
44 | #define VS6624_MAN_HSIZE0_MSB 0x0383 /* input required manual H size MSB */ | ||
45 | #define VS6624_MAN_HSIZE0_LSB 0x0384 /* input required manual H size LSB */ | ||
46 | #define VS6624_MAN_VSIZE0_MSB 0x0387 /* input required manual V size MSB */ | ||
47 | #define VS6624_MAN_VSIZE0_LSB 0x0388 /* input required manual V size LSB */ | ||
48 | #define VS6624_ZOOM_HSTEP0_MSB 0x038B /* set the zoom H step MSB */ | ||
49 | #define VS6624_ZOOM_HSTEP0_LSB 0x038C /* set the zoom H step LSB */ | ||
50 | #define VS6624_ZOOM_VSTEP0_MSB 0x038F /* set the zoom V step MSB */ | ||
51 | #define VS6624_ZOOM_VSTEP0_LSB 0x0390 /* set the zoom V step LSB */ | ||
52 | #define VS6624_ZOOM_CTRL0 0x0392 /* control zoon in, out and stop */ | ||
53 | #define VS6624_PAN_HSTEP0_MSB 0x0395 /* set the pan H step MSB */ | ||
54 | #define VS6624_PAN_HSTEP0_LSB 0x0396 /* set the pan H step LSB */ | ||
55 | #define VS6624_PAN_VSTEP0_MSB 0x0399 /* set the pan V step MSB */ | ||
56 | #define VS6624_PAN_VSTEP0_LSB 0x039A /* set the pan V step LSB */ | ||
57 | #define VS6624_PAN_CTRL0 0x039C /* control pan operation */ | ||
58 | #define VS6624_CROP_CTRL0 0x039E /* select cropping mode */ | ||
59 | #define VS6624_CROP_HSTART0_MSB 0x03A1 /* set the cropping H start address MSB */ | ||
60 | #define VS6624_CROP_HSTART0_LSB 0x03A2 /* set the cropping H start address LSB */ | ||
61 | #define VS6624_CROP_HSIZE0_MSB 0x03A5 /* set the cropping H size MSB */ | ||
62 | #define VS6624_CROP_HSIZE0_LSB 0x03A6 /* set the cropping H size LSB */ | ||
63 | #define VS6624_CROP_VSTART0_MSB 0x03A9 /* set the cropping V start address MSB */ | ||
64 | #define VS6624_CROP_VSTART0_LSB 0x03AA /* set the cropping V start address LSB */ | ||
65 | #define VS6624_CROP_VSIZE0_MSB 0x03AD /* set the cropping V size MSB */ | ||
66 | #define VS6624_CROP_VSIZE0_LSB 0x03AE /* set the cropping V size LSB */ | ||
67 | #define VS6624_IMG_FMT0 0x03B0 /* select required output image format */ | ||
68 | #define VS6624_BAYER_OUT_ALIGN0 0x03B2 /* set bayer output alignment */ | ||
69 | #define VS6624_CONTRAST0 0x03B4 /* contrast control for output */ | ||
70 | #define VS6624_SATURATION0 0x03B6 /* saturation control for output */ | ||
71 | #define VS6624_GAMMA0 0x03B8 /* gamma settings */ | ||
72 | #define VS6624_HMIRROR0 0x03BA /* horizontal image orientation flip */ | ||
73 | #define VS6624_VFLIP0 0x03BC /* vertical image orientation flip */ | ||
74 | #define VS6624_CHANNEL_ID0 0x03BE /* logical DMA channel number */ | ||
75 | /* pipe setup bank1 */ | ||
76 | #define VS6624_IMAGE_SIZE1 0x0400 /* required output dimension */ | ||
77 | #define VS6624_MAN_HSIZE1_MSB 0x0403 /* input required manual H size MSB */ | ||
78 | #define VS6624_MAN_HSIZE1_LSB 0x0404 /* input required manual H size LSB */ | ||
79 | #define VS6624_MAN_VSIZE1_MSB 0x0407 /* input required manual V size MSB */ | ||
80 | #define VS6624_MAN_VSIZE1_LSB 0x0408 /* input required manual V size LSB */ | ||
81 | #define VS6624_ZOOM_HSTEP1_MSB 0x040B /* set the zoom H step MSB */ | ||
82 | #define VS6624_ZOOM_HSTEP1_LSB 0x040C /* set the zoom H step LSB */ | ||
83 | #define VS6624_ZOOM_VSTEP1_MSB 0x040F /* set the zoom V step MSB */ | ||
84 | #define VS6624_ZOOM_VSTEP1_LSB 0x0410 /* set the zoom V step LSB */ | ||
85 | #define VS6624_ZOOM_CTRL1 0x0412 /* control zoon in, out and stop */ | ||
86 | #define VS6624_PAN_HSTEP1_MSB 0x0415 /* set the pan H step MSB */ | ||
87 | #define VS6624_PAN_HSTEP1_LSB 0x0416 /* set the pan H step LSB */ | ||
88 | #define VS6624_PAN_VSTEP1_MSB 0x0419 /* set the pan V step MSB */ | ||
89 | #define VS6624_PAN_VSTEP1_LSB 0x041A /* set the pan V step LSB */ | ||
90 | #define VS6624_PAN_CTRL1 0x041C /* control pan operation */ | ||
91 | #define VS6624_CROP_CTRL1 0x041E /* select cropping mode */ | ||
92 | #define VS6624_CROP_HSTART1_MSB 0x0421 /* set the cropping H start address MSB */ | ||
93 | #define VS6624_CROP_HSTART1_LSB 0x0422 /* set the cropping H start address LSB */ | ||
94 | #define VS6624_CROP_HSIZE1_MSB 0x0425 /* set the cropping H size MSB */ | ||
95 | #define VS6624_CROP_HSIZE1_LSB 0x0426 /* set the cropping H size LSB */ | ||
96 | #define VS6624_CROP_VSTART1_MSB 0x0429 /* set the cropping V start address MSB */ | ||
97 | #define VS6624_CROP_VSTART1_LSB 0x042A /* set the cropping V start address LSB */ | ||
98 | #define VS6624_CROP_VSIZE1_MSB 0x042D /* set the cropping V size MSB */ | ||
99 | #define VS6624_CROP_VSIZE1_LSB 0x042E /* set the cropping V size LSB */ | ||
100 | #define VS6624_IMG_FMT1 0x0430 /* select required output image format */ | ||
101 | #define VS6624_BAYER_OUT_ALIGN1 0x0432 /* set bayer output alignment */ | ||
102 | #define VS6624_CONTRAST1 0x0434 /* contrast control for output */ | ||
103 | #define VS6624_SATURATION1 0x0436 /* saturation control for output */ | ||
104 | #define VS6624_GAMMA1 0x0438 /* gamma settings */ | ||
105 | #define VS6624_HMIRROR1 0x043A /* horizontal image orientation flip */ | ||
106 | #define VS6624_VFLIP1 0x043C /* vertical image orientation flip */ | ||
107 | #define VS6624_CHANNEL_ID1 0x043E /* logical DMA channel number */ | ||
108 | /* view live control */ | ||
109 | #define VS6624_VIEW_LIVE_EN 0x0480 /* enable view live mode */ | ||
110 | #define VS6624_INIT_PIPE_SETUP 0x0482 /* select initial pipe setup bank */ | ||
111 | /* view live status */ | ||
112 | #define VS6624_CUR_PIPE_SETUP 0x0500 /* indicates most recently applied setup bank */ | ||
113 | /* power management */ | ||
114 | #define VS6624_TIME_TO_POWER_DOWN 0x0580 /* automatically transition time to stop mode */ | ||
115 | /* video timing parameter host inputs */ | ||
116 | #define VS6624_EXT_CLK_FREQ_NUM_MSB 0x0605 /* external clock frequency numerator MSB */ | ||
117 | #define VS6624_EXT_CLK_FREQ_NUM_LSB 0x0606 /* external clock frequency numerator LSB */ | ||
118 | #define VS6624_EXT_CLK_FREQ_DEN 0x0608 /* external clock frequency denominator */ | ||
119 | /* video timing control */ | ||
120 | #define VS6624_SYS_CLK_MODE 0x0880 /* decides system clock frequency */ | ||
121 | /* frame dimension parameter host inputs */ | ||
122 | #define VS6624_LIGHT_FREQ 0x0C80 /* AC frequency used for flicker free time */ | ||
123 | #define VS6624_FLICKER_COMPAT 0x0C82 /* flicker compatible frame length */ | ||
124 | /* static frame rate control */ | ||
125 | #define VS6624_FR_NUM_MSB 0x0D81 /* desired frame rate numerator MSB */ | ||
126 | #define VS6624_FR_NUM_LSB 0x0D82 /* desired frame rate numerator LSB */ | ||
127 | #define VS6624_FR_DEN 0x0D84 /* desired frame rate denominator */ | ||
128 | /* automatic frame rate control */ | ||
129 | #define VS6624_DISABLE_FR_DAMPER 0x0E80 /* defines frame rate mode */ | ||
130 | #define VS6624_MIN_DAMPER_OUT_MSB 0x0E8C /* minimum frame rate MSB */ | ||
131 | #define VS6624_MIN_DAMPER_OUT_LSB 0x0E8A /* minimum frame rate LSB */ | ||
132 | /* exposure controls */ | ||
133 | #define VS6624_EXPO_MODE 0x1180 /* exposure mode */ | ||
134 | #define VS6624_EXPO_METER 0x1182 /* weights to be associated with the zones */ | ||
135 | #define VS6624_EXPO_TIME_NUM 0x1184 /* exposure time numerator */ | ||
136 | #define VS6624_EXPO_TIME_DEN 0x1186 /* exposure time denominator */ | ||
137 | #define VS6624_EXPO_TIME_MSB 0x1189 /* exposure time for the Manual Mode MSB */ | ||
138 | #define VS6624_EXPO_TIME_LSB 0x118A /* exposure time for the Manual Mode LSB */ | ||
139 | #define VS6624_EXPO_COMPENSATION 0x1190 /* exposure compensation */ | ||
140 | #define VS6624_DIRECT_COARSE_MSB 0x1195 /* coarse integration lines for Direct Mode MSB */ | ||
141 | #define VS6624_DIRECT_COARSE_LSB 0x1196 /* coarse integration lines for Direct Mode LSB */ | ||
142 | #define VS6624_DIRECT_FINE_MSB 0x1199 /* fine integration pixels for Direct Mode MSB */ | ||
143 | #define VS6624_DIRECT_FINE_LSB 0x119A /* fine integration pixels for Direct Mode LSB */ | ||
144 | #define VS6624_DIRECT_ANAL_GAIN_MSB 0x119D /* analog gain for Direct Mode MSB */ | ||
145 | #define VS6624_DIRECT_ANAL_GAIN_LSB 0x119E /* analog gain for Direct Mode LSB */ | ||
146 | #define VS6624_DIRECT_DIGI_GAIN_MSB 0x11A1 /* digital gain for Direct Mode MSB */ | ||
147 | #define VS6624_DIRECT_DIGI_GAIN_LSB 0x11A2 /* digital gain for Direct Mode LSB */ | ||
148 | #define VS6624_FLASH_COARSE_MSB 0x11A5 /* coarse integration lines for Flash Gun Mode MSB */ | ||
149 | #define VS6624_FLASH_COARSE_LSB 0x11A6 /* coarse integration lines for Flash Gun Mode LSB */ | ||
150 | #define VS6624_FLASH_FINE_MSB 0x11A9 /* fine integration pixels for Flash Gun Mode MSB */ | ||
151 | #define VS6624_FLASH_FINE_LSB 0x11AA /* fine integration pixels for Flash Gun Mode LSB */ | ||
152 | #define VS6624_FLASH_ANAL_GAIN_MSB 0x11AD /* analog gain for Flash Gun Mode MSB */ | ||
153 | #define VS6624_FLASH_ANAL_GAIN_LSB 0x11AE /* analog gain for Flash Gun Mode LSB */ | ||
154 | #define VS6624_FLASH_DIGI_GAIN_MSB 0x11B1 /* digital gain for Flash Gun Mode MSB */ | ||
155 | #define VS6624_FLASH_DIGI_GAIN_LSB 0x11B2 /* digital gain for Flash Gun Mode LSB */ | ||
156 | #define VS6624_FREEZE_AE 0x11B4 /* freeze auto exposure */ | ||
157 | #define VS6624_MAX_INT_TIME_MSB 0x11B7 /* user maximum integration time MSB */ | ||
158 | #define VS6624_MAX_INT_TIME_LSB 0x11B8 /* user maximum integration time LSB */ | ||
159 | #define VS6624_FLASH_AG_THR_MSB 0x11BB /* recommend flash gun analog gain threshold MSB */ | ||
160 | #define VS6624_FLASH_AG_THR_LSB 0x11BC /* recommend flash gun analog gain threshold LSB */ | ||
161 | #define VS6624_ANTI_FLICKER_MODE 0x11C0 /* anti flicker mode */ | ||
162 | /* white balance control */ | ||
163 | #define VS6624_WB_MODE 0x1480 /* set white balance mode */ | ||
164 | #define VS6624_MAN_RG 0x1482 /* user setting for red channel gain */ | ||
165 | #define VS6624_MAN_GG 0x1484 /* user setting for green channel gain */ | ||
166 | #define VS6624_MAN_BG 0x1486 /* user setting for blue channel gain */ | ||
167 | #define VS6624_FLASH_RG_MSB 0x148B /* red gain for Flash Gun MSB */ | ||
168 | #define VS6624_FLASH_RG_LSB 0x148C /* red gain for Flash Gun LSB */ | ||
169 | #define VS6624_FLASH_GG_MSB 0x148F /* green gain for Flash Gun MSB */ | ||
170 | #define VS6624_FLASH_GG_LSB 0x1490 /* green gain for Flash Gun LSB */ | ||
171 | #define VS6624_FLASH_BG_MSB 0x1493 /* blue gain for Flash Gun MSB */ | ||
172 | #define VS6624_FLASH_BG_LSB 0x1494 /* blue gain for Flash Gun LSB */ | ||
173 | /* sensor setup */ | ||
174 | #define VS6624_BC_OFFSET 0x1990 /* Black Correction Offset */ | ||
175 | /* image stability */ | ||
176 | #define VS6624_STABLE_WB 0x1900 /* white balance stable */ | ||
177 | #define VS6624_STABLE_EXPO 0x1902 /* exposure stable */ | ||
178 | #define VS6624_STABLE 0x1906 /* system stable */ | ||
179 | /* flash control */ | ||
180 | #define VS6624_FLASH_MODE 0x1A80 /* flash mode */ | ||
181 | #define VS6624_FLASH_OFF_LINE_MSB 0x1A83 /* off line at flash pulse mode MSB */ | ||
182 | #define VS6624_FLASH_OFF_LINE_LSB 0x1A84 /* off line at flash pulse mode LSB */ | ||
183 | /* flash status */ | ||
184 | #define VS6624_FLASH_RECOM 0x1B00 /* flash gun is recommended */ | ||
185 | #define VS6624_FLASH_GRAB_COMPLETE 0x1B02 /* flash gun image has been grabbed */ | ||
186 | /* scythe filter controls */ | ||
187 | #define VS6624_SCYTHE_FILTER 0x1D80 /* disable scythe defect correction */ | ||
188 | /* jack filter controls */ | ||
189 | #define VS6624_JACK_FILTER 0x1E00 /* disable jack defect correction */ | ||
190 | /* demosaic control */ | ||
191 | #define VS6624_ANTI_ALIAS_FILTER 0x1E80 /* anti alias filter suppress */ | ||
192 | /* color matrix dampers */ | ||
193 | #define VS6624_CM_DISABLE 0x1F00 /* disable color matrix damper */ | ||
194 | #define VS6624_CM_LOW_THR_MSB 0x1F03 /* low threshold for exposure MSB */ | ||
195 | #define VS6624_CM_LOW_THR_LSB 0x1F04 /* low threshold for exposure LSB */ | ||
196 | #define VS6624_CM_HIGH_THR_MSB 0x1F07 /* high threshold for exposure MSB */ | ||
197 | #define VS6624_CM_HIGH_THR_LSB 0x1F08 /* high threshold for exposure LSB */ | ||
198 | #define VS6624_CM_MIN_OUT_MSB 0x1F0B /* minimum possible damper output MSB */ | ||
199 | #define VS6624_CM_MIN_OUT_LSB 0x1F0C /* minimum possible damper output LSB */ | ||
200 | /* peaking control */ | ||
201 | #define VS6624_PEAK_GAIN 0x2000 /* controls peaking gain */ | ||
202 | #define VS6624_PEAK_G_DISABLE 0x2002 /* disable peak gain damping */ | ||
203 | #define VS6624_PEAK_LOW_THR_G_MSB 0x2005 /* low threshold for exposure for gain MSB */ | ||
204 | #define VS6624_PEAK_LOW_THR_G_LSB 0x2006 /* low threshold for exposure for gain LSB */ | ||
205 | #define VS6624_PEAK_HIGH_THR_G_MSB 0x2009 /* high threshold for exposure for gain MSB */ | ||
206 | #define VS6624_PEAK_HIGH_THR_G_LSB 0x200A /* high threshold for exposure for gain LSB */ | ||
207 | #define VS6624_PEAK_MIN_OUT_G_MSB 0x200D /* minimum damper output for gain MSB */ | ||
208 | #define VS6624_PEAK_MIN_OUT_G_LSB 0x200E /* minimum damper output for gain LSB */ | ||
209 | #define VS6624_PEAK_LOW_THR 0x2010 /* adjust degree of coring */ | ||
210 | #define VS6624_PEAK_C_DISABLE 0x2012 /* disable coring damping */ | ||
211 | #define VS6624_PEAK_HIGH_THR 0x2014 /* adjust maximum gain */ | ||
212 | #define VS6624_PEAK_LOW_THR_C_MSB 0x2017 /* low threshold for exposure for coring MSB */ | ||
213 | #define VS6624_PEAK_LOW_THR_C_LSB 0x2018 /* low threshold for exposure for coring LSB */ | ||
214 | #define VS6624_PEAK_HIGH_THR_C_MSB 0x201B /* high threshold for exposure for coring MSB */ | ||
215 | #define VS6624_PEAK_HIGH_THR_C_LSB 0x201C /* high threshold for exposure for coring LSB */ | ||
216 | #define VS6624_PEAK_MIN_OUT_C_MSB 0x201F /* minimum damper output for coring MSB */ | ||
217 | #define VS6624_PEAK_MIN_OUT_C_LSB 0x2020 /* minimum damper output for coring LSB */ | ||
218 | /* pipe 0 RGB to YUV matrix manual control */ | ||
219 | #define VS6624_RYM0_MAN_CTRL 0x2180 /* enable manual RGB to YUV matrix */ | ||
220 | #define VS6624_RYM0_W00_MSB 0x2183 /* row 0 column 0 of YUV matrix MSB */ | ||
221 | #define VS6624_RYM0_W00_LSB 0x2184 /* row 0 column 0 of YUV matrix LSB */ | ||
222 | #define VS6624_RYM0_W01_MSB 0x2187 /* row 0 column 1 of YUV matrix MSB */ | ||
223 | #define VS6624_RYM0_W01_LSB 0x2188 /* row 0 column 1 of YUV matrix LSB */ | ||
224 | #define VS6624_RYM0_W02_MSB 0x218C /* row 0 column 2 of YUV matrix MSB */ | ||
225 | #define VS6624_RYM0_W02_LSB 0x218D /* row 0 column 2 of YUV matrix LSB */ | ||
226 | #define VS6624_RYM0_W10_MSB 0x2190 /* row 1 column 0 of YUV matrix MSB */ | ||
227 | #define VS6624_RYM0_W10_LSB 0x218F /* row 1 column 0 of YUV matrix LSB */ | ||
228 | #define VS6624_RYM0_W11_MSB 0x2193 /* row 1 column 1 of YUV matrix MSB */ | ||
229 | #define VS6624_RYM0_W11_LSB 0x2194 /* row 1 column 1 of YUV matrix LSB */ | ||
230 | #define VS6624_RYM0_W12_MSB 0x2197 /* row 1 column 2 of YUV matrix MSB */ | ||
231 | #define VS6624_RYM0_W12_LSB 0x2198 /* row 1 column 2 of YUV matrix LSB */ | ||
232 | #define VS6624_RYM0_W20_MSB 0x219B /* row 2 column 0 of YUV matrix MSB */ | ||
233 | #define VS6624_RYM0_W20_LSB 0x219C /* row 2 column 0 of YUV matrix LSB */ | ||
234 | #define VS6624_RYM0_W21_MSB 0x21A0 /* row 2 column 1 of YUV matrix MSB */ | ||
235 | #define VS6624_RYM0_W21_LSB 0x219F /* row 2 column 1 of YUV matrix LSB */ | ||
236 | #define VS6624_RYM0_W22_MSB 0x21A3 /* row 2 column 2 of YUV matrix MSB */ | ||
237 | #define VS6624_RYM0_W22_LSB 0x21A4 /* row 2 column 2 of YUV matrix LSB */ | ||
238 | #define VS6624_RYM0_YINY_MSB 0x21A7 /* Y in Y MSB */ | ||
239 | #define VS6624_RYM0_YINY_LSB 0x21A8 /* Y in Y LSB */ | ||
240 | #define VS6624_RYM0_YINCB_MSB 0x21AB /* Y in Cb MSB */ | ||
241 | #define VS6624_RYM0_YINCB_LSB 0x21AC /* Y in Cb LSB */ | ||
242 | #define VS6624_RYM0_YINCR_MSB 0x21B0 /* Y in Cr MSB */ | ||
243 | #define VS6624_RYM0_YINCR_LSB 0x21AF /* Y in Cr LSB */ | ||
244 | /* pipe 1 RGB to YUV matrix manual control */ | ||
245 | #define VS6624_RYM1_MAN_CTRL 0x2200 /* enable manual RGB to YUV matrix */ | ||
246 | #define VS6624_RYM1_W00_MSB 0x2203 /* row 0 column 0 of YUV matrix MSB */ | ||
247 | #define VS6624_RYM1_W00_LSB 0x2204 /* row 0 column 0 of YUV matrix LSB */ | ||
248 | #define VS6624_RYM1_W01_MSB 0x2207 /* row 0 column 1 of YUV matrix MSB */ | ||
249 | #define VS6624_RYM1_W01_LSB 0x2208 /* row 0 column 1 of YUV matrix LSB */ | ||
250 | #define VS6624_RYM1_W02_MSB 0x220C /* row 0 column 2 of YUV matrix MSB */ | ||
251 | #define VS6624_RYM1_W02_LSB 0x220D /* row 0 column 2 of YUV matrix LSB */ | ||
252 | #define VS6624_RYM1_W10_MSB 0x2210 /* row 1 column 0 of YUV matrix MSB */ | ||
253 | #define VS6624_RYM1_W10_LSB 0x220F /* row 1 column 0 of YUV matrix LSB */ | ||
254 | #define VS6624_RYM1_W11_MSB 0x2213 /* row 1 column 1 of YUV matrix MSB */ | ||
255 | #define VS6624_RYM1_W11_LSB 0x2214 /* row 1 column 1 of YUV matrix LSB */ | ||
256 | #define VS6624_RYM1_W12_MSB 0x2217 /* row 1 column 2 of YUV matrix MSB */ | ||
257 | #define VS6624_RYM1_W12_LSB 0x2218 /* row 1 column 2 of YUV matrix LSB */ | ||
258 | #define VS6624_RYM1_W20_MSB 0x221B /* row 2 column 0 of YUV matrix MSB */ | ||
259 | #define VS6624_RYM1_W20_LSB 0x221C /* row 2 column 0 of YUV matrix LSB */ | ||
260 | #define VS6624_RYM1_W21_MSB 0x2220 /* row 2 column 1 of YUV matrix MSB */ | ||
261 | #define VS6624_RYM1_W21_LSB 0x221F /* row 2 column 1 of YUV matrix LSB */ | ||
262 | #define VS6624_RYM1_W22_MSB 0x2223 /* row 2 column 2 of YUV matrix MSB */ | ||
263 | #define VS6624_RYM1_W22_LSB 0x2224 /* row 2 column 2 of YUV matrix LSB */ | ||
264 | #define VS6624_RYM1_YINY_MSB 0x2227 /* Y in Y MSB */ | ||
265 | #define VS6624_RYM1_YINY_LSB 0x2228 /* Y in Y LSB */ | ||
266 | #define VS6624_RYM1_YINCB_MSB 0x222B /* Y in Cb MSB */ | ||
267 | #define VS6624_RYM1_YINCB_LSB 0x222C /* Y in Cb LSB */ | ||
268 | #define VS6624_RYM1_YINCR_MSB 0x2220 /* Y in Cr MSB */ | ||
269 | #define VS6624_RYM1_YINCR_LSB 0x222F /* Y in Cr LSB */ | ||
270 | /* pipe 0 gamma manual control */ | ||
271 | #define VS6624_GAMMA_MAN_CTRL0 0x2280 /* enable manual gamma setup */ | ||
272 | #define VS6624_GAMMA_PEAK_R0 0x2282 /* peaked red channel gamma value */ | ||
273 | #define VS6624_GAMMA_PEAK_G0 0x2284 /* peaked green channel gamma value */ | ||
274 | #define VS6624_GAMMA_PEAK_B0 0x2286 /* peaked blue channel gamma value */ | ||
275 | #define VS6624_GAMMA_UNPEAK_R0 0x2288 /* unpeaked red channel gamma value */ | ||
276 | #define VS6624_GAMMA_UNPEAK_G0 0x228A /* unpeaked green channel gamma value */ | ||
277 | #define VS6624_GAMMA_UNPEAK_B0 0x228C /* unpeaked blue channel gamma value */ | ||
278 | /* pipe 1 gamma manual control */ | ||
279 | #define VS6624_GAMMA_MAN_CTRL1 0x2300 /* enable manual gamma setup */ | ||
280 | #define VS6624_GAMMA_PEAK_R1 0x2302 /* peaked red channel gamma value */ | ||
281 | #define VS6624_GAMMA_PEAK_G1 0x2304 /* peaked green channel gamma value */ | ||
282 | #define VS6624_GAMMA_PEAK_B1 0x2306 /* peaked blue channel gamma value */ | ||
283 | #define VS6624_GAMMA_UNPEAK_R1 0x2308 /* unpeaked red channel gamma value */ | ||
284 | #define VS6624_GAMMA_UNPEAK_G1 0x230A /* unpeaked green channel gamma value */ | ||
285 | #define VS6624_GAMMA_UNPEAK_B1 0x230C /* unpeaked blue channel gamma value */ | ||
286 | /* fade to black */ | ||
287 | #define VS6624_F2B_DISABLE 0x2480 /* disable fade to black */ | ||
288 | #define VS6624_F2B_BLACK_VAL_MSB 0x2483 /* black value MSB */ | ||
289 | #define VS6624_F2B_BLACK_VAL_LSB 0x2484 /* black value LSB */ | ||
290 | #define VS6624_F2B_LOW_THR_MSB 0x2487 /* low threshold for exposure MSB */ | ||
291 | #define VS6624_F2B_LOW_THR_LSB 0x2488 /* low threshold for exposure LSB */ | ||
292 | #define VS6624_F2B_HIGH_THR_MSB 0x248B /* high threshold for exposure MSB */ | ||
293 | #define VS6624_F2B_HIGH_THR_LSB 0x248C /* high threshold for exposure LSB */ | ||
294 | #define VS6624_F2B_MIN_OUT_MSB 0x248F /* minimum damper output MSB */ | ||
295 | #define VS6624_F2B_MIN_OUT_LSB 0x2490 /* minimum damper output LSB */ | ||
296 | /* output formatter control */ | ||
297 | #define VS6624_CODE_CK_EN 0x2580 /* code check enable */ | ||
298 | #define VS6624_BLANK_FMT 0x2582 /* blank format */ | ||
299 | #define VS6624_SYNC_CODE_SETUP 0x2584 /* sync code setup */ | ||
300 | #define VS6624_HSYNC_SETUP 0x2586 /* H sync setup */ | ||
301 | #define VS6624_VSYNC_SETUP 0x2588 /* V sync setup */ | ||
302 | #define VS6624_PCLK_SETUP 0x258A /* PCLK setup */ | ||
303 | #define VS6624_PCLK_EN 0x258C /* PCLK enable */ | ||
304 | #define VS6624_OPF_SP_SETUP 0x258E /* output formatter sp setup */ | ||
305 | #define VS6624_BLANK_DATA_MSB 0x2590 /* blank data MSB */ | ||
306 | #define VS6624_BLANK_DATA_LSB 0x2592 /* blank data LSB */ | ||
307 | #define VS6624_RGB_SETUP 0x2594 /* RGB setup */ | ||
308 | #define VS6624_YUV_SETUP 0x2596 /* YUV setup */ | ||
309 | #define VS6624_VSYNC_RIS_COARSE_H 0x2598 /* V sync rising coarse high */ | ||
310 | #define VS6624_VSYNC_RIS_COARSE_L 0x259A /* V sync rising coarse low */ | ||
311 | #define VS6624_VSYNC_RIS_FINE_H 0x259C /* V sync rising fine high */ | ||
312 | #define VS6624_VSYNC_RIS_FINE_L 0x259E /* V sync rising fine low */ | ||
313 | #define VS6624_VSYNC_FALL_COARSE_H 0x25A0 /* V sync falling coarse high */ | ||
314 | #define VS6624_VSYNC_FALL_COARSE_L 0x25A2 /* V sync falling coarse low */ | ||
315 | #define VS6624_VSYNC_FALL_FINE_H 0x25A4 /* V sync falling fine high */ | ||
316 | #define VS6624_VSYNC_FALL_FINE_L 0x25A6 /* V sync falling fine low */ | ||
317 | #define VS6624_HSYNC_RIS_H 0x25A8 /* H sync rising high */ | ||
318 | #define VS6624_HSYNC_RIS_L 0x25AA /* H sync rising low */ | ||
319 | #define VS6624_HSYNC_FALL_H 0x25AC /* H sync falling high */ | ||
320 | #define VS6624_HSYNC_FALL_L 0x25AE /* H sync falling low */ | ||
321 | #define VS6624_OUT_IF 0x25B0 /* output interface */ | ||
322 | #define VS6624_CCP_EXT_DATA 0x25B2 /* CCP extra data */ | ||
323 | /* NoRA controls */ | ||
324 | #define VS6624_NORA_DISABLE 0x2600 /* NoRA control mode */ | ||
325 | #define VS6624_NORA_USAGE 0x2602 /* usage */ | ||
326 | #define VS6624_NORA_SPLIT_KN 0x2604 /* split kn */ | ||
327 | #define VS6624_NORA_SPLIT_NI 0x2606 /* split ni */ | ||
328 | #define VS6624_NORA_TIGHT_G 0x2608 /* tight green */ | ||
329 | #define VS6624_NORA_DISABLE_NP 0x260A /* disable noro promoting */ | ||
330 | #define VS6624_NORA_LOW_THR_MSB 0x260D /* low threshold for exposure MSB */ | ||
331 | #define VS6624_NORA_LOW_THR_LSB 0x260E /* low threshold for exposure LSB */ | ||
332 | #define VS6624_NORA_HIGH_THR_MSB 0x2611 /* high threshold for exposure MSB */ | ||
333 | #define VS6624_NORA_HIGH_THR_LSB 0x2612 /* high threshold for exposure LSB */ | ||
334 | #define VS6624_NORA_MIN_OUT_MSB 0x2615 /* minimum damper output MSB */ | ||
335 | #define VS6624_NORA_MIN_OUT_LSB 0x2616 /* minimum damper output LSB */ | ||
336 | |||
337 | #endif | ||
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 453dbbd1e6e8..7fd7ac567e1a 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c | |||
@@ -129,9 +129,9 @@ MODULE_LICENSE("GPL"); | |||
129 | MODULE_VERSION("0.33.1"); | 129 | MODULE_VERSION("0.33.1"); |
130 | 130 | ||
131 | #ifdef MODULE | 131 | #ifdef MODULE |
132 | static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; | 132 | static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; |
133 | #else | 133 | #else |
134 | static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; | 134 | static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; |
135 | #endif | 135 | #endif |
136 | module_param_array(pardev, charp, NULL, 0); | 136 | module_param_array(pardev, charp, NULL, 0); |
137 | MODULE_PARM_DESC(pardev, "pardev: where to search for\n" | 137 | MODULE_PARM_DESC(pardev, "pardev: where to search for\n" |
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index a22f765e968a..3bb99e93febe 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c | |||
@@ -291,15 +291,4 @@ static struct i2c_driver wm8739_driver = { | |||
291 | .id_table = wm8739_id, | 291 | .id_table = wm8739_id, |
292 | }; | 292 | }; |
293 | 293 | ||
294 | static __init int init_wm8739(void) | 294 | module_i2c_driver(wm8739_driver); |
295 | { | ||
296 | return i2c_add_driver(&wm8739_driver); | ||
297 | } | ||
298 | |||
299 | static __exit void exit_wm8739(void) | ||
300 | { | ||
301 | i2c_del_driver(&wm8739_driver); | ||
302 | } | ||
303 | |||
304 | module_init(init_wm8739); | ||
305 | module_exit(exit_wm8739); | ||
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 9cedb1e69b58..bee77ea9f49e 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c | |||
@@ -339,15 +339,4 @@ static struct i2c_driver wm8775_driver = { | |||
339 | .id_table = wm8775_id, | 339 | .id_table = wm8775_id, |
340 | }; | 340 | }; |
341 | 341 | ||
342 | static __init int init_wm8775(void) | 342 | module_i2c_driver(wm8775_driver); |
343 | { | ||
344 | return i2c_add_driver(&wm8775_driver); | ||
345 | } | ||
346 | |||
347 | static __exit void exit_wm8775(void) | ||
348 | { | ||
349 | i2c_del_driver(&wm8775_driver); | ||
350 | } | ||
351 | |||
352 | module_init(init_wm8775); | ||
353 | module_exit(exit_wm8775); | ||