diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-21 12:03:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-21 12:03:10 -0400 |
commit | c720f5655df159a630fa0290a0bd67c93e92b0bf (patch) | |
tree | 940d139d0ec1ff5201efddef6cc663166a8a2df3 /drivers/media | |
parent | 33e6c1a0de818d3698cdab27c42915661011319d (diff) | |
parent | 84d6ae431f315e8973aac3c3fe1d550fc9240ef3 (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (222 commits)
V4L/DVB (13033): pt1: Don't use a deprecated DMA_BIT_MASK macro
V4L/DVB (13029): radio-si4713: remove #include <linux/version.h>
V4L/DVB (13027): go7007: convert printks to v4l2_info
V4L/DVB (13026): s2250-board: Implement brightness and contrast controls
V4L/DVB (13025): s2250-board: Fix memory leaks
V4L/DVB (13024): go7007: Implement vidioc_g_std and vidioc_querystd
V4L/DVB (13023): go7007: Merge struct gofh and go declarations
V4L/DVB (13022): go7007: Fix mpeg controls
V4L/DVB (13021): go7007: Fix whitespace and line lengths
V4L/DVB (13020): go7007: Updates to Kconfig and Makefile
V4L/DVB (13019): video: initial support for ADV7180
V4L/DVB (13018): kzalloc failure ignored in au8522_probe()
V4L/DVB (13017): gspca: kmalloc failure ignored in sd_start()
V4L/DVB (13016): kmalloc failure ignored in lgdt3304_attach() and s921_attach()
V4L/DVB (13015): kmalloc failure ignored in m920x_firmware_download()
V4L/DVB (13014): Add support for Compro VideoMate E800 (DVB-T part only)
V4L/DVB (13013): FM TX: si4713: Kconfig: Fixed two typos.
V4L/DVB (13012): uvc: introduce missing kfree
V4L/DVB (13011): Change tuner type of BeholdTV cards
V4L/DVB (13009): gspca - stv06xx-hdcs: Reduce exposure range
...
Diffstat (limited to 'drivers/media')
155 files changed, 31450 insertions, 3572 deletions
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index fc76c30e24f1..155c93eb75da 100644 --- a/drivers/media/common/tuners/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c | |||
@@ -210,7 +210,8 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) | |||
210 | tda18271_i2c_gate_ctrl(fe, 0); | 210 | tda18271_i2c_gate_ctrl(fe, 0); |
211 | 211 | ||
212 | if (ret != 1) | 212 | if (ret != 1) |
213 | tda_err("ERROR: i2c_transfer returned: %d\n", ret); | 213 | tda_err("ERROR: idx = 0x%x, len = %d, " |
214 | "i2c_transfer returned: %d\n", idx, len, ret); | ||
214 | 215 | ||
215 | return (ret == 1 ? 0 : ret); | 216 | return (ret == 1 ? 0 : ret); |
216 | } | 217 | } |
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index bc4b004ba7db..64595112000d 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c | |||
@@ -36,6 +36,27 @@ static LIST_HEAD(hybrid_tuner_instance_list); | |||
36 | 36 | ||
37 | /*---------------------------------------------------------------------*/ | 37 | /*---------------------------------------------------------------------*/ |
38 | 38 | ||
39 | static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) | ||
40 | { | ||
41 | struct tda18271_priv *priv = fe->tuner_priv; | ||
42 | |||
43 | int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0, | ||
44 | priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0, | ||
45 | priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0); | ||
46 | |||
47 | if (tda_fail(ret)) | ||
48 | goto fail; | ||
49 | |||
50 | tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", | ||
51 | standby ? "standby" : "active", | ||
52 | priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", | ||
53 | priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); | ||
54 | fail: | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | /*---------------------------------------------------------------------*/ | ||
59 | |||
39 | static inline int charge_pump_source(struct dvb_frontend *fe, int force) | 60 | static inline int charge_pump_source(struct dvb_frontend *fe, int force) |
40 | { | 61 | { |
41 | struct tda18271_priv *priv = fe->tuner_priv; | 62 | struct tda18271_priv *priv = fe->tuner_priv; |
@@ -271,7 +292,7 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, | |||
271 | tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); | 292 | tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); |
272 | 293 | ||
273 | /* calculate temperature compensation */ | 294 | /* calculate temperature compensation */ |
274 | rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal); | 295 | rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal) / 1000; |
275 | 296 | ||
276 | regs[R_EB14] = approx + rfcal_comp; | 297 | regs[R_EB14] = approx + rfcal_comp; |
277 | ret = tda18271_write_regs(fe, R_EB14, 1); | 298 | ret = tda18271_write_regs(fe, R_EB14, 1); |
@@ -800,7 +821,7 @@ static int tda18271_init(struct dvb_frontend *fe) | |||
800 | 821 | ||
801 | mutex_lock(&priv->lock); | 822 | mutex_lock(&priv->lock); |
802 | 823 | ||
803 | /* power up */ | 824 | /* full power up */ |
804 | ret = tda18271_set_standby_mode(fe, 0, 0, 0); | 825 | ret = tda18271_set_standby_mode(fe, 0, 0, 0); |
805 | if (tda_fail(ret)) | 826 | if (tda_fail(ret)) |
806 | goto fail; | 827 | goto fail; |
@@ -818,6 +839,21 @@ fail: | |||
818 | return ret; | 839 | return ret; |
819 | } | 840 | } |
820 | 841 | ||
842 | static int tda18271_sleep(struct dvb_frontend *fe) | ||
843 | { | ||
844 | struct tda18271_priv *priv = fe->tuner_priv; | ||
845 | int ret; | ||
846 | |||
847 | mutex_lock(&priv->lock); | ||
848 | |||
849 | /* enter standby mode, with required output features enabled */ | ||
850 | ret = tda18271_toggle_output(fe, 1); | ||
851 | |||
852 | mutex_unlock(&priv->lock); | ||
853 | |||
854 | return ret; | ||
855 | } | ||
856 | |||
821 | /* ------------------------------------------------------------------ */ | 857 | /* ------------------------------------------------------------------ */ |
822 | 858 | ||
823 | static int tda18271_agc(struct dvb_frontend *fe) | 859 | static int tda18271_agc(struct dvb_frontend *fe) |
@@ -827,8 +863,9 @@ static int tda18271_agc(struct dvb_frontend *fe) | |||
827 | 863 | ||
828 | switch (priv->config) { | 864 | switch (priv->config) { |
829 | case 0: | 865 | case 0: |
830 | /* no LNA */ | 866 | /* no external agc configuration required */ |
831 | tda_dbg("no agc configuration provided\n"); | 867 | if (tda18271_debug & DBG_ADV) |
868 | tda_dbg("no agc configuration provided\n"); | ||
832 | break; | 869 | break; |
833 | case 3: | 870 | case 3: |
834 | /* switch with GPIO of saa713x */ | 871 | /* switch with GPIO of saa713x */ |
@@ -1010,22 +1047,6 @@ fail: | |||
1010 | return ret; | 1047 | return ret; |
1011 | } | 1048 | } |
1012 | 1049 | ||
1013 | static int tda18271_sleep(struct dvb_frontend *fe) | ||
1014 | { | ||
1015 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1016 | int ret; | ||
1017 | |||
1018 | mutex_lock(&priv->lock); | ||
1019 | |||
1020 | /* standby mode w/ slave tuner output | ||
1021 | * & loop thru & xtal oscillator on */ | ||
1022 | ret = tda18271_set_standby_mode(fe, 1, 0, 0); | ||
1023 | |||
1024 | mutex_unlock(&priv->lock); | ||
1025 | |||
1026 | return ret; | ||
1027 | } | ||
1028 | |||
1029 | static int tda18271_release(struct dvb_frontend *fe) | 1050 | static int tda18271_release(struct dvb_frontend *fe) |
1030 | { | 1051 | { |
1031 | struct tda18271_priv *priv = fe->tuner_priv; | 1052 | struct tda18271_priv *priv = fe->tuner_priv; |
@@ -1199,6 +1220,9 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | |||
1199 | priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; | 1220 | priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; |
1200 | priv->role = (cfg) ? cfg->role : TDA18271_MASTER; | 1221 | priv->role = (cfg) ? cfg->role : TDA18271_MASTER; |
1201 | priv->config = (cfg) ? cfg->config : 0; | 1222 | priv->config = (cfg) ? cfg->config : 0; |
1223 | priv->small_i2c = (cfg) ? cfg->small_i2c : 0; | ||
1224 | priv->output_opt = (cfg) ? | ||
1225 | cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON; | ||
1202 | 1226 | ||
1203 | /* tda18271_cal_on_startup == -1 when cal | 1227 | /* tda18271_cal_on_startup == -1 when cal |
1204 | * module option is unset */ | 1228 | * module option is unset */ |
@@ -1216,9 +1240,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | |||
1216 | 1240 | ||
1217 | fe->tuner_priv = priv; | 1241 | fe->tuner_priv = priv; |
1218 | 1242 | ||
1219 | if (cfg) | ||
1220 | priv->small_i2c = cfg->small_i2c; | ||
1221 | |||
1222 | if (tda_fail(tda18271_get_id(fe))) | 1243 | if (tda_fail(tda18271_get_id(fe))) |
1223 | goto fail; | 1244 | goto fail; |
1224 | 1245 | ||
@@ -1238,9 +1259,19 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | |||
1238 | /* existing tuner instance */ | 1259 | /* existing tuner instance */ |
1239 | fe->tuner_priv = priv; | 1260 | fe->tuner_priv = priv; |
1240 | 1261 | ||
1241 | /* allow dvb driver to override i2c gate setting */ | 1262 | /* allow dvb driver to override configuration settings */ |
1242 | if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG)) | 1263 | if (cfg) { |
1243 | priv->gate = cfg->gate; | 1264 | if (cfg->gate != TDA18271_GATE_ANALOG) |
1265 | priv->gate = cfg->gate; | ||
1266 | if (cfg->role) | ||
1267 | priv->role = cfg->role; | ||
1268 | if (cfg->config) | ||
1269 | priv->config = cfg->config; | ||
1270 | if (cfg->small_i2c) | ||
1271 | priv->small_i2c = cfg->small_i2c; | ||
1272 | if (cfg->output_opt) | ||
1273 | priv->output_opt = cfg->output_opt; | ||
1274 | } | ||
1244 | break; | 1275 | break; |
1245 | } | 1276 | } |
1246 | 1277 | ||
diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index ab14ceb9e0ce..e21fdeff3ddf 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c | |||
@@ -962,10 +962,9 @@ struct tda18271_cid_target_map { | |||
962 | static struct tda18271_cid_target_map tda18271_cid_target[] = { | 962 | static struct tda18271_cid_target_map tda18271_cid_target[] = { |
963 | { .rfmax = 46000, .target = 0x04, .limit = 1800 }, | 963 | { .rfmax = 46000, .target = 0x04, .limit = 1800 }, |
964 | { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, | 964 | { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, |
965 | { .rfmax = 79100, .target = 0x01, .limit = 4000 }, | 965 | { .rfmax = 70100, .target = 0x01, .limit = 4000 }, |
966 | { .rfmax = 136800, .target = 0x18, .limit = 4000 }, | 966 | { .rfmax = 136800, .target = 0x18, .limit = 4000 }, |
967 | { .rfmax = 156700, .target = 0x18, .limit = 4000 }, | 967 | { .rfmax = 156700, .target = 0x18, .limit = 4000 }, |
968 | { .rfmax = 156700, .target = 0x18, .limit = 4000 }, | ||
969 | { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, | 968 | { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, |
970 | { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, | 969 | { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, |
971 | { .rfmax = 345000, .target = 0x18, .limit = 4000 }, | 970 | { .rfmax = 345000, .target = 0x18, .limit = 4000 }, |
diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index e6a80ad09356..2bee229acd91 100644 --- a/drivers/media/common/tuners/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h | |||
@@ -108,6 +108,7 @@ struct tda18271_priv { | |||
108 | enum tda18271_role role; | 108 | enum tda18271_role role; |
109 | enum tda18271_i2c_gate gate; | 109 | enum tda18271_i2c_gate gate; |
110 | enum tda18271_ver id; | 110 | enum tda18271_ver id; |
111 | enum tda18271_output_options output_opt; | ||
111 | 112 | ||
112 | unsigned int config; /* interface to saa713x / tda829x */ | 113 | unsigned int config; /* interface to saa713x / tda829x */ |
113 | unsigned int tm_rfcal; | 114 | unsigned int tm_rfcal; |
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h index 71bac9593f1e..323f2912128d 100644 --- a/drivers/media/common/tuners/tda18271.h +++ b/drivers/media/common/tuners/tda18271.h | |||
@@ -67,6 +67,17 @@ enum tda18271_i2c_gate { | |||
67 | TDA18271_GATE_DIGITAL, | 67 | TDA18271_GATE_DIGITAL, |
68 | }; | 68 | }; |
69 | 69 | ||
70 | enum tda18271_output_options { | ||
71 | /* slave tuner output & loop thru & xtal oscillator always on */ | ||
72 | TDA18271_OUTPUT_LT_XT_ON = 0, | ||
73 | |||
74 | /* slave tuner output loop thru off */ | ||
75 | TDA18271_OUTPUT_LT_OFF = 1, | ||
76 | |||
77 | /* xtal oscillator off */ | ||
78 | TDA18271_OUTPUT_XT_OFF = 2, | ||
79 | }; | ||
80 | |||
70 | struct tda18271_config { | 81 | struct tda18271_config { |
71 | /* override default if freq / std settings (optional) */ | 82 | /* override default if freq / std settings (optional) */ |
72 | struct tda18271_std_map *std_map; | 83 | struct tda18271_std_map *std_map; |
@@ -77,6 +88,9 @@ struct tda18271_config { | |||
77 | /* use i2c gate provided by analog or digital demod */ | 88 | /* use i2c gate provided by analog or digital demod */ |
78 | enum tda18271_i2c_gate gate; | 89 | enum tda18271_i2c_gate gate; |
79 | 90 | ||
91 | /* output options that can be disabled */ | ||
92 | enum tda18271_output_options output_opt; | ||
93 | |||
80 | /* force rf tracking filter calibration on startup */ | 94 | /* force rf tracking filter calibration on startup */ |
81 | unsigned int rf_cal_on_startup:1; | 95 | unsigned int rf_cal_on_startup:1; |
82 | 96 | ||
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 5c6ef1e23c94..2b876f3988c1 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c | |||
@@ -1320,6 +1320,23 @@ static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { | |||
1320 | }, | 1320 | }, |
1321 | }; | 1321 | }; |
1322 | 1322 | ||
1323 | /* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */ | ||
1324 | |||
1325 | static struct tuner_range tuner_cu1216l_ranges[] = { | ||
1326 | { 16 * 160.25 /*MHz*/, 0xce, 0x01 }, | ||
1327 | { 16 * 444.25 /*MHz*/, 0xce, 0x02 }, | ||
1328 | { 16 * 999.99 , 0xce, 0x04 }, | ||
1329 | }; | ||
1330 | |||
1331 | static struct tuner_params tuner_philips_cu1216l_params[] = { | ||
1332 | { | ||
1333 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1334 | .ranges = tuner_cu1216l_ranges, | ||
1335 | .count = ARRAY_SIZE(tuner_cu1216l_ranges), | ||
1336 | .iffreq = 16 * 36.125, /*MHz*/ | ||
1337 | }, | ||
1338 | }; | ||
1339 | |||
1323 | /* --------------------------------------------------------------------- */ | 1340 | /* --------------------------------------------------------------------- */ |
1324 | 1341 | ||
1325 | struct tunertype tuners[] = { | 1342 | struct tunertype tuners[] = { |
@@ -1778,6 +1795,16 @@ struct tunertype tuners[] = { | |||
1778 | .params = tuner_partsnic_pti_5nf05_params, | 1795 | .params = tuner_partsnic_pti_5nf05_params, |
1779 | .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), | 1796 | .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), |
1780 | }, | 1797 | }, |
1798 | [TUNER_PHILIPS_CU1216L] = { | ||
1799 | .name = "Philips CU1216L", | ||
1800 | .params = tuner_philips_cu1216l_params, | ||
1801 | .count = ARRAY_SIZE(tuner_philips_cu1216l_params), | ||
1802 | .stepsize = 62500, | ||
1803 | }, | ||
1804 | [TUNER_NXP_TDA18271] = { | ||
1805 | .name = "NXP TDA18271", | ||
1806 | /* see tda18271-fe.c for details */ | ||
1807 | }, | ||
1781 | }; | 1808 | }; |
1782 | EXPORT_SYMBOL(tuners); | 1809 | EXPORT_SYMBOL(tuners); |
1783 | 1810 | ||
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 1d0e4b1ef10c..35d0817126e9 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig | |||
@@ -68,6 +68,10 @@ comment "Supported FireWire (IEEE 1394) Adapters" | |||
68 | depends on DVB_CORE && IEEE1394 | 68 | depends on DVB_CORE && IEEE1394 |
69 | source "drivers/media/dvb/firewire/Kconfig" | 69 | source "drivers/media/dvb/firewire/Kconfig" |
70 | 70 | ||
71 | comment "Supported Earthsoft PT1 Adapters" | ||
72 | depends on DVB_CORE && PCI && I2C | ||
73 | source "drivers/media/dvb/pt1/Kconfig" | ||
74 | |||
71 | comment "Supported DVB Frontends" | 75 | comment "Supported DVB Frontends" |
72 | depends on DVB_CORE | 76 | depends on DVB_CORE |
73 | source "drivers/media/dvb/frontends/Kconfig" | 77 | source "drivers/media/dvb/frontends/Kconfig" |
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index 6092a5bb5a7d..16d262ddb45d 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile | |||
@@ -2,6 +2,6 @@ | |||
2 | # Makefile for the kernel multimedia device drivers. | 2 | # Makefile for the kernel multimedia device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ | 5 | obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/ |
6 | 6 | ||
7 | obj-$(CONFIG_DVB_FIREDTV) += firewire/ | 7 | obj-$(CONFIG_DVB_FIREDTV) += firewire/ |
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index d13ebcb0c6b6..ddf639ed2fd8 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
@@ -850,6 +850,49 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe, | |||
850 | return 0; | 850 | return 0; |
851 | } | 851 | } |
852 | 852 | ||
853 | static int dvb_frontend_clear_cache(struct dvb_frontend *fe) | ||
854 | { | ||
855 | int i; | ||
856 | |||
857 | memset(&(fe->dtv_property_cache), 0, | ||
858 | sizeof(struct dtv_frontend_properties)); | ||
859 | |||
860 | fe->dtv_property_cache.state = DTV_CLEAR; | ||
861 | fe->dtv_property_cache.delivery_system = SYS_UNDEFINED; | ||
862 | fe->dtv_property_cache.inversion = INVERSION_AUTO; | ||
863 | fe->dtv_property_cache.fec_inner = FEC_AUTO; | ||
864 | fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; | ||
865 | fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO; | ||
866 | fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; | ||
867 | fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO; | ||
868 | fe->dtv_property_cache.symbol_rate = QAM_AUTO; | ||
869 | fe->dtv_property_cache.code_rate_HP = FEC_AUTO; | ||
870 | fe->dtv_property_cache.code_rate_LP = FEC_AUTO; | ||
871 | |||
872 | fe->dtv_property_cache.isdbt_partial_reception = -1; | ||
873 | fe->dtv_property_cache.isdbt_sb_mode = -1; | ||
874 | fe->dtv_property_cache.isdbt_sb_subchannel = -1; | ||
875 | fe->dtv_property_cache.isdbt_sb_segment_idx = -1; | ||
876 | fe->dtv_property_cache.isdbt_sb_segment_count = -1; | ||
877 | fe->dtv_property_cache.isdbt_layer_enabled = 0x7; | ||
878 | for (i = 0; i < 3; i++) { | ||
879 | fe->dtv_property_cache.layer[i].fec = FEC_AUTO; | ||
880 | fe->dtv_property_cache.layer[i].modulation = QAM_AUTO; | ||
881 | fe->dtv_property_cache.layer[i].interleaving = -1; | ||
882 | fe->dtv_property_cache.layer[i].segment_count = -1; | ||
883 | } | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | #define _DTV_CMD(n, s, b) \ | ||
889 | [n] = { \ | ||
890 | .name = #n, \ | ||
891 | .cmd = n, \ | ||
892 | .set = s,\ | ||
893 | .buffer = b \ | ||
894 | } | ||
895 | |||
853 | static struct dtv_cmds_h dtv_cmds[] = { | 896 | static struct dtv_cmds_h dtv_cmds[] = { |
854 | [DTV_TUNE] = { | 897 | [DTV_TUNE] = { |
855 | .name = "DTV_TUNE", | 898 | .name = "DTV_TUNE", |
@@ -949,6 +992,47 @@ static struct dtv_cmds_h dtv_cmds[] = { | |||
949 | .cmd = DTV_TRANSMISSION_MODE, | 992 | .cmd = DTV_TRANSMISSION_MODE, |
950 | .set = 1, | 993 | .set = 1, |
951 | }, | 994 | }, |
995 | |||
996 | _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0), | ||
997 | _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0), | ||
998 | _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0), | ||
999 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0), | ||
1000 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0), | ||
1001 | _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0), | ||
1002 | _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0), | ||
1003 | _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0), | ||
1004 | _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0), | ||
1005 | _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0), | ||
1006 | _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0), | ||
1007 | _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0), | ||
1008 | _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0), | ||
1009 | _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0), | ||
1010 | _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0), | ||
1011 | _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0), | ||
1012 | _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0), | ||
1013 | _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0), | ||
1014 | |||
1015 | _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0), | ||
1016 | _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0), | ||
1017 | _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0), | ||
1018 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0), | ||
1019 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0), | ||
1020 | _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0), | ||
1021 | _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0), | ||
1022 | _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0), | ||
1023 | _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0), | ||
1024 | _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0), | ||
1025 | _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0), | ||
1026 | _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0), | ||
1027 | _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0), | ||
1028 | _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0), | ||
1029 | _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0), | ||
1030 | _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0), | ||
1031 | _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0), | ||
1032 | _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0), | ||
1033 | |||
1034 | _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0), | ||
1035 | |||
952 | /* Get */ | 1036 | /* Get */ |
953 | [DTV_DISEQC_SLAVE_REPLY] = { | 1037 | [DTV_DISEQC_SLAVE_REPLY] = { |
954 | .name = "DTV_DISEQC_SLAVE_REPLY", | 1038 | .name = "DTV_DISEQC_SLAVE_REPLY", |
@@ -956,6 +1040,7 @@ static struct dtv_cmds_h dtv_cmds[] = { | |||
956 | .set = 0, | 1040 | .set = 0, |
957 | .buffer = 1, | 1041 | .buffer = 1, |
958 | }, | 1042 | }, |
1043 | |||
959 | [DTV_API_VERSION] = { | 1044 | [DTV_API_VERSION] = { |
960 | .name = "DTV_API_VERSION", | 1045 | .name = "DTV_API_VERSION", |
961 | .cmd = DTV_API_VERSION, | 1046 | .cmd = DTV_API_VERSION, |
@@ -1165,14 +1250,21 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe) | |||
1165 | if(c->delivery_system == SYS_ISDBT) { | 1250 | if(c->delivery_system == SYS_ISDBT) { |
1166 | /* Fake out a generic DVB-T request so we pass validation in the ioctl */ | 1251 | /* Fake out a generic DVB-T request so we pass validation in the ioctl */ |
1167 | p->frequency = c->frequency; | 1252 | p->frequency = c->frequency; |
1168 | p->inversion = INVERSION_AUTO; | 1253 | p->inversion = c->inversion; |
1169 | p->u.ofdm.constellation = QAM_AUTO; | 1254 | p->u.ofdm.constellation = QAM_AUTO; |
1170 | p->u.ofdm.code_rate_HP = FEC_AUTO; | 1255 | p->u.ofdm.code_rate_HP = FEC_AUTO; |
1171 | p->u.ofdm.code_rate_LP = FEC_AUTO; | 1256 | p->u.ofdm.code_rate_LP = FEC_AUTO; |
1172 | p->u.ofdm.bandwidth = BANDWIDTH_AUTO; | ||
1173 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; | 1257 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; |
1174 | p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; | 1258 | p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; |
1175 | p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; | 1259 | p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; |
1260 | if (c->bandwidth_hz == 8000000) | ||
1261 | p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
1262 | else if (c->bandwidth_hz == 7000000) | ||
1263 | p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
1264 | else if (c->bandwidth_hz == 6000000) | ||
1265 | p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
1266 | else | ||
1267 | p->u.ofdm.bandwidth = BANDWIDTH_AUTO; | ||
1176 | } | 1268 | } |
1177 | } | 1269 | } |
1178 | 1270 | ||
@@ -1274,6 +1366,65 @@ static int dtv_property_process_get(struct dvb_frontend *fe, | |||
1274 | case DTV_HIERARCHY: | 1366 | case DTV_HIERARCHY: |
1275 | tvp->u.data = fe->dtv_property_cache.hierarchy; | 1367 | tvp->u.data = fe->dtv_property_cache.hierarchy; |
1276 | break; | 1368 | break; |
1369 | |||
1370 | /* ISDB-T Support here */ | ||
1371 | case DTV_ISDBT_PARTIAL_RECEPTION: | ||
1372 | tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception; | ||
1373 | break; | ||
1374 | case DTV_ISDBT_SOUND_BROADCASTING: | ||
1375 | tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode; | ||
1376 | break; | ||
1377 | case DTV_ISDBT_SB_SUBCHANNEL_ID: | ||
1378 | tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel; | ||
1379 | break; | ||
1380 | case DTV_ISDBT_SB_SEGMENT_IDX: | ||
1381 | tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx; | ||
1382 | break; | ||
1383 | case DTV_ISDBT_SB_SEGMENT_COUNT: | ||
1384 | tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count; | ||
1385 | break; | ||
1386 | case DTV_ISDBT_LAYER_ENABLED: | ||
1387 | tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled; | ||
1388 | break; | ||
1389 | case DTV_ISDBT_LAYERA_FEC: | ||
1390 | tvp->u.data = fe->dtv_property_cache.layer[0].fec; | ||
1391 | break; | ||
1392 | case DTV_ISDBT_LAYERA_MODULATION: | ||
1393 | tvp->u.data = fe->dtv_property_cache.layer[0].modulation; | ||
1394 | break; | ||
1395 | case DTV_ISDBT_LAYERA_SEGMENT_COUNT: | ||
1396 | tvp->u.data = fe->dtv_property_cache.layer[0].segment_count; | ||
1397 | break; | ||
1398 | case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: | ||
1399 | tvp->u.data = fe->dtv_property_cache.layer[0].interleaving; | ||
1400 | break; | ||
1401 | case DTV_ISDBT_LAYERB_FEC: | ||
1402 | tvp->u.data = fe->dtv_property_cache.layer[1].fec; | ||
1403 | break; | ||
1404 | case DTV_ISDBT_LAYERB_MODULATION: | ||
1405 | tvp->u.data = fe->dtv_property_cache.layer[1].modulation; | ||
1406 | break; | ||
1407 | case DTV_ISDBT_LAYERB_SEGMENT_COUNT: | ||
1408 | tvp->u.data = fe->dtv_property_cache.layer[1].segment_count; | ||
1409 | break; | ||
1410 | case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: | ||
1411 | tvp->u.data = fe->dtv_property_cache.layer[1].interleaving; | ||
1412 | break; | ||
1413 | case DTV_ISDBT_LAYERC_FEC: | ||
1414 | tvp->u.data = fe->dtv_property_cache.layer[2].fec; | ||
1415 | break; | ||
1416 | case DTV_ISDBT_LAYERC_MODULATION: | ||
1417 | tvp->u.data = fe->dtv_property_cache.layer[2].modulation; | ||
1418 | break; | ||
1419 | case DTV_ISDBT_LAYERC_SEGMENT_COUNT: | ||
1420 | tvp->u.data = fe->dtv_property_cache.layer[2].segment_count; | ||
1421 | break; | ||
1422 | case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: | ||
1423 | tvp->u.data = fe->dtv_property_cache.layer[2].interleaving; | ||
1424 | break; | ||
1425 | case DTV_ISDBS_TS_ID: | ||
1426 | tvp->u.data = fe->dtv_property_cache.isdbs_ts_id; | ||
1427 | break; | ||
1277 | default: | 1428 | default: |
1278 | r = -1; | 1429 | r = -1; |
1279 | } | 1430 | } |
@@ -1302,10 +1453,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe, | |||
1302 | /* Reset a cache of data specific to the frontend here. This does | 1453 | /* Reset a cache of data specific to the frontend here. This does |
1303 | * not effect hardware. | 1454 | * not effect hardware. |
1304 | */ | 1455 | */ |
1456 | dvb_frontend_clear_cache(fe); | ||
1305 | dprintk("%s() Flushing property cache\n", __func__); | 1457 | dprintk("%s() Flushing property cache\n", __func__); |
1306 | memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties)); | ||
1307 | fe->dtv_property_cache.state = tvp->cmd; | ||
1308 | fe->dtv_property_cache.delivery_system = SYS_UNDEFINED; | ||
1309 | break; | 1458 | break; |
1310 | case DTV_TUNE: | 1459 | case DTV_TUNE: |
1311 | /* interpret the cache of data, build either a traditional frontend | 1460 | /* interpret the cache of data, build either a traditional frontend |
@@ -1371,6 +1520,65 @@ static int dtv_property_process_set(struct dvb_frontend *fe, | |||
1371 | case DTV_HIERARCHY: | 1520 | case DTV_HIERARCHY: |
1372 | fe->dtv_property_cache.hierarchy = tvp->u.data; | 1521 | fe->dtv_property_cache.hierarchy = tvp->u.data; |
1373 | break; | 1522 | break; |
1523 | |||
1524 | /* ISDB-T Support here */ | ||
1525 | case DTV_ISDBT_PARTIAL_RECEPTION: | ||
1526 | fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data; | ||
1527 | break; | ||
1528 | case DTV_ISDBT_SOUND_BROADCASTING: | ||
1529 | fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data; | ||
1530 | break; | ||
1531 | case DTV_ISDBT_SB_SUBCHANNEL_ID: | ||
1532 | fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data; | ||
1533 | break; | ||
1534 | case DTV_ISDBT_SB_SEGMENT_IDX: | ||
1535 | fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data; | ||
1536 | break; | ||
1537 | case DTV_ISDBT_SB_SEGMENT_COUNT: | ||
1538 | fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data; | ||
1539 | break; | ||
1540 | case DTV_ISDBT_LAYER_ENABLED: | ||
1541 | fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data; | ||
1542 | break; | ||
1543 | case DTV_ISDBT_LAYERA_FEC: | ||
1544 | fe->dtv_property_cache.layer[0].fec = tvp->u.data; | ||
1545 | break; | ||
1546 | case DTV_ISDBT_LAYERA_MODULATION: | ||
1547 | fe->dtv_property_cache.layer[0].modulation = tvp->u.data; | ||
1548 | break; | ||
1549 | case DTV_ISDBT_LAYERA_SEGMENT_COUNT: | ||
1550 | fe->dtv_property_cache.layer[0].segment_count = tvp->u.data; | ||
1551 | break; | ||
1552 | case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: | ||
1553 | fe->dtv_property_cache.layer[0].interleaving = tvp->u.data; | ||
1554 | break; | ||
1555 | case DTV_ISDBT_LAYERB_FEC: | ||
1556 | fe->dtv_property_cache.layer[1].fec = tvp->u.data; | ||
1557 | break; | ||
1558 | case DTV_ISDBT_LAYERB_MODULATION: | ||
1559 | fe->dtv_property_cache.layer[1].modulation = tvp->u.data; | ||
1560 | break; | ||
1561 | case DTV_ISDBT_LAYERB_SEGMENT_COUNT: | ||
1562 | fe->dtv_property_cache.layer[1].segment_count = tvp->u.data; | ||
1563 | break; | ||
1564 | case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: | ||
1565 | fe->dtv_property_cache.layer[1].interleaving = tvp->u.data; | ||
1566 | break; | ||
1567 | case DTV_ISDBT_LAYERC_FEC: | ||
1568 | fe->dtv_property_cache.layer[2].fec = tvp->u.data; | ||
1569 | break; | ||
1570 | case DTV_ISDBT_LAYERC_MODULATION: | ||
1571 | fe->dtv_property_cache.layer[2].modulation = tvp->u.data; | ||
1572 | break; | ||
1573 | case DTV_ISDBT_LAYERC_SEGMENT_COUNT: | ||
1574 | fe->dtv_property_cache.layer[2].segment_count = tvp->u.data; | ||
1575 | break; | ||
1576 | case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: | ||
1577 | fe->dtv_property_cache.layer[2].interleaving = tvp->u.data; | ||
1578 | break; | ||
1579 | case DTV_ISDBS_TS_ID: | ||
1580 | fe->dtv_property_cache.isdbs_ts_id = tvp->u.data; | ||
1581 | break; | ||
1374 | default: | 1582 | default: |
1375 | r = -1; | 1583 | r = -1; |
1376 | } | 1584 | } |
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index e176da472d7a..810f07d63246 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h | |||
@@ -341,6 +341,23 @@ struct dtv_frontend_properties { | |||
341 | fe_rolloff_t rolloff; | 341 | fe_rolloff_t rolloff; |
342 | 342 | ||
343 | fe_delivery_system_t delivery_system; | 343 | fe_delivery_system_t delivery_system; |
344 | |||
345 | /* ISDB-T specifics */ | ||
346 | u8 isdbt_partial_reception; | ||
347 | u8 isdbt_sb_mode; | ||
348 | u8 isdbt_sb_subchannel; | ||
349 | u32 isdbt_sb_segment_idx; | ||
350 | u32 isdbt_sb_segment_count; | ||
351 | u8 isdbt_layer_enabled; | ||
352 | struct { | ||
353 | u8 segment_count; | ||
354 | fe_code_rate_t fec; | ||
355 | fe_modulation_t modulation; | ||
356 | u8 interleaving; | ||
357 | } layer[3]; | ||
358 | |||
359 | /* ISDB-T specifics */ | ||
360 | u32 isdbs_ts_id; | ||
344 | }; | 361 | }; |
345 | 362 | ||
346 | struct dvb_frontend { | 363 | struct dvb_frontend { |
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 8b8bc04ee980..0e4b97fba384 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig | |||
@@ -71,6 +71,7 @@ config DVB_USB_DIB0700 | |||
71 | depends on DVB_USB | 71 | depends on DVB_USB |
72 | select DVB_DIB7000P if !DVB_FE_CUSTOMISE | 72 | select DVB_DIB7000P if !DVB_FE_CUSTOMISE |
73 | select DVB_DIB7000M if !DVB_FE_CUSTOMISE | 73 | select DVB_DIB7000M if !DVB_FE_CUSTOMISE |
74 | select DVB_DIB8000 if !DVB_FE_CUSTOMISE | ||
74 | select DVB_DIB3000MC if !DVB_FE_CUSTOMISE | 75 | select DVB_DIB3000MC if !DVB_FE_CUSTOMISE |
75 | select DVB_S5H1411 if !DVB_FE_CUSTOMISE | 76 | select DVB_S5H1411 if !DVB_FE_CUSTOMISE |
76 | select DVB_LGDT3305 if !DVB_FE_CUSTOMISE | 77 | select DVB_LGDT3305 if !DVB_FE_CUSTOMISE |
@@ -87,7 +88,7 @@ config DVB_USB_DIB0700 | |||
87 | Avermedia and other big and small companies. | 88 | Avermedia and other big and small companies. |
88 | 89 | ||
89 | For an up-to-date list of devices supported by this driver, have a look | 90 | For an up-to-date list of devices supported by this driver, have a look |
90 | on the Linux-DVB Wiki at www.linuxtv.org. | 91 | on the LinuxTV Wiki at www.linuxtv.org. |
91 | 92 | ||
92 | Say Y if you own such a device and want to use it. You should build it as | 93 | Say Y if you own such a device and want to use it. You should build it as |
93 | a module. | 94 | a module. |
@@ -315,3 +316,9 @@ config DVB_USB_CE6230 | |||
315 | select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE | 316 | select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE |
316 | help | 317 | help |
317 | Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver | 318 | Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver |
319 | |||
320 | config DVB_USB_FRIIO | ||
321 | tristate "Friio ISDB-T USB2.0 Receiver support" | ||
322 | depends on DVB_USB | ||
323 | help | ||
324 | Say Y here to support the Japanese DTV receiver Friio. | ||
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index f92734ed777a..85b83a43d55d 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile | |||
@@ -79,6 +79,9 @@ obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o | |||
79 | dvb-usb-ce6230-objs = ce6230.o | 79 | dvb-usb-ce6230-objs = ce6230.o |
80 | obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o | 80 | obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o |
81 | 81 | ||
82 | dvb-usb-friio-objs = friio.o friio-fe.o | ||
83 | obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o | ||
84 | |||
82 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 85 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ |
83 | # due to tuner-xc3028 | 86 | # due to tuner-xc3028 |
84 | EXTRA_CFLAGS += -Idrivers/media/common/tuners | 87 | EXTRA_CFLAGS += -Idrivers/media/common/tuners |
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 99cdd0d101ca..cf042b309b46 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c | |||
@@ -61,10 +61,13 @@ static struct af9013_config af9015_af9013_config[] = { | |||
61 | 61 | ||
62 | static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) | 62 | static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) |
63 | { | 63 | { |
64 | #define BUF_LEN 63 | ||
65 | #define REQ_HDR_LEN 8 /* send header size */ | ||
66 | #define ACK_HDR_LEN 2 /* rece header size */ | ||
64 | int act_len, ret; | 67 | int act_len, ret; |
65 | u8 buf[64]; | 68 | u8 buf[BUF_LEN]; |
66 | u8 write = 1; | 69 | u8 write = 1; |
67 | u8 msg_len = 8; | 70 | u8 msg_len = REQ_HDR_LEN; |
68 | static u8 seq; /* packet sequence number */ | 71 | static u8 seq; /* packet sequence number */ |
69 | 72 | ||
70 | if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) | 73 | if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) |
@@ -94,7 +97,7 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) | |||
94 | break; | 97 | break; |
95 | case WRITE_MEMORY: | 98 | case WRITE_MEMORY: |
96 | if (((req->addr & 0xff00) == 0xff00) || | 99 | if (((req->addr & 0xff00) == 0xff00) || |
97 | ((req->addr & 0xae00) == 0xae00)) | 100 | ((req->addr & 0xff00) == 0xae00)) |
98 | buf[0] = WRITE_VIRTUAL_MEMORY; | 101 | buf[0] = WRITE_VIRTUAL_MEMORY; |
99 | case WRITE_VIRTUAL_MEMORY: | 102 | case WRITE_VIRTUAL_MEMORY: |
100 | case COPY_FIRMWARE: | 103 | case COPY_FIRMWARE: |
@@ -107,17 +110,26 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) | |||
107 | goto error_unlock; | 110 | goto error_unlock; |
108 | } | 111 | } |
109 | 112 | ||
113 | /* buffer overflow check */ | ||
114 | if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || | ||
115 | (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { | ||
116 | err("too much data; cmd:%d len:%d", req->cmd, req->data_len); | ||
117 | ret = -EINVAL; | ||
118 | goto error_unlock; | ||
119 | } | ||
120 | |||
110 | /* write requested */ | 121 | /* write requested */ |
111 | if (write) { | 122 | if (write) { |
112 | memcpy(&buf[8], req->data, req->data_len); | 123 | memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); |
113 | msg_len += req->data_len; | 124 | msg_len += req->data_len; |
114 | } | 125 | } |
126 | |||
115 | deb_xfer(">>> "); | 127 | deb_xfer(">>> "); |
116 | debug_dump(buf, msg_len, deb_xfer); | 128 | debug_dump(buf, msg_len, deb_xfer); |
117 | 129 | ||
118 | /* send req */ | 130 | /* send req */ |
119 | ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, | 131 | ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, |
120 | &act_len, AF9015_USB_TIMEOUT); | 132 | &act_len, AF9015_USB_TIMEOUT); |
121 | if (ret) | 133 | if (ret) |
122 | err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); | 134 | err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); |
123 | else | 135 | else |
@@ -130,10 +142,14 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) | |||
130 | if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) | 142 | if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) |
131 | goto exit_unlock; | 143 | goto exit_unlock; |
132 | 144 | ||
133 | /* receive ack and data if read req */ | 145 | /* write receives seq + status = 2 bytes |
134 | msg_len = 1 + 1 + req->data_len; /* seq + status + data len */ | 146 | read receives seq + status + data = 2 + N bytes */ |
147 | msg_len = ACK_HDR_LEN; | ||
148 | if (!write) | ||
149 | msg_len += req->data_len; | ||
150 | |||
135 | ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, | 151 | ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, |
136 | &act_len, AF9015_USB_TIMEOUT); | 152 | &act_len, AF9015_USB_TIMEOUT); |
137 | if (ret) { | 153 | if (ret) { |
138 | err("recv bulk message failed:%d", ret); | 154 | err("recv bulk message failed:%d", ret); |
139 | ret = -1; | 155 | ret = -1; |
@@ -159,7 +175,7 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) | |||
159 | 175 | ||
160 | /* read request, copy returned data to return buf */ | 176 | /* read request, copy returned data to return buf */ |
161 | if (!write) | 177 | if (!write) |
162 | memcpy(req->data, &buf[2], req->data_len); | 178 | memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); |
163 | 179 | ||
164 | error_unlock: | 180 | error_unlock: |
165 | exit_unlock: | 181 | exit_unlock: |
@@ -369,12 +385,14 @@ static int af9015_init_endpoint(struct dvb_usb_device *d) | |||
369 | u8 packet_size; | 385 | u8 packet_size; |
370 | deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); | 386 | deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); |
371 | 387 | ||
388 | /* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. | ||
389 | We use smaller - about 1/4 from the original, 5 and 87. */ | ||
372 | #define TS_PACKET_SIZE 188 | 390 | #define TS_PACKET_SIZE 188 |
373 | 391 | ||
374 | #define TS_USB20_PACKET_COUNT 348 | 392 | #define TS_USB20_PACKET_COUNT 87 |
375 | #define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) | 393 | #define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) |
376 | 394 | ||
377 | #define TS_USB11_PACKET_COUNT 21 | 395 | #define TS_USB11_PACKET_COUNT 5 |
378 | #define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) | 396 | #define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) |
379 | 397 | ||
380 | #define TS_USB20_MAX_PACKET_SIZE 512 | 398 | #define TS_USB20_MAX_PACKET_SIZE 512 |
@@ -868,13 +886,13 @@ static int af9015_read_config(struct usb_device *udev) | |||
868 | /* USB1.1 set smaller buffersize and disable 2nd adapter */ | 886 | /* USB1.1 set smaller buffersize and disable 2nd adapter */ |
869 | if (udev->speed == USB_SPEED_FULL) { | 887 | if (udev->speed == USB_SPEED_FULL) { |
870 | af9015_properties[i].adapter[0].stream.u.bulk.buffersize | 888 | af9015_properties[i].adapter[0].stream.u.bulk.buffersize |
871 | = TS_USB11_MAX_PACKET_SIZE; | 889 | = TS_USB11_FRAME_SIZE; |
872 | /* disable 2nd adapter because we don't have | 890 | /* disable 2nd adapter because we don't have |
873 | PID-filters */ | 891 | PID-filters */ |
874 | af9015_config.dual_mode = 0; | 892 | af9015_config.dual_mode = 0; |
875 | } else { | 893 | } else { |
876 | af9015_properties[i].adapter[0].stream.u.bulk.buffersize | 894 | af9015_properties[i].adapter[0].stream.u.bulk.buffersize |
877 | = TS_USB20_MAX_PACKET_SIZE; | 895 | = TS_USB20_FRAME_SIZE; |
878 | } | 896 | } |
879 | } | 897 | } |
880 | 898 | ||
@@ -1310,7 +1328,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { | |||
1310 | .u = { | 1328 | .u = { |
1311 | .bulk = { | 1329 | .bulk = { |
1312 | .buffersize = | 1330 | .buffersize = |
1313 | TS_USB20_MAX_PACKET_SIZE, | 1331 | TS_USB20_FRAME_SIZE, |
1314 | } | 1332 | } |
1315 | } | 1333 | } |
1316 | }, | 1334 | }, |
@@ -1416,7 +1434,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { | |||
1416 | .u = { | 1434 | .u = { |
1417 | .bulk = { | 1435 | .bulk = { |
1418 | .buffersize = | 1436 | .buffersize = |
1419 | TS_USB20_MAX_PACKET_SIZE, | 1437 | TS_USB20_FRAME_SIZE, |
1420 | } | 1438 | } |
1421 | } | 1439 | } |
1422 | }, | 1440 | }, |
@@ -1522,7 +1540,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { | |||
1522 | .u = { | 1540 | .u = { |
1523 | .bulk = { | 1541 | .bulk = { |
1524 | .buffersize = | 1542 | .buffersize = |
1525 | TS_USB20_MAX_PACKET_SIZE, | 1543 | TS_USB20_FRAME_SIZE, |
1526 | } | 1544 | } |
1527 | } | 1545 | } |
1528 | }, | 1546 | }, |
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 7381aff4dcf6..2ae7f648effe 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c | |||
@@ -203,11 +203,11 @@ static struct i2c_algorithm anysee_i2c_algo = { | |||
203 | 203 | ||
204 | static int anysee_mt352_demod_init(struct dvb_frontend *fe) | 204 | static int anysee_mt352_demod_init(struct dvb_frontend *fe) |
205 | { | 205 | { |
206 | static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; | 206 | static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; |
207 | static u8 reset [] = { RESET, 0x80 }; | 207 | static u8 reset[] = { RESET, 0x80 }; |
208 | static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; | 208 | static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; |
209 | static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; | 209 | static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; |
210 | static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; | 210 | static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; |
211 | static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; | 211 | static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; |
212 | 212 | ||
213 | mt352_write(fe, clock_config, sizeof(clock_config)); | 213 | mt352_write(fe, clock_config, sizeof(clock_config)); |
@@ -485,7 +485,7 @@ static int anysee_probe(struct usb_interface *intf, | |||
485 | return ret; | 485 | return ret; |
486 | } | 486 | } |
487 | 487 | ||
488 | static struct usb_device_id anysee_table [] = { | 488 | static struct usb_device_id anysee_table[] = { |
489 | { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, | 489 | { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, |
490 | { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, | 490 | { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, |
491 | { } /* Terminating entry */ | 491 | { } /* Terminating entry */ |
@@ -511,7 +511,7 @@ static struct dvb_usb_device_properties anysee_properties = { | |||
511 | .endpoint = 0x82, | 511 | .endpoint = 0x82, |
512 | .u = { | 512 | .u = { |
513 | .bulk = { | 513 | .bulk = { |
514 | .buffersize = 512, | 514 | .buffersize = (16*512), |
515 | } | 515 | } |
516 | } | 516 | } |
517 | }, | 517 | }, |
diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c index 52badc00e673..0737c6377892 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ b/drivers/media/dvb/dvb-usb/ce6230.c | |||
@@ -274,7 +274,7 @@ static struct dvb_usb_device_properties ce6230_properties = { | |||
274 | .endpoint = 0x82, | 274 | .endpoint = 0x82, |
275 | .u = { | 275 | .u = { |
276 | .bulk = { | 276 | .bulk = { |
277 | .buffersize = 512, | 277 | .buffersize = (16*512), |
278 | } | 278 | } |
279 | } | 279 | } |
280 | }, | 280 | }, |
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index d1d6f4491403..0b2812aa30a4 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c | |||
@@ -4,13 +4,14 @@ | |||
4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
5 | * Software Foundation, version 2. | 5 | * Software Foundation, version 2. |
6 | * | 6 | * |
7 | * Copyright (C) 2005-7 DiBcom, SA | 7 | * Copyright (C) 2005-9 DiBcom, SA et al |
8 | */ | 8 | */ |
9 | #include "dib0700.h" | 9 | #include "dib0700.h" |
10 | 10 | ||
11 | #include "dib3000mc.h" | 11 | #include "dib3000mc.h" |
12 | #include "dib7000m.h" | 12 | #include "dib7000m.h" |
13 | #include "dib7000p.h" | 13 | #include "dib7000p.h" |
14 | #include "dib8000.h" | ||
14 | #include "mt2060.h" | 15 | #include "mt2060.h" |
15 | #include "mt2266.h" | 16 | #include "mt2266.h" |
16 | #include "tuner-xc2028.h" | 17 | #include "tuner-xc2028.h" |
@@ -1098,11 +1099,13 @@ static struct dibx000_agc_config dib7070_agc_config = { | |||
1098 | 1099 | ||
1099 | static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) | 1100 | static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) |
1100 | { | 1101 | { |
1102 | deb_info("reset: %d", onoff); | ||
1101 | return dib7000p_set_gpio(fe, 8, 0, !onoff); | 1103 | return dib7000p_set_gpio(fe, 8, 0, !onoff); |
1102 | } | 1104 | } |
1103 | 1105 | ||
1104 | static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) | 1106 | static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) |
1105 | { | 1107 | { |
1108 | deb_info("sleep: %d", onoff); | ||
1106 | return dib7000p_set_gpio(fe, 9, 0, onoff); | 1109 | return dib7000p_set_gpio(fe, 9, 0, onoff); |
1107 | } | 1110 | } |
1108 | 1111 | ||
@@ -1112,16 +1115,26 @@ static struct dib0070_config dib7070p_dib0070_config[2] = { | |||
1112 | .reset = dib7070_tuner_reset, | 1115 | .reset = dib7070_tuner_reset, |
1113 | .sleep = dib7070_tuner_sleep, | 1116 | .sleep = dib7070_tuner_sleep, |
1114 | .clock_khz = 12000, | 1117 | .clock_khz = 12000, |
1115 | .clock_pad_drive = 4 | 1118 | .clock_pad_drive = 4, |
1119 | .charge_pump = 2, | ||
1116 | }, { | 1120 | }, { |
1117 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, | 1121 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, |
1118 | .reset = dib7070_tuner_reset, | 1122 | .reset = dib7070_tuner_reset, |
1119 | .sleep = dib7070_tuner_sleep, | 1123 | .sleep = dib7070_tuner_sleep, |
1120 | .clock_khz = 12000, | 1124 | .clock_khz = 12000, |
1121 | 1125 | .charge_pump = 2, | |
1122 | } | 1126 | } |
1123 | }; | 1127 | }; |
1124 | 1128 | ||
1129 | static struct dib0070_config dib7770p_dib0070_config = { | ||
1130 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, | ||
1131 | .reset = dib7070_tuner_reset, | ||
1132 | .sleep = dib7070_tuner_sleep, | ||
1133 | .clock_khz = 12000, | ||
1134 | .clock_pad_drive = 0, | ||
1135 | .flip_chip = 1, | ||
1136 | }; | ||
1137 | |||
1125 | static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) | 1138 | static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) |
1126 | { | 1139 | { |
1127 | struct dvb_usb_adapter *adap = fe->dvb->priv; | 1140 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
@@ -1139,6 +1152,45 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_fronte | |||
1139 | return state->set_param_save(fe, fep); | 1152 | return state->set_param_save(fe, fep); |
1140 | } | 1153 | } |
1141 | 1154 | ||
1155 | static int dib7770_set_param_override(struct dvb_frontend *fe, | ||
1156 | struct dvb_frontend_parameters *fep) | ||
1157 | { | ||
1158 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1159 | struct dib0700_adapter_state *state = adap->priv; | ||
1160 | |||
1161 | u16 offset; | ||
1162 | u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); | ||
1163 | switch (band) { | ||
1164 | case BAND_VHF: | ||
1165 | dib7000p_set_gpio(fe, 0, 0, 1); | ||
1166 | offset = 850; | ||
1167 | break; | ||
1168 | case BAND_UHF: | ||
1169 | default: | ||
1170 | dib7000p_set_gpio(fe, 0, 0, 0); | ||
1171 | offset = 250; | ||
1172 | break; | ||
1173 | } | ||
1174 | deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); | ||
1175 | dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); | ||
1176 | return state->set_param_save(fe, fep); | ||
1177 | } | ||
1178 | |||
1179 | static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) | ||
1180 | { | ||
1181 | struct dib0700_adapter_state *st = adap->priv; | ||
1182 | struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, | ||
1183 | DIBX000_I2C_INTERFACE_TUNER, 1); | ||
1184 | |||
1185 | if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, | ||
1186 | &dib7770p_dib0070_config) == NULL) | ||
1187 | return -ENODEV; | ||
1188 | |||
1189 | st->set_param_save = adap->fe->ops.tuner_ops.set_params; | ||
1190 | adap->fe->ops.tuner_ops.set_params = dib7770_set_param_override; | ||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1142 | static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) | 1194 | static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) |
1143 | { | 1195 | { |
1144 | struct dib0700_adapter_state *st = adap->priv; | 1196 | struct dib0700_adapter_state *st = adap->priv; |
@@ -1217,6 +1269,306 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) | |||
1217 | return adap->fe == NULL ? -ENODEV : 0; | 1269 | return adap->fe == NULL ? -ENODEV : 0; |
1218 | } | 1270 | } |
1219 | 1271 | ||
1272 | /* DIB807x generic */ | ||
1273 | static struct dibx000_agc_config dib807x_agc_config[2] = { | ||
1274 | { | ||
1275 | BAND_VHF, | ||
1276 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, | ||
1277 | * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, | ||
1278 | * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0, | ||
1279 | * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, | ||
1280 | * P_agc_write=0 */ | ||
1281 | (0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) | | ||
1282 | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | | ||
1283 | (0 << 0), /* setup*/ | ||
1284 | |||
1285 | 600, /* inv_gain*/ | ||
1286 | 10, /* time_stabiliz*/ | ||
1287 | |||
1288 | 0, /* alpha_level*/ | ||
1289 | 118, /* thlock*/ | ||
1290 | |||
1291 | 0, /* wbd_inv*/ | ||
1292 | 3530, /* wbd_ref*/ | ||
1293 | 1, /* wbd_sel*/ | ||
1294 | 5, /* wbd_alpha*/ | ||
1295 | |||
1296 | 65535, /* agc1_max*/ | ||
1297 | 0, /* agc1_min*/ | ||
1298 | |||
1299 | 65535, /* agc2_max*/ | ||
1300 | 0, /* agc2_min*/ | ||
1301 | |||
1302 | 0, /* agc1_pt1*/ | ||
1303 | 40, /* agc1_pt2*/ | ||
1304 | 183, /* agc1_pt3*/ | ||
1305 | 206, /* agc1_slope1*/ | ||
1306 | 255, /* agc1_slope2*/ | ||
1307 | 72, /* agc2_pt1*/ | ||
1308 | 152, /* agc2_pt2*/ | ||
1309 | 88, /* agc2_slope1*/ | ||
1310 | 90, /* agc2_slope2*/ | ||
1311 | |||
1312 | 17, /* alpha_mant*/ | ||
1313 | 27, /* alpha_exp*/ | ||
1314 | 23, /* beta_mant*/ | ||
1315 | 51, /* beta_exp*/ | ||
1316 | |||
1317 | 0, /* perform_agc_softsplit*/ | ||
1318 | }, { | ||
1319 | BAND_UHF, | ||
1320 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, | ||
1321 | * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, | ||
1322 | * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, | ||
1323 | * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, | ||
1324 | * P_agc_write=0 */ | ||
1325 | (0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) | | ||
1326 | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | | ||
1327 | (0 << 0), /* setup */ | ||
1328 | |||
1329 | 600, /* inv_gain*/ | ||
1330 | 10, /* time_stabiliz*/ | ||
1331 | |||
1332 | 0, /* alpha_level*/ | ||
1333 | 118, /* thlock*/ | ||
1334 | |||
1335 | 0, /* wbd_inv*/ | ||
1336 | 3530, /* wbd_ref*/ | ||
1337 | 1, /* wbd_sel*/ | ||
1338 | 5, /* wbd_alpha*/ | ||
1339 | |||
1340 | 65535, /* agc1_max*/ | ||
1341 | 0, /* agc1_min*/ | ||
1342 | |||
1343 | 65535, /* agc2_max*/ | ||
1344 | 0, /* agc2_min*/ | ||
1345 | |||
1346 | 0, /* agc1_pt1*/ | ||
1347 | 40, /* agc1_pt2*/ | ||
1348 | 183, /* agc1_pt3*/ | ||
1349 | 206, /* agc1_slope1*/ | ||
1350 | 255, /* agc1_slope2*/ | ||
1351 | 72, /* agc2_pt1*/ | ||
1352 | 152, /* agc2_pt2*/ | ||
1353 | 88, /* agc2_slope1*/ | ||
1354 | 90, /* agc2_slope2*/ | ||
1355 | |||
1356 | 17, /* alpha_mant*/ | ||
1357 | 27, /* alpha_exp*/ | ||
1358 | 23, /* beta_mant*/ | ||
1359 | 51, /* beta_exp*/ | ||
1360 | |||
1361 | 0, /* perform_agc_softsplit*/ | ||
1362 | } | ||
1363 | }; | ||
1364 | |||
1365 | static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = { | ||
1366 | 60000, 15000, /* internal, sampling*/ | ||
1367 | 1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/ | ||
1368 | 0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core, | ||
1369 | ADClkSrc, modulo */ | ||
1370 | (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/ | ||
1371 | (0 << 25) | 0, /* ifreq = 0.000000 MHz*/ | ||
1372 | 18179755, /* timf*/ | ||
1373 | 12000000, /* xtal_hz*/ | ||
1374 | }; | ||
1375 | |||
1376 | static struct dib8000_config dib807x_dib8000_config[2] = { | ||
1377 | { | ||
1378 | .output_mpeg2_in_188_bytes = 1, | ||
1379 | |||
1380 | .agc_config_count = 2, | ||
1381 | .agc = dib807x_agc_config, | ||
1382 | .pll = &dib807x_bw_config_12_mhz, | ||
1383 | .tuner_is_baseband = 1, | ||
1384 | |||
1385 | .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, | ||
1386 | .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, | ||
1387 | .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, | ||
1388 | |||
1389 | .hostbus_diversity = 1, | ||
1390 | .div_cfg = 1, | ||
1391 | .agc_control = &dib0070_ctrl_agc_filter, | ||
1392 | .output_mode = OUTMODE_MPEG2_FIFO, | ||
1393 | .drives = 0x2d98, | ||
1394 | }, { | ||
1395 | .output_mpeg2_in_188_bytes = 1, | ||
1396 | |||
1397 | .agc_config_count = 2, | ||
1398 | .agc = dib807x_agc_config, | ||
1399 | .pll = &dib807x_bw_config_12_mhz, | ||
1400 | .tuner_is_baseband = 1, | ||
1401 | |||
1402 | .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, | ||
1403 | .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, | ||
1404 | .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, | ||
1405 | |||
1406 | .hostbus_diversity = 1, | ||
1407 | .agc_control = &dib0070_ctrl_agc_filter, | ||
1408 | .output_mode = OUTMODE_MPEG2_FIFO, | ||
1409 | .drives = 0x2d98, | ||
1410 | } | ||
1411 | }; | ||
1412 | |||
1413 | static int dib807x_tuner_reset(struct dvb_frontend *fe, int onoff) | ||
1414 | { | ||
1415 | return dib8000_set_gpio(fe, 5, 0, !onoff); | ||
1416 | } | ||
1417 | |||
1418 | static int dib807x_tuner_sleep(struct dvb_frontend *fe, int onoff) | ||
1419 | { | ||
1420 | return dib8000_set_gpio(fe, 0, 0, onoff); | ||
1421 | } | ||
1422 | |||
1423 | static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { | ||
1424 | { 240, 7}, | ||
1425 | { 0xffff, 6}, | ||
1426 | }; | ||
1427 | |||
1428 | static struct dib0070_config dib807x_dib0070_config[2] = { | ||
1429 | { | ||
1430 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, | ||
1431 | .reset = dib807x_tuner_reset, | ||
1432 | .sleep = dib807x_tuner_sleep, | ||
1433 | .clock_khz = 12000, | ||
1434 | .clock_pad_drive = 4, | ||
1435 | .vga_filter = 1, | ||
1436 | .force_crystal_mode = 1, | ||
1437 | .enable_third_order_filter = 1, | ||
1438 | .charge_pump = 0, | ||
1439 | .wbd_gain = dib8070_wbd_gain_cfg, | ||
1440 | .osc_buffer_state = 0, | ||
1441 | .freq_offset_khz_uhf = -100, | ||
1442 | .freq_offset_khz_vhf = -100, | ||
1443 | }, { | ||
1444 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, | ||
1445 | .reset = dib807x_tuner_reset, | ||
1446 | .sleep = dib807x_tuner_sleep, | ||
1447 | .clock_khz = 12000, | ||
1448 | .clock_pad_drive = 2, | ||
1449 | .vga_filter = 1, | ||
1450 | .force_crystal_mode = 1, | ||
1451 | .enable_third_order_filter = 1, | ||
1452 | .charge_pump = 0, | ||
1453 | .wbd_gain = dib8070_wbd_gain_cfg, | ||
1454 | .osc_buffer_state = 0, | ||
1455 | .freq_offset_khz_uhf = -25, | ||
1456 | .freq_offset_khz_vhf = -25, | ||
1457 | } | ||
1458 | }; | ||
1459 | |||
1460 | static int dib807x_set_param_override(struct dvb_frontend *fe, | ||
1461 | struct dvb_frontend_parameters *fep) | ||
1462 | { | ||
1463 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1464 | struct dib0700_adapter_state *state = adap->priv; | ||
1465 | |||
1466 | u16 offset = dib0070_wbd_offset(fe); | ||
1467 | u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); | ||
1468 | switch (band) { | ||
1469 | case BAND_VHF: | ||
1470 | offset += 750; | ||
1471 | break; | ||
1472 | case BAND_UHF: /* fall-thru wanted */ | ||
1473 | default: | ||
1474 | offset += 250; break; | ||
1475 | } | ||
1476 | deb_info("WBD for DiB8000: %d\n", offset); | ||
1477 | dib8000_set_wbd_ref(fe, offset); | ||
1478 | |||
1479 | return state->set_param_save(fe, fep); | ||
1480 | } | ||
1481 | |||
1482 | static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) | ||
1483 | { | ||
1484 | struct dib0700_adapter_state *st = adap->priv; | ||
1485 | struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, | ||
1486 | DIBX000_I2C_INTERFACE_TUNER, 1); | ||
1487 | |||
1488 | if (adap->id == 0) { | ||
1489 | if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, | ||
1490 | &dib807x_dib0070_config[0]) == NULL) | ||
1491 | return -ENODEV; | ||
1492 | } else { | ||
1493 | if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, | ||
1494 | &dib807x_dib0070_config[1]) == NULL) | ||
1495 | return -ENODEV; | ||
1496 | } | ||
1497 | |||
1498 | st->set_param_save = adap->fe->ops.tuner_ops.set_params; | ||
1499 | adap->fe->ops.tuner_ops.set_params = dib807x_set_param_override; | ||
1500 | return 0; | ||
1501 | } | ||
1502 | |||
1503 | |||
1504 | /* STK807x */ | ||
1505 | static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) | ||
1506 | { | ||
1507 | dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); | ||
1508 | msleep(10); | ||
1509 | dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); | ||
1510 | dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); | ||
1511 | dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); | ||
1512 | |||
1513 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); | ||
1514 | |||
1515 | dib0700_ctrl_clock(adap->dev, 72, 1); | ||
1516 | |||
1517 | msleep(10); | ||
1518 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); | ||
1519 | msleep(10); | ||
1520 | dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); | ||
1521 | |||
1522 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, | ||
1523 | 0x80); | ||
1524 | |||
1525 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, | ||
1526 | &dib807x_dib8000_config[0]); | ||
1527 | |||
1528 | return adap->fe == NULL ? -ENODEV : 0; | ||
1529 | } | ||
1530 | |||
1531 | /* STK807xPVR */ | ||
1532 | static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) | ||
1533 | { | ||
1534 | dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); | ||
1535 | msleep(30); | ||
1536 | dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); | ||
1537 | msleep(500); | ||
1538 | dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); | ||
1539 | dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); | ||
1540 | dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); | ||
1541 | |||
1542 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); | ||
1543 | |||
1544 | dib0700_ctrl_clock(adap->dev, 72, 1); | ||
1545 | |||
1546 | msleep(10); | ||
1547 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); | ||
1548 | msleep(10); | ||
1549 | dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); | ||
1550 | |||
1551 | /* initialize IC 0 */ | ||
1552 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x80); | ||
1553 | |||
1554 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, | ||
1555 | &dib807x_dib8000_config[0]); | ||
1556 | |||
1557 | return adap->fe == NULL ? -ENODEV : 0; | ||
1558 | } | ||
1559 | |||
1560 | static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) | ||
1561 | { | ||
1562 | /* initialize IC 1 */ | ||
1563 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x82); | ||
1564 | |||
1565 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, | ||
1566 | &dib807x_dib8000_config[1]); | ||
1567 | |||
1568 | return adap->fe == NULL ? -ENODEV : 0; | ||
1569 | } | ||
1570 | |||
1571 | |||
1220 | /* STK7070PD */ | 1572 | /* STK7070PD */ |
1221 | static struct dib7000p_config stk7070pd_dib7000p_config[2] = { | 1573 | static struct dib7000p_config stk7070pd_dib7000p_config[2] = { |
1222 | { | 1574 | { |
@@ -1500,7 +1852,15 @@ struct usb_device_id dib0700_usb_id_table[] = { | |||
1500 | { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, | 1852 | { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, |
1501 | { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, | 1853 | { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, |
1502 | { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, | 1854 | { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, |
1503 | { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, | 1855 | /* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, |
1856 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, | ||
1857 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, | ||
1858 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, | ||
1859 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, | ||
1860 | /* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, | ||
1861 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, | ||
1862 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, | ||
1863 | { USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) }, | ||
1504 | { 0 } /* Terminating entry */ | 1864 | { 0 } /* Terminating entry */ |
1505 | }; | 1865 | }; |
1506 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); | 1866 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); |
@@ -1565,7 +1925,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
1565 | { NULL }, | 1925 | { NULL }, |
1566 | }, | 1926 | }, |
1567 | { "Leadtek Winfast DTV Dongle (STK7700P based)", | 1927 | { "Leadtek Winfast DTV Dongle (STK7700P based)", |
1568 | { &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] }, | 1928 | { &dib0700_usb_id_table[8] }, |
1569 | { NULL }, | 1929 | { NULL }, |
1570 | }, | 1930 | }, |
1571 | { "AVerMedia AVerTV DVB-T Express", | 1931 | { "AVerMedia AVerTV DVB-T Express", |
@@ -1764,6 +2124,41 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
1764 | 2124 | ||
1765 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | 2125 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, |
1766 | 2126 | ||
2127 | .num_adapters = 1, | ||
2128 | .adapter = { | ||
2129 | { | ||
2130 | .frontend_attach = stk7070p_frontend_attach, | ||
2131 | .tuner_attach = dib7070p_tuner_attach, | ||
2132 | |||
2133 | DIB0700_DEFAULT_STREAMING_CONFIG(0x02), | ||
2134 | |||
2135 | .size_of_priv = sizeof(struct dib0700_adapter_state), | ||
2136 | }, | ||
2137 | }, | ||
2138 | |||
2139 | .num_device_descs = 3, | ||
2140 | .devices = { | ||
2141 | { "Pinnacle PCTV 73A", | ||
2142 | { &dib0700_usb_id_table[56], NULL }, | ||
2143 | { NULL }, | ||
2144 | }, | ||
2145 | { "Pinnacle PCTV 73e SE", | ||
2146 | { &dib0700_usb_id_table[57], NULL }, | ||
2147 | { NULL }, | ||
2148 | }, | ||
2149 | { "Pinnacle PCTV 282e", | ||
2150 | { &dib0700_usb_id_table[58], NULL }, | ||
2151 | { NULL }, | ||
2152 | }, | ||
2153 | }, | ||
2154 | |||
2155 | .rc_interval = DEFAULT_RC_INTERVAL, | ||
2156 | .rc_key_map = dib0700_rc_keys, | ||
2157 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | ||
2158 | .rc_query = dib0700_rc_query | ||
2159 | |||
2160 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | ||
2161 | |||
1767 | .num_adapters = 2, | 2162 | .num_adapters = 2, |
1768 | .adapter = { | 2163 | .adapter = { |
1769 | { | 2164 | { |
@@ -1927,6 +2322,102 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
1927 | { NULL }, | 2322 | { NULL }, |
1928 | }, | 2323 | }, |
1929 | }, | 2324 | }, |
2325 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | ||
2326 | |||
2327 | .num_adapters = 1, | ||
2328 | .adapter = { | ||
2329 | { | ||
2330 | .frontend_attach = stk7070p_frontend_attach, | ||
2331 | .tuner_attach = dib7770p_tuner_attach, | ||
2332 | |||
2333 | DIB0700_DEFAULT_STREAMING_CONFIG(0x02), | ||
2334 | |||
2335 | .size_of_priv = | ||
2336 | sizeof(struct dib0700_adapter_state), | ||
2337 | }, | ||
2338 | }, | ||
2339 | |||
2340 | .num_device_descs = 2, | ||
2341 | .devices = { | ||
2342 | { "DiBcom STK7770P reference design", | ||
2343 | { &dib0700_usb_id_table[59], NULL }, | ||
2344 | { NULL }, | ||
2345 | }, | ||
2346 | { "Terratec Cinergy T USB XXS (HD)", | ||
2347 | { &dib0700_usb_id_table[34], &dib0700_usb_id_table[60] }, | ||
2348 | { NULL }, | ||
2349 | }, | ||
2350 | }, | ||
2351 | .rc_interval = DEFAULT_RC_INTERVAL, | ||
2352 | .rc_key_map = dib0700_rc_keys, | ||
2353 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | ||
2354 | .rc_query = dib0700_rc_query | ||
2355 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | ||
2356 | .num_adapters = 1, | ||
2357 | .adapter = { | ||
2358 | { | ||
2359 | .frontend_attach = stk807x_frontend_attach, | ||
2360 | .tuner_attach = dib807x_tuner_attach, | ||
2361 | |||
2362 | DIB0700_DEFAULT_STREAMING_CONFIG(0x02), | ||
2363 | |||
2364 | .size_of_priv = | ||
2365 | sizeof(struct dib0700_adapter_state), | ||
2366 | }, | ||
2367 | }, | ||
2368 | |||
2369 | .num_device_descs = 2, | ||
2370 | .devices = { | ||
2371 | { "DiBcom STK807xP reference design", | ||
2372 | { &dib0700_usb_id_table[62], NULL }, | ||
2373 | { NULL }, | ||
2374 | }, | ||
2375 | { "Prolink Pixelview SBTVD", | ||
2376 | { &dib0700_usb_id_table[63], NULL }, | ||
2377 | { NULL }, | ||
2378 | }, | ||
2379 | }, | ||
2380 | |||
2381 | .rc_interval = DEFAULT_RC_INTERVAL, | ||
2382 | .rc_key_map = dib0700_rc_keys, | ||
2383 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | ||
2384 | .rc_query = dib0700_rc_query | ||
2385 | |||
2386 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | ||
2387 | .num_adapters = 2, | ||
2388 | .adapter = { | ||
2389 | { | ||
2390 | .frontend_attach = stk807xpvr_frontend_attach0, | ||
2391 | .tuner_attach = dib807x_tuner_attach, | ||
2392 | |||
2393 | DIB0700_DEFAULT_STREAMING_CONFIG(0x02), | ||
2394 | |||
2395 | .size_of_priv = | ||
2396 | sizeof(struct dib0700_adapter_state), | ||
2397 | }, | ||
2398 | { | ||
2399 | .frontend_attach = stk807xpvr_frontend_attach1, | ||
2400 | .tuner_attach = dib807x_tuner_attach, | ||
2401 | |||
2402 | DIB0700_DEFAULT_STREAMING_CONFIG(0x03), | ||
2403 | |||
2404 | .size_of_priv = | ||
2405 | sizeof(struct dib0700_adapter_state), | ||
2406 | }, | ||
2407 | }, | ||
2408 | |||
2409 | .num_device_descs = 1, | ||
2410 | .devices = { | ||
2411 | { "DiBcom STK807xPVR reference design", | ||
2412 | { &dib0700_usb_id_table[61], NULL }, | ||
2413 | { NULL }, | ||
2414 | }, | ||
2415 | }, | ||
2416 | |||
2417 | .rc_interval = DEFAULT_RC_INTERVAL, | ||
2418 | .rc_key_map = dib0700_rc_keys, | ||
2419 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | ||
2420 | .rc_query = dib0700_rc_query | ||
1930 | }, | 2421 | }, |
1931 | }; | 2422 | }; |
1932 | 2423 | ||
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 185a5069b10b..a548c14c1944 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
@@ -46,6 +46,7 @@ | |||
46 | #define USB_VID_MSI_2 0x1462 | 46 | #define USB_VID_MSI_2 0x1462 |
47 | #define USB_VID_OPERA1 0x695c | 47 | #define USB_VID_OPERA1 0x695c |
48 | #define USB_VID_PINNACLE 0x2304 | 48 | #define USB_VID_PINNACLE 0x2304 |
49 | #define USB_VID_PIXELVIEW 0x1554 | ||
49 | #define USB_VID_TECHNOTREND 0x0b48 | 50 | #define USB_VID_TECHNOTREND 0x0b48 |
50 | #define USB_VID_TERRATEC 0x0ccd | 51 | #define USB_VID_TERRATEC 0x0ccd |
51 | #define USB_VID_TELESTAR 0x10b9 | 52 | #define USB_VID_TELESTAR 0x10b9 |
@@ -59,6 +60,7 @@ | |||
59 | #define USB_VID_YUAN 0x1164 | 60 | #define USB_VID_YUAN 0x1164 |
60 | #define USB_VID_XTENSIONS 0x1ae7 | 61 | #define USB_VID_XTENSIONS 0x1ae7 |
61 | #define USB_VID_HUMAX_COEX 0x10b9 | 62 | #define USB_VID_HUMAX_COEX 0x10b9 |
63 | #define USB_VID_774 0x7a69 | ||
62 | 64 | ||
63 | /* Product IDs */ | 65 | /* Product IDs */ |
64 | #define USB_PID_ADSTECH_USB2_COLD 0xa333 | 66 | #define USB_PID_ADSTECH_USB2_COLD 0xa333 |
@@ -95,7 +97,10 @@ | |||
95 | #define USB_PID_DIBCOM_STK7700_U7000 0x7001 | 97 | #define USB_PID_DIBCOM_STK7700_U7000 0x7001 |
96 | #define USB_PID_DIBCOM_STK7070P 0x1ebc | 98 | #define USB_PID_DIBCOM_STK7070P 0x1ebc |
97 | #define USB_PID_DIBCOM_STK7070PD 0x1ebe | 99 | #define USB_PID_DIBCOM_STK7070PD 0x1ebe |
100 | #define USB_PID_DIBCOM_STK807XP 0x1f90 | ||
101 | #define USB_PID_DIBCOM_STK807XPVR 0x1f98 | ||
98 | #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 | 102 | #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 |
103 | #define USB_PID_DIBCOM_STK7770P 0x1e80 | ||
99 | #define USB_PID_DPOSH_M9206_COLD 0x9206 | 104 | #define USB_PID_DPOSH_M9206_COLD 0x9206 |
100 | #define USB_PID_DPOSH_M9206_WARM 0xa090 | 105 | #define USB_PID_DPOSH_M9206_WARM 0xa090 |
101 | #define USB_PID_UNIWILL_STK7700P 0x6003 | 106 | #define USB_PID_UNIWILL_STK7700P 0x6003 |
@@ -184,6 +189,7 @@ | |||
184 | #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 | 189 | #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 |
185 | #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 | 190 | #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 |
186 | #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 | 191 | #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 |
192 | #define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab | ||
187 | #define USB_PID_TERRATEC_T3 0x10a0 | 193 | #define USB_PID_TERRATEC_T3 0x10a0 |
188 | #define USB_PID_TERRATEC_T5 0x10a1 | 194 | #define USB_PID_TERRATEC_T5 0x10a1 |
189 | #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e | 195 | #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e |
@@ -195,6 +201,10 @@ | |||
195 | #define USB_PID_PINNACLE_PCTV73E 0x0237 | 201 | #define USB_PID_PINNACLE_PCTV73E 0x0237 |
196 | #define USB_PID_PINNACLE_PCTV801E 0x023a | 202 | #define USB_PID_PINNACLE_PCTV801E 0x023a |
197 | #define USB_PID_PINNACLE_PCTV801E_SE 0x023b | 203 | #define USB_PID_PINNACLE_PCTV801E_SE 0x023b |
204 | #define USB_PID_PINNACLE_PCTV73A 0x0243 | ||
205 | #define USB_PID_PINNACLE_PCTV73ESE 0x0245 | ||
206 | #define USB_PID_PINNACLE_PCTV282E 0x0248 | ||
207 | #define USB_PID_PIXELVIEW_SBTVD 0x5010 | ||
198 | #define USB_PID_PCTV_200E 0x020e | 208 | #define USB_PID_PCTV_200E 0x020e |
199 | #define USB_PID_PCTV_400E 0x020f | 209 | #define USB_PID_PCTV_400E 0x020f |
200 | #define USB_PID_PCTV_450E 0x0222 | 210 | #define USB_PID_PCTV_450E 0x0222 |
@@ -265,5 +275,6 @@ | |||
265 | #define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 | 275 | #define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 |
266 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 | 276 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 |
267 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 | 277 | #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 |
278 | #define USB_PID_FRIIO_WHITE 0x0001 | ||
268 | 279 | ||
269 | #endif | 280 | #endif |
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c new file mode 100644 index 000000000000..c4dfe25cf60d --- /dev/null +++ b/drivers/media/dvb/dvb-usb/friio-fe.c | |||
@@ -0,0 +1,483 @@ | |||
1 | /* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. | ||
2 | * | ||
3 | * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp> | ||
4 | * | ||
5 | * This module is based off the the gl861 and vp702x modules. | ||
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 Free | ||
9 | * Software Foundation, version 2. | ||
10 | * | ||
11 | * see Documentation/dvb/README.dvb-usb for more information | ||
12 | */ | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include "friio.h" | ||
18 | |||
19 | struct jdvbt90502_state { | ||
20 | struct i2c_adapter *i2c; | ||
21 | struct dvb_frontend frontend; | ||
22 | struct jdvbt90502_config config; | ||
23 | }; | ||
24 | |||
25 | /* NOTE: TC90502 has 16bit register-address? */ | ||
26 | /* register 0x0100 is used for reading PLL status, so reg is u16 here */ | ||
27 | static int jdvbt90502_reg_read(struct jdvbt90502_state *state, | ||
28 | const u16 reg, u8 *buf, const size_t count) | ||
29 | { | ||
30 | int ret; | ||
31 | u8 wbuf[3]; | ||
32 | struct i2c_msg msg[2]; | ||
33 | |||
34 | wbuf[0] = reg & 0xFF; | ||
35 | wbuf[1] = 0; | ||
36 | wbuf[2] = reg >> 8; | ||
37 | |||
38 | msg[0].addr = state->config.demod_address; | ||
39 | msg[0].flags = 0; | ||
40 | msg[0].buf = wbuf; | ||
41 | msg[0].len = sizeof(wbuf); | ||
42 | |||
43 | msg[1].addr = msg[0].addr; | ||
44 | msg[1].flags = I2C_M_RD; | ||
45 | msg[1].buf = buf; | ||
46 | msg[1].len = count; | ||
47 | |||
48 | ret = i2c_transfer(state->i2c, msg, 2); | ||
49 | if (ret != 2) { | ||
50 | deb_fe(" reg read failed.\n"); | ||
51 | return -EREMOTEIO; | ||
52 | } | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | /* currently 16bit register-address is not used, so reg is u8 here */ | ||
57 | static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state, | ||
58 | const u8 reg, const u8 val) | ||
59 | { | ||
60 | struct i2c_msg msg; | ||
61 | u8 wbuf[2]; | ||
62 | |||
63 | wbuf[0] = reg; | ||
64 | wbuf[1] = val; | ||
65 | |||
66 | msg.addr = state->config.demod_address; | ||
67 | msg.flags = 0; | ||
68 | msg.buf = wbuf; | ||
69 | msg.len = sizeof(wbuf); | ||
70 | |||
71 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
72 | deb_fe(" reg write failed."); | ||
73 | return -EREMOTEIO; | ||
74 | } | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int _jdvbt90502_write(struct dvb_frontend *fe, u8 *buf, int len) | ||
79 | { | ||
80 | struct jdvbt90502_state *state = fe->demodulator_priv; | ||
81 | int err, i; | ||
82 | for (i = 0; i < len - 1; i++) { | ||
83 | err = jdvbt90502_single_reg_write(state, | ||
84 | buf[0] + i, buf[i + 1]); | ||
85 | if (err) | ||
86 | return err; | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | /* read pll status byte via the demodulator's I2C register */ | ||
93 | /* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */ | ||
94 | static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result) | ||
95 | { | ||
96 | int ret; | ||
97 | |||
98 | /* +1 for reading */ | ||
99 | u8 pll_addr_byte = (state->config.pll_address << 1) + 1; | ||
100 | |||
101 | *result = 0; | ||
102 | |||
103 | ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG, | ||
104 | pll_addr_byte); | ||
105 | if (ret) | ||
106 | goto error; | ||
107 | |||
108 | ret = jdvbt90502_reg_read(state, 0x0100, result, 1); | ||
109 | if (ret) | ||
110 | goto error; | ||
111 | |||
112 | deb_fe("PLL read val:%02x\n", *result); | ||
113 | return 0; | ||
114 | |||
115 | error: | ||
116 | deb_fe("%s:ret == %d\n", __func__, ret); | ||
117 | return -EREMOTEIO; | ||
118 | } | ||
119 | |||
120 | |||
121 | /* set pll frequency via the demodulator's I2C register */ | ||
122 | static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq) | ||
123 | { | ||
124 | int ret; | ||
125 | int retry; | ||
126 | u8 res1; | ||
127 | u8 res2[9]; | ||
128 | |||
129 | u8 pll_freq_cmd[PLL_CMD_LEN]; | ||
130 | u8 pll_agc_cmd[PLL_CMD_LEN]; | ||
131 | struct i2c_msg msg[2]; | ||
132 | u32 f; | ||
133 | |||
134 | deb_fe("%s: freq=%d, step=%d\n", __func__, freq, | ||
135 | state->frontend.ops.info.frequency_stepsize); | ||
136 | /* freq -> oscilator frequency conversion. */ | ||
137 | /* freq: 473,000,000 + n*6,000,000 (no 1/7MHz shift to center freq) */ | ||
138 | /* add 400[1/7 MHZ] = 57.142857MHz. 57MHz for the IF, */ | ||
139 | /* 1/7MHz for center freq shift */ | ||
140 | f = freq / state->frontend.ops.info.frequency_stepsize; | ||
141 | f += 400; | ||
142 | pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */ | ||
143 | pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1; | ||
144 | pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F; | ||
145 | pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF; | ||
146 | pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */ | ||
147 | pll_freq_cmd[BANDSWITCH_BYTE] = 0x08; /* UHF band */ | ||
148 | |||
149 | msg[0].addr = state->config.demod_address; | ||
150 | msg[0].flags = 0; | ||
151 | msg[0].buf = pll_freq_cmd; | ||
152 | msg[0].len = sizeof(pll_freq_cmd); | ||
153 | |||
154 | ret = i2c_transfer(state->i2c, &msg[0], 1); | ||
155 | if (ret != 1) | ||
156 | goto error; | ||
157 | |||
158 | udelay(50); | ||
159 | |||
160 | pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG]; | ||
161 | pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE]; | ||
162 | pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1]; | ||
163 | pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2]; | ||
164 | pll_agc_cmd[CONTROL_BYTE] = 0x9A; /* AGC_CTRL instead of BANDSWITCH */ | ||
165 | pll_agc_cmd[AGC_CTRL_BYTE] = 0x50; | ||
166 | /* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */ | ||
167 | |||
168 | msg[1].addr = msg[0].addr; | ||
169 | msg[1].flags = 0; | ||
170 | msg[1].buf = pll_agc_cmd; | ||
171 | msg[1].len = sizeof(pll_agc_cmd); | ||
172 | |||
173 | ret = i2c_transfer(state->i2c, &msg[1], 1); | ||
174 | if (ret != 1) | ||
175 | goto error; | ||
176 | |||
177 | /* I don't know what these cmds are for, */ | ||
178 | /* but the USB log on a windows box contains them */ | ||
179 | ret = jdvbt90502_single_reg_write(state, 0x01, 0x40); | ||
180 | ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00); | ||
181 | if (ret) | ||
182 | goto error; | ||
183 | udelay(100); | ||
184 | |||
185 | /* wait for the demod to be ready? */ | ||
186 | #define RETRY_COUNT 5 | ||
187 | for (retry = 0; retry < RETRY_COUNT; retry++) { | ||
188 | ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1); | ||
189 | if (ret) | ||
190 | goto error; | ||
191 | /* if (res1 != 0x00) goto error; */ | ||
192 | ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2)); | ||
193 | if (ret) | ||
194 | goto error; | ||
195 | if (res2[0] >= 0xA7) | ||
196 | break; | ||
197 | msleep(100); | ||
198 | } | ||
199 | if (retry >= RETRY_COUNT) { | ||
200 | deb_fe("%s: FE does not get ready after freq setting.\n", | ||
201 | __func__); | ||
202 | return -EREMOTEIO; | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | error: | ||
207 | deb_fe("%s:ret == %d\n", __func__, ret); | ||
208 | return -EREMOTEIO; | ||
209 | } | ||
210 | |||
211 | static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state) | ||
212 | { | ||
213 | u8 result; | ||
214 | int ret; | ||
215 | |||
216 | *state = FE_HAS_SIGNAL; | ||
217 | |||
218 | ret = jdvbt90502_pll_read(fe->demodulator_priv, &result); | ||
219 | if (ret) { | ||
220 | deb_fe("%s:ret == %d\n", __func__, ret); | ||
221 | return -EREMOTEIO; | ||
222 | } | ||
223 | |||
224 | *state = FE_HAS_SIGNAL | ||
225 | | FE_HAS_CARRIER | ||
226 | | FE_HAS_VITERBI | ||
227 | | FE_HAS_SYNC; | ||
228 | |||
229 | if (result & PLL_STATUS_LOCKED) | ||
230 | *state |= FE_HAS_LOCK; | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int jdvbt90502_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
236 | { | ||
237 | *ber = 0; | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe, | ||
242 | u16 *strength) | ||
243 | { | ||
244 | int ret; | ||
245 | u8 rbuf[37]; | ||
246 | |||
247 | *strength = 0; | ||
248 | |||
249 | /* status register (incl. signal strength) : 0x89 */ | ||
250 | /* TODO: read just the necessary registers [0x8B..0x8D]? */ | ||
251 | ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089, | ||
252 | rbuf, sizeof(rbuf)); | ||
253 | |||
254 | if (ret) { | ||
255 | deb_fe("%s:ret == %d\n", __func__, ret); | ||
256 | return -EREMOTEIO; | ||
257 | } | ||
258 | |||
259 | /* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */ | ||
260 | *strength = (rbuf[3] << 8) + rbuf[4]; | ||
261 | if (rbuf[2]) | ||
262 | *strength = 0xffff; | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int jdvbt90502_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
268 | { | ||
269 | *snr = 0x0101; | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int jdvbt90502_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
274 | { | ||
275 | *ucblocks = 0; | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int jdvbt90502_get_tune_settings(struct dvb_frontend *fe, | ||
280 | struct dvb_frontend_tune_settings *fs) | ||
281 | { | ||
282 | fs->min_delay_ms = 500; | ||
283 | fs->step_size = 0; | ||
284 | fs->max_drift = 0; | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int jdvbt90502_get_frontend(struct dvb_frontend *fe, | ||
290 | struct dvb_frontend_parameters *p) | ||
291 | { | ||
292 | p->inversion = INVERSION_AUTO; | ||
293 | p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
294 | p->u.ofdm.code_rate_HP = FEC_AUTO; | ||
295 | p->u.ofdm.code_rate_LP = FEC_AUTO; | ||
296 | p->u.ofdm.constellation = QAM_64; | ||
297 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; | ||
298 | p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; | ||
299 | p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int jdvbt90502_set_frontend(struct dvb_frontend *fe, | ||
304 | struct dvb_frontend_parameters *p) | ||
305 | { | ||
306 | /** | ||
307 | * NOTE: ignore all the paramters except frequency. | ||
308 | * others should be fixed to the proper value for ISDB-T, | ||
309 | * but don't check here. | ||
310 | */ | ||
311 | |||
312 | struct jdvbt90502_state *state = fe->demodulator_priv; | ||
313 | int ret; | ||
314 | |||
315 | deb_fe("%s: Freq:%d\n", __func__, p->frequency); | ||
316 | |||
317 | ret = jdvbt90502_pll_set_freq(state, p->frequency); | ||
318 | if (ret) { | ||
319 | deb_fe("%s:ret == %d\n", __func__, ret); | ||
320 | return -EREMOTEIO; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int jdvbt90502_sleep(struct dvb_frontend *fe) | ||
327 | { | ||
328 | deb_fe("%s called.\n", __func__); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * (reg, val) commad list to initialize this module. | ||
335 | * captured on a Windows box. | ||
336 | */ | ||
337 | static u8 init_code[][2] = { | ||
338 | {0x01, 0x40}, | ||
339 | {0x04, 0x38}, | ||
340 | {0x05, 0x40}, | ||
341 | {0x07, 0x40}, | ||
342 | {0x0F, 0x4F}, | ||
343 | {0x11, 0x21}, | ||
344 | {0x12, 0x0B}, | ||
345 | {0x13, 0x2F}, | ||
346 | {0x14, 0x31}, | ||
347 | {0x16, 0x02}, | ||
348 | {0x21, 0xC4}, | ||
349 | {0x22, 0x20}, | ||
350 | {0x2C, 0x79}, | ||
351 | {0x2D, 0x34}, | ||
352 | {0x2F, 0x00}, | ||
353 | {0x30, 0x28}, | ||
354 | {0x31, 0x31}, | ||
355 | {0x32, 0xDF}, | ||
356 | {0x38, 0x01}, | ||
357 | {0x39, 0x78}, | ||
358 | {0x3B, 0x33}, | ||
359 | {0x3C, 0x33}, | ||
360 | {0x48, 0x90}, | ||
361 | {0x51, 0x68}, | ||
362 | {0x5E, 0x38}, | ||
363 | {0x71, 0x00}, | ||
364 | {0x72, 0x08}, | ||
365 | {0x77, 0x00}, | ||
366 | {0xC0, 0x21}, | ||
367 | {0xC1, 0x10}, | ||
368 | {0xE4, 0x1A}, | ||
369 | {0xEA, 0x1F}, | ||
370 | {0x77, 0x00}, | ||
371 | {0x71, 0x00}, | ||
372 | {0x71, 0x00}, | ||
373 | {0x76, 0x0C}, | ||
374 | }; | ||
375 | |||
376 | const static int init_code_len = sizeof(init_code) / sizeof(u8[2]); | ||
377 | |||
378 | static int jdvbt90502_init(struct dvb_frontend *fe) | ||
379 | { | ||
380 | int i = -1; | ||
381 | int ret; | ||
382 | struct i2c_msg msg; | ||
383 | |||
384 | struct jdvbt90502_state *state = fe->demodulator_priv; | ||
385 | |||
386 | deb_fe("%s called.\n", __func__); | ||
387 | |||
388 | msg.addr = state->config.demod_address; | ||
389 | msg.flags = 0; | ||
390 | msg.len = 2; | ||
391 | for (i = 0; i < init_code_len; i++) { | ||
392 | msg.buf = init_code[i]; | ||
393 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
394 | if (ret != 1) | ||
395 | goto error; | ||
396 | } | ||
397 | msleep(100); | ||
398 | |||
399 | return 0; | ||
400 | |||
401 | error: | ||
402 | deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret); | ||
403 | return -EREMOTEIO; | ||
404 | } | ||
405 | |||
406 | |||
407 | static void jdvbt90502_release(struct dvb_frontend *fe) | ||
408 | { | ||
409 | struct jdvbt90502_state *state = fe->demodulator_priv; | ||
410 | kfree(state); | ||
411 | } | ||
412 | |||
413 | |||
414 | static struct dvb_frontend_ops jdvbt90502_ops; | ||
415 | |||
416 | struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d) | ||
417 | { | ||
418 | struct jdvbt90502_state *state = NULL; | ||
419 | |||
420 | deb_info("%s called.\n", __func__); | ||
421 | |||
422 | /* allocate memory for the internal state */ | ||
423 | state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL); | ||
424 | if (state == NULL) | ||
425 | goto error; | ||
426 | |||
427 | /* setup the state */ | ||
428 | state->i2c = &d->i2c_adap; | ||
429 | memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config)); | ||
430 | |||
431 | /* create dvb_frontend */ | ||
432 | memcpy(&state->frontend.ops, &jdvbt90502_ops, | ||
433 | sizeof(jdvbt90502_ops)); | ||
434 | state->frontend.demodulator_priv = state; | ||
435 | |||
436 | if (jdvbt90502_init(&state->frontend) < 0) | ||
437 | goto error; | ||
438 | |||
439 | return &state->frontend; | ||
440 | |||
441 | error: | ||
442 | kfree(state); | ||
443 | return NULL; | ||
444 | } | ||
445 | |||
446 | static struct dvb_frontend_ops jdvbt90502_ops = { | ||
447 | |||
448 | .info = { | ||
449 | .name = "Comtech JDVBT90502 ISDB-T", | ||
450 | .type = FE_OFDM, | ||
451 | .frequency_min = 473000000, /* UHF 13ch, center */ | ||
452 | .frequency_max = 767142857, /* UHF 62ch, center */ | ||
453 | .frequency_stepsize = JDVBT90502_PLL_CLK / | ||
454 | JDVBT90502_PLL_DIVIDER, | ||
455 | .frequency_tolerance = 0, | ||
456 | |||
457 | /* NOTE: this driver ignores all parameters but frequency. */ | ||
458 | .caps = FE_CAN_INVERSION_AUTO | | ||
459 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
460 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
461 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | | ||
462 | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
463 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
464 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
465 | FE_CAN_HIERARCHY_AUTO, | ||
466 | }, | ||
467 | |||
468 | .release = jdvbt90502_release, | ||
469 | |||
470 | .init = jdvbt90502_init, | ||
471 | .sleep = jdvbt90502_sleep, | ||
472 | .write = _jdvbt90502_write, | ||
473 | |||
474 | .set_frontend = jdvbt90502_set_frontend, | ||
475 | .get_frontend = jdvbt90502_get_frontend, | ||
476 | .get_tune_settings = jdvbt90502_get_tune_settings, | ||
477 | |||
478 | .read_status = jdvbt90502_read_status, | ||
479 | .read_ber = jdvbt90502_read_ber, | ||
480 | .read_signal_strength = jdvbt90502_read_signal_strength, | ||
481 | .read_snr = jdvbt90502_read_snr, | ||
482 | .read_ucblocks = jdvbt90502_read_ucblocks, | ||
483 | }; | ||
diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/dvb/dvb-usb/friio.c new file mode 100644 index 000000000000..14a65b4aec07 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/friio.c | |||
@@ -0,0 +1,525 @@ | |||
1 | /* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. | ||
2 | * | ||
3 | * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp> | ||
4 | * | ||
5 | * This module is based off the the gl861 and vp702x modules. | ||
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 Free | ||
9 | * Software Foundation, version 2. | ||
10 | * | ||
11 | * see Documentation/dvb/README.dvb-usb for more information | ||
12 | */ | ||
13 | #include "friio.h" | ||
14 | |||
15 | /* debug */ | ||
16 | int dvb_usb_friio_debug; | ||
17 | module_param_named(debug, dvb_usb_friio_debug, int, 0644); | ||
18 | MODULE_PARM_DESC(debug, | ||
19 | "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))." | ||
20 | DVB_USB_DEBUG_STATUS); | ||
21 | |||
22 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
23 | |||
24 | /** | ||
25 | * Indirect I2C access to the PLL via FE. | ||
26 | * whole I2C protocol data to the PLL is sent via the FE's I2C register. | ||
27 | * This is done by a control msg to the FE with the I2C data accompanied, and | ||
28 | * a specific USB request number is assigned for that purpose. | ||
29 | * | ||
30 | * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE). | ||
31 | * TODO: refoctored, smarter i2c functions. | ||
32 | */ | ||
33 | static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr, | ||
34 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) | ||
35 | { | ||
36 | u16 index = wbuf[0]; /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */ | ||
37 | u16 value = addr << (8 + 1); | ||
38 | int wo = (rbuf == NULL || rlen == 0); /* write only */ | ||
39 | u8 req, type; | ||
40 | |||
41 | deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n", | ||
42 | wbuf[1], wbuf[0], wlen - 1); | ||
43 | |||
44 | if (wo && wlen >= 2) { | ||
45 | req = GL861_REQ_I2C_DATA_CTRL_WRITE; | ||
46 | type = GL861_WRITE; | ||
47 | udelay(20); | ||
48 | return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), | ||
49 | req, type, value, index, | ||
50 | &wbuf[1], wlen - 1, 2000); | ||
51 | } | ||
52 | |||
53 | deb_xfer("not supported ctrl-msg, aborting."); | ||
54 | return -EINVAL; | ||
55 | } | ||
56 | |||
57 | /* normal I2C access (without extra data arguments). | ||
58 | * write to the register wbuf[0] at I2C address addr with the value wbuf[1], | ||
59 | * or read from the register wbuf[0]. | ||
60 | * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3 | ||
61 | */ | ||
62 | static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, | ||
63 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) | ||
64 | { | ||
65 | u16 index; | ||
66 | u16 value = addr << (8 + 1); | ||
67 | int wo = (rbuf == NULL || rlen == 0); /* write-only */ | ||
68 | u8 req, type; | ||
69 | unsigned int pipe; | ||
70 | |||
71 | /* special case for the indirect I2C access to the PLL via FE, */ | ||
72 | if (addr == friio_fe_config.demod_address && | ||
73 | wbuf[0] == JDVBT90502_2ND_I2C_REG) | ||
74 | return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen); | ||
75 | |||
76 | if (wo) { | ||
77 | req = GL861_REQ_I2C_WRITE; | ||
78 | type = GL861_WRITE; | ||
79 | pipe = usb_sndctrlpipe(d->udev, 0); | ||
80 | } else { /* rw */ | ||
81 | req = GL861_REQ_I2C_READ; | ||
82 | type = GL861_READ; | ||
83 | pipe = usb_rcvctrlpipe(d->udev, 0); | ||
84 | } | ||
85 | |||
86 | switch (wlen) { | ||
87 | case 1: | ||
88 | index = wbuf[0]; | ||
89 | break; | ||
90 | case 2: | ||
91 | index = wbuf[0]; | ||
92 | value = value + wbuf[1]; | ||
93 | break; | ||
94 | case 3: | ||
95 | /* special case for 16bit register-address */ | ||
96 | index = (wbuf[2] << 8) | wbuf[0]; | ||
97 | value = value + wbuf[1]; | ||
98 | break; | ||
99 | default: | ||
100 | deb_xfer("wlen = %x, aborting.", wlen); | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | msleep(1); | ||
104 | return usb_control_msg(d->udev, pipe, req, type, | ||
105 | value, index, rbuf, rlen, 2000); | ||
106 | } | ||
107 | |||
108 | /* I2C */ | ||
109 | static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | ||
110 | int num) | ||
111 | { | ||
112 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
113 | int i; | ||
114 | |||
115 | |||
116 | if (num > 2) | ||
117 | return -EINVAL; | ||
118 | |||
119 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
120 | return -EAGAIN; | ||
121 | |||
122 | for (i = 0; i < num; i++) { | ||
123 | /* write/read request */ | ||
124 | if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { | ||
125 | if (gl861_i2c_msg(d, msg[i].addr, | ||
126 | msg[i].buf, msg[i].len, | ||
127 | msg[i + 1].buf, msg[i + 1].len) < 0) | ||
128 | break; | ||
129 | i++; | ||
130 | } else | ||
131 | if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, | ||
132 | msg[i].len, NULL, 0) < 0) | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | mutex_unlock(&d->i2c_mutex); | ||
137 | return i; | ||
138 | } | ||
139 | |||
140 | static u32 gl861_i2c_func(struct i2c_adapter *adapter) | ||
141 | { | ||
142 | return I2C_FUNC_I2C; | ||
143 | } | ||
144 | |||
145 | |||
146 | static int friio_ext_ctl(struct dvb_usb_adapter *adap, | ||
147 | u32 sat_color, int lnb_on) | ||
148 | { | ||
149 | int i; | ||
150 | int ret; | ||
151 | struct i2c_msg msg; | ||
152 | u8 buf[2]; | ||
153 | u32 mask; | ||
154 | u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0; | ||
155 | |||
156 | msg.addr = 0x00; | ||
157 | msg.flags = 0; | ||
158 | msg.len = 2; | ||
159 | msg.buf = buf; | ||
160 | |||
161 | buf[0] = 0x00; | ||
162 | |||
163 | /* send 2bit header (&B10) */ | ||
164 | buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE; | ||
165 | ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
166 | buf[1] |= FRIIO_CTL_CLK; | ||
167 | ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
168 | |||
169 | buf[1] = lnb | FRIIO_CTL_STROBE; | ||
170 | ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
171 | buf[1] |= FRIIO_CTL_CLK; | ||
172 | ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
173 | |||
174 | /* send 32bit(satur, R, G, B) data in serial */ | ||
175 | mask = 1 << 31; | ||
176 | for (i = 0; i < 32; i++) { | ||
177 | buf[1] = lnb | FRIIO_CTL_STROBE; | ||
178 | if (sat_color & mask) | ||
179 | buf[1] |= FRIIO_CTL_LED; | ||
180 | ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
181 | buf[1] |= FRIIO_CTL_CLK; | ||
182 | ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
183 | mask >>= 1; | ||
184 | } | ||
185 | |||
186 | /* set the strobe off */ | ||
187 | buf[1] = lnb; | ||
188 | ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
189 | buf[1] |= FRIIO_CTL_CLK; | ||
190 | ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); | ||
191 | |||
192 | return (ret == 70); | ||
193 | } | ||
194 | |||
195 | |||
196 | static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); | ||
197 | |||
198 | /* TODO: move these init cmds to the FE's init routine? */ | ||
199 | static u8 streaming_init_cmds[][2] = { | ||
200 | {0x33, 0x08}, | ||
201 | {0x37, 0x40}, | ||
202 | {0x3A, 0x1F}, | ||
203 | {0x3B, 0xFF}, | ||
204 | {0x3C, 0x1F}, | ||
205 | {0x3D, 0xFF}, | ||
206 | {0x38, 0x00}, | ||
207 | {0x35, 0x00}, | ||
208 | {0x39, 0x00}, | ||
209 | {0x36, 0x00}, | ||
210 | }; | ||
211 | static int cmdlen = sizeof(streaming_init_cmds) / 2; | ||
212 | |||
213 | /* | ||
214 | * Command sequence in this init function is a replay | ||
215 | * of the captured USB commands from the Windows proprietary driver. | ||
216 | */ | ||
217 | static int friio_initialize(struct dvb_usb_device *d) | ||
218 | { | ||
219 | int ret; | ||
220 | int i; | ||
221 | int retry = 0; | ||
222 | u8 rbuf[2]; | ||
223 | u8 wbuf[3]; | ||
224 | |||
225 | deb_info("%s called.\n", __func__); | ||
226 | |||
227 | /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */ | ||
228 | /* because the i2c device is not set up yet. */ | ||
229 | wbuf[0] = 0x11; | ||
230 | wbuf[1] = 0x02; | ||
231 | ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); | ||
232 | if (ret < 0) | ||
233 | goto error; | ||
234 | msleep(2); | ||
235 | |||
236 | wbuf[0] = 0x11; | ||
237 | wbuf[1] = 0x00; | ||
238 | ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); | ||
239 | if (ret < 0) | ||
240 | goto error; | ||
241 | msleep(1); | ||
242 | |||
243 | /* following msgs should be in the FE's init code? */ | ||
244 | /* cmd sequence to identify the device type? (friio black/white) */ | ||
245 | wbuf[0] = 0x03; | ||
246 | wbuf[1] = 0x80; | ||
247 | /* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */ | ||
248 | ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), | ||
249 | GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE, | ||
250 | 0x1200, 0x0100, wbuf, 2, 2000); | ||
251 | if (ret < 0) | ||
252 | goto error; | ||
253 | |||
254 | msleep(2); | ||
255 | wbuf[0] = 0x00; | ||
256 | wbuf[2] = 0x01; /* reg.0x0100 */ | ||
257 | wbuf[1] = 0x00; | ||
258 | ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2); | ||
259 | /* my Friio White returns 0xffff. */ | ||
260 | if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff) | ||
261 | goto error; | ||
262 | |||
263 | msleep(2); | ||
264 | wbuf[0] = 0x03; | ||
265 | wbuf[1] = 0x80; | ||
266 | ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), | ||
267 | GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE, | ||
268 | 0x9000, 0x0100, wbuf, 2, 2000); | ||
269 | if (ret < 0) | ||
270 | goto error; | ||
271 | |||
272 | msleep(2); | ||
273 | wbuf[0] = 0x00; | ||
274 | wbuf[2] = 0x01; /* reg.0x0100 */ | ||
275 | wbuf[1] = 0x00; | ||
276 | ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2); | ||
277 | /* my Friio White returns 0xffff again. */ | ||
278 | if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff) | ||
279 | goto error; | ||
280 | |||
281 | msleep(1); | ||
282 | |||
283 | restart: | ||
284 | /* ============ start DEMOD init cmds ================== */ | ||
285 | /* read PLL status to clear the POR bit */ | ||
286 | wbuf[0] = JDVBT90502_2ND_I2C_REG; | ||
287 | wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1; /* +1 for reading */ | ||
288 | ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0); | ||
289 | if (ret < 0) | ||
290 | goto error; | ||
291 | |||
292 | msleep(5); | ||
293 | /* note: DEMODULATOR has 16bit register-address. */ | ||
294 | wbuf[0] = 0x00; | ||
295 | wbuf[2] = 0x01; /* reg addr: 0x0100 */ | ||
296 | wbuf[1] = 0x00; /* val: not used */ | ||
297 | ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1); | ||
298 | if (ret < 0) | ||
299 | goto error; | ||
300 | /* | ||
301 | msleep(1); | ||
302 | wbuf[0] = 0x80; | ||
303 | wbuf[1] = 0x00; | ||
304 | ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1); | ||
305 | if (ret < 0) | ||
306 | goto error; | ||
307 | */ | ||
308 | if (rbuf[0] & 0x80) { /* still in PowerOnReset state? */ | ||
309 | if (++retry > 3) { | ||
310 | deb_info("failed to get the correct" | ||
311 | " FE demod status:0x%02x\n", rbuf[0]); | ||
312 | goto error; | ||
313 | } | ||
314 | msleep(100); | ||
315 | goto restart; | ||
316 | } | ||
317 | |||
318 | /* TODO: check return value in rbuf */ | ||
319 | /* =========== end DEMOD init cmds ===================== */ | ||
320 | msleep(1); | ||
321 | |||
322 | wbuf[0] = 0x30; | ||
323 | wbuf[1] = 0x04; | ||
324 | ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); | ||
325 | if (ret < 0) | ||
326 | goto error; | ||
327 | |||
328 | msleep(2); | ||
329 | /* following 2 cmds unnecessary? */ | ||
330 | wbuf[0] = 0x00; | ||
331 | wbuf[1] = 0x01; | ||
332 | ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); | ||
333 | if (ret < 0) | ||
334 | goto error; | ||
335 | |||
336 | wbuf[0] = 0x06; | ||
337 | wbuf[1] = 0x0F; | ||
338 | ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); | ||
339 | if (ret < 0) | ||
340 | goto error; | ||
341 | |||
342 | /* some streaming ctl cmds (maybe) */ | ||
343 | msleep(10); | ||
344 | for (i = 0; i < cmdlen; i++) { | ||
345 | ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2, | ||
346 | NULL, 0); | ||
347 | if (ret < 0) | ||
348 | goto error; | ||
349 | msleep(1); | ||
350 | } | ||
351 | msleep(20); | ||
352 | |||
353 | /* change the LED color etc. */ | ||
354 | ret = friio_streaming_ctrl(&d->adapter[0], 0); | ||
355 | if (ret < 0) | ||
356 | goto error; | ||
357 | |||
358 | return 0; | ||
359 | |||
360 | error: | ||
361 | deb_info("%s:ret == %d\n", __func__, ret); | ||
362 | return -EIO; | ||
363 | } | ||
364 | |||
365 | /* Callbacks for DVB USB */ | ||
366 | |||
367 | static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
368 | { | ||
369 | int ret; | ||
370 | |||
371 | deb_info("%s called.(%d)\n", __func__, onoff); | ||
372 | |||
373 | /* set the LED color and saturation (and LNB on) */ | ||
374 | if (onoff) | ||
375 | ret = friio_ext_ctl(adap, 0x6400ff64, 1); | ||
376 | else | ||
377 | ret = friio_ext_ctl(adap, 0x96ff00ff, 1); | ||
378 | |||
379 | if (ret != 1) { | ||
380 | deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret); | ||
381 | return -EREMOTEIO; | ||
382 | } | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static int friio_frontend_attach(struct dvb_usb_adapter *adap) | ||
387 | { | ||
388 | if (friio_initialize(adap->dev) < 0) | ||
389 | return -EIO; | ||
390 | |||
391 | adap->fe = jdvbt90502_attach(adap->dev); | ||
392 | if (adap->fe == NULL) | ||
393 | return -EIO; | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | /* DVB USB Driver stuff */ | ||
399 | static struct dvb_usb_device_properties friio_properties; | ||
400 | |||
401 | static int friio_probe(struct usb_interface *intf, | ||
402 | const struct usb_device_id *id) | ||
403 | { | ||
404 | struct dvb_usb_device *d; | ||
405 | struct usb_host_interface *alt; | ||
406 | int ret; | ||
407 | |||
408 | if (intf->num_altsetting < GL861_ALTSETTING_COUNT) | ||
409 | return -ENODEV; | ||
410 | |||
411 | alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING); | ||
412 | if (alt == NULL) { | ||
413 | deb_rc("not alt found!\n"); | ||
414 | return -ENODEV; | ||
415 | } | ||
416 | ret = usb_set_interface(interface_to_usbdev(intf), | ||
417 | alt->desc.bInterfaceNumber, | ||
418 | alt->desc.bAlternateSetting); | ||
419 | if (ret != 0) { | ||
420 | deb_rc("failed to set alt-setting!\n"); | ||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | ret = dvb_usb_device_init(intf, &friio_properties, | ||
425 | THIS_MODULE, &d, adapter_nr); | ||
426 | if (ret == 0) | ||
427 | friio_streaming_ctrl(&d->adapter[0], 1); | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | |||
433 | struct jdvbt90502_config friio_fe_config = { | ||
434 | .demod_address = FRIIO_DEMOD_ADDR, | ||
435 | .pll_address = FRIIO_PLL_ADDR, | ||
436 | }; | ||
437 | |||
438 | static struct i2c_algorithm gl861_i2c_algo = { | ||
439 | .master_xfer = gl861_i2c_xfer, | ||
440 | .functionality = gl861_i2c_func, | ||
441 | }; | ||
442 | |||
443 | static struct usb_device_id friio_table[] = { | ||
444 | { USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) }, | ||
445 | { } /* Terminating entry */ | ||
446 | }; | ||
447 | MODULE_DEVICE_TABLE(usb, friio_table); | ||
448 | |||
449 | |||
450 | static struct dvb_usb_device_properties friio_properties = { | ||
451 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
452 | .usb_ctrl = DEVICE_SPECIFIC, | ||
453 | |||
454 | .size_of_priv = 0, | ||
455 | |||
456 | .num_adapters = 1, | ||
457 | .adapter = { | ||
458 | /* caps:0 => no pid filter, 188B TS packet */ | ||
459 | /* GL861 has a HW pid filter, but no info available. */ | ||
460 | { | ||
461 | .caps = 0, | ||
462 | |||
463 | .frontend_attach = friio_frontend_attach, | ||
464 | .streaming_ctrl = friio_streaming_ctrl, | ||
465 | |||
466 | .stream = { | ||
467 | .type = USB_BULK, | ||
468 | /* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */ | ||
469 | .count = 8, | ||
470 | .endpoint = 0x01, | ||
471 | .u = { | ||
472 | /* GL861 has 6KB buf inside */ | ||
473 | .bulk = { | ||
474 | .buffersize = 16384, | ||
475 | } | ||
476 | } | ||
477 | }, | ||
478 | } | ||
479 | }, | ||
480 | .i2c_algo = &gl861_i2c_algo, | ||
481 | |||
482 | .num_device_descs = 1, | ||
483 | .devices = { | ||
484 | { | ||
485 | .name = "774 Friio ISDB-T USB2.0", | ||
486 | .cold_ids = { NULL }, | ||
487 | .warm_ids = { &friio_table[0], NULL }, | ||
488 | }, | ||
489 | } | ||
490 | }; | ||
491 | |||
492 | static struct usb_driver friio_driver = { | ||
493 | .name = "dvb_usb_friio", | ||
494 | .probe = friio_probe, | ||
495 | .disconnect = dvb_usb_device_exit, | ||
496 | .id_table = friio_table, | ||
497 | }; | ||
498 | |||
499 | |||
500 | /* module stuff */ | ||
501 | static int __init friio_module_init(void) | ||
502 | { | ||
503 | int ret; | ||
504 | |||
505 | ret = usb_register(&friio_driver); | ||
506 | if (ret) | ||
507 | err("usb_register failed. Error number %d", ret); | ||
508 | |||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | |||
513 | static void __exit friio_module_exit(void) | ||
514 | { | ||
515 | /* deregister this driver from the USB subsystem */ | ||
516 | usb_deregister(&friio_driver); | ||
517 | } | ||
518 | |||
519 | module_init(friio_module_init); | ||
520 | module_exit(friio_module_exit); | ||
521 | |||
522 | MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>"); | ||
523 | MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver"); | ||
524 | MODULE_VERSION("0.2"); | ||
525 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-usb/friio.h b/drivers/media/dvb/dvb-usb/friio.h new file mode 100644 index 000000000000..af8d55e390fb --- /dev/null +++ b/drivers/media/dvb/dvb-usb/friio.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. | ||
2 | * | ||
3 | * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp> | ||
4 | * | ||
5 | * This module is based off the the gl861 and vp702x modules. | ||
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 Free | ||
9 | * Software Foundation, version 2. | ||
10 | * | ||
11 | * see Documentation/dvb/README.dvb-usb for more information | ||
12 | */ | ||
13 | #ifndef _DVB_USB_FRIIO_H_ | ||
14 | #define _DVB_USB_FRIIO_H_ | ||
15 | |||
16 | /** | ||
17 | * Friio Components | ||
18 | * USB hub: AU4254 | ||
19 | * USB controller(+ TS dmx & streaming): GL861 | ||
20 | * Frontend: comtech JDVBT-90502 | ||
21 | * (tuner PLL: tua6034, I2C addr:(0xC0 >> 1)) | ||
22 | * (OFDM demodulator: TC90502, I2C addr:(0x30 >> 1)) | ||
23 | * LED x3 (+LNB) controll: PIC 16F676 | ||
24 | * EEPROM: 24C08 | ||
25 | * | ||
26 | * (USB smart card reader: AU9522) | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #define DVB_USB_LOG_PREFIX "friio" | ||
31 | #include "dvb-usb.h" | ||
32 | |||
33 | extern int dvb_usb_friio_debug; | ||
34 | #define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args) | ||
35 | #define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args) | ||
36 | #define deb_rc(args...) dprintk(dvb_usb_friio_debug, 0x04, args) | ||
37 | #define deb_fe(args...) dprintk(dvb_usb_friio_debug, 0x08, args) | ||
38 | |||
39 | /* Vendor requests */ | ||
40 | #define GL861_WRITE 0x40 | ||
41 | #define GL861_READ 0xc0 | ||
42 | |||
43 | /* command bytes */ | ||
44 | #define GL861_REQ_I2C_WRITE 0x01 | ||
45 | #define GL861_REQ_I2C_READ 0x02 | ||
46 | /* For control msg with data argument */ | ||
47 | /* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */ | ||
48 | #define GL861_REQ_I2C_DATA_CTRL_WRITE 0x03 | ||
49 | |||
50 | #define GL861_ALTSETTING_COUNT 2 | ||
51 | #define FRIIO_BULK_ALTSETTING 0 | ||
52 | #define FRIIO_ISOC_ALTSETTING 1 | ||
53 | |||
54 | /* LED & LNB control via PIC. */ | ||
55 | /* basically, it's serial control with clock and strobe. */ | ||
56 | /* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */ | ||
57 | /* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/ | ||
58 | #define FRIIO_CTL_LNB (1 << 0) | ||
59 | #define FRIIO_CTL_STROBE (1 << 1) | ||
60 | #define FRIIO_CTL_CLK (1 << 2) | ||
61 | #define FRIIO_CTL_LED (1 << 3) | ||
62 | |||
63 | /* Front End related */ | ||
64 | |||
65 | #define FRIIO_DEMOD_ADDR (0x30 >> 1) | ||
66 | #define FRIIO_PLL_ADDR (0xC0 >> 1) | ||
67 | |||
68 | #define JDVBT90502_PLL_CLK 4000000 | ||
69 | #define JDVBT90502_PLL_DIVIDER 28 | ||
70 | |||
71 | #define JDVBT90502_2ND_I2C_REG 0xFE | ||
72 | |||
73 | /* byte index for pll i2c command data structure*/ | ||
74 | /* see datasheet for tua6034 */ | ||
75 | #define DEMOD_REDIRECT_REG 0 | ||
76 | #define ADDRESS_BYTE 1 | ||
77 | #define DIVIDER_BYTE1 2 | ||
78 | #define DIVIDER_BYTE2 3 | ||
79 | #define CONTROL_BYTE 4 | ||
80 | #define BANDSWITCH_BYTE 5 | ||
81 | #define AGC_CTRL_BYTE 5 | ||
82 | #define PLL_CMD_LEN 6 | ||
83 | |||
84 | /* bit masks for PLL STATUS response */ | ||
85 | #define PLL_STATUS_POR_MODE 0x80 /* 1: Power on Reset (test) Mode */ | ||
86 | #define PLL_STATUS_LOCKED 0x40 /* 1: locked */ | ||
87 | #define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */ | ||
88 | #define PLL_STATUS_TESTMODE 0x07 /* digital output level (5 level) */ | ||
89 | /* 0.15Vcc step 0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */ | ||
90 | |||
91 | |||
92 | struct jdvbt90502_config { | ||
93 | u8 demod_address; /* i2c addr for demodulator IC */ | ||
94 | u8 pll_address; /* PLL addr on the secondary i2c*/ | ||
95 | }; | ||
96 | extern struct jdvbt90502_config friio_fe_config; | ||
97 | |||
98 | extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d); | ||
99 | #endif | ||
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c index aec7a1943b66..ef9b7bed13ff 100644 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ b/drivers/media/dvb/dvb-usb/m920x.c | |||
@@ -337,6 +337,8 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar | |||
337 | int i, pass, ret = 0; | 337 | int i, pass, ret = 0; |
338 | 338 | ||
339 | buff = kmalloc(65536, GFP_KERNEL); | 339 | buff = kmalloc(65536, GFP_KERNEL); |
340 | if (buff == NULL) | ||
341 | return -ENOMEM; | ||
340 | 342 | ||
341 | if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) | 343 | if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) |
342 | goto done; | 344 | goto done; |
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index b794e860b4e2..d7c4837fa71c 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -484,6 +484,14 @@ config DVB_S921 | |||
484 | AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. | 484 | AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. |
485 | Say Y when you want to support this frontend. | 485 | Say Y when you want to support this frontend. |
486 | 486 | ||
487 | config DVB_DIB8000 | ||
488 | tristate "DiBcom 8000MB/MC" | ||
489 | depends on DVB_CORE && I2C | ||
490 | default m if DVB_FE_CUSTOMISE | ||
491 | help | ||
492 | A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator. | ||
493 | Say Y when you want to support this frontend. | ||
494 | |||
487 | comment "Digital terrestrial only tuners/PLL" | 495 | comment "Digital terrestrial only tuners/PLL" |
488 | depends on DVB_CORE | 496 | depends on DVB_CORE |
489 | 497 | ||
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 3b49d37ab5fa..3523767e7a76 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o | |||
23 | obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o | 23 | obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o |
24 | obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o | 24 | obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o |
25 | obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o | 25 | obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o |
26 | obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o | ||
26 | obj-$(CONFIG_DVB_MT312) += mt312.o | 27 | obj-$(CONFIG_DVB_MT312) += mt312.o |
27 | obj-$(CONFIG_DVB_VES1820) += ves1820.o | 28 | obj-$(CONFIG_DVB_VES1820) += ves1820.o |
28 | obj-$(CONFIG_DVB_VES1X93) += ves1x93.o | 29 | obj-$(CONFIG_DVB_VES1X93) += ves1x93.o |
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index 9e9a75576a1d..74981ee923c8 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c | |||
@@ -792,6 +792,11 @@ static int au8522_probe(struct i2c_client *client, | |||
792 | } | 792 | } |
793 | 793 | ||
794 | demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL); | 794 | demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL); |
795 | if (demod_config == NULL) { | ||
796 | if (instance == 1) | ||
797 | kfree(state); | ||
798 | return -ENOMEM; | ||
799 | } | ||
795 | demod_config->demod_address = 0x8e >> 1; | 800 | demod_config->demod_address = 0x8e >> 1; |
796 | 801 | ||
797 | state->config = demod_config; | 802 | state->config = demod_config; |
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index da92cbe1b8ea..2be17b93e0bd 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c | |||
@@ -1,12 +1,29 @@ | |||
1 | /* | 1 | /* |
2 | * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. | 2 | * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. |
3 | * | 3 | * |
4 | * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) | 4 | * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation, version 2. | 8 | * published by the Free Software Foundation; either version 2 of the |
9 | * License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | * | ||
22 | * This code is more or less generated from another driver, please | ||
23 | * excuse some codingstyle oddities. | ||
24 | * | ||
9 | */ | 25 | */ |
26 | |||
10 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
11 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
12 | 29 | ||
@@ -19,27 +36,65 @@ static int debug; | |||
19 | module_param(debug, int, 0644); | 36 | module_param(debug, int, 0644); |
20 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | 37 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); |
21 | 38 | ||
22 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0) | 39 | #define dprintk(args...) do { \ |
40 | if (debug) { \ | ||
41 | printk(KERN_DEBUG "DiB0070: "); \ | ||
42 | printk(args); \ | ||
43 | printk("\n"); \ | ||
44 | } \ | ||
45 | } while (0) | ||
23 | 46 | ||
24 | #define DIB0070_P1D 0x00 | 47 | #define DIB0070_P1D 0x00 |
25 | #define DIB0070_P1F 0x01 | 48 | #define DIB0070_P1F 0x01 |
26 | #define DIB0070_P1G 0x03 | 49 | #define DIB0070_P1G 0x03 |
27 | #define DIB0070S_P1A 0x02 | 50 | #define DIB0070S_P1A 0x02 |
28 | 51 | ||
52 | enum frontend_tune_state { | ||
53 | CT_TUNER_START = 10, | ||
54 | CT_TUNER_STEP_0, | ||
55 | CT_TUNER_STEP_1, | ||
56 | CT_TUNER_STEP_2, | ||
57 | CT_TUNER_STEP_3, | ||
58 | CT_TUNER_STEP_4, | ||
59 | CT_TUNER_STEP_5, | ||
60 | CT_TUNER_STEP_6, | ||
61 | CT_TUNER_STEP_7, | ||
62 | CT_TUNER_STOP, | ||
63 | }; | ||
64 | |||
65 | #define FE_CALLBACK_TIME_NEVER 0xffffffff | ||
66 | |||
29 | struct dib0070_state { | 67 | struct dib0070_state { |
30 | struct i2c_adapter *i2c; | 68 | struct i2c_adapter *i2c; |
31 | struct dvb_frontend *fe; | 69 | struct dvb_frontend *fe; |
32 | const struct dib0070_config *cfg; | 70 | const struct dib0070_config *cfg; |
33 | u16 wbd_ff_offset; | 71 | u16 wbd_ff_offset; |
34 | u8 revision; | 72 | u8 revision; |
73 | |||
74 | enum frontend_tune_state tune_state; | ||
75 | u32 current_rf; | ||
76 | |||
77 | /* for the captrim binary search */ | ||
78 | s8 step; | ||
79 | u16 adc_diff; | ||
80 | |||
81 | s8 captrim; | ||
82 | s8 fcaptrim; | ||
83 | u16 lo4; | ||
84 | |||
85 | const struct dib0070_tuning *current_tune_table_index; | ||
86 | const struct dib0070_lna_match *lna_match; | ||
87 | |||
88 | u8 wbd_gain_current; | ||
89 | u16 wbd_offset_3_3[2]; | ||
35 | }; | 90 | }; |
36 | 91 | ||
37 | static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) | 92 | static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) |
38 | { | 93 | { |
39 | u8 b[2]; | 94 | u8 b[2]; |
40 | struct i2c_msg msg[2] = { | 95 | struct i2c_msg msg[2] = { |
41 | { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, | 96 | {.addr = state->cfg->i2c_address,.flags = 0,.buf = ®,.len = 1}, |
42 | { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, | 97 | {.addr = state->cfg->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2}, |
43 | }; | 98 | }; |
44 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | 99 | if (i2c_transfer(state->i2c, msg, 2) != 2) { |
45 | printk(KERN_WARNING "DiB0070 I2C read failed\n"); | 100 | printk(KERN_WARNING "DiB0070 I2C read failed\n"); |
@@ -51,7 +106,7 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) | |||
51 | static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) | 106 | static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) |
52 | { | 107 | { |
53 | u8 b[3] = { reg, val >> 8, val & 0xff }; | 108 | u8 b[3] = { reg, val >> 8, val & 0xff }; |
54 | struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; | 109 | struct i2c_msg msg = {.addr = state->cfg->i2c_address,.flags = 0,.buf = b,.len = 3 }; |
55 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | 110 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { |
56 | printk(KERN_WARNING "DiB0070 I2C write failed\n"); | 111 | printk(KERN_WARNING "DiB0070 I2C write failed\n"); |
57 | return -EREMOTEIO; | 112 | return -EREMOTEIO; |
@@ -59,55 +114,71 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) | |||
59 | return 0; | 114 | return 0; |
60 | } | 115 | } |
61 | 116 | ||
62 | #define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0) | 117 | #define HARD_RESET(state) do { \ |
118 | state->cfg->sleep(state->fe, 0); \ | ||
119 | if (state->cfg->reset) { \ | ||
120 | state->cfg->reset(state->fe,1); msleep(10); \ | ||
121 | state->cfg->reset(state->fe,0); msleep(10); \ | ||
122 | } \ | ||
123 | } while (0) | ||
63 | 124 | ||
64 | static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) | 125 | static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) |
65 | { | 126 | { |
66 | struct dib0070_state *st = fe->tuner_priv; | 127 | struct dib0070_state *state = fe->tuner_priv; |
67 | u16 tmp = 0; | 128 | u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; |
68 | tmp = dib0070_read_reg(st, 0x02) & 0x3fff; | 129 | |
130 | if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 7000) | ||
131 | tmp |= (0 << 14); | ||
132 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 6000) | ||
133 | tmp |= (1 << 14); | ||
134 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 5000) | ||
135 | tmp |= (2 << 14); | ||
136 | else | ||
137 | tmp |= (3 << 14); | ||
69 | 138 | ||
70 | switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) { | 139 | dib0070_write_reg(state, 0x02, tmp); |
71 | case 8000: | 140 | |
72 | tmp |= (0 << 14); | 141 | /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ |
73 | break; | 142 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { |
74 | case 7000: | 143 | u16 value = dib0070_read_reg(state, 0x17); |
75 | tmp |= (1 << 14); | 144 | |
76 | break; | 145 | dib0070_write_reg(state, 0x17, value & 0xfffc); |
77 | case 6000: | 146 | tmp = dib0070_read_reg(state, 0x01) & 0x01ff; |
78 | tmp |= (2 << 14); | 147 | dib0070_write_reg(state, 0x01, tmp | (60 << 9)); |
79 | break; | 148 | |
80 | case 5000: | 149 | dib0070_write_reg(state, 0x17, value); |
81 | default: | ||
82 | tmp |= (3 << 14); | ||
83 | break; | ||
84 | } | 150 | } |
85 | dib0070_write_reg(st, 0x02, tmp); | ||
86 | return 0; | 151 | return 0; |
87 | } | 152 | } |
88 | 153 | ||
89 | static void dib0070_captrim(struct dib0070_state *st, u16 LO4) | 154 | static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state) |
90 | { | 155 | { |
91 | int8_t captrim, fcaptrim, step_sign, step; | 156 | int8_t step_sign; |
92 | u16 adc, adc_diff = 3000; | 157 | u16 adc; |
158 | int ret = 0; | ||
93 | 159 | ||
160 | if (*tune_state == CT_TUNER_STEP_0) { | ||
94 | 161 | ||
162 | dib0070_write_reg(state, 0x0f, 0xed10); | ||
163 | dib0070_write_reg(state, 0x17, 0x0034); | ||
95 | 164 | ||
96 | dib0070_write_reg(st, 0x0f, 0xed10); | 165 | dib0070_write_reg(state, 0x18, 0x0032); |
97 | dib0070_write_reg(st, 0x17, 0x0034); | 166 | state->step = state->captrim = state->fcaptrim = 64; |
167 | state->adc_diff = 3000; | ||
168 | ret = 20; | ||
98 | 169 | ||
99 | dib0070_write_reg(st, 0x18, 0x0032); | 170 | *tune_state = CT_TUNER_STEP_1; |
100 | msleep(2); | 171 | } else if (*tune_state == CT_TUNER_STEP_1) { |
172 | state->step /= 2; | ||
173 | dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); | ||
174 | ret = 15; | ||
101 | 175 | ||
102 | step = captrim = fcaptrim = 64; | 176 | *tune_state = CT_TUNER_STEP_2; |
177 | } else if (*tune_state == CT_TUNER_STEP_2) { | ||
103 | 178 | ||
104 | do { | 179 | adc = dib0070_read_reg(state, 0x19); |
105 | step /= 2; | ||
106 | dib0070_write_reg(st, 0x14, LO4 | captrim); | ||
107 | msleep(1); | ||
108 | adc = dib0070_read_reg(st, 0x19); | ||
109 | 180 | ||
110 | dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024); | 181 | dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc * (u32) 1800 / (u32) 1024); |
111 | 182 | ||
112 | if (adc >= 400) { | 183 | if (adc >= 400) { |
113 | adc -= 400; | 184 | adc -= 400; |
@@ -117,379 +188,430 @@ static void dib0070_captrim(struct dib0070_state *st, u16 LO4) | |||
117 | step_sign = 1; | 188 | step_sign = 1; |
118 | } | 189 | } |
119 | 190 | ||
120 | if (adc < adc_diff) { | 191 | if (adc < state->adc_diff) { |
121 | dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff); | 192 | dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff); |
122 | adc_diff = adc; | 193 | state->adc_diff = adc; |
123 | fcaptrim = captrim; | 194 | state->fcaptrim = state->captrim; |
124 | 195 | ||
196 | } | ||
197 | state->captrim += (step_sign * state->step); | ||
125 | 198 | ||
199 | if (state->step >= 1) | ||
200 | *tune_state = CT_TUNER_STEP_1; | ||
201 | else | ||
202 | *tune_state = CT_TUNER_STEP_3; | ||
126 | 203 | ||
127 | } | 204 | } else if (*tune_state == CT_TUNER_STEP_3) { |
128 | captrim += (step_sign * step); | 205 | dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim); |
129 | } while (step >= 1); | 206 | dib0070_write_reg(state, 0x18, 0x07ff); |
207 | *tune_state = CT_TUNER_STEP_4; | ||
208 | } | ||
130 | 209 | ||
131 | dib0070_write_reg(st, 0x14, LO4 | fcaptrim); | 210 | return ret; |
132 | dib0070_write_reg(st, 0x18, 0x07ff); | ||
133 | } | 211 | } |
134 | 212 | ||
135 | #define LPF 100 // define for the loop filter 100kHz by default 16-07-06 | 213 | static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) |
136 | #define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7) | ||
137 | #define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12) | ||
138 | #define LO4_SET_CTRIM(l, c) l |= (c) << 10 | ||
139 | static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) | ||
140 | { | 214 | { |
141 | struct dib0070_state *st = fe->tuner_priv; | 215 | struct dib0070_state *state = fe->tuner_priv; |
142 | u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf); | 216 | u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); |
143 | 217 | dprintk("CTRL_LO5: 0x%x", lo5); | |
144 | u8 band = BAND_OF_FREQUENCY(freq), c; | 218 | return dib0070_write_reg(state, 0x15, lo5); |
219 | } | ||
145 | 220 | ||
146 | /*******************VCO***********************************/ | 221 | void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) |
147 | u16 lo4 = 0; | 222 | { |
223 | struct dib0070_state *state = fe->tuner_priv; | ||
148 | 224 | ||
149 | u8 REFDIV, PRESC = 2; | 225 | if (open) { |
150 | u32 FBDiv, Rest, FREF, VCOF_kHz; | 226 | dib0070_write_reg(state, 0x1b, 0xff00); |
151 | u16 Num, Den; | 227 | dib0070_write_reg(state, 0x1a, 0x0000); |
152 | /*******************FrontEnd******************************/ | 228 | } else { |
153 | u16 value = 0; | 229 | dib0070_write_reg(state, 0x1b, 0x4112); |
230 | if (state->cfg->vga_filter != 0) { | ||
231 | dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); | ||
232 | dprintk("vga filter register is set to %x", state->cfg->vga_filter); | ||
233 | } else | ||
234 | dib0070_write_reg(state, 0x1a, 0x0009); | ||
235 | } | ||
236 | } | ||
154 | 237 | ||
155 | dprintk( "Tuning for Band: %hd (%d kHz)", band, freq); | 238 | EXPORT_SYMBOL(dib0070_ctrl_agc_filter); |
239 | struct dib0070_tuning { | ||
240 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | ||
241 | u8 switch_trim; | ||
242 | u8 vco_band; | ||
243 | u8 hfdiv; | ||
244 | u8 vco_multi; | ||
245 | u8 presc; | ||
246 | u8 wbdmux; | ||
247 | u16 tuner_enable; | ||
248 | }; | ||
156 | 249 | ||
250 | struct dib0070_lna_match { | ||
251 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | ||
252 | u8 lna_band; | ||
253 | }; | ||
157 | 254 | ||
158 | dib0070_write_reg(st, 0x17, 0x30); | 255 | static const struct dib0070_tuning dib0070s_tuning_table[] = { |
256 | {570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800}, /* UHF */ | ||
257 | {700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800}, | ||
258 | {863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800}, | ||
259 | {1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND */ | ||
260 | {1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, | ||
261 | {2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, | ||
262 | {0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000}, /* SBAND */ | ||
263 | }; | ||
159 | 264 | ||
160 | dib0070_set_bandwidth(fe, ch); /* c is used as HF */ | 265 | static const struct dib0070_tuning dib0070_tuning_table[] = { |
161 | switch (st->revision) { | 266 | {115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000}, /* FM below 92MHz cannot be tuned */ |
162 | case DIB0070S_P1A: | 267 | {179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000}, /* VHF */ |
163 | switch (band) { | 268 | {189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000}, |
164 | case BAND_LBAND: | 269 | {250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000}, |
165 | LO4_SET_VCO_HFDIV(lo4, 1, 1); | 270 | {569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800}, /* UHF */ |
166 | c = 2; | 271 | {699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800}, |
167 | break; | 272 | {863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800}, |
168 | case BAND_SBAND: | 273 | {0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND or everything higher than UHF */ |
169 | LO4_SET_VCO_HFDIV(lo4, 0, 0); | 274 | }; |
170 | LO4_SET_CTRIM(lo4, 1); | ||
171 | c = 1; | ||
172 | break; | ||
173 | case BAND_UHF: | ||
174 | default: | ||
175 | if (freq < 570000) { | ||
176 | LO4_SET_VCO_HFDIV(lo4, 1, 3); | ||
177 | PRESC = 6; c = 6; | ||
178 | } else if (freq < 680000) { | ||
179 | LO4_SET_VCO_HFDIV(lo4, 0, 2); | ||
180 | c = 4; | ||
181 | } else { | ||
182 | LO4_SET_VCO_HFDIV(lo4, 1, 2); | ||
183 | c = 4; | ||
184 | } | ||
185 | break; | ||
186 | } break; | ||
187 | |||
188 | case DIB0070_P1G: | ||
189 | case DIB0070_P1F: | ||
190 | default: | ||
191 | switch (band) { | ||
192 | case BAND_FM: | ||
193 | LO4_SET_VCO_HFDIV(lo4, 0, 7); | ||
194 | c = 24; | ||
195 | break; | ||
196 | case BAND_LBAND: | ||
197 | LO4_SET_VCO_HFDIV(lo4, 1, 0); | ||
198 | c = 2; | ||
199 | break; | ||
200 | case BAND_VHF: | ||
201 | if (freq < 180000) { | ||
202 | LO4_SET_VCO_HFDIV(lo4, 0, 3); | ||
203 | c = 16; | ||
204 | } else if (freq < 190000) { | ||
205 | LO4_SET_VCO_HFDIV(lo4, 1, 3); | ||
206 | c = 16; | ||
207 | } else { | ||
208 | LO4_SET_VCO_HFDIV(lo4, 0, 6); | ||
209 | c = 12; | ||
210 | } | ||
211 | break; | ||
212 | |||
213 | case BAND_UHF: | ||
214 | default: | ||
215 | if (freq < 570000) { | ||
216 | LO4_SET_VCO_HFDIV(lo4, 1, 5); | ||
217 | c = 6; | ||
218 | } else if (freq < 700000) { | ||
219 | LO4_SET_VCO_HFDIV(lo4, 0, 1); | ||
220 | c = 4; | ||
221 | } else { | ||
222 | LO4_SET_VCO_HFDIV(lo4, 1, 1); | ||
223 | c = 4; | ||
224 | } | ||
225 | break; | ||
226 | } | ||
227 | break; | ||
228 | } | ||
229 | 275 | ||
230 | dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf); | 276 | static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { |
231 | dprintk( "VCO = %hd", (lo4 >> 11) & 0x3); | 277 | {180000, 0}, /* VHF */ |
278 | {188000, 1}, | ||
279 | {196400, 2}, | ||
280 | {250000, 3}, | ||
281 | {550000, 0}, /* UHF */ | ||
282 | {590000, 1}, | ||
283 | {666000, 3}, | ||
284 | {864000, 5}, | ||
285 | {1500000, 0}, /* LBAND or everything higher than UHF */ | ||
286 | {1600000, 1}, | ||
287 | {2000000, 3}, | ||
288 | {0xffffffff, 7}, | ||
289 | }; | ||
232 | 290 | ||
291 | static const struct dib0070_lna_match dib0070_lna[] = { | ||
292 | {180000, 0}, /* VHF */ | ||
293 | {188000, 1}, | ||
294 | {196400, 2}, | ||
295 | {250000, 3}, | ||
296 | {550000, 2}, /* UHF */ | ||
297 | {650000, 3}, | ||
298 | {750000, 5}, | ||
299 | {850000, 6}, | ||
300 | {864000, 7}, | ||
301 | {1500000, 0}, /* LBAND or everything higher than UHF */ | ||
302 | {1600000, 1}, | ||
303 | {2000000, 3}, | ||
304 | {0xffffffff, 7}, | ||
305 | }; | ||
233 | 306 | ||
234 | VCOF_kHz = (c * freq) * 2; | 307 | #define LPF 100 // define for the loop filter 100kHz by default 16-07-06 |
235 | dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq); | 308 | static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) |
309 | { | ||
310 | struct dib0070_state *state = fe->tuner_priv; | ||
236 | 311 | ||
237 | switch (band) { | 312 | const struct dib0070_tuning *tune; |
238 | case BAND_VHF: | 313 | const struct dib0070_lna_match *lna_match; |
239 | REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000); | ||
240 | break; | ||
241 | case BAND_FM: | ||
242 | REFDIV = (u8) ((st->cfg->clock_khz) / 1000); | ||
243 | break; | ||
244 | default: | ||
245 | REFDIV = (u8) ( st->cfg->clock_khz / 10000); | ||
246 | break; | ||
247 | } | ||
248 | FREF = st->cfg->clock_khz / REFDIV; | ||
249 | 314 | ||
250 | dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF); | 315 | enum frontend_tune_state *tune_state = &state->tune_state; |
316 | int ret = 10; /* 1ms is the default delay most of the time */ | ||
251 | 317 | ||
318 | u8 band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); | ||
319 | u32 freq = fe->dtv_property_cache.frequency / 1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); | ||
252 | 320 | ||
321 | #ifdef CONFIG_SYS_ISDBT | ||
322 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) | ||
323 | if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) | ||
324 | && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) | ||
325 | || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) | ||
326 | && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2))) | ||
327 | || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) | ||
328 | && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) | ||
329 | freq += 850; | ||
330 | #endif | ||
331 | if (state->current_rf != freq) { | ||
253 | 332 | ||
254 | switch (st->revision) { | 333 | switch (state->revision) { |
255 | case DIB0070S_P1A: | 334 | case DIB0070S_P1A: |
256 | FBDiv = (VCOF_kHz / PRESC / FREF); | 335 | tune = dib0070s_tuning_table; |
257 | Rest = (VCOF_kHz / PRESC) - FBDiv * FREF; | 336 | lna_match = dib0070_lna; |
258 | break; | 337 | break; |
259 | |||
260 | case DIB0070_P1G: | ||
261 | case DIB0070_P1F: | ||
262 | default: | 338 | default: |
263 | FBDiv = (freq / (FREF / 2)); | 339 | tune = dib0070_tuning_table; |
264 | Rest = 2 * freq - FBDiv * FREF; | 340 | if (state->cfg->flip_chip) |
341 | lna_match = dib0070_lna_flip_chip; | ||
342 | else | ||
343 | lna_match = dib0070_lna; | ||
265 | break; | 344 | break; |
266 | } | 345 | } |
267 | 346 | while (freq > tune->max_freq) /* find the right one */ | |
268 | 347 | tune++; | |
269 | if (Rest < LPF) Rest = 0; | 348 | while (freq > lna_match->max_freq) /* find the right one */ |
270 | else if (Rest < 2 * LPF) Rest = 2 * LPF; | 349 | lna_match++; |
271 | else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; } | ||
272 | else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; | ||
273 | Rest = (Rest * 6528) / (FREF / 10); | ||
274 | dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest); | ||
275 | |||
276 | Num = 0; | ||
277 | Den = 1; | ||
278 | 350 | ||
279 | if (Rest > 0) { | 351 | state->current_tune_table_index = tune; |
280 | LO4_SET_SD(lo4, 1); | 352 | state->lna_match = lna_match; |
281 | Den = 255; | ||
282 | Num = (u16)Rest; | ||
283 | } | 353 | } |
284 | dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1); | ||
285 | 354 | ||
355 | if (*tune_state == CT_TUNER_START) { | ||
356 | dprintk("Tuning for Band: %hd (%d kHz)", band, freq); | ||
357 | if (state->current_rf != freq) { | ||
358 | u8 REFDIV; | ||
359 | u32 FBDiv, Rest, FREF, VCOF_kHz; | ||
360 | u8 Den; | ||
286 | 361 | ||
362 | state->current_rf = freq; | ||
363 | state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); | ||
287 | 364 | ||
288 | dib0070_write_reg(st, 0x11, (u16)FBDiv); | 365 | dib0070_write_reg(state, 0x17, 0x30); |
289 | 366 | ||
367 | VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; | ||
290 | 368 | ||
291 | dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV); | 369 | switch (band) { |
292 | 370 | case BAND_VHF: | |
371 | REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); | ||
372 | break; | ||
373 | case BAND_FM: | ||
374 | REFDIV = (u8) ((state->cfg->clock_khz) / 1000); | ||
375 | break; | ||
376 | default: | ||
377 | REFDIV = (u8) (state->cfg->clock_khz / 10000); | ||
378 | break; | ||
379 | } | ||
380 | FREF = state->cfg->clock_khz / REFDIV; | ||
381 | |||
382 | switch (state->revision) { | ||
383 | case DIB0070S_P1A: | ||
384 | FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); | ||
385 | Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; | ||
386 | break; | ||
387 | |||
388 | case DIB0070_P1G: | ||
389 | case DIB0070_P1F: | ||
390 | default: | ||
391 | FBDiv = (freq / (FREF / 2)); | ||
392 | Rest = 2 * freq - FBDiv * FREF; | ||
393 | break; | ||
394 | } | ||
293 | 395 | ||
294 | dib0070_write_reg(st, 0x13, Num); | 396 | if (Rest < LPF) |
397 | Rest = 0; | ||
398 | else if (Rest < 2 * LPF) | ||
399 | Rest = 2 * LPF; | ||
400 | else if (Rest > (FREF - LPF)) { | ||
401 | Rest = 0; | ||
402 | FBDiv += 1; | ||
403 | } else if (Rest > (FREF - 2 * LPF)) | ||
404 | Rest = FREF - 2 * LPF; | ||
405 | Rest = (Rest * 6528) / (FREF / 10); | ||
406 | |||
407 | Den = 1; | ||
408 | if (Rest > 0) { | ||
409 | state->lo4 |= (1 << 14) | (1 << 12); | ||
410 | Den = 255; | ||
411 | } | ||
295 | 412 | ||
413 | dib0070_write_reg(state, 0x11, (u16) FBDiv); | ||
414 | dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); | ||
415 | dib0070_write_reg(state, 0x13, (u16) Rest); | ||
296 | 416 | ||
297 | value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001; | 417 | if (state->revision == DIB0070S_P1A) { |
298 | 418 | ||
299 | switch (band) { | 419 | if (band == BAND_SBAND) { |
300 | case BAND_UHF: value |= 0x4000 | 0x0800; break; | 420 | dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); |
301 | case BAND_LBAND: value |= 0x2000 | 0x0400; break; | 421 | dib0070_write_reg(state, 0x1d, 0xFFFF); |
302 | default: value |= 0x8000 | 0x1000; break; | 422 | } else |
303 | } | 423 | dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); |
304 | dib0070_write_reg(st, 0x20, value); | 424 | } |
305 | 425 | ||
306 | dib0070_captrim(st, lo4); | 426 | dib0070_write_reg(state, 0x20, |
307 | if (st->revision == DIB0070S_P1A) { | 427 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); |
308 | if (band == BAND_SBAND) | ||
309 | dib0070_write_reg(st, 0x15, 0x16e2); | ||
310 | else | ||
311 | dib0070_write_reg(st, 0x15, 0x56e5); | ||
312 | } | ||
313 | 428 | ||
429 | dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); | ||
430 | dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); | ||
431 | dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); | ||
432 | dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); | ||
433 | dprintk("VCO = %hd", state->current_tune_table_index->vco_band); | ||
434 | dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); | ||
314 | 435 | ||
436 | *tune_state = CT_TUNER_STEP_0; | ||
437 | } else { /* we are already tuned to this frequency - the configuration is correct */ | ||
438 | ret = 50; /* wakeup time */ | ||
439 | *tune_state = CT_TUNER_STEP_5; | ||
440 | } | ||
441 | } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { | ||
442 | |||
443 | ret = dib0070_captrim(state, tune_state); | ||
444 | |||
445 | } else if (*tune_state == CT_TUNER_STEP_4) { | ||
446 | const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; | ||
447 | if (tmp != NULL) { | ||
448 | while (freq / 1000 > tmp->freq) /* find the right one */ | ||
449 | tmp++; | ||
450 | dib0070_write_reg(state, 0x0f, | ||
451 | (0 << 15) | (1 << 14) | (3 << 12) | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | (state-> | ||
452 | current_tune_table_index-> | ||
453 | wbdmux << 0)); | ||
454 | state->wbd_gain_current = tmp->wbd_gain_val; | ||
455 | } else { | ||
456 | dib0070_write_reg(state, 0x0f, | ||
457 | (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> | ||
458 | wbdmux << 0)); | ||
459 | state->wbd_gain_current = 6; | ||
460 | } | ||
315 | 461 | ||
316 | switch (band) { | 462 | dib0070_write_reg(state, 0x06, 0x3fff); |
317 | case BAND_UHF: value = 0x7c82; break; | 463 | dib0070_write_reg(state, 0x07, |
318 | case BAND_LBAND: value = 0x7c84; break; | 464 | (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); |
319 | default: value = 0x7c81; break; | 465 | dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); |
320 | } | 466 | dib0070_write_reg(state, 0x0d, 0x0d80); |
321 | dib0070_write_reg(st, 0x0f, value); | 467 | |
322 | dib0070_write_reg(st, 0x06, 0x3fff); | 468 | dib0070_write_reg(state, 0x18, 0x07ff); |
323 | 469 | dib0070_write_reg(state, 0x17, 0x0033); | |
324 | /* Front End */ | 470 | |
325 | /* c == TUNE, value = SWITCH */ | 471 | *tune_state = CT_TUNER_STEP_5; |
326 | c = 0; | 472 | } else if (*tune_state == CT_TUNER_STEP_5) { |
327 | value = 0; | 473 | dib0070_set_bandwidth(fe, ch); |
328 | switch (band) { | 474 | *tune_state = CT_TUNER_STOP; |
329 | case BAND_FM: | 475 | } else { |
330 | c = 0; value = 1; | 476 | ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ |
331 | break; | ||
332 | |||
333 | case BAND_VHF: | ||
334 | if (freq <= 180000) c = 0; | ||
335 | else if (freq <= 188200) c = 1; | ||
336 | else if (freq <= 196400) c = 2; | ||
337 | else c = 3; | ||
338 | value = 1; | ||
339 | break; | ||
340 | |||
341 | case BAND_LBAND: | ||
342 | if (freq <= 1500000) c = 0; | ||
343 | else if (freq <= 1600000) c = 1; | ||
344 | else c = 3; | ||
345 | break; | ||
346 | |||
347 | case BAND_SBAND: | ||
348 | c = 7; | ||
349 | dib0070_write_reg(st, 0x1d,0xFFFF); | ||
350 | break; | ||
351 | |||
352 | case BAND_UHF: | ||
353 | default: | ||
354 | if (st->cfg->flip_chip) { | ||
355 | if (freq <= 550000) c = 0; | ||
356 | else if (freq <= 590000) c = 1; | ||
357 | else if (freq <= 666000) c = 3; | ||
358 | else c = 5; | ||
359 | } else { | ||
360 | if (freq <= 550000) c = 2; | ||
361 | else if (freq <= 650000) c = 3; | ||
362 | else if (freq <= 750000) c = 5; | ||
363 | else if (freq <= 850000) c = 6; | ||
364 | else c = 7; | ||
365 | } | ||
366 | value = 2; | ||
367 | break; | ||
368 | } | 477 | } |
478 | return ret; | ||
479 | } | ||
369 | 480 | ||
370 | /* default: LNA_MATCH=7, BIAS=3 */ | 481 | static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) |
371 | dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0)); | 482 | { |
372 | dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127)); | 483 | struct dib0070_state *state = fe->tuner_priv; |
373 | dib0070_write_reg(st, 0x0d, 0x0d80); | 484 | uint32_t ret; |
374 | 485 | ||
486 | state->tune_state = CT_TUNER_START; | ||
375 | 487 | ||
376 | dib0070_write_reg(st, 0x18, 0x07ff); | 488 | do { |
377 | dib0070_write_reg(st, 0x17, 0x0033); | 489 | ret = dib0070_tune_digital(fe, p); |
490 | if (ret != FE_CALLBACK_TIME_NEVER) | ||
491 | msleep(ret / 10); | ||
492 | else | ||
493 | break; | ||
494 | } while (state->tune_state != CT_TUNER_STOP); | ||
378 | 495 | ||
379 | return 0; | 496 | return 0; |
380 | } | 497 | } |
381 | 498 | ||
382 | static int dib0070_wakeup(struct dvb_frontend *fe) | 499 | static int dib0070_wakeup(struct dvb_frontend *fe) |
383 | { | 500 | { |
384 | struct dib0070_state *st = fe->tuner_priv; | 501 | struct dib0070_state *state = fe->tuner_priv; |
385 | if (st->cfg->sleep) | 502 | if (state->cfg->sleep) |
386 | st->cfg->sleep(fe, 0); | 503 | state->cfg->sleep(fe, 0); |
387 | return 0; | 504 | return 0; |
388 | } | 505 | } |
389 | 506 | ||
390 | static int dib0070_sleep(struct dvb_frontend *fe) | 507 | static int dib0070_sleep(struct dvb_frontend *fe) |
391 | { | 508 | { |
392 | struct dib0070_state *st = fe->tuner_priv; | 509 | struct dib0070_state *state = fe->tuner_priv; |
393 | if (st->cfg->sleep) | 510 | if (state->cfg->sleep) |
394 | st->cfg->sleep(fe, 1); | 511 | state->cfg->sleep(fe, 1); |
395 | return 0; | 512 | return 0; |
396 | } | 513 | } |
397 | 514 | ||
398 | static u16 dib0070_p1f_defaults[] = | 515 | static const u16 dib0070_p1f_defaults[] = { |
399 | |||
400 | { | ||
401 | 7, 0x02, | 516 | 7, 0x02, |
402 | 0x0008, | 517 | 0x0008, |
403 | 0x0000, | 518 | 0x0000, |
404 | 0x0000, | 519 | 0x0000, |
405 | 0x0000, | 520 | 0x0000, |
406 | 0x0000, | 521 | 0x0000, |
407 | 0x0002, | 522 | 0x0002, |
408 | 0x0100, | 523 | 0x0100, |
409 | 524 | ||
410 | 3, 0x0d, | 525 | 3, 0x0d, |
411 | 0x0d80, | 526 | 0x0d80, |
412 | 0x0001, | 527 | 0x0001, |
413 | 0x0000, | 528 | 0x0000, |
414 | 529 | ||
415 | 4, 0x11, | 530 | 4, 0x11, |
416 | 0x0000, | 531 | 0x0000, |
417 | 0x0103, | 532 | 0x0103, |
418 | 0x0000, | 533 | 0x0000, |
419 | 0x0000, | 534 | 0x0000, |
420 | 535 | ||
421 | 3, 0x16, | 536 | 3, 0x16, |
422 | 0x0004 | 0x0040, | 537 | 0x0004 | 0x0040, |
423 | 0x0030, | 538 | 0x0030, |
424 | 0x07ff, | 539 | 0x07ff, |
425 | 540 | ||
426 | 6, 0x1b, | 541 | 6, 0x1b, |
427 | 0x4112, | 542 | 0x4112, |
428 | 0xff00, | 543 | 0xff00, |
429 | 0xc07f, | 544 | 0xc07f, |
430 | 0x0000, | 545 | 0x0000, |
431 | 0x0180, | 546 | 0x0180, |
432 | 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, | 547 | 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, |
433 | 548 | ||
434 | 0, | 549 | 0, |
435 | }; | 550 | }; |
436 | 551 | ||
437 | static void dib0070_wbd_calibration(struct dvb_frontend *fe) | 552 | static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) |
438 | { | 553 | { |
439 | u16 wbd_offs; | 554 | u16 tuner_en = dib0070_read_reg(state, 0x20); |
440 | struct dib0070_state *state = fe->tuner_priv; | 555 | u16 offset; |
441 | |||
442 | if (state->cfg->sleep) | ||
443 | state->cfg->sleep(fe, 0); | ||
444 | 556 | ||
445 | dib0070_write_reg(state, 0x0f, 0x6d81); | 557 | dib0070_write_reg(state, 0x18, 0x07ff); |
446 | dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); | 558 | dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); |
559 | dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); | ||
447 | msleep(9); | 560 | msleep(9); |
448 | wbd_offs = dib0070_read_reg(state, 0x19); | 561 | offset = dib0070_read_reg(state, 0x19); |
449 | dib0070_write_reg(state, 0x20, 0); | 562 | dib0070_write_reg(state, 0x20, tuner_en); |
450 | state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); | 563 | return offset; |
451 | dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); | ||
452 | |||
453 | if (state->cfg->sleep) | ||
454 | state->cfg->sleep(fe, 1); | ||
455 | |||
456 | } | 564 | } |
457 | 565 | ||
458 | u16 dib0070_wbd_offset(struct dvb_frontend *fe) | 566 | static void dib0070_wbd_offset_calibration(struct dib0070_state *state) |
459 | { | 567 | { |
460 | struct dib0070_state *st = fe->tuner_priv; | 568 | u8 gain; |
461 | return st->wbd_ff_offset; | 569 | for (gain = 6; gain < 8; gain++) { |
570 | state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); | ||
571 | dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain - 6]); | ||
572 | } | ||
462 | } | 573 | } |
463 | 574 | ||
464 | EXPORT_SYMBOL(dib0070_wbd_offset); | 575 | u16 dib0070_wbd_offset(struct dvb_frontend *fe) |
465 | static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) | ||
466 | { | 576 | { |
467 | struct dib0070_state *state = fe->tuner_priv; | 577 | struct dib0070_state *state = fe->tuner_priv; |
468 | u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); | 578 | const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; |
469 | dprintk( "CTRL_LO5: 0x%x", lo5); | 579 | u32 freq = fe->dtv_property_cache.frequency / 1000; |
470 | return dib0070_write_reg(state, 0x15, lo5); | 580 | |
581 | if (tmp != NULL) { | ||
582 | while (freq / 1000 > tmp->freq) /* find the right one */ | ||
583 | tmp++; | ||
584 | state->wbd_gain_current = tmp->wbd_gain_val; | ||
585 | } else | ||
586 | state->wbd_gain_current = 6; | ||
587 | |||
588 | return state->wbd_offset_3_3[state->wbd_gain_current - 6]; | ||
471 | } | 589 | } |
472 | 590 | ||
591 | EXPORT_SYMBOL(dib0070_wbd_offset); | ||
592 | |||
473 | #define pgm_read_word(w) (*w) | 593 | #define pgm_read_word(w) (*w) |
474 | static int dib0070_reset(struct dib0070_state *state) | 594 | static int dib0070_reset(struct dvb_frontend *fe) |
475 | { | 595 | { |
596 | struct dib0070_state *state = fe->tuner_priv; | ||
476 | u16 l, r, *n; | 597 | u16 l, r, *n; |
477 | 598 | ||
478 | HARD_RESET(state); | 599 | HARD_RESET(state); |
479 | 600 | ||
480 | |||
481 | #ifndef FORCE_SBAND_TUNER | 601 | #ifndef FORCE_SBAND_TUNER |
482 | if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) | 602 | if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) |
483 | state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; | 603 | state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; |
484 | else | 604 | else |
605 | #else | ||
606 | #warning forcing SBAND | ||
485 | #endif | 607 | #endif |
486 | state->revision = DIB0070S_P1A; | 608 | state->revision = DIB0070S_P1A; |
487 | 609 | ||
488 | /* P1F or not */ | 610 | /* P1F or not */ |
489 | dprintk( "Revision: %x", state->revision); | 611 | dprintk("Revision: %x", state->revision); |
490 | 612 | ||
491 | if (state->revision == DIB0070_P1D) { | 613 | if (state->revision == DIB0070_P1D) { |
492 | dprintk( "Error: this driver is not to be used meant for P1D or earlier"); | 614 | dprintk("Error: this driver is not to be used meant for P1D or earlier"); |
493 | return -EINVAL; | 615 | return -EINVAL; |
494 | } | 616 | } |
495 | 617 | ||
@@ -498,7 +620,7 @@ static int dib0070_reset(struct dib0070_state *state) | |||
498 | while (l) { | 620 | while (l) { |
499 | r = pgm_read_word(n++); | 621 | r = pgm_read_word(n++); |
500 | do { | 622 | do { |
501 | dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); | 623 | dib0070_write_reg(state, (u8) r, pgm_read_word(n++)); |
502 | r++; | 624 | r++; |
503 | } while (--l); | 625 | } while (--l); |
504 | l = pgm_read_word(n++); | 626 | l = pgm_read_word(n++); |
@@ -514,24 +636,25 @@ static int dib0070_reset(struct dib0070_state *state) | |||
514 | r |= state->cfg->osc_buffer_state << 3; | 636 | r |= state->cfg->osc_buffer_state << 3; |
515 | 637 | ||
516 | dib0070_write_reg(state, 0x10, r); | 638 | dib0070_write_reg(state, 0x10, r); |
517 | dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4)); | 639 | dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5)); |
518 | 640 | ||
519 | if (state->cfg->invert_iq) { | 641 | if (state->cfg->invert_iq) { |
520 | r = dib0070_read_reg(state, 0x02) & 0xffdf; | 642 | r = dib0070_read_reg(state, 0x02) & 0xffdf; |
521 | dib0070_write_reg(state, 0x02, r | (1 << 5)); | 643 | dib0070_write_reg(state, 0x02, r | (1 << 5)); |
522 | } | 644 | } |
523 | 645 | ||
524 | |||
525 | if (state->revision == DIB0070S_P1A) | 646 | if (state->revision == DIB0070S_P1A) |
526 | dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1); | 647 | dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); |
527 | else | 648 | else |
528 | dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0); | 649 | dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); |
529 | 650 | ||
530 | dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); | 651 | dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); |
652 | |||
653 | dib0070_wbd_offset_calibration(state); | ||
654 | |||
531 | return 0; | 655 | return 0; |
532 | } | 656 | } |
533 | 657 | ||
534 | |||
535 | static int dib0070_release(struct dvb_frontend *fe) | 658 | static int dib0070_release(struct dvb_frontend *fe) |
536 | { | 659 | { |
537 | kfree(fe->tuner_priv); | 660 | kfree(fe->tuner_priv); |
@@ -539,23 +662,24 @@ static int dib0070_release(struct dvb_frontend *fe) | |||
539 | return 0; | 662 | return 0; |
540 | } | 663 | } |
541 | 664 | ||
542 | static struct dvb_tuner_ops dib0070_ops = { | 665 | static const struct dvb_tuner_ops dib0070_ops = { |
543 | .info = { | 666 | .info = { |
544 | .name = "DiBcom DiB0070", | 667 | .name = "DiBcom DiB0070", |
545 | .frequency_min = 45000000, | 668 | .frequency_min = 45000000, |
546 | .frequency_max = 860000000, | 669 | .frequency_max = 860000000, |
547 | .frequency_step = 1000, | 670 | .frequency_step = 1000, |
548 | }, | 671 | }, |
549 | .release = dib0070_release, | 672 | .release = dib0070_release, |
550 | 673 | ||
551 | .init = dib0070_wakeup, | 674 | .init = dib0070_wakeup, |
552 | .sleep = dib0070_sleep, | 675 | .sleep = dib0070_sleep, |
553 | .set_params = dib0070_tune_digital, | 676 | .set_params = dib0070_tune, |
554 | // .get_frequency = dib0070_get_frequency, | 677 | |
555 | // .get_bandwidth = dib0070_get_bandwidth | 678 | // .get_frequency = dib0070_get_frequency, |
679 | // .get_bandwidth = dib0070_get_bandwidth | ||
556 | }; | 680 | }; |
557 | 681 | ||
558 | struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) | 682 | struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) |
559 | { | 683 | { |
560 | struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); | 684 | struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); |
561 | if (state == NULL) | 685 | if (state == NULL) |
@@ -563,25 +687,24 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter | |||
563 | 687 | ||
564 | state->cfg = cfg; | 688 | state->cfg = cfg; |
565 | state->i2c = i2c; | 689 | state->i2c = i2c; |
566 | state->fe = fe; | 690 | state->fe = fe; |
567 | fe->tuner_priv = state; | 691 | fe->tuner_priv = state; |
568 | 692 | ||
569 | if (dib0070_reset(state) != 0) | 693 | if (dib0070_reset(fe) != 0) |
570 | goto free_mem; | 694 | goto free_mem; |
571 | 695 | ||
572 | dib0070_wbd_calibration(fe); | ||
573 | |||
574 | printk(KERN_INFO "DiB0070: successfully identified\n"); | 696 | printk(KERN_INFO "DiB0070: successfully identified\n"); |
575 | memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); | 697 | memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); |
576 | 698 | ||
577 | fe->tuner_priv = state; | 699 | fe->tuner_priv = state; |
578 | return fe; | 700 | return fe; |
579 | 701 | ||
580 | free_mem: | 702 | free_mem: |
581 | kfree(state); | 703 | kfree(state); |
582 | fe->tuner_priv = NULL; | 704 | fe->tuner_priv = NULL; |
583 | return NULL; | 705 | return NULL; |
584 | } | 706 | } |
707 | |||
585 | EXPORT_SYMBOL(dib0070_attach); | 708 | EXPORT_SYMBOL(dib0070_attach); |
586 | 709 | ||
587 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | 710 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); |
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h index 9670f5d20cfb..8a2e1e710adb 100644 --- a/drivers/media/dvb/frontends/dib0070.h +++ b/drivers/media/dvb/frontends/dib0070.h | |||
@@ -15,6 +15,11 @@ struct i2c_adapter; | |||
15 | 15 | ||
16 | #define DEFAULT_DIB0070_I2C_ADDRESS 0x60 | 16 | #define DEFAULT_DIB0070_I2C_ADDRESS 0x60 |
17 | 17 | ||
18 | struct dib0070_wbd_gain_cfg { | ||
19 | u16 freq; | ||
20 | u16 wbd_gain_val; | ||
21 | }; | ||
22 | |||
18 | struct dib0070_config { | 23 | struct dib0070_config { |
19 | u8 i2c_address; | 24 | u8 i2c_address; |
20 | 25 | ||
@@ -26,26 +31,28 @@ struct dib0070_config { | |||
26 | int freq_offset_khz_uhf; | 31 | int freq_offset_khz_uhf; |
27 | int freq_offset_khz_vhf; | 32 | int freq_offset_khz_vhf; |
28 | 33 | ||
29 | u8 osc_buffer_state; /* 0= normal, 1= tri-state */ | 34 | u8 osc_buffer_state; /* 0= normal, 1= tri-state */ |
30 | u32 clock_khz; | 35 | u32 clock_khz; |
31 | u8 clock_pad_drive; /* (Drive + 1) * 2mA */ | 36 | u8 clock_pad_drive; /* (Drive + 1) * 2mA */ |
32 | 37 | ||
33 | u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ | 38 | u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ |
34 | 39 | ||
35 | u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ | 40 | u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ |
36 | 41 | ||
37 | u8 flip_chip; | 42 | u8 flip_chip; |
43 | u8 enable_third_order_filter; | ||
44 | u8 charge_pump; | ||
45 | |||
46 | const struct dib0070_wbd_gain_cfg *wbd_gain; | ||
47 | |||
48 | u8 vga_filter; | ||
38 | }; | 49 | }; |
39 | 50 | ||
40 | #if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE)) | 51 | #if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE)) |
41 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | 52 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); |
42 | struct i2c_adapter *i2c, | ||
43 | struct dib0070_config *cfg); | ||
44 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); | 53 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); |
45 | #else | 54 | #else |
46 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | 55 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) |
47 | struct i2c_adapter *i2c, | ||
48 | struct dib0070_config *cfg) | ||
49 | { | 56 | { |
50 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 57 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
51 | return NULL; | 58 | return NULL; |
@@ -57,5 +64,6 @@ static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) | |||
57 | return -ENODEV; | 64 | return -ENODEV; |
58 | } | 65 | } |
59 | #endif | 66 | #endif |
67 | extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); | ||
60 | 68 | ||
61 | #endif | 69 | #endif |
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index fc96fbf03d6d..55ef6eeb0769 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/i2c.h> | 11 | #include <linux/i2c.h> |
12 | 12 | ||
13 | #include "dvb_math.h" | ||
13 | #include "dvb_frontend.h" | 14 | #include "dvb_frontend.h" |
14 | 15 | ||
15 | #include "dib7000p.h" | 16 | #include "dib7000p.h" |
@@ -1217,7 +1218,37 @@ static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | |||
1217 | 1218 | ||
1218 | static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr) | 1219 | static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr) |
1219 | { | 1220 | { |
1220 | *snr = 0x0000; | 1221 | struct dib7000p_state *state = fe->demodulator_priv; |
1222 | u16 val; | ||
1223 | s32 signal_mant, signal_exp, noise_mant, noise_exp; | ||
1224 | u32 result = 0; | ||
1225 | |||
1226 | val = dib7000p_read_word(state, 479); | ||
1227 | noise_mant = (val >> 4) & 0xff; | ||
1228 | noise_exp = ((val & 0xf) << 2); | ||
1229 | val = dib7000p_read_word(state, 480); | ||
1230 | noise_exp += ((val >> 14) & 0x3); | ||
1231 | if ((noise_exp & 0x20) != 0) | ||
1232 | noise_exp -= 0x40; | ||
1233 | |||
1234 | signal_mant = (val >> 6) & 0xFF; | ||
1235 | signal_exp = (val & 0x3F); | ||
1236 | if ((signal_exp & 0x20) != 0) | ||
1237 | signal_exp -= 0x40; | ||
1238 | |||
1239 | if (signal_mant != 0) | ||
1240 | result = intlog10(2) * 10 * signal_exp + 10 * | ||
1241 | intlog10(signal_mant); | ||
1242 | else | ||
1243 | result = intlog10(2) * 10 * signal_exp - 100; | ||
1244 | |||
1245 | if (noise_mant != 0) | ||
1246 | result -= intlog10(2) * 10 * noise_exp + 10 * | ||
1247 | intlog10(noise_mant); | ||
1248 | else | ||
1249 | result -= intlog10(2) * 10 * noise_exp - 100; | ||
1250 | |||
1251 | *snr = result / ((1 << 24) / 10); | ||
1221 | return 0; | 1252 | return 0; |
1222 | } | 1253 | } |
1223 | 1254 | ||
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c new file mode 100644 index 000000000000..852c790d09d9 --- /dev/null +++ b/drivers/media/dvb/frontends/dib8000.c | |||
@@ -0,0 +1,2277 @@ | |||
1 | /* | ||
2 | * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T). | ||
3 | * | ||
4 | * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/) | ||
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 as | ||
8 | * published by the Free Software Foundation, version 2. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/i2c.h> | ||
12 | #include "dvb_math.h" | ||
13 | |||
14 | #include "dvb_frontend.h" | ||
15 | |||
16 | #include "dib8000.h" | ||
17 | |||
18 | #define LAYER_ALL -1 | ||
19 | #define LAYER_A 1 | ||
20 | #define LAYER_B 2 | ||
21 | #define LAYER_C 3 | ||
22 | |||
23 | #define FE_CALLBACK_TIME_NEVER 0xffffffff | ||
24 | |||
25 | static int debug; | ||
26 | module_param(debug, int, 0644); | ||
27 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | ||
28 | |||
29 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) | ||
30 | |||
31 | enum frontend_tune_state { | ||
32 | CT_AGC_START = 20, | ||
33 | CT_AGC_STEP_0, | ||
34 | CT_AGC_STEP_1, | ||
35 | CT_AGC_STEP_2, | ||
36 | CT_AGC_STEP_3, | ||
37 | CT_AGC_STEP_4, | ||
38 | CT_AGC_STOP, | ||
39 | |||
40 | CT_DEMOD_START = 30, | ||
41 | }; | ||
42 | |||
43 | #define FE_STATUS_TUNE_FAILED 0 | ||
44 | |||
45 | struct i2c_device { | ||
46 | struct i2c_adapter *adap; | ||
47 | u8 addr; | ||
48 | }; | ||
49 | |||
50 | struct dib8000_state { | ||
51 | struct dvb_frontend fe; | ||
52 | struct dib8000_config cfg; | ||
53 | |||
54 | struct i2c_device i2c; | ||
55 | |||
56 | struct dibx000_i2c_master i2c_master; | ||
57 | |||
58 | u16 wbd_ref; | ||
59 | |||
60 | u8 current_band; | ||
61 | u32 current_bandwidth; | ||
62 | struct dibx000_agc_config *current_agc; | ||
63 | u32 timf; | ||
64 | u32 timf_default; | ||
65 | |||
66 | u8 div_force_off:1; | ||
67 | u8 div_state:1; | ||
68 | u16 div_sync_wait; | ||
69 | |||
70 | u8 agc_state; | ||
71 | u8 differential_constellation; | ||
72 | u8 diversity_onoff; | ||
73 | |||
74 | s16 ber_monitored_layer; | ||
75 | u16 gpio_dir; | ||
76 | u16 gpio_val; | ||
77 | |||
78 | u16 revision; | ||
79 | u8 isdbt_cfg_loaded; | ||
80 | enum frontend_tune_state tune_state; | ||
81 | u32 status; | ||
82 | }; | ||
83 | |||
84 | enum dib8000_power_mode { | ||
85 | DIB8000M_POWER_ALL = 0, | ||
86 | DIB8000M_POWER_INTERFACE_ONLY, | ||
87 | }; | ||
88 | |||
89 | static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) | ||
90 | { | ||
91 | u8 wb[2] = { reg >> 8, reg & 0xff }; | ||
92 | u8 rb[2]; | ||
93 | struct i2c_msg msg[2] = { | ||
94 | {.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2}, | ||
95 | {.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2}, | ||
96 | }; | ||
97 | |||
98 | if (i2c_transfer(i2c->adap, msg, 2) != 2) | ||
99 | dprintk("i2c read error on %d", reg); | ||
100 | |||
101 | return (rb[0] << 8) | rb[1]; | ||
102 | } | ||
103 | |||
104 | static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) | ||
105 | { | ||
106 | return dib8000_i2c_read16(&state->i2c, reg); | ||
107 | } | ||
108 | |||
109 | static u32 dib8000_read32(struct dib8000_state *state, u16 reg) | ||
110 | { | ||
111 | u16 rw[2]; | ||
112 | |||
113 | rw[0] = dib8000_read_word(state, reg + 0); | ||
114 | rw[1] = dib8000_read_word(state, reg + 1); | ||
115 | |||
116 | return ((rw[0] << 16) | (rw[1])); | ||
117 | } | ||
118 | |||
119 | static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) | ||
120 | { | ||
121 | u8 b[4] = { | ||
122 | (reg >> 8) & 0xff, reg & 0xff, | ||
123 | (val >> 8) & 0xff, val & 0xff, | ||
124 | }; | ||
125 | struct i2c_msg msg = { | ||
126 | .addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4 | ||
127 | }; | ||
128 | return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; | ||
129 | } | ||
130 | |||
131 | static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) | ||
132 | { | ||
133 | return dib8000_i2c_write16(&state->i2c, reg, val); | ||
134 | } | ||
135 | |||
136 | const int16_t coeff_2k_sb_1seg_dqpsk[8] = { | ||
137 | (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, | ||
138 | (920 << 5) | 0x09 | ||
139 | }; | ||
140 | |||
141 | const int16_t coeff_2k_sb_1seg[8] = { | ||
142 | (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f | ||
143 | }; | ||
144 | |||
145 | const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { | ||
146 | (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, | ||
147 | (-931 << 5) | 0x0f | ||
148 | }; | ||
149 | |||
150 | const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { | ||
151 | (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, | ||
152 | (982 << 5) | 0x0c | ||
153 | }; | ||
154 | |||
155 | const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { | ||
156 | (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, | ||
157 | (-720 << 5) | 0x0d | ||
158 | }; | ||
159 | |||
160 | const int16_t coeff_2k_sb_3seg[8] = { | ||
161 | (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, | ||
162 | (-610 << 5) | 0x0a | ||
163 | }; | ||
164 | |||
165 | const int16_t coeff_4k_sb_1seg_dqpsk[8] = { | ||
166 | (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, | ||
167 | (-922 << 5) | 0x0d | ||
168 | }; | ||
169 | |||
170 | const int16_t coeff_4k_sb_1seg[8] = { | ||
171 | (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, | ||
172 | (-655 << 5) | 0x0a | ||
173 | }; | ||
174 | |||
175 | const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { | ||
176 | (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, | ||
177 | (-958 << 5) | 0x13 | ||
178 | }; | ||
179 | |||
180 | const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { | ||
181 | (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, | ||
182 | (-568 << 5) | 0x0f | ||
183 | }; | ||
184 | |||
185 | const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { | ||
186 | (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, | ||
187 | (-848 << 5) | 0x13 | ||
188 | }; | ||
189 | |||
190 | const int16_t coeff_4k_sb_3seg[8] = { | ||
191 | (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, | ||
192 | (-869 << 5) | 0x13 | ||
193 | }; | ||
194 | |||
195 | const int16_t coeff_8k_sb_1seg_dqpsk[8] = { | ||
196 | (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, | ||
197 | (-598 << 5) | 0x10 | ||
198 | }; | ||
199 | |||
200 | const int16_t coeff_8k_sb_1seg[8] = { | ||
201 | (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, | ||
202 | (585 << 5) | 0x0f | ||
203 | }; | ||
204 | |||
205 | const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { | ||
206 | (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, | ||
207 | (0 << 5) | 0x14 | ||
208 | }; | ||
209 | |||
210 | const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { | ||
211 | (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, | ||
212 | (-877 << 5) | 0x15 | ||
213 | }; | ||
214 | |||
215 | const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { | ||
216 | (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, | ||
217 | (-921 << 5) | 0x14 | ||
218 | }; | ||
219 | |||
220 | const int16_t coeff_8k_sb_3seg[8] = { | ||
221 | (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, | ||
222 | (690 << 5) | 0x14 | ||
223 | }; | ||
224 | |||
225 | const int16_t ana_fe_coeff_3seg[24] = { | ||
226 | 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 | ||
227 | }; | ||
228 | |||
229 | const int16_t ana_fe_coeff_1seg[24] = { | ||
230 | 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 | ||
231 | }; | ||
232 | |||
233 | const int16_t ana_fe_coeff_13seg[24] = { | ||
234 | 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 | ||
235 | }; | ||
236 | |||
237 | static u16 fft_to_mode(struct dib8000_state *state) | ||
238 | { | ||
239 | u16 mode; | ||
240 | switch (state->fe.dtv_property_cache.transmission_mode) { | ||
241 | case TRANSMISSION_MODE_2K: | ||
242 | mode = 1; | ||
243 | break; | ||
244 | case TRANSMISSION_MODE_4K: | ||
245 | mode = 2; | ||
246 | break; | ||
247 | default: | ||
248 | case TRANSMISSION_MODE_AUTO: | ||
249 | case TRANSMISSION_MODE_8K: | ||
250 | mode = 3; | ||
251 | break; | ||
252 | } | ||
253 | return mode; | ||
254 | } | ||
255 | |||
256 | static void dib8000_set_acquisition_mode(struct dib8000_state *state) | ||
257 | { | ||
258 | u16 nud = dib8000_read_word(state, 298); | ||
259 | nud |= (1 << 3) | (1 << 0); | ||
260 | dprintk("acquisition mode activated"); | ||
261 | dib8000_write_word(state, 298, nud); | ||
262 | } | ||
263 | |||
264 | static int dib8000_set_output_mode(struct dib8000_state *state, int mode) | ||
265 | { | ||
266 | u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ | ||
267 | |||
268 | outreg = 0; | ||
269 | fifo_threshold = 1792; | ||
270 | smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); | ||
271 | |||
272 | dprintk("-I- Setting output mode for demod %p to %d", &state->fe, mode); | ||
273 | |||
274 | switch (mode) { | ||
275 | case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock | ||
276 | outreg = (1 << 10); /* 0x0400 */ | ||
277 | break; | ||
278 | case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock | ||
279 | outreg = (1 << 10) | (1 << 6); /* 0x0440 */ | ||
280 | break; | ||
281 | case OUTMODE_MPEG2_SERIAL: // STBs with serial input | ||
282 | outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ | ||
283 | break; | ||
284 | case OUTMODE_DIVERSITY: | ||
285 | if (state->cfg.hostbus_diversity) { | ||
286 | outreg = (1 << 10) | (4 << 6); /* 0x0500 */ | ||
287 | sram &= 0xfdff; | ||
288 | } else | ||
289 | sram |= 0x0c00; | ||
290 | break; | ||
291 | case OUTMODE_MPEG2_FIFO: // e.g. USB feeding | ||
292 | smo_mode |= (3 << 1); | ||
293 | fifo_threshold = 512; | ||
294 | outreg = (1 << 10) | (5 << 6); | ||
295 | break; | ||
296 | case OUTMODE_HIGH_Z: // disable | ||
297 | outreg = 0; | ||
298 | break; | ||
299 | |||
300 | case OUTMODE_ANALOG_ADC: | ||
301 | outreg = (1 << 10) | (3 << 6); | ||
302 | dib8000_set_acquisition_mode(state); | ||
303 | break; | ||
304 | |||
305 | default: | ||
306 | dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe); | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | |||
310 | if (state->cfg.output_mpeg2_in_188_bytes) | ||
311 | smo_mode |= (1 << 5); | ||
312 | |||
313 | dib8000_write_word(state, 299, smo_mode); | ||
314 | dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */ | ||
315 | dib8000_write_word(state, 1286, outreg); | ||
316 | dib8000_write_word(state, 1291, sram); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) | ||
322 | { | ||
323 | struct dib8000_state *state = fe->demodulator_priv; | ||
324 | u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0; | ||
325 | |||
326 | if (!state->differential_constellation) { | ||
327 | dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 | ||
328 | dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 | ||
329 | } else { | ||
330 | dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0 | ||
331 | dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0 | ||
332 | } | ||
333 | state->diversity_onoff = onoff; | ||
334 | |||
335 | switch (onoff) { | ||
336 | case 0: /* only use the internal way - not the diversity input */ | ||
337 | dib8000_write_word(state, 270, 1); | ||
338 | dib8000_write_word(state, 271, 0); | ||
339 | break; | ||
340 | case 1: /* both ways */ | ||
341 | dib8000_write_word(state, 270, 6); | ||
342 | dib8000_write_word(state, 271, 6); | ||
343 | break; | ||
344 | case 2: /* only the diversity input */ | ||
345 | dib8000_write_word(state, 270, 0); | ||
346 | dib8000_write_word(state, 271, 1); | ||
347 | break; | ||
348 | } | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode) | ||
353 | { | ||
354 | /* by default everything is going to be powered off */ | ||
355 | u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, | ||
356 | reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; | ||
357 | |||
358 | /* now, depending on the requested mode, we power on */ | ||
359 | switch (mode) { | ||
360 | /* power up everything in the demod */ | ||
361 | case DIB8000M_POWER_ALL: | ||
362 | reg_774 = 0x0000; | ||
363 | reg_775 = 0x0000; | ||
364 | reg_776 = 0x0000; | ||
365 | reg_900 &= 0xfffc; | ||
366 | reg_1280 &= 0x00ff; | ||
367 | break; | ||
368 | case DIB8000M_POWER_INTERFACE_ONLY: | ||
369 | reg_1280 &= 0x00ff; | ||
370 | break; | ||
371 | } | ||
372 | |||
373 | dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280); | ||
374 | dib8000_write_word(state, 774, reg_774); | ||
375 | dib8000_write_word(state, 775, reg_775); | ||
376 | dib8000_write_word(state, 776, reg_776); | ||
377 | dib8000_write_word(state, 900, reg_900); | ||
378 | dib8000_write_word(state, 1280, reg_1280); | ||
379 | } | ||
380 | |||
381 | static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) | ||
382 | { | ||
383 | int ret = 0; | ||
384 | u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908); | ||
385 | |||
386 | switch (no) { | ||
387 | case DIBX000_SLOW_ADC_ON: | ||
388 | reg_908 |= (1 << 1) | (1 << 0); | ||
389 | ret |= dib8000_write_word(state, 908, reg_908); | ||
390 | reg_908 &= ~(1 << 1); | ||
391 | break; | ||
392 | |||
393 | case DIBX000_SLOW_ADC_OFF: | ||
394 | reg_908 |= (1 << 1) | (1 << 0); | ||
395 | break; | ||
396 | |||
397 | case DIBX000_ADC_ON: | ||
398 | reg_907 &= 0x0fff; | ||
399 | reg_908 &= 0x0003; | ||
400 | break; | ||
401 | |||
402 | case DIBX000_ADC_OFF: // leave the VBG voltage on | ||
403 | reg_907 |= (1 << 14) | (1 << 13) | (1 << 12); | ||
404 | reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); | ||
405 | break; | ||
406 | |||
407 | case DIBX000_VBG_ENABLE: | ||
408 | reg_907 &= ~(1 << 15); | ||
409 | break; | ||
410 | |||
411 | case DIBX000_VBG_DISABLE: | ||
412 | reg_907 |= (1 << 15); | ||
413 | break; | ||
414 | |||
415 | default: | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | ret |= dib8000_write_word(state, 907, reg_907); | ||
420 | ret |= dib8000_write_word(state, 908, reg_908); | ||
421 | |||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | static int dib8000_set_bandwidth(struct dib8000_state *state, u32 bw) | ||
426 | { | ||
427 | u32 timf; | ||
428 | |||
429 | if (bw == 0) | ||
430 | bw = 6000; | ||
431 | |||
432 | if (state->timf == 0) { | ||
433 | dprintk("using default timf"); | ||
434 | timf = state->timf_default; | ||
435 | } else { | ||
436 | dprintk("using updated timf"); | ||
437 | timf = state->timf; | ||
438 | } | ||
439 | |||
440 | dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff)); | ||
441 | dib8000_write_word(state, 30, (u16) ((timf) & 0xffff)); | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static int dib8000_sad_calib(struct dib8000_state *state) | ||
447 | { | ||
448 | /* internal */ | ||
449 | dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); | ||
450 | dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096 | ||
451 | |||
452 | /* do the calibration */ | ||
453 | dib8000_write_word(state, 923, (1 << 0)); | ||
454 | dib8000_write_word(state, 923, (0 << 0)); | ||
455 | |||
456 | msleep(1); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) | ||
461 | { | ||
462 | struct dib8000_state *state = fe->demodulator_priv; | ||
463 | if (value > 4095) | ||
464 | value = 4095; | ||
465 | state->wbd_ref = value; | ||
466 | return dib8000_write_word(state, 106, value); | ||
467 | } | ||
468 | |||
469 | EXPORT_SYMBOL(dib8000_set_wbd_ref); | ||
470 | static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) | ||
471 | { | ||
472 | dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); | ||
473 | dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */ | ||
474 | dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff)); | ||
475 | dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); | ||
476 | dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); | ||
477 | dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); | ||
478 | |||
479 | dib8000_write_word(state, 922, bw->sad_cfg); | ||
480 | } | ||
481 | |||
482 | static void dib8000_reset_pll(struct dib8000_state *state) | ||
483 | { | ||
484 | const struct dibx000_bandwidth_config *pll = state->cfg.pll; | ||
485 | u16 clk_cfg1; | ||
486 | |||
487 | // clk_cfg0 | ||
488 | dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); | ||
489 | |||
490 | // clk_cfg1 | ||
491 | clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | | ||
492 | (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | (pll->pll_range << 1) | (pll->pll_reset << 0); | ||
493 | |||
494 | dib8000_write_word(state, 902, clk_cfg1); | ||
495 | clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); | ||
496 | dib8000_write_word(state, 902, clk_cfg1); | ||
497 | |||
498 | dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */ | ||
499 | |||
500 | /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ | ||
501 | if (state->cfg.pll->ADClkSrc == 0) | ||
502 | dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); | ||
503 | else if (state->cfg.refclksel != 0) | ||
504 | dib8000_write_word(state, 904, | ||
505 | (0 << 15) | (1 << 12) | ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | (pll-> | ||
506 | ADClkSrc << 7) | (0 << 1)); | ||
507 | else | ||
508 | dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); | ||
509 | |||
510 | dib8000_reset_pll_common(state, pll); | ||
511 | } | ||
512 | |||
513 | static int dib8000_reset_gpio(struct dib8000_state *st) | ||
514 | { | ||
515 | /* reset the GPIOs */ | ||
516 | dib8000_write_word(st, 1029, st->cfg.gpio_dir); | ||
517 | dib8000_write_word(st, 1030, st->cfg.gpio_val); | ||
518 | |||
519 | /* TODO 782 is P_gpio_od */ | ||
520 | |||
521 | dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos); | ||
522 | |||
523 | dib8000_write_word(st, 1037, st->cfg.pwm_freq_div); | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val) | ||
528 | { | ||
529 | st->cfg.gpio_dir = dib8000_read_word(st, 1029); | ||
530 | st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */ | ||
531 | st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */ | ||
532 | dib8000_write_word(st, 1029, st->cfg.gpio_dir); | ||
533 | |||
534 | st->cfg.gpio_val = dib8000_read_word(st, 1030); | ||
535 | st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */ | ||
536 | st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */ | ||
537 | dib8000_write_word(st, 1030, st->cfg.gpio_val); | ||
538 | |||
539 | dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val); | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) | ||
545 | { | ||
546 | struct dib8000_state *state = fe->demodulator_priv; | ||
547 | return dib8000_cfg_gpio(state, num, dir, val); | ||
548 | } | ||
549 | |||
550 | EXPORT_SYMBOL(dib8000_set_gpio); | ||
551 | static const u16 dib8000_defaults[] = { | ||
552 | /* auto search configuration - lock0 by default waiting | ||
553 | * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */ | ||
554 | 3, 7, | ||
555 | 0x0004, | ||
556 | 0x0400, | ||
557 | 0x0814, | ||
558 | |||
559 | 12, 11, | ||
560 | 0x001b, | ||
561 | 0x7740, | ||
562 | 0x005b, | ||
563 | 0x8d80, | ||
564 | 0x01c9, | ||
565 | 0xc380, | ||
566 | 0x0000, | ||
567 | 0x0080, | ||
568 | 0x0000, | ||
569 | 0x0090, | ||
570 | 0x0001, | ||
571 | 0xd4c0, | ||
572 | |||
573 | /*1, 32, | ||
574 | 0x6680 // P_corm_thres Lock algorithms configuration */ | ||
575 | |||
576 | 11, 80, /* set ADC level to -16 */ | ||
577 | (1 << 13) - 825 - 117, | ||
578 | (1 << 13) - 837 - 117, | ||
579 | (1 << 13) - 811 - 117, | ||
580 | (1 << 13) - 766 - 117, | ||
581 | (1 << 13) - 737 - 117, | ||
582 | (1 << 13) - 693 - 117, | ||
583 | (1 << 13) - 648 - 117, | ||
584 | (1 << 13) - 619 - 117, | ||
585 | (1 << 13) - 575 - 117, | ||
586 | (1 << 13) - 531 - 117, | ||
587 | (1 << 13) - 501 - 117, | ||
588 | |||
589 | 4, 108, | ||
590 | 0, | ||
591 | 0, | ||
592 | 0, | ||
593 | 0, | ||
594 | |||
595 | 1, 175, | ||
596 | 0x0410, | ||
597 | 1, 179, | ||
598 | 8192, // P_fft_nb_to_cut | ||
599 | |||
600 | 6, 181, | ||
601 | 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800 | ||
602 | 0x2800, | ||
603 | 0x2800, | ||
604 | 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800 | ||
605 | 0x2800, | ||
606 | 0x2800, | ||
607 | |||
608 | 2, 193, | ||
609 | 0x0666, // P_pha3_thres | ||
610 | 0x0000, // P_cti_use_cpe, P_cti_use_prog | ||
611 | |||
612 | 2, 205, | ||
613 | 0x200f, // P_cspu_regul, P_cspu_win_cut | ||
614 | 0x000f, // P_des_shift_work | ||
615 | |||
616 | 5, 215, | ||
617 | 0x023d, // P_adp_regul_cnt | ||
618 | 0x00a4, // P_adp_noise_cnt | ||
619 | 0x00a4, // P_adp_regul_ext | ||
620 | 0x7ff0, // P_adp_noise_ext | ||
621 | 0x3ccc, // P_adp_fil | ||
622 | |||
623 | 1, 230, | ||
624 | 0x0000, // P_2d_byp_ti_num | ||
625 | |||
626 | 1, 263, | ||
627 | 0x800, //P_equal_thres_wgn | ||
628 | |||
629 | 1, 268, | ||
630 | (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode | ||
631 | |||
632 | 1, 270, | ||
633 | 0x0001, // P_div_lock0_wait | ||
634 | 1, 285, | ||
635 | 0x0020, //p_fec_ | ||
636 | 1, 299, | ||
637 | 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard | ||
638 | |||
639 | 1, 338, | ||
640 | (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 | ||
641 | (1 << 10) | // P_ctrl_pre_freq_mode_sat=1 | ||
642 | (0 << 9) | // P_ctrl_pre_freq_inh=0 | ||
643 | (3 << 5) | // P_ctrl_pre_freq_step=3 | ||
644 | (1 << 0), // P_pre_freq_win_len=1 | ||
645 | |||
646 | 1, 903, | ||
647 | (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW) | ||
648 | |||
649 | 0, | ||
650 | }; | ||
651 | |||
652 | static u16 dib8000_identify(struct i2c_device *client) | ||
653 | { | ||
654 | u16 value; | ||
655 | |||
656 | //because of glitches sometimes | ||
657 | value = dib8000_i2c_read16(client, 896); | ||
658 | |||
659 | if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) { | ||
660 | dprintk("wrong Vendor ID (read=0x%x)", value); | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | value = dib8000_i2c_read16(client, 897); | ||
665 | if (value != 0x8000 && value != 0x8001 && value != 0x8002) { | ||
666 | dprintk("wrong Device ID (%x)", value); | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | switch (value) { | ||
671 | case 0x8000: | ||
672 | dprintk("found DiB8000A"); | ||
673 | break; | ||
674 | case 0x8001: | ||
675 | dprintk("found DiB8000B"); | ||
676 | break; | ||
677 | case 0x8002: | ||
678 | dprintk("found DiB8000C"); | ||
679 | break; | ||
680 | } | ||
681 | return value; | ||
682 | } | ||
683 | |||
684 | static int dib8000_reset(struct dvb_frontend *fe) | ||
685 | { | ||
686 | struct dib8000_state *state = fe->demodulator_priv; | ||
687 | |||
688 | dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */ | ||
689 | |||
690 | if ((state->revision = dib8000_identify(&state->i2c)) == 0) | ||
691 | return -EINVAL; | ||
692 | |||
693 | if (state->revision == 0x8000) | ||
694 | dprintk("error : dib8000 MA not supported"); | ||
695 | |||
696 | dibx000_reset_i2c_master(&state->i2c_master); | ||
697 | |||
698 | dib8000_set_power_mode(state, DIB8000M_POWER_ALL); | ||
699 | |||
700 | /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ | ||
701 | dib8000_set_adc_state(state, DIBX000_VBG_ENABLE); | ||
702 | |||
703 | /* restart all parts */ | ||
704 | dib8000_write_word(state, 770, 0xffff); | ||
705 | dib8000_write_word(state, 771, 0xffff); | ||
706 | dib8000_write_word(state, 772, 0xfffc); | ||
707 | dib8000_write_word(state, 898, 0x000c); // sad | ||
708 | dib8000_write_word(state, 1280, 0x004d); | ||
709 | dib8000_write_word(state, 1281, 0x000c); | ||
710 | |||
711 | dib8000_write_word(state, 770, 0x0000); | ||
712 | dib8000_write_word(state, 771, 0x0000); | ||
713 | dib8000_write_word(state, 772, 0x0000); | ||
714 | dib8000_write_word(state, 898, 0x0004); // sad | ||
715 | dib8000_write_word(state, 1280, 0x0000); | ||
716 | dib8000_write_word(state, 1281, 0x0000); | ||
717 | |||
718 | /* drives */ | ||
719 | if (state->cfg.drives) | ||
720 | dib8000_write_word(state, 906, state->cfg.drives); | ||
721 | else { | ||
722 | dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); | ||
723 | dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust | ||
724 | } | ||
725 | |||
726 | dib8000_reset_pll(state); | ||
727 | |||
728 | if (dib8000_reset_gpio(state) != 0) | ||
729 | dprintk("GPIO reset was not successful."); | ||
730 | |||
731 | if (dib8000_set_output_mode(state, OUTMODE_HIGH_Z) != 0) | ||
732 | dprintk("OUTPUT_MODE could not be resetted."); | ||
733 | |||
734 | state->current_agc = NULL; | ||
735 | |||
736 | // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... | ||
737 | /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */ | ||
738 | if (state->cfg.pll->ifreq == 0) | ||
739 | dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */ | ||
740 | else | ||
741 | dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */ | ||
742 | |||
743 | { | ||
744 | u16 l = 0, r; | ||
745 | const u16 *n; | ||
746 | n = dib8000_defaults; | ||
747 | l = *n++; | ||
748 | while (l) { | ||
749 | r = *n++; | ||
750 | do { | ||
751 | dib8000_write_word(state, r, *n++); | ||
752 | r++; | ||
753 | } while (--l); | ||
754 | l = *n++; | ||
755 | } | ||
756 | } | ||
757 | state->isdbt_cfg_loaded = 0; | ||
758 | |||
759 | //div_cfg override for special configs | ||
760 | if (state->cfg.div_cfg != 0) | ||
761 | dib8000_write_word(state, 903, state->cfg.div_cfg); | ||
762 | |||
763 | /* unforce divstr regardless whether i2c enumeration was done or not */ | ||
764 | dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1)); | ||
765 | |||
766 | dib8000_set_bandwidth(state, 6000); | ||
767 | |||
768 | dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); | ||
769 | dib8000_sad_calib(state); | ||
770 | dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); | ||
771 | |||
772 | dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); | ||
773 | |||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | static void dib8000_restart_agc(struct dib8000_state *state) | ||
778 | { | ||
779 | // P_restart_iqc & P_restart_agc | ||
780 | dib8000_write_word(state, 770, 0x0a00); | ||
781 | dib8000_write_word(state, 770, 0x0000); | ||
782 | } | ||
783 | |||
784 | static int dib8000_update_lna(struct dib8000_state *state) | ||
785 | { | ||
786 | u16 dyn_gain; | ||
787 | |||
788 | if (state->cfg.update_lna) { | ||
789 | // read dyn_gain here (because it is demod-dependent and not tuner) | ||
790 | dyn_gain = dib8000_read_word(state, 390); | ||
791 | |||
792 | if (state->cfg.update_lna(&state->fe, dyn_gain)) { // LNA has changed | ||
793 | dib8000_restart_agc(state); | ||
794 | return 1; | ||
795 | } | ||
796 | } | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) | ||
801 | { | ||
802 | struct dibx000_agc_config *agc = NULL; | ||
803 | int i; | ||
804 | if (state->current_band == band && state->current_agc != NULL) | ||
805 | return 0; | ||
806 | state->current_band = band; | ||
807 | |||
808 | for (i = 0; i < state->cfg.agc_config_count; i++) | ||
809 | if (state->cfg.agc[i].band_caps & band) { | ||
810 | agc = &state->cfg.agc[i]; | ||
811 | break; | ||
812 | } | ||
813 | |||
814 | if (agc == NULL) { | ||
815 | dprintk("no valid AGC configuration found for band 0x%02x", band); | ||
816 | return -EINVAL; | ||
817 | } | ||
818 | |||
819 | state->current_agc = agc; | ||
820 | |||
821 | /* AGC */ | ||
822 | dib8000_write_word(state, 76, agc->setup); | ||
823 | dib8000_write_word(state, 77, agc->inv_gain); | ||
824 | dib8000_write_word(state, 78, agc->time_stabiliz); | ||
825 | dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock); | ||
826 | |||
827 | // Demod AGC loop configuration | ||
828 | dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp); | ||
829 | dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp); | ||
830 | |||
831 | dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", | ||
832 | state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); | ||
833 | |||
834 | /* AGC continued */ | ||
835 | if (state->wbd_ref != 0) | ||
836 | dib8000_write_word(state, 106, state->wbd_ref); | ||
837 | else // use default | ||
838 | dib8000_write_word(state, 106, agc->wbd_ref); | ||
839 | dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); | ||
840 | dib8000_write_word(state, 108, agc->agc1_max); | ||
841 | dib8000_write_word(state, 109, agc->agc1_min); | ||
842 | dib8000_write_word(state, 110, agc->agc2_max); | ||
843 | dib8000_write_word(state, 111, agc->agc2_min); | ||
844 | dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2); | ||
845 | dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); | ||
846 | dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); | ||
847 | dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); | ||
848 | |||
849 | dib8000_write_word(state, 75, agc->agc1_pt3); | ||
850 | dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */ | ||
851 | |||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | static int dib8000_agc_soft_split(struct dib8000_state *state) | ||
856 | { | ||
857 | u16 agc, split_offset; | ||
858 | |||
859 | if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) | ||
860 | return FE_CALLBACK_TIME_NEVER; | ||
861 | |||
862 | // n_agc_global | ||
863 | agc = dib8000_read_word(state, 390); | ||
864 | |||
865 | if (agc > state->current_agc->split.min_thres) | ||
866 | split_offset = state->current_agc->split.min; | ||
867 | else if (agc < state->current_agc->split.max_thres) | ||
868 | split_offset = state->current_agc->split.max; | ||
869 | else | ||
870 | split_offset = state->current_agc->split.max * | ||
871 | (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); | ||
872 | |||
873 | dprintk("AGC split_offset: %d", split_offset); | ||
874 | |||
875 | // P_agc_force_split and P_agc_split_offset | ||
876 | dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset); | ||
877 | return 5000; | ||
878 | } | ||
879 | |||
880 | static int dib8000_agc_startup(struct dvb_frontend *fe) | ||
881 | { | ||
882 | struct dib8000_state *state = fe->demodulator_priv; | ||
883 | enum frontend_tune_state *tune_state = &state->tune_state; | ||
884 | |||
885 | int ret = 0; | ||
886 | |||
887 | switch (*tune_state) { | ||
888 | case CT_AGC_START: | ||
889 | // set power-up level: interf+analog+AGC | ||
890 | |||
891 | dib8000_set_adc_state(state, DIBX000_ADC_ON); | ||
892 | |||
893 | if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { | ||
894 | *tune_state = CT_AGC_STOP; | ||
895 | state->status = FE_STATUS_TUNE_FAILED; | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | ret = 70; | ||
900 | *tune_state = CT_AGC_STEP_0; | ||
901 | break; | ||
902 | |||
903 | case CT_AGC_STEP_0: | ||
904 | //AGC initialization | ||
905 | if (state->cfg.agc_control) | ||
906 | state->cfg.agc_control(&state->fe, 1); | ||
907 | |||
908 | dib8000_restart_agc(state); | ||
909 | |||
910 | // wait AGC rough lock time | ||
911 | ret = 50; | ||
912 | *tune_state = CT_AGC_STEP_1; | ||
913 | break; | ||
914 | |||
915 | case CT_AGC_STEP_1: | ||
916 | // wait AGC accurate lock time | ||
917 | ret = 70; | ||
918 | |||
919 | if (dib8000_update_lna(state)) | ||
920 | // wait only AGC rough lock time | ||
921 | ret = 50; | ||
922 | else | ||
923 | *tune_state = CT_AGC_STEP_2; | ||
924 | break; | ||
925 | |||
926 | case CT_AGC_STEP_2: | ||
927 | dib8000_agc_soft_split(state); | ||
928 | |||
929 | if (state->cfg.agc_control) | ||
930 | state->cfg.agc_control(&state->fe, 0); | ||
931 | |||
932 | *tune_state = CT_AGC_STOP; | ||
933 | break; | ||
934 | default: | ||
935 | ret = dib8000_agc_soft_split(state); | ||
936 | break; | ||
937 | } | ||
938 | return ret; | ||
939 | |||
940 | } | ||
941 | |||
942 | static void dib8000_update_timf(struct dib8000_state *state) | ||
943 | { | ||
944 | u32 timf = state->timf = dib8000_read32(state, 435); | ||
945 | |||
946 | dib8000_write_word(state, 29, (u16) (timf >> 16)); | ||
947 | dib8000_write_word(state, 30, (u16) (timf & 0xffff)); | ||
948 | dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); | ||
949 | } | ||
950 | |||
951 | static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching) | ||
952 | { | ||
953 | u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0; | ||
954 | u8 guard, crate, constellation, timeI; | ||
955 | u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; | ||
956 | u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled | ||
957 | const s16 *ncoeff, *ana_fe; | ||
958 | u16 tmcc_pow = 0; | ||
959 | u16 coff_pow = 0x2800; | ||
960 | u16 init_prbs = 0xfff; | ||
961 | u16 ana_gain = 0; | ||
962 | u16 adc_target_16dB[11] = { | ||
963 | (1 << 13) - 825 - 117, | ||
964 | (1 << 13) - 837 - 117, | ||
965 | (1 << 13) - 811 - 117, | ||
966 | (1 << 13) - 766 - 117, | ||
967 | (1 << 13) - 737 - 117, | ||
968 | (1 << 13) - 693 - 117, | ||
969 | (1 << 13) - 648 - 117, | ||
970 | (1 << 13) - 619 - 117, | ||
971 | (1 << 13) - 575 - 117, | ||
972 | (1 << 13) - 531 - 117, | ||
973 | (1 << 13) - 501 - 117 | ||
974 | }; | ||
975 | |||
976 | if (state->ber_monitored_layer != LAYER_ALL) | ||
977 | dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer); | ||
978 | else | ||
979 | dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); | ||
980 | |||
981 | i = dib8000_read_word(state, 26) & 1; // P_dds_invspec | ||
982 | dib8000_write_word(state, 26, state->fe.dtv_property_cache.inversion ^ i); | ||
983 | |||
984 | if (state->fe.dtv_property_cache.isdbt_sb_mode) { | ||
985 | //compute new dds_freq for the seg and adjust prbs | ||
986 | int seg_offset = | ||
987 | state->fe.dtv_property_cache.isdbt_sb_segment_idx - (state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) - | ||
988 | (state->fe.dtv_property_cache.isdbt_sb_segment_count % 2); | ||
989 | int clk = state->cfg.pll->internal; | ||
990 | u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26) | ||
991 | int dds_offset = seg_offset * segtodds; | ||
992 | int new_dds, sub_channel; | ||
993 | if ((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0) // if even | ||
994 | dds_offset -= (int)(segtodds / 2); | ||
995 | |||
996 | if (state->cfg.pll->ifreq == 0) { | ||
997 | if ((state->fe.dtv_property_cache.inversion ^ i) == 0) { | ||
998 | dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); | ||
999 | new_dds = dds_offset; | ||
1000 | } else | ||
1001 | new_dds = dds_offset; | ||
1002 | |||
1003 | // We shift tuning frequency if the wanted segment is : | ||
1004 | // - the segment of center frequency with an odd total number of segments | ||
1005 | // - the segment to the left of center frequency with an even total number of segments | ||
1006 | // - the segment to the right of center frequency with an even total number of segments | ||
1007 | if ((state->fe.dtv_property_cache.delivery_system == SYS_ISDBT) && (state->fe.dtv_property_cache.isdbt_sb_mode == 1) | ||
1008 | && | ||
1009 | (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) | ||
1010 | && (state->fe.dtv_property_cache.isdbt_sb_segment_idx == | ||
1011 | ((state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) | ||
1012 | || (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0) | ||
1013 | && (state->fe.dtv_property_cache.isdbt_sb_segment_idx == (state->fe.dtv_property_cache.isdbt_sb_segment_count / 2))) | ||
1014 | || (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0) | ||
1015 | && (state->fe.dtv_property_cache.isdbt_sb_segment_idx == | ||
1016 | ((state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) | ||
1017 | )) { | ||
1018 | new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26) | ||
1019 | } | ||
1020 | } else { | ||
1021 | if ((state->fe.dtv_property_cache.inversion ^ i) == 0) | ||
1022 | new_dds = state->cfg.pll->ifreq - dds_offset; | ||
1023 | else | ||
1024 | new_dds = state->cfg.pll->ifreq + dds_offset; | ||
1025 | } | ||
1026 | dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff)); | ||
1027 | dib8000_write_word(state, 28, (u16) (new_dds & 0xffff)); | ||
1028 | if (state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) // if odd | ||
1029 | sub_channel = ((state->fe.dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3; | ||
1030 | else // if even | ||
1031 | sub_channel = ((state->fe.dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3; | ||
1032 | sub_channel -= 6; | ||
1033 | |||
1034 | if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K | ||
1035 | || state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { | ||
1036 | dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1 | ||
1037 | dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1 | ||
1038 | } else { | ||
1039 | dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0 | ||
1040 | dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0 | ||
1041 | } | ||
1042 | |||
1043 | switch (state->fe.dtv_property_cache.transmission_mode) { | ||
1044 | case TRANSMISSION_MODE_2K: | ||
1045 | switch (sub_channel) { | ||
1046 | case -6: | ||
1047 | init_prbs = 0x0; | ||
1048 | break; // 41, 0, 1 | ||
1049 | case -5: | ||
1050 | init_prbs = 0x423; | ||
1051 | break; // 02~04 | ||
1052 | case -4: | ||
1053 | init_prbs = 0x9; | ||
1054 | break; // 05~07 | ||
1055 | case -3: | ||
1056 | init_prbs = 0x5C7; | ||
1057 | break; // 08~10 | ||
1058 | case -2: | ||
1059 | init_prbs = 0x7A6; | ||
1060 | break; // 11~13 | ||
1061 | case -1: | ||
1062 | init_prbs = 0x3D8; | ||
1063 | break; // 14~16 | ||
1064 | case 0: | ||
1065 | init_prbs = 0x527; | ||
1066 | break; // 17~19 | ||
1067 | case 1: | ||
1068 | init_prbs = 0x7FF; | ||
1069 | break; // 20~22 | ||
1070 | case 2: | ||
1071 | init_prbs = 0x79B; | ||
1072 | break; // 23~25 | ||
1073 | case 3: | ||
1074 | init_prbs = 0x3D6; | ||
1075 | break; // 26~28 | ||
1076 | case 4: | ||
1077 | init_prbs = 0x3A2; | ||
1078 | break; // 29~31 | ||
1079 | case 5: | ||
1080 | init_prbs = 0x53B; | ||
1081 | break; // 32~34 | ||
1082 | case 6: | ||
1083 | init_prbs = 0x2F4; | ||
1084 | break; // 35~37 | ||
1085 | default: | ||
1086 | case 7: | ||
1087 | init_prbs = 0x213; | ||
1088 | break; // 38~40 | ||
1089 | } | ||
1090 | break; | ||
1091 | |||
1092 | case TRANSMISSION_MODE_4K: | ||
1093 | switch (sub_channel) { | ||
1094 | case -6: | ||
1095 | init_prbs = 0x0; | ||
1096 | break; // 41, 0, 1 | ||
1097 | case -5: | ||
1098 | init_prbs = 0x208; | ||
1099 | break; // 02~04 | ||
1100 | case -4: | ||
1101 | init_prbs = 0xC3; | ||
1102 | break; // 05~07 | ||
1103 | case -3: | ||
1104 | init_prbs = 0x7B9; | ||
1105 | break; // 08~10 | ||
1106 | case -2: | ||
1107 | init_prbs = 0x423; | ||
1108 | break; // 11~13 | ||
1109 | case -1: | ||
1110 | init_prbs = 0x5C7; | ||
1111 | break; // 14~16 | ||
1112 | case 0: | ||
1113 | init_prbs = 0x3D8; | ||
1114 | break; // 17~19 | ||
1115 | case 1: | ||
1116 | init_prbs = 0x7FF; | ||
1117 | break; // 20~22 | ||
1118 | case 2: | ||
1119 | init_prbs = 0x3D6; | ||
1120 | break; // 23~25 | ||
1121 | case 3: | ||
1122 | init_prbs = 0x53B; | ||
1123 | break; // 26~28 | ||
1124 | case 4: | ||
1125 | init_prbs = 0x213; | ||
1126 | break; // 29~31 | ||
1127 | case 5: | ||
1128 | init_prbs = 0x29; | ||
1129 | break; // 32~34 | ||
1130 | case 6: | ||
1131 | init_prbs = 0xD0; | ||
1132 | break; // 35~37 | ||
1133 | default: | ||
1134 | case 7: | ||
1135 | init_prbs = 0x48E; | ||
1136 | break; // 38~40 | ||
1137 | } | ||
1138 | break; | ||
1139 | |||
1140 | default: | ||
1141 | case TRANSMISSION_MODE_8K: | ||
1142 | switch (sub_channel) { | ||
1143 | case -6: | ||
1144 | init_prbs = 0x0; | ||
1145 | break; // 41, 0, 1 | ||
1146 | case -5: | ||
1147 | init_prbs = 0x740; | ||
1148 | break; // 02~04 | ||
1149 | case -4: | ||
1150 | init_prbs = 0x069; | ||
1151 | break; // 05~07 | ||
1152 | case -3: | ||
1153 | init_prbs = 0x7DD; | ||
1154 | break; // 08~10 | ||
1155 | case -2: | ||
1156 | init_prbs = 0x208; | ||
1157 | break; // 11~13 | ||
1158 | case -1: | ||
1159 | init_prbs = 0x7B9; | ||
1160 | break; // 14~16 | ||
1161 | case 0: | ||
1162 | init_prbs = 0x5C7; | ||
1163 | break; // 17~19 | ||
1164 | case 1: | ||
1165 | init_prbs = 0x7FF; | ||
1166 | break; // 20~22 | ||
1167 | case 2: | ||
1168 | init_prbs = 0x53B; | ||
1169 | break; // 23~25 | ||
1170 | case 3: | ||
1171 | init_prbs = 0x29; | ||
1172 | break; // 26~28 | ||
1173 | case 4: | ||
1174 | init_prbs = 0x48E; | ||
1175 | break; // 29~31 | ||
1176 | case 5: | ||
1177 | init_prbs = 0x4C4; | ||
1178 | break; // 32~34 | ||
1179 | case 6: | ||
1180 | init_prbs = 0x367; | ||
1181 | break; // 33~37 | ||
1182 | default: | ||
1183 | case 7: | ||
1184 | init_prbs = 0x684; | ||
1185 | break; // 38~40 | ||
1186 | } | ||
1187 | break; | ||
1188 | } | ||
1189 | } else { // if not state->fe.dtv_property_cache.isdbt_sb_mode | ||
1190 | dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff)); | ||
1191 | dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff)); | ||
1192 | dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003)); | ||
1193 | } | ||
1194 | /*P_mode == ?? */ | ||
1195 | dib8000_write_word(state, 10, (seq << 4)); | ||
1196 | // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000); | ||
1197 | |||
1198 | switch (state->fe.dtv_property_cache.guard_interval) { | ||
1199 | case GUARD_INTERVAL_1_32: | ||
1200 | guard = 0; | ||
1201 | break; | ||
1202 | case GUARD_INTERVAL_1_16: | ||
1203 | guard = 1; | ||
1204 | break; | ||
1205 | case GUARD_INTERVAL_1_8: | ||
1206 | guard = 2; | ||
1207 | break; | ||
1208 | case GUARD_INTERVAL_1_4: | ||
1209 | default: | ||
1210 | guard = 3; | ||
1211 | break; | ||
1212 | } | ||
1213 | |||
1214 | dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1 | ||
1215 | |||
1216 | max_constellation = DQPSK; | ||
1217 | for (i = 0; i < 3; i++) { | ||
1218 | switch (state->fe.dtv_property_cache.layer[i].modulation) { | ||
1219 | case DQPSK: | ||
1220 | constellation = 0; | ||
1221 | break; | ||
1222 | case QPSK: | ||
1223 | constellation = 1; | ||
1224 | break; | ||
1225 | case QAM_16: | ||
1226 | constellation = 2; | ||
1227 | break; | ||
1228 | case QAM_64: | ||
1229 | default: | ||
1230 | constellation = 3; | ||
1231 | break; | ||
1232 | } | ||
1233 | |||
1234 | switch (state->fe.dtv_property_cache.layer[i].fec) { | ||
1235 | case FEC_1_2: | ||
1236 | crate = 1; | ||
1237 | break; | ||
1238 | case FEC_2_3: | ||
1239 | crate = 2; | ||
1240 | break; | ||
1241 | case FEC_3_4: | ||
1242 | crate = 3; | ||
1243 | break; | ||
1244 | case FEC_5_6: | ||
1245 | crate = 5; | ||
1246 | break; | ||
1247 | case FEC_7_8: | ||
1248 | default: | ||
1249 | crate = 7; | ||
1250 | break; | ||
1251 | } | ||
1252 | |||
1253 | if ((state->fe.dtv_property_cache.layer[i].interleaving > 0) && | ||
1254 | ((state->fe.dtv_property_cache.layer[i].interleaving <= 3) || | ||
1255 | (state->fe.dtv_property_cache.layer[i].interleaving == 4 && state->fe.dtv_property_cache.isdbt_sb_mode == 1)) | ||
1256 | ) | ||
1257 | timeI = state->fe.dtv_property_cache.layer[i].interleaving; | ||
1258 | else | ||
1259 | timeI = 0; | ||
1260 | dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe.dtv_property_cache.layer[i].segment_count & 0xf) << 6) | | ||
1261 | (crate << 3) | timeI); | ||
1262 | if (state->fe.dtv_property_cache.layer[i].segment_count > 0) { | ||
1263 | switch (max_constellation) { | ||
1264 | case DQPSK: | ||
1265 | case QPSK: | ||
1266 | if (state->fe.dtv_property_cache.layer[i].modulation == QAM_16 || | ||
1267 | state->fe.dtv_property_cache.layer[i].modulation == QAM_64) | ||
1268 | max_constellation = state->fe.dtv_property_cache.layer[i].modulation; | ||
1269 | break; | ||
1270 | case QAM_16: | ||
1271 | if (state->fe.dtv_property_cache.layer[i].modulation == QAM_64) | ||
1272 | max_constellation = state->fe.dtv_property_cache.layer[i].modulation; | ||
1273 | break; | ||
1274 | } | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | mode = fft_to_mode(state); | ||
1279 | |||
1280 | //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/ | ||
1281 | |||
1282 | dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | | ||
1283 | ((state->fe.dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe.dtv_property_cache. | ||
1284 | isdbt_sb_mode & 1) << 4)); | ||
1285 | |||
1286 | dprintk("mode = %d ; guard = %d", mode, state->fe.dtv_property_cache.guard_interval); | ||
1287 | |||
1288 | /* signal optimization parameter */ | ||
1289 | |||
1290 | if (state->fe.dtv_property_cache.isdbt_partial_reception) { | ||
1291 | seg_diff_mask = (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; | ||
1292 | for (i = 1; i < 3; i++) | ||
1293 | nbseg_diff += | ||
1294 | (state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * state->fe.dtv_property_cache.layer[i].segment_count; | ||
1295 | for (i = 0; i < nbseg_diff; i++) | ||
1296 | seg_diff_mask |= 1 << permu_seg[i + 1]; | ||
1297 | } else { | ||
1298 | for (i = 0; i < 3; i++) | ||
1299 | nbseg_diff += | ||
1300 | (state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * state->fe.dtv_property_cache.layer[i].segment_count; | ||
1301 | for (i = 0; i < nbseg_diff; i++) | ||
1302 | seg_diff_mask |= 1 << permu_seg[i]; | ||
1303 | } | ||
1304 | dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask); | ||
1305 | |||
1306 | state->differential_constellation = (seg_diff_mask != 0); | ||
1307 | dib8000_set_diversity_in(&state->fe, state->diversity_onoff); | ||
1308 | |||
1309 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb | ||
1310 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 1) // 3-segments | ||
1311 | seg_mask13 = 0x00E0; | ||
1312 | else // 1-segment | ||
1313 | seg_mask13 = 0x0040; | ||
1314 | } else | ||
1315 | seg_mask13 = 0x1fff; | ||
1316 | |||
1317 | // WRITE: Mode & Diff mask | ||
1318 | dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask); | ||
1319 | |||
1320 | if ((seg_diff_mask) || (state->fe.dtv_property_cache.isdbt_sb_mode)) | ||
1321 | dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); | ||
1322 | else | ||
1323 | dib8000_write_word(state, 268, (2 << 9) | 39); //init value | ||
1324 | |||
1325 | // ---- SMALL ---- | ||
1326 | // P_small_seg_diff | ||
1327 | dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352 | ||
1328 | |||
1329 | dib8000_write_word(state, 353, seg_mask13); // ADDR 353 | ||
1330 | |||
1331 | /* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */ | ||
1332 | // dib8000_write_word(state, 351, (state->fe.dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5 ); | ||
1333 | |||
1334 | // ---- SMALL ---- | ||
1335 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { | ||
1336 | switch (state->fe.dtv_property_cache.transmission_mode) { | ||
1337 | case TRANSMISSION_MODE_2K: | ||
1338 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg | ||
1339 | if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK | ||
1340 | ncoeff = coeff_2k_sb_1seg_dqpsk; | ||
1341 | else // QPSK or QAM | ||
1342 | ncoeff = coeff_2k_sb_1seg; | ||
1343 | } else { // 3-segments | ||
1344 | if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment | ||
1345 | if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments | ||
1346 | ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; | ||
1347 | else // QPSK or QAM on external segments | ||
1348 | ncoeff = coeff_2k_sb_3seg_0dqpsk; | ||
1349 | } else { // QPSK or QAM on central segment | ||
1350 | if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments | ||
1351 | ncoeff = coeff_2k_sb_3seg_1dqpsk; | ||
1352 | else // QPSK or QAM on external segments | ||
1353 | ncoeff = coeff_2k_sb_3seg; | ||
1354 | } | ||
1355 | } | ||
1356 | break; | ||
1357 | |||
1358 | case TRANSMISSION_MODE_4K: | ||
1359 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg | ||
1360 | if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK | ||
1361 | ncoeff = coeff_4k_sb_1seg_dqpsk; | ||
1362 | else // QPSK or QAM | ||
1363 | ncoeff = coeff_4k_sb_1seg; | ||
1364 | } else { // 3-segments | ||
1365 | if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment | ||
1366 | if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments | ||
1367 | ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; | ||
1368 | } else { // QPSK or QAM on external segments | ||
1369 | ncoeff = coeff_4k_sb_3seg_0dqpsk; | ||
1370 | } | ||
1371 | } else { // QPSK or QAM on central segment | ||
1372 | if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments | ||
1373 | ncoeff = coeff_4k_sb_3seg_1dqpsk; | ||
1374 | } else // QPSK or QAM on external segments | ||
1375 | ncoeff = coeff_4k_sb_3seg; | ||
1376 | } | ||
1377 | } | ||
1378 | break; | ||
1379 | |||
1380 | case TRANSMISSION_MODE_AUTO: | ||
1381 | case TRANSMISSION_MODE_8K: | ||
1382 | default: | ||
1383 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg | ||
1384 | if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK | ||
1385 | ncoeff = coeff_8k_sb_1seg_dqpsk; | ||
1386 | else // QPSK or QAM | ||
1387 | ncoeff = coeff_8k_sb_1seg; | ||
1388 | } else { // 3-segments | ||
1389 | if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment | ||
1390 | if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments | ||
1391 | ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; | ||
1392 | } else { // QPSK or QAM on external segments | ||
1393 | ncoeff = coeff_8k_sb_3seg_0dqpsk; | ||
1394 | } | ||
1395 | } else { // QPSK or QAM on central segment | ||
1396 | if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments | ||
1397 | ncoeff = coeff_8k_sb_3seg_1dqpsk; | ||
1398 | } else // QPSK or QAM on external segments | ||
1399 | ncoeff = coeff_8k_sb_3seg; | ||
1400 | } | ||
1401 | } | ||
1402 | break; | ||
1403 | } | ||
1404 | } | ||
1405 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) | ||
1406 | for (i = 0; i < 8; i++) | ||
1407 | dib8000_write_word(state, 343 + i, ncoeff[i]); | ||
1408 | |||
1409 | // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 | ||
1410 | dib8000_write_word(state, 351, | ||
1411 | (state->fe.dtv_property_cache.isdbt_sb_mode << 9) | (state->fe.dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); | ||
1412 | |||
1413 | // ---- COFF ---- | ||
1414 | // Carloff, the most robust | ||
1415 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { // Sound Broadcasting mode - use both TMCC and AC pilots | ||
1416 | |||
1417 | // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64 | ||
1418 | // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 | ||
1419 | dib8000_write_word(state, 187, | ||
1420 | (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe.dtv_property_cache.isdbt_partial_reception & 1) << 2) | ||
1421 | | 0x3); | ||
1422 | |||
1423 | /* // P_small_coef_ext_enable = 1 */ | ||
1424 | /* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */ | ||
1425 | |||
1426 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg | ||
1427 | |||
1428 | // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1) | ||
1429 | if (mode == 3) | ||
1430 | dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14)); | ||
1431 | else | ||
1432 | dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14)); | ||
1433 | // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, | ||
1434 | // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 | ||
1435 | dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4); | ||
1436 | // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 | ||
1437 | dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); | ||
1438 | // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 | ||
1439 | dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); | ||
1440 | |||
1441 | // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k | ||
1442 | dib8000_write_word(state, 181, 300); | ||
1443 | dib8000_write_word(state, 182, 150); | ||
1444 | dib8000_write_word(state, 183, 80); | ||
1445 | dib8000_write_word(state, 184, 300); | ||
1446 | dib8000_write_word(state, 185, 150); | ||
1447 | dib8000_write_word(state, 186, 80); | ||
1448 | } else { // Sound Broadcasting mode 3 seg | ||
1449 | // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15 | ||
1450 | /* if (mode == 3) */ | ||
1451 | /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */ | ||
1452 | /* else */ | ||
1453 | /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */ | ||
1454 | dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); | ||
1455 | |||
1456 | // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, | ||
1457 | // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 | ||
1458 | dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4); | ||
1459 | // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 | ||
1460 | dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); | ||
1461 | //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 | ||
1462 | dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); | ||
1463 | |||
1464 | // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k | ||
1465 | dib8000_write_word(state, 181, 350); | ||
1466 | dib8000_write_word(state, 182, 300); | ||
1467 | dib8000_write_word(state, 183, 250); | ||
1468 | dib8000_write_word(state, 184, 350); | ||
1469 | dib8000_write_word(state, 185, 300); | ||
1470 | dib8000_write_word(state, 186, 250); | ||
1471 | } | ||
1472 | |||
1473 | } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments | ||
1474 | dib8000_write_word(state, 180, (16 << 6) | 9); | ||
1475 | dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2); | ||
1476 | coff_pow = 0x2800; | ||
1477 | for (i = 0; i < 6; i++) | ||
1478 | dib8000_write_word(state, 181 + i, coff_pow); | ||
1479 | |||
1480 | // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1, | ||
1481 | // P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 | ||
1482 | dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1); | ||
1483 | |||
1484 | // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 | ||
1485 | dib8000_write_word(state, 340, (8 << 6) | (6 << 0)); | ||
1486 | // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 | ||
1487 | dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); | ||
1488 | } | ||
1489 | // ---- FFT ---- | ||
1490 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1 && state->fe.dtv_property_cache.isdbt_partial_reception == 0) // 1-seg | ||
1491 | dib8000_write_word(state, 178, 64); // P_fft_powrange=64 | ||
1492 | else | ||
1493 | dib8000_write_word(state, 178, 32); // P_fft_powrange=32 | ||
1494 | |||
1495 | /* make the cpil_coff_lock more robust but slower p_coff_winlen | ||
1496 | * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) | ||
1497 | */ | ||
1498 | /* if ( ( nbseg_diff>0)&&(nbseg_diff<13)) | ||
1499 | dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */ | ||
1500 | |||
1501 | dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */ | ||
1502 | dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */ | ||
1503 | dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */ | ||
1504 | if ((!state->fe.dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0)) | ||
1505 | dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ | ||
1506 | else | ||
1507 | dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */ | ||
1508 | dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */ | ||
1509 | //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */ | ||
1510 | if (!autosearching) | ||
1511 | dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ | ||
1512 | else | ||
1513 | dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. | ||
1514 | dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000); | ||
1515 | |||
1516 | dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */ | ||
1517 | |||
1518 | /* offset loop parameters */ | ||
1519 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { | ||
1520 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg | ||
1521 | /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ | ||
1522 | dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40); | ||
1523 | |||
1524 | else // Sound Broadcasting mode 3 seg | ||
1525 | /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ | ||
1526 | dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60); | ||
1527 | } else | ||
1528 | // TODO in 13 seg, timf_alpha can always be the same or not ? | ||
1529 | /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ | ||
1530 | dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80); | ||
1531 | |||
1532 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { | ||
1533 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg | ||
1534 | /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */ | ||
1535 | dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode)); | ||
1536 | |||
1537 | else // Sound Broadcasting mode 3 seg | ||
1538 | /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */ | ||
1539 | dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode)); | ||
1540 | } else | ||
1541 | /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */ | ||
1542 | dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode)); | ||
1543 | |||
1544 | /* P_dvsy_sync_wait - reuse mode */ | ||
1545 | switch (state->fe.dtv_property_cache.transmission_mode) { | ||
1546 | case TRANSMISSION_MODE_8K: | ||
1547 | mode = 256; | ||
1548 | break; | ||
1549 | case TRANSMISSION_MODE_4K: | ||
1550 | mode = 128; | ||
1551 | break; | ||
1552 | default: | ||
1553 | case TRANSMISSION_MODE_2K: | ||
1554 | mode = 64; | ||
1555 | break; | ||
1556 | } | ||
1557 | if (state->cfg.diversity_delay == 0) | ||
1558 | mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo | ||
1559 | else | ||
1560 | mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo | ||
1561 | mode <<= 4; | ||
1562 | dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode); | ||
1563 | |||
1564 | /* channel estimation fine configuration */ | ||
1565 | switch (max_constellation) { | ||
1566 | case QAM_64: | ||
1567 | ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB | ||
1568 | coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ | ||
1569 | coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ | ||
1570 | coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ | ||
1571 | coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ | ||
1572 | //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1 | ||
1573 | break; | ||
1574 | case QAM_16: | ||
1575 | ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB | ||
1576 | coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ | ||
1577 | coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ | ||
1578 | coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ | ||
1579 | coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ | ||
1580 | //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16))) | ||
1581 | break; | ||
1582 | default: | ||
1583 | ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level | ||
1584 | coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ | ||
1585 | coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ | ||
1586 | coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */ | ||
1587 | coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ | ||
1588 | break; | ||
1589 | } | ||
1590 | for (mode = 0; mode < 4; mode++) | ||
1591 | dib8000_write_word(state, 215 + mode, coeff[mode]); | ||
1592 | |||
1593 | // update ana_gain depending on max constellation | ||
1594 | dib8000_write_word(state, 116, ana_gain); | ||
1595 | // update ADC target depending on ana_gain | ||
1596 | if (ana_gain) { // set -16dB ADC target for ana_gain=-1 | ||
1597 | for (i = 0; i < 10; i++) | ||
1598 | dib8000_write_word(state, 80 + i, adc_target_16dB[i]); | ||
1599 | } else { // set -22dB ADC target for ana_gain=0 | ||
1600 | for (i = 0; i < 10; i++) | ||
1601 | dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355); | ||
1602 | } | ||
1603 | |||
1604 | // ---- ANA_FE ---- | ||
1605 | if (state->fe.dtv_property_cache.isdbt_sb_mode) { | ||
1606 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 1) // 3-segments | ||
1607 | ana_fe = ana_fe_coeff_3seg; | ||
1608 | else // 1-segment | ||
1609 | ana_fe = ana_fe_coeff_1seg; | ||
1610 | } else | ||
1611 | ana_fe = ana_fe_coeff_13seg; | ||
1612 | |||
1613 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0) | ||
1614 | for (mode = 0; mode < 24; mode++) | ||
1615 | dib8000_write_word(state, 117 + mode, ana_fe[mode]); | ||
1616 | |||
1617 | // ---- CHAN_BLK ---- | ||
1618 | for (i = 0; i < 13; i++) { | ||
1619 | if ((((~seg_diff_mask) >> i) & 1) == 1) { | ||
1620 | P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0)); | ||
1621 | P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0)); | ||
1622 | } | ||
1623 | } | ||
1624 | dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge | ||
1625 | dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge | ||
1626 | // "P_cspu_left_edge" not used => do not care | ||
1627 | // "P_cspu_right_edge" not used => do not care | ||
1628 | |||
1629 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb | ||
1630 | dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1 | ||
1631 | dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0 | ||
1632 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0 // 1-segment | ||
1633 | && state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) { | ||
1634 | //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0 | ||
1635 | dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15 | ||
1636 | } | ||
1637 | } else if (state->isdbt_cfg_loaded == 0) { | ||
1638 | dib8000_write_word(state, 228, 0); // default value | ||
1639 | dib8000_write_word(state, 265, 31); // default value | ||
1640 | dib8000_write_word(state, 205, 0x200f); // init value | ||
1641 | } | ||
1642 | // ---- TMCC ---- | ||
1643 | for (i = 0; i < 3; i++) | ||
1644 | tmcc_pow += | ||
1645 | (((state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe.dtv_property_cache.layer[i].segment_count); | ||
1646 | // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); | ||
1647 | // Threshold is set at 1/4 of max power. | ||
1648 | tmcc_pow *= (1 << (9 - 2)); | ||
1649 | |||
1650 | dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k | ||
1651 | dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k | ||
1652 | dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k | ||
1653 | //dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); | ||
1654 | // ---- PHA3 ---- | ||
1655 | |||
1656 | if (state->isdbt_cfg_loaded == 0) | ||
1657 | dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */ | ||
1658 | |||
1659 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) | ||
1660 | state->isdbt_cfg_loaded = 0; | ||
1661 | else | ||
1662 | state->isdbt_cfg_loaded = 1; | ||
1663 | |||
1664 | } | ||
1665 | |||
1666 | static int dib8000_autosearch_start(struct dvb_frontend *fe) | ||
1667 | { | ||
1668 | u8 factor; | ||
1669 | u32 value; | ||
1670 | struct dib8000_state *state = fe->demodulator_priv; | ||
1671 | |||
1672 | int slist = 0; | ||
1673 | |||
1674 | state->fe.dtv_property_cache.inversion = 0; | ||
1675 | if (!state->fe.dtv_property_cache.isdbt_sb_mode) | ||
1676 | state->fe.dtv_property_cache.layer[0].segment_count = 13; | ||
1677 | state->fe.dtv_property_cache.layer[0].modulation = QAM_64; | ||
1678 | state->fe.dtv_property_cache.layer[0].fec = FEC_2_3; | ||
1679 | state->fe.dtv_property_cache.layer[0].interleaving = 0; | ||
1680 | |||
1681 | //choose the right list, in sb, always do everything | ||
1682 | if (state->fe.dtv_property_cache.isdbt_sb_mode) { | ||
1683 | state->fe.dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; | ||
1684 | state->fe.dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; | ||
1685 | slist = 7; | ||
1686 | dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); | ||
1687 | } else { | ||
1688 | if (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { | ||
1689 | if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { | ||
1690 | slist = 7; | ||
1691 | dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2 | ||
1692 | } else | ||
1693 | slist = 3; | ||
1694 | } else { | ||
1695 | if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { | ||
1696 | slist = 2; | ||
1697 | dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 | ||
1698 | } else | ||
1699 | slist = 0; | ||
1700 | } | ||
1701 | |||
1702 | if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) | ||
1703 | state->fe.dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; | ||
1704 | if (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) | ||
1705 | state->fe.dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; | ||
1706 | |||
1707 | dprintk("using list for autosearch : %d", slist); | ||
1708 | dib8000_set_channel(state, (unsigned char)slist, 1); | ||
1709 | //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 | ||
1710 | |||
1711 | factor = 1; | ||
1712 | |||
1713 | //set lock_mask values | ||
1714 | dib8000_write_word(state, 6, 0x4); | ||
1715 | dib8000_write_word(state, 7, 0x8); | ||
1716 | dib8000_write_word(state, 8, 0x1000); | ||
1717 | |||
1718 | //set lock_mask wait time values | ||
1719 | value = 50 * state->cfg.pll->internal * factor; | ||
1720 | dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time | ||
1721 | dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time | ||
1722 | value = 100 * state->cfg.pll->internal * factor; | ||
1723 | dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time | ||
1724 | dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time | ||
1725 | value = 1000 * state->cfg.pll->internal * factor; | ||
1726 | dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time | ||
1727 | dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time | ||
1728 | |||
1729 | value = dib8000_read_word(state, 0); | ||
1730 | dib8000_write_word(state, 0, (u16) ((1 << 15) | value)); | ||
1731 | dib8000_read_word(state, 1284); // reset the INT. n_irq_pending | ||
1732 | dib8000_write_word(state, 0, (u16) value); | ||
1733 | |||
1734 | } | ||
1735 | |||
1736 | return 0; | ||
1737 | } | ||
1738 | |||
1739 | static int dib8000_autosearch_irq(struct dvb_frontend *fe) | ||
1740 | { | ||
1741 | struct dib8000_state *state = fe->demodulator_priv; | ||
1742 | u16 irq_pending = dib8000_read_word(state, 1284); | ||
1743 | |||
1744 | if (irq_pending & 0x1) { // failed | ||
1745 | dprintk("dib8000_autosearch_irq failed"); | ||
1746 | return 1; | ||
1747 | } | ||
1748 | |||
1749 | if (irq_pending & 0x2) { // succeeded | ||
1750 | dprintk("dib8000_autosearch_irq succeeded"); | ||
1751 | return 2; | ||
1752 | } | ||
1753 | |||
1754 | return 0; // still pending | ||
1755 | } | ||
1756 | |||
1757 | static int dib8000_tune(struct dvb_frontend *fe) | ||
1758 | { | ||
1759 | struct dib8000_state *state = fe->demodulator_priv; | ||
1760 | int ret = 0; | ||
1761 | u16 value, mode = fft_to_mode(state); | ||
1762 | |||
1763 | // we are already tuned - just resuming from suspend | ||
1764 | if (state == NULL) | ||
1765 | return -EINVAL; | ||
1766 | |||
1767 | dib8000_set_bandwidth(state, state->fe.dtv_property_cache.bandwidth_hz / 1000); | ||
1768 | dib8000_set_channel(state, 0, 0); | ||
1769 | |||
1770 | // restart demod | ||
1771 | ret |= dib8000_write_word(state, 770, 0x4000); | ||
1772 | ret |= dib8000_write_word(state, 770, 0x0000); | ||
1773 | msleep(45); | ||
1774 | |||
1775 | /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */ | ||
1776 | /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */ | ||
1777 | |||
1778 | // never achieved a lock before - wait for timfreq to update | ||
1779 | if (state->timf == 0) { | ||
1780 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { | ||
1781 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg | ||
1782 | msleep(300); | ||
1783 | else // Sound Broadcasting mode 3 seg | ||
1784 | msleep(500); | ||
1785 | } else // 13 seg | ||
1786 | msleep(200); | ||
1787 | } | ||
1788 | //dump_reg(state); | ||
1789 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { | ||
1790 | if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg | ||
1791 | |||
1792 | /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */ | ||
1793 | dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40); | ||
1794 | //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80); | ||
1795 | |||
1796 | /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */ | ||
1797 | ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5)); | ||
1798 | |||
1799 | } else { // Sound Broadcasting mode 3 seg | ||
1800 | |||
1801 | /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */ | ||
1802 | dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60); | ||
1803 | |||
1804 | ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5)); | ||
1805 | } | ||
1806 | |||
1807 | } else { // 13 seg | ||
1808 | /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */ | ||
1809 | dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80); | ||
1810 | |||
1811 | ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5)); | ||
1812 | |||
1813 | } | ||
1814 | |||
1815 | // we achieved a coff_cpil_lock - it's time to update the timf | ||
1816 | if ((dib8000_read_word(state, 568) >> 11) & 0x1) | ||
1817 | dib8000_update_timf(state); | ||
1818 | |||
1819 | //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start | ||
1820 | dib8000_write_word(state, 6, 0x200); | ||
1821 | |||
1822 | if (state->revision == 0x8002) { | ||
1823 | value = dib8000_read_word(state, 903); | ||
1824 | dib8000_write_word(state, 903, value & ~(1 << 3)); | ||
1825 | msleep(1); | ||
1826 | dib8000_write_word(state, 903, value | (1 << 3)); | ||
1827 | } | ||
1828 | |||
1829 | return ret; | ||
1830 | } | ||
1831 | |||
1832 | static int dib8000_wakeup(struct dvb_frontend *fe) | ||
1833 | { | ||
1834 | struct dib8000_state *state = fe->demodulator_priv; | ||
1835 | |||
1836 | dib8000_set_power_mode(state, DIB8000M_POWER_ALL); | ||
1837 | dib8000_set_adc_state(state, DIBX000_ADC_ON); | ||
1838 | if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) | ||
1839 | dprintk("could not start Slow ADC"); | ||
1840 | |||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | static int dib8000_sleep(struct dvb_frontend *fe) | ||
1845 | { | ||
1846 | struct dib8000_state *st = fe->demodulator_priv; | ||
1847 | if (1) { | ||
1848 | dib8000_set_output_mode(st, OUTMODE_HIGH_Z); | ||
1849 | dib8000_set_power_mode(st, DIB8000M_POWER_INTERFACE_ONLY); | ||
1850 | return dib8000_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(st, DIBX000_ADC_OFF); | ||
1851 | } else { | ||
1852 | |||
1853 | return 0; | ||
1854 | } | ||
1855 | } | ||
1856 | |||
1857 | static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) | ||
1858 | { | ||
1859 | struct dib8000_state *state = fe->demodulator_priv; | ||
1860 | u16 i, val = 0; | ||
1861 | |||
1862 | fe->dtv_property_cache.bandwidth_hz = 6000000; | ||
1863 | |||
1864 | fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; | ||
1865 | |||
1866 | val = dib8000_read_word(state, 570); | ||
1867 | fe->dtv_property_cache.inversion = (val & 0x40) >> 6; | ||
1868 | switch ((val & 0x30) >> 4) { | ||
1869 | case 1: | ||
1870 | fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; | ||
1871 | break; | ||
1872 | case 3: | ||
1873 | default: | ||
1874 | fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; | ||
1875 | break; | ||
1876 | } | ||
1877 | |||
1878 | switch (val & 0x3) { | ||
1879 | case 0: | ||
1880 | fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; | ||
1881 | dprintk("dib8000_get_frontend GI = 1/32 "); | ||
1882 | break; | ||
1883 | case 1: | ||
1884 | fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; | ||
1885 | dprintk("dib8000_get_frontend GI = 1/16 "); | ||
1886 | break; | ||
1887 | case 2: | ||
1888 | dprintk("dib8000_get_frontend GI = 1/8 "); | ||
1889 | fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; | ||
1890 | break; | ||
1891 | case 3: | ||
1892 | dprintk("dib8000_get_frontend GI = 1/4 "); | ||
1893 | fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; | ||
1894 | break; | ||
1895 | } | ||
1896 | |||
1897 | val = dib8000_read_word(state, 505); | ||
1898 | fe->dtv_property_cache.isdbt_partial_reception = val & 1; | ||
1899 | dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception); | ||
1900 | |||
1901 | for (i = 0; i < 3; i++) { | ||
1902 | val = dib8000_read_word(state, 493 + i); | ||
1903 | fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; | ||
1904 | dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); | ||
1905 | |||
1906 | val = dib8000_read_word(state, 499 + i); | ||
1907 | fe->dtv_property_cache.layer[i].interleaving = val & 0x3; | ||
1908 | dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving); | ||
1909 | |||
1910 | val = dib8000_read_word(state, 481 + i); | ||
1911 | switch (val & 0x7) { | ||
1912 | case 1: | ||
1913 | fe->dtv_property_cache.layer[i].fec = FEC_1_2; | ||
1914 | dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i); | ||
1915 | break; | ||
1916 | case 2: | ||
1917 | fe->dtv_property_cache.layer[i].fec = FEC_2_3; | ||
1918 | dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i); | ||
1919 | break; | ||
1920 | case 3: | ||
1921 | fe->dtv_property_cache.layer[i].fec = FEC_3_4; | ||
1922 | dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i); | ||
1923 | break; | ||
1924 | case 5: | ||
1925 | fe->dtv_property_cache.layer[i].fec = FEC_5_6; | ||
1926 | dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i); | ||
1927 | break; | ||
1928 | default: | ||
1929 | fe->dtv_property_cache.layer[i].fec = FEC_7_8; | ||
1930 | dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i); | ||
1931 | break; | ||
1932 | } | ||
1933 | |||
1934 | val = dib8000_read_word(state, 487 + i); | ||
1935 | switch (val & 0x3) { | ||
1936 | case 0: | ||
1937 | dprintk("dib8000_get_frontend : Layer %d DQPSK ", i); | ||
1938 | fe->dtv_property_cache.layer[i].modulation = DQPSK; | ||
1939 | break; | ||
1940 | case 1: | ||
1941 | fe->dtv_property_cache.layer[i].modulation = QPSK; | ||
1942 | dprintk("dib8000_get_frontend : Layer %d QPSK ", i); | ||
1943 | break; | ||
1944 | case 2: | ||
1945 | fe->dtv_property_cache.layer[i].modulation = QAM_16; | ||
1946 | dprintk("dib8000_get_frontend : Layer %d QAM16 ", i); | ||
1947 | break; | ||
1948 | case 3: | ||
1949 | default: | ||
1950 | dprintk("dib8000_get_frontend : Layer %d QAM64 ", i); | ||
1951 | fe->dtv_property_cache.layer[i].modulation = QAM_64; | ||
1952 | break; | ||
1953 | } | ||
1954 | } | ||
1955 | return 0; | ||
1956 | } | ||
1957 | |||
1958 | static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) | ||
1959 | { | ||
1960 | struct dib8000_state *state = fe->demodulator_priv; | ||
1961 | int time, ret; | ||
1962 | |||
1963 | dib8000_set_output_mode(state, OUTMODE_HIGH_Z); | ||
1964 | |||
1965 | if (fe->ops.tuner_ops.set_params) | ||
1966 | fe->ops.tuner_ops.set_params(fe, fep); | ||
1967 | |||
1968 | /* start up the AGC */ | ||
1969 | state->tune_state = CT_AGC_START; | ||
1970 | do { | ||
1971 | time = dib8000_agc_startup(fe); | ||
1972 | if (time != FE_CALLBACK_TIME_NEVER) | ||
1973 | msleep(time / 10); | ||
1974 | else | ||
1975 | break; | ||
1976 | } while (state->tune_state != CT_AGC_STOP); | ||
1977 | |||
1978 | if (state->fe.dtv_property_cache.frequency == 0) { | ||
1979 | dprintk("dib8000: must at least specify frequency "); | ||
1980 | return 0; | ||
1981 | } | ||
1982 | |||
1983 | if (state->fe.dtv_property_cache.bandwidth_hz == 0) { | ||
1984 | dprintk("dib8000: no bandwidth specified, set to default "); | ||
1985 | state->fe.dtv_property_cache.bandwidth_hz = 6000000; | ||
1986 | } | ||
1987 | |||
1988 | state->tune_state = CT_DEMOD_START; | ||
1989 | |||
1990 | if ((state->fe.dtv_property_cache.delivery_system != SYS_ISDBT) || | ||
1991 | (state->fe.dtv_property_cache.inversion == INVERSION_AUTO) || | ||
1992 | (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || | ||
1993 | (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || | ||
1994 | (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && | ||
1995 | (state->fe.dtv_property_cache.layer[0].segment_count != 0xff) && | ||
1996 | (state->fe.dtv_property_cache.layer[0].segment_count != 0) && | ||
1997 | ((state->fe.dtv_property_cache.layer[0].modulation == QAM_AUTO) || | ||
1998 | (state->fe.dtv_property_cache.layer[0].fec == FEC_AUTO))) || | ||
1999 | (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && | ||
2000 | (state->fe.dtv_property_cache.layer[1].segment_count != 0xff) && | ||
2001 | (state->fe.dtv_property_cache.layer[1].segment_count != 0) && | ||
2002 | ((state->fe.dtv_property_cache.layer[1].modulation == QAM_AUTO) || | ||
2003 | (state->fe.dtv_property_cache.layer[1].fec == FEC_AUTO))) || | ||
2004 | (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && | ||
2005 | (state->fe.dtv_property_cache.layer[2].segment_count != 0xff) && | ||
2006 | (state->fe.dtv_property_cache.layer[2].segment_count != 0) && | ||
2007 | ((state->fe.dtv_property_cache.layer[2].modulation == QAM_AUTO) || | ||
2008 | (state->fe.dtv_property_cache.layer[2].fec == FEC_AUTO))) || | ||
2009 | (((state->fe.dtv_property_cache.layer[0].segment_count == 0) || | ||
2010 | ((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && | ||
2011 | ((state->fe.dtv_property_cache.layer[1].segment_count == 0) || | ||
2012 | ((state->fe.dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && | ||
2013 | ((state->fe.dtv_property_cache.layer[2].segment_count == 0) || ((state->fe.dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { | ||
2014 | int i = 800, found; | ||
2015 | |||
2016 | dib8000_set_bandwidth(state, fe->dtv_property_cache.bandwidth_hz / 1000); | ||
2017 | dib8000_autosearch_start(fe); | ||
2018 | do { | ||
2019 | msleep(10); | ||
2020 | found = dib8000_autosearch_irq(fe); | ||
2021 | } while (found == 0 && i--); | ||
2022 | |||
2023 | dprintk("Frequency %d Hz, autosearch returns: %d", fep->frequency, found); | ||
2024 | |||
2025 | if (found == 0 || found == 1) | ||
2026 | return 0; // no channel found | ||
2027 | |||
2028 | dib8000_get_frontend(fe, fep); | ||
2029 | } | ||
2030 | |||
2031 | ret = dib8000_tune(fe); | ||
2032 | |||
2033 | /* make this a config parameter */ | ||
2034 | dib8000_set_output_mode(state, state->cfg.output_mode); | ||
2035 | |||
2036 | return ret; | ||
2037 | } | ||
2038 | |||
2039 | static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) | ||
2040 | { | ||
2041 | struct dib8000_state *state = fe->demodulator_priv; | ||
2042 | u16 lock = dib8000_read_word(state, 568); | ||
2043 | |||
2044 | *stat = 0; | ||
2045 | |||
2046 | if ((lock >> 14) & 1) // AGC | ||
2047 | *stat |= FE_HAS_SIGNAL; | ||
2048 | |||
2049 | if ((lock >> 8) & 1) // Equal | ||
2050 | *stat |= FE_HAS_CARRIER; | ||
2051 | |||
2052 | if ((lock >> 3) & 1) // TMCC_SYNC | ||
2053 | *stat |= FE_HAS_SYNC; | ||
2054 | |||
2055 | if ((lock >> 5) & 7) // FEC MPEG | ||
2056 | *stat |= FE_HAS_LOCK; | ||
2057 | |||
2058 | lock = dib8000_read_word(state, 554); // Viterbi Layer A | ||
2059 | if (lock & 0x01) | ||
2060 | *stat |= FE_HAS_VITERBI; | ||
2061 | |||
2062 | lock = dib8000_read_word(state, 555); // Viterbi Layer B | ||
2063 | if (lock & 0x01) | ||
2064 | *stat |= FE_HAS_VITERBI; | ||
2065 | |||
2066 | lock = dib8000_read_word(state, 556); // Viterbi Layer C | ||
2067 | if (lock & 0x01) | ||
2068 | *stat |= FE_HAS_VITERBI; | ||
2069 | |||
2070 | return 0; | ||
2071 | } | ||
2072 | |||
2073 | static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) | ||
2074 | { | ||
2075 | struct dib8000_state *state = fe->demodulator_priv; | ||
2076 | *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments | ||
2077 | return 0; | ||
2078 | } | ||
2079 | |||
2080 | static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) | ||
2081 | { | ||
2082 | struct dib8000_state *state = fe->demodulator_priv; | ||
2083 | *unc = dib8000_read_word(state, 565); // packet error on 13 seg | ||
2084 | return 0; | ||
2085 | } | ||
2086 | |||
2087 | static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | ||
2088 | { | ||
2089 | struct dib8000_state *state = fe->demodulator_priv; | ||
2090 | u16 val = dib8000_read_word(state, 390); | ||
2091 | *strength = 65535 - val; | ||
2092 | return 0; | ||
2093 | } | ||
2094 | |||
2095 | static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) | ||
2096 | { | ||
2097 | struct dib8000_state *state = fe->demodulator_priv; | ||
2098 | u16 val; | ||
2099 | s32 signal_mant, signal_exp, noise_mant, noise_exp; | ||
2100 | u32 result = 0; | ||
2101 | |||
2102 | val = dib8000_read_word(state, 542); | ||
2103 | noise_mant = (val >> 6) & 0xff; | ||
2104 | noise_exp = (val & 0x3f); | ||
2105 | |||
2106 | val = dib8000_read_word(state, 543); | ||
2107 | signal_mant = (val >> 6) & 0xff; | ||
2108 | signal_exp = (val & 0x3f); | ||
2109 | |||
2110 | if ((noise_exp & 0x20) != 0) | ||
2111 | noise_exp -= 0x40; | ||
2112 | if ((signal_exp & 0x20) != 0) | ||
2113 | signal_exp -= 0x40; | ||
2114 | |||
2115 | if (signal_mant != 0) | ||
2116 | result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant); | ||
2117 | else | ||
2118 | result = intlog10(2) * 10 * signal_exp - 100; | ||
2119 | if (noise_mant != 0) | ||
2120 | result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant); | ||
2121 | else | ||
2122 | result -= intlog10(2) * 10 * noise_exp - 100; | ||
2123 | |||
2124 | *snr = result / (1 << 24); | ||
2125 | return 0; | ||
2126 | } | ||
2127 | |||
2128 | int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) | ||
2129 | { | ||
2130 | int k = 0; | ||
2131 | u8 new_addr = 0; | ||
2132 | struct i2c_device client = {.adap = host }; | ||
2133 | |||
2134 | for (k = no_of_demods - 1; k >= 0; k--) { | ||
2135 | /* designated i2c address */ | ||
2136 | new_addr = first_addr + (k << 1); | ||
2137 | |||
2138 | client.addr = new_addr; | ||
2139 | dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ | ||
2140 | if (dib8000_identify(&client) == 0) { | ||
2141 | dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ | ||
2142 | client.addr = default_addr; | ||
2143 | if (dib8000_identify(&client) == 0) { | ||
2144 | dprintk("#%d: not identified", k); | ||
2145 | return -EINVAL; | ||
2146 | } | ||
2147 | } | ||
2148 | |||
2149 | /* start diversity to pull_down div_str - just for i2c-enumeration */ | ||
2150 | dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6)); | ||
2151 | |||
2152 | /* set new i2c address and force divstart */ | ||
2153 | dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2); | ||
2154 | client.addr = new_addr; | ||
2155 | dib8000_identify(&client); | ||
2156 | |||
2157 | dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); | ||
2158 | } | ||
2159 | |||
2160 | for (k = 0; k < no_of_demods; k++) { | ||
2161 | new_addr = first_addr | (k << 1); | ||
2162 | client.addr = new_addr; | ||
2163 | |||
2164 | // unforce divstr | ||
2165 | dib8000_i2c_write16(&client, 1285, new_addr << 2); | ||
2166 | |||
2167 | /* deactivate div - it was just for i2c-enumeration */ | ||
2168 | dib8000_i2c_write16(&client, 1286, 0); | ||
2169 | } | ||
2170 | |||
2171 | return 0; | ||
2172 | } | ||
2173 | |||
2174 | EXPORT_SYMBOL(dib8000_i2c_enumeration); | ||
2175 | static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) | ||
2176 | { | ||
2177 | tune->min_delay_ms = 1000; | ||
2178 | tune->step_size = 0; | ||
2179 | tune->max_drift = 0; | ||
2180 | return 0; | ||
2181 | } | ||
2182 | |||
2183 | static void dib8000_release(struct dvb_frontend *fe) | ||
2184 | { | ||
2185 | struct dib8000_state *st = fe->demodulator_priv; | ||
2186 | dibx000_exit_i2c_master(&st->i2c_master); | ||
2187 | kfree(st); | ||
2188 | } | ||
2189 | |||
2190 | struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) | ||
2191 | { | ||
2192 | struct dib8000_state *st = fe->demodulator_priv; | ||
2193 | return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); | ||
2194 | } | ||
2195 | |||
2196 | EXPORT_SYMBOL(dib8000_get_i2c_master); | ||
2197 | |||
2198 | static const struct dvb_frontend_ops dib8000_ops = { | ||
2199 | .info = { | ||
2200 | .name = "DiBcom 8000 ISDB-T", | ||
2201 | .type = FE_OFDM, | ||
2202 | .frequency_min = 44250000, | ||
2203 | .frequency_max = 867250000, | ||
2204 | .frequency_stepsize = 62500, | ||
2205 | .caps = FE_CAN_INVERSION_AUTO | | ||
2206 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
2207 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
2208 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
2209 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, | ||
2210 | }, | ||
2211 | |||
2212 | .release = dib8000_release, | ||
2213 | |||
2214 | .init = dib8000_wakeup, | ||
2215 | .sleep = dib8000_sleep, | ||
2216 | |||
2217 | .set_frontend = dib8000_set_frontend, | ||
2218 | .get_tune_settings = dib8000_fe_get_tune_settings, | ||
2219 | .get_frontend = dib8000_get_frontend, | ||
2220 | |||
2221 | .read_status = dib8000_read_status, | ||
2222 | .read_ber = dib8000_read_ber, | ||
2223 | .read_signal_strength = dib8000_read_signal_strength, | ||
2224 | .read_snr = dib8000_read_snr, | ||
2225 | .read_ucblocks = dib8000_read_unc_blocks, | ||
2226 | }; | ||
2227 | |||
2228 | struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) | ||
2229 | { | ||
2230 | struct dvb_frontend *fe; | ||
2231 | struct dib8000_state *state; | ||
2232 | |||
2233 | dprintk("dib8000_attach"); | ||
2234 | |||
2235 | state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); | ||
2236 | if (state == NULL) | ||
2237 | return NULL; | ||
2238 | |||
2239 | memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); | ||
2240 | state->i2c.adap = i2c_adap; | ||
2241 | state->i2c.addr = i2c_addr; | ||
2242 | state->gpio_val = cfg->gpio_val; | ||
2243 | state->gpio_dir = cfg->gpio_dir; | ||
2244 | |||
2245 | /* Ensure the output mode remains at the previous default if it's | ||
2246 | * not specifically set by the caller. | ||
2247 | */ | ||
2248 | if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) | ||
2249 | state->cfg.output_mode = OUTMODE_MPEG2_FIFO; | ||
2250 | |||
2251 | fe = &state->fe; | ||
2252 | fe->demodulator_priv = state; | ||
2253 | memcpy(&state->fe.ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); | ||
2254 | |||
2255 | state->timf_default = cfg->pll->timf; | ||
2256 | |||
2257 | if (dib8000_identify(&state->i2c) == 0) | ||
2258 | goto error; | ||
2259 | |||
2260 | dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); | ||
2261 | |||
2262 | dib8000_reset(fe); | ||
2263 | |||
2264 | dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ | ||
2265 | |||
2266 | return fe; | ||
2267 | |||
2268 | error: | ||
2269 | kfree(state); | ||
2270 | return NULL; | ||
2271 | } | ||
2272 | |||
2273 | EXPORT_SYMBOL(dib8000_attach); | ||
2274 | |||
2275 | MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>"); | ||
2276 | MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator"); | ||
2277 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h new file mode 100644 index 000000000000..a86de340dd54 --- /dev/null +++ b/drivers/media/dvb/frontends/dib8000.h | |||
@@ -0,0 +1,79 @@ | |||
1 | #ifndef DIB8000_H | ||
2 | #define DIB8000_H | ||
3 | |||
4 | #include "dibx000_common.h" | ||
5 | |||
6 | struct dib8000_config { | ||
7 | u8 output_mpeg2_in_188_bytes; | ||
8 | u8 hostbus_diversity; | ||
9 | u8 tuner_is_baseband; | ||
10 | int (*update_lna) (struct dvb_frontend *, u16 agc_global); | ||
11 | |||
12 | u8 agc_config_count; | ||
13 | struct dibx000_agc_config *agc; | ||
14 | struct dibx000_bandwidth_config *pll; | ||
15 | |||
16 | #define DIB8000_GPIO_DEFAULT_DIRECTIONS 0xffff | ||
17 | u16 gpio_dir; | ||
18 | #define DIB8000_GPIO_DEFAULT_VALUES 0x0000 | ||
19 | u16 gpio_val; | ||
20 | #define DIB8000_GPIO_PWM_POS0(v) ((v & 0xf) << 12) | ||
21 | #define DIB8000_GPIO_PWM_POS1(v) ((v & 0xf) << 8 ) | ||
22 | #define DIB8000_GPIO_PWM_POS2(v) ((v & 0xf) << 4 ) | ||
23 | #define DIB8000_GPIO_PWM_POS3(v) (v & 0xf) | ||
24 | #define DIB8000_GPIO_DEFAULT_PWM_POS 0xffff | ||
25 | u16 gpio_pwm_pos; | ||
26 | u16 pwm_freq_div; | ||
27 | |||
28 | void (*agc_control) (struct dvb_frontend *, u8 before); | ||
29 | |||
30 | u16 drives; | ||
31 | u16 diversity_delay; | ||
32 | u8 div_cfg; | ||
33 | u8 output_mode; | ||
34 | u8 refclksel; | ||
35 | }; | ||
36 | |||
37 | #define DEFAULT_DIB8000_I2C_ADDRESS 18 | ||
38 | |||
39 | #if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE)) | ||
40 | extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); | ||
41 | extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); | ||
42 | |||
43 | extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); | ||
44 | |||
45 | extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); | ||
46 | extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); | ||
47 | #else | ||
48 | static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) | ||
49 | { | ||
50 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x) | ||
55 | { | ||
56 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) | ||
61 | { | ||
62 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
63 | return -ENODEV; | ||
64 | } | ||
65 | |||
66 | int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) | ||
67 | { | ||
68 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
69 | return -ENODEV; | ||
70 | } | ||
71 | |||
72 | int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) | ||
73 | { | ||
74 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
75 | return -ENODEV; | ||
76 | } | ||
77 | #endif | ||
78 | |||
79 | #endif | ||
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 315e09e95b0c..4efca30d2127 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c | |||
@@ -15,29 +15,31 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) | |||
15 | (val >> 8) & 0xff, val & 0xff, | 15 | (val >> 8) & 0xff, val & 0xff, |
16 | }; | 16 | }; |
17 | struct i2c_msg msg = { | 17 | struct i2c_msg msg = { |
18 | .addr = mst->i2c_addr, .flags = 0, .buf = b, .len = 4 | 18 | .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4 |
19 | }; | 19 | }; |
20 | return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; | 20 | return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; |
21 | } | 21 | } |
22 | 22 | ||
23 | 23 | ||
24 | static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf) | 24 | static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, |
25 | enum dibx000_i2c_interface intf) | ||
25 | { | 26 | { |
26 | if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { | 27 | if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { |
27 | dprintk("selecting interface: %d\n",intf); | 28 | dprintk("selecting interface: %d\n", intf); |
28 | mst->selected_interface = intf; | 29 | mst->selected_interface = intf; |
29 | return dibx000_write_word(mst, mst->base_reg + 4, intf); | 30 | return dibx000_write_word(mst, mst->base_reg + 4, intf); |
30 | } | 31 | } |
31 | return 0; | 32 | return 0; |
32 | } | 33 | } |
33 | 34 | ||
34 | static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 addr, int onoff) | 35 | static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], |
36 | u8 addr, int onoff) | ||
35 | { | 37 | { |
36 | u16 val; | 38 | u16 val; |
37 | 39 | ||
38 | 40 | ||
39 | if (onoff) | 41 | if (onoff) |
40 | val = addr << 8; // bit 7 = use master or not, if 0, the gate is open | 42 | val = addr << 8; // bit 7 = use master or not, if 0, the gate is open |
41 | else | 43 | else |
42 | val = 1 << 7; | 44 | val = 1 << 7; |
43 | 45 | ||
@@ -45,7 +47,7 @@ static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 ad | |||
45 | val <<= 1; | 47 | val <<= 1; |
46 | 48 | ||
47 | tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); | 49 | tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); |
48 | tx[1] = ( (mst->base_reg + 1) & 0xff); | 50 | tx[1] = ((mst->base_reg + 1) & 0xff); |
49 | tx[2] = val >> 8; | 51 | tx[2] = val >> 8; |
50 | tx[3] = val & 0xff; | 52 | tx[3] = val & 0xff; |
51 | 53 | ||
@@ -57,59 +59,78 @@ static u32 dibx000_i2c_func(struct i2c_adapter *adapter) | |||
57 | return I2C_FUNC_I2C; | 59 | return I2C_FUNC_I2C; |
58 | } | 60 | } |
59 | 61 | ||
60 | static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) | 62 | static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, |
63 | struct i2c_msg msg[], int num) | ||
61 | { | 64 | { |
62 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); | 65 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); |
63 | struct i2c_msg m[2 + num]; | 66 | struct i2c_msg m[2 + num]; |
64 | u8 tx_open[4], tx_close[4]; | 67 | u8 tx_open[4], tx_close[4]; |
65 | 68 | ||
66 | memset(m,0, sizeof(struct i2c_msg) * (2 + num)); | 69 | memset(m, 0, sizeof(struct i2c_msg) * (2 + num)); |
67 | 70 | ||
68 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); | 71 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); |
69 | 72 | ||
70 | dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); | 73 | dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); |
71 | m[0].addr = mst->i2c_addr; | 74 | m[0].addr = mst->i2c_addr; |
72 | m[0].buf = tx_open; | 75 | m[0].buf = tx_open; |
73 | m[0].len = 4; | 76 | m[0].len = 4; |
74 | 77 | ||
75 | memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); | 78 | memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); |
76 | 79 | ||
77 | dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); | 80 | dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); |
78 | m[num+1].addr = mst->i2c_addr; | 81 | m[num + 1].addr = mst->i2c_addr; |
79 | m[num+1].buf = tx_close; | 82 | m[num + 1].buf = tx_close; |
80 | m[num+1].len = 4; | 83 | m[num + 1].len = 4; |
81 | 84 | ||
82 | return i2c_transfer(mst->i2c_adap, m, 2+num) == 2 + num ? num : -EIO; | 85 | return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO; |
83 | } | 86 | } |
84 | 87 | ||
85 | static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { | 88 | static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { |
86 | .master_xfer = dibx000_i2c_gated_tuner_xfer, | 89 | .master_xfer = dibx000_i2c_gated_tuner_xfer, |
87 | .functionality = dibx000_i2c_func, | 90 | .functionality = dibx000_i2c_func, |
88 | }; | 91 | }; |
89 | 92 | ||
90 | struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating) | 93 | struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, |
94 | enum dibx000_i2c_interface intf, | ||
95 | int gating) | ||
91 | { | 96 | { |
92 | struct i2c_adapter *i2c = NULL; | 97 | struct i2c_adapter *i2c = NULL; |
93 | 98 | ||
94 | switch (intf) { | 99 | switch (intf) { |
95 | case DIBX000_I2C_INTERFACE_TUNER: | 100 | case DIBX000_I2C_INTERFACE_TUNER: |
96 | if (gating) | 101 | if (gating) |
97 | i2c = &mst->gated_tuner_i2c_adap; | 102 | i2c = &mst->gated_tuner_i2c_adap; |
98 | break; | 103 | break; |
99 | default: | 104 | default: |
100 | printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); | 105 | printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); |
101 | break; | 106 | break; |
102 | } | 107 | } |
103 | 108 | ||
104 | return i2c; | 109 | return i2c; |
105 | } | 110 | } |
111 | |||
106 | EXPORT_SYMBOL(dibx000_get_i2c_adapter); | 112 | EXPORT_SYMBOL(dibx000_get_i2c_adapter); |
107 | 113 | ||
108 | static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) | 114 | void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst) |
115 | { | ||
116 | /* initialize the i2c-master by closing the gate */ | ||
117 | u8 tx[4]; | ||
118 | struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 }; | ||
119 | |||
120 | dibx000_i2c_gate_ctrl(mst, tx, 0, 0); | ||
121 | i2c_transfer(mst->i2c_adap, &m, 1); | ||
122 | mst->selected_interface = 0xff; // the first time force a select of the I2C | ||
123 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); | ||
124 | } | ||
125 | |||
126 | EXPORT_SYMBOL(dibx000_reset_i2c_master); | ||
127 | |||
128 | static int i2c_adapter_init(struct i2c_adapter *i2c_adap, | ||
129 | struct i2c_algorithm *algo, const char *name, | ||
130 | struct dibx000_i2c_master *mst) | ||
109 | { | 131 | { |
110 | strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); | 132 | strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); |
111 | i2c_adap->class = I2C_CLASS_TV_DIGITAL, | 133 | i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo; |
112 | i2c_adap->algo = algo; | ||
113 | i2c_adap->algo_data = NULL; | 134 | i2c_adap->algo_data = NULL; |
114 | i2c_set_adapdata(i2c_adap, mst); | 135 | i2c_set_adapdata(i2c_adap, mst); |
115 | if (i2c_add_adapter(i2c_adap) < 0) | 136 | if (i2c_add_adapter(i2c_adap) < 0) |
@@ -117,34 +138,40 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm * | |||
117 | return 0; | 138 | return 0; |
118 | } | 139 | } |
119 | 140 | ||
120 | int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr) | 141 | int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, |
142 | struct i2c_adapter *i2c_adap, u8 i2c_addr) | ||
121 | { | 143 | { |
122 | u8 tx[4]; | 144 | u8 tx[4]; |
123 | struct i2c_msg m = { .addr = i2c_addr >> 1, .buf = tx, .len = 4 }; | 145 | struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; |
124 | 146 | ||
125 | mst->device_rev = device_rev; | 147 | mst->device_rev = device_rev; |
126 | mst->i2c_adap = i2c_adap; | 148 | mst->i2c_adap = i2c_adap; |
127 | mst->i2c_addr = i2c_addr >> 1; | 149 | mst->i2c_addr = i2c_addr >> 1; |
128 | 150 | ||
129 | if (device_rev == DIB7000P) | 151 | if (device_rev == DIB7000P || device_rev == DIB8000) |
130 | mst->base_reg = 1024; | 152 | mst->base_reg = 1024; |
131 | else | 153 | else |
132 | mst->base_reg = 768; | 154 | mst->base_reg = 768; |
133 | 155 | ||
134 | if (i2c_adapter_init(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, "DiBX000 tuner I2C bus", mst) != 0) | 156 | if (i2c_adapter_init |
135 | printk(KERN_ERR "DiBX000: could not initialize the tuner i2c_adapter\n"); | 157 | (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, |
158 | "DiBX000 tuner I2C bus", mst) != 0) | ||
159 | printk(KERN_ERR | ||
160 | "DiBX000: could not initialize the tuner i2c_adapter\n"); | ||
136 | 161 | ||
137 | /* initialize the i2c-master by closing the gate */ | 162 | /* initialize the i2c-master by closing the gate */ |
138 | dibx000_i2c_gate_ctrl(mst, tx, 0, 0); | 163 | dibx000_i2c_gate_ctrl(mst, tx, 0, 0); |
139 | 164 | ||
140 | return i2c_transfer(i2c_adap, &m, 1) == 1; | 165 | return i2c_transfer(i2c_adap, &m, 1) == 1; |
141 | } | 166 | } |
167 | |||
142 | EXPORT_SYMBOL(dibx000_init_i2c_master); | 168 | EXPORT_SYMBOL(dibx000_init_i2c_master); |
143 | 169 | ||
144 | void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) | 170 | void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) |
145 | { | 171 | { |
146 | i2c_del_adapter(&mst->gated_tuner_i2c_adap); | 172 | i2c_del_adapter(&mst->gated_tuner_i2c_adap); |
147 | } | 173 | } |
174 | |||
148 | EXPORT_SYMBOL(dibx000_exit_i2c_master); | 175 | EXPORT_SYMBOL(dibx000_exit_i2c_master); |
149 | 176 | ||
150 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | 177 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); |
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 84e4d5362922..5be10eca07c0 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define DIBX000_COMMON_H | 2 | #define DIBX000_COMMON_H |
3 | 3 | ||
4 | enum dibx000_i2c_interface { | 4 | enum dibx000_i2c_interface { |
5 | DIBX000_I2C_INTERFACE_TUNER = 0, | 5 | DIBX000_I2C_INTERFACE_TUNER = 0, |
6 | DIBX000_I2C_INTERFACE_GPIO_1_2 = 1, | 6 | DIBX000_I2C_INTERFACE_GPIO_1_2 = 1, |
7 | DIBX000_I2C_INTERFACE_GPIO_3_4 = 2 | 7 | DIBX000_I2C_INTERFACE_GPIO_3_4 = 2 |
8 | }; | 8 | }; |
@@ -12,22 +12,29 @@ struct dibx000_i2c_master { | |||
12 | #define DIB7000 2 | 12 | #define DIB7000 2 |
13 | #define DIB7000P 11 | 13 | #define DIB7000P 11 |
14 | #define DIB7000MC 12 | 14 | #define DIB7000MC 12 |
15 | #define DIB8000 13 | ||
15 | u16 device_rev; | 16 | u16 device_rev; |
16 | 17 | ||
17 | enum dibx000_i2c_interface selected_interface; | 18 | enum dibx000_i2c_interface selected_interface; |
18 | 19 | ||
19 | // struct i2c_adapter tuner_i2c_adap; | 20 | // struct i2c_adapter tuner_i2c_adap; |
20 | struct i2c_adapter gated_tuner_i2c_adap; | 21 | struct i2c_adapter gated_tuner_i2c_adap; |
21 | 22 | ||
22 | struct i2c_adapter *i2c_adap; | 23 | struct i2c_adapter *i2c_adap; |
23 | u8 i2c_addr; | 24 | u8 i2c_addr; |
24 | 25 | ||
25 | u16 base_reg; | 26 | u16 base_reg; |
26 | }; | 27 | }; |
27 | 28 | ||
28 | extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr); | 29 | extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, |
29 | extern struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating); | 30 | u16 device_rev, struct i2c_adapter *i2c_adap, |
31 | u8 i2c_addr); | ||
32 | extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master | ||
33 | *mst, | ||
34 | enum dibx000_i2c_interface | ||
35 | intf, int gating); | ||
30 | extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); | 36 | extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); |
37 | extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); | ||
31 | 38 | ||
32 | #define BAND_LBAND 0x01 | 39 | #define BAND_LBAND 0x01 |
33 | #define BAND_UHF 0x02 | 40 | #define BAND_UHF 0x02 |
@@ -41,18 +48,18 @@ extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); | |||
41 | (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) | 48 | (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) |
42 | 49 | ||
43 | struct dibx000_agc_config { | 50 | struct dibx000_agc_config { |
44 | /* defines the capabilities of this AGC-setting - using the BAND_-defines*/ | 51 | /* defines the capabilities of this AGC-setting - using the BAND_-defines */ |
45 | u8 band_caps; | 52 | u8 band_caps; |
46 | 53 | ||
47 | u16 setup; | 54 | u16 setup; |
48 | 55 | ||
49 | u16 inv_gain; | 56 | u16 inv_gain; |
50 | u16 time_stabiliz; | 57 | u16 time_stabiliz; |
51 | 58 | ||
52 | u8 alpha_level; | 59 | u8 alpha_level; |
53 | u16 thlock; | 60 | u16 thlock; |
54 | 61 | ||
55 | u8 wbd_inv; | 62 | u8 wbd_inv; |
56 | u16 wbd_ref; | 63 | u16 wbd_ref; |
57 | u8 wbd_sel; | 64 | u8 wbd_sel; |
58 | u8 wbd_alpha; | 65 | u8 wbd_alpha; |
@@ -92,8 +99,8 @@ struct dibx000_agc_config { | |||
92 | }; | 99 | }; |
93 | 100 | ||
94 | struct dibx000_bandwidth_config { | 101 | struct dibx000_bandwidth_config { |
95 | u32 internal; | 102 | u32 internal; |
96 | u32 sampling; | 103 | u32 sampling; |
97 | 104 | ||
98 | u8 pll_prediv; | 105 | u8 pll_prediv; |
99 | u8 pll_ratio; | 106 | u8 pll_ratio; |
diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c index eb72a9866c93..e334b5d4e578 100644 --- a/drivers/media/dvb/frontends/lgdt3304.c +++ b/drivers/media/dvb/frontends/lgdt3304.c | |||
@@ -363,6 +363,8 @@ struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, | |||
363 | 363 | ||
364 | struct lgdt3304_state *state; | 364 | struct lgdt3304_state *state; |
365 | state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL); | 365 | state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL); |
366 | if (state == NULL) | ||
367 | return NULL; | ||
366 | state->addr = config->i2c_address; | 368 | state->addr = config->i2c_address; |
367 | state->i2c = i2c; | 369 | state->i2c = i2c; |
368 | 370 | ||
diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c index 3f5a0e1dfdf5..3156b64cfc96 100644 --- a/drivers/media/dvb/frontends/s921_module.c +++ b/drivers/media/dvb/frontends/s921_module.c | |||
@@ -169,6 +169,8 @@ struct dvb_frontend* s921_attach(const struct s921_config *config, | |||
169 | 169 | ||
170 | struct s921_state *state; | 170 | struct s921_state *state; |
171 | state = kzalloc(sizeof(struct s921_state), GFP_KERNEL); | 171 | state = kzalloc(sizeof(struct s921_state), GFP_KERNEL); |
172 | if (state == NULL) | ||
173 | return NULL; | ||
172 | 174 | ||
173 | state->addr = config->i2c_address; | 175 | state->addr = config->i2c_address; |
174 | state->i2c = i2c; | 176 | state->i2c = i2c; |
diff --git a/drivers/media/dvb/pt1/Kconfig b/drivers/media/dvb/pt1/Kconfig new file mode 100644 index 000000000000..24501d5bf70d --- /dev/null +++ b/drivers/media/dvb/pt1/Kconfig | |||
@@ -0,0 +1,12 @@ | |||
1 | config DVB_PT1 | ||
2 | tristate "PT1 cards" | ||
3 | depends on DVB_CORE && PCI && I2C | ||
4 | help | ||
5 | Support for Earthsoft PT1 PCI cards. | ||
6 | |||
7 | Since these cards have no MPEG decoder onboard, they transmit | ||
8 | only compressed MPEG data over the PCI bus, so you need | ||
9 | an external software decoder to watch TV on your computer. | ||
10 | |||
11 | Say Y or M if you own such a device and want to use it. | ||
12 | |||
diff --git a/drivers/media/dvb/pt1/Makefile b/drivers/media/dvb/pt1/Makefile new file mode 100644 index 000000000000..a66da17bbe31 --- /dev/null +++ b/drivers/media/dvb/pt1/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o | ||
2 | |||
3 | obj-$(CONFIG_DVB_PT1) += earth-pt1.o | ||
4 | |||
5 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends | ||
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c new file mode 100644 index 000000000000..8ffbcecad931 --- /dev/null +++ b/drivers/media/dvb/pt1/pt1.c | |||
@@ -0,0 +1,1056 @@ | |||
1 | /* | ||
2 | * driver for Earthsoft PT1 | ||
3 | * | ||
4 | * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | ||
5 | * | ||
6 | * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | ||
7 | * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | ||
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 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/kthread.h> | ||
28 | #include <linux/freezer.h> | ||
29 | |||
30 | #include "dvbdev.h" | ||
31 | #include "dvb_demux.h" | ||
32 | #include "dmxdev.h" | ||
33 | #include "dvb_net.h" | ||
34 | #include "dvb_frontend.h" | ||
35 | |||
36 | #include "va1j5jf8007t.h" | ||
37 | #include "va1j5jf8007s.h" | ||
38 | |||
39 | #define DRIVER_NAME "earth-pt1" | ||
40 | |||
41 | #define PT1_PAGE_SHIFT 12 | ||
42 | #define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT) | ||
43 | #define PT1_NR_UPACKETS 1024 | ||
44 | #define PT1_NR_BUFS 511 | ||
45 | |||
46 | struct pt1_buffer_page { | ||
47 | __le32 upackets[PT1_NR_UPACKETS]; | ||
48 | }; | ||
49 | |||
50 | struct pt1_table_page { | ||
51 | __le32 next_pfn; | ||
52 | __le32 buf_pfns[PT1_NR_BUFS]; | ||
53 | }; | ||
54 | |||
55 | struct pt1_buffer { | ||
56 | struct pt1_buffer_page *page; | ||
57 | dma_addr_t addr; | ||
58 | }; | ||
59 | |||
60 | struct pt1_table { | ||
61 | struct pt1_table_page *page; | ||
62 | dma_addr_t addr; | ||
63 | struct pt1_buffer bufs[PT1_NR_BUFS]; | ||
64 | }; | ||
65 | |||
66 | #define PT1_NR_ADAPS 4 | ||
67 | |||
68 | struct pt1_adapter; | ||
69 | |||
70 | struct pt1 { | ||
71 | struct pci_dev *pdev; | ||
72 | void __iomem *regs; | ||
73 | struct i2c_adapter i2c_adap; | ||
74 | int i2c_running; | ||
75 | struct pt1_adapter *adaps[PT1_NR_ADAPS]; | ||
76 | struct pt1_table *tables; | ||
77 | struct task_struct *kthread; | ||
78 | }; | ||
79 | |||
80 | struct pt1_adapter { | ||
81 | struct pt1 *pt1; | ||
82 | int index; | ||
83 | |||
84 | u8 *buf; | ||
85 | int upacket_count; | ||
86 | int packet_count; | ||
87 | |||
88 | struct dvb_adapter adap; | ||
89 | struct dvb_demux demux; | ||
90 | int users; | ||
91 | struct dmxdev dmxdev; | ||
92 | struct dvb_net net; | ||
93 | struct dvb_frontend *fe; | ||
94 | int (*orig_set_voltage)(struct dvb_frontend *fe, | ||
95 | fe_sec_voltage_t voltage); | ||
96 | }; | ||
97 | |||
98 | #define pt1_printk(level, pt1, format, arg...) \ | ||
99 | dev_printk(level, &(pt1)->pdev->dev, format, ##arg) | ||
100 | |||
101 | static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data) | ||
102 | { | ||
103 | writel(data, pt1->regs + reg * 4); | ||
104 | } | ||
105 | |||
106 | static u32 pt1_read_reg(struct pt1 *pt1, int reg) | ||
107 | { | ||
108 | return readl(pt1->regs + reg * 4); | ||
109 | } | ||
110 | |||
111 | static int pt1_nr_tables = 64; | ||
112 | module_param_named(nr_tables, pt1_nr_tables, int, 0); | ||
113 | |||
114 | static void pt1_increment_table_count(struct pt1 *pt1) | ||
115 | { | ||
116 | pt1_write_reg(pt1, 0, 0x00000020); | ||
117 | } | ||
118 | |||
119 | static void pt1_init_table_count(struct pt1 *pt1) | ||
120 | { | ||
121 | pt1_write_reg(pt1, 0, 0x00000010); | ||
122 | } | ||
123 | |||
124 | static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn) | ||
125 | { | ||
126 | pt1_write_reg(pt1, 5, first_pfn); | ||
127 | pt1_write_reg(pt1, 0, 0x0c000040); | ||
128 | } | ||
129 | |||
130 | static void pt1_unregister_tables(struct pt1 *pt1) | ||
131 | { | ||
132 | pt1_write_reg(pt1, 0, 0x08080000); | ||
133 | } | ||
134 | |||
135 | static int pt1_sync(struct pt1 *pt1) | ||
136 | { | ||
137 | int i; | ||
138 | for (i = 0; i < 57; i++) { | ||
139 | if (pt1_read_reg(pt1, 0) & 0x20000000) | ||
140 | return 0; | ||
141 | pt1_write_reg(pt1, 0, 0x00000008); | ||
142 | } | ||
143 | pt1_printk(KERN_ERR, pt1, "could not sync\n"); | ||
144 | return -EIO; | ||
145 | } | ||
146 | |||
147 | static u64 pt1_identify(struct pt1 *pt1) | ||
148 | { | ||
149 | int i; | ||
150 | u64 id; | ||
151 | id = 0; | ||
152 | for (i = 0; i < 57; i++) { | ||
153 | id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i; | ||
154 | pt1_write_reg(pt1, 0, 0x00000008); | ||
155 | } | ||
156 | return id; | ||
157 | } | ||
158 | |||
159 | static int pt1_unlock(struct pt1 *pt1) | ||
160 | { | ||
161 | int i; | ||
162 | pt1_write_reg(pt1, 0, 0x00000008); | ||
163 | for (i = 0; i < 3; i++) { | ||
164 | if (pt1_read_reg(pt1, 0) & 0x80000000) | ||
165 | return 0; | ||
166 | schedule_timeout_uninterruptible((HZ + 999) / 1000); | ||
167 | } | ||
168 | pt1_printk(KERN_ERR, pt1, "could not unlock\n"); | ||
169 | return -EIO; | ||
170 | } | ||
171 | |||
172 | static int pt1_reset_pci(struct pt1 *pt1) | ||
173 | { | ||
174 | int i; | ||
175 | pt1_write_reg(pt1, 0, 0x01010000); | ||
176 | pt1_write_reg(pt1, 0, 0x01000000); | ||
177 | for (i = 0; i < 10; i++) { | ||
178 | if (pt1_read_reg(pt1, 0) & 0x00000001) | ||
179 | return 0; | ||
180 | schedule_timeout_uninterruptible((HZ + 999) / 1000); | ||
181 | } | ||
182 | pt1_printk(KERN_ERR, pt1, "could not reset PCI\n"); | ||
183 | return -EIO; | ||
184 | } | ||
185 | |||
186 | static int pt1_reset_ram(struct pt1 *pt1) | ||
187 | { | ||
188 | int i; | ||
189 | pt1_write_reg(pt1, 0, 0x02020000); | ||
190 | pt1_write_reg(pt1, 0, 0x02000000); | ||
191 | for (i = 0; i < 10; i++) { | ||
192 | if (pt1_read_reg(pt1, 0) & 0x00000002) | ||
193 | return 0; | ||
194 | schedule_timeout_uninterruptible((HZ + 999) / 1000); | ||
195 | } | ||
196 | pt1_printk(KERN_ERR, pt1, "could not reset RAM\n"); | ||
197 | return -EIO; | ||
198 | } | ||
199 | |||
200 | static int pt1_do_enable_ram(struct pt1 *pt1) | ||
201 | { | ||
202 | int i, j; | ||
203 | u32 status; | ||
204 | status = pt1_read_reg(pt1, 0) & 0x00000004; | ||
205 | pt1_write_reg(pt1, 0, 0x00000002); | ||
206 | for (i = 0; i < 10; i++) { | ||
207 | for (j = 0; j < 1024; j++) { | ||
208 | if ((pt1_read_reg(pt1, 0) & 0x00000004) != status) | ||
209 | return 0; | ||
210 | } | ||
211 | schedule_timeout_uninterruptible((HZ + 999) / 1000); | ||
212 | } | ||
213 | pt1_printk(KERN_ERR, pt1, "could not enable RAM\n"); | ||
214 | return -EIO; | ||
215 | } | ||
216 | |||
217 | static int pt1_enable_ram(struct pt1 *pt1) | ||
218 | { | ||
219 | int i, ret; | ||
220 | schedule_timeout_uninterruptible((HZ + 999) / 1000); | ||
221 | for (i = 0; i < 10; i++) { | ||
222 | ret = pt1_do_enable_ram(pt1); | ||
223 | if (ret < 0) | ||
224 | return ret; | ||
225 | } | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static void pt1_disable_ram(struct pt1 *pt1) | ||
230 | { | ||
231 | pt1_write_reg(pt1, 0, 0x0b0b0000); | ||
232 | } | ||
233 | |||
234 | static void pt1_set_stream(struct pt1 *pt1, int index, int enabled) | ||
235 | { | ||
236 | pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index); | ||
237 | } | ||
238 | |||
239 | static void pt1_init_streams(struct pt1 *pt1) | ||
240 | { | ||
241 | int i; | ||
242 | for (i = 0; i < PT1_NR_ADAPS; i++) | ||
243 | pt1_set_stream(pt1, i, 0); | ||
244 | } | ||
245 | |||
246 | static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) | ||
247 | { | ||
248 | u32 upacket; | ||
249 | int i; | ||
250 | int index; | ||
251 | struct pt1_adapter *adap; | ||
252 | int offset; | ||
253 | u8 *buf; | ||
254 | |||
255 | if (!page->upackets[PT1_NR_UPACKETS - 1]) | ||
256 | return 0; | ||
257 | |||
258 | for (i = 0; i < PT1_NR_UPACKETS; i++) { | ||
259 | upacket = le32_to_cpu(page->upackets[i]); | ||
260 | index = (upacket >> 29) - 1; | ||
261 | if (index < 0 || index >= PT1_NR_ADAPS) | ||
262 | continue; | ||
263 | |||
264 | adap = pt1->adaps[index]; | ||
265 | if (upacket >> 25 & 1) | ||
266 | adap->upacket_count = 0; | ||
267 | else if (!adap->upacket_count) | ||
268 | continue; | ||
269 | |||
270 | buf = adap->buf; | ||
271 | offset = adap->packet_count * 188 + adap->upacket_count * 3; | ||
272 | buf[offset] = upacket >> 16; | ||
273 | buf[offset + 1] = upacket >> 8; | ||
274 | if (adap->upacket_count != 62) | ||
275 | buf[offset + 2] = upacket; | ||
276 | |||
277 | if (++adap->upacket_count >= 63) { | ||
278 | adap->upacket_count = 0; | ||
279 | if (++adap->packet_count >= 21) { | ||
280 | dvb_dmx_swfilter_packets(&adap->demux, buf, 21); | ||
281 | adap->packet_count = 0; | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | |||
286 | page->upackets[PT1_NR_UPACKETS - 1] = 0; | ||
287 | return 1; | ||
288 | } | ||
289 | |||
290 | static int pt1_thread(void *data) | ||
291 | { | ||
292 | struct pt1 *pt1; | ||
293 | int table_index; | ||
294 | int buf_index; | ||
295 | struct pt1_buffer_page *page; | ||
296 | |||
297 | pt1 = data; | ||
298 | set_freezable(); | ||
299 | |||
300 | table_index = 0; | ||
301 | buf_index = 0; | ||
302 | |||
303 | while (!kthread_should_stop()) { | ||
304 | try_to_freeze(); | ||
305 | |||
306 | page = pt1->tables[table_index].bufs[buf_index].page; | ||
307 | if (!pt1_filter(pt1, page)) { | ||
308 | schedule_timeout_interruptible((HZ + 999) / 1000); | ||
309 | continue; | ||
310 | } | ||
311 | |||
312 | if (++buf_index >= PT1_NR_BUFS) { | ||
313 | pt1_increment_table_count(pt1); | ||
314 | buf_index = 0; | ||
315 | if (++table_index >= pt1_nr_tables) | ||
316 | table_index = 0; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr) | ||
324 | { | ||
325 | dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr); | ||
326 | } | ||
327 | |||
328 | static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp) | ||
329 | { | ||
330 | void *page; | ||
331 | dma_addr_t addr; | ||
332 | |||
333 | page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr, | ||
334 | GFP_KERNEL); | ||
335 | if (page == NULL) | ||
336 | return NULL; | ||
337 | |||
338 | BUG_ON(addr & (PT1_PAGE_SIZE - 1)); | ||
339 | BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1); | ||
340 | |||
341 | *addrp = addr; | ||
342 | *pfnp = addr >> PT1_PAGE_SHIFT; | ||
343 | return page; | ||
344 | } | ||
345 | |||
346 | static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf) | ||
347 | { | ||
348 | pt1_free_page(pt1, buf->page, buf->addr); | ||
349 | } | ||
350 | |||
351 | static int | ||
352 | pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf, u32 *pfnp) | ||
353 | { | ||
354 | struct pt1_buffer_page *page; | ||
355 | dma_addr_t addr; | ||
356 | |||
357 | page = pt1_alloc_page(pt1, &addr, pfnp); | ||
358 | if (page == NULL) | ||
359 | return -ENOMEM; | ||
360 | |||
361 | page->upackets[PT1_NR_UPACKETS - 1] = 0; | ||
362 | |||
363 | buf->page = page; | ||
364 | buf->addr = addr; | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table) | ||
369 | { | ||
370 | int i; | ||
371 | |||
372 | for (i = 0; i < PT1_NR_BUFS; i++) | ||
373 | pt1_cleanup_buffer(pt1, &table->bufs[i]); | ||
374 | |||
375 | pt1_free_page(pt1, table->page, table->addr); | ||
376 | } | ||
377 | |||
378 | static int | ||
379 | pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp) | ||
380 | { | ||
381 | struct pt1_table_page *page; | ||
382 | dma_addr_t addr; | ||
383 | int i, ret; | ||
384 | u32 buf_pfn; | ||
385 | |||
386 | page = pt1_alloc_page(pt1, &addr, pfnp); | ||
387 | if (page == NULL) | ||
388 | return -ENOMEM; | ||
389 | |||
390 | for (i = 0; i < PT1_NR_BUFS; i++) { | ||
391 | ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn); | ||
392 | if (ret < 0) | ||
393 | goto err; | ||
394 | |||
395 | page->buf_pfns[i] = cpu_to_le32(buf_pfn); | ||
396 | } | ||
397 | |||
398 | pt1_increment_table_count(pt1); | ||
399 | table->page = page; | ||
400 | table->addr = addr; | ||
401 | return 0; | ||
402 | |||
403 | err: | ||
404 | while (i--) | ||
405 | pt1_cleanup_buffer(pt1, &table->bufs[i]); | ||
406 | |||
407 | pt1_free_page(pt1, page, addr); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | static void pt1_cleanup_tables(struct pt1 *pt1) | ||
412 | { | ||
413 | struct pt1_table *tables; | ||
414 | int i; | ||
415 | |||
416 | tables = pt1->tables; | ||
417 | pt1_unregister_tables(pt1); | ||
418 | |||
419 | for (i = 0; i < pt1_nr_tables; i++) | ||
420 | pt1_cleanup_table(pt1, &tables[i]); | ||
421 | |||
422 | vfree(tables); | ||
423 | } | ||
424 | |||
425 | static int pt1_init_tables(struct pt1 *pt1) | ||
426 | { | ||
427 | struct pt1_table *tables; | ||
428 | int i, ret; | ||
429 | u32 first_pfn, pfn; | ||
430 | |||
431 | tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables); | ||
432 | if (tables == NULL) | ||
433 | return -ENOMEM; | ||
434 | |||
435 | pt1_init_table_count(pt1); | ||
436 | |||
437 | i = 0; | ||
438 | if (pt1_nr_tables) { | ||
439 | ret = pt1_init_table(pt1, &tables[0], &first_pfn); | ||
440 | if (ret) | ||
441 | goto err; | ||
442 | i++; | ||
443 | } | ||
444 | |||
445 | while (i < pt1_nr_tables) { | ||
446 | ret = pt1_init_table(pt1, &tables[i], &pfn); | ||
447 | if (ret) | ||
448 | goto err; | ||
449 | tables[i - 1].page->next_pfn = cpu_to_le32(pfn); | ||
450 | i++; | ||
451 | } | ||
452 | |||
453 | tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn); | ||
454 | |||
455 | pt1_register_tables(pt1, first_pfn); | ||
456 | pt1->tables = tables; | ||
457 | return 0; | ||
458 | |||
459 | err: | ||
460 | while (i--) | ||
461 | pt1_cleanup_table(pt1, &tables[i]); | ||
462 | |||
463 | vfree(tables); | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | static int pt1_start_feed(struct dvb_demux_feed *feed) | ||
468 | { | ||
469 | struct pt1_adapter *adap; | ||
470 | adap = container_of(feed->demux, struct pt1_adapter, demux); | ||
471 | if (!adap->users++) | ||
472 | pt1_set_stream(adap->pt1, adap->index, 1); | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int pt1_stop_feed(struct dvb_demux_feed *feed) | ||
477 | { | ||
478 | struct pt1_adapter *adap; | ||
479 | adap = container_of(feed->demux, struct pt1_adapter, demux); | ||
480 | if (!--adap->users) | ||
481 | pt1_set_stream(adap->pt1, adap->index, 0); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static void | ||
486 | pt1_set_power(struct pt1 *pt1, int power, int lnb, int reset) | ||
487 | { | ||
488 | pt1_write_reg(pt1, 1, power | lnb << 1 | !reset << 3); | ||
489 | } | ||
490 | |||
491 | static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
492 | { | ||
493 | struct pt1_adapter *adap; | ||
494 | int lnb; | ||
495 | |||
496 | adap = container_of(fe->dvb, struct pt1_adapter, adap); | ||
497 | |||
498 | switch (voltage) { | ||
499 | case SEC_VOLTAGE_13: /* actually 11V */ | ||
500 | lnb = 2; | ||
501 | break; | ||
502 | case SEC_VOLTAGE_18: /* actually 15V */ | ||
503 | lnb = 3; | ||
504 | break; | ||
505 | case SEC_VOLTAGE_OFF: | ||
506 | lnb = 0; | ||
507 | break; | ||
508 | default: | ||
509 | return -EINVAL; | ||
510 | } | ||
511 | |||
512 | pt1_set_power(adap->pt1, 1, lnb, 0); | ||
513 | |||
514 | if (adap->orig_set_voltage) | ||
515 | return adap->orig_set_voltage(fe, voltage); | ||
516 | else | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static void pt1_free_adapter(struct pt1_adapter *adap) | ||
521 | { | ||
522 | dvb_unregister_frontend(adap->fe); | ||
523 | dvb_net_release(&adap->net); | ||
524 | adap->demux.dmx.close(&adap->demux.dmx); | ||
525 | dvb_dmxdev_release(&adap->dmxdev); | ||
526 | dvb_dmx_release(&adap->demux); | ||
527 | dvb_unregister_adapter(&adap->adap); | ||
528 | free_page((unsigned long)adap->buf); | ||
529 | kfree(adap); | ||
530 | } | ||
531 | |||
532 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
533 | |||
534 | static struct pt1_adapter * | ||
535 | pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe) | ||
536 | { | ||
537 | struct pt1_adapter *adap; | ||
538 | void *buf; | ||
539 | struct dvb_adapter *dvb_adap; | ||
540 | struct dvb_demux *demux; | ||
541 | struct dmxdev *dmxdev; | ||
542 | int ret; | ||
543 | |||
544 | adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL); | ||
545 | if (!adap) { | ||
546 | ret = -ENOMEM; | ||
547 | goto err; | ||
548 | } | ||
549 | |||
550 | adap->pt1 = pt1; | ||
551 | |||
552 | adap->orig_set_voltage = fe->ops.set_voltage; | ||
553 | fe->ops.set_voltage = pt1_set_voltage; | ||
554 | |||
555 | buf = (u8 *)__get_free_page(GFP_KERNEL); | ||
556 | if (!buf) { | ||
557 | ret = -ENOMEM; | ||
558 | goto err_kfree; | ||
559 | } | ||
560 | |||
561 | adap->buf = buf; | ||
562 | adap->upacket_count = 0; | ||
563 | adap->packet_count = 0; | ||
564 | |||
565 | dvb_adap = &adap->adap; | ||
566 | dvb_adap->priv = adap; | ||
567 | ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE, | ||
568 | &pt1->pdev->dev, adapter_nr); | ||
569 | if (ret < 0) | ||
570 | goto err_free_page; | ||
571 | |||
572 | demux = &adap->demux; | ||
573 | demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; | ||
574 | demux->priv = adap; | ||
575 | demux->feednum = 256; | ||
576 | demux->filternum = 256; | ||
577 | demux->start_feed = pt1_start_feed; | ||
578 | demux->stop_feed = pt1_stop_feed; | ||
579 | demux->write_to_decoder = NULL; | ||
580 | ret = dvb_dmx_init(demux); | ||
581 | if (ret < 0) | ||
582 | goto err_unregister_adapter; | ||
583 | |||
584 | dmxdev = &adap->dmxdev; | ||
585 | dmxdev->filternum = 256; | ||
586 | dmxdev->demux = &demux->dmx; | ||
587 | dmxdev->capabilities = 0; | ||
588 | ret = dvb_dmxdev_init(dmxdev, dvb_adap); | ||
589 | if (ret < 0) | ||
590 | goto err_dmx_release; | ||
591 | |||
592 | dvb_net_init(dvb_adap, &adap->net, &demux->dmx); | ||
593 | |||
594 | ret = dvb_register_frontend(dvb_adap, fe); | ||
595 | if (ret < 0) | ||
596 | goto err_net_release; | ||
597 | adap->fe = fe; | ||
598 | |||
599 | return adap; | ||
600 | |||
601 | err_net_release: | ||
602 | dvb_net_release(&adap->net); | ||
603 | adap->demux.dmx.close(&adap->demux.dmx); | ||
604 | dvb_dmxdev_release(&adap->dmxdev); | ||
605 | err_dmx_release: | ||
606 | dvb_dmx_release(demux); | ||
607 | err_unregister_adapter: | ||
608 | dvb_unregister_adapter(dvb_adap); | ||
609 | err_free_page: | ||
610 | free_page((unsigned long)buf); | ||
611 | err_kfree: | ||
612 | kfree(adap); | ||
613 | err: | ||
614 | return ERR_PTR(ret); | ||
615 | } | ||
616 | |||
617 | static void pt1_cleanup_adapters(struct pt1 *pt1) | ||
618 | { | ||
619 | int i; | ||
620 | for (i = 0; i < PT1_NR_ADAPS; i++) | ||
621 | pt1_free_adapter(pt1->adaps[i]); | ||
622 | } | ||
623 | |||
624 | struct pt1_config { | ||
625 | struct va1j5jf8007s_config va1j5jf8007s_config; | ||
626 | struct va1j5jf8007t_config va1j5jf8007t_config; | ||
627 | }; | ||
628 | |||
629 | static const struct pt1_config pt1_configs[2] = { | ||
630 | { | ||
631 | { .demod_address = 0x1b }, | ||
632 | { .demod_address = 0x1a }, | ||
633 | }, { | ||
634 | { .demod_address = 0x19 }, | ||
635 | { .demod_address = 0x18 }, | ||
636 | }, | ||
637 | }; | ||
638 | |||
639 | static int pt1_init_adapters(struct pt1 *pt1) | ||
640 | { | ||
641 | int i, j; | ||
642 | struct i2c_adapter *i2c_adap; | ||
643 | const struct pt1_config *config; | ||
644 | struct dvb_frontend *fe[4]; | ||
645 | struct pt1_adapter *adap; | ||
646 | int ret; | ||
647 | |||
648 | i = 0; | ||
649 | j = 0; | ||
650 | |||
651 | i2c_adap = &pt1->i2c_adap; | ||
652 | do { | ||
653 | config = &pt1_configs[i / 2]; | ||
654 | |||
655 | fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config, | ||
656 | i2c_adap); | ||
657 | if (!fe[i]) { | ||
658 | ret = -ENODEV; /* This does not sound nice... */ | ||
659 | goto err; | ||
660 | } | ||
661 | i++; | ||
662 | |||
663 | fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config, | ||
664 | i2c_adap); | ||
665 | if (!fe[i]) { | ||
666 | ret = -ENODEV; | ||
667 | goto err; | ||
668 | } | ||
669 | i++; | ||
670 | |||
671 | ret = va1j5jf8007s_prepare(fe[i - 2]); | ||
672 | if (ret < 0) | ||
673 | goto err; | ||
674 | |||
675 | ret = va1j5jf8007t_prepare(fe[i - 1]); | ||
676 | if (ret < 0) | ||
677 | goto err; | ||
678 | |||
679 | } while (i < 4); | ||
680 | |||
681 | do { | ||
682 | adap = pt1_alloc_adapter(pt1, fe[j]); | ||
683 | if (IS_ERR(adap)) | ||
684 | goto err; | ||
685 | adap->index = j; | ||
686 | pt1->adaps[j] = adap; | ||
687 | } while (++j < 4); | ||
688 | |||
689 | return 0; | ||
690 | |||
691 | err: | ||
692 | while (i-- > j) | ||
693 | fe[i]->ops.release(fe[i]); | ||
694 | |||
695 | while (j--) | ||
696 | pt1_free_adapter(pt1->adaps[j]); | ||
697 | |||
698 | return ret; | ||
699 | } | ||
700 | |||
701 | static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable, | ||
702 | int clock, int data, int next_addr) | ||
703 | { | ||
704 | pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 | | ||
705 | !clock << 11 | !data << 10 | next_addr); | ||
706 | } | ||
707 | |||
708 | static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data) | ||
709 | { | ||
710 | pt1_i2c_emit(pt1, addr, 1, 0, 0, data, addr + 1); | ||
711 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2); | ||
712 | pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3); | ||
713 | *addrp = addr + 3; | ||
714 | } | ||
715 | |||
716 | static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp) | ||
717 | { | ||
718 | pt1_i2c_emit(pt1, addr, 1, 0, 0, 1, addr + 1); | ||
719 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2); | ||
720 | pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3); | ||
721 | pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4); | ||
722 | *addrp = addr + 4; | ||
723 | } | ||
724 | |||
725 | static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data) | ||
726 | { | ||
727 | int i; | ||
728 | for (i = 0; i < 8; i++) | ||
729 | pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1); | ||
730 | pt1_i2c_write_bit(pt1, addr, &addr, 1); | ||
731 | *addrp = addr; | ||
732 | } | ||
733 | |||
734 | static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last) | ||
735 | { | ||
736 | int i; | ||
737 | for (i = 0; i < 8; i++) | ||
738 | pt1_i2c_read_bit(pt1, addr, &addr); | ||
739 | pt1_i2c_write_bit(pt1, addr, &addr, last); | ||
740 | *addrp = addr; | ||
741 | } | ||
742 | |||
743 | static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp) | ||
744 | { | ||
745 | pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); | ||
746 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); | ||
747 | pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3); | ||
748 | *addrp = addr + 3; | ||
749 | } | ||
750 | |||
751 | static void | ||
752 | pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) | ||
753 | { | ||
754 | int i; | ||
755 | pt1_i2c_prepare(pt1, addr, &addr); | ||
756 | pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1); | ||
757 | for (i = 0; i < msg->len; i++) | ||
758 | pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]); | ||
759 | *addrp = addr; | ||
760 | } | ||
761 | |||
762 | static void | ||
763 | pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) | ||
764 | { | ||
765 | int i; | ||
766 | pt1_i2c_prepare(pt1, addr, &addr); | ||
767 | pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1); | ||
768 | for (i = 0; i < msg->len; i++) | ||
769 | pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1); | ||
770 | *addrp = addr; | ||
771 | } | ||
772 | |||
773 | static int pt1_i2c_end(struct pt1 *pt1, int addr) | ||
774 | { | ||
775 | pt1_i2c_emit(pt1, addr, 1, 0, 0, 0, addr + 1); | ||
776 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); | ||
777 | pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0); | ||
778 | |||
779 | pt1_write_reg(pt1, 0, 0x00000004); | ||
780 | do { | ||
781 | if (signal_pending(current)) | ||
782 | return -EINTR; | ||
783 | schedule_timeout_interruptible((HZ + 999) / 1000); | ||
784 | } while (pt1_read_reg(pt1, 0) & 0x00000080); | ||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | static void pt1_i2c_begin(struct pt1 *pt1, int *addrp) | ||
789 | { | ||
790 | int addr; | ||
791 | addr = 0; | ||
792 | |||
793 | pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */); | ||
794 | addr = addr + 1; | ||
795 | |||
796 | if (!pt1->i2c_running) { | ||
797 | pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); | ||
798 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); | ||
799 | addr = addr + 2; | ||
800 | pt1->i2c_running = 1; | ||
801 | } | ||
802 | *addrp = addr; | ||
803 | } | ||
804 | |||
805 | static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | ||
806 | { | ||
807 | struct pt1 *pt1; | ||
808 | int i; | ||
809 | struct i2c_msg *msg, *next_msg; | ||
810 | int addr, ret; | ||
811 | u16 len; | ||
812 | u32 word; | ||
813 | |||
814 | pt1 = i2c_get_adapdata(adap); | ||
815 | |||
816 | for (i = 0; i < num; i++) { | ||
817 | msg = &msgs[i]; | ||
818 | if (msg->flags & I2C_M_RD) | ||
819 | return -ENOTSUPP; | ||
820 | |||
821 | if (i + 1 < num) | ||
822 | next_msg = &msgs[i + 1]; | ||
823 | else | ||
824 | next_msg = NULL; | ||
825 | |||
826 | if (next_msg && next_msg->flags & I2C_M_RD) { | ||
827 | i++; | ||
828 | |||
829 | len = next_msg->len; | ||
830 | if (len > 4) | ||
831 | return -ENOTSUPP; | ||
832 | |||
833 | pt1_i2c_begin(pt1, &addr); | ||
834 | pt1_i2c_write_msg(pt1, addr, &addr, msg); | ||
835 | pt1_i2c_read_msg(pt1, addr, &addr, next_msg); | ||
836 | ret = pt1_i2c_end(pt1, addr); | ||
837 | if (ret < 0) | ||
838 | return ret; | ||
839 | |||
840 | word = pt1_read_reg(pt1, 2); | ||
841 | while (len--) { | ||
842 | next_msg->buf[len] = word; | ||
843 | word >>= 8; | ||
844 | } | ||
845 | } else { | ||
846 | pt1_i2c_begin(pt1, &addr); | ||
847 | pt1_i2c_write_msg(pt1, addr, &addr, msg); | ||
848 | ret = pt1_i2c_end(pt1, addr); | ||
849 | if (ret < 0) | ||
850 | return ret; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | return num; | ||
855 | } | ||
856 | |||
857 | static u32 pt1_i2c_func(struct i2c_adapter *adap) | ||
858 | { | ||
859 | return I2C_FUNC_I2C; | ||
860 | } | ||
861 | |||
862 | static const struct i2c_algorithm pt1_i2c_algo = { | ||
863 | .master_xfer = pt1_i2c_xfer, | ||
864 | .functionality = pt1_i2c_func, | ||
865 | }; | ||
866 | |||
867 | static void pt1_i2c_wait(struct pt1 *pt1) | ||
868 | { | ||
869 | int i; | ||
870 | for (i = 0; i < 128; i++) | ||
871 | pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0); | ||
872 | } | ||
873 | |||
874 | static void pt1_i2c_init(struct pt1 *pt1) | ||
875 | { | ||
876 | int i; | ||
877 | for (i = 0; i < 1024; i++) | ||
878 | pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0); | ||
879 | } | ||
880 | |||
881 | static void __devexit pt1_remove(struct pci_dev *pdev) | ||
882 | { | ||
883 | struct pt1 *pt1; | ||
884 | void __iomem *regs; | ||
885 | |||
886 | pt1 = pci_get_drvdata(pdev); | ||
887 | regs = pt1->regs; | ||
888 | |||
889 | kthread_stop(pt1->kthread); | ||
890 | pt1_cleanup_tables(pt1); | ||
891 | pt1_cleanup_adapters(pt1); | ||
892 | pt1_disable_ram(pt1); | ||
893 | pt1_set_power(pt1, 0, 0, 1); | ||
894 | i2c_del_adapter(&pt1->i2c_adap); | ||
895 | pci_set_drvdata(pdev, NULL); | ||
896 | kfree(pt1); | ||
897 | pci_iounmap(pdev, regs); | ||
898 | pci_release_regions(pdev); | ||
899 | pci_disable_device(pdev); | ||
900 | } | ||
901 | |||
902 | static int __devinit | ||
903 | pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
904 | { | ||
905 | int ret; | ||
906 | void __iomem *regs; | ||
907 | struct pt1 *pt1; | ||
908 | struct i2c_adapter *i2c_adap; | ||
909 | struct task_struct *kthread; | ||
910 | |||
911 | ret = pci_enable_device(pdev); | ||
912 | if (ret < 0) | ||
913 | goto err; | ||
914 | |||
915 | ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
916 | if (ret < 0) | ||
917 | goto err_pci_disable_device; | ||
918 | |||
919 | pci_set_master(pdev); | ||
920 | |||
921 | ret = pci_request_regions(pdev, DRIVER_NAME); | ||
922 | if (ret < 0) | ||
923 | goto err_pci_disable_device; | ||
924 | |||
925 | regs = pci_iomap(pdev, 0, 0); | ||
926 | if (!regs) { | ||
927 | ret = -EIO; | ||
928 | goto err_pci_release_regions; | ||
929 | } | ||
930 | |||
931 | pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL); | ||
932 | if (!pt1) { | ||
933 | ret = -ENOMEM; | ||
934 | goto err_pci_iounmap; | ||
935 | } | ||
936 | |||
937 | pt1->pdev = pdev; | ||
938 | pt1->regs = regs; | ||
939 | pci_set_drvdata(pdev, pt1); | ||
940 | |||
941 | i2c_adap = &pt1->i2c_adap; | ||
942 | i2c_adap->class = I2C_CLASS_TV_DIGITAL; | ||
943 | i2c_adap->algo = &pt1_i2c_algo; | ||
944 | i2c_adap->algo_data = NULL; | ||
945 | i2c_adap->dev.parent = &pdev->dev; | ||
946 | i2c_set_adapdata(i2c_adap, pt1); | ||
947 | ret = i2c_add_adapter(i2c_adap); | ||
948 | if (ret < 0) | ||
949 | goto err_kfree; | ||
950 | |||
951 | pt1_set_power(pt1, 0, 0, 1); | ||
952 | |||
953 | pt1_i2c_init(pt1); | ||
954 | pt1_i2c_wait(pt1); | ||
955 | |||
956 | ret = pt1_sync(pt1); | ||
957 | if (ret < 0) | ||
958 | goto err_i2c_del_adapter; | ||
959 | |||
960 | pt1_identify(pt1); | ||
961 | |||
962 | ret = pt1_unlock(pt1); | ||
963 | if (ret < 0) | ||
964 | goto err_i2c_del_adapter; | ||
965 | |||
966 | ret = pt1_reset_pci(pt1); | ||
967 | if (ret < 0) | ||
968 | goto err_i2c_del_adapter; | ||
969 | |||
970 | ret = pt1_reset_ram(pt1); | ||
971 | if (ret < 0) | ||
972 | goto err_i2c_del_adapter; | ||
973 | |||
974 | ret = pt1_enable_ram(pt1); | ||
975 | if (ret < 0) | ||
976 | goto err_i2c_del_adapter; | ||
977 | |||
978 | pt1_init_streams(pt1); | ||
979 | |||
980 | pt1_set_power(pt1, 1, 0, 1); | ||
981 | schedule_timeout_uninterruptible((HZ + 49) / 50); | ||
982 | |||
983 | pt1_set_power(pt1, 1, 0, 0); | ||
984 | schedule_timeout_uninterruptible((HZ + 999) / 1000); | ||
985 | |||
986 | ret = pt1_init_adapters(pt1); | ||
987 | if (ret < 0) | ||
988 | goto err_pt1_disable_ram; | ||
989 | |||
990 | ret = pt1_init_tables(pt1); | ||
991 | if (ret < 0) | ||
992 | goto err_pt1_cleanup_adapters; | ||
993 | |||
994 | kthread = kthread_run(pt1_thread, pt1, "pt1"); | ||
995 | if (IS_ERR(kthread)) { | ||
996 | ret = PTR_ERR(kthread); | ||
997 | goto err_pt1_cleanup_tables; | ||
998 | } | ||
999 | |||
1000 | pt1->kthread = kthread; | ||
1001 | return 0; | ||
1002 | |||
1003 | err_pt1_cleanup_tables: | ||
1004 | pt1_cleanup_tables(pt1); | ||
1005 | err_pt1_cleanup_adapters: | ||
1006 | pt1_cleanup_adapters(pt1); | ||
1007 | err_pt1_disable_ram: | ||
1008 | pt1_disable_ram(pt1); | ||
1009 | pt1_set_power(pt1, 0, 0, 1); | ||
1010 | err_i2c_del_adapter: | ||
1011 | i2c_del_adapter(i2c_adap); | ||
1012 | err_kfree: | ||
1013 | pci_set_drvdata(pdev, NULL); | ||
1014 | kfree(pt1); | ||
1015 | err_pci_iounmap: | ||
1016 | pci_iounmap(pdev, regs); | ||
1017 | err_pci_release_regions: | ||
1018 | pci_release_regions(pdev); | ||
1019 | err_pci_disable_device: | ||
1020 | pci_disable_device(pdev); | ||
1021 | err: | ||
1022 | return ret; | ||
1023 | |||
1024 | } | ||
1025 | |||
1026 | static struct pci_device_id pt1_id_table[] = { | ||
1027 | { PCI_DEVICE(0x10ee, 0x211a) }, | ||
1028 | { }, | ||
1029 | }; | ||
1030 | MODULE_DEVICE_TABLE(pci, pt1_id_table); | ||
1031 | |||
1032 | static struct pci_driver pt1_driver = { | ||
1033 | .name = DRIVER_NAME, | ||
1034 | .probe = pt1_probe, | ||
1035 | .remove = __devexit_p(pt1_remove), | ||
1036 | .id_table = pt1_id_table, | ||
1037 | }; | ||
1038 | |||
1039 | |||
1040 | static int __init pt1_init(void) | ||
1041 | { | ||
1042 | return pci_register_driver(&pt1_driver); | ||
1043 | } | ||
1044 | |||
1045 | |||
1046 | static void __exit pt1_cleanup(void) | ||
1047 | { | ||
1048 | pci_unregister_driver(&pt1_driver); | ||
1049 | } | ||
1050 | |||
1051 | module_init(pt1_init); | ||
1052 | module_exit(pt1_cleanup); | ||
1053 | |||
1054 | MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>"); | ||
1055 | MODULE_DESCRIPTION("Earthsoft PT1 Driver"); | ||
1056 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c new file mode 100644 index 000000000000..2db940f8635f --- /dev/null +++ b/drivers/media/dvb/pt1/va1j5jf8007s.c | |||
@@ -0,0 +1,658 @@ | |||
1 | /* | ||
2 | * ISDB-S driver for VA1J5JF8007 | ||
3 | * | ||
4 | * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | ||
5 | * | ||
6 | * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | ||
7 | * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | ||
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 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include "dvb_frontend.h" | ||
29 | #include "va1j5jf8007s.h" | ||
30 | |||
31 | enum va1j5jf8007s_tune_state { | ||
32 | VA1J5JF8007S_IDLE, | ||
33 | VA1J5JF8007S_SET_FREQUENCY_1, | ||
34 | VA1J5JF8007S_SET_FREQUENCY_2, | ||
35 | VA1J5JF8007S_SET_FREQUENCY_3, | ||
36 | VA1J5JF8007S_CHECK_FREQUENCY, | ||
37 | VA1J5JF8007S_SET_MODULATION, | ||
38 | VA1J5JF8007S_CHECK_MODULATION, | ||
39 | VA1J5JF8007S_SET_TS_ID, | ||
40 | VA1J5JF8007S_CHECK_TS_ID, | ||
41 | VA1J5JF8007S_TRACK, | ||
42 | }; | ||
43 | |||
44 | struct va1j5jf8007s_state { | ||
45 | const struct va1j5jf8007s_config *config; | ||
46 | struct i2c_adapter *adap; | ||
47 | struct dvb_frontend fe; | ||
48 | enum va1j5jf8007s_tune_state tune_state; | ||
49 | }; | ||
50 | |||
51 | static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe) | ||
52 | { | ||
53 | return DVBFE_ALGO_HW; | ||
54 | } | ||
55 | |||
56 | static int | ||
57 | va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
58 | { | ||
59 | struct va1j5jf8007s_state *state; | ||
60 | |||
61 | state = fe->demodulator_priv; | ||
62 | |||
63 | switch (state->tune_state) { | ||
64 | case VA1J5JF8007S_IDLE: | ||
65 | case VA1J5JF8007S_SET_FREQUENCY_1: | ||
66 | case VA1J5JF8007S_SET_FREQUENCY_2: | ||
67 | case VA1J5JF8007S_SET_FREQUENCY_3: | ||
68 | case VA1J5JF8007S_CHECK_FREQUENCY: | ||
69 | *status = 0; | ||
70 | return 0; | ||
71 | |||
72 | |||
73 | case VA1J5JF8007S_SET_MODULATION: | ||
74 | case VA1J5JF8007S_CHECK_MODULATION: | ||
75 | *status |= FE_HAS_SIGNAL; | ||
76 | return 0; | ||
77 | |||
78 | case VA1J5JF8007S_SET_TS_ID: | ||
79 | case VA1J5JF8007S_CHECK_TS_ID: | ||
80 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
81 | return 0; | ||
82 | |||
83 | case VA1J5JF8007S_TRACK: | ||
84 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | BUG(); | ||
89 | } | ||
90 | |||
91 | struct va1j5jf8007s_cb_map { | ||
92 | u32 frequency; | ||
93 | u8 cb; | ||
94 | }; | ||
95 | |||
96 | static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = { | ||
97 | { 986000, 0xb2 }, | ||
98 | { 1072000, 0xd2 }, | ||
99 | { 1154000, 0xe2 }, | ||
100 | { 1291000, 0x20 }, | ||
101 | { 1447000, 0x40 }, | ||
102 | { 1615000, 0x60 }, | ||
103 | { 1791000, 0x80 }, | ||
104 | { 1972000, 0xa0 }, | ||
105 | }; | ||
106 | |||
107 | static u8 va1j5jf8007s_lookup_cb(u32 frequency) | ||
108 | { | ||
109 | int i; | ||
110 | const struct va1j5jf8007s_cb_map *map; | ||
111 | |||
112 | for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) { | ||
113 | map = &va1j5jf8007s_cb_maps[i]; | ||
114 | if (frequency < map->frequency) | ||
115 | return map->cb; | ||
116 | } | ||
117 | return 0xc0; | ||
118 | } | ||
119 | |||
120 | static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state) | ||
121 | { | ||
122 | u32 frequency; | ||
123 | u16 word; | ||
124 | u8 buf[6]; | ||
125 | struct i2c_msg msg; | ||
126 | |||
127 | frequency = state->fe.dtv_property_cache.frequency; | ||
128 | |||
129 | word = (frequency + 500) / 1000; | ||
130 | if (frequency < 1072000) | ||
131 | word = (word << 1 & ~0x1f) | (word & 0x0f); | ||
132 | |||
133 | buf[0] = 0xfe; | ||
134 | buf[1] = 0xc0; | ||
135 | buf[2] = 0x40 | word >> 8; | ||
136 | buf[3] = word; | ||
137 | buf[4] = 0xe0; | ||
138 | buf[5] = va1j5jf8007s_lookup_cb(frequency); | ||
139 | |||
140 | msg.addr = state->config->demod_address; | ||
141 | msg.flags = 0; | ||
142 | msg.len = sizeof(buf); | ||
143 | msg.buf = buf; | ||
144 | |||
145 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
146 | return -EREMOTEIO; | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state) | ||
152 | { | ||
153 | u8 buf[3]; | ||
154 | struct i2c_msg msg; | ||
155 | |||
156 | buf[0] = 0xfe; | ||
157 | buf[1] = 0xc0; | ||
158 | buf[2] = 0xe4; | ||
159 | |||
160 | msg.addr = state->config->demod_address; | ||
161 | msg.flags = 0; | ||
162 | msg.len = sizeof(buf); | ||
163 | msg.buf = buf; | ||
164 | |||
165 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
166 | return -EREMOTEIO; | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state) | ||
172 | { | ||
173 | u32 frequency; | ||
174 | u8 buf[4]; | ||
175 | struct i2c_msg msg; | ||
176 | |||
177 | frequency = state->fe.dtv_property_cache.frequency; | ||
178 | |||
179 | buf[0] = 0xfe; | ||
180 | buf[1] = 0xc0; | ||
181 | buf[2] = 0xf4; | ||
182 | buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4; | ||
183 | |||
184 | msg.addr = state->config->demod_address; | ||
185 | msg.flags = 0; | ||
186 | msg.len = sizeof(buf); | ||
187 | msg.buf = buf; | ||
188 | |||
189 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
190 | return -EREMOTEIO; | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int | ||
196 | va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock) | ||
197 | { | ||
198 | u8 addr; | ||
199 | u8 write_buf[2], read_buf[1]; | ||
200 | struct i2c_msg msgs[2]; | ||
201 | |||
202 | addr = state->config->demod_address; | ||
203 | |||
204 | write_buf[0] = 0xfe; | ||
205 | write_buf[1] = 0xc1; | ||
206 | |||
207 | msgs[0].addr = addr; | ||
208 | msgs[0].flags = 0; | ||
209 | msgs[0].len = sizeof(write_buf); | ||
210 | msgs[0].buf = write_buf; | ||
211 | |||
212 | msgs[1].addr = addr; | ||
213 | msgs[1].flags = I2C_M_RD; | ||
214 | msgs[1].len = sizeof(read_buf); | ||
215 | msgs[1].buf = read_buf; | ||
216 | |||
217 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
218 | return -EREMOTEIO; | ||
219 | |||
220 | *lock = read_buf[0] & 0x40; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state) | ||
225 | { | ||
226 | u8 buf[2]; | ||
227 | struct i2c_msg msg; | ||
228 | |||
229 | buf[0] = 0x03; | ||
230 | buf[1] = 0x01; | ||
231 | |||
232 | msg.addr = state->config->demod_address; | ||
233 | msg.flags = 0; | ||
234 | msg.len = sizeof(buf); | ||
235 | msg.buf = buf; | ||
236 | |||
237 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
238 | return -EREMOTEIO; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int | ||
244 | va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock) | ||
245 | { | ||
246 | u8 addr; | ||
247 | u8 write_buf[1], read_buf[1]; | ||
248 | struct i2c_msg msgs[2]; | ||
249 | |||
250 | addr = state->config->demod_address; | ||
251 | |||
252 | write_buf[0] = 0xc3; | ||
253 | |||
254 | msgs[0].addr = addr; | ||
255 | msgs[0].flags = 0; | ||
256 | msgs[0].len = sizeof(write_buf); | ||
257 | msgs[0].buf = write_buf; | ||
258 | |||
259 | msgs[1].addr = addr; | ||
260 | msgs[1].flags = I2C_M_RD; | ||
261 | msgs[1].len = sizeof(read_buf); | ||
262 | msgs[1].buf = read_buf; | ||
263 | |||
264 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
265 | return -EREMOTEIO; | ||
266 | |||
267 | *lock = !(read_buf[0] & 0x10); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int | ||
272 | va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state) | ||
273 | { | ||
274 | u32 ts_id; | ||
275 | u8 buf[3]; | ||
276 | struct i2c_msg msg; | ||
277 | |||
278 | ts_id = state->fe.dtv_property_cache.isdbs_ts_id; | ||
279 | if (!ts_id) | ||
280 | return 0; | ||
281 | |||
282 | buf[0] = 0x8f; | ||
283 | buf[1] = ts_id >> 8; | ||
284 | buf[2] = ts_id; | ||
285 | |||
286 | msg.addr = state->config->demod_address; | ||
287 | msg.flags = 0; | ||
288 | msg.len = sizeof(buf); | ||
289 | msg.buf = buf; | ||
290 | |||
291 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
292 | return -EREMOTEIO; | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int | ||
298 | va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock) | ||
299 | { | ||
300 | u8 addr; | ||
301 | u8 write_buf[1], read_buf[2]; | ||
302 | struct i2c_msg msgs[2]; | ||
303 | u32 ts_id; | ||
304 | |||
305 | ts_id = state->fe.dtv_property_cache.isdbs_ts_id; | ||
306 | if (!ts_id) { | ||
307 | *lock = 1; | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | addr = state->config->demod_address; | ||
312 | |||
313 | write_buf[0] = 0xe6; | ||
314 | |||
315 | msgs[0].addr = addr; | ||
316 | msgs[0].flags = 0; | ||
317 | msgs[0].len = sizeof(write_buf); | ||
318 | msgs[0].buf = write_buf; | ||
319 | |||
320 | msgs[1].addr = addr; | ||
321 | msgs[1].flags = I2C_M_RD; | ||
322 | msgs[1].len = sizeof(read_buf); | ||
323 | msgs[1].buf = read_buf; | ||
324 | |||
325 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
326 | return -EREMOTEIO; | ||
327 | |||
328 | *lock = (read_buf[0] << 8 | read_buf[1]) == ts_id; | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int | ||
333 | va1j5jf8007s_tune(struct dvb_frontend *fe, | ||
334 | struct dvb_frontend_parameters *params, | ||
335 | unsigned int mode_flags, unsigned int *delay, | ||
336 | fe_status_t *status) | ||
337 | { | ||
338 | struct va1j5jf8007s_state *state; | ||
339 | int ret; | ||
340 | int lock; | ||
341 | |||
342 | state = fe->demodulator_priv; | ||
343 | |||
344 | if (params != NULL) | ||
345 | state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1; | ||
346 | |||
347 | switch (state->tune_state) { | ||
348 | case VA1J5JF8007S_IDLE: | ||
349 | *delay = 3 * HZ; | ||
350 | *status = 0; | ||
351 | return 0; | ||
352 | |||
353 | case VA1J5JF8007S_SET_FREQUENCY_1: | ||
354 | ret = va1j5jf8007s_set_frequency_1(state); | ||
355 | if (ret < 0) | ||
356 | return ret; | ||
357 | |||
358 | state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2; | ||
359 | *delay = 0; | ||
360 | *status = 0; | ||
361 | return 0; | ||
362 | |||
363 | case VA1J5JF8007S_SET_FREQUENCY_2: | ||
364 | ret = va1j5jf8007s_set_frequency_2(state); | ||
365 | if (ret < 0) | ||
366 | return ret; | ||
367 | |||
368 | state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3; | ||
369 | *delay = (HZ + 99) / 100; | ||
370 | *status = 0; | ||
371 | return 0; | ||
372 | |||
373 | case VA1J5JF8007S_SET_FREQUENCY_3: | ||
374 | ret = va1j5jf8007s_set_frequency_3(state); | ||
375 | if (ret < 0) | ||
376 | return ret; | ||
377 | |||
378 | state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY; | ||
379 | *delay = 0; | ||
380 | *status = 0; | ||
381 | return 0; | ||
382 | |||
383 | case VA1J5JF8007S_CHECK_FREQUENCY: | ||
384 | ret = va1j5jf8007s_check_frequency(state, &lock); | ||
385 | if (ret < 0) | ||
386 | return ret; | ||
387 | |||
388 | if (!lock) { | ||
389 | *delay = (HZ + 999) / 1000; | ||
390 | *status = 0; | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | state->tune_state = VA1J5JF8007S_SET_MODULATION; | ||
395 | *delay = 0; | ||
396 | *status = FE_HAS_SIGNAL; | ||
397 | return 0; | ||
398 | |||
399 | case VA1J5JF8007S_SET_MODULATION: | ||
400 | ret = va1j5jf8007s_set_modulation(state); | ||
401 | if (ret < 0) | ||
402 | return ret; | ||
403 | |||
404 | state->tune_state = VA1J5JF8007S_CHECK_MODULATION; | ||
405 | *delay = 0; | ||
406 | *status = FE_HAS_SIGNAL; | ||
407 | return 0; | ||
408 | |||
409 | case VA1J5JF8007S_CHECK_MODULATION: | ||
410 | ret = va1j5jf8007s_check_modulation(state, &lock); | ||
411 | if (ret < 0) | ||
412 | return ret; | ||
413 | |||
414 | if (!lock) { | ||
415 | *delay = (HZ + 49) / 50; | ||
416 | *status = FE_HAS_SIGNAL; | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | state->tune_state = VA1J5JF8007S_SET_TS_ID; | ||
421 | *delay = 0; | ||
422 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
423 | return 0; | ||
424 | |||
425 | case VA1J5JF8007S_SET_TS_ID: | ||
426 | ret = va1j5jf8007s_set_ts_id(state); | ||
427 | if (ret < 0) | ||
428 | return ret; | ||
429 | |||
430 | state->tune_state = VA1J5JF8007S_CHECK_TS_ID; | ||
431 | return 0; | ||
432 | |||
433 | case VA1J5JF8007S_CHECK_TS_ID: | ||
434 | ret = va1j5jf8007s_check_ts_id(state, &lock); | ||
435 | if (ret < 0) | ||
436 | return ret; | ||
437 | |||
438 | if (!lock) { | ||
439 | *delay = (HZ + 99) / 100; | ||
440 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | state->tune_state = VA1J5JF8007S_TRACK; | ||
445 | /* fall through */ | ||
446 | |||
447 | case VA1J5JF8007S_TRACK: | ||
448 | *delay = 3 * HZ; | ||
449 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | BUG(); | ||
454 | } | ||
455 | |||
456 | static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state) | ||
457 | { | ||
458 | u8 buf[4]; | ||
459 | struct i2c_msg msg; | ||
460 | |||
461 | buf[0] = 0xfe; | ||
462 | buf[1] = 0xc0; | ||
463 | buf[2] = 0xf0; | ||
464 | buf[3] = 0x04; | ||
465 | |||
466 | msg.addr = state->config->demod_address; | ||
467 | msg.flags = 0; | ||
468 | msg.len = sizeof(buf); | ||
469 | msg.buf = buf; | ||
470 | |||
471 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
472 | return -EREMOTEIO; | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep) | ||
478 | { | ||
479 | u8 buf[2]; | ||
480 | struct i2c_msg msg; | ||
481 | |||
482 | buf[0] = 0x17; | ||
483 | buf[1] = sleep ? 0x01 : 0x00; | ||
484 | |||
485 | msg.addr = state->config->demod_address; | ||
486 | msg.flags = 0; | ||
487 | msg.len = sizeof(buf); | ||
488 | msg.buf = buf; | ||
489 | |||
490 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
491 | return -EREMOTEIO; | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int va1j5jf8007s_sleep(struct dvb_frontend *fe) | ||
497 | { | ||
498 | struct va1j5jf8007s_state *state; | ||
499 | int ret; | ||
500 | |||
501 | state = fe->demodulator_priv; | ||
502 | |||
503 | ret = va1j5jf8007s_init_frequency(state); | ||
504 | if (ret < 0) | ||
505 | return ret; | ||
506 | |||
507 | return va1j5jf8007s_set_sleep(state, 1); | ||
508 | } | ||
509 | |||
510 | static int va1j5jf8007s_init(struct dvb_frontend *fe) | ||
511 | { | ||
512 | struct va1j5jf8007s_state *state; | ||
513 | |||
514 | state = fe->demodulator_priv; | ||
515 | state->tune_state = VA1J5JF8007S_IDLE; | ||
516 | |||
517 | return va1j5jf8007s_set_sleep(state, 0); | ||
518 | } | ||
519 | |||
520 | static void va1j5jf8007s_release(struct dvb_frontend *fe) | ||
521 | { | ||
522 | struct va1j5jf8007s_state *state; | ||
523 | state = fe->demodulator_priv; | ||
524 | kfree(state); | ||
525 | } | ||
526 | |||
527 | static struct dvb_frontend_ops va1j5jf8007s_ops = { | ||
528 | .info = { | ||
529 | .name = "VA1J5JF8007 ISDB-S", | ||
530 | .type = FE_QPSK, | ||
531 | .frequency_min = 950000, | ||
532 | .frequency_max = 2150000, | ||
533 | .frequency_stepsize = 1000, | ||
534 | .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | | ||
535 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
536 | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, | ||
537 | }, | ||
538 | |||
539 | .get_frontend_algo = va1j5jf8007s_get_frontend_algo, | ||
540 | .read_status = va1j5jf8007s_read_status, | ||
541 | .tune = va1j5jf8007s_tune, | ||
542 | .sleep = va1j5jf8007s_sleep, | ||
543 | .init = va1j5jf8007s_init, | ||
544 | .release = va1j5jf8007s_release, | ||
545 | }; | ||
546 | |||
547 | static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state) | ||
548 | { | ||
549 | u8 addr; | ||
550 | u8 write_buf[1], read_buf[1]; | ||
551 | struct i2c_msg msgs[2]; | ||
552 | |||
553 | addr = state->config->demod_address; | ||
554 | |||
555 | write_buf[0] = 0x07; | ||
556 | |||
557 | msgs[0].addr = addr; | ||
558 | msgs[0].flags = 0; | ||
559 | msgs[0].len = sizeof(write_buf); | ||
560 | msgs[0].buf = write_buf; | ||
561 | |||
562 | msgs[1].addr = addr; | ||
563 | msgs[1].flags = I2C_M_RD; | ||
564 | msgs[1].len = sizeof(read_buf); | ||
565 | msgs[1].buf = read_buf; | ||
566 | |||
567 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
568 | return -EREMOTEIO; | ||
569 | |||
570 | if (read_buf[0] != 0x41) | ||
571 | return -EIO; | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | static const u8 va1j5jf8007s_prepare_bufs[][2] = { | ||
577 | {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, | ||
578 | {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, | ||
579 | {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, | ||
580 | {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, | ||
581 | }; | ||
582 | |||
583 | static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state) | ||
584 | { | ||
585 | u8 addr; | ||
586 | u8 buf[2]; | ||
587 | struct i2c_msg msg; | ||
588 | int i; | ||
589 | |||
590 | addr = state->config->demod_address; | ||
591 | |||
592 | msg.addr = addr; | ||
593 | msg.flags = 0; | ||
594 | msg.len = 2; | ||
595 | msg.buf = buf; | ||
596 | for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_prepare_bufs); i++) { | ||
597 | memcpy(buf, va1j5jf8007s_prepare_bufs[i], sizeof(buf)); | ||
598 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
599 | return -EREMOTEIO; | ||
600 | } | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | /* must be called after va1j5jf8007t_attach */ | ||
606 | int va1j5jf8007s_prepare(struct dvb_frontend *fe) | ||
607 | { | ||
608 | struct va1j5jf8007s_state *state; | ||
609 | int ret; | ||
610 | |||
611 | state = fe->demodulator_priv; | ||
612 | |||
613 | ret = va1j5jf8007s_prepare_1(state); | ||
614 | if (ret < 0) | ||
615 | return ret; | ||
616 | |||
617 | ret = va1j5jf8007s_prepare_2(state); | ||
618 | if (ret < 0) | ||
619 | return ret; | ||
620 | |||
621 | return va1j5jf8007s_init_frequency(state); | ||
622 | } | ||
623 | |||
624 | struct dvb_frontend * | ||
625 | va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, | ||
626 | struct i2c_adapter *adap) | ||
627 | { | ||
628 | struct va1j5jf8007s_state *state; | ||
629 | struct dvb_frontend *fe; | ||
630 | u8 buf[2]; | ||
631 | struct i2c_msg msg; | ||
632 | |||
633 | state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL); | ||
634 | if (!state) | ||
635 | return NULL; | ||
636 | |||
637 | state->config = config; | ||
638 | state->adap = adap; | ||
639 | |||
640 | fe = &state->fe; | ||
641 | memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops)); | ||
642 | fe->demodulator_priv = state; | ||
643 | |||
644 | buf[0] = 0x01; | ||
645 | buf[1] = 0x80; | ||
646 | |||
647 | msg.addr = state->config->demod_address; | ||
648 | msg.flags = 0; | ||
649 | msg.len = sizeof(buf); | ||
650 | msg.buf = buf; | ||
651 | |||
652 | if (i2c_transfer(state->adap, &msg, 1) != 1) { | ||
653 | kfree(state); | ||
654 | return NULL; | ||
655 | } | ||
656 | |||
657 | return fe; | ||
658 | } | ||
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.h b/drivers/media/dvb/pt1/va1j5jf8007s.h new file mode 100644 index 000000000000..aa228a816353 --- /dev/null +++ b/drivers/media/dvb/pt1/va1j5jf8007s.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * ISDB-S driver for VA1J5JF8007 | ||
3 | * | ||
4 | * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | ||
5 | * | ||
6 | * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | ||
7 | * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | ||
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 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef VA1J5JF8007S_H | ||
25 | #define VA1J5JF8007S_H | ||
26 | |||
27 | struct va1j5jf8007s_config { | ||
28 | u8 demod_address; | ||
29 | }; | ||
30 | |||
31 | struct i2c_adapter; | ||
32 | |||
33 | struct dvb_frontend * | ||
34 | va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, | ||
35 | struct i2c_adapter *adap); | ||
36 | |||
37 | /* must be called after va1j5jf8007t_attach */ | ||
38 | int va1j5jf8007s_prepare(struct dvb_frontend *fe); | ||
39 | |||
40 | #endif | ||
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c new file mode 100644 index 000000000000..71117f4ca7e6 --- /dev/null +++ b/drivers/media/dvb/pt1/va1j5jf8007t.c | |||
@@ -0,0 +1,468 @@ | |||
1 | /* | ||
2 | * ISDB-T driver for VA1J5JF8007 | ||
3 | * | ||
4 | * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | ||
5 | * | ||
6 | * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | ||
7 | * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | ||
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 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include "dvb_frontend.h" | ||
29 | #include "dvb_math.h" | ||
30 | #include "va1j5jf8007t.h" | ||
31 | |||
32 | enum va1j5jf8007t_tune_state { | ||
33 | VA1J5JF8007T_IDLE, | ||
34 | VA1J5JF8007T_SET_FREQUENCY, | ||
35 | VA1J5JF8007T_CHECK_FREQUENCY, | ||
36 | VA1J5JF8007T_SET_MODULATION, | ||
37 | VA1J5JF8007T_CHECK_MODULATION, | ||
38 | VA1J5JF8007T_TRACK, | ||
39 | VA1J5JF8007T_ABORT, | ||
40 | }; | ||
41 | |||
42 | struct va1j5jf8007t_state { | ||
43 | const struct va1j5jf8007t_config *config; | ||
44 | struct i2c_adapter *adap; | ||
45 | struct dvb_frontend fe; | ||
46 | enum va1j5jf8007t_tune_state tune_state; | ||
47 | }; | ||
48 | |||
49 | static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe) | ||
50 | { | ||
51 | return DVBFE_ALGO_HW; | ||
52 | } | ||
53 | |||
54 | static int | ||
55 | va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
56 | { | ||
57 | struct va1j5jf8007t_state *state; | ||
58 | |||
59 | state = fe->demodulator_priv; | ||
60 | |||
61 | switch (state->tune_state) { | ||
62 | case VA1J5JF8007T_IDLE: | ||
63 | case VA1J5JF8007T_SET_FREQUENCY: | ||
64 | case VA1J5JF8007T_CHECK_FREQUENCY: | ||
65 | *status = 0; | ||
66 | return 0; | ||
67 | |||
68 | |||
69 | case VA1J5JF8007T_SET_MODULATION: | ||
70 | case VA1J5JF8007T_CHECK_MODULATION: | ||
71 | case VA1J5JF8007T_ABORT: | ||
72 | *status |= FE_HAS_SIGNAL; | ||
73 | return 0; | ||
74 | |||
75 | case VA1J5JF8007T_TRACK: | ||
76 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | BUG(); | ||
81 | } | ||
82 | |||
83 | struct va1j5jf8007t_cb_map { | ||
84 | u32 frequency; | ||
85 | u8 cb; | ||
86 | }; | ||
87 | |||
88 | static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = { | ||
89 | { 90000000, 0x80 }, | ||
90 | { 140000000, 0x81 }, | ||
91 | { 170000000, 0xa1 }, | ||
92 | { 220000000, 0x62 }, | ||
93 | { 330000000, 0xa2 }, | ||
94 | { 402000000, 0xe2 }, | ||
95 | { 450000000, 0x64 }, | ||
96 | { 550000000, 0x84 }, | ||
97 | { 600000000, 0xa4 }, | ||
98 | { 700000000, 0xc4 }, | ||
99 | }; | ||
100 | |||
101 | static u8 va1j5jf8007t_lookup_cb(u32 frequency) | ||
102 | { | ||
103 | int i; | ||
104 | const struct va1j5jf8007t_cb_map *map; | ||
105 | |||
106 | for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) { | ||
107 | map = &va1j5jf8007t_cb_maps[i]; | ||
108 | if (frequency < map->frequency) | ||
109 | return map->cb; | ||
110 | } | ||
111 | return 0xe4; | ||
112 | } | ||
113 | |||
114 | static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state) | ||
115 | { | ||
116 | u32 frequency; | ||
117 | u16 word; | ||
118 | u8 buf[6]; | ||
119 | struct i2c_msg msg; | ||
120 | |||
121 | frequency = state->fe.dtv_property_cache.frequency; | ||
122 | |||
123 | word = (frequency + 71428) / 142857 + 399; | ||
124 | buf[0] = 0xfe; | ||
125 | buf[1] = 0xc2; | ||
126 | buf[2] = word >> 8; | ||
127 | buf[3] = word; | ||
128 | buf[4] = 0x80; | ||
129 | buf[5] = va1j5jf8007t_lookup_cb(frequency); | ||
130 | |||
131 | msg.addr = state->config->demod_address; | ||
132 | msg.flags = 0; | ||
133 | msg.len = sizeof(buf); | ||
134 | msg.buf = buf; | ||
135 | |||
136 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
137 | return -EREMOTEIO; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int | ||
143 | va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock) | ||
144 | { | ||
145 | u8 addr; | ||
146 | u8 write_buf[2], read_buf[1]; | ||
147 | struct i2c_msg msgs[2]; | ||
148 | |||
149 | addr = state->config->demod_address; | ||
150 | |||
151 | write_buf[0] = 0xfe; | ||
152 | write_buf[1] = 0xc3; | ||
153 | |||
154 | msgs[0].addr = addr; | ||
155 | msgs[0].flags = 0; | ||
156 | msgs[0].len = sizeof(write_buf); | ||
157 | msgs[0].buf = write_buf; | ||
158 | |||
159 | msgs[1].addr = addr; | ||
160 | msgs[1].flags = I2C_M_RD; | ||
161 | msgs[1].len = sizeof(read_buf); | ||
162 | msgs[1].buf = read_buf; | ||
163 | |||
164 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
165 | return -EREMOTEIO; | ||
166 | |||
167 | *lock = read_buf[0] & 0x40; | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state) | ||
172 | { | ||
173 | u8 buf[2]; | ||
174 | struct i2c_msg msg; | ||
175 | |||
176 | buf[0] = 0x01; | ||
177 | buf[1] = 0x40; | ||
178 | |||
179 | msg.addr = state->config->demod_address; | ||
180 | msg.flags = 0; | ||
181 | msg.len = sizeof(buf); | ||
182 | msg.buf = buf; | ||
183 | |||
184 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
185 | return -EREMOTEIO; | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state, | ||
191 | int *lock, int *retry) | ||
192 | { | ||
193 | u8 addr; | ||
194 | u8 write_buf[1], read_buf[1]; | ||
195 | struct i2c_msg msgs[2]; | ||
196 | |||
197 | addr = state->config->demod_address; | ||
198 | |||
199 | write_buf[0] = 0x80; | ||
200 | |||
201 | msgs[0].addr = addr; | ||
202 | msgs[0].flags = 0; | ||
203 | msgs[0].len = sizeof(write_buf); | ||
204 | msgs[0].buf = write_buf; | ||
205 | |||
206 | msgs[1].addr = addr; | ||
207 | msgs[1].flags = I2C_M_RD; | ||
208 | msgs[1].len = sizeof(read_buf); | ||
209 | msgs[1].buf = read_buf; | ||
210 | |||
211 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
212 | return -EREMOTEIO; | ||
213 | |||
214 | *lock = !(read_buf[0] & 0x10); | ||
215 | *retry = read_buf[0] & 0x80; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int | ||
220 | va1j5jf8007t_tune(struct dvb_frontend *fe, | ||
221 | struct dvb_frontend_parameters *params, | ||
222 | unsigned int mode_flags, unsigned int *delay, | ||
223 | fe_status_t *status) | ||
224 | { | ||
225 | struct va1j5jf8007t_state *state; | ||
226 | int ret; | ||
227 | int lock, retry; | ||
228 | |||
229 | state = fe->demodulator_priv; | ||
230 | |||
231 | if (params != NULL) | ||
232 | state->tune_state = VA1J5JF8007T_SET_FREQUENCY; | ||
233 | |||
234 | switch (state->tune_state) { | ||
235 | case VA1J5JF8007T_IDLE: | ||
236 | *delay = 3 * HZ; | ||
237 | *status = 0; | ||
238 | return 0; | ||
239 | |||
240 | case VA1J5JF8007T_SET_FREQUENCY: | ||
241 | ret = va1j5jf8007t_set_frequency(state); | ||
242 | if (ret < 0) | ||
243 | return ret; | ||
244 | |||
245 | state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY; | ||
246 | *delay = 0; | ||
247 | *status = 0; | ||
248 | return 0; | ||
249 | |||
250 | case VA1J5JF8007T_CHECK_FREQUENCY: | ||
251 | ret = va1j5jf8007t_check_frequency(state, &lock); | ||
252 | if (ret < 0) | ||
253 | return ret; | ||
254 | |||
255 | if (!lock) { | ||
256 | *delay = (HZ + 999) / 1000; | ||
257 | *status = 0; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | state->tune_state = VA1J5JF8007T_SET_MODULATION; | ||
262 | *delay = 0; | ||
263 | *status = FE_HAS_SIGNAL; | ||
264 | return 0; | ||
265 | |||
266 | case VA1J5JF8007T_SET_MODULATION: | ||
267 | ret = va1j5jf8007t_set_modulation(state); | ||
268 | if (ret < 0) | ||
269 | return ret; | ||
270 | |||
271 | state->tune_state = VA1J5JF8007T_CHECK_MODULATION; | ||
272 | *delay = 0; | ||
273 | *status = FE_HAS_SIGNAL; | ||
274 | return 0; | ||
275 | |||
276 | case VA1J5JF8007T_CHECK_MODULATION: | ||
277 | ret = va1j5jf8007t_check_modulation(state, &lock, &retry); | ||
278 | if (ret < 0) | ||
279 | return ret; | ||
280 | |||
281 | if (!lock) { | ||
282 | if (!retry) { | ||
283 | state->tune_state = VA1J5JF8007T_ABORT; | ||
284 | *delay = 3 * HZ; | ||
285 | *status = FE_HAS_SIGNAL; | ||
286 | return 0; | ||
287 | } | ||
288 | *delay = (HZ + 999) / 1000; | ||
289 | *status = FE_HAS_SIGNAL; | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | state->tune_state = VA1J5JF8007T_TRACK; | ||
294 | /* fall through */ | ||
295 | |||
296 | case VA1J5JF8007T_TRACK: | ||
297 | *delay = 3 * HZ; | ||
298 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | ||
299 | return 0; | ||
300 | |||
301 | case VA1J5JF8007T_ABORT: | ||
302 | *delay = 3 * HZ; | ||
303 | *status = FE_HAS_SIGNAL; | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | BUG(); | ||
308 | } | ||
309 | |||
310 | static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state) | ||
311 | { | ||
312 | u8 buf[7]; | ||
313 | struct i2c_msg msg; | ||
314 | |||
315 | buf[0] = 0xfe; | ||
316 | buf[1] = 0xc2; | ||
317 | buf[2] = 0x01; | ||
318 | buf[3] = 0x8f; | ||
319 | buf[4] = 0xc1; | ||
320 | buf[5] = 0x80; | ||
321 | buf[6] = 0x80; | ||
322 | |||
323 | msg.addr = state->config->demod_address; | ||
324 | msg.flags = 0; | ||
325 | msg.len = sizeof(buf); | ||
326 | msg.buf = buf; | ||
327 | |||
328 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
329 | return -EREMOTEIO; | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep) | ||
335 | { | ||
336 | u8 buf[2]; | ||
337 | struct i2c_msg msg; | ||
338 | |||
339 | buf[0] = 0x03; | ||
340 | buf[1] = sleep ? 0x90 : 0x80; | ||
341 | |||
342 | msg.addr = state->config->demod_address; | ||
343 | msg.flags = 0; | ||
344 | msg.len = sizeof(buf); | ||
345 | msg.buf = buf; | ||
346 | |||
347 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
348 | return -EREMOTEIO; | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int va1j5jf8007t_sleep(struct dvb_frontend *fe) | ||
354 | { | ||
355 | struct va1j5jf8007t_state *state; | ||
356 | int ret; | ||
357 | |||
358 | state = fe->demodulator_priv; | ||
359 | |||
360 | ret = va1j5jf8007t_init_frequency(state); | ||
361 | if (ret < 0) | ||
362 | return ret; | ||
363 | |||
364 | return va1j5jf8007t_set_sleep(state, 1); | ||
365 | } | ||
366 | |||
367 | static int va1j5jf8007t_init(struct dvb_frontend *fe) | ||
368 | { | ||
369 | struct va1j5jf8007t_state *state; | ||
370 | |||
371 | state = fe->demodulator_priv; | ||
372 | state->tune_state = VA1J5JF8007T_IDLE; | ||
373 | |||
374 | return va1j5jf8007t_set_sleep(state, 0); | ||
375 | } | ||
376 | |||
377 | static void va1j5jf8007t_release(struct dvb_frontend *fe) | ||
378 | { | ||
379 | struct va1j5jf8007t_state *state; | ||
380 | state = fe->demodulator_priv; | ||
381 | kfree(state); | ||
382 | } | ||
383 | |||
384 | static struct dvb_frontend_ops va1j5jf8007t_ops = { | ||
385 | .info = { | ||
386 | .name = "VA1J5JF8007 ISDB-T", | ||
387 | .type = FE_OFDM, | ||
388 | .frequency_min = 90000000, | ||
389 | .frequency_max = 770000000, | ||
390 | .frequency_stepsize = 142857, | ||
391 | .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | | ||
392 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
393 | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, | ||
394 | }, | ||
395 | |||
396 | .get_frontend_algo = va1j5jf8007t_get_frontend_algo, | ||
397 | .read_status = va1j5jf8007t_read_status, | ||
398 | .tune = va1j5jf8007t_tune, | ||
399 | .sleep = va1j5jf8007t_sleep, | ||
400 | .init = va1j5jf8007t_init, | ||
401 | .release = va1j5jf8007t_release, | ||
402 | }; | ||
403 | |||
404 | static const u8 va1j5jf8007t_prepare_bufs[][2] = { | ||
405 | {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, | ||
406 | {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00}, | ||
407 | {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03}, | ||
408 | {0xef, 0x01} | ||
409 | }; | ||
410 | |||
411 | int va1j5jf8007t_prepare(struct dvb_frontend *fe) | ||
412 | { | ||
413 | struct va1j5jf8007t_state *state; | ||
414 | u8 buf[2]; | ||
415 | struct i2c_msg msg; | ||
416 | int i; | ||
417 | |||
418 | state = fe->demodulator_priv; | ||
419 | |||
420 | msg.addr = state->config->demod_address; | ||
421 | msg.flags = 0; | ||
422 | msg.len = sizeof(buf); | ||
423 | msg.buf = buf; | ||
424 | |||
425 | for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_prepare_bufs); i++) { | ||
426 | memcpy(buf, va1j5jf8007t_prepare_bufs[i], sizeof(buf)); | ||
427 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
428 | return -EREMOTEIO; | ||
429 | } | ||
430 | |||
431 | return va1j5jf8007t_init_frequency(state); | ||
432 | } | ||
433 | |||
434 | struct dvb_frontend * | ||
435 | va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, | ||
436 | struct i2c_adapter *adap) | ||
437 | { | ||
438 | struct va1j5jf8007t_state *state; | ||
439 | struct dvb_frontend *fe; | ||
440 | u8 buf[2]; | ||
441 | struct i2c_msg msg; | ||
442 | |||
443 | state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL); | ||
444 | if (!state) | ||
445 | return NULL; | ||
446 | |||
447 | state->config = config; | ||
448 | state->adap = adap; | ||
449 | |||
450 | fe = &state->fe; | ||
451 | memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops)); | ||
452 | fe->demodulator_priv = state; | ||
453 | |||
454 | buf[0] = 0x01; | ||
455 | buf[1] = 0x80; | ||
456 | |||
457 | msg.addr = state->config->demod_address; | ||
458 | msg.flags = 0; | ||
459 | msg.len = sizeof(buf); | ||
460 | msg.buf = buf; | ||
461 | |||
462 | if (i2c_transfer(state->adap, &msg, 1) != 1) { | ||
463 | kfree(state); | ||
464 | return NULL; | ||
465 | } | ||
466 | |||
467 | return fe; | ||
468 | } | ||
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.h b/drivers/media/dvb/pt1/va1j5jf8007t.h new file mode 100644 index 000000000000..ed49906f7769 --- /dev/null +++ b/drivers/media/dvb/pt1/va1j5jf8007t.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * ISDB-T driver for VA1J5JF8007 | ||
3 | * | ||
4 | * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | ||
5 | * | ||
6 | * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | ||
7 | * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | ||
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 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef VA1J5JF8007T_H | ||
25 | #define VA1J5JF8007T_H | ||
26 | |||
27 | struct va1j5jf8007t_config { | ||
28 | u8 demod_address; | ||
29 | }; | ||
30 | |||
31 | struct i2c_adapter; | ||
32 | |||
33 | struct dvb_frontend * | ||
34 | va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, | ||
35 | struct i2c_adapter *adap); | ||
36 | |||
37 | /* must be called after va1j5jf8007s_attach */ | ||
38 | int va1j5jf8007t_prepare(struct dvb_frontend *fe); | ||
39 | |||
40 | #endif | ||
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 25a36ad60c5e..a87a477c87f2 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig | |||
@@ -346,7 +346,7 @@ config RADIO_SI4713 | |||
346 | ---help--- | 346 | ---help--- |
347 | Say Y here if you want support to Si4713 FM Radio Transmitter. | 347 | Say Y here if you want support to Si4713 FM Radio Transmitter. |
348 | This device can transmit audio through FM. It can transmit | 348 | This device can transmit audio through FM. It can transmit |
349 | EDS and EBDS signals as well. This module is the v4l2 radio | 349 | RDS and RBDS signals as well. This module is the v4l2 radio |
350 | interface for the i2c driver of this device. | 350 | interface for the i2c driver of this device. |
351 | 351 | ||
352 | To compile this driver as a module, choose M here: the | 352 | To compile this driver as a module, choose M here: the |
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 65c14b704586..170bbe554787 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/version.h> | ||
28 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
29 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
30 | #include <linux/videodev2.h> | 29 | #include <linux/videodev2.h> |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 1d758525d236..e6186b338a12 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -265,6 +265,15 @@ config VIDEO_SAA6588 | |||
265 | 265 | ||
266 | comment "Video decoders" | 266 | comment "Video decoders" |
267 | 267 | ||
268 | config VIDEO_ADV7180 | ||
269 | tristate "Analog Devices ADV7180 decoder" | ||
270 | depends on VIDEO_V4L2 && I2C | ||
271 | ---help--- | ||
272 | Support for the Analog Devices ADV7180 video decoder. | ||
273 | |||
274 | To compile this driver as a module, choose M here: the | ||
275 | module will be called adv7180. | ||
276 | |||
268 | config VIDEO_BT819 | 277 | config VIDEO_BT819 |
269 | tristate "BT819A VideoStream decoder" | 278 | tristate "BT819A VideoStream decoder" |
270 | depends on VIDEO_V4L2 && I2C | 279 | depends on VIDEO_V4L2 && I2C |
@@ -493,6 +502,39 @@ config VIDEO_UPD64083 | |||
493 | 502 | ||
494 | endmenu # encoder / decoder chips | 503 | endmenu # encoder / decoder chips |
495 | 504 | ||
505 | config DISPLAY_DAVINCI_DM646X_EVM | ||
506 | tristate "DM646x EVM Video Display" | ||
507 | depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM | ||
508 | select VIDEOBUF_DMA_CONTIG | ||
509 | select VIDEO_DAVINCI_VPIF | ||
510 | select VIDEO_ADV7343 | ||
511 | select VIDEO_THS7303 | ||
512 | help | ||
513 | Support for DM6467 based display device. | ||
514 | |||
515 | To compile this driver as a module, choose M here: the | ||
516 | module will be called vpif_display. | ||
517 | |||
518 | config CAPTURE_DAVINCI_DM646X_EVM | ||
519 | tristate "DM646x EVM Video Capture" | ||
520 | depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM | ||
521 | select VIDEOBUF_DMA_CONTIG | ||
522 | select VIDEO_DAVINCI_VPIF | ||
523 | help | ||
524 | Support for DM6467 based capture device. | ||
525 | |||
526 | To compile this driver as a module, choose M here: the | ||
527 | module will be called vpif_capture. | ||
528 | |||
529 | config VIDEO_DAVINCI_VPIF | ||
530 | tristate "DaVinci VPIF Driver" | ||
531 | depends on DISPLAY_DAVINCI_DM646X_EVM | ||
532 | help | ||
533 | Support for DaVinci VPIF Driver. | ||
534 | |||
535 | To compile this driver as a module, choose M here: the | ||
536 | module will be called vpif. | ||
537 | |||
496 | config VIDEO_VIVI | 538 | config VIDEO_VIVI |
497 | tristate "Virtual Video Driver" | 539 | tristate "Virtual Video Driver" |
498 | depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 | 540 | depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 |
@@ -505,6 +547,55 @@ config VIDEO_VIVI | |||
505 | Say Y here if you want to test video apps or debug V4L devices. | 547 | Say Y here if you want to test video apps or debug V4L devices. |
506 | In doubt, say N. | 548 | In doubt, say N. |
507 | 549 | ||
550 | config VIDEO_VPSS_SYSTEM | ||
551 | tristate "VPSS System module driver" | ||
552 | depends on ARCH_DAVINCI | ||
553 | help | ||
554 | Support for vpss system module for video driver | ||
555 | default y | ||
556 | |||
557 | config VIDEO_VPFE_CAPTURE | ||
558 | tristate "VPFE Video Capture Driver" | ||
559 | depends on VIDEO_V4L2 && ARCH_DAVINCI | ||
560 | select VIDEOBUF_DMA_CONTIG | ||
561 | help | ||
562 | Support for DMXXXX VPFE based frame grabber. This is the | ||
563 | common V4L2 module for following DMXXX SoCs from Texas | ||
564 | Instruments:- DM6446 & DM355. | ||
565 | |||
566 | To compile this driver as a module, choose M here: the | ||
567 | module will be called vpfe-capture. | ||
568 | |||
569 | config VIDEO_DM6446_CCDC | ||
570 | tristate "DM6446 CCDC HW module" | ||
571 | depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE | ||
572 | select VIDEO_VPSS_SYSTEM | ||
573 | default y | ||
574 | help | ||
575 | Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces | ||
576 | with decoder modules such as TVP5146 over BT656 or | ||
577 | sensor module such as MT9T001 over a raw interface. This | ||
578 | module configures the interface and CCDC/ISIF to do | ||
579 | video frame capture from slave decoders. | ||
580 | |||
581 | To compile this driver as a module, choose M here: the | ||
582 | module will be called vpfe. | ||
583 | |||
584 | config VIDEO_DM355_CCDC | ||
585 | tristate "DM355 CCDC HW module" | ||
586 | depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE | ||
587 | select VIDEO_VPSS_SYSTEM | ||
588 | default y | ||
589 | help | ||
590 | Enables DM355 CCD hw module. DM355 CCDC hw interfaces | ||
591 | with decoder modules such as TVP5146 over BT656 or | ||
592 | sensor module such as MT9T001 over a raw interface. This | ||
593 | module configures the interface and CCDC/ISIF to do | ||
594 | video frame capture from a slave decoders | ||
595 | |||
596 | To compile this driver as a module, choose M here: the | ||
597 | module will be called vpfe. | ||
598 | |||
508 | source "drivers/media/video/bt8xx/Kconfig" | 599 | source "drivers/media/video/bt8xx/Kconfig" |
509 | 600 | ||
510 | config VIDEO_PMS | 601 | config VIDEO_PMS |
@@ -690,6 +781,8 @@ source "drivers/media/video/ivtv/Kconfig" | |||
690 | 781 | ||
691 | source "drivers/media/video/cx18/Kconfig" | 782 | source "drivers/media/video/cx18/Kconfig" |
692 | 783 | ||
784 | source "drivers/media/video/saa7164/Kconfig" | ||
785 | |||
693 | config VIDEO_M32R_AR | 786 | config VIDEO_M32R_AR |
694 | tristate "AR devices" | 787 | tristate "AR devices" |
695 | depends on M32R && VIDEO_V4L1 | 788 | depends on M32R && VIDEO_V4L1 |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9f2e3214a482..e541932a789b 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -45,6 +45,7 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o | |||
45 | obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o | 45 | obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o |
46 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o | 46 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o |
47 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o | 47 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o |
48 | obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o | ||
48 | obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o | 49 | obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o |
49 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o | 50 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o |
50 | obj-$(CONFIG_VIDEO_BT819) += bt819.o | 51 | obj-$(CONFIG_VIDEO_BT819) += bt819.o |
@@ -154,12 +155,17 @@ obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o | |||
154 | obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o | 155 | obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o |
155 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o | 156 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o |
156 | 157 | ||
158 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ | ||
159 | |||
157 | obj-$(CONFIG_VIDEO_AU0828) += au0828/ | 160 | obj-$(CONFIG_VIDEO_AU0828) += au0828/ |
158 | 161 | ||
159 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ | 162 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ |
163 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ | ||
160 | 164 | ||
161 | obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o | 165 | obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o |
162 | 166 | ||
167 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ | ||
168 | |||
163 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core | 169 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core |
164 | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends | 170 | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends |
165 | EXTRA_CFLAGS += -Idrivers/media/common/tuners | 171 | EXTRA_CFLAGS += -Idrivers/media/common/tuners |
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c new file mode 100644 index 000000000000..1b3cbd02a7fd --- /dev/null +++ b/drivers/media/video/adv7180.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * adv7180.c Analog Devices ADV7180 video decoder driver | ||
3 | * Copyright (c) 2009 Intel Corporation | ||
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 version 2 as | ||
7 | * published by the Free Software Foundation. | ||
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 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/i2c-id.h> | ||
26 | #include <media/v4l2-ioctl.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/v4l2-chip-ident.h> | ||
30 | |||
31 | #define DRIVER_NAME "adv7180" | ||
32 | |||
33 | #define ADV7180_INPUT_CONTROL_REG 0x00 | ||
34 | #define ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM 0x00 | ||
35 | #define ADV7180_AUTODETECT_ENABLE_REG 0x07 | ||
36 | #define ADV7180_AUTODETECT_DEFAULT 0x7f | ||
37 | |||
38 | |||
39 | #define ADV7180_STATUS1_REG 0x10 | ||
40 | #define ADV7180_STATUS1_AUTOD_MASK 0x70 | ||
41 | #define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 | ||
42 | #define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 | ||
43 | #define ADV7180_STATUS1_AUTOD_PAL_M 0x20 | ||
44 | #define ADV7180_STATUS1_AUTOD_PAL_60 0x30 | ||
45 | #define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 | ||
46 | #define ADV7180_STATUS1_AUTOD_SECAM 0x50 | ||
47 | #define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 | ||
48 | #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 | ||
49 | |||
50 | #define ADV7180_IDENT_REG 0x11 | ||
51 | #define ADV7180_ID_7180 0x18 | ||
52 | |||
53 | |||
54 | struct adv7180_state { | ||
55 | struct v4l2_subdev sd; | ||
56 | }; | ||
57 | |||
58 | static v4l2_std_id determine_norm(struct i2c_client *client) | ||
59 | { | ||
60 | u8 status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG); | ||
61 | |||
62 | switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { | ||
63 | case ADV7180_STATUS1_AUTOD_NTSM_M_J: | ||
64 | return V4L2_STD_NTSC_M_JP; | ||
65 | case ADV7180_STATUS1_AUTOD_NTSC_4_43: | ||
66 | return V4L2_STD_NTSC_443; | ||
67 | case ADV7180_STATUS1_AUTOD_PAL_M: | ||
68 | return V4L2_STD_PAL_M; | ||
69 | case ADV7180_STATUS1_AUTOD_PAL_60: | ||
70 | return V4L2_STD_PAL_60; | ||
71 | case ADV7180_STATUS1_AUTOD_PAL_B_G: | ||
72 | return V4L2_STD_PAL; | ||
73 | case ADV7180_STATUS1_AUTOD_SECAM: | ||
74 | return V4L2_STD_SECAM; | ||
75 | case ADV7180_STATUS1_AUTOD_PAL_COMB: | ||
76 | return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; | ||
77 | case ADV7180_STATUS1_AUTOD_SECAM_525: | ||
78 | return V4L2_STD_SECAM; | ||
79 | default: | ||
80 | return V4L2_STD_UNKNOWN; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) | ||
85 | { | ||
86 | return container_of(sd, struct adv7180_state, sd); | ||
87 | } | ||
88 | |||
89 | static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) | ||
90 | { | ||
91 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
92 | |||
93 | *std = determine_norm(client); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int adv7180_g_chip_ident(struct v4l2_subdev *sd, | ||
98 | struct v4l2_dbg_chip_ident *chip) | ||
99 | { | ||
100 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
101 | |||
102 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0); | ||
103 | } | ||
104 | |||
105 | static const struct v4l2_subdev_video_ops adv7180_video_ops = { | ||
106 | .querystd = adv7180_querystd, | ||
107 | }; | ||
108 | |||
109 | static const struct v4l2_subdev_core_ops adv7180_core_ops = { | ||
110 | .g_chip_ident = adv7180_g_chip_ident, | ||
111 | }; | ||
112 | |||
113 | static const struct v4l2_subdev_ops adv7180_ops = { | ||
114 | .core = &adv7180_core_ops, | ||
115 | .video = &adv7180_video_ops, | ||
116 | }; | ||
117 | |||
118 | /* | ||
119 | * Generic i2c probe | ||
120 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' | ||
121 | */ | ||
122 | |||
123 | static int adv7180_probe(struct i2c_client *client, | ||
124 | const struct i2c_device_id *id) | ||
125 | { | ||
126 | struct adv7180_state *state; | ||
127 | struct v4l2_subdev *sd; | ||
128 | int ret; | ||
129 | |||
130 | /* Check if the adapter supports the needed features */ | ||
131 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
132 | return -EIO; | ||
133 | |||
134 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | ||
135 | client->addr << 1, client->adapter->name); | ||
136 | |||
137 | state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL); | ||
138 | if (state == NULL) | ||
139 | return -ENOMEM; | ||
140 | sd = &state->sd; | ||
141 | v4l2_i2c_subdev_init(sd, client, &adv7180_ops); | ||
142 | |||
143 | /* Initialize adv7180 */ | ||
144 | /* enable autodetection */ | ||
145 | ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, | ||
146 | ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM); | ||
147 | if (ret > 0) | ||
148 | ret = i2c_smbus_write_byte_data(client, | ||
149 | ADV7180_AUTODETECT_ENABLE_REG, | ||
150 | ADV7180_AUTODETECT_DEFAULT); | ||
151 | if (ret < 0) { | ||
152 | printk(KERN_ERR DRIVER_NAME | ||
153 | ": Failed to communicate to chip: %d\n", ret); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int adv7180_remove(struct i2c_client *client) | ||
161 | { | ||
162 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
163 | |||
164 | v4l2_device_unregister_subdev(sd); | ||
165 | kfree(to_state(sd)); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static const struct i2c_device_id adv7180_id[] = { | ||
170 | {DRIVER_NAME, 0}, | ||
171 | {}, | ||
172 | }; | ||
173 | |||
174 | MODULE_DEVICE_TABLE(i2c, adv7180_id); | ||
175 | |||
176 | static struct i2c_driver adv7180_driver = { | ||
177 | .driver = { | ||
178 | .owner = THIS_MODULE, | ||
179 | .name = DRIVER_NAME, | ||
180 | }, | ||
181 | .probe = adv7180_probe, | ||
182 | .remove = adv7180_remove, | ||
183 | .id_table = adv7180_id, | ||
184 | }; | ||
185 | |||
186 | static __init int adv7180_init(void) | ||
187 | { | ||
188 | return i2c_add_driver(&adv7180_driver); | ||
189 | } | ||
190 | |||
191 | static __exit void adv7180_exit(void) | ||
192 | { | ||
193 | i2c_del_driver(&adv7180_driver); | ||
194 | } | ||
195 | |||
196 | module_init(adv7180_init); | ||
197 | module_exit(adv7180_exit); | ||
198 | |||
199 | MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); | ||
200 | MODULE_AUTHOR("Mocean Laboratories"); | ||
201 | MODULE_LICENSE("GPL v2"); | ||
202 | |||
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c index 30f5caf5dda5..df26f2fe44eb 100644 --- a/drivers/media/video/adv7343.c +++ b/drivers/media/video/adv7343.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/videodev2.h> | 25 | #include <linux/videodev2.h> |
26 | #include <linux/uaccess.h> | 26 | #include <linux/uaccess.h> |
27 | #include <linux/version.h> | ||
28 | 27 | ||
29 | #include <media/adv7343.h> | 28 | #include <media/adv7343.h> |
30 | #include <media/v4l2-device.h> | 29 | #include <media/v4l2-device.h> |
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 830c4a933f63..57dd9195daf5 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c | |||
@@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev) | |||
212 | be abstracted out if we ever need to support a different | 212 | be abstracted out if we ever need to support a different |
213 | demod) */ | 213 | demod) */ |
214 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 214 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
215 | "au8522", "au8522", 0x8e >> 1); | 215 | "au8522", "au8522", 0x8e >> 1, NULL); |
216 | if (sd == NULL) | 216 | if (sd == NULL) |
217 | printk(KERN_ERR "analog subdev registration failed\n"); | 217 | printk(KERN_ERR "analog subdev registration failed\n"); |
218 | } | 218 | } |
@@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev) | |||
221 | if (dev->board.tuner_type != TUNER_ABSENT) { | 221 | if (dev->board.tuner_type != TUNER_ABSENT) { |
222 | /* Load the tuner module, which does the attach */ | 222 | /* Load the tuner module, which does the attach */ |
223 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 223 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
224 | "tuner", "tuner", dev->board.tuner_addr); | 224 | "tuner", "tuner", dev->board.tuner_addr, NULL); |
225 | if (sd == NULL) | 225 | if (sd == NULL) |
226 | printk(KERN_ERR "tuner subdev registration fail\n"); | 226 | printk(KERN_ERR "tuner subdev registration fail\n"); |
227 | 227 | ||
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index b42251fa96ba..12279f6d9bc4 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c | |||
@@ -3524,8 +3524,8 @@ void __devinit bttv_init_card2(struct bttv *btv) | |||
3524 | }; | 3524 | }; |
3525 | struct v4l2_subdev *sd; | 3525 | struct v4l2_subdev *sd; |
3526 | 3526 | ||
3527 | sd = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3527 | sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3528 | &btv->c.i2c_adap, "saa6588", "saa6588", addrs); | 3528 | &btv->c.i2c_adap, "saa6588", "saa6588", 0, addrs); |
3529 | btv->has_saa6588 = (sd != NULL); | 3529 | btv->has_saa6588 = (sd != NULL); |
3530 | } | 3530 | } |
3531 | 3531 | ||
@@ -3549,8 +3549,8 @@ void __devinit bttv_init_card2(struct bttv *btv) | |||
3549 | I2C_CLIENT_END | 3549 | I2C_CLIENT_END |
3550 | }; | 3550 | }; |
3551 | 3551 | ||
3552 | btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3552 | btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3553 | &btv->c.i2c_adap, "msp3400", "msp3400", addrs); | 3553 | &btv->c.i2c_adap, "msp3400", "msp3400", 0, addrs); |
3554 | if (btv->sd_msp34xx) | 3554 | if (btv->sd_msp34xx) |
3555 | return; | 3555 | return; |
3556 | goto no_audio; | 3556 | goto no_audio; |
@@ -3563,16 +3563,16 @@ void __devinit bttv_init_card2(struct bttv *btv) | |||
3563 | I2C_CLIENT_END | 3563 | I2C_CLIENT_END |
3564 | }; | 3564 | }; |
3565 | 3565 | ||
3566 | if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3566 | if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3567 | &btv->c.i2c_adap, "tda7432", "tda7432", addrs)) | 3567 | &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs)) |
3568 | return; | 3568 | return; |
3569 | goto no_audio; | 3569 | goto no_audio; |
3570 | } | 3570 | } |
3571 | 3571 | ||
3572 | case 3: { | 3572 | case 3: { |
3573 | /* The user specified that we should probe for tvaudio */ | 3573 | /* The user specified that we should probe for tvaudio */ |
3574 | btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3574 | btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3575 | &btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs()); | 3575 | &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs()); |
3576 | if (btv->sd_tvaudio) | 3576 | if (btv->sd_tvaudio) |
3577 | return; | 3577 | return; |
3578 | goto no_audio; | 3578 | goto no_audio; |
@@ -3591,13 +3591,13 @@ void __devinit bttv_init_card2(struct bttv *btv) | |||
3591 | it really is a msp3400, so it will return NULL when the device | 3591 | it really is a msp3400, so it will return NULL when the device |
3592 | found is really something else (e.g. a tea6300). */ | 3592 | found is really something else (e.g. a tea6300). */ |
3593 | if (!bttv_tvcards[btv->c.type].no_msp34xx) { | 3593 | if (!bttv_tvcards[btv->c.type].no_msp34xx) { |
3594 | btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev, | 3594 | btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3595 | &btv->c.i2c_adap, "msp3400", "msp3400", | 3595 | &btv->c.i2c_adap, "msp3400", "msp3400", |
3596 | I2C_ADDR_MSP3400 >> 1); | 3596 | 0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1)); |
3597 | } else if (bttv_tvcards[btv->c.type].msp34xx_alt) { | 3597 | } else if (bttv_tvcards[btv->c.type].msp34xx_alt) { |
3598 | btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev, | 3598 | btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3599 | &btv->c.i2c_adap, "msp3400", "msp3400", | 3599 | &btv->c.i2c_adap, "msp3400", "msp3400", |
3600 | I2C_ADDR_MSP3400_ALT >> 1); | 3600 | 0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1)); |
3601 | } | 3601 | } |
3602 | 3602 | ||
3603 | /* If we found a msp34xx, then we're done. */ | 3603 | /* If we found a msp34xx, then we're done. */ |
@@ -3611,14 +3611,14 @@ void __devinit bttv_init_card2(struct bttv *btv) | |||
3611 | I2C_CLIENT_END | 3611 | I2C_CLIENT_END |
3612 | }; | 3612 | }; |
3613 | 3613 | ||
3614 | if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3614 | if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3615 | &btv->c.i2c_adap, "tda7432", "tda7432", addrs)) | 3615 | &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs)) |
3616 | return; | 3616 | return; |
3617 | } | 3617 | } |
3618 | 3618 | ||
3619 | /* Now see if we can find one of the tvaudio devices. */ | 3619 | /* Now see if we can find one of the tvaudio devices. */ |
3620 | btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3620 | btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3621 | &btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs()); | 3621 | &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs()); |
3622 | if (btv->sd_tvaudio) | 3622 | if (btv->sd_tvaudio) |
3623 | return; | 3623 | return; |
3624 | 3624 | ||
@@ -3641,15 +3641,15 @@ void __devinit bttv_init_tuner(struct bttv *btv) | |||
3641 | 3641 | ||
3642 | /* Load tuner module before issuing tuner config call! */ | 3642 | /* Load tuner module before issuing tuner config call! */ |
3643 | if (bttv_tvcards[btv->c.type].has_radio) | 3643 | if (bttv_tvcards[btv->c.type].has_radio) |
3644 | v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3644 | v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3645 | &btv->c.i2c_adap, "tuner", "tuner", | 3645 | &btv->c.i2c_adap, "tuner", "tuner", |
3646 | v4l2_i2c_tuner_addrs(ADDRS_RADIO)); | 3646 | 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); |
3647 | v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3647 | v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3648 | &btv->c.i2c_adap, "tuner", "tuner", | 3648 | &btv->c.i2c_adap, "tuner", "tuner", |
3649 | v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | 3649 | 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); |
3650 | v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, | 3650 | v4l2_i2c_new_subdev(&btv->c.v4l2_dev, |
3651 | &btv->c.i2c_adap, "tuner", "tuner", | 3651 | &btv->c.i2c_adap, "tuner", "tuner", |
3652 | v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); | 3652 | 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); |
3653 | 3653 | ||
3654 | tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; | 3654 | tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; |
3655 | tun_setup.type = btv->tuner_type; | 3655 | tun_setup.type = btv->tuner_type; |
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 9c149a781294..657c481d255c 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c | |||
@@ -1955,7 +1955,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, | |||
1955 | 1955 | ||
1956 | cam->sensor_addr = 0x42; | 1956 | cam->sensor_addr = 0x42; |
1957 | cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter, | 1957 | cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter, |
1958 | "ov7670", "ov7670", cam->sensor_addr); | 1958 | "ov7670", "ov7670", cam->sensor_addr, NULL); |
1959 | if (cam->sensor == NULL) { | 1959 | if (cam->sensor == NULL) { |
1960 | ret = -ENODEV; | 1960 | ret = -ENODEV; |
1961 | goto out_smbus; | 1961 | goto out_smbus; |
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index dd0224f328ad..6dd51e27582c 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -231,7 +231,7 @@ MODULE_PARM_DESC(enc_pcm_bufs, | |||
231 | "Number of encoder PCM buffers\n" | 231 | "Number of encoder PCM buffers\n" |
232 | "\t\t\tDefault is computed from other enc_pcm_* parameters"); | 232 | "\t\t\tDefault is computed from other enc_pcm_* parameters"); |
233 | 233 | ||
234 | MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card"); | 234 | MODULE_PARM_DESC(cx18_first_minor, "Set device node number assigned to first card"); |
235 | 235 | ||
236 | MODULE_AUTHOR("Hans Verkuil"); | 236 | MODULE_AUTHOR("Hans Verkuil"); |
237 | MODULE_DESCRIPTION("CX23418 driver"); | 237 | MODULE_DESCRIPTION("CX23418 driver"); |
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index da395fef50df..2477461e84d7 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c | |||
@@ -116,7 +116,7 @@ static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type, | |||
116 | /* Our default information for ir-kbd-i2c.c to use */ | 116 | /* Our default information for ir-kbd-i2c.c to use */ |
117 | switch (hw) { | 117 | switch (hw) { |
118 | case CX18_HW_Z8F0811_IR_RX_HAUP: | 118 | case CX18_HW_Z8F0811_IR_RX_HAUP: |
119 | info.platform_data = &z8f0811_ir_init_data; | 119 | info.platform_data = (void *) &z8f0811_ir_init_data; |
120 | break; | 120 | break; |
121 | default: | 121 | default: |
122 | break; | 122 | break; |
@@ -139,16 +139,16 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx) | |||
139 | 139 | ||
140 | if (hw == CX18_HW_TUNER) { | 140 | if (hw == CX18_HW_TUNER) { |
141 | /* special tuner group handling */ | 141 | /* special tuner group handling */ |
142 | sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev, | 142 | sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, |
143 | adap, mod, type, cx->card_i2c->radio); | 143 | adap, mod, type, 0, cx->card_i2c->radio); |
144 | if (sd != NULL) | 144 | if (sd != NULL) |
145 | sd->grp_id = hw; | 145 | sd->grp_id = hw; |
146 | sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev, | 146 | sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, |
147 | adap, mod, type, cx->card_i2c->demod); | 147 | adap, mod, type, 0, cx->card_i2c->demod); |
148 | if (sd != NULL) | 148 | if (sd != NULL) |
149 | sd->grp_id = hw; | 149 | sd->grp_id = hw; |
150 | sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev, | 150 | sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, |
151 | adap, mod, type, cx->card_i2c->tv); | 151 | adap, mod, type, 0, cx->card_i2c->tv); |
152 | if (sd != NULL) | 152 | if (sd != NULL) |
153 | sd->grp_id = hw; | 153 | sd->grp_id = hw; |
154 | return sd != NULL ? 0 : -1; | 154 | return sd != NULL ? 0 : -1; |
@@ -162,7 +162,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx) | |||
162 | return -1; | 162 | return -1; |
163 | 163 | ||
164 | /* It's an I2C device other than an analog tuner or IR chip */ | 164 | /* It's an I2C device other than an analog tuner or IR chip */ |
165 | sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]); | 165 | sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx], NULL); |
166 | if (sd != NULL) | 166 | if (sd != NULL) |
167 | sd->grp_id = hw; | 167 | sd->grp_id = hw; |
168 | return sd != NULL ? 0 : -1; | 168 | return sd != NULL ? 0 : -1; |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 54d248e16d85..7df513a2dba8 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -245,9 +245,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type) | |||
245 | video_set_drvdata(s->video_dev, s); | 245 | video_set_drvdata(s->video_dev, s); |
246 | 246 | ||
247 | /* Register device. First try the desired minor, then any free one. */ | 247 | /* Register device. First try the desired minor, then any free one. */ |
248 | ret = video_register_device(s->video_dev, vfl_type, num); | 248 | ret = video_register_device_no_warn(s->video_dev, vfl_type, num); |
249 | if (ret < 0) { | 249 | if (ret < 0) { |
250 | CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n", | 250 | CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", |
251 | s->name, num); | 251 | s->name, num); |
252 | video_device_release(s->video_dev); | 252 | video_device_release(s->video_dev); |
253 | s->video_dev = NULL; | 253 | s->video_dev = NULL; |
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 63d2239fd324..319c459459e0 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c | |||
@@ -313,7 +313,7 @@ void cx231xx_card_setup(struct cx231xx *dev) | |||
313 | if (dev->board.decoder == CX231XX_AVDECODER) { | 313 | if (dev->board.decoder == CX231XX_AVDECODER) { |
314 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, | 314 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
315 | &dev->i2c_bus[0].i2c_adap, | 315 | &dev->i2c_bus[0].i2c_adap, |
316 | "cx25840", "cx25840", 0x88 >> 1); | 316 | "cx25840", "cx25840", 0x88 >> 1, NULL); |
317 | if (dev->sd_cx25840 == NULL) | 317 | if (dev->sd_cx25840 == NULL) |
318 | cx231xx_info("cx25840 subdev registration failure\n"); | 318 | cx231xx_info("cx25840 subdev registration failure\n"); |
319 | cx25840_call(dev, core, load_fw); | 319 | cx25840_call(dev, core, load_fw); |
@@ -323,7 +323,7 @@ void cx231xx_card_setup(struct cx231xx *dev) | |||
323 | if (dev->board.tuner_type != TUNER_ABSENT) { | 323 | if (dev->board.tuner_type != TUNER_ABSENT) { |
324 | dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, | 324 | dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
325 | &dev->i2c_bus[1].i2c_adap, | 325 | &dev->i2c_bus[1].i2c_adap, |
326 | "tuner", "tuner", 0xc2 >> 1); | 326 | "tuner", "tuner", 0xc2 >> 1, NULL); |
327 | if (dev->sd_tuner == NULL) | 327 | if (dev->sd_tuner == NULL) |
328 | cx231xx_info("tuner subdev registration failure\n"); | 328 | cx231xx_info("tuner subdev registration failure\n"); |
329 | 329 | ||
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c index 0316257b7345..c04222ffb286 100644 --- a/drivers/media/video/cx23885/cimax2.c +++ b/drivers/media/video/cx23885/cimax2.c | |||
@@ -75,7 +75,6 @@ struct netup_ci_state { | |||
75 | void *priv; | 75 | void *priv; |
76 | }; | 76 | }; |
77 | 77 | ||
78 | struct mutex gpio_mutex;/* Two CiMax's uses same GPIO lines */ | ||
79 | 78 | ||
80 | int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, | 79 | int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, |
81 | u8 *buf, int len) | 80 | u8 *buf, int len) |
@@ -183,10 +182,11 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | |||
183 | if (ret != 0) | 182 | if (ret != 0) |
184 | return ret; | 183 | return ret; |
185 | 184 | ||
186 | mutex_lock(&gpio_mutex); | 185 | mutex_lock(&dev->gpio_lock); |
187 | 186 | ||
188 | /* write addr */ | 187 | /* write addr */ |
189 | cx_write(MC417_OEN, NETUP_EN_ALL); | 188 | cx_write(MC417_OEN, NETUP_EN_ALL); |
189 | msleep(2); | ||
190 | cx_write(MC417_RWD, NETUP_CTRL_OFF | | 190 | cx_write(MC417_RWD, NETUP_CTRL_OFF | |
191 | NETUP_ADLO | (0xff & addr)); | 191 | NETUP_ADLO | (0xff & addr)); |
192 | cx_clear(MC417_RWD, NETUP_ADLO); | 192 | cx_clear(MC417_RWD, NETUP_ADLO); |
@@ -194,9 +194,10 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | |||
194 | NETUP_ADHI | (0xff & (addr >> 8))); | 194 | NETUP_ADHI | (0xff & (addr >> 8))); |
195 | cx_clear(MC417_RWD, NETUP_ADHI); | 195 | cx_clear(MC417_RWD, NETUP_ADHI); |
196 | 196 | ||
197 | if (read) /* data in */ | 197 | if (read) { /* data in */ |
198 | cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); | 198 | cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); |
199 | else /* data out */ | 199 | msleep(2); |
200 | } else /* data out */ | ||
200 | cx_write(MC417_RWD, NETUP_CTRL_OFF | data); | 201 | cx_write(MC417_RWD, NETUP_CTRL_OFF | data); |
201 | 202 | ||
202 | /* choose chip */ | 203 | /* choose chip */ |
@@ -206,7 +207,7 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | |||
206 | cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR); | 207 | cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR); |
207 | mem = netup_ci_get_mem(dev); | 208 | mem = netup_ci_get_mem(dev); |
208 | 209 | ||
209 | mutex_unlock(&gpio_mutex); | 210 | mutex_unlock(&dev->gpio_lock); |
210 | 211 | ||
211 | if (!read) | 212 | if (!read) |
212 | if (mem < 0) | 213 | if (mem < 0) |
@@ -403,7 +404,6 @@ int netup_ci_init(struct cx23885_tsport *port) | |||
403 | switch (port->nr) { | 404 | switch (port->nr) { |
404 | case 1: | 405 | case 1: |
405 | state->ci_i2c_addr = 0x40; | 406 | state->ci_i2c_addr = 0x40; |
406 | mutex_init(&gpio_mutex); | ||
407 | break; | 407 | break; |
408 | case 2: | 408 | case 2: |
409 | state->ci_i2c_addr = 0x41; | 409 | state->ci_i2c_addr = 0x41; |
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 3143d85ef31d..bfdf79f1033c 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c | |||
@@ -210,6 +210,10 @@ struct cx23885_board cx23885_boards[] = { | |||
210 | .portb = CX23885_MPEG_ENCODER, | 210 | .portb = CX23885_MPEG_ENCODER, |
211 | .portc = CX23885_MPEG_DVB, | 211 | .portc = CX23885_MPEG_DVB, |
212 | }, | 212 | }, |
213 | [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { | ||
214 | .name = "Compro VideoMate E800", | ||
215 | .portc = CX23885_MPEG_DVB, | ||
216 | }, | ||
213 | }; | 217 | }; |
214 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); | 218 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); |
215 | 219 | ||
@@ -341,6 +345,10 @@ struct cx23885_subid cx23885_subids[] = { | |||
341 | .subvendor = 0x0070, | 345 | .subvendor = 0x0070, |
342 | .subdevice = 0x8541, | 346 | .subdevice = 0x8541, |
343 | .card = CX23885_BOARD_HAUPPAUGE_HVR1850, | 347 | .card = CX23885_BOARD_HAUPPAUGE_HVR1850, |
348 | }, { | ||
349 | .subvendor = 0x1858, | ||
350 | .subdevice = 0xe800, | ||
351 | .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800, | ||
344 | }, | 352 | }, |
345 | }; | 353 | }; |
346 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); | 354 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); |
@@ -536,6 +544,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) | |||
536 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | 544 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: |
537 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | 545 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: |
538 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | 546 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: |
547 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
539 | /* Tuner Reset Command */ | 548 | /* Tuner Reset Command */ |
540 | bitmask = 0x04; | 549 | bitmask = 0x04; |
541 | break; | 550 | break; |
@@ -687,6 +696,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) | |||
687 | break; | 696 | break; |
688 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | 697 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: |
689 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | 698 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: |
699 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
690 | /* GPIO-2 xc3028 tuner reset */ | 700 | /* GPIO-2 xc3028 tuner reset */ |
691 | 701 | ||
692 | /* The following GPIO's are on the internal AVCore (cx25840) */ | 702 | /* The following GPIO's are on the internal AVCore (cx25840) */ |
@@ -911,6 +921,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
911 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | 921 | case CX23885_BOARD_HAUPPAUGE_HVR1255: |
912 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | 922 | case CX23885_BOARD_HAUPPAUGE_HVR1210: |
913 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 923 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
924 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
914 | default: | 925 | default: |
915 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | 926 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ |
916 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | 927 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
@@ -927,9 +938,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
927 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | 938 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: |
928 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | 939 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: |
929 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | 940 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: |
941 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
930 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, | 942 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
931 | &dev->i2c_bus[2].i2c_adap, | 943 | &dev->i2c_bus[2].i2c_adap, |
932 | "cx25840", "cx25840", 0x88 >> 1); | 944 | "cx25840", "cx25840", 0x88 >> 1, NULL); |
933 | v4l2_subdev_call(dev->sd_cx25840, core, load_fw); | 945 | v4l2_subdev_call(dev->sd_cx25840, core, load_fw); |
934 | break; | 946 | break; |
935 | } | 947 | } |
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 40d438d7234d..c31284ba19dd 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c | |||
@@ -758,6 +758,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) | |||
758 | int i; | 758 | int i; |
759 | 759 | ||
760 | mutex_init(&dev->lock); | 760 | mutex_init(&dev->lock); |
761 | mutex_init(&dev->gpio_lock); | ||
761 | 762 | ||
762 | atomic_inc(&dev->refcount); | 763 | atomic_inc(&dev->refcount); |
763 | 764 | ||
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 022fad798fc2..45e13ee66dc7 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c | |||
@@ -255,15 +255,18 @@ static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = { | |||
255 | static struct tda18271_config hauppauge_tda18271_config = { | 255 | static struct tda18271_config hauppauge_tda18271_config = { |
256 | .std_map = &hauppauge_tda18271_std_map, | 256 | .std_map = &hauppauge_tda18271_std_map, |
257 | .gate = TDA18271_GATE_ANALOG, | 257 | .gate = TDA18271_GATE_ANALOG, |
258 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
258 | }; | 259 | }; |
259 | 260 | ||
260 | static struct tda18271_config hauppauge_hvr1200_tuner_config = { | 261 | static struct tda18271_config hauppauge_hvr1200_tuner_config = { |
261 | .std_map = &hauppauge_hvr1200_tda18271_std_map, | 262 | .std_map = &hauppauge_hvr1200_tda18271_std_map, |
262 | .gate = TDA18271_GATE_ANALOG, | 263 | .gate = TDA18271_GATE_ANALOG, |
264 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
263 | }; | 265 | }; |
264 | 266 | ||
265 | static struct tda18271_config hauppauge_hvr1210_tuner_config = { | 267 | static struct tda18271_config hauppauge_hvr1210_tuner_config = { |
266 | .gate = TDA18271_GATE_DIGITAL, | 268 | .gate = TDA18271_GATE_DIGITAL, |
269 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
267 | }; | 270 | }; |
268 | 271 | ||
269 | static struct tda18271_std_map hauppauge_hvr127x_std_map = { | 272 | static struct tda18271_std_map hauppauge_hvr127x_std_map = { |
@@ -275,6 +278,7 @@ static struct tda18271_std_map hauppauge_hvr127x_std_map = { | |||
275 | 278 | ||
276 | static struct tda18271_config hauppauge_hvr127x_config = { | 279 | static struct tda18271_config hauppauge_hvr127x_config = { |
277 | .std_map = &hauppauge_hvr127x_std_map, | 280 | .std_map = &hauppauge_hvr127x_std_map, |
281 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
278 | }; | 282 | }; |
279 | 283 | ||
280 | static struct lgdt3305_config hauppauge_lgdt3305_config = { | 284 | static struct lgdt3305_config hauppauge_lgdt3305_config = { |
@@ -743,6 +747,7 @@ static int dvb_register(struct cx23885_tsport *port) | |||
743 | } | 747 | } |
744 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | 748 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: |
745 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | 749 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: |
750 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
746 | i2c_bus = &dev->i2c_bus[0]; | 751 | i2c_bus = &dev->i2c_bus[0]; |
747 | 752 | ||
748 | fe0->dvb.frontend = dvb_attach(zl10353_attach, | 753 | fe0->dvb.frontend = dvb_attach(zl10353_attach, |
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 5d6093336300..654cc253cd50 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c | |||
@@ -1521,11 +1521,11 @@ int cx23885_video_register(struct cx23885_dev *dev) | |||
1521 | if (dev->tuner_addr) | 1521 | if (dev->tuner_addr) |
1522 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | 1522 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
1523 | &dev->i2c_bus[1].i2c_adap, | 1523 | &dev->i2c_bus[1].i2c_adap, |
1524 | "tuner", "tuner", dev->tuner_addr); | 1524 | "tuner", "tuner", dev->tuner_addr, NULL); |
1525 | else | 1525 | else |
1526 | sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, | 1526 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
1527 | &dev->i2c_bus[1].i2c_adap, | 1527 | &dev->i2c_bus[1].i2c_adap, |
1528 | "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV)); | 1528 | "tuner", "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV)); |
1529 | if (sd) { | 1529 | if (sd) { |
1530 | struct tuner_setup tun_setup; | 1530 | struct tuner_setup tun_setup; |
1531 | 1531 | ||
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 86f26947bb78..cc7a165561ff 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h | |||
@@ -78,6 +78,7 @@ | |||
78 | #define CX23885_BOARD_MYGICA_X8506 22 | 78 | #define CX23885_BOARD_MYGICA_X8506 22 |
79 | #define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 | 79 | #define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 |
80 | #define CX23885_BOARD_HAUPPAUGE_HVR1850 24 | 80 | #define CX23885_BOARD_HAUPPAUGE_HVR1850 24 |
81 | #define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25 | ||
81 | 82 | ||
82 | #define GPIO_0 0x00000001 | 83 | #define GPIO_0 0x00000001 |
83 | #define GPIO_1 0x00000002 | 84 | #define GPIO_1 0x00000002 |
@@ -325,6 +326,7 @@ struct cx23885_dev { | |||
325 | 326 | ||
326 | int nr; | 327 | int nr; |
327 | struct mutex lock; | 328 | struct mutex lock; |
329 | struct mutex gpio_lock; | ||
328 | 330 | ||
329 | /* board details */ | 331 | /* board details */ |
330 | unsigned int board; | 332 | unsigned int board; |
diff --git a/drivers/media/video/cx23885/netup-eeprom.c b/drivers/media/video/cx23885/netup-eeprom.c index 042bbbbd48f8..98a48f500684 100644 --- a/drivers/media/video/cx23885/netup-eeprom.c +++ b/drivers/media/video/cx23885/netup-eeprom.c | |||
@@ -97,11 +97,11 @@ void netup_get_card_info(struct i2c_adapter *i2c_adap, | |||
97 | { | 97 | { |
98 | int i, j; | 98 | int i, j; |
99 | 99 | ||
100 | cinfo->rev = netup_eeprom_read(i2c_adap, 13); | 100 | cinfo->rev = netup_eeprom_read(i2c_adap, 63); |
101 | 101 | ||
102 | for (i = 0, j = 0; i < 6; i++, j++) | 102 | for (i = 64, j = 0; i < 70; i++, j++) |
103 | cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i); | 103 | cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i); |
104 | 104 | ||
105 | for (i = 6, j = 0; i < 12; i++, j++) | 105 | for (i = 70, j = 0; i < 76; i++, j++) |
106 | cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i); | 106 | cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i); |
107 | }; | 107 | }; |
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index e5f07fbd5a35..33be6369871a 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -3439,20 +3439,20 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) | |||
3439 | The radio_type is sometimes missing, or set to UNSET but | 3439 | The radio_type is sometimes missing, or set to UNSET but |
3440 | later code configures a tea5767. | 3440 | later code configures a tea5767. |
3441 | */ | 3441 | */ |
3442 | v4l2_i2c_new_probed_subdev(&core->v4l2_dev, &core->i2c_adap, | 3442 | v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, |
3443 | "tuner", "tuner", | 3443 | "tuner", "tuner", |
3444 | v4l2_i2c_tuner_addrs(ADDRS_RADIO)); | 3444 | 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); |
3445 | if (has_demod) | 3445 | if (has_demod) |
3446 | v4l2_i2c_new_probed_subdev(&core->v4l2_dev, | 3446 | v4l2_i2c_new_subdev(&core->v4l2_dev, |
3447 | &core->i2c_adap, "tuner", "tuner", | 3447 | &core->i2c_adap, "tuner", "tuner", |
3448 | v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | 3448 | 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); |
3449 | if (core->board.tuner_addr == ADDR_UNSET) { | 3449 | if (core->board.tuner_addr == ADDR_UNSET) { |
3450 | v4l2_i2c_new_probed_subdev(&core->v4l2_dev, | 3450 | v4l2_i2c_new_subdev(&core->v4l2_dev, |
3451 | &core->i2c_adap, "tuner", "tuner", | 3451 | &core->i2c_adap, "tuner", "tuner", |
3452 | has_demod ? tv_addrs + 4 : tv_addrs); | 3452 | 0, has_demod ? tv_addrs + 4 : tv_addrs); |
3453 | } else { | 3453 | } else { |
3454 | v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, | 3454 | v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, |
3455 | "tuner", "tuner", core->board.tuner_addr); | 3455 | "tuner", "tuner", core->board.tuner_addr, NULL); |
3456 | } | 3456 | } |
3457 | } | 3457 | } |
3458 | 3458 | ||
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 2bb54c3ef5cd..81d2b5dea18e 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -1881,14 +1881,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1881 | 1881 | ||
1882 | if (core->board.audio_chip == V4L2_IDENT_WM8775) | 1882 | if (core->board.audio_chip == V4L2_IDENT_WM8775) |
1883 | v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, | 1883 | v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, |
1884 | "wm8775", "wm8775", 0x36 >> 1); | 1884 | "wm8775", "wm8775", 0x36 >> 1, NULL); |
1885 | 1885 | ||
1886 | if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { | 1886 | if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { |
1887 | /* This probes for a tda9874 as is used on some | 1887 | /* This probes for a tda9874 as is used on some |
1888 | Pixelview Ultra boards. */ | 1888 | Pixelview Ultra boards. */ |
1889 | v4l2_i2c_new_probed_subdev_addr(&core->v4l2_dev, | 1889 | v4l2_i2c_new_subdev(&core->v4l2_dev, |
1890 | &core->i2c_adap, | 1890 | &core->i2c_adap, |
1891 | "tvaudio", "tvaudio", 0xb0 >> 1); | 1891 | "tvaudio", "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); |
1892 | } | 1892 | } |
1893 | 1893 | ||
1894 | switch (core->boardnr) { | 1894 | switch (core->boardnr) { |
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile new file mode 100644 index 000000000000..1a8b8f3f182e --- /dev/null +++ b/drivers/media/video/davinci/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | # | ||
2 | # Makefile for the davinci video device drivers. | ||
3 | # | ||
4 | |||
5 | # VPIF | ||
6 | obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o | ||
7 | |||
8 | #DM646x EVM Display driver | ||
9 | obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o | ||
10 | #DM646x EVM Capture driver | ||
11 | obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o | ||
12 | |||
13 | # Capture: DM6446 and DM355 | ||
14 | obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o | ||
15 | obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o | ||
16 | obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o | ||
17 | obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o | ||
diff --git a/drivers/media/video/davinci/ccdc_hw_device.h b/drivers/media/video/davinci/ccdc_hw_device.h new file mode 100644 index 000000000000..86b9b3518965 --- /dev/null +++ b/drivers/media/video/davinci/ccdc_hw_device.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Texas Instruments Inc | ||
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 | * ccdc device API | ||
19 | */ | ||
20 | #ifndef _CCDC_HW_DEVICE_H | ||
21 | #define _CCDC_HW_DEVICE_H | ||
22 | |||
23 | #ifdef __KERNEL__ | ||
24 | #include <linux/videodev2.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <media/davinci/vpfe_types.h> | ||
27 | #include <media/davinci/ccdc_types.h> | ||
28 | |||
29 | /* | ||
30 | * ccdc hw operations | ||
31 | */ | ||
32 | struct ccdc_hw_ops { | ||
33 | /* Pointer to initialize function to initialize ccdc device */ | ||
34 | int (*open) (struct device *dev); | ||
35 | /* Pointer to deinitialize function */ | ||
36 | int (*close) (struct device *dev); | ||
37 | /* set ccdc base address */ | ||
38 | void (*set_ccdc_base)(void *base, int size); | ||
39 | /* Pointer to function to enable or disable ccdc */ | ||
40 | void (*enable) (int en); | ||
41 | /* reset sbl. only for 6446 */ | ||
42 | void (*reset) (void); | ||
43 | /* enable output to sdram */ | ||
44 | void (*enable_out_to_sdram) (int en); | ||
45 | /* Pointer to function to set hw parameters */ | ||
46 | int (*set_hw_if_params) (struct vpfe_hw_if_param *param); | ||
47 | /* get interface parameters */ | ||
48 | int (*get_hw_if_params) (struct vpfe_hw_if_param *param); | ||
49 | /* | ||
50 | * Pointer to function to set parameters. Used | ||
51 | * for implementing VPFE_S_CCDC_PARAMS | ||
52 | */ | ||
53 | int (*set_params) (void *params); | ||
54 | /* | ||
55 | * Pointer to function to get parameter. Used | ||
56 | * for implementing VPFE_G_CCDC_PARAMS | ||
57 | */ | ||
58 | int (*get_params) (void *params); | ||
59 | /* Pointer to function to configure ccdc */ | ||
60 | int (*configure) (void); | ||
61 | |||
62 | /* Pointer to function to set buffer type */ | ||
63 | int (*set_buftype) (enum ccdc_buftype buf_type); | ||
64 | /* Pointer to function to get buffer type */ | ||
65 | enum ccdc_buftype (*get_buftype) (void); | ||
66 | /* Pointer to function to set frame format */ | ||
67 | int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); | ||
68 | /* Pointer to function to get frame format */ | ||
69 | enum ccdc_frmfmt (*get_frame_format) (void); | ||
70 | /* enumerate hw pix formats */ | ||
71 | int (*enum_pix)(u32 *hw_pix, int i); | ||
72 | /* Pointer to function to set buffer type */ | ||
73 | u32 (*get_pixel_format) (void); | ||
74 | /* Pointer to function to get pixel format. */ | ||
75 | int (*set_pixel_format) (u32 pixfmt); | ||
76 | /* Pointer to function to set image window */ | ||
77 | int (*set_image_window) (struct v4l2_rect *win); | ||
78 | /* Pointer to function to set image window */ | ||
79 | void (*get_image_window) (struct v4l2_rect *win); | ||
80 | /* Pointer to function to get line length */ | ||
81 | unsigned int (*get_line_length) (void); | ||
82 | |||
83 | /* Query CCDC control IDs */ | ||
84 | int (*queryctrl)(struct v4l2_queryctrl *qctrl); | ||
85 | /* Set CCDC control */ | ||
86 | int (*set_control)(struct v4l2_control *ctrl); | ||
87 | /* Get CCDC control */ | ||
88 | int (*get_control)(struct v4l2_control *ctrl); | ||
89 | |||
90 | /* Pointer to function to set frame buffer address */ | ||
91 | void (*setfbaddr) (unsigned long addr); | ||
92 | /* Pointer to function to get field id */ | ||
93 | int (*getfid) (void); | ||
94 | }; | ||
95 | |||
96 | struct ccdc_hw_device { | ||
97 | /* ccdc device name */ | ||
98 | char name[32]; | ||
99 | /* module owner */ | ||
100 | struct module *owner; | ||
101 | /* hw ops */ | ||
102 | struct ccdc_hw_ops hw_ops; | ||
103 | }; | ||
104 | |||
105 | /* Used by CCDC module to register & unregister with vpfe capture driver */ | ||
106 | int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); | ||
107 | void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); | ||
108 | |||
109 | #endif | ||
110 | #endif | ||
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c new file mode 100644 index 000000000000..4629cabe3f28 --- /dev/null +++ b/drivers/media/video/davinci/dm355_ccdc.c | |||
@@ -0,0 +1,978 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2009 Texas Instruments Inc | ||
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 | * CCDC hardware module for DM355 | ||
19 | * ------------------------------ | ||
20 | * | ||
21 | * This module is for configuring DM355 CCD controller of VPFE to capture | ||
22 | * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules | ||
23 | * such as Defect Pixel Correction, Color Space Conversion etc to | ||
24 | * pre-process the Bayer RGB data, before writing it to SDRAM. This | ||
25 | * module also allows application to configure individual | ||
26 | * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. | ||
27 | * To do so, application include dm355_ccdc.h and vpfe_capture.h header | ||
28 | * files. The setparams() API is called by vpfe_capture driver | ||
29 | * to configure module parameters | ||
30 | * | ||
31 | * TODO: 1) Raw bayer parameter settings and bayer capture | ||
32 | * 2) Split module parameter structure to module specific ioctl structs | ||
33 | * 3) add support for lense shading correction | ||
34 | * 4) investigate if enum used for user space type definition | ||
35 | * to be replaced by #defines or integer | ||
36 | */ | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | #include <linux/videodev2.h> | ||
40 | #include <media/davinci/dm355_ccdc.h> | ||
41 | #include <media/davinci/vpss.h> | ||
42 | #include "dm355_ccdc_regs.h" | ||
43 | #include "ccdc_hw_device.h" | ||
44 | |||
45 | MODULE_LICENSE("GPL"); | ||
46 | MODULE_DESCRIPTION("CCDC Driver for DM355"); | ||
47 | MODULE_AUTHOR("Texas Instruments"); | ||
48 | |||
49 | static struct device *dev; | ||
50 | |||
51 | /* Object for CCDC raw mode */ | ||
52 | static struct ccdc_params_raw ccdc_hw_params_raw = { | ||
53 | .pix_fmt = CCDC_PIXFMT_RAW, | ||
54 | .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, | ||
55 | .win = CCDC_WIN_VGA, | ||
56 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
57 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
58 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
59 | .gain = { | ||
60 | .r_ye = 256, | ||
61 | .gb_g = 256, | ||
62 | .gr_cy = 256, | ||
63 | .b_mg = 256 | ||
64 | }, | ||
65 | .config_params = { | ||
66 | .datasft = 2, | ||
67 | .data_sz = CCDC_DATA_10BITS, | ||
68 | .mfilt1 = CCDC_NO_MEDIAN_FILTER1, | ||
69 | .mfilt2 = CCDC_NO_MEDIAN_FILTER2, | ||
70 | .alaw = { | ||
71 | .gama_wd = 2, | ||
72 | }, | ||
73 | .blk_clamp = { | ||
74 | .sample_pixel = 1, | ||
75 | .dc_sub = 25 | ||
76 | }, | ||
77 | .col_pat_field0 = { | ||
78 | .olop = CCDC_GREEN_BLUE, | ||
79 | .olep = CCDC_BLUE, | ||
80 | .elop = CCDC_RED, | ||
81 | .elep = CCDC_GREEN_RED | ||
82 | }, | ||
83 | .col_pat_field1 = { | ||
84 | .olop = CCDC_GREEN_BLUE, | ||
85 | .olep = CCDC_BLUE, | ||
86 | .elop = CCDC_RED, | ||
87 | .elep = CCDC_GREEN_RED | ||
88 | }, | ||
89 | }, | ||
90 | }; | ||
91 | |||
92 | |||
93 | /* Object for CCDC ycbcr mode */ | ||
94 | static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { | ||
95 | .win = CCDC_WIN_PAL, | ||
96 | .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, | ||
97 | .frm_fmt = CCDC_FRMFMT_INTERLACED, | ||
98 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
99 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
100 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
101 | .bt656_enable = 1, | ||
102 | .pix_order = CCDC_PIXORDER_CBYCRY, | ||
103 | .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED | ||
104 | }; | ||
105 | |||
106 | static enum vpfe_hw_if_type ccdc_if_type; | ||
107 | static void *__iomem ccdc_base_addr; | ||
108 | static int ccdc_addr_size; | ||
109 | |||
110 | /* Raw Bayer formats */ | ||
111 | static u32 ccdc_raw_bayer_pix_formats[] = | ||
112 | {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; | ||
113 | |||
114 | /* Raw YUV formats */ | ||
115 | static u32 ccdc_raw_yuv_pix_formats[] = | ||
116 | {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; | ||
117 | |||
118 | /* register access routines */ | ||
119 | static inline u32 regr(u32 offset) | ||
120 | { | ||
121 | return __raw_readl(ccdc_base_addr + offset); | ||
122 | } | ||
123 | |||
124 | static inline void regw(u32 val, u32 offset) | ||
125 | { | ||
126 | __raw_writel(val, ccdc_base_addr + offset); | ||
127 | } | ||
128 | |||
129 | static void ccdc_set_ccdc_base(void *addr, int size) | ||
130 | { | ||
131 | ccdc_base_addr = addr; | ||
132 | ccdc_addr_size = size; | ||
133 | } | ||
134 | |||
135 | static void ccdc_enable(int en) | ||
136 | { | ||
137 | unsigned int temp; | ||
138 | temp = regr(SYNCEN); | ||
139 | temp &= (~CCDC_SYNCEN_VDHDEN_MASK); | ||
140 | temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); | ||
141 | regw(temp, SYNCEN); | ||
142 | } | ||
143 | |||
144 | static void ccdc_enable_output_to_sdram(int en) | ||
145 | { | ||
146 | unsigned int temp; | ||
147 | temp = regr(SYNCEN); | ||
148 | temp &= (~(CCDC_SYNCEN_WEN_MASK)); | ||
149 | temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); | ||
150 | regw(temp, SYNCEN); | ||
151 | } | ||
152 | |||
153 | static void ccdc_config_gain_offset(void) | ||
154 | { | ||
155 | /* configure gain */ | ||
156 | regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN); | ||
157 | regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN); | ||
158 | regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN); | ||
159 | regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN); | ||
160 | /* configure offset */ | ||
161 | regw(ccdc_hw_params_raw.ccdc_offset, OFFSET); | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * ccdc_restore_defaults() | ||
166 | * This function restore power on defaults in the ccdc registers | ||
167 | */ | ||
168 | static int ccdc_restore_defaults(void) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | dev_dbg(dev, "\nstarting ccdc_restore_defaults..."); | ||
173 | /* set all registers to zero */ | ||
174 | for (i = 0; i <= CCDC_REG_LAST; i += 4) | ||
175 | regw(0, i); | ||
176 | |||
177 | /* now override the values with power on defaults in registers */ | ||
178 | regw(MODESET_DEFAULT, MODESET); | ||
179 | /* no culling support */ | ||
180 | regw(CULH_DEFAULT, CULH); | ||
181 | regw(CULV_DEFAULT, CULV); | ||
182 | /* Set default Gain and Offset */ | ||
183 | ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT; | ||
184 | ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT; | ||
185 | ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT; | ||
186 | ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT; | ||
187 | ccdc_config_gain_offset(); | ||
188 | regw(OUTCLIP_DEFAULT, OUTCLIP); | ||
189 | regw(LSCCFG2_DEFAULT, LSCCFG2); | ||
190 | /* select ccdc input */ | ||
191 | if (vpss_select_ccdc_source(VPSS_CCDCIN)) { | ||
192 | dev_dbg(dev, "\ncouldn't select ccdc input source"); | ||
193 | return -EFAULT; | ||
194 | } | ||
195 | /* select ccdc clock */ | ||
196 | if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { | ||
197 | dev_dbg(dev, "\ncouldn't enable ccdc clock"); | ||
198 | return -EFAULT; | ||
199 | } | ||
200 | dev_dbg(dev, "\nEnd of ccdc_restore_defaults..."); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int ccdc_open(struct device *device) | ||
205 | { | ||
206 | dev = device; | ||
207 | return ccdc_restore_defaults(); | ||
208 | } | ||
209 | |||
210 | static int ccdc_close(struct device *device) | ||
211 | { | ||
212 | /* disable clock */ | ||
213 | vpss_enable_clock(VPSS_CCDC_CLOCK, 0); | ||
214 | /* do nothing for now */ | ||
215 | return 0; | ||
216 | } | ||
217 | /* | ||
218 | * ccdc_setwin() | ||
219 | * This function will configure the window size to | ||
220 | * be capture in CCDC reg. | ||
221 | */ | ||
222 | static void ccdc_setwin(struct v4l2_rect *image_win, | ||
223 | enum ccdc_frmfmt frm_fmt, int ppc) | ||
224 | { | ||
225 | int horz_start, horz_nr_pixels; | ||
226 | int vert_start, vert_nr_lines; | ||
227 | int mid_img = 0; | ||
228 | |||
229 | dev_dbg(dev, "\nStarting ccdc_setwin..."); | ||
230 | |||
231 | /* | ||
232 | * ppc - per pixel count. indicates how many pixels per cell | ||
233 | * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. | ||
234 | * raw capture this is 1 | ||
235 | */ | ||
236 | horz_start = image_win->left << (ppc - 1); | ||
237 | horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; | ||
238 | |||
239 | /* Writing the horizontal info into the registers */ | ||
240 | regw(horz_start, SPH); | ||
241 | regw(horz_nr_pixels, NPH); | ||
242 | vert_start = image_win->top; | ||
243 | |||
244 | if (frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
245 | vert_nr_lines = (image_win->height >> 1) - 1; | ||
246 | vert_start >>= 1; | ||
247 | /* Since first line doesn't have any data */ | ||
248 | vert_start += 1; | ||
249 | /* configure VDINT0 and VDINT1 */ | ||
250 | regw(vert_start, VDINT0); | ||
251 | } else { | ||
252 | /* Since first line doesn't have any data */ | ||
253 | vert_start += 1; | ||
254 | vert_nr_lines = image_win->height - 1; | ||
255 | /* configure VDINT0 and VDINT1 */ | ||
256 | mid_img = vert_start + (image_win->height / 2); | ||
257 | regw(vert_start, VDINT0); | ||
258 | regw(mid_img, VDINT1); | ||
259 | } | ||
260 | regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); | ||
261 | regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); | ||
262 | regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); | ||
263 | dev_dbg(dev, "\nEnd of ccdc_setwin..."); | ||
264 | } | ||
265 | |||
266 | static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) | ||
267 | { | ||
268 | if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || | ||
269 | ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { | ||
270 | dev_dbg(dev, "Invalid value of data shift\n"); | ||
271 | return -EINVAL; | ||
272 | } | ||
273 | |||
274 | if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || | ||
275 | ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { | ||
276 | dev_dbg(dev, "Invalid value of median filter1\n"); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || | ||
281 | ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { | ||
282 | dev_dbg(dev, "Invalid value of median filter2\n"); | ||
283 | return -EINVAL; | ||
284 | } | ||
285 | |||
286 | if ((ccdcparam->med_filt_thres < 0) || | ||
287 | (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { | ||
288 | dev_dbg(dev, "Invalid value of median filter thresold\n"); | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | |||
292 | if (ccdcparam->data_sz < CCDC_DATA_16BITS || | ||
293 | ccdcparam->data_sz > CCDC_DATA_8BITS) { | ||
294 | dev_dbg(dev, "Invalid value of data size\n"); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | if (ccdcparam->alaw.enable) { | ||
299 | if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || | ||
300 | ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { | ||
301 | dev_dbg(dev, "Invalid value of ALAW\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | if (ccdcparam->blk_clamp.b_clamp_enable) { | ||
307 | if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || | ||
308 | ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { | ||
309 | dev_dbg(dev, "Invalid value of sample pixel\n"); | ||
310 | return -EINVAL; | ||
311 | } | ||
312 | if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || | ||
313 | ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { | ||
314 | dev_dbg(dev, "Invalid value of sample lines\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | } | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | /* Parameter operations */ | ||
322 | static int ccdc_set_params(void __user *params) | ||
323 | { | ||
324 | struct ccdc_config_params_raw ccdc_raw_params; | ||
325 | int x; | ||
326 | |||
327 | /* only raw module parameters can be set through the IOCTL */ | ||
328 | if (ccdc_if_type != VPFE_RAW_BAYER) | ||
329 | return -EINVAL; | ||
330 | |||
331 | x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); | ||
332 | if (x) { | ||
333 | dev_dbg(dev, "ccdc_set_params: error in copying ccdc" | ||
334 | "params, %d\n", x); | ||
335 | return -EFAULT; | ||
336 | } | ||
337 | |||
338 | if (!validate_ccdc_param(&ccdc_raw_params)) { | ||
339 | memcpy(&ccdc_hw_params_raw.config_params, | ||
340 | &ccdc_raw_params, | ||
341 | sizeof(ccdc_raw_params)); | ||
342 | return 0; | ||
343 | } | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | /* This function will configure CCDC for YCbCr video capture */ | ||
348 | static void ccdc_config_ycbcr(void) | ||
349 | { | ||
350 | struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr; | ||
351 | u32 temp; | ||
352 | |||
353 | /* first set the CCDC power on defaults values in all registers */ | ||
354 | dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); | ||
355 | ccdc_restore_defaults(); | ||
356 | |||
357 | /* configure pixel format & video frame format */ | ||
358 | temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << | ||
359 | CCDC_INPUT_MODE_SHIFT) | | ||
360 | ((params->frm_fmt & CCDC_FRM_FMT_MASK) << | ||
361 | CCDC_FRM_FMT_SHIFT)); | ||
362 | |||
363 | /* setup BT.656 sync mode */ | ||
364 | if (params->bt656_enable) { | ||
365 | regw(CCDC_REC656IF_BT656_EN, REC656IF); | ||
366 | /* | ||
367 | * configure the FID, VD, HD pin polarity fld,hd pol positive, | ||
368 | * vd negative, 8-bit pack mode | ||
369 | */ | ||
370 | temp |= CCDC_VD_POL_NEGATIVE; | ||
371 | } else { /* y/c external sync mode */ | ||
372 | temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << | ||
373 | CCDC_FID_POL_SHIFT) | | ||
374 | ((params->hd_pol & CCDC_HD_POL_MASK) << | ||
375 | CCDC_HD_POL_SHIFT) | | ||
376 | ((params->vd_pol & CCDC_VD_POL_MASK) << | ||
377 | CCDC_VD_POL_SHIFT)); | ||
378 | } | ||
379 | |||
380 | /* pack the data to 8-bit */ | ||
381 | temp |= CCDC_DATA_PACK_ENABLE; | ||
382 | |||
383 | regw(temp, MODESET); | ||
384 | |||
385 | /* configure video window */ | ||
386 | ccdc_setwin(¶ms->win, params->frm_fmt, 2); | ||
387 | |||
388 | /* configure the order of y cb cr in SD-RAM */ | ||
389 | temp = (params->pix_order << CCDC_Y8POS_SHIFT); | ||
390 | temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; | ||
391 | regw(temp, CCDCFG); | ||
392 | |||
393 | /* | ||
394 | * configure the horizontal line offset. This is done by rounding up | ||
395 | * width to a multiple of 16 pixels and multiply by two to account for | ||
396 | * y:cb:cr 4:2:2 data | ||
397 | */ | ||
398 | regw(((params->win.width * 2 + 31) >> 5), HSIZE); | ||
399 | |||
400 | /* configure the memory line offset */ | ||
401 | if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { | ||
402 | /* two fields are interleaved in memory */ | ||
403 | regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); | ||
404 | } | ||
405 | |||
406 | dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * ccdc_config_black_clamp() | ||
411 | * configure parameters for Optical Black Clamp | ||
412 | */ | ||
413 | static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) | ||
414 | { | ||
415 | u32 val; | ||
416 | |||
417 | if (!bclamp->b_clamp_enable) { | ||
418 | /* configure DCSub */ | ||
419 | regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); | ||
420 | regw(0x0000, CLAMP); | ||
421 | return; | ||
422 | } | ||
423 | /* Enable the Black clamping, set sample lines and pixels */ | ||
424 | val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | | ||
425 | ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << | ||
426 | CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; | ||
427 | regw(val, CLAMP); | ||
428 | |||
429 | /* If Black clamping is enable then make dcsub 0 */ | ||
430 | val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) | ||
431 | << CCDC_NUM_LINE_CALC_SHIFT; | ||
432 | regw(val, DCSUB); | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * ccdc_config_black_compense() | ||
437 | * configure parameters for Black Compensation | ||
438 | */ | ||
439 | static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) | ||
440 | { | ||
441 | u32 val; | ||
442 | |||
443 | val = (bcomp->b & CCDC_BLK_COMP_MASK) | | ||
444 | ((bcomp->gb & CCDC_BLK_COMP_MASK) << | ||
445 | CCDC_BLK_COMP_GB_COMP_SHIFT); | ||
446 | regw(val, BLKCMP1); | ||
447 | |||
448 | val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << | ||
449 | CCDC_BLK_COMP_GR_COMP_SHIFT) | | ||
450 | ((bcomp->r & CCDC_BLK_COMP_MASK) << | ||
451 | CCDC_BLK_COMP_R_COMP_SHIFT); | ||
452 | regw(val, BLKCMP0); | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * ccdc_write_dfc_entry() | ||
457 | * write an entry in the dfc table. | ||
458 | */ | ||
459 | int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) | ||
460 | { | ||
461 | /* TODO This is to be re-visited and adjusted */ | ||
462 | #define DFC_WRITE_WAIT_COUNT 1000 | ||
463 | u32 val, count = DFC_WRITE_WAIT_COUNT; | ||
464 | |||
465 | regw(dfc->dft_corr_vert[index], DFCMEM0); | ||
466 | regw(dfc->dft_corr_horz[index], DFCMEM1); | ||
467 | regw(dfc->dft_corr_sub1[index], DFCMEM2); | ||
468 | regw(dfc->dft_corr_sub2[index], DFCMEM3); | ||
469 | regw(dfc->dft_corr_sub3[index], DFCMEM4); | ||
470 | /* set WR bit to write */ | ||
471 | val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; | ||
472 | regw(val, DFCMEMCTL); | ||
473 | |||
474 | /* | ||
475 | * Assume, it is very short. If we get an error, we need to | ||
476 | * adjust this value | ||
477 | */ | ||
478 | while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) | ||
479 | count--; | ||
480 | /* | ||
481 | * TODO We expect the count to be non-zero to be successful. Adjust | ||
482 | * the count if write requires more time | ||
483 | */ | ||
484 | |||
485 | if (count) { | ||
486 | dev_err(dev, "defect table write timeout !!!\n"); | ||
487 | return -1; | ||
488 | } | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * ccdc_config_vdfc() | ||
494 | * configure parameters for Vertical Defect Correction | ||
495 | */ | ||
496 | static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) | ||
497 | { | ||
498 | u32 val; | ||
499 | int i; | ||
500 | |||
501 | /* Configure General Defect Correction. The table used is from IPIPE */ | ||
502 | val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; | ||
503 | |||
504 | /* Configure Vertical Defect Correction if needed */ | ||
505 | if (!dfc->ver_dft_en) { | ||
506 | /* Enable only General Defect Correction */ | ||
507 | regw(val, DFCCTL); | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | if (dfc->table_size > CCDC_DFT_TABLE_SIZE) | ||
512 | return -EINVAL; | ||
513 | |||
514 | val |= CCDC_DFCCTL_VDFC_DISABLE; | ||
515 | val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << | ||
516 | CCDC_DFCCTL_VDFCSL_SHIFT; | ||
517 | val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << | ||
518 | CCDC_DFCCTL_VDFCUDA_SHIFT; | ||
519 | val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << | ||
520 | CCDC_DFCCTL_VDFLSFT_SHIFT; | ||
521 | regw(val , DFCCTL); | ||
522 | |||
523 | /* clear address ptr to offset 0 */ | ||
524 | val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; | ||
525 | |||
526 | /* write defect table entries */ | ||
527 | for (i = 0; i < dfc->table_size; i++) { | ||
528 | /* increment address for non zero index */ | ||
529 | if (i != 0) | ||
530 | val = CCDC_DFCMEMCTL_INC_ADDR; | ||
531 | regw(val, DFCMEMCTL); | ||
532 | if (ccdc_write_dfc_entry(i, dfc) < 0) | ||
533 | return -EFAULT; | ||
534 | } | ||
535 | |||
536 | /* update saturation level and enable dfc */ | ||
537 | regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); | ||
538 | val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << | ||
539 | CCDC_DFCCTL_VDFCEN_SHIFT); | ||
540 | regw(val, DFCCTL); | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * ccdc_config_csc() | ||
546 | * configure parameters for color space conversion | ||
547 | * Each register CSCM0-7 has two values in S8Q5 format. | ||
548 | */ | ||
549 | static void ccdc_config_csc(struct ccdc_csc *csc) | ||
550 | { | ||
551 | u32 val1, val2; | ||
552 | int i; | ||
553 | |||
554 | if (!csc->enable) | ||
555 | return; | ||
556 | |||
557 | /* Enable the CSC sub-module */ | ||
558 | regw(CCDC_CSC_ENABLE, CSCCTL); | ||
559 | |||
560 | /* Converting the co-eff as per the format of the register */ | ||
561 | for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) { | ||
562 | if ((i % 2) == 0) { | ||
563 | /* CSCM - LSB */ | ||
564 | val1 = (csc->coeff[i].integer & | ||
565 | CCDC_CSC_COEF_INTEG_MASK) | ||
566 | << CCDC_CSC_COEF_INTEG_SHIFT; | ||
567 | /* | ||
568 | * convert decimal part to binary. Use 2 decimal | ||
569 | * precision, user values range from .00 - 0.99 | ||
570 | */ | ||
571 | val1 |= (((csc->coeff[i].decimal & | ||
572 | CCDC_CSC_COEF_DECIMAL_MASK) * | ||
573 | CCDC_CSC_DEC_MAX) / 100); | ||
574 | } else { | ||
575 | |||
576 | /* CSCM - MSB */ | ||
577 | val2 = (csc->coeff[i].integer & | ||
578 | CCDC_CSC_COEF_INTEG_MASK) | ||
579 | << CCDC_CSC_COEF_INTEG_SHIFT; | ||
580 | val2 |= (((csc->coeff[i].decimal & | ||
581 | CCDC_CSC_COEF_DECIMAL_MASK) * | ||
582 | CCDC_CSC_DEC_MAX) / 100); | ||
583 | val2 <<= CCDC_CSCM_MSB_SHIFT; | ||
584 | val2 |= val1; | ||
585 | regw(val2, (CSCM0 + ((i - 1) << 1))); | ||
586 | } | ||
587 | } | ||
588 | } | ||
589 | |||
590 | /* | ||
591 | * ccdc_config_color_patterns() | ||
592 | * configure parameters for color patterns | ||
593 | */ | ||
594 | static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, | ||
595 | struct ccdc_col_pat *pat1) | ||
596 | { | ||
597 | u32 val; | ||
598 | |||
599 | val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | | ||
600 | (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | | ||
601 | (pat1->elop << 12) | (pat1->elep << 14)); | ||
602 | regw(val, COLPTN); | ||
603 | } | ||
604 | |||
605 | /* This function will configure CCDC for Raw mode image capture */ | ||
606 | static int ccdc_config_raw(void) | ||
607 | { | ||
608 | struct ccdc_params_raw *params = &ccdc_hw_params_raw; | ||
609 | struct ccdc_config_params_raw *config_params = | ||
610 | &ccdc_hw_params_raw.config_params; | ||
611 | unsigned int val; | ||
612 | |||
613 | dev_dbg(dev, "\nStarting ccdc_config_raw..."); | ||
614 | |||
615 | /* restore power on defaults to register */ | ||
616 | ccdc_restore_defaults(); | ||
617 | |||
618 | /* CCDCFG register: | ||
619 | * set CCD Not to swap input since input is RAW data | ||
620 | * set FID detection function to Latch at V-Sync | ||
621 | * set WENLOG - ccdc valid area to AND | ||
622 | * set TRGSEL to WENBIT | ||
623 | * set EXTRG to DISABLE | ||
624 | * disable latching function on VSYNC - shadowed registers | ||
625 | */ | ||
626 | regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | | ||
627 | CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | | ||
628 | CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); | ||
629 | |||
630 | /* | ||
631 | * Set VDHD direction to input, input type to raw input | ||
632 | * normal data polarity, do not use external WEN | ||
633 | */ | ||
634 | val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | | ||
635 | CCDC_EXWEN_DISABLE); | ||
636 | |||
637 | /* | ||
638 | * Configure the vertical sync polarity (MODESET.VDPOL), horizontal | ||
639 | * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), | ||
640 | * frame format(progressive or interlace), & pixel format (Input mode) | ||
641 | */ | ||
642 | val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | | ||
643 | ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | | ||
644 | ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | | ||
645 | ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | | ||
646 | ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); | ||
647 | |||
648 | /* set pack for alaw compression */ | ||
649 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
650 | config_params->alaw.enable) | ||
651 | val |= CCDC_DATA_PACK_ENABLE; | ||
652 | |||
653 | /* Configure for LPF */ | ||
654 | if (config_params->lpf_enable) | ||
655 | val |= (config_params->lpf_enable & CCDC_LPF_MASK) << | ||
656 | CCDC_LPF_SHIFT; | ||
657 | |||
658 | /* Configure the data shift */ | ||
659 | val |= (config_params->datasft & CCDC_DATASFT_MASK) << | ||
660 | CCDC_DATASFT_SHIFT; | ||
661 | regw(val , MODESET); | ||
662 | dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val); | ||
663 | |||
664 | /* Configure the Median Filter threshold */ | ||
665 | regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); | ||
666 | |||
667 | /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ | ||
668 | val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | | ||
669 | CCDC_CFA_MOSAIC; | ||
670 | |||
671 | /* Enable and configure aLaw register if needed */ | ||
672 | if (config_params->alaw.enable) { | ||
673 | val |= (CCDC_ALAW_ENABLE | | ||
674 | ((config_params->alaw.gama_wd & | ||
675 | CCDC_ALAW_GAMA_WD_MASK) << | ||
676 | CCDC_GAMMAWD_INPUT_SHIFT)); | ||
677 | } | ||
678 | |||
679 | /* Configure Median filter1 & filter2 */ | ||
680 | val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | | ||
681 | (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); | ||
682 | |||
683 | regw(val, GAMMAWD); | ||
684 | dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val); | ||
685 | |||
686 | /* configure video window */ | ||
687 | ccdc_setwin(¶ms->win, params->frm_fmt, 1); | ||
688 | |||
689 | /* Optical Clamp Averaging */ | ||
690 | ccdc_config_black_clamp(&config_params->blk_clamp); | ||
691 | |||
692 | /* Black level compensation */ | ||
693 | ccdc_config_black_compense(&config_params->blk_comp); | ||
694 | |||
695 | /* Vertical Defect Correction if needed */ | ||
696 | if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) | ||
697 | return -EFAULT; | ||
698 | |||
699 | /* color space conversion */ | ||
700 | ccdc_config_csc(&config_params->csc); | ||
701 | |||
702 | /* color pattern */ | ||
703 | ccdc_config_color_patterns(&config_params->col_pat_field0, | ||
704 | &config_params->col_pat_field1); | ||
705 | |||
706 | /* Configure the Gain & offset control */ | ||
707 | ccdc_config_gain_offset(); | ||
708 | |||
709 | dev_dbg(dev, "\nWriting %x to COLPTN...\n", val); | ||
710 | |||
711 | /* Configure DATAOFST register */ | ||
712 | val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << | ||
713 | CCDC_DATAOFST_H_SHIFT; | ||
714 | val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << | ||
715 | CCDC_DATAOFST_V_SHIFT; | ||
716 | regw(val, DATAOFST); | ||
717 | |||
718 | /* configuring HSIZE register */ | ||
719 | val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << | ||
720 | CCDC_HSIZE_FLIP_SHIFT; | ||
721 | |||
722 | /* If pack 8 is enable then 1 pixel will take 1 byte */ | ||
723 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
724 | config_params->alaw.enable) { | ||
725 | val |= (((params->win.width) + 31) >> 5) & | ||
726 | CCDC_HSIZE_VAL_MASK; | ||
727 | |||
728 | /* adjust to multiple of 32 */ | ||
729 | dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", | ||
730 | (((params->win.width) + 31) >> 5) & | ||
731 | CCDC_HSIZE_VAL_MASK); | ||
732 | } else { | ||
733 | /* else one pixel will take 2 byte */ | ||
734 | val |= (((params->win.width * 2) + 31) >> 5) & | ||
735 | CCDC_HSIZE_VAL_MASK; | ||
736 | |||
737 | dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", | ||
738 | (((params->win.width * 2) + 31) >> 5) & | ||
739 | CCDC_HSIZE_VAL_MASK); | ||
740 | } | ||
741 | regw(val, HSIZE); | ||
742 | |||
743 | /* Configure SDOFST register */ | ||
744 | if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
745 | if (params->image_invert_enable) { | ||
746 | /* For interlace inverse mode */ | ||
747 | regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); | ||
748 | dev_dbg(dev, "\nWriting %x to SDOFST...\n", | ||
749 | CCDC_SDOFST_INTERLACE_INVERSE); | ||
750 | } else { | ||
751 | /* For interlace non inverse mode */ | ||
752 | regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); | ||
753 | dev_dbg(dev, "\nWriting %x to SDOFST...\n", | ||
754 | CCDC_SDOFST_INTERLACE_NORMAL); | ||
755 | } | ||
756 | } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { | ||
757 | if (params->image_invert_enable) { | ||
758 | /* For progessive inverse mode */ | ||
759 | regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); | ||
760 | dev_dbg(dev, "\nWriting %x to SDOFST...\n", | ||
761 | CCDC_SDOFST_PROGRESSIVE_INVERSE); | ||
762 | } else { | ||
763 | /* For progessive non inverse mode */ | ||
764 | regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); | ||
765 | dev_dbg(dev, "\nWriting %x to SDOFST...\n", | ||
766 | CCDC_SDOFST_PROGRESSIVE_NORMAL); | ||
767 | } | ||
768 | } | ||
769 | dev_dbg(dev, "\nend of ccdc_config_raw..."); | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static int ccdc_configure(void) | ||
774 | { | ||
775 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
776 | return ccdc_config_raw(); | ||
777 | else | ||
778 | ccdc_config_ycbcr(); | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int ccdc_set_buftype(enum ccdc_buftype buf_type) | ||
783 | { | ||
784 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
785 | ccdc_hw_params_raw.buf_type = buf_type; | ||
786 | else | ||
787 | ccdc_hw_params_ycbcr.buf_type = buf_type; | ||
788 | return 0; | ||
789 | } | ||
790 | static enum ccdc_buftype ccdc_get_buftype(void) | ||
791 | { | ||
792 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
793 | return ccdc_hw_params_raw.buf_type; | ||
794 | return ccdc_hw_params_ycbcr.buf_type; | ||
795 | } | ||
796 | |||
797 | static int ccdc_enum_pix(u32 *pix, int i) | ||
798 | { | ||
799 | int ret = -EINVAL; | ||
800 | if (ccdc_if_type == VPFE_RAW_BAYER) { | ||
801 | if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { | ||
802 | *pix = ccdc_raw_bayer_pix_formats[i]; | ||
803 | ret = 0; | ||
804 | } | ||
805 | } else { | ||
806 | if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { | ||
807 | *pix = ccdc_raw_yuv_pix_formats[i]; | ||
808 | ret = 0; | ||
809 | } | ||
810 | } | ||
811 | return ret; | ||
812 | } | ||
813 | |||
814 | static int ccdc_set_pixel_format(u32 pixfmt) | ||
815 | { | ||
816 | struct ccdc_a_law *alaw = | ||
817 | &ccdc_hw_params_raw.config_params.alaw; | ||
818 | |||
819 | if (ccdc_if_type == VPFE_RAW_BAYER) { | ||
820 | ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW; | ||
821 | if (pixfmt == V4L2_PIX_FMT_SBGGR8) | ||
822 | alaw->enable = 1; | ||
823 | else if (pixfmt != V4L2_PIX_FMT_SBGGR16) | ||
824 | return -EINVAL; | ||
825 | } else { | ||
826 | if (pixfmt == V4L2_PIX_FMT_YUYV) | ||
827 | ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; | ||
828 | else if (pixfmt == V4L2_PIX_FMT_UYVY) | ||
829 | ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; | ||
830 | else | ||
831 | return -EINVAL; | ||
832 | } | ||
833 | return 0; | ||
834 | } | ||
835 | static u32 ccdc_get_pixel_format(void) | ||
836 | { | ||
837 | struct ccdc_a_law *alaw = | ||
838 | &ccdc_hw_params_raw.config_params.alaw; | ||
839 | u32 pixfmt; | ||
840 | |||
841 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
842 | if (alaw->enable) | ||
843 | pixfmt = V4L2_PIX_FMT_SBGGR8; | ||
844 | else | ||
845 | pixfmt = V4L2_PIX_FMT_SBGGR16; | ||
846 | else { | ||
847 | if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) | ||
848 | pixfmt = V4L2_PIX_FMT_YUYV; | ||
849 | else | ||
850 | pixfmt = V4L2_PIX_FMT_UYVY; | ||
851 | } | ||
852 | return pixfmt; | ||
853 | } | ||
854 | static int ccdc_set_image_window(struct v4l2_rect *win) | ||
855 | { | ||
856 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
857 | ccdc_hw_params_raw.win = *win; | ||
858 | else | ||
859 | ccdc_hw_params_ycbcr.win = *win; | ||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static void ccdc_get_image_window(struct v4l2_rect *win) | ||
864 | { | ||
865 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
866 | *win = ccdc_hw_params_raw.win; | ||
867 | else | ||
868 | *win = ccdc_hw_params_ycbcr.win; | ||
869 | } | ||
870 | |||
871 | static unsigned int ccdc_get_line_length(void) | ||
872 | { | ||
873 | struct ccdc_config_params_raw *config_params = | ||
874 | &ccdc_hw_params_raw.config_params; | ||
875 | unsigned int len; | ||
876 | |||
877 | if (ccdc_if_type == VPFE_RAW_BAYER) { | ||
878 | if ((config_params->alaw.enable) || | ||
879 | (config_params->data_sz == CCDC_DATA_8BITS)) | ||
880 | len = ccdc_hw_params_raw.win.width; | ||
881 | else | ||
882 | len = ccdc_hw_params_raw.win.width * 2; | ||
883 | } else | ||
884 | len = ccdc_hw_params_ycbcr.win.width * 2; | ||
885 | return ALIGN(len, 32); | ||
886 | } | ||
887 | |||
888 | static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) | ||
889 | { | ||
890 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
891 | ccdc_hw_params_raw.frm_fmt = frm_fmt; | ||
892 | else | ||
893 | ccdc_hw_params_ycbcr.frm_fmt = frm_fmt; | ||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static enum ccdc_frmfmt ccdc_get_frame_format(void) | ||
898 | { | ||
899 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
900 | return ccdc_hw_params_raw.frm_fmt; | ||
901 | else | ||
902 | return ccdc_hw_params_ycbcr.frm_fmt; | ||
903 | } | ||
904 | |||
905 | static int ccdc_getfid(void) | ||
906 | { | ||
907 | return (regr(MODESET) >> 15) & 1; | ||
908 | } | ||
909 | |||
910 | /* misc operations */ | ||
911 | static inline void ccdc_setfbaddr(unsigned long addr) | ||
912 | { | ||
913 | regw((addr >> 21) & 0x007f, STADRH); | ||
914 | regw((addr >> 5) & 0x0ffff, STADRL); | ||
915 | } | ||
916 | |||
917 | static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) | ||
918 | { | ||
919 | ccdc_if_type = params->if_type; | ||
920 | |||
921 | switch (params->if_type) { | ||
922 | case VPFE_BT656: | ||
923 | case VPFE_YCBCR_SYNC_16: | ||
924 | case VPFE_YCBCR_SYNC_8: | ||
925 | ccdc_hw_params_ycbcr.vd_pol = params->vdpol; | ||
926 | ccdc_hw_params_ycbcr.hd_pol = params->hdpol; | ||
927 | break; | ||
928 | default: | ||
929 | /* TODO add support for raw bayer here */ | ||
930 | return -EINVAL; | ||
931 | } | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static struct ccdc_hw_device ccdc_hw_dev = { | ||
936 | .name = "DM355 CCDC", | ||
937 | .owner = THIS_MODULE, | ||
938 | .hw_ops = { | ||
939 | .open = ccdc_open, | ||
940 | .close = ccdc_close, | ||
941 | .set_ccdc_base = ccdc_set_ccdc_base, | ||
942 | .enable = ccdc_enable, | ||
943 | .enable_out_to_sdram = ccdc_enable_output_to_sdram, | ||
944 | .set_hw_if_params = ccdc_set_hw_if_params, | ||
945 | .set_params = ccdc_set_params, | ||
946 | .configure = ccdc_configure, | ||
947 | .set_buftype = ccdc_set_buftype, | ||
948 | .get_buftype = ccdc_get_buftype, | ||
949 | .enum_pix = ccdc_enum_pix, | ||
950 | .set_pixel_format = ccdc_set_pixel_format, | ||
951 | .get_pixel_format = ccdc_get_pixel_format, | ||
952 | .set_frame_format = ccdc_set_frame_format, | ||
953 | .get_frame_format = ccdc_get_frame_format, | ||
954 | .set_image_window = ccdc_set_image_window, | ||
955 | .get_image_window = ccdc_get_image_window, | ||
956 | .get_line_length = ccdc_get_line_length, | ||
957 | .setfbaddr = ccdc_setfbaddr, | ||
958 | .getfid = ccdc_getfid, | ||
959 | }, | ||
960 | }; | ||
961 | |||
962 | static int dm355_ccdc_init(void) | ||
963 | { | ||
964 | printk(KERN_NOTICE "dm355_ccdc_init\n"); | ||
965 | if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) | ||
966 | return -1; | ||
967 | printk(KERN_NOTICE "%s is registered with vpfe.\n", | ||
968 | ccdc_hw_dev.name); | ||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static void dm355_ccdc_exit(void) | ||
973 | { | ||
974 | vpfe_unregister_ccdc_device(&ccdc_hw_dev); | ||
975 | } | ||
976 | |||
977 | module_init(dm355_ccdc_init); | ||
978 | module_exit(dm355_ccdc_exit); | ||
diff --git a/drivers/media/video/davinci/dm355_ccdc_regs.h b/drivers/media/video/davinci/dm355_ccdc_regs.h new file mode 100644 index 000000000000..d6d2ef0533b5 --- /dev/null +++ b/drivers/media/video/davinci/dm355_ccdc_regs.h | |||
@@ -0,0 +1,310 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2009 Texas Instruments Inc | ||
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 | #ifndef _DM355_CCDC_REGS_H | ||
19 | #define _DM355_CCDC_REGS_H | ||
20 | |||
21 | /**************************************************************************\ | ||
22 | * Register OFFSET Definitions | ||
23 | \**************************************************************************/ | ||
24 | #define SYNCEN 0x00 | ||
25 | #define MODESET 0x04 | ||
26 | #define HDWIDTH 0x08 | ||
27 | #define VDWIDTH 0x0c | ||
28 | #define PPLN 0x10 | ||
29 | #define LPFR 0x14 | ||
30 | #define SPH 0x18 | ||
31 | #define NPH 0x1c | ||
32 | #define SLV0 0x20 | ||
33 | #define SLV1 0x24 | ||
34 | #define NLV 0x28 | ||
35 | #define CULH 0x2c | ||
36 | #define CULV 0x30 | ||
37 | #define HSIZE 0x34 | ||
38 | #define SDOFST 0x38 | ||
39 | #define STADRH 0x3c | ||
40 | #define STADRL 0x40 | ||
41 | #define CLAMP 0x44 | ||
42 | #define DCSUB 0x48 | ||
43 | #define COLPTN 0x4c | ||
44 | #define BLKCMP0 0x50 | ||
45 | #define BLKCMP1 0x54 | ||
46 | #define MEDFILT 0x58 | ||
47 | #define RYEGAIN 0x5c | ||
48 | #define GRCYGAIN 0x60 | ||
49 | #define GBGGAIN 0x64 | ||
50 | #define BMGGAIN 0x68 | ||
51 | #define OFFSET 0x6c | ||
52 | #define OUTCLIP 0x70 | ||
53 | #define VDINT0 0x74 | ||
54 | #define VDINT1 0x78 | ||
55 | #define RSV0 0x7c | ||
56 | #define GAMMAWD 0x80 | ||
57 | #define REC656IF 0x84 | ||
58 | #define CCDCFG 0x88 | ||
59 | #define FMTCFG 0x8c | ||
60 | #define FMTPLEN 0x90 | ||
61 | #define FMTSPH 0x94 | ||
62 | #define FMTLNH 0x98 | ||
63 | #define FMTSLV 0x9c | ||
64 | #define FMTLNV 0xa0 | ||
65 | #define FMTRLEN 0xa4 | ||
66 | #define FMTHCNT 0xa8 | ||
67 | #define FMT_ADDR_PTR_B 0xac | ||
68 | #define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4)) | ||
69 | #define FMTPGM_VF0 0xcc | ||
70 | #define FMTPGM_VF1 0xd0 | ||
71 | #define FMTPGM_AP0 0xd4 | ||
72 | #define FMTPGM_AP1 0xd8 | ||
73 | #define FMTPGM_AP2 0xdc | ||
74 | #define FMTPGM_AP3 0xe0 | ||
75 | #define FMTPGM_AP4 0xe4 | ||
76 | #define FMTPGM_AP5 0xe8 | ||
77 | #define FMTPGM_AP6 0xec | ||
78 | #define FMTPGM_AP7 0xf0 | ||
79 | #define LSCCFG1 0xf4 | ||
80 | #define LSCCFG2 0xf8 | ||
81 | #define LSCH0 0xfc | ||
82 | #define LSCV0 0x100 | ||
83 | #define LSCKH 0x104 | ||
84 | #define LSCKV 0x108 | ||
85 | #define LSCMEMCTL 0x10c | ||
86 | #define LSCMEMD 0x110 | ||
87 | #define LSCMEMQ 0x114 | ||
88 | #define DFCCTL 0x118 | ||
89 | #define DFCVSAT 0x11c | ||
90 | #define DFCMEMCTL 0x120 | ||
91 | #define DFCMEM0 0x124 | ||
92 | #define DFCMEM1 0x128 | ||
93 | #define DFCMEM2 0x12c | ||
94 | #define DFCMEM3 0x130 | ||
95 | #define DFCMEM4 0x134 | ||
96 | #define CSCCTL 0x138 | ||
97 | #define CSCM0 0x13c | ||
98 | #define CSCM1 0x140 | ||
99 | #define CSCM2 0x144 | ||
100 | #define CSCM3 0x148 | ||
101 | #define CSCM4 0x14c | ||
102 | #define CSCM5 0x150 | ||
103 | #define CSCM6 0x154 | ||
104 | #define CSCM7 0x158 | ||
105 | #define DATAOFST 0x15c | ||
106 | #define CCDC_REG_LAST DATAOFST | ||
107 | /************************************************************** | ||
108 | * Define for various register bit mask and shifts for CCDC | ||
109 | * | ||
110 | **************************************************************/ | ||
111 | #define CCDC_RAW_IP_MODE 0 | ||
112 | #define CCDC_VDHDOUT_INPUT 0 | ||
113 | #define CCDC_YCINSWP_RAW (0 << 4) | ||
114 | #define CCDC_EXWEN_DISABLE 0 | ||
115 | #define CCDC_DATAPOL_NORMAL 0 | ||
116 | #define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 | ||
117 | #define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) | ||
118 | #define CCDC_CCDCFG_WENLOG_AND 0 | ||
119 | #define CCDC_CCDCFG_TRGSEL_WEN 0 | ||
120 | #define CCDC_CCDCFG_EXTRG_DISABLE 0 | ||
121 | #define CCDC_CFA_MOSAIC 0 | ||
122 | #define CCDC_Y8POS_SHIFT 11 | ||
123 | |||
124 | #define CCDC_VDC_DFCVSAT_MASK 0x3fff | ||
125 | #define CCDC_DATAOFST_MASK 0x0ff | ||
126 | #define CCDC_DATAOFST_H_SHIFT 0 | ||
127 | #define CCDC_DATAOFST_V_SHIFT 8 | ||
128 | #define CCDC_GAMMAWD_CFA_MASK 1 | ||
129 | #define CCDC_GAMMAWD_CFA_SHIFT 5 | ||
130 | #define CCDC_GAMMAWD_INPUT_SHIFT 2 | ||
131 | #define CCDC_FID_POL_MASK 1 | ||
132 | #define CCDC_FID_POL_SHIFT 4 | ||
133 | #define CCDC_HD_POL_MASK 1 | ||
134 | #define CCDC_HD_POL_SHIFT 3 | ||
135 | #define CCDC_VD_POL_MASK 1 | ||
136 | #define CCDC_VD_POL_SHIFT 2 | ||
137 | #define CCDC_VD_POL_NEGATIVE (1 << 2) | ||
138 | #define CCDC_FRM_FMT_MASK 1 | ||
139 | #define CCDC_FRM_FMT_SHIFT 7 | ||
140 | #define CCDC_DATA_SZ_MASK 7 | ||
141 | #define CCDC_DATA_SZ_SHIFT 8 | ||
142 | #define CCDC_VDHDOUT_MASK 1 | ||
143 | #define CCDC_VDHDOUT_SHIFT 0 | ||
144 | #define CCDC_EXWEN_MASK 1 | ||
145 | #define CCDC_EXWEN_SHIFT 5 | ||
146 | #define CCDC_INPUT_MODE_MASK 3 | ||
147 | #define CCDC_INPUT_MODE_SHIFT 12 | ||
148 | #define CCDC_PIX_FMT_MASK 3 | ||
149 | #define CCDC_PIX_FMT_SHIFT 12 | ||
150 | #define CCDC_DATAPOL_MASK 1 | ||
151 | #define CCDC_DATAPOL_SHIFT 6 | ||
152 | #define CCDC_WEN_ENABLE (1 << 1) | ||
153 | #define CCDC_VDHDEN_ENABLE (1 << 16) | ||
154 | #define CCDC_LPF_ENABLE (1 << 14) | ||
155 | #define CCDC_ALAW_ENABLE 1 | ||
156 | #define CCDC_ALAW_GAMA_WD_MASK 7 | ||
157 | #define CCDC_REC656IF_BT656_EN 3 | ||
158 | |||
159 | #define CCDC_FMTCFG_FMTMODE_MASK 3 | ||
160 | #define CCDC_FMTCFG_FMTMODE_SHIFT 1 | ||
161 | #define CCDC_FMTCFG_LNUM_MASK 3 | ||
162 | #define CCDC_FMTCFG_LNUM_SHIFT 4 | ||
163 | #define CCDC_FMTCFG_ADDRINC_MASK 7 | ||
164 | #define CCDC_FMTCFG_ADDRINC_SHIFT 8 | ||
165 | |||
166 | #define CCDC_CCDCFG_FIDMD_SHIFT 6 | ||
167 | #define CCDC_CCDCFG_WENLOG_SHIFT 8 | ||
168 | #define CCDC_CCDCFG_TRGSEL_SHIFT 9 | ||
169 | #define CCDC_CCDCFG_EXTRG_SHIFT 10 | ||
170 | #define CCDC_CCDCFG_MSBINVI_SHIFT 13 | ||
171 | |||
172 | #define CCDC_HSIZE_FLIP_SHIFT 12 | ||
173 | #define CCDC_HSIZE_FLIP_MASK 1 | ||
174 | #define CCDC_HSIZE_VAL_MASK 0xFFF | ||
175 | #define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 | ||
176 | #define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D | ||
177 | #define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D | ||
178 | #define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 | ||
179 | #define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 | ||
180 | #define CCDC_START_PX_HOR_MASK 0x7FFF | ||
181 | #define CCDC_NUM_PX_HOR_MASK 0x7FFF | ||
182 | #define CCDC_START_VER_ONE_MASK 0x7FFF | ||
183 | #define CCDC_START_VER_TWO_MASK 0x7FFF | ||
184 | #define CCDC_NUM_LINES_VER 0x7FFF | ||
185 | |||
186 | #define CCDC_BLK_CLAMP_ENABLE (1 << 15) | ||
187 | #define CCDC_BLK_SGAIN_MASK 0x1F | ||
188 | #define CCDC_BLK_ST_PXL_MASK 0x1FFF | ||
189 | #define CCDC_BLK_SAMPLE_LN_MASK 3 | ||
190 | #define CCDC_BLK_SAMPLE_LN_SHIFT 13 | ||
191 | |||
192 | #define CCDC_NUM_LINE_CALC_MASK 3 | ||
193 | #define CCDC_NUM_LINE_CALC_SHIFT 14 | ||
194 | |||
195 | #define CCDC_BLK_DC_SUB_MASK 0x3FFF | ||
196 | #define CCDC_BLK_COMP_MASK 0xFF | ||
197 | #define CCDC_BLK_COMP_GB_COMP_SHIFT 8 | ||
198 | #define CCDC_BLK_COMP_GR_COMP_SHIFT 0 | ||
199 | #define CCDC_BLK_COMP_R_COMP_SHIFT 8 | ||
200 | #define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) | ||
201 | #define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) | ||
202 | #define CCDC_FPC_ENABLE (1 << 15) | ||
203 | #define CCDC_FPC_FPC_NUM_MASK 0x7FFF | ||
204 | #define CCDC_DATA_PACK_ENABLE (1 << 11) | ||
205 | #define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF | ||
206 | #define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF | ||
207 | #define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 | ||
208 | #define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF | ||
209 | #define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF | ||
210 | #define CCDC_FMT_VERT_FMTSLV_SHIFT 16 | ||
211 | #define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF | ||
212 | #define CCDC_VP_OUT_VERT_NUM_SHIFT 17 | ||
213 | #define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF | ||
214 | #define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 | ||
215 | #define CCDC_VP_OUT_HORZ_ST_MASK 0xF | ||
216 | |||
217 | #define CCDC_CSC_COEF_INTEG_MASK 7 | ||
218 | #define CCDC_CSC_COEF_DECIMAL_MASK 0x1f | ||
219 | #define CCDC_CSC_COEF_INTEG_SHIFT 5 | ||
220 | #define CCDC_CSCM_MSB_SHIFT 8 | ||
221 | #define CCDC_CSC_ENABLE 1 | ||
222 | #define CCDC_CSC_DEC_MAX 32 | ||
223 | |||
224 | #define CCDC_MFILT1_SHIFT 10 | ||
225 | #define CCDC_MFILT2_SHIFT 8 | ||
226 | #define CCDC_MED_FILT_THRESH 0x3FFF | ||
227 | #define CCDC_LPF_MASK 1 | ||
228 | #define CCDC_LPF_SHIFT 14 | ||
229 | #define CCDC_OFFSET_MASK 0x3FF | ||
230 | #define CCDC_DATASFT_MASK 7 | ||
231 | #define CCDC_DATASFT_SHIFT 8 | ||
232 | |||
233 | #define CCDC_DF_ENABLE 1 | ||
234 | |||
235 | #define CCDC_FMTPLEN_P0_MASK 0xF | ||
236 | #define CCDC_FMTPLEN_P1_MASK 0xF | ||
237 | #define CCDC_FMTPLEN_P2_MASK 7 | ||
238 | #define CCDC_FMTPLEN_P3_MASK 7 | ||
239 | #define CCDC_FMTPLEN_P0_SHIFT 0 | ||
240 | #define CCDC_FMTPLEN_P1_SHIFT 4 | ||
241 | #define CCDC_FMTPLEN_P2_SHIFT 8 | ||
242 | #define CCDC_FMTPLEN_P3_SHIFT 12 | ||
243 | |||
244 | #define CCDC_FMTSPH_MASK 0x1FFF | ||
245 | #define CCDC_FMTLNH_MASK 0x1FFF | ||
246 | #define CCDC_FMTSLV_MASK 0x1FFF | ||
247 | #define CCDC_FMTLNV_MASK 0x7FFF | ||
248 | #define CCDC_FMTRLEN_MASK 0x1FFF | ||
249 | #define CCDC_FMTHCNT_MASK 0x1FFF | ||
250 | |||
251 | #define CCDC_ADP_INIT_MASK 0x1FFF | ||
252 | #define CCDC_ADP_LINE_SHIFT 13 | ||
253 | #define CCDC_ADP_LINE_MASK 3 | ||
254 | #define CCDC_FMTPGN_APTR_MASK 7 | ||
255 | |||
256 | #define CCDC_DFCCTL_GDFCEN_MASK 1 | ||
257 | #define CCDC_DFCCTL_VDFCEN_MASK 1 | ||
258 | #define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) | ||
259 | #define CCDC_DFCCTL_VDFCEN_SHIFT 4 | ||
260 | #define CCDC_DFCCTL_VDFCSL_MASK 3 | ||
261 | #define CCDC_DFCCTL_VDFCSL_SHIFT 5 | ||
262 | #define CCDC_DFCCTL_VDFCUDA_MASK 1 | ||
263 | #define CCDC_DFCCTL_VDFCUDA_SHIFT 7 | ||
264 | #define CCDC_DFCCTL_VDFLSFT_MASK 3 | ||
265 | #define CCDC_DFCCTL_VDFLSFT_SHIFT 8 | ||
266 | #define CCDC_DFCMEMCTL_DFCMARST_MASK 1 | ||
267 | #define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 | ||
268 | #define CCDC_DFCMEMCTL_DFCMWR_MASK 1 | ||
269 | #define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 | ||
270 | #define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) | ||
271 | |||
272 | #define CCDC_LSCCFG_GFTSF_MASK 7 | ||
273 | #define CCDC_LSCCFG_GFTSF_SHIFT 1 | ||
274 | #define CCDC_LSCCFG_GFTINV_MASK 0xf | ||
275 | #define CCDC_LSCCFG_GFTINV_SHIFT 4 | ||
276 | #define CCDC_LSC_GFTABLE_SEL_MASK 3 | ||
277 | #define CCDC_LSC_GFTABLE_EPEL_SHIFT 8 | ||
278 | #define CCDC_LSC_GFTABLE_OPEL_SHIFT 10 | ||
279 | #define CCDC_LSC_GFTABLE_EPOL_SHIFT 12 | ||
280 | #define CCDC_LSC_GFTABLE_OPOL_SHIFT 14 | ||
281 | #define CCDC_LSC_GFMODE_MASK 3 | ||
282 | #define CCDC_LSC_GFMODE_SHIFT 4 | ||
283 | #define CCDC_LSC_DISABLE 0 | ||
284 | #define CCDC_LSC_ENABLE 1 | ||
285 | #define CCDC_LSC_TABLE1_SLC 0 | ||
286 | #define CCDC_LSC_TABLE2_SLC 1 | ||
287 | #define CCDC_LSC_TABLE3_SLC 2 | ||
288 | #define CCDC_LSC_MEMADDR_RESET (1 << 2) | ||
289 | #define CCDC_LSC_MEMADDR_INCR (0 << 2) | ||
290 | #define CCDC_LSC_FRAC_MASK_T1 0xFF | ||
291 | #define CCDC_LSC_INT_MASK 3 | ||
292 | #define CCDC_LSC_FRAC_MASK 0x3FFF | ||
293 | #define CCDC_LSC_CENTRE_MASK 0x3FFF | ||
294 | #define CCDC_LSC_COEF_MASK 0xff | ||
295 | #define CCDC_LSC_COEFL_SHIFT 0 | ||
296 | #define CCDC_LSC_COEFU_SHIFT 8 | ||
297 | #define CCDC_GAIN_MASK 0x7FF | ||
298 | #define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) | ||
299 | #define CCDC_SYNCEN_WEN_MASK (1 << 1) | ||
300 | #define CCDC_SYNCEN_WEN_SHIFT 1 | ||
301 | |||
302 | /* Power on Defaults in hardware */ | ||
303 | #define MODESET_DEFAULT 0x200 | ||
304 | #define CULH_DEFAULT 0xFFFF | ||
305 | #define CULV_DEFAULT 0xFF | ||
306 | #define GAIN_DEFAULT 256 | ||
307 | #define OUTCLIP_DEFAULT 0x3FFF | ||
308 | #define LSCCFG2_DEFAULT 0xE | ||
309 | |||
310 | #endif | ||
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c new file mode 100644 index 000000000000..2f19a919f477 --- /dev/null +++ b/drivers/media/video/davinci/dm644x_ccdc.c | |||
@@ -0,0 +1,878 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2009 Texas Instruments Inc | ||
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 | * CCDC hardware module for DM6446 | ||
19 | * ------------------------------ | ||
20 | * | ||
21 | * This module is for configuring CCD controller of DM6446 VPFE to capture | ||
22 | * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules | ||
23 | * such as Defect Pixel Correction, Color Space Conversion etc to | ||
24 | * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This | ||
25 | * module also allows application to configure individual | ||
26 | * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. | ||
27 | * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header | ||
28 | * files. The setparams() API is called by vpfe_capture driver | ||
29 | * to configure module parameters. This file is named DM644x so that other | ||
30 | * variants such DM6443 may be supported using the same module. | ||
31 | * | ||
32 | * TODO: Test Raw bayer parameter settings and bayer capture | ||
33 | * Split module parameter structure to module specific ioctl structs | ||
34 | * investigate if enum used for user space type definition | ||
35 | * to be replaced by #defines or integer | ||
36 | */ | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | #include <linux/videodev2.h> | ||
40 | #include <media/davinci/dm644x_ccdc.h> | ||
41 | #include <media/davinci/vpss.h> | ||
42 | #include "dm644x_ccdc_regs.h" | ||
43 | #include "ccdc_hw_device.h" | ||
44 | |||
45 | MODULE_LICENSE("GPL"); | ||
46 | MODULE_DESCRIPTION("CCDC Driver for DM6446"); | ||
47 | MODULE_AUTHOR("Texas Instruments"); | ||
48 | |||
49 | static struct device *dev; | ||
50 | |||
51 | /* Object for CCDC raw mode */ | ||
52 | static struct ccdc_params_raw ccdc_hw_params_raw = { | ||
53 | .pix_fmt = CCDC_PIXFMT_RAW, | ||
54 | .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, | ||
55 | .win = CCDC_WIN_VGA, | ||
56 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
57 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
58 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
59 | .config_params = { | ||
60 | .data_sz = CCDC_DATA_10BITS, | ||
61 | }, | ||
62 | }; | ||
63 | |||
64 | /* Object for CCDC ycbcr mode */ | ||
65 | static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { | ||
66 | .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, | ||
67 | .frm_fmt = CCDC_FRMFMT_INTERLACED, | ||
68 | .win = CCDC_WIN_PAL, | ||
69 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
70 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
71 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
72 | .bt656_enable = 1, | ||
73 | .pix_order = CCDC_PIXORDER_CBYCRY, | ||
74 | .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED | ||
75 | }; | ||
76 | |||
77 | #define CCDC_MAX_RAW_YUV_FORMATS 2 | ||
78 | |||
79 | /* Raw Bayer formats */ | ||
80 | static u32 ccdc_raw_bayer_pix_formats[] = | ||
81 | {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; | ||
82 | |||
83 | /* Raw YUV formats */ | ||
84 | static u32 ccdc_raw_yuv_pix_formats[] = | ||
85 | {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; | ||
86 | |||
87 | static void *__iomem ccdc_base_addr; | ||
88 | static int ccdc_addr_size; | ||
89 | static enum vpfe_hw_if_type ccdc_if_type; | ||
90 | |||
91 | /* register access routines */ | ||
92 | static inline u32 regr(u32 offset) | ||
93 | { | ||
94 | return __raw_readl(ccdc_base_addr + offset); | ||
95 | } | ||
96 | |||
97 | static inline void regw(u32 val, u32 offset) | ||
98 | { | ||
99 | __raw_writel(val, ccdc_base_addr + offset); | ||
100 | } | ||
101 | |||
102 | static void ccdc_set_ccdc_base(void *addr, int size) | ||
103 | { | ||
104 | ccdc_base_addr = addr; | ||
105 | ccdc_addr_size = size; | ||
106 | } | ||
107 | |||
108 | static void ccdc_enable(int flag) | ||
109 | { | ||
110 | regw(flag, CCDC_PCR); | ||
111 | } | ||
112 | |||
113 | static void ccdc_enable_vport(int flag) | ||
114 | { | ||
115 | if (flag) | ||
116 | /* enable video port */ | ||
117 | regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); | ||
118 | else | ||
119 | regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * ccdc_setwin() | ||
124 | * This function will configure the window size | ||
125 | * to be capture in CCDC reg | ||
126 | */ | ||
127 | void ccdc_setwin(struct v4l2_rect *image_win, | ||
128 | enum ccdc_frmfmt frm_fmt, | ||
129 | int ppc) | ||
130 | { | ||
131 | int horz_start, horz_nr_pixels; | ||
132 | int vert_start, vert_nr_lines; | ||
133 | int val = 0, mid_img = 0; | ||
134 | |||
135 | dev_dbg(dev, "\nStarting ccdc_setwin..."); | ||
136 | /* | ||
137 | * ppc - per pixel count. indicates how many pixels per cell | ||
138 | * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. | ||
139 | * raw capture this is 1 | ||
140 | */ | ||
141 | horz_start = image_win->left << (ppc - 1); | ||
142 | horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; | ||
143 | regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, | ||
144 | CCDC_HORZ_INFO); | ||
145 | |||
146 | vert_start = image_win->top; | ||
147 | |||
148 | if (frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
149 | vert_nr_lines = (image_win->height >> 1) - 1; | ||
150 | vert_start >>= 1; | ||
151 | /* Since first line doesn't have any data */ | ||
152 | vert_start += 1; | ||
153 | /* configure VDINT0 */ | ||
154 | val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); | ||
155 | regw(val, CCDC_VDINT); | ||
156 | |||
157 | } else { | ||
158 | /* Since first line doesn't have any data */ | ||
159 | vert_start += 1; | ||
160 | vert_nr_lines = image_win->height - 1; | ||
161 | /* | ||
162 | * configure VDINT0 and VDINT1. VDINT1 will be at half | ||
163 | * of image height | ||
164 | */ | ||
165 | mid_img = vert_start + (image_win->height / 2); | ||
166 | val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | | ||
167 | (mid_img & CCDC_VDINT_VDINT1_MASK); | ||
168 | regw(val, CCDC_VDINT); | ||
169 | |||
170 | } | ||
171 | regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, | ||
172 | CCDC_VERT_START); | ||
173 | regw(vert_nr_lines, CCDC_VERT_LINES); | ||
174 | dev_dbg(dev, "\nEnd of ccdc_setwin..."); | ||
175 | } | ||
176 | |||
177 | static void ccdc_readregs(void) | ||
178 | { | ||
179 | unsigned int val = 0; | ||
180 | |||
181 | val = regr(CCDC_ALAW); | ||
182 | dev_notice(dev, "\nReading 0x%x to ALAW...\n", val); | ||
183 | val = regr(CCDC_CLAMP); | ||
184 | dev_notice(dev, "\nReading 0x%x to CLAMP...\n", val); | ||
185 | val = regr(CCDC_DCSUB); | ||
186 | dev_notice(dev, "\nReading 0x%x to DCSUB...\n", val); | ||
187 | val = regr(CCDC_BLKCMP); | ||
188 | dev_notice(dev, "\nReading 0x%x to BLKCMP...\n", val); | ||
189 | val = regr(CCDC_FPC_ADDR); | ||
190 | dev_notice(dev, "\nReading 0x%x to FPC_ADDR...\n", val); | ||
191 | val = regr(CCDC_FPC); | ||
192 | dev_notice(dev, "\nReading 0x%x to FPC...\n", val); | ||
193 | val = regr(CCDC_FMTCFG); | ||
194 | dev_notice(dev, "\nReading 0x%x to FMTCFG...\n", val); | ||
195 | val = regr(CCDC_COLPTN); | ||
196 | dev_notice(dev, "\nReading 0x%x to COLPTN...\n", val); | ||
197 | val = regr(CCDC_FMT_HORZ); | ||
198 | dev_notice(dev, "\nReading 0x%x to FMT_HORZ...\n", val); | ||
199 | val = regr(CCDC_FMT_VERT); | ||
200 | dev_notice(dev, "\nReading 0x%x to FMT_VERT...\n", val); | ||
201 | val = regr(CCDC_HSIZE_OFF); | ||
202 | dev_notice(dev, "\nReading 0x%x to HSIZE_OFF...\n", val); | ||
203 | val = regr(CCDC_SDOFST); | ||
204 | dev_notice(dev, "\nReading 0x%x to SDOFST...\n", val); | ||
205 | val = regr(CCDC_VP_OUT); | ||
206 | dev_notice(dev, "\nReading 0x%x to VP_OUT...\n", val); | ||
207 | val = regr(CCDC_SYN_MODE); | ||
208 | dev_notice(dev, "\nReading 0x%x to SYN_MODE...\n", val); | ||
209 | val = regr(CCDC_HORZ_INFO); | ||
210 | dev_notice(dev, "\nReading 0x%x to HORZ_INFO...\n", val); | ||
211 | val = regr(CCDC_VERT_START); | ||
212 | dev_notice(dev, "\nReading 0x%x to VERT_START...\n", val); | ||
213 | val = regr(CCDC_VERT_LINES); | ||
214 | dev_notice(dev, "\nReading 0x%x to VERT_LINES...\n", val); | ||
215 | } | ||
216 | |||
217 | static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) | ||
218 | { | ||
219 | if (ccdcparam->alaw.enable) { | ||
220 | if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || | ||
221 | (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || | ||
222 | (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { | ||
223 | dev_dbg(dev, "\nInvalid data line select"); | ||
224 | return -1; | ||
225 | } | ||
226 | } | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) | ||
231 | { | ||
232 | struct ccdc_config_params_raw *config_params = | ||
233 | &ccdc_hw_params_raw.config_params; | ||
234 | unsigned int *fpc_virtaddr = NULL; | ||
235 | unsigned int *fpc_physaddr = NULL; | ||
236 | |||
237 | memcpy(config_params, raw_params, sizeof(*raw_params)); | ||
238 | /* | ||
239 | * allocate memory for fault pixel table and copy the user | ||
240 | * values to the table | ||
241 | */ | ||
242 | if (!config_params->fault_pxl.enable) | ||
243 | return 0; | ||
244 | |||
245 | fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; | ||
246 | fpc_virtaddr = (unsigned int *)phys_to_virt( | ||
247 | (unsigned long)fpc_physaddr); | ||
248 | /* | ||
249 | * Allocate memory for FPC table if current | ||
250 | * FPC table buffer is not big enough to | ||
251 | * accomodate FPC Number requested | ||
252 | */ | ||
253 | if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) { | ||
254 | if (fpc_physaddr != NULL) { | ||
255 | free_pages((unsigned long)fpc_physaddr, | ||
256 | get_order | ||
257 | (config_params->fault_pxl.fp_num * | ||
258 | FP_NUM_BYTES)); | ||
259 | } | ||
260 | |||
261 | /* Allocate memory for FPC table */ | ||
262 | fpc_virtaddr = | ||
263 | (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA, | ||
264 | get_order(raw_params-> | ||
265 | fault_pxl.fp_num * | ||
266 | FP_NUM_BYTES)); | ||
267 | |||
268 | if (fpc_virtaddr == NULL) { | ||
269 | dev_dbg(dev, | ||
270 | "\nUnable to allocate memory for FPC"); | ||
271 | return -EFAULT; | ||
272 | } | ||
273 | fpc_physaddr = | ||
274 | (unsigned int *)virt_to_phys((void *)fpc_virtaddr); | ||
275 | } | ||
276 | |||
277 | /* Copy number of fault pixels and FPC table */ | ||
278 | config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num; | ||
279 | if (copy_from_user(fpc_virtaddr, | ||
280 | (void __user *)raw_params->fault_pxl.fpc_table_addr, | ||
281 | config_params->fault_pxl.fp_num * FP_NUM_BYTES)) { | ||
282 | dev_dbg(dev, "\n copy_from_user failed"); | ||
283 | return -EFAULT; | ||
284 | } | ||
285 | config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int ccdc_close(struct device *dev) | ||
290 | { | ||
291 | struct ccdc_config_params_raw *config_params = | ||
292 | &ccdc_hw_params_raw.config_params; | ||
293 | unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; | ||
294 | |||
295 | fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; | ||
296 | |||
297 | if (fpc_physaddr != NULL) { | ||
298 | fpc_virtaddr = (unsigned int *) | ||
299 | phys_to_virt((unsigned long)fpc_physaddr); | ||
300 | free_pages((unsigned long)fpc_virtaddr, | ||
301 | get_order(config_params->fault_pxl.fp_num * | ||
302 | FP_NUM_BYTES)); | ||
303 | } | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * ccdc_restore_defaults() | ||
309 | * This function will write defaults to all CCDC registers | ||
310 | */ | ||
311 | static void ccdc_restore_defaults(void) | ||
312 | { | ||
313 | int i; | ||
314 | |||
315 | /* disable CCDC */ | ||
316 | ccdc_enable(0); | ||
317 | /* set all registers to default value */ | ||
318 | for (i = 4; i <= 0x94; i += 4) | ||
319 | regw(0, i); | ||
320 | regw(CCDC_NO_CULLING, CCDC_CULLING); | ||
321 | regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); | ||
322 | } | ||
323 | |||
324 | static int ccdc_open(struct device *device) | ||
325 | { | ||
326 | dev = device; | ||
327 | ccdc_restore_defaults(); | ||
328 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
329 | ccdc_enable_vport(1); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static void ccdc_sbl_reset(void) | ||
334 | { | ||
335 | vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); | ||
336 | } | ||
337 | |||
338 | /* Parameter operations */ | ||
339 | static int ccdc_set_params(void __user *params) | ||
340 | { | ||
341 | struct ccdc_config_params_raw ccdc_raw_params; | ||
342 | int x; | ||
343 | |||
344 | if (ccdc_if_type != VPFE_RAW_BAYER) | ||
345 | return -EINVAL; | ||
346 | |||
347 | x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); | ||
348 | if (x) { | ||
349 | dev_dbg(dev, "ccdc_set_params: error in copying" | ||
350 | "ccdc params, %d\n", x); | ||
351 | return -EFAULT; | ||
352 | } | ||
353 | |||
354 | if (!validate_ccdc_param(&ccdc_raw_params)) { | ||
355 | if (!ccdc_update_raw_params(&ccdc_raw_params)) | ||
356 | return 0; | ||
357 | } | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * ccdc_config_ycbcr() | ||
363 | * This function will configure CCDC for YCbCr video capture | ||
364 | */ | ||
365 | void ccdc_config_ycbcr(void) | ||
366 | { | ||
367 | struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr; | ||
368 | u32 syn_mode; | ||
369 | |||
370 | dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); | ||
371 | /* | ||
372 | * first restore the CCDC registers to default values | ||
373 | * This is important since we assume default values to be set in | ||
374 | * a lot of registers that we didn't touch | ||
375 | */ | ||
376 | ccdc_restore_defaults(); | ||
377 | |||
378 | /* | ||
379 | * configure pixel format, frame format, configure video frame | ||
380 | * format, enable output to SDRAM, enable internal timing generator | ||
381 | * and 8bit pack mode | ||
382 | */ | ||
383 | syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << | ||
384 | CCDC_SYN_MODE_INPMOD_SHIFT) | | ||
385 | ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << | ||
386 | CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | | ||
387 | CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); | ||
388 | |||
389 | /* setup BT.656 sync mode */ | ||
390 | if (params->bt656_enable) { | ||
391 | regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); | ||
392 | |||
393 | /* | ||
394 | * configure the FID, VD, HD pin polarity, | ||
395 | * fld,hd pol positive, vd negative, 8-bit data | ||
396 | */ | ||
397 | syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE | CCDC_SYN_MODE_8BITS; | ||
398 | } else { | ||
399 | /* y/c external sync mode */ | ||
400 | syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << | ||
401 | CCDC_FID_POL_SHIFT) | | ||
402 | ((params->hd_pol & CCDC_HD_POL_MASK) << | ||
403 | CCDC_HD_POL_SHIFT) | | ||
404 | ((params->vd_pol & CCDC_VD_POL_MASK) << | ||
405 | CCDC_VD_POL_SHIFT)); | ||
406 | } | ||
407 | regw(syn_mode, CCDC_SYN_MODE); | ||
408 | |||
409 | /* configure video window */ | ||
410 | ccdc_setwin(¶ms->win, params->frm_fmt, 2); | ||
411 | |||
412 | /* | ||
413 | * configure the order of y cb cr in SDRAM, and disable latch | ||
414 | * internal register on vsync | ||
415 | */ | ||
416 | regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | | ||
417 | CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); | ||
418 | |||
419 | /* | ||
420 | * configure the horizontal line offset. This should be a | ||
421 | * on 32 byte bondary. So clear LSB 5 bits | ||
422 | */ | ||
423 | regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); | ||
424 | |||
425 | /* configure the memory line offset */ | ||
426 | if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) | ||
427 | /* two fields are interleaved in memory */ | ||
428 | regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); | ||
429 | |||
430 | ccdc_sbl_reset(); | ||
431 | dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); | ||
432 | ccdc_readregs(); | ||
433 | } | ||
434 | |||
435 | static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) | ||
436 | { | ||
437 | u32 val; | ||
438 | |||
439 | if (!bclamp->enable) { | ||
440 | /* configure DCSub */ | ||
441 | val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; | ||
442 | regw(val, CCDC_DCSUB); | ||
443 | dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val); | ||
444 | regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); | ||
445 | dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n"); | ||
446 | return; | ||
447 | } | ||
448 | /* | ||
449 | * Configure gain, Start pixel, No of line to be avg, | ||
450 | * No of pixel/line to be avg, & Enable the Black clamping | ||
451 | */ | ||
452 | val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | | ||
453 | ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << | ||
454 | CCDC_BLK_ST_PXL_SHIFT) | | ||
455 | ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << | ||
456 | CCDC_BLK_SAMPLE_LINE_SHIFT) | | ||
457 | ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << | ||
458 | CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); | ||
459 | regw(val, CCDC_CLAMP); | ||
460 | dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val); | ||
461 | /* If Black clamping is enable then make dcsub 0 */ | ||
462 | regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); | ||
463 | dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n"); | ||
464 | } | ||
465 | |||
466 | static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) | ||
467 | { | ||
468 | u32 val; | ||
469 | |||
470 | val = ((bcomp->b & CCDC_BLK_COMP_MASK) | | ||
471 | ((bcomp->gb & CCDC_BLK_COMP_MASK) << | ||
472 | CCDC_BLK_COMP_GB_COMP_SHIFT) | | ||
473 | ((bcomp->gr & CCDC_BLK_COMP_MASK) << | ||
474 | CCDC_BLK_COMP_GR_COMP_SHIFT) | | ||
475 | ((bcomp->r & CCDC_BLK_COMP_MASK) << | ||
476 | CCDC_BLK_COMP_R_COMP_SHIFT)); | ||
477 | regw(val, CCDC_BLKCMP); | ||
478 | } | ||
479 | |||
480 | static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) | ||
481 | { | ||
482 | u32 val; | ||
483 | |||
484 | /* Initially disable FPC */ | ||
485 | val = CCDC_FPC_DISABLE; | ||
486 | regw(val, CCDC_FPC); | ||
487 | |||
488 | if (!fpc->enable) | ||
489 | return; | ||
490 | |||
491 | /* Configure Fault pixel if needed */ | ||
492 | regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); | ||
493 | dev_dbg(dev, "\nWriting 0x%x to FPC_ADDR...\n", | ||
494 | (fpc->fpc_table_addr)); | ||
495 | /* Write the FPC params with FPC disable */ | ||
496 | val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; | ||
497 | regw(val, CCDC_FPC); | ||
498 | |||
499 | dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val); | ||
500 | /* read the FPC register */ | ||
501 | val = regr(CCDC_FPC) | CCDC_FPC_ENABLE; | ||
502 | regw(val, CCDC_FPC); | ||
503 | dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val); | ||
504 | } | ||
505 | |||
506 | /* | ||
507 | * ccdc_config_raw() | ||
508 | * This function will configure CCDC for Raw capture mode | ||
509 | */ | ||
510 | void ccdc_config_raw(void) | ||
511 | { | ||
512 | struct ccdc_params_raw *params = &ccdc_hw_params_raw; | ||
513 | struct ccdc_config_params_raw *config_params = | ||
514 | &ccdc_hw_params_raw.config_params; | ||
515 | unsigned int syn_mode = 0; | ||
516 | unsigned int val; | ||
517 | |||
518 | dev_dbg(dev, "\nStarting ccdc_config_raw..."); | ||
519 | |||
520 | /* Reset CCDC */ | ||
521 | ccdc_restore_defaults(); | ||
522 | |||
523 | /* Disable latching function registers on VSYNC */ | ||
524 | regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); | ||
525 | |||
526 | /* | ||
527 | * Configure the vertical sync polarity(SYN_MODE.VDPOL), | ||
528 | * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity | ||
529 | * (SYN_MODE.FLDPOL), frame format(progressive or interlace), | ||
530 | * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output | ||
531 | * SDRAM, enable internal timing generator | ||
532 | */ | ||
533 | syn_mode = | ||
534 | (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | | ||
535 | ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | | ||
536 | ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | | ||
537 | ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | | ||
538 | ((config_params->data_sz & CCDC_DATA_SZ_MASK) << | ||
539 | CCDC_DATA_SZ_SHIFT) | | ||
540 | ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | | ||
541 | CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); | ||
542 | |||
543 | /* Enable and configure aLaw register if needed */ | ||
544 | if (config_params->alaw.enable) { | ||
545 | val = ((config_params->alaw.gama_wd & | ||
546 | CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); | ||
547 | regw(val, CCDC_ALAW); | ||
548 | dev_dbg(dev, "\nWriting 0x%x to ALAW...\n", val); | ||
549 | } | ||
550 | |||
551 | /* Configure video window */ | ||
552 | ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); | ||
553 | |||
554 | /* Configure Black Clamp */ | ||
555 | ccdc_config_black_clamp(&config_params->blk_clamp); | ||
556 | |||
557 | /* Configure Black level compensation */ | ||
558 | ccdc_config_black_compense(&config_params->blk_comp); | ||
559 | |||
560 | /* Configure Fault Pixel Correction */ | ||
561 | ccdc_config_fpc(&config_params->fault_pxl); | ||
562 | |||
563 | /* If data size is 8 bit then pack the data */ | ||
564 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
565 | config_params->alaw.enable) | ||
566 | syn_mode |= CCDC_DATA_PACK_ENABLE; | ||
567 | |||
568 | #ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE | ||
569 | /* enable video port */ | ||
570 | val = CCDC_ENABLE_VIDEO_PORT; | ||
571 | #else | ||
572 | /* disable video port */ | ||
573 | val = CCDC_DISABLE_VIDEO_PORT; | ||
574 | #endif | ||
575 | |||
576 | if (config_params->data_sz == CCDC_DATA_8BITS) | ||
577 | val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) | ||
578 | << CCDC_FMTCFG_VPIN_SHIFT; | ||
579 | else | ||
580 | val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) | ||
581 | << CCDC_FMTCFG_VPIN_SHIFT; | ||
582 | /* Write value in FMTCFG */ | ||
583 | regw(val, CCDC_FMTCFG); | ||
584 | |||
585 | dev_dbg(dev, "\nWriting 0x%x to FMTCFG...\n", val); | ||
586 | /* Configure the color pattern according to mt9t001 sensor */ | ||
587 | regw(CCDC_COLPTN_VAL, CCDC_COLPTN); | ||
588 | |||
589 | dev_dbg(dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); | ||
590 | /* | ||
591 | * Configure Data formatter(Video port) pixel selection | ||
592 | * (FMT_HORZ, FMT_VERT) | ||
593 | */ | ||
594 | val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << | ||
595 | CCDC_FMT_HORZ_FMTSPH_SHIFT) | | ||
596 | (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); | ||
597 | regw(val, CCDC_FMT_HORZ); | ||
598 | |||
599 | dev_dbg(dev, "\nWriting 0x%x to FMT_HORZ...\n", val); | ||
600 | val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) | ||
601 | << CCDC_FMT_VERT_FMTSLV_SHIFT; | ||
602 | if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) | ||
603 | val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; | ||
604 | else | ||
605 | val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; | ||
606 | |||
607 | dev_dbg(dev, "\nparams->win.height 0x%x ...\n", | ||
608 | params->win.height); | ||
609 | regw(val, CCDC_FMT_VERT); | ||
610 | |||
611 | dev_dbg(dev, "\nWriting 0x%x to FMT_VERT...\n", val); | ||
612 | |||
613 | dev_dbg(dev, "\nbelow regw(val, FMT_VERT)..."); | ||
614 | |||
615 | /* | ||
616 | * Configure Horizontal offset register. If pack 8 is enabled then | ||
617 | * 1 pixel will take 1 byte | ||
618 | */ | ||
619 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
620 | config_params->alaw.enable) | ||
621 | regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & | ||
622 | CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); | ||
623 | else | ||
624 | /* else one pixel will take 2 byte */ | ||
625 | regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + | ||
626 | CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, | ||
627 | CCDC_HSIZE_OFF); | ||
628 | |||
629 | /* Set value for SDOFST */ | ||
630 | if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
631 | if (params->image_invert_enable) { | ||
632 | /* For intelace inverse mode */ | ||
633 | regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); | ||
634 | dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n"); | ||
635 | } | ||
636 | |||
637 | else { | ||
638 | /* For intelace non inverse mode */ | ||
639 | regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); | ||
640 | dev_dbg(dev, "\nWriting 0x0249 to SDOFST...\n"); | ||
641 | } | ||
642 | } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { | ||
643 | regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); | ||
644 | dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n"); | ||
645 | } | ||
646 | |||
647 | /* | ||
648 | * Configure video port pixel selection (VPOUT) | ||
649 | * Here -1 is to make the height value less than FMT_VERT.FMTLNV | ||
650 | */ | ||
651 | if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) | ||
652 | val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) | ||
653 | << CCDC_VP_OUT_VERT_NUM_SHIFT; | ||
654 | else | ||
655 | val = | ||
656 | ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) - | ||
657 | 1) & CCDC_VP_OUT_VERT_NUM_MASK)) << | ||
658 | CCDC_VP_OUT_VERT_NUM_SHIFT; | ||
659 | |||
660 | val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) | ||
661 | << CCDC_VP_OUT_HORZ_NUM_SHIFT; | ||
662 | val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; | ||
663 | regw(val, CCDC_VP_OUT); | ||
664 | |||
665 | dev_dbg(dev, "\nWriting 0x%x to VP_OUT...\n", val); | ||
666 | regw(syn_mode, CCDC_SYN_MODE); | ||
667 | dev_dbg(dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); | ||
668 | |||
669 | ccdc_sbl_reset(); | ||
670 | dev_dbg(dev, "\nend of ccdc_config_raw..."); | ||
671 | ccdc_readregs(); | ||
672 | } | ||
673 | |||
674 | static int ccdc_configure(void) | ||
675 | { | ||
676 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
677 | ccdc_config_raw(); | ||
678 | else | ||
679 | ccdc_config_ycbcr(); | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static int ccdc_set_buftype(enum ccdc_buftype buf_type) | ||
684 | { | ||
685 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
686 | ccdc_hw_params_raw.buf_type = buf_type; | ||
687 | else | ||
688 | ccdc_hw_params_ycbcr.buf_type = buf_type; | ||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static enum ccdc_buftype ccdc_get_buftype(void) | ||
693 | { | ||
694 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
695 | return ccdc_hw_params_raw.buf_type; | ||
696 | return ccdc_hw_params_ycbcr.buf_type; | ||
697 | } | ||
698 | |||
699 | static int ccdc_enum_pix(u32 *pix, int i) | ||
700 | { | ||
701 | int ret = -EINVAL; | ||
702 | if (ccdc_if_type == VPFE_RAW_BAYER) { | ||
703 | if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { | ||
704 | *pix = ccdc_raw_bayer_pix_formats[i]; | ||
705 | ret = 0; | ||
706 | } | ||
707 | } else { | ||
708 | if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { | ||
709 | *pix = ccdc_raw_yuv_pix_formats[i]; | ||
710 | ret = 0; | ||
711 | } | ||
712 | } | ||
713 | return ret; | ||
714 | } | ||
715 | |||
716 | static int ccdc_set_pixel_format(u32 pixfmt) | ||
717 | { | ||
718 | if (ccdc_if_type == VPFE_RAW_BAYER) { | ||
719 | ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW; | ||
720 | if (pixfmt == V4L2_PIX_FMT_SBGGR8) | ||
721 | ccdc_hw_params_raw.config_params.alaw.enable = 1; | ||
722 | else if (pixfmt != V4L2_PIX_FMT_SBGGR16) | ||
723 | return -EINVAL; | ||
724 | } else { | ||
725 | if (pixfmt == V4L2_PIX_FMT_YUYV) | ||
726 | ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; | ||
727 | else if (pixfmt == V4L2_PIX_FMT_UYVY) | ||
728 | ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; | ||
729 | else | ||
730 | return -EINVAL; | ||
731 | } | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static u32 ccdc_get_pixel_format(void) | ||
736 | { | ||
737 | struct ccdc_a_law *alaw = | ||
738 | &ccdc_hw_params_raw.config_params.alaw; | ||
739 | u32 pixfmt; | ||
740 | |||
741 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
742 | if (alaw->enable) | ||
743 | pixfmt = V4L2_PIX_FMT_SBGGR8; | ||
744 | else | ||
745 | pixfmt = V4L2_PIX_FMT_SBGGR16; | ||
746 | else { | ||
747 | if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) | ||
748 | pixfmt = V4L2_PIX_FMT_YUYV; | ||
749 | else | ||
750 | pixfmt = V4L2_PIX_FMT_UYVY; | ||
751 | } | ||
752 | return pixfmt; | ||
753 | } | ||
754 | |||
755 | static int ccdc_set_image_window(struct v4l2_rect *win) | ||
756 | { | ||
757 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
758 | ccdc_hw_params_raw.win = *win; | ||
759 | else | ||
760 | ccdc_hw_params_ycbcr.win = *win; | ||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | static void ccdc_get_image_window(struct v4l2_rect *win) | ||
765 | { | ||
766 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
767 | *win = ccdc_hw_params_raw.win; | ||
768 | else | ||
769 | *win = ccdc_hw_params_ycbcr.win; | ||
770 | } | ||
771 | |||
772 | static unsigned int ccdc_get_line_length(void) | ||
773 | { | ||
774 | struct ccdc_config_params_raw *config_params = | ||
775 | &ccdc_hw_params_raw.config_params; | ||
776 | unsigned int len; | ||
777 | |||
778 | if (ccdc_if_type == VPFE_RAW_BAYER) { | ||
779 | if ((config_params->alaw.enable) || | ||
780 | (config_params->data_sz == CCDC_DATA_8BITS)) | ||
781 | len = ccdc_hw_params_raw.win.width; | ||
782 | else | ||
783 | len = ccdc_hw_params_raw.win.width * 2; | ||
784 | } else | ||
785 | len = ccdc_hw_params_ycbcr.win.width * 2; | ||
786 | return ALIGN(len, 32); | ||
787 | } | ||
788 | |||
789 | static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) | ||
790 | { | ||
791 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
792 | ccdc_hw_params_raw.frm_fmt = frm_fmt; | ||
793 | else | ||
794 | ccdc_hw_params_ycbcr.frm_fmt = frm_fmt; | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | static enum ccdc_frmfmt ccdc_get_frame_format(void) | ||
799 | { | ||
800 | if (ccdc_if_type == VPFE_RAW_BAYER) | ||
801 | return ccdc_hw_params_raw.frm_fmt; | ||
802 | else | ||
803 | return ccdc_hw_params_ycbcr.frm_fmt; | ||
804 | } | ||
805 | |||
806 | static int ccdc_getfid(void) | ||
807 | { | ||
808 | return (regr(CCDC_SYN_MODE) >> 15) & 1; | ||
809 | } | ||
810 | |||
811 | /* misc operations */ | ||
812 | static inline void ccdc_setfbaddr(unsigned long addr) | ||
813 | { | ||
814 | regw(addr & 0xffffffe0, CCDC_SDR_ADDR); | ||
815 | } | ||
816 | |||
817 | static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) | ||
818 | { | ||
819 | ccdc_if_type = params->if_type; | ||
820 | |||
821 | switch (params->if_type) { | ||
822 | case VPFE_BT656: | ||
823 | case VPFE_YCBCR_SYNC_16: | ||
824 | case VPFE_YCBCR_SYNC_8: | ||
825 | ccdc_hw_params_ycbcr.vd_pol = params->vdpol; | ||
826 | ccdc_hw_params_ycbcr.hd_pol = params->hdpol; | ||
827 | break; | ||
828 | default: | ||
829 | /* TODO add support for raw bayer here */ | ||
830 | return -EINVAL; | ||
831 | } | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static struct ccdc_hw_device ccdc_hw_dev = { | ||
836 | .name = "DM6446 CCDC", | ||
837 | .owner = THIS_MODULE, | ||
838 | .hw_ops = { | ||
839 | .open = ccdc_open, | ||
840 | .close = ccdc_close, | ||
841 | .set_ccdc_base = ccdc_set_ccdc_base, | ||
842 | .reset = ccdc_sbl_reset, | ||
843 | .enable = ccdc_enable, | ||
844 | .set_hw_if_params = ccdc_set_hw_if_params, | ||
845 | .set_params = ccdc_set_params, | ||
846 | .configure = ccdc_configure, | ||
847 | .set_buftype = ccdc_set_buftype, | ||
848 | .get_buftype = ccdc_get_buftype, | ||
849 | .enum_pix = ccdc_enum_pix, | ||
850 | .set_pixel_format = ccdc_set_pixel_format, | ||
851 | .get_pixel_format = ccdc_get_pixel_format, | ||
852 | .set_frame_format = ccdc_set_frame_format, | ||
853 | .get_frame_format = ccdc_get_frame_format, | ||
854 | .set_image_window = ccdc_set_image_window, | ||
855 | .get_image_window = ccdc_get_image_window, | ||
856 | .get_line_length = ccdc_get_line_length, | ||
857 | .setfbaddr = ccdc_setfbaddr, | ||
858 | .getfid = ccdc_getfid, | ||
859 | }, | ||
860 | }; | ||
861 | |||
862 | static int dm644x_ccdc_init(void) | ||
863 | { | ||
864 | printk(KERN_NOTICE "dm644x_ccdc_init\n"); | ||
865 | if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) | ||
866 | return -1; | ||
867 | printk(KERN_NOTICE "%s is registered with vpfe.\n", | ||
868 | ccdc_hw_dev.name); | ||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | static void dm644x_ccdc_exit(void) | ||
873 | { | ||
874 | vpfe_unregister_ccdc_device(&ccdc_hw_dev); | ||
875 | } | ||
876 | |||
877 | module_init(dm644x_ccdc_init); | ||
878 | module_exit(dm644x_ccdc_exit); | ||
diff --git a/drivers/media/video/davinci/dm644x_ccdc_regs.h b/drivers/media/video/davinci/dm644x_ccdc_regs.h new file mode 100644 index 000000000000..6e5d05324466 --- /dev/null +++ b/drivers/media/video/davinci/dm644x_ccdc_regs.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2009 Texas Instruments Inc | ||
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 | #ifndef _DM644X_CCDC_REGS_H | ||
19 | #define _DM644X_CCDC_REGS_H | ||
20 | |||
21 | /**************************************************************************\ | ||
22 | * Register OFFSET Definitions | ||
23 | \**************************************************************************/ | ||
24 | #define CCDC_PID 0x0 | ||
25 | #define CCDC_PCR 0x4 | ||
26 | #define CCDC_SYN_MODE 0x8 | ||
27 | #define CCDC_HD_VD_WID 0xc | ||
28 | #define CCDC_PIX_LINES 0x10 | ||
29 | #define CCDC_HORZ_INFO 0x14 | ||
30 | #define CCDC_VERT_START 0x18 | ||
31 | #define CCDC_VERT_LINES 0x1c | ||
32 | #define CCDC_CULLING 0x20 | ||
33 | #define CCDC_HSIZE_OFF 0x24 | ||
34 | #define CCDC_SDOFST 0x28 | ||
35 | #define CCDC_SDR_ADDR 0x2c | ||
36 | #define CCDC_CLAMP 0x30 | ||
37 | #define CCDC_DCSUB 0x34 | ||
38 | #define CCDC_COLPTN 0x38 | ||
39 | #define CCDC_BLKCMP 0x3c | ||
40 | #define CCDC_FPC 0x40 | ||
41 | #define CCDC_FPC_ADDR 0x44 | ||
42 | #define CCDC_VDINT 0x48 | ||
43 | #define CCDC_ALAW 0x4c | ||
44 | #define CCDC_REC656IF 0x50 | ||
45 | #define CCDC_CCDCFG 0x54 | ||
46 | #define CCDC_FMTCFG 0x58 | ||
47 | #define CCDC_FMT_HORZ 0x5c | ||
48 | #define CCDC_FMT_VERT 0x60 | ||
49 | #define CCDC_FMT_ADDR0 0x64 | ||
50 | #define CCDC_FMT_ADDR1 0x68 | ||
51 | #define CCDC_FMT_ADDR2 0x6c | ||
52 | #define CCDC_FMT_ADDR3 0x70 | ||
53 | #define CCDC_FMT_ADDR4 0x74 | ||
54 | #define CCDC_FMT_ADDR5 0x78 | ||
55 | #define CCDC_FMT_ADDR6 0x7c | ||
56 | #define CCDC_FMT_ADDR7 0x80 | ||
57 | #define CCDC_PRGEVEN_0 0x84 | ||
58 | #define CCDC_PRGEVEN_1 0x88 | ||
59 | #define CCDC_PRGODD_0 0x8c | ||
60 | #define CCDC_PRGODD_1 0x90 | ||
61 | #define CCDC_VP_OUT 0x94 | ||
62 | |||
63 | |||
64 | /*************************************************************** | ||
65 | * Define for various register bit mask and shifts for CCDC | ||
66 | ****************************************************************/ | ||
67 | #define CCDC_FID_POL_MASK 1 | ||
68 | #define CCDC_FID_POL_SHIFT 4 | ||
69 | #define CCDC_HD_POL_MASK 1 | ||
70 | #define CCDC_HD_POL_SHIFT 3 | ||
71 | #define CCDC_VD_POL_MASK 1 | ||
72 | #define CCDC_VD_POL_SHIFT 2 | ||
73 | #define CCDC_HSIZE_OFF_MASK 0xffffffe0 | ||
74 | #define CCDC_32BYTE_ALIGN_VAL 31 | ||
75 | #define CCDC_FRM_FMT_MASK 0x1 | ||
76 | #define CCDC_FRM_FMT_SHIFT 7 | ||
77 | #define CCDC_DATA_SZ_MASK 7 | ||
78 | #define CCDC_DATA_SZ_SHIFT 8 | ||
79 | #define CCDC_PIX_FMT_MASK 3 | ||
80 | #define CCDC_PIX_FMT_SHIFT 12 | ||
81 | #define CCDC_VP2SDR_DISABLE 0xFFFBFFFF | ||
82 | #define CCDC_WEN_ENABLE (1 << 17) | ||
83 | #define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF | ||
84 | #define CCDC_VDHDEN_ENABLE (1 << 16) | ||
85 | #define CCDC_LPF_ENABLE (1 << 14) | ||
86 | #define CCDC_ALAW_ENABLE (1 << 3) | ||
87 | #define CCDC_ALAW_GAMA_WD_MASK 7 | ||
88 | #define CCDC_BLK_CLAMP_ENABLE (1 << 31) | ||
89 | #define CCDC_BLK_SGAIN_MASK 0x1F | ||
90 | #define CCDC_BLK_ST_PXL_MASK 0x7FFF | ||
91 | #define CCDC_BLK_ST_PXL_SHIFT 10 | ||
92 | #define CCDC_BLK_SAMPLE_LN_MASK 7 | ||
93 | #define CCDC_BLK_SAMPLE_LN_SHIFT 28 | ||
94 | #define CCDC_BLK_SAMPLE_LINE_MASK 7 | ||
95 | #define CCDC_BLK_SAMPLE_LINE_SHIFT 25 | ||
96 | #define CCDC_BLK_DC_SUB_MASK 0x03FFF | ||
97 | #define CCDC_BLK_COMP_MASK 0xFF | ||
98 | #define CCDC_BLK_COMP_GB_COMP_SHIFT 8 | ||
99 | #define CCDC_BLK_COMP_GR_COMP_SHIFT 16 | ||
100 | #define CCDC_BLK_COMP_R_COMP_SHIFT 24 | ||
101 | #define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) | ||
102 | #define CCDC_FPC_ENABLE (1 << 15) | ||
103 | #define CCDC_FPC_DISABLE 0 | ||
104 | #define CCDC_FPC_FPC_NUM_MASK 0x7FFF | ||
105 | #define CCDC_DATA_PACK_ENABLE (1 << 11) | ||
106 | #define CCDC_FMTCFG_VPIN_MASK 7 | ||
107 | #define CCDC_FMTCFG_VPIN_SHIFT 12 | ||
108 | #define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF | ||
109 | #define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF | ||
110 | #define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 | ||
111 | #define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF | ||
112 | #define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF | ||
113 | #define CCDC_FMT_VERT_FMTSLV_SHIFT 16 | ||
114 | #define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF | ||
115 | #define CCDC_VP_OUT_VERT_NUM_SHIFT 17 | ||
116 | #define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF | ||
117 | #define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 | ||
118 | #define CCDC_VP_OUT_HORZ_ST_MASK 0xF | ||
119 | #define CCDC_HORZ_INFO_SPH_SHIFT 16 | ||
120 | #define CCDC_VERT_START_SLV0_SHIFT 16 | ||
121 | #define CCDC_VDINT_VDINT0_SHIFT 16 | ||
122 | #define CCDC_VDINT_VDINT1_MASK 0xFFFF | ||
123 | #define CCDC_PPC_RAW 1 | ||
124 | #define CCDC_DCSUB_DEFAULT_VAL 0 | ||
125 | #define CCDC_CLAMP_DEFAULT_VAL 0 | ||
126 | #define CCDC_ENABLE_VIDEO_PORT 0x8000 | ||
127 | #define CCDC_DISABLE_VIDEO_PORT 0 | ||
128 | #define CCDC_COLPTN_VAL 0xBB11BB11 | ||
129 | #define CCDC_TWO_BYTES_PER_PIXEL 2 | ||
130 | #define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D | ||
131 | #define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 | ||
132 | #define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 | ||
133 | #define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 | ||
134 | #define CCDC_INTERLACED_HEIGHT_SHIFT 1 | ||
135 | #define CCDC_SYN_MODE_INPMOD_SHIFT 12 | ||
136 | #define CCDC_SYN_MODE_INPMOD_MASK 3 | ||
137 | #define CCDC_SYN_MODE_8BITS (7 << 8) | ||
138 | #define CCDC_SYN_FLDMODE_MASK 1 | ||
139 | #define CCDC_SYN_FLDMODE_SHIFT 7 | ||
140 | #define CCDC_REC656IF_BT656_EN 3 | ||
141 | #define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) | ||
142 | #define CCDC_CCDCFG_Y8POS_SHIFT 11 | ||
143 | #define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 | ||
144 | #define CCDC_NO_CULLING 0xffff00ff | ||
145 | #endif | ||
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c new file mode 100644 index 000000000000..402ce43ef38e --- /dev/null +++ b/drivers/media/video/davinci/vpfe_capture.c | |||
@@ -0,0 +1,2124 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Texas Instruments Inc | ||
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 | * Driver name : VPFE Capture driver | ||
19 | * VPFE Capture driver allows applications to capture and stream video | ||
20 | * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as | ||
21 | * TVP5146 or Raw Bayer RGB image data from an image sensor | ||
22 | * such as Microns' MT9T001, MT9T031 etc. | ||
23 | * | ||
24 | * These SoCs have, in common, a Video Processing Subsystem (VPSS) that | ||
25 | * consists of a Video Processing Front End (VPFE) for capturing | ||
26 | * video/raw image data and Video Processing Back End (VPBE) for displaying | ||
27 | * YUV data through an in-built analog encoder or Digital LCD port. This | ||
28 | * driver is for capture through VPFE. A typical EVM using these SoCs have | ||
29 | * following high level configuration. | ||
30 | * | ||
31 | * | ||
32 | * decoder(TVP5146/ YUV/ | ||
33 | * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) | ||
34 | * data input | | | ||
35 | * V | | ||
36 | * SDRAM | | ||
37 | * V | ||
38 | * Image Processor | ||
39 | * | | ||
40 | * V | ||
41 | * SDRAM | ||
42 | * The data flow happens from a decoder connected to the VPFE over a | ||
43 | * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface | ||
44 | * and to the input of VPFE through an optional MUX (if more inputs are | ||
45 | * to be interfaced on the EVM). The input data is first passed through | ||
46 | * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC | ||
47 | * does very little or no processing on YUV data and does pre-process Raw | ||
48 | * Bayer RGB data through modules such as Defect Pixel Correction (DFC) | ||
49 | * Color Space Conversion (CSC), data gain/offset etc. After this, data | ||
50 | * can be written to SDRAM or can be connected to the image processing | ||
51 | * block such as IPIPE (on DM355 only). | ||
52 | * | ||
53 | * Features supported | ||
54 | * - MMAP IO | ||
55 | * - Capture using TVP5146 over BT.656 | ||
56 | * - support for interfacing decoders using sub device model | ||
57 | * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV | ||
58 | * data capture to SDRAM. | ||
59 | * TODO list | ||
60 | * - Support multiple REQBUF after open | ||
61 | * - Support for de-allocating buffers through REQBUF | ||
62 | * - Support for Raw Bayer RGB capture | ||
63 | * - Support for chaining Image Processor | ||
64 | * - Support for static allocation of buffers | ||
65 | * - Support for USERPTR IO | ||
66 | * - Support for STREAMON before QBUF | ||
67 | * - Support for control ioctls | ||
68 | */ | ||
69 | #include <linux/module.h> | ||
70 | #include <linux/init.h> | ||
71 | #include <linux/platform_device.h> | ||
72 | #include <linux/interrupt.h> | ||
73 | #include <linux/version.h> | ||
74 | #include <media/v4l2-common.h> | ||
75 | #include <linux/io.h> | ||
76 | #include <media/davinci/vpfe_capture.h> | ||
77 | #include "ccdc_hw_device.h" | ||
78 | |||
79 | static int debug; | ||
80 | static u32 numbuffers = 3; | ||
81 | static u32 bufsize = (720 * 576 * 2); | ||
82 | |||
83 | module_param(numbuffers, uint, S_IRUGO); | ||
84 | module_param(bufsize, uint, S_IRUGO); | ||
85 | module_param(debug, int, 0644); | ||
86 | |||
87 | MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); | ||
88 | MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); | ||
89 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
90 | |||
91 | MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); | ||
92 | MODULE_LICENSE("GPL"); | ||
93 | MODULE_AUTHOR("Texas Instruments"); | ||
94 | |||
95 | /* standard information */ | ||
96 | struct vpfe_standard { | ||
97 | v4l2_std_id std_id; | ||
98 | unsigned int width; | ||
99 | unsigned int height; | ||
100 | struct v4l2_fract pixelaspect; | ||
101 | /* 0 - progressive, 1 - interlaced */ | ||
102 | int frame_format; | ||
103 | }; | ||
104 | |||
105 | /* ccdc configuration */ | ||
106 | struct ccdc_config { | ||
107 | /* This make sure vpfe is probed and ready to go */ | ||
108 | int vpfe_probed; | ||
109 | /* name of ccdc device */ | ||
110 | char name[32]; | ||
111 | /* for storing mem maps for CCDC */ | ||
112 | int ccdc_addr_size; | ||
113 | void *__iomem ccdc_addr; | ||
114 | }; | ||
115 | |||
116 | /* data structures */ | ||
117 | static struct vpfe_config_params config_params = { | ||
118 | .min_numbuffers = 3, | ||
119 | .numbuffers = 3, | ||
120 | .min_bufsize = 720 * 480 * 2, | ||
121 | .device_bufsize = 720 * 576 * 2, | ||
122 | }; | ||
123 | |||
124 | /* ccdc device registered */ | ||
125 | static struct ccdc_hw_device *ccdc_dev; | ||
126 | /* lock for accessing ccdc information */ | ||
127 | static DEFINE_MUTEX(ccdc_lock); | ||
128 | /* ccdc configuration */ | ||
129 | static struct ccdc_config *ccdc_cfg; | ||
130 | |||
131 | const struct vpfe_standard vpfe_standards[] = { | ||
132 | {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, | ||
133 | {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, | ||
134 | }; | ||
135 | |||
136 | /* Used when raw Bayer image from ccdc is directly captured to SDRAM */ | ||
137 | static const struct vpfe_pixel_format vpfe_pix_fmts[] = { | ||
138 | { | ||
139 | .fmtdesc = { | ||
140 | .index = 0, | ||
141 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
142 | .description = "Bayer GrRBGb 8bit A-Law compr.", | ||
143 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
144 | }, | ||
145 | .bpp = 1, | ||
146 | }, | ||
147 | { | ||
148 | .fmtdesc = { | ||
149 | .index = 1, | ||
150 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
151 | .description = "Bayer GrRBGb - 16bit", | ||
152 | .pixelformat = V4L2_PIX_FMT_SBGGR16, | ||
153 | }, | ||
154 | .bpp = 2, | ||
155 | }, | ||
156 | { | ||
157 | .fmtdesc = { | ||
158 | .index = 2, | ||
159 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
160 | .description = "Bayer GrRBGb 8bit DPCM compr.", | ||
161 | .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, | ||
162 | }, | ||
163 | .bpp = 1, | ||
164 | }, | ||
165 | { | ||
166 | .fmtdesc = { | ||
167 | .index = 3, | ||
168 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
169 | .description = "YCbCr 4:2:2 Interleaved UYVY", | ||
170 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
171 | }, | ||
172 | .bpp = 2, | ||
173 | }, | ||
174 | { | ||
175 | .fmtdesc = { | ||
176 | .index = 4, | ||
177 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
178 | .description = "YCbCr 4:2:2 Interleaved YUYV", | ||
179 | .pixelformat = V4L2_PIX_FMT_YUYV, | ||
180 | }, | ||
181 | .bpp = 2, | ||
182 | }, | ||
183 | { | ||
184 | .fmtdesc = { | ||
185 | .index = 5, | ||
186 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
187 | .description = "Y/CbCr 4:2:0 - Semi planar", | ||
188 | .pixelformat = V4L2_PIX_FMT_NV12, | ||
189 | }, | ||
190 | .bpp = 1, | ||
191 | }, | ||
192 | }; | ||
193 | |||
194 | /* | ||
195 | * vpfe_lookup_pix_format() | ||
196 | * lookup an entry in the vpfe pix format table based on pix_format | ||
197 | */ | ||
198 | static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) | ||
199 | { | ||
200 | int i; | ||
201 | |||
202 | for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { | ||
203 | if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) | ||
204 | return &vpfe_pix_fmts[i]; | ||
205 | } | ||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * vpfe_register_ccdc_device. CCDC module calls this to | ||
211 | * register with vpfe capture | ||
212 | */ | ||
213 | int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) | ||
214 | { | ||
215 | int ret = 0; | ||
216 | printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); | ||
217 | |||
218 | BUG_ON(!dev->hw_ops.open); | ||
219 | BUG_ON(!dev->hw_ops.enable); | ||
220 | BUG_ON(!dev->hw_ops.set_hw_if_params); | ||
221 | BUG_ON(!dev->hw_ops.configure); | ||
222 | BUG_ON(!dev->hw_ops.set_buftype); | ||
223 | BUG_ON(!dev->hw_ops.get_buftype); | ||
224 | BUG_ON(!dev->hw_ops.enum_pix); | ||
225 | BUG_ON(!dev->hw_ops.set_frame_format); | ||
226 | BUG_ON(!dev->hw_ops.get_frame_format); | ||
227 | BUG_ON(!dev->hw_ops.get_pixel_format); | ||
228 | BUG_ON(!dev->hw_ops.set_pixel_format); | ||
229 | BUG_ON(!dev->hw_ops.set_params); | ||
230 | BUG_ON(!dev->hw_ops.set_image_window); | ||
231 | BUG_ON(!dev->hw_ops.get_image_window); | ||
232 | BUG_ON(!dev->hw_ops.get_line_length); | ||
233 | BUG_ON(!dev->hw_ops.setfbaddr); | ||
234 | BUG_ON(!dev->hw_ops.getfid); | ||
235 | |||
236 | mutex_lock(&ccdc_lock); | ||
237 | if (NULL == ccdc_cfg) { | ||
238 | /* | ||
239 | * TODO. Will this ever happen? if so, we need to fix it. | ||
240 | * Proabably we need to add the request to a linked list and | ||
241 | * walk through it during vpfe probe | ||
242 | */ | ||
243 | printk(KERN_ERR "vpfe capture not initialized\n"); | ||
244 | ret = -1; | ||
245 | goto unlock; | ||
246 | } | ||
247 | |||
248 | if (strcmp(dev->name, ccdc_cfg->name)) { | ||
249 | /* ignore this ccdc */ | ||
250 | ret = -1; | ||
251 | goto unlock; | ||
252 | } | ||
253 | |||
254 | if (ccdc_dev) { | ||
255 | printk(KERN_ERR "ccdc already registered\n"); | ||
256 | ret = -1; | ||
257 | goto unlock; | ||
258 | } | ||
259 | |||
260 | ccdc_dev = dev; | ||
261 | dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr, | ||
262 | ccdc_cfg->ccdc_addr_size); | ||
263 | unlock: | ||
264 | mutex_unlock(&ccdc_lock); | ||
265 | return ret; | ||
266 | } | ||
267 | EXPORT_SYMBOL(vpfe_register_ccdc_device); | ||
268 | |||
269 | /* | ||
270 | * vpfe_unregister_ccdc_device. CCDC module calls this to | ||
271 | * unregister with vpfe capture | ||
272 | */ | ||
273 | void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) | ||
274 | { | ||
275 | if (NULL == dev) { | ||
276 | printk(KERN_ERR "invalid ccdc device ptr\n"); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", | ||
281 | dev->name); | ||
282 | |||
283 | if (strcmp(dev->name, ccdc_cfg->name)) { | ||
284 | /* ignore this ccdc */ | ||
285 | return; | ||
286 | } | ||
287 | |||
288 | mutex_lock(&ccdc_lock); | ||
289 | ccdc_dev = NULL; | ||
290 | mutex_unlock(&ccdc_lock); | ||
291 | return; | ||
292 | } | ||
293 | EXPORT_SYMBOL(vpfe_unregister_ccdc_device); | ||
294 | |||
295 | /* | ||
296 | * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings | ||
297 | */ | ||
298 | static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, | ||
299 | struct v4l2_format *f) | ||
300 | { | ||
301 | struct v4l2_rect image_win; | ||
302 | enum ccdc_buftype buf_type; | ||
303 | enum ccdc_frmfmt frm_fmt; | ||
304 | |||
305 | memset(f, 0, sizeof(*f)); | ||
306 | f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
307 | ccdc_dev->hw_ops.get_image_window(&image_win); | ||
308 | f->fmt.pix.width = image_win.width; | ||
309 | f->fmt.pix.height = image_win.height; | ||
310 | f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); | ||
311 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * | ||
312 | f->fmt.pix.height; | ||
313 | buf_type = ccdc_dev->hw_ops.get_buftype(); | ||
314 | f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format(); | ||
315 | frm_fmt = ccdc_dev->hw_ops.get_frame_format(); | ||
316 | if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) | ||
317 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
318 | else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
319 | if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) | ||
320 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
321 | else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) | ||
322 | f->fmt.pix.field = V4L2_FIELD_SEQ_TB; | ||
323 | else { | ||
324 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n"); | ||
325 | return -EINVAL; | ||
326 | } | ||
327 | } else { | ||
328 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n"); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * vpfe_config_ccdc_image_format() | ||
336 | * For a pix format, configure ccdc to setup the capture | ||
337 | */ | ||
338 | static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) | ||
339 | { | ||
340 | enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; | ||
341 | int ret = 0; | ||
342 | |||
343 | if (ccdc_dev->hw_ops.set_pixel_format( | ||
344 | vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { | ||
345 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
346 | "couldn't set pix format in ccdc\n"); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | /* configure the image window */ | ||
350 | ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); | ||
351 | |||
352 | switch (vpfe_dev->fmt.fmt.pix.field) { | ||
353 | case V4L2_FIELD_INTERLACED: | ||
354 | /* do nothing, since it is default */ | ||
355 | ret = ccdc_dev->hw_ops.set_buftype( | ||
356 | CCDC_BUFTYPE_FLD_INTERLEAVED); | ||
357 | break; | ||
358 | case V4L2_FIELD_NONE: | ||
359 | frm_fmt = CCDC_FRMFMT_PROGRESSIVE; | ||
360 | /* buffer type only applicable for interlaced scan */ | ||
361 | break; | ||
362 | case V4L2_FIELD_SEQ_TB: | ||
363 | ret = ccdc_dev->hw_ops.set_buftype( | ||
364 | CCDC_BUFTYPE_FLD_SEPARATED); | ||
365 | break; | ||
366 | default: | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | /* set the frame format */ | ||
371 | if (!ret) | ||
372 | ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); | ||
373 | return ret; | ||
374 | } | ||
375 | /* | ||
376 | * vpfe_config_image_format() | ||
377 | * For a given standard, this functions sets up the default | ||
378 | * pix format & crop values in the vpfe device and ccdc. It first | ||
379 | * starts with defaults based values from the standard table. | ||
380 | * It then checks if sub device support g_fmt and then override the | ||
381 | * values based on that.Sets crop values to match with scan resolution | ||
382 | * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the | ||
383 | * values in ccdc | ||
384 | */ | ||
385 | static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, | ||
386 | const v4l2_std_id *std_id) | ||
387 | { | ||
388 | struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; | ||
389 | int i, ret = 0; | ||
390 | |||
391 | for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { | ||
392 | if (vpfe_standards[i].std_id & *std_id) { | ||
393 | vpfe_dev->std_info.active_pixels = | ||
394 | vpfe_standards[i].width; | ||
395 | vpfe_dev->std_info.active_lines = | ||
396 | vpfe_standards[i].height; | ||
397 | vpfe_dev->std_info.frame_format = | ||
398 | vpfe_standards[i].frame_format; | ||
399 | vpfe_dev->std_index = i; | ||
400 | break; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | if (i == ARRAY_SIZE(vpfe_standards)) { | ||
405 | v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | |||
409 | vpfe_dev->crop.top = 0; | ||
410 | vpfe_dev->crop.left = 0; | ||
411 | vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; | ||
412 | vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; | ||
413 | vpfe_dev->fmt.fmt.pix.width = vpfe_dev->crop.width; | ||
414 | vpfe_dev->fmt.fmt.pix.height = vpfe_dev->crop.height; | ||
415 | |||
416 | /* first field and frame format based on standard frame format */ | ||
417 | if (vpfe_dev->std_info.frame_format) { | ||
418 | vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
419 | /* assume V4L2_PIX_FMT_UYVY as default */ | ||
420 | vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; | ||
421 | } else { | ||
422 | vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_NONE; | ||
423 | /* assume V4L2_PIX_FMT_SBGGR8 */ | ||
424 | vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
425 | } | ||
426 | |||
427 | /* if sub device supports g_fmt, override the defaults */ | ||
428 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, | ||
429 | sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt); | ||
430 | |||
431 | if (ret && ret != -ENOIOCTLCMD) { | ||
432 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
433 | "error in getting g_fmt from sub device\n"); | ||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | /* Sets the values in CCDC */ | ||
438 | ret = vpfe_config_ccdc_image_format(vpfe_dev); | ||
439 | if (ret) | ||
440 | return ret; | ||
441 | |||
442 | /* Update the values of sizeimage and bytesperline */ | ||
443 | if (!ret) { | ||
444 | vpfe_dev->fmt.fmt.pix.bytesperline = | ||
445 | ccdc_dev->hw_ops.get_line_length(); | ||
446 | vpfe_dev->fmt.fmt.pix.sizeimage = | ||
447 | vpfe_dev->fmt.fmt.pix.bytesperline * | ||
448 | vpfe_dev->fmt.fmt.pix.height; | ||
449 | } | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) | ||
454 | { | ||
455 | int ret = 0; | ||
456 | |||
457 | /* set first input of current subdevice as the current input */ | ||
458 | vpfe_dev->current_input = 0; | ||
459 | |||
460 | /* set default standard */ | ||
461 | vpfe_dev->std_index = 0; | ||
462 | |||
463 | /* Configure the default format information */ | ||
464 | ret = vpfe_config_image_format(vpfe_dev, | ||
465 | &vpfe_standards[vpfe_dev->std_index].std_id); | ||
466 | if (ret) | ||
467 | return ret; | ||
468 | |||
469 | /* now open the ccdc device to initialize it */ | ||
470 | mutex_lock(&ccdc_lock); | ||
471 | if (NULL == ccdc_dev) { | ||
472 | v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); | ||
473 | ret = -ENODEV; | ||
474 | goto unlock; | ||
475 | } | ||
476 | |||
477 | if (!try_module_get(ccdc_dev->owner)) { | ||
478 | v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); | ||
479 | ret = -ENODEV; | ||
480 | goto unlock; | ||
481 | } | ||
482 | ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); | ||
483 | if (!ret) | ||
484 | vpfe_dev->initialized = 1; | ||
485 | unlock: | ||
486 | mutex_unlock(&ccdc_lock); | ||
487 | return ret; | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * vpfe_open : It creates object of file handle structure and | ||
492 | * stores it in private_data member of filepointer | ||
493 | */ | ||
494 | static int vpfe_open(struct file *file) | ||
495 | { | ||
496 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
497 | struct vpfe_fh *fh; | ||
498 | |||
499 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); | ||
500 | |||
501 | if (!vpfe_dev->cfg->num_subdevs) { | ||
502 | v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); | ||
503 | return -ENODEV; | ||
504 | } | ||
505 | |||
506 | /* Allocate memory for the file handle object */ | ||
507 | fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); | ||
508 | if (NULL == fh) { | ||
509 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
510 | "unable to allocate memory for file handle object\n"); | ||
511 | return -ENOMEM; | ||
512 | } | ||
513 | /* store pointer to fh in private_data member of file */ | ||
514 | file->private_data = fh; | ||
515 | fh->vpfe_dev = vpfe_dev; | ||
516 | mutex_lock(&vpfe_dev->lock); | ||
517 | /* If decoder is not initialized. initialize it */ | ||
518 | if (!vpfe_dev->initialized) { | ||
519 | if (vpfe_initialize_device(vpfe_dev)) { | ||
520 | mutex_unlock(&vpfe_dev->lock); | ||
521 | return -ENODEV; | ||
522 | } | ||
523 | } | ||
524 | /* Increment device usrs counter */ | ||
525 | vpfe_dev->usrs++; | ||
526 | /* Set io_allowed member to false */ | ||
527 | fh->io_allowed = 0; | ||
528 | /* Initialize priority of this instance to default priority */ | ||
529 | fh->prio = V4L2_PRIORITY_UNSET; | ||
530 | v4l2_prio_open(&vpfe_dev->prio, &fh->prio); | ||
531 | mutex_unlock(&vpfe_dev->lock); | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) | ||
536 | { | ||
537 | unsigned long addr; | ||
538 | |||
539 | vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, | ||
540 | struct videobuf_buffer, queue); | ||
541 | list_del(&vpfe_dev->next_frm->queue); | ||
542 | vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; | ||
543 | addr = videobuf_to_dma_contig(vpfe_dev->next_frm); | ||
544 | ccdc_dev->hw_ops.setfbaddr(addr); | ||
545 | } | ||
546 | |||
547 | static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) | ||
548 | { | ||
549 | struct timeval timevalue; | ||
550 | |||
551 | do_gettimeofday(&timevalue); | ||
552 | vpfe_dev->cur_frm->ts = timevalue; | ||
553 | vpfe_dev->cur_frm->state = VIDEOBUF_DONE; | ||
554 | vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; | ||
555 | wake_up_interruptible(&vpfe_dev->cur_frm->done); | ||
556 | vpfe_dev->cur_frm = vpfe_dev->next_frm; | ||
557 | } | ||
558 | |||
559 | /* ISR for VINT0*/ | ||
560 | static irqreturn_t vpfe_isr(int irq, void *dev_id) | ||
561 | { | ||
562 | struct vpfe_device *vpfe_dev = dev_id; | ||
563 | enum v4l2_field field; | ||
564 | unsigned long addr; | ||
565 | int fid; | ||
566 | |||
567 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); | ||
568 | field = vpfe_dev->fmt.fmt.pix.field; | ||
569 | |||
570 | /* if streaming not started, don't do anything */ | ||
571 | if (!vpfe_dev->started) | ||
572 | return IRQ_HANDLED; | ||
573 | |||
574 | /* only for 6446 this will be applicable */ | ||
575 | if (NULL != ccdc_dev->hw_ops.reset) | ||
576 | ccdc_dev->hw_ops.reset(); | ||
577 | |||
578 | if (field == V4L2_FIELD_NONE) { | ||
579 | /* handle progressive frame capture */ | ||
580 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
581 | "frame format is progressive...\n"); | ||
582 | if (vpfe_dev->cur_frm != vpfe_dev->next_frm) | ||
583 | vpfe_process_buffer_complete(vpfe_dev); | ||
584 | return IRQ_HANDLED; | ||
585 | } | ||
586 | |||
587 | /* interlaced or TB capture check which field we are in hardware */ | ||
588 | fid = ccdc_dev->hw_ops.getfid(); | ||
589 | |||
590 | /* switch the software maintained field id */ | ||
591 | vpfe_dev->field_id ^= 1; | ||
592 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", | ||
593 | fid, vpfe_dev->field_id); | ||
594 | if (fid == vpfe_dev->field_id) { | ||
595 | /* we are in-sync here,continue */ | ||
596 | if (fid == 0) { | ||
597 | /* | ||
598 | * One frame is just being captured. If the next frame | ||
599 | * is available, release the current frame and move on | ||
600 | */ | ||
601 | if (vpfe_dev->cur_frm != vpfe_dev->next_frm) | ||
602 | vpfe_process_buffer_complete(vpfe_dev); | ||
603 | /* | ||
604 | * based on whether the two fields are stored | ||
605 | * interleavely or separately in memory, reconfigure | ||
606 | * the CCDC memory address | ||
607 | */ | ||
608 | if (field == V4L2_FIELD_SEQ_TB) { | ||
609 | addr = | ||
610 | videobuf_to_dma_contig(vpfe_dev->cur_frm); | ||
611 | addr += vpfe_dev->field_off; | ||
612 | ccdc_dev->hw_ops.setfbaddr(addr); | ||
613 | } | ||
614 | return IRQ_HANDLED; | ||
615 | } | ||
616 | /* | ||
617 | * if one field is just being captured configure | ||
618 | * the next frame get the next frame from the empty | ||
619 | * queue if no frame is available hold on to the | ||
620 | * current buffer | ||
621 | */ | ||
622 | spin_lock(&vpfe_dev->dma_queue_lock); | ||
623 | if (!list_empty(&vpfe_dev->dma_queue) && | ||
624 | vpfe_dev->cur_frm == vpfe_dev->next_frm) | ||
625 | vpfe_schedule_next_buffer(vpfe_dev); | ||
626 | spin_unlock(&vpfe_dev->dma_queue_lock); | ||
627 | } else if (fid == 0) { | ||
628 | /* | ||
629 | * out of sync. Recover from any hardware out-of-sync. | ||
630 | * May loose one frame | ||
631 | */ | ||
632 | vpfe_dev->field_id = fid; | ||
633 | } | ||
634 | return IRQ_HANDLED; | ||
635 | } | ||
636 | |||
637 | /* vdint1_isr - isr handler for VINT1 interrupt */ | ||
638 | static irqreturn_t vdint1_isr(int irq, void *dev_id) | ||
639 | { | ||
640 | struct vpfe_device *vpfe_dev = dev_id; | ||
641 | |||
642 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); | ||
643 | |||
644 | /* if streaming not started, don't do anything */ | ||
645 | if (!vpfe_dev->started) | ||
646 | return IRQ_HANDLED; | ||
647 | |||
648 | spin_lock(&vpfe_dev->dma_queue_lock); | ||
649 | if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && | ||
650 | !list_empty(&vpfe_dev->dma_queue) && | ||
651 | vpfe_dev->cur_frm == vpfe_dev->next_frm) | ||
652 | vpfe_schedule_next_buffer(vpfe_dev); | ||
653 | spin_unlock(&vpfe_dev->dma_queue_lock); | ||
654 | return IRQ_HANDLED; | ||
655 | } | ||
656 | |||
657 | static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) | ||
658 | { | ||
659 | enum ccdc_frmfmt frame_format; | ||
660 | |||
661 | frame_format = ccdc_dev->hw_ops.get_frame_format(); | ||
662 | if (frame_format == CCDC_FRMFMT_PROGRESSIVE) | ||
663 | free_irq(IRQ_VDINT1, vpfe_dev); | ||
664 | } | ||
665 | |||
666 | static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) | ||
667 | { | ||
668 | enum ccdc_frmfmt frame_format; | ||
669 | |||
670 | frame_format = ccdc_dev->hw_ops.get_frame_format(); | ||
671 | if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { | ||
672 | return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, | ||
673 | IRQF_DISABLED, "vpfe_capture1", | ||
674 | vpfe_dev); | ||
675 | } | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | /* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ | ||
680 | static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) | ||
681 | { | ||
682 | vpfe_dev->started = 0; | ||
683 | ccdc_dev->hw_ops.enable(0); | ||
684 | if (ccdc_dev->hw_ops.enable_out_to_sdram) | ||
685 | ccdc_dev->hw_ops.enable_out_to_sdram(0); | ||
686 | } | ||
687 | |||
688 | /* | ||
689 | * vpfe_release : This function deletes buffer queue, frees the | ||
690 | * buffers and the vpfe file handle | ||
691 | */ | ||
692 | static int vpfe_release(struct file *file) | ||
693 | { | ||
694 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
695 | struct vpfe_fh *fh = file->private_data; | ||
696 | struct vpfe_subdev_info *sdinfo; | ||
697 | int ret; | ||
698 | |||
699 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); | ||
700 | |||
701 | /* Get the device lock */ | ||
702 | mutex_lock(&vpfe_dev->lock); | ||
703 | /* if this instance is doing IO */ | ||
704 | if (fh->io_allowed) { | ||
705 | if (vpfe_dev->started) { | ||
706 | sdinfo = vpfe_dev->current_subdev; | ||
707 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, | ||
708 | sdinfo->grp_id, | ||
709 | video, s_stream, 0); | ||
710 | if (ret && (ret != -ENOIOCTLCMD)) | ||
711 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
712 | "stream off failed in subdev\n"); | ||
713 | vpfe_stop_ccdc_capture(vpfe_dev); | ||
714 | vpfe_detach_irq(vpfe_dev); | ||
715 | videobuf_streamoff(&vpfe_dev->buffer_queue); | ||
716 | } | ||
717 | vpfe_dev->io_usrs = 0; | ||
718 | vpfe_dev->numbuffers = config_params.numbuffers; | ||
719 | } | ||
720 | |||
721 | /* Decrement device usrs counter */ | ||
722 | vpfe_dev->usrs--; | ||
723 | /* Close the priority */ | ||
724 | v4l2_prio_close(&vpfe_dev->prio, &fh->prio); | ||
725 | /* If this is the last file handle */ | ||
726 | if (!vpfe_dev->usrs) { | ||
727 | vpfe_dev->initialized = 0; | ||
728 | if (ccdc_dev->hw_ops.close) | ||
729 | ccdc_dev->hw_ops.close(vpfe_dev->pdev); | ||
730 | module_put(ccdc_dev->owner); | ||
731 | } | ||
732 | mutex_unlock(&vpfe_dev->lock); | ||
733 | file->private_data = NULL; | ||
734 | /* Free memory allocated to file handle object */ | ||
735 | kfree(fh); | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * vpfe_mmap : It is used to map kernel space buffers | ||
741 | * into user spaces | ||
742 | */ | ||
743 | static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) | ||
744 | { | ||
745 | /* Get the device object and file handle object */ | ||
746 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
747 | |||
748 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); | ||
749 | |||
750 | return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); | ||
751 | } | ||
752 | |||
753 | /* | ||
754 | * vpfe_poll: It is used for select/poll system call | ||
755 | */ | ||
756 | static unsigned int vpfe_poll(struct file *file, poll_table *wait) | ||
757 | { | ||
758 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
759 | |||
760 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); | ||
761 | |||
762 | if (vpfe_dev->started) | ||
763 | return videobuf_poll_stream(file, | ||
764 | &vpfe_dev->buffer_queue, wait); | ||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | /* vpfe capture driver file operations */ | ||
769 | static const struct v4l2_file_operations vpfe_fops = { | ||
770 | .owner = THIS_MODULE, | ||
771 | .open = vpfe_open, | ||
772 | .release = vpfe_release, | ||
773 | .unlocked_ioctl = video_ioctl2, | ||
774 | .mmap = vpfe_mmap, | ||
775 | .poll = vpfe_poll | ||
776 | }; | ||
777 | |||
778 | /* | ||
779 | * vpfe_check_format() | ||
780 | * This function adjust the input pixel format as per hardware | ||
781 | * capabilities and update the same in pixfmt. | ||
782 | * Following algorithm used :- | ||
783 | * | ||
784 | * If given pixformat is not in the vpfe list of pix formats or not | ||
785 | * supported by the hardware, current value of pixformat in the device | ||
786 | * is used | ||
787 | * If given field is not supported, then current field is used. If field | ||
788 | * is different from current, then it is matched with that from sub device. | ||
789 | * Minimum height is 2 lines for interlaced or tb field and 1 line for | ||
790 | * progressive. Maximum height is clamped to active active lines of scan | ||
791 | * Minimum width is 32 bytes in memory and width is clamped to active | ||
792 | * pixels of scan. | ||
793 | * bytesperline is a multiple of 32. | ||
794 | */ | ||
795 | static const struct vpfe_pixel_format * | ||
796 | vpfe_check_format(struct vpfe_device *vpfe_dev, | ||
797 | struct v4l2_pix_format *pixfmt) | ||
798 | { | ||
799 | u32 min_height = 1, min_width = 32, max_width, max_height; | ||
800 | const struct vpfe_pixel_format *vpfe_pix_fmt; | ||
801 | u32 pix; | ||
802 | int temp, found; | ||
803 | |||
804 | vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); | ||
805 | if (NULL == vpfe_pix_fmt) { | ||
806 | /* | ||
807 | * use current pixel format in the vpfe device. We | ||
808 | * will find this pix format in the table | ||
809 | */ | ||
810 | pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; | ||
811 | vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); | ||
812 | } | ||
813 | |||
814 | /* check if hw supports it */ | ||
815 | temp = 0; | ||
816 | found = 0; | ||
817 | while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { | ||
818 | if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { | ||
819 | found = 1; | ||
820 | break; | ||
821 | } | ||
822 | temp++; | ||
823 | } | ||
824 | |||
825 | if (!found) { | ||
826 | /* use current pixel format */ | ||
827 | pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; | ||
828 | /* | ||
829 | * Since this is currently used in the vpfe device, we | ||
830 | * will find this pix format in the table | ||
831 | */ | ||
832 | vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); | ||
833 | } | ||
834 | |||
835 | /* check what field format is supported */ | ||
836 | if (pixfmt->field == V4L2_FIELD_ANY) { | ||
837 | /* if field is any, use current value as default */ | ||
838 | pixfmt->field = vpfe_dev->fmt.fmt.pix.field; | ||
839 | } | ||
840 | |||
841 | /* | ||
842 | * if field is not same as current field in the vpfe device | ||
843 | * try matching the field with the sub device field | ||
844 | */ | ||
845 | if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { | ||
846 | /* | ||
847 | * If field value is not in the supported fields, use current | ||
848 | * field used in the device as default | ||
849 | */ | ||
850 | switch (pixfmt->field) { | ||
851 | case V4L2_FIELD_INTERLACED: | ||
852 | case V4L2_FIELD_SEQ_TB: | ||
853 | /* if sub device is supporting progressive, use that */ | ||
854 | if (!vpfe_dev->std_info.frame_format) | ||
855 | pixfmt->field = V4L2_FIELD_NONE; | ||
856 | break; | ||
857 | case V4L2_FIELD_NONE: | ||
858 | if (vpfe_dev->std_info.frame_format) | ||
859 | pixfmt->field = V4L2_FIELD_INTERLACED; | ||
860 | break; | ||
861 | |||
862 | default: | ||
863 | /* use current field as default */ | ||
864 | pixfmt->field = vpfe_dev->fmt.fmt.pix.field; | ||
865 | break; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | /* Now adjust image resolutions supported */ | ||
870 | if (pixfmt->field == V4L2_FIELD_INTERLACED || | ||
871 | pixfmt->field == V4L2_FIELD_SEQ_TB) | ||
872 | min_height = 2; | ||
873 | |||
874 | max_width = vpfe_dev->std_info.active_pixels; | ||
875 | max_height = vpfe_dev->std_info.active_lines; | ||
876 | min_width /= vpfe_pix_fmt->bpp; | ||
877 | |||
878 | v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", | ||
879 | pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); | ||
880 | |||
881 | pixfmt->width = clamp((pixfmt->width), min_width, max_width); | ||
882 | pixfmt->height = clamp((pixfmt->height), min_height, max_height); | ||
883 | |||
884 | /* If interlaced, adjust height to be a multiple of 2 */ | ||
885 | if (pixfmt->field == V4L2_FIELD_INTERLACED) | ||
886 | pixfmt->height &= (~1); | ||
887 | /* | ||
888 | * recalculate bytesperline and sizeimage since width | ||
889 | * and height might have changed | ||
890 | */ | ||
891 | pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) | ||
892 | & ~31); | ||
893 | if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) | ||
894 | pixfmt->sizeimage = | ||
895 | pixfmt->bytesperline * pixfmt->height + | ||
896 | ((pixfmt->bytesperline * pixfmt->height) >> 1); | ||
897 | else | ||
898 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
899 | |||
900 | v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height =" | ||
901 | " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", | ||
902 | pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, | ||
903 | pixfmt->bytesperline, pixfmt->sizeimage); | ||
904 | return vpfe_pix_fmt; | ||
905 | } | ||
906 | |||
907 | static int vpfe_querycap(struct file *file, void *priv, | ||
908 | struct v4l2_capability *cap) | ||
909 | { | ||
910 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
911 | |||
912 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); | ||
913 | |||
914 | cap->version = VPFE_CAPTURE_VERSION_CODE; | ||
915 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
916 | strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); | ||
917 | strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); | ||
918 | strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, | ||
923 | struct v4l2_format *fmt) | ||
924 | { | ||
925 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
926 | int ret = 0; | ||
927 | |||
928 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); | ||
929 | /* Fill in the information about format */ | ||
930 | *fmt = vpfe_dev->fmt; | ||
931 | return ret; | ||
932 | } | ||
933 | |||
934 | static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, | ||
935 | struct v4l2_fmtdesc *fmt) | ||
936 | { | ||
937 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
938 | const struct vpfe_pixel_format *pix_fmt; | ||
939 | int temp_index; | ||
940 | u32 pix; | ||
941 | |||
942 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); | ||
943 | |||
944 | if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) | ||
945 | return -EINVAL; | ||
946 | |||
947 | /* Fill in the information about format */ | ||
948 | pix_fmt = vpfe_lookup_pix_format(pix); | ||
949 | if (NULL != pix_fmt) { | ||
950 | temp_index = fmt->index; | ||
951 | *fmt = pix_fmt->fmtdesc; | ||
952 | fmt->index = temp_index; | ||
953 | return 0; | ||
954 | } | ||
955 | return -EINVAL; | ||
956 | } | ||
957 | |||
958 | static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, | ||
959 | struct v4l2_format *fmt) | ||
960 | { | ||
961 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
962 | const struct vpfe_pixel_format *pix_fmts; | ||
963 | int ret = 0; | ||
964 | |||
965 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); | ||
966 | |||
967 | /* If streaming is started, return error */ | ||
968 | if (vpfe_dev->started) { | ||
969 | v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); | ||
970 | return -EBUSY; | ||
971 | } | ||
972 | |||
973 | /* Check for valid frame format */ | ||
974 | pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); | ||
975 | |||
976 | if (NULL == pix_fmts) | ||
977 | return -EINVAL; | ||
978 | |||
979 | /* store the pixel format in the device object */ | ||
980 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
981 | if (ret) | ||
982 | return ret; | ||
983 | |||
984 | /* First detach any IRQ if currently attached */ | ||
985 | vpfe_detach_irq(vpfe_dev); | ||
986 | vpfe_dev->fmt = *fmt; | ||
987 | /* set image capture parameters in the ccdc */ | ||
988 | ret = vpfe_config_ccdc_image_format(vpfe_dev); | ||
989 | mutex_unlock(&vpfe_dev->lock); | ||
990 | return ret; | ||
991 | } | ||
992 | |||
993 | static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, | ||
994 | struct v4l2_format *f) | ||
995 | { | ||
996 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
997 | const struct vpfe_pixel_format *pix_fmts; | ||
998 | |||
999 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); | ||
1000 | |||
1001 | pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); | ||
1002 | if (NULL == pix_fmts) | ||
1003 | return -EINVAL; | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | /* | ||
1008 | * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a | ||
1009 | * given app input index | ||
1010 | */ | ||
1011 | static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, | ||
1012 | int *subdev_index, | ||
1013 | int *subdev_input_index, | ||
1014 | int app_input_index) | ||
1015 | { | ||
1016 | struct vpfe_config *cfg = vpfe_dev->cfg; | ||
1017 | struct vpfe_subdev_info *sdinfo; | ||
1018 | int i, j = 0; | ||
1019 | |||
1020 | for (i = 0; i < cfg->num_subdevs; i++) { | ||
1021 | sdinfo = &cfg->sub_devs[i]; | ||
1022 | if (app_input_index < (j + sdinfo->num_inputs)) { | ||
1023 | *subdev_index = i; | ||
1024 | *subdev_input_index = app_input_index - j; | ||
1025 | return 0; | ||
1026 | } | ||
1027 | j += sdinfo->num_inputs; | ||
1028 | } | ||
1029 | return -EINVAL; | ||
1030 | } | ||
1031 | |||
1032 | /* | ||
1033 | * vpfe_get_app_input - Get app input index for a given subdev input index | ||
1034 | * driver stores the input index of the current sub device and translate it | ||
1035 | * when application request the current input | ||
1036 | */ | ||
1037 | static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, | ||
1038 | int *app_input_index) | ||
1039 | { | ||
1040 | struct vpfe_config *cfg = vpfe_dev->cfg; | ||
1041 | struct vpfe_subdev_info *sdinfo; | ||
1042 | int i, j = 0; | ||
1043 | |||
1044 | for (i = 0; i < cfg->num_subdevs; i++) { | ||
1045 | sdinfo = &cfg->sub_devs[i]; | ||
1046 | if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { | ||
1047 | if (vpfe_dev->current_input >= sdinfo->num_inputs) | ||
1048 | return -1; | ||
1049 | *app_input_index = j + vpfe_dev->current_input; | ||
1050 | return 0; | ||
1051 | } | ||
1052 | j += sdinfo->num_inputs; | ||
1053 | } | ||
1054 | return -EINVAL; | ||
1055 | } | ||
1056 | |||
1057 | static int vpfe_enum_input(struct file *file, void *priv, | ||
1058 | struct v4l2_input *inp) | ||
1059 | { | ||
1060 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1061 | struct vpfe_subdev_info *sdinfo; | ||
1062 | int subdev, index ; | ||
1063 | |||
1064 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); | ||
1065 | |||
1066 | if (vpfe_get_subdev_input_index(vpfe_dev, | ||
1067 | &subdev, | ||
1068 | &index, | ||
1069 | inp->index) < 0) { | ||
1070 | v4l2_err(&vpfe_dev->v4l2_dev, "input information not found" | ||
1071 | " for the subdev\n"); | ||
1072 | return -EINVAL; | ||
1073 | } | ||
1074 | sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; | ||
1075 | memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); | ||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) | ||
1080 | { | ||
1081 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1082 | |||
1083 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); | ||
1084 | |||
1085 | return vpfe_get_app_input_index(vpfe_dev, index); | ||
1086 | } | ||
1087 | |||
1088 | |||
1089 | static int vpfe_s_input(struct file *file, void *priv, unsigned int index) | ||
1090 | { | ||
1091 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1092 | struct vpfe_subdev_info *sdinfo; | ||
1093 | int subdev_index, inp_index; | ||
1094 | struct vpfe_route *route; | ||
1095 | u32 input = 0, output = 0; | ||
1096 | int ret = -EINVAL; | ||
1097 | |||
1098 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); | ||
1099 | |||
1100 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1101 | if (ret) | ||
1102 | return ret; | ||
1103 | |||
1104 | /* | ||
1105 | * If streaming is started return device busy | ||
1106 | * error | ||
1107 | */ | ||
1108 | if (vpfe_dev->started) { | ||
1109 | v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); | ||
1110 | ret = -EBUSY; | ||
1111 | goto unlock_out; | ||
1112 | } | ||
1113 | |||
1114 | if (vpfe_get_subdev_input_index(vpfe_dev, | ||
1115 | &subdev_index, | ||
1116 | &inp_index, | ||
1117 | index) < 0) { | ||
1118 | v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); | ||
1119 | goto unlock_out; | ||
1120 | } | ||
1121 | |||
1122 | sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; | ||
1123 | route = &sdinfo->routes[inp_index]; | ||
1124 | if (route && sdinfo->can_route) { | ||
1125 | input = route->input; | ||
1126 | output = route->output; | ||
1127 | } | ||
1128 | |||
1129 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1130 | video, s_routing, input, output, 0); | ||
1131 | |||
1132 | if (ret) { | ||
1133 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1134 | "vpfe_doioctl:error in setting input in decoder\n"); | ||
1135 | ret = -EINVAL; | ||
1136 | goto unlock_out; | ||
1137 | } | ||
1138 | vpfe_dev->current_subdev = sdinfo; | ||
1139 | vpfe_dev->current_input = index; | ||
1140 | vpfe_dev->std_index = 0; | ||
1141 | |||
1142 | /* set the bus/interface parameter for the sub device in ccdc */ | ||
1143 | ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); | ||
1144 | if (ret) | ||
1145 | goto unlock_out; | ||
1146 | |||
1147 | /* set the default image parameters in the device */ | ||
1148 | ret = vpfe_config_image_format(vpfe_dev, | ||
1149 | &vpfe_standards[vpfe_dev->std_index].std_id); | ||
1150 | unlock_out: | ||
1151 | mutex_unlock(&vpfe_dev->lock); | ||
1152 | return ret; | ||
1153 | } | ||
1154 | |||
1155 | static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1156 | { | ||
1157 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1158 | struct vpfe_subdev_info *sdinfo; | ||
1159 | int ret = 0; | ||
1160 | |||
1161 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); | ||
1162 | |||
1163 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1164 | sdinfo = vpfe_dev->current_subdev; | ||
1165 | if (ret) | ||
1166 | return ret; | ||
1167 | /* Call querystd function of decoder device */ | ||
1168 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1169 | video, querystd, std_id); | ||
1170 | mutex_unlock(&vpfe_dev->lock); | ||
1171 | return ret; | ||
1172 | } | ||
1173 | |||
1174 | static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1175 | { | ||
1176 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1177 | struct vpfe_subdev_info *sdinfo; | ||
1178 | int ret = 0; | ||
1179 | |||
1180 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); | ||
1181 | |||
1182 | /* Call decoder driver function to set the standard */ | ||
1183 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1184 | if (ret) | ||
1185 | return ret; | ||
1186 | |||
1187 | sdinfo = vpfe_dev->current_subdev; | ||
1188 | /* If streaming is started, return device busy error */ | ||
1189 | if (vpfe_dev->started) { | ||
1190 | v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); | ||
1191 | ret = -EBUSY; | ||
1192 | goto unlock_out; | ||
1193 | } | ||
1194 | |||
1195 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1196 | core, s_std, *std_id); | ||
1197 | if (ret < 0) { | ||
1198 | v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); | ||
1199 | goto unlock_out; | ||
1200 | } | ||
1201 | ret = vpfe_config_image_format(vpfe_dev, std_id); | ||
1202 | |||
1203 | unlock_out: | ||
1204 | mutex_unlock(&vpfe_dev->lock); | ||
1205 | return ret; | ||
1206 | } | ||
1207 | |||
1208 | static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1209 | { | ||
1210 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1211 | |||
1212 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); | ||
1213 | |||
1214 | *std_id = vpfe_standards[vpfe_dev->std_index].std_id; | ||
1215 | return 0; | ||
1216 | } | ||
1217 | /* | ||
1218 | * Videobuf operations | ||
1219 | */ | ||
1220 | static int vpfe_videobuf_setup(struct videobuf_queue *vq, | ||
1221 | unsigned int *count, | ||
1222 | unsigned int *size) | ||
1223 | { | ||
1224 | struct vpfe_fh *fh = vq->priv_data; | ||
1225 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1226 | |||
1227 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); | ||
1228 | *size = config_params.device_bufsize; | ||
1229 | |||
1230 | if (*count < config_params.min_numbuffers) | ||
1231 | *count = config_params.min_numbuffers; | ||
1232 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1233 | "count=%d, size=%d\n", *count, *size); | ||
1234 | return 0; | ||
1235 | } | ||
1236 | |||
1237 | static int vpfe_videobuf_prepare(struct videobuf_queue *vq, | ||
1238 | struct videobuf_buffer *vb, | ||
1239 | enum v4l2_field field) | ||
1240 | { | ||
1241 | struct vpfe_fh *fh = vq->priv_data; | ||
1242 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1243 | |||
1244 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); | ||
1245 | |||
1246 | /* If buffer is not initialized, initialize it */ | ||
1247 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
1248 | vb->width = vpfe_dev->fmt.fmt.pix.width; | ||
1249 | vb->height = vpfe_dev->fmt.fmt.pix.height; | ||
1250 | vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; | ||
1251 | vb->field = field; | ||
1252 | } | ||
1253 | vb->state = VIDEOBUF_PREPARED; | ||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | static void vpfe_videobuf_queue(struct videobuf_queue *vq, | ||
1258 | struct videobuf_buffer *vb) | ||
1259 | { | ||
1260 | /* Get the file handle object and device object */ | ||
1261 | struct vpfe_fh *fh = vq->priv_data; | ||
1262 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1263 | unsigned long flags; | ||
1264 | |||
1265 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); | ||
1266 | |||
1267 | /* add the buffer to the DMA queue */ | ||
1268 | spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); | ||
1269 | list_add_tail(&vb->queue, &vpfe_dev->dma_queue); | ||
1270 | spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); | ||
1271 | |||
1272 | /* Change state of the buffer */ | ||
1273 | vb->state = VIDEOBUF_QUEUED; | ||
1274 | } | ||
1275 | |||
1276 | static void vpfe_videobuf_release(struct videobuf_queue *vq, | ||
1277 | struct videobuf_buffer *vb) | ||
1278 | { | ||
1279 | struct vpfe_fh *fh = vq->priv_data; | ||
1280 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1281 | unsigned long flags; | ||
1282 | |||
1283 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); | ||
1284 | |||
1285 | /* | ||
1286 | * We need to flush the buffer from the dma queue since | ||
1287 | * they are de-allocated | ||
1288 | */ | ||
1289 | spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); | ||
1290 | INIT_LIST_HEAD(&vpfe_dev->dma_queue); | ||
1291 | spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); | ||
1292 | videobuf_dma_contig_free(vq, vb); | ||
1293 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
1294 | } | ||
1295 | |||
1296 | static struct videobuf_queue_ops vpfe_videobuf_qops = { | ||
1297 | .buf_setup = vpfe_videobuf_setup, | ||
1298 | .buf_prepare = vpfe_videobuf_prepare, | ||
1299 | .buf_queue = vpfe_videobuf_queue, | ||
1300 | .buf_release = vpfe_videobuf_release, | ||
1301 | }; | ||
1302 | |||
1303 | /* | ||
1304 | * vpfe_reqbufs. currently support REQBUF only once opening | ||
1305 | * the device. | ||
1306 | */ | ||
1307 | static int vpfe_reqbufs(struct file *file, void *priv, | ||
1308 | struct v4l2_requestbuffers *req_buf) | ||
1309 | { | ||
1310 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1311 | struct vpfe_fh *fh = file->private_data; | ||
1312 | int ret = 0; | ||
1313 | |||
1314 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); | ||
1315 | |||
1316 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { | ||
1317 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1318 | return -EINVAL; | ||
1319 | } | ||
1320 | |||
1321 | if (V4L2_MEMORY_USERPTR == req_buf->memory) { | ||
1322 | /* we don't support user ptr IO */ | ||
1323 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs:" | ||
1324 | " USERPTR IO not supported\n"); | ||
1325 | return -EINVAL; | ||
1326 | } | ||
1327 | |||
1328 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1329 | if (ret) | ||
1330 | return ret; | ||
1331 | |||
1332 | if (vpfe_dev->io_usrs != 0) { | ||
1333 | v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); | ||
1334 | ret = -EBUSY; | ||
1335 | goto unlock_out; | ||
1336 | } | ||
1337 | |||
1338 | vpfe_dev->memory = req_buf->memory; | ||
1339 | videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, | ||
1340 | &vpfe_videobuf_qops, | ||
1341 | NULL, | ||
1342 | &vpfe_dev->irqlock, | ||
1343 | req_buf->type, | ||
1344 | vpfe_dev->fmt.fmt.pix.field, | ||
1345 | sizeof(struct videobuf_buffer), | ||
1346 | fh); | ||
1347 | |||
1348 | fh->io_allowed = 1; | ||
1349 | vpfe_dev->io_usrs = 1; | ||
1350 | INIT_LIST_HEAD(&vpfe_dev->dma_queue); | ||
1351 | ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); | ||
1352 | unlock_out: | ||
1353 | mutex_unlock(&vpfe_dev->lock); | ||
1354 | return ret; | ||
1355 | } | ||
1356 | |||
1357 | static int vpfe_querybuf(struct file *file, void *priv, | ||
1358 | struct v4l2_buffer *buf) | ||
1359 | { | ||
1360 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1361 | |||
1362 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); | ||
1363 | |||
1364 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { | ||
1365 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1366 | return -EINVAL; | ||
1367 | } | ||
1368 | |||
1369 | if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { | ||
1370 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); | ||
1371 | return -EINVAL; | ||
1372 | } | ||
1373 | /* Call videobuf_querybuf to get information */ | ||
1374 | return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); | ||
1375 | } | ||
1376 | |||
1377 | static int vpfe_qbuf(struct file *file, void *priv, | ||
1378 | struct v4l2_buffer *p) | ||
1379 | { | ||
1380 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1381 | struct vpfe_fh *fh = file->private_data; | ||
1382 | |||
1383 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); | ||
1384 | |||
1385 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { | ||
1386 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1387 | return -EINVAL; | ||
1388 | } | ||
1389 | |||
1390 | /* | ||
1391 | * If this file handle is not allowed to do IO, | ||
1392 | * return error | ||
1393 | */ | ||
1394 | if (!fh->io_allowed) { | ||
1395 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | ||
1396 | return -EACCES; | ||
1397 | } | ||
1398 | return videobuf_qbuf(&vpfe_dev->buffer_queue, p); | ||
1399 | } | ||
1400 | |||
1401 | static int vpfe_dqbuf(struct file *file, void *priv, | ||
1402 | struct v4l2_buffer *buf) | ||
1403 | { | ||
1404 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1405 | |||
1406 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); | ||
1407 | |||
1408 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { | ||
1409 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1410 | return -EINVAL; | ||
1411 | } | ||
1412 | return videobuf_dqbuf(&vpfe_dev->buffer_queue, | ||
1413 | buf, file->f_flags & O_NONBLOCK); | ||
1414 | } | ||
1415 | |||
1416 | /* | ||
1417 | * vpfe_calculate_offsets : This function calculates buffers offset | ||
1418 | * for top and bottom field | ||
1419 | */ | ||
1420 | static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) | ||
1421 | { | ||
1422 | struct v4l2_rect image_win; | ||
1423 | |||
1424 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); | ||
1425 | |||
1426 | ccdc_dev->hw_ops.get_image_window(&image_win); | ||
1427 | vpfe_dev->field_off = image_win.height * image_win.width; | ||
1428 | } | ||
1429 | |||
1430 | /* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ | ||
1431 | static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) | ||
1432 | { | ||
1433 | ccdc_dev->hw_ops.enable(1); | ||
1434 | if (ccdc_dev->hw_ops.enable_out_to_sdram) | ||
1435 | ccdc_dev->hw_ops.enable_out_to_sdram(1); | ||
1436 | vpfe_dev->started = 1; | ||
1437 | } | ||
1438 | |||
1439 | /* | ||
1440 | * vpfe_streamon. Assume the DMA queue is not empty. | ||
1441 | * application is expected to call QBUF before calling | ||
1442 | * this ioctl. If not, driver returns error | ||
1443 | */ | ||
1444 | static int vpfe_streamon(struct file *file, void *priv, | ||
1445 | enum v4l2_buf_type buf_type) | ||
1446 | { | ||
1447 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1448 | struct vpfe_fh *fh = file->private_data; | ||
1449 | struct vpfe_subdev_info *sdinfo; | ||
1450 | unsigned long addr; | ||
1451 | int ret = 0; | ||
1452 | |||
1453 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); | ||
1454 | |||
1455 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { | ||
1456 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1457 | return -EINVAL; | ||
1458 | } | ||
1459 | |||
1460 | /* If file handle is not allowed IO, return error */ | ||
1461 | if (!fh->io_allowed) { | ||
1462 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | ||
1463 | return -EACCES; | ||
1464 | } | ||
1465 | |||
1466 | sdinfo = vpfe_dev->current_subdev; | ||
1467 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1468 | video, s_stream, 1); | ||
1469 | |||
1470 | if (ret && (ret != -ENOIOCTLCMD)) { | ||
1471 | v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); | ||
1472 | return -EINVAL; | ||
1473 | } | ||
1474 | |||
1475 | /* If buffer queue is empty, return error */ | ||
1476 | if (list_empty(&vpfe_dev->buffer_queue.stream)) { | ||
1477 | v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); | ||
1478 | return -EIO; | ||
1479 | } | ||
1480 | |||
1481 | /* Call videobuf_streamon to start streaming * in videobuf */ | ||
1482 | ret = videobuf_streamon(&vpfe_dev->buffer_queue); | ||
1483 | if (ret) | ||
1484 | return ret; | ||
1485 | |||
1486 | |||
1487 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1488 | if (ret) | ||
1489 | goto streamoff; | ||
1490 | /* Get the next frame from the buffer queue */ | ||
1491 | vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, | ||
1492 | struct videobuf_buffer, queue); | ||
1493 | vpfe_dev->cur_frm = vpfe_dev->next_frm; | ||
1494 | /* Remove buffer from the buffer queue */ | ||
1495 | list_del(&vpfe_dev->cur_frm->queue); | ||
1496 | /* Mark state of the current frame to active */ | ||
1497 | vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1498 | /* Initialize field_id and started member */ | ||
1499 | vpfe_dev->field_id = 0; | ||
1500 | addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); | ||
1501 | |||
1502 | /* Calculate field offset */ | ||
1503 | vpfe_calculate_offsets(vpfe_dev); | ||
1504 | |||
1505 | if (vpfe_attach_irq(vpfe_dev) < 0) { | ||
1506 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1507 | "Error in attaching interrupt handle\n"); | ||
1508 | ret = -EFAULT; | ||
1509 | goto unlock_out; | ||
1510 | } | ||
1511 | if (ccdc_dev->hw_ops.configure() < 0) { | ||
1512 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1513 | "Error in configuring ccdc\n"); | ||
1514 | ret = -EINVAL; | ||
1515 | goto unlock_out; | ||
1516 | } | ||
1517 | ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); | ||
1518 | vpfe_start_ccdc_capture(vpfe_dev); | ||
1519 | mutex_unlock(&vpfe_dev->lock); | ||
1520 | return ret; | ||
1521 | unlock_out: | ||
1522 | mutex_unlock(&vpfe_dev->lock); | ||
1523 | streamoff: | ||
1524 | ret = videobuf_streamoff(&vpfe_dev->buffer_queue); | ||
1525 | return ret; | ||
1526 | } | ||
1527 | |||
1528 | static int vpfe_streamoff(struct file *file, void *priv, | ||
1529 | enum v4l2_buf_type buf_type) | ||
1530 | { | ||
1531 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1532 | struct vpfe_fh *fh = file->private_data; | ||
1533 | struct vpfe_subdev_info *sdinfo; | ||
1534 | int ret = 0; | ||
1535 | |||
1536 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); | ||
1537 | |||
1538 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { | ||
1539 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1540 | return -EINVAL; | ||
1541 | } | ||
1542 | |||
1543 | /* If io is allowed for this file handle, return error */ | ||
1544 | if (!fh->io_allowed) { | ||
1545 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | ||
1546 | return -EACCES; | ||
1547 | } | ||
1548 | |||
1549 | /* If streaming is not started, return error */ | ||
1550 | if (!vpfe_dev->started) { | ||
1551 | v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); | ||
1552 | return -EINVAL; | ||
1553 | } | ||
1554 | |||
1555 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1556 | if (ret) | ||
1557 | return ret; | ||
1558 | |||
1559 | vpfe_stop_ccdc_capture(vpfe_dev); | ||
1560 | vpfe_detach_irq(vpfe_dev); | ||
1561 | |||
1562 | sdinfo = vpfe_dev->current_subdev; | ||
1563 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1564 | video, s_stream, 0); | ||
1565 | |||
1566 | if (ret && (ret != -ENOIOCTLCMD)) | ||
1567 | v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); | ||
1568 | ret = videobuf_streamoff(&vpfe_dev->buffer_queue); | ||
1569 | mutex_unlock(&vpfe_dev->lock); | ||
1570 | return ret; | ||
1571 | } | ||
1572 | |||
1573 | static int vpfe_cropcap(struct file *file, void *priv, | ||
1574 | struct v4l2_cropcap *crop) | ||
1575 | { | ||
1576 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1577 | |||
1578 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); | ||
1579 | |||
1580 | if (vpfe_dev->std_index > ARRAY_SIZE(vpfe_standards)) | ||
1581 | return -EINVAL; | ||
1582 | |||
1583 | memset(crop, 0, sizeof(struct v4l2_cropcap)); | ||
1584 | crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1585 | crop->bounds.width = crop->defrect.width = | ||
1586 | vpfe_standards[vpfe_dev->std_index].width; | ||
1587 | crop->bounds.height = crop->defrect.height = | ||
1588 | vpfe_standards[vpfe_dev->std_index].height; | ||
1589 | crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; | ||
1590 | return 0; | ||
1591 | } | ||
1592 | |||
1593 | static int vpfe_g_crop(struct file *file, void *priv, | ||
1594 | struct v4l2_crop *crop) | ||
1595 | { | ||
1596 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1597 | |||
1598 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n"); | ||
1599 | |||
1600 | crop->c = vpfe_dev->crop; | ||
1601 | return 0; | ||
1602 | } | ||
1603 | |||
1604 | static int vpfe_s_crop(struct file *file, void *priv, | ||
1605 | struct v4l2_crop *crop) | ||
1606 | { | ||
1607 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1608 | int ret = 0; | ||
1609 | |||
1610 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); | ||
1611 | |||
1612 | if (vpfe_dev->started) { | ||
1613 | /* make sure streaming is not started */ | ||
1614 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1615 | "Cannot change crop when streaming is ON\n"); | ||
1616 | return -EBUSY; | ||
1617 | } | ||
1618 | |||
1619 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1620 | if (ret) | ||
1621 | return ret; | ||
1622 | |||
1623 | if (crop->c.top < 0 || crop->c.left < 0) { | ||
1624 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1625 | "doesn't support negative values for top & left\n"); | ||
1626 | ret = -EINVAL; | ||
1627 | goto unlock_out; | ||
1628 | } | ||
1629 | |||
1630 | /* adjust the width to 16 pixel boundry */ | ||
1631 | crop->c.width = ((crop->c.width + 15) & ~0xf); | ||
1632 | |||
1633 | /* make sure parameters are valid */ | ||
1634 | if ((crop->c.left + crop->c.width > | ||
1635 | vpfe_dev->std_info.active_pixels) || | ||
1636 | (crop->c.top + crop->c.height > | ||
1637 | vpfe_dev->std_info.active_lines)) { | ||
1638 | v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); | ||
1639 | ret = -EINVAL; | ||
1640 | goto unlock_out; | ||
1641 | } | ||
1642 | ccdc_dev->hw_ops.set_image_window(&crop->c); | ||
1643 | vpfe_dev->fmt.fmt.pix.width = crop->c.width; | ||
1644 | vpfe_dev->fmt.fmt.pix.height = crop->c.height; | ||
1645 | vpfe_dev->fmt.fmt.pix.bytesperline = | ||
1646 | ccdc_dev->hw_ops.get_line_length(); | ||
1647 | vpfe_dev->fmt.fmt.pix.sizeimage = | ||
1648 | vpfe_dev->fmt.fmt.pix.bytesperline * | ||
1649 | vpfe_dev->fmt.fmt.pix.height; | ||
1650 | vpfe_dev->crop = crop->c; | ||
1651 | unlock_out: | ||
1652 | mutex_unlock(&vpfe_dev->lock); | ||
1653 | return ret; | ||
1654 | } | ||
1655 | |||
1656 | |||
1657 | static long vpfe_param_handler(struct file *file, void *priv, | ||
1658 | int cmd, void *param) | ||
1659 | { | ||
1660 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1661 | int ret = 0; | ||
1662 | |||
1663 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); | ||
1664 | |||
1665 | if (vpfe_dev->started) { | ||
1666 | /* only allowed if streaming is not started */ | ||
1667 | v4l2_err(&vpfe_dev->v4l2_dev, "device already started\n"); | ||
1668 | return -EBUSY; | ||
1669 | } | ||
1670 | |||
1671 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1672 | if (ret) | ||
1673 | return ret; | ||
1674 | |||
1675 | switch (cmd) { | ||
1676 | case VPFE_CMD_S_CCDC_RAW_PARAMS: | ||
1677 | v4l2_warn(&vpfe_dev->v4l2_dev, | ||
1678 | "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); | ||
1679 | ret = ccdc_dev->hw_ops.set_params(param); | ||
1680 | if (ret) { | ||
1681 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1682 | "Error in setting parameters in CCDC\n"); | ||
1683 | goto unlock_out; | ||
1684 | } | ||
1685 | if (vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt) < 0) { | ||
1686 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1687 | "Invalid image format at CCDC\n"); | ||
1688 | goto unlock_out; | ||
1689 | } | ||
1690 | break; | ||
1691 | default: | ||
1692 | ret = -EINVAL; | ||
1693 | } | ||
1694 | unlock_out: | ||
1695 | mutex_unlock(&vpfe_dev->lock); | ||
1696 | return ret; | ||
1697 | } | ||
1698 | |||
1699 | |||
1700 | /* vpfe capture ioctl operations */ | ||
1701 | static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { | ||
1702 | .vidioc_querycap = vpfe_querycap, | ||
1703 | .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap, | ||
1704 | .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap, | ||
1705 | .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap, | ||
1706 | .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap, | ||
1707 | .vidioc_enum_input = vpfe_enum_input, | ||
1708 | .vidioc_g_input = vpfe_g_input, | ||
1709 | .vidioc_s_input = vpfe_s_input, | ||
1710 | .vidioc_querystd = vpfe_querystd, | ||
1711 | .vidioc_s_std = vpfe_s_std, | ||
1712 | .vidioc_g_std = vpfe_g_std, | ||
1713 | .vidioc_reqbufs = vpfe_reqbufs, | ||
1714 | .vidioc_querybuf = vpfe_querybuf, | ||
1715 | .vidioc_qbuf = vpfe_qbuf, | ||
1716 | .vidioc_dqbuf = vpfe_dqbuf, | ||
1717 | .vidioc_streamon = vpfe_streamon, | ||
1718 | .vidioc_streamoff = vpfe_streamoff, | ||
1719 | .vidioc_cropcap = vpfe_cropcap, | ||
1720 | .vidioc_g_crop = vpfe_g_crop, | ||
1721 | .vidioc_s_crop = vpfe_s_crop, | ||
1722 | .vidioc_default = vpfe_param_handler, | ||
1723 | }; | ||
1724 | |||
1725 | static struct vpfe_device *vpfe_initialize(void) | ||
1726 | { | ||
1727 | struct vpfe_device *vpfe_dev; | ||
1728 | |||
1729 | /* Default number of buffers should be 3 */ | ||
1730 | if ((numbuffers > 0) && | ||
1731 | (numbuffers < config_params.min_numbuffers)) | ||
1732 | numbuffers = config_params.min_numbuffers; | ||
1733 | |||
1734 | /* | ||
1735 | * Set buffer size to min buffers size if invalid buffer size is | ||
1736 | * given | ||
1737 | */ | ||
1738 | if (bufsize < config_params.min_bufsize) | ||
1739 | bufsize = config_params.min_bufsize; | ||
1740 | |||
1741 | config_params.numbuffers = numbuffers; | ||
1742 | |||
1743 | if (numbuffers) | ||
1744 | config_params.device_bufsize = bufsize; | ||
1745 | |||
1746 | /* Allocate memory for device objects */ | ||
1747 | vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); | ||
1748 | |||
1749 | return vpfe_dev; | ||
1750 | } | ||
1751 | |||
1752 | static void vpfe_disable_clock(struct vpfe_device *vpfe_dev) | ||
1753 | { | ||
1754 | struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; | ||
1755 | |||
1756 | clk_disable(vpfe_cfg->vpssclk); | ||
1757 | clk_put(vpfe_cfg->vpssclk); | ||
1758 | clk_disable(vpfe_cfg->slaveclk); | ||
1759 | clk_put(vpfe_cfg->slaveclk); | ||
1760 | v4l2_info(vpfe_dev->pdev->driver, | ||
1761 | "vpfe vpss master & slave clocks disabled\n"); | ||
1762 | } | ||
1763 | |||
1764 | static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) | ||
1765 | { | ||
1766 | struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; | ||
1767 | int ret = -ENOENT; | ||
1768 | |||
1769 | vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master"); | ||
1770 | if (NULL == vpfe_cfg->vpssclk) { | ||
1771 | v4l2_err(vpfe_dev->pdev->driver, "No clock defined for" | ||
1772 | "vpss_master\n"); | ||
1773 | return ret; | ||
1774 | } | ||
1775 | |||
1776 | if (clk_enable(vpfe_cfg->vpssclk)) { | ||
1777 | v4l2_err(vpfe_dev->pdev->driver, | ||
1778 | "vpfe vpss master clock not enabled\n"); | ||
1779 | goto out; | ||
1780 | } | ||
1781 | v4l2_info(vpfe_dev->pdev->driver, | ||
1782 | "vpfe vpss master clock enabled\n"); | ||
1783 | |||
1784 | vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave"); | ||
1785 | if (NULL == vpfe_cfg->slaveclk) { | ||
1786 | v4l2_err(vpfe_dev->pdev->driver, | ||
1787 | "No clock defined for vpss slave\n"); | ||
1788 | goto out; | ||
1789 | } | ||
1790 | |||
1791 | if (clk_enable(vpfe_cfg->slaveclk)) { | ||
1792 | v4l2_err(vpfe_dev->pdev->driver, | ||
1793 | "vpfe vpss slave clock not enabled\n"); | ||
1794 | goto out; | ||
1795 | } | ||
1796 | v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n"); | ||
1797 | return 0; | ||
1798 | out: | ||
1799 | if (vpfe_cfg->vpssclk) | ||
1800 | clk_put(vpfe_cfg->vpssclk); | ||
1801 | if (vpfe_cfg->slaveclk) | ||
1802 | clk_put(vpfe_cfg->slaveclk); | ||
1803 | |||
1804 | return -1; | ||
1805 | } | ||
1806 | |||
1807 | /* | ||
1808 | * vpfe_probe : This function creates device entries by register | ||
1809 | * itself to the V4L2 driver and initializes fields of each | ||
1810 | * device objects | ||
1811 | */ | ||
1812 | static __init int vpfe_probe(struct platform_device *pdev) | ||
1813 | { | ||
1814 | struct vpfe_subdev_info *sdinfo; | ||
1815 | struct vpfe_config *vpfe_cfg; | ||
1816 | struct resource *res1; | ||
1817 | struct vpfe_device *vpfe_dev; | ||
1818 | struct i2c_adapter *i2c_adap; | ||
1819 | struct video_device *vfd; | ||
1820 | int ret = -ENOMEM, i, j; | ||
1821 | int num_subdevs = 0; | ||
1822 | |||
1823 | /* Get the pointer to the device object */ | ||
1824 | vpfe_dev = vpfe_initialize(); | ||
1825 | |||
1826 | if (!vpfe_dev) { | ||
1827 | v4l2_err(pdev->dev.driver, | ||
1828 | "Failed to allocate memory for vpfe_dev\n"); | ||
1829 | return ret; | ||
1830 | } | ||
1831 | |||
1832 | vpfe_dev->pdev = &pdev->dev; | ||
1833 | |||
1834 | if (NULL == pdev->dev.platform_data) { | ||
1835 | v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); | ||
1836 | ret = -ENOENT; | ||
1837 | goto probe_free_dev_mem; | ||
1838 | } | ||
1839 | |||
1840 | vpfe_cfg = pdev->dev.platform_data; | ||
1841 | vpfe_dev->cfg = vpfe_cfg; | ||
1842 | if (NULL == vpfe_cfg->ccdc || | ||
1843 | NULL == vpfe_cfg->card_name || | ||
1844 | NULL == vpfe_cfg->sub_devs) { | ||
1845 | v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); | ||
1846 | ret = -ENOENT; | ||
1847 | goto probe_free_dev_mem; | ||
1848 | } | ||
1849 | |||
1850 | /* enable vpss clocks */ | ||
1851 | ret = vpfe_enable_clock(vpfe_dev); | ||
1852 | if (ret) | ||
1853 | goto probe_free_dev_mem; | ||
1854 | |||
1855 | mutex_lock(&ccdc_lock); | ||
1856 | /* Allocate memory for ccdc configuration */ | ||
1857 | ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); | ||
1858 | if (NULL == ccdc_cfg) { | ||
1859 | v4l2_err(pdev->dev.driver, | ||
1860 | "Memory allocation failed for ccdc_cfg\n"); | ||
1861 | goto probe_disable_clock; | ||
1862 | } | ||
1863 | |||
1864 | strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); | ||
1865 | /* Get VINT0 irq resource */ | ||
1866 | res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1867 | if (!res1) { | ||
1868 | v4l2_err(pdev->dev.driver, | ||
1869 | "Unable to get interrupt for VINT0\n"); | ||
1870 | ret = -ENOENT; | ||
1871 | goto probe_disable_clock; | ||
1872 | } | ||
1873 | vpfe_dev->ccdc_irq0 = res1->start; | ||
1874 | |||
1875 | /* Get VINT1 irq resource */ | ||
1876 | res1 = platform_get_resource(pdev, | ||
1877 | IORESOURCE_IRQ, 1); | ||
1878 | if (!res1) { | ||
1879 | v4l2_err(pdev->dev.driver, | ||
1880 | "Unable to get interrupt for VINT1\n"); | ||
1881 | ret = -ENOENT; | ||
1882 | goto probe_disable_clock; | ||
1883 | } | ||
1884 | vpfe_dev->ccdc_irq1 = res1->start; | ||
1885 | |||
1886 | /* Get address base of CCDC */ | ||
1887 | res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1888 | if (!res1) { | ||
1889 | v4l2_err(pdev->dev.driver, | ||
1890 | "Unable to get register address map\n"); | ||
1891 | ret = -ENOENT; | ||
1892 | goto probe_disable_clock; | ||
1893 | } | ||
1894 | |||
1895 | ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1; | ||
1896 | if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size, | ||
1897 | pdev->dev.driver->name)) { | ||
1898 | v4l2_err(pdev->dev.driver, | ||
1899 | "Failed request_mem_region for ccdc base\n"); | ||
1900 | ret = -ENXIO; | ||
1901 | goto probe_disable_clock; | ||
1902 | } | ||
1903 | ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start, | ||
1904 | ccdc_cfg->ccdc_addr_size); | ||
1905 | if (!ccdc_cfg->ccdc_addr) { | ||
1906 | v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc addr\n"); | ||
1907 | ret = -ENXIO; | ||
1908 | goto probe_out_release_mem1; | ||
1909 | } | ||
1910 | |||
1911 | ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, | ||
1912 | "vpfe_capture0", vpfe_dev); | ||
1913 | |||
1914 | if (0 != ret) { | ||
1915 | v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); | ||
1916 | goto probe_out_unmap1; | ||
1917 | } | ||
1918 | |||
1919 | /* Allocate memory for video device */ | ||
1920 | vfd = video_device_alloc(); | ||
1921 | if (NULL == vfd) { | ||
1922 | ret = -ENOMEM; | ||
1923 | v4l2_err(pdev->dev.driver, | ||
1924 | "Unable to alloc video device\n"); | ||
1925 | goto probe_out_release_irq; | ||
1926 | } | ||
1927 | |||
1928 | /* Initialize field of video device */ | ||
1929 | vfd->release = video_device_release; | ||
1930 | vfd->fops = &vpfe_fops; | ||
1931 | vfd->ioctl_ops = &vpfe_ioctl_ops; | ||
1932 | vfd->minor = -1; | ||
1933 | vfd->tvnorms = 0; | ||
1934 | vfd->current_norm = V4L2_STD_PAL; | ||
1935 | vfd->v4l2_dev = &vpfe_dev->v4l2_dev; | ||
1936 | snprintf(vfd->name, sizeof(vfd->name), | ||
1937 | "%s_V%d.%d.%d", | ||
1938 | CAPTURE_DRV_NAME, | ||
1939 | (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, | ||
1940 | (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, | ||
1941 | (VPFE_CAPTURE_VERSION_CODE) & 0xff); | ||
1942 | /* Set video_dev to the video device */ | ||
1943 | vpfe_dev->video_dev = vfd; | ||
1944 | |||
1945 | ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); | ||
1946 | if (ret) { | ||
1947 | v4l2_err(pdev->dev.driver, | ||
1948 | "Unable to register v4l2 device.\n"); | ||
1949 | goto probe_out_video_release; | ||
1950 | } | ||
1951 | v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); | ||
1952 | spin_lock_init(&vpfe_dev->irqlock); | ||
1953 | spin_lock_init(&vpfe_dev->dma_queue_lock); | ||
1954 | mutex_init(&vpfe_dev->lock); | ||
1955 | |||
1956 | /* Initialize field of the device objects */ | ||
1957 | vpfe_dev->numbuffers = config_params.numbuffers; | ||
1958 | |||
1959 | /* Initialize prio member of device object */ | ||
1960 | v4l2_prio_init(&vpfe_dev->prio); | ||
1961 | /* register video device */ | ||
1962 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1963 | "trying to register vpfe device.\n"); | ||
1964 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1965 | "video_dev=%x\n", (int)&vpfe_dev->video_dev); | ||
1966 | vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1967 | ret = video_register_device(vpfe_dev->video_dev, | ||
1968 | VFL_TYPE_GRABBER, -1); | ||
1969 | |||
1970 | if (ret) { | ||
1971 | v4l2_err(pdev->dev.driver, | ||
1972 | "Unable to register video device.\n"); | ||
1973 | goto probe_out_v4l2_unregister; | ||
1974 | } | ||
1975 | |||
1976 | v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); | ||
1977 | /* set the driver data in platform device */ | ||
1978 | platform_set_drvdata(pdev, vpfe_dev); | ||
1979 | /* set driver private data */ | ||
1980 | video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); | ||
1981 | i2c_adap = i2c_get_adapter(1); | ||
1982 | vpfe_cfg = pdev->dev.platform_data; | ||
1983 | num_subdevs = vpfe_cfg->num_subdevs; | ||
1984 | vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, | ||
1985 | GFP_KERNEL); | ||
1986 | if (NULL == vpfe_dev->sd) { | ||
1987 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1988 | "unable to allocate memory for subdevice pointers\n"); | ||
1989 | ret = -ENOMEM; | ||
1990 | goto probe_out_video_unregister; | ||
1991 | } | ||
1992 | |||
1993 | for (i = 0; i < num_subdevs; i++) { | ||
1994 | struct v4l2_input *inps; | ||
1995 | |||
1996 | sdinfo = &vpfe_cfg->sub_devs[i]; | ||
1997 | |||
1998 | /* Load up the subdevice */ | ||
1999 | vpfe_dev->sd[i] = | ||
2000 | v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, | ||
2001 | i2c_adap, | ||
2002 | sdinfo->name, | ||
2003 | &sdinfo->board_info, | ||
2004 | NULL); | ||
2005 | if (vpfe_dev->sd[i]) { | ||
2006 | v4l2_info(&vpfe_dev->v4l2_dev, | ||
2007 | "v4l2 sub device %s registered\n", | ||
2008 | sdinfo->name); | ||
2009 | vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; | ||
2010 | /* update tvnorms from the sub devices */ | ||
2011 | for (j = 0; j < sdinfo->num_inputs; j++) { | ||
2012 | inps = &sdinfo->inputs[j]; | ||
2013 | vfd->tvnorms |= inps->std; | ||
2014 | } | ||
2015 | } else { | ||
2016 | v4l2_info(&vpfe_dev->v4l2_dev, | ||
2017 | "v4l2 sub device %s register fails\n", | ||
2018 | sdinfo->name); | ||
2019 | goto probe_sd_out; | ||
2020 | } | ||
2021 | } | ||
2022 | |||
2023 | /* set first sub device as current one */ | ||
2024 | vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; | ||
2025 | |||
2026 | /* We have at least one sub device to work with */ | ||
2027 | mutex_unlock(&ccdc_lock); | ||
2028 | return 0; | ||
2029 | |||
2030 | probe_sd_out: | ||
2031 | kfree(vpfe_dev->sd); | ||
2032 | probe_out_video_unregister: | ||
2033 | video_unregister_device(vpfe_dev->video_dev); | ||
2034 | probe_out_v4l2_unregister: | ||
2035 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); | ||
2036 | probe_out_video_release: | ||
2037 | if (vpfe_dev->video_dev->minor == -1) | ||
2038 | video_device_release(vpfe_dev->video_dev); | ||
2039 | probe_out_release_irq: | ||
2040 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); | ||
2041 | probe_out_unmap1: | ||
2042 | iounmap(ccdc_cfg->ccdc_addr); | ||
2043 | probe_out_release_mem1: | ||
2044 | release_mem_region(res1->start, res1->end - res1->start + 1); | ||
2045 | probe_disable_clock: | ||
2046 | vpfe_disable_clock(vpfe_dev); | ||
2047 | mutex_unlock(&ccdc_lock); | ||
2048 | kfree(ccdc_cfg); | ||
2049 | probe_free_dev_mem: | ||
2050 | kfree(vpfe_dev); | ||
2051 | return ret; | ||
2052 | } | ||
2053 | |||
2054 | /* | ||
2055 | * vpfe_remove : It un-register device from V4L2 driver | ||
2056 | */ | ||
2057 | static int vpfe_remove(struct platform_device *pdev) | ||
2058 | { | ||
2059 | struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); | ||
2060 | struct resource *res; | ||
2061 | |||
2062 | v4l2_info(pdev->dev.driver, "vpfe_remove\n"); | ||
2063 | |||
2064 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); | ||
2065 | kfree(vpfe_dev->sd); | ||
2066 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); | ||
2067 | video_unregister_device(vpfe_dev->video_dev); | ||
2068 | mutex_lock(&ccdc_lock); | ||
2069 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
2070 | release_mem_region(res->start, res->end - res->start + 1); | ||
2071 | iounmap(ccdc_cfg->ccdc_addr); | ||
2072 | mutex_unlock(&ccdc_lock); | ||
2073 | vpfe_disable_clock(vpfe_dev); | ||
2074 | kfree(vpfe_dev); | ||
2075 | kfree(ccdc_cfg); | ||
2076 | return 0; | ||
2077 | } | ||
2078 | |||
2079 | static int | ||
2080 | vpfe_suspend(struct device *dev) | ||
2081 | { | ||
2082 | /* add suspend code here later */ | ||
2083 | return -1; | ||
2084 | } | ||
2085 | |||
2086 | static int | ||
2087 | vpfe_resume(struct device *dev) | ||
2088 | { | ||
2089 | /* add resume code here later */ | ||
2090 | return -1; | ||
2091 | } | ||
2092 | |||
2093 | static struct dev_pm_ops vpfe_dev_pm_ops = { | ||
2094 | .suspend = vpfe_suspend, | ||
2095 | .resume = vpfe_resume, | ||
2096 | }; | ||
2097 | |||
2098 | static struct platform_driver vpfe_driver = { | ||
2099 | .driver = { | ||
2100 | .name = CAPTURE_DRV_NAME, | ||
2101 | .owner = THIS_MODULE, | ||
2102 | .pm = &vpfe_dev_pm_ops, | ||
2103 | }, | ||
2104 | .probe = vpfe_probe, | ||
2105 | .remove = __devexit_p(vpfe_remove), | ||
2106 | }; | ||
2107 | |||
2108 | static __init int vpfe_init(void) | ||
2109 | { | ||
2110 | printk(KERN_NOTICE "vpfe_init\n"); | ||
2111 | /* Register driver to the kernel */ | ||
2112 | return platform_driver_register(&vpfe_driver); | ||
2113 | } | ||
2114 | |||
2115 | /* | ||
2116 | * vpfe_cleanup : This function un-registers device driver | ||
2117 | */ | ||
2118 | static void vpfe_cleanup(void) | ||
2119 | { | ||
2120 | platform_driver_unregister(&vpfe_driver); | ||
2121 | } | ||
2122 | |||
2123 | module_init(vpfe_init); | ||
2124 | module_exit(vpfe_cleanup); | ||
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c new file mode 100644 index 000000000000..3b8eac31ecae --- /dev/null +++ b/drivers/media/video/davinci/vpif.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * vpif - DM646x Video Port Interface driver | ||
3 | * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) | ||
4 | * that receiveing video byte stream and two channels(2, 3) for video output. | ||
5 | * The hardware supports SDTV, HDTV formats, raw data capture. | ||
6 | * Currently, the driver supports NTSC and PAL standards. | ||
7 | * | ||
8 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation version 2. | ||
13 | * | ||
14 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
15 | * kind, whether express or implied; without even the implied warranty | ||
16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <mach/hardware.h> | ||
27 | |||
28 | #include "vpif.h" | ||
29 | |||
30 | MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | #define VPIF_CH0_MAX_MODES (22) | ||
34 | #define VPIF_CH1_MAX_MODES (02) | ||
35 | #define VPIF_CH2_MAX_MODES (15) | ||
36 | #define VPIF_CH3_MAX_MODES (02) | ||
37 | |||
38 | static resource_size_t res_len; | ||
39 | static struct resource *res; | ||
40 | spinlock_t vpif_lock; | ||
41 | |||
42 | void __iomem *vpif_base; | ||
43 | |||
44 | static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) | ||
45 | { | ||
46 | if (val) | ||
47 | vpif_set_bit(reg, bit); | ||
48 | else | ||
49 | vpif_clr_bit(reg, bit); | ||
50 | } | ||
51 | |||
52 | /* This structure is used to keep track of VPIF size register's offsets */ | ||
53 | struct vpif_registers { | ||
54 | u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; | ||
55 | u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; | ||
56 | u32 vanc1_size, width_mask, len_mask; | ||
57 | u8 max_modes; | ||
58 | }; | ||
59 | |||
60 | static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { | ||
61 | /* Channel0 */ | ||
62 | { | ||
63 | VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, | ||
64 | VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, | ||
65 | VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, | ||
66 | VPIF_CH0_MAX_MODES, | ||
67 | }, | ||
68 | /* Channel1 */ | ||
69 | { | ||
70 | VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, | ||
71 | VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, | ||
72 | VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, | ||
73 | VPIF_CH1_MAX_MODES, | ||
74 | }, | ||
75 | /* Channel2 */ | ||
76 | { | ||
77 | VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, | ||
78 | VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, | ||
79 | VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, | ||
80 | VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, | ||
81 | VPIF_CH2_MAX_MODES | ||
82 | }, | ||
83 | /* Channel3 */ | ||
84 | { | ||
85 | VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, | ||
86 | VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, | ||
87 | VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, | ||
88 | VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, | ||
89 | VPIF_CH3_MAX_MODES | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | /* vpif_set_mode_info: | ||
94 | * This function is used to set horizontal and vertical config parameters | ||
95 | * As per the standard in the channel, configure the values of L1, L3, | ||
96 | * L5, L7 L9, L11 in VPIF Register , also write width and height | ||
97 | */ | ||
98 | static void vpif_set_mode_info(const struct vpif_channel_config_params *config, | ||
99 | u8 channel_id, u8 config_channel_id) | ||
100 | { | ||
101 | u32 value; | ||
102 | |||
103 | value = (config->eav2sav & vpifregs[config_channel_id].width_mask); | ||
104 | value <<= VPIF_CH_LEN_SHIFT; | ||
105 | value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); | ||
106 | regw(value, vpifregs[channel_id].h_cfg); | ||
107 | |||
108 | value = (config->l1 & vpifregs[config_channel_id].len_mask); | ||
109 | value <<= VPIF_CH_LEN_SHIFT; | ||
110 | value |= (config->l3 & vpifregs[config_channel_id].len_mask); | ||
111 | regw(value, vpifregs[channel_id].v_cfg_00); | ||
112 | |||
113 | value = (config->l5 & vpifregs[config_channel_id].len_mask); | ||
114 | value <<= VPIF_CH_LEN_SHIFT; | ||
115 | value |= (config->l7 & vpifregs[config_channel_id].len_mask); | ||
116 | regw(value, vpifregs[channel_id].v_cfg_01); | ||
117 | |||
118 | value = (config->l9 & vpifregs[config_channel_id].len_mask); | ||
119 | value <<= VPIF_CH_LEN_SHIFT; | ||
120 | value |= (config->l11 & vpifregs[config_channel_id].len_mask); | ||
121 | regw(value, vpifregs[channel_id].v_cfg_02); | ||
122 | |||
123 | value = (config->vsize & vpifregs[config_channel_id].len_mask); | ||
124 | regw(value, vpifregs[channel_id].v_cfg); | ||
125 | } | ||
126 | |||
127 | /* config_vpif_params | ||
128 | * Function to set the parameters of a channel | ||
129 | * Mainly modifies the channel ciontrol register | ||
130 | * It sets frame format, yc mux mode | ||
131 | */ | ||
132 | static void config_vpif_params(struct vpif_params *vpifparams, | ||
133 | u8 channel_id, u8 found) | ||
134 | { | ||
135 | const struct vpif_channel_config_params *config = &vpifparams->std_info; | ||
136 | u32 value, ch_nip, reg; | ||
137 | u8 start, end; | ||
138 | int i; | ||
139 | |||
140 | start = channel_id; | ||
141 | end = channel_id + found; | ||
142 | |||
143 | for (i = start; i < end; i++) { | ||
144 | reg = vpifregs[i].ch_ctrl; | ||
145 | if (channel_id < 2) | ||
146 | ch_nip = VPIF_CAPTURE_CH_NIP; | ||
147 | else | ||
148 | ch_nip = VPIF_DISPLAY_CH_NIP; | ||
149 | |||
150 | vpif_wr_bit(reg, ch_nip, config->frm_fmt); | ||
151 | vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); | ||
152 | vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, | ||
153 | vpifparams->video_params.storage_mode); | ||
154 | |||
155 | /* Set raster scanning SDR Format */ | ||
156 | vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); | ||
157 | vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); | ||
158 | |||
159 | if (channel_id > 1) /* Set the Pixel enable bit */ | ||
160 | vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); | ||
161 | else if (config->capture_format) { | ||
162 | /* Set the polarity of various pins */ | ||
163 | vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, | ||
164 | vpifparams->iface.fid_pol); | ||
165 | vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, | ||
166 | vpifparams->iface.vd_pol); | ||
167 | vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, | ||
168 | vpifparams->iface.hd_pol); | ||
169 | |||
170 | value = regr(reg); | ||
171 | /* Set data width */ | ||
172 | value &= ((~(unsigned int)(0x3)) << | ||
173 | VPIF_CH_DATA_WIDTH_BIT); | ||
174 | value |= ((vpifparams->params.data_sz) << | ||
175 | VPIF_CH_DATA_WIDTH_BIT); | ||
176 | regw(value, reg); | ||
177 | } | ||
178 | |||
179 | /* Write the pitch in the driver */ | ||
180 | regw((vpifparams->video_params.hpitch), | ||
181 | vpifregs[i].line_offset); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /* vpif_set_video_params | ||
186 | * This function is used to set video parameters in VPIF register | ||
187 | */ | ||
188 | int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) | ||
189 | { | ||
190 | const struct vpif_channel_config_params *config = &vpifparams->std_info; | ||
191 | int found = 1; | ||
192 | |||
193 | vpif_set_mode_info(config, channel_id, channel_id); | ||
194 | if (!config->ycmux_mode) { | ||
195 | /* YC are on separate channels (HDTV formats) */ | ||
196 | vpif_set_mode_info(config, channel_id + 1, channel_id); | ||
197 | found = 2; | ||
198 | } | ||
199 | |||
200 | config_vpif_params(vpifparams, channel_id, found); | ||
201 | |||
202 | regw(0x80, VPIF_REQ_SIZE); | ||
203 | regw(0x01, VPIF_EMULATION_CTRL); | ||
204 | |||
205 | return found; | ||
206 | } | ||
207 | EXPORT_SYMBOL(vpif_set_video_params); | ||
208 | |||
209 | void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, | ||
210 | u8 channel_id) | ||
211 | { | ||
212 | u32 value; | ||
213 | |||
214 | value = 0x3F8 & (vbiparams->hstart0); | ||
215 | value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); | ||
216 | regw(value, vpifregs[channel_id].vanc0_strt); | ||
217 | |||
218 | value = 0x3F8 & (vbiparams->hstart1); | ||
219 | value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); | ||
220 | regw(value, vpifregs[channel_id].vanc1_strt); | ||
221 | |||
222 | value = 0x3F8 & (vbiparams->hsize0); | ||
223 | value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); | ||
224 | regw(value, vpifregs[channel_id].vanc0_size); | ||
225 | |||
226 | value = 0x3F8 & (vbiparams->hsize1); | ||
227 | value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); | ||
228 | regw(value, vpifregs[channel_id].vanc1_size); | ||
229 | |||
230 | } | ||
231 | EXPORT_SYMBOL(vpif_set_vbi_display_params); | ||
232 | |||
233 | int vpif_channel_getfid(u8 channel_id) | ||
234 | { | ||
235 | return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) | ||
236 | >> VPIF_CH_FID_SHIFT; | ||
237 | } | ||
238 | EXPORT_SYMBOL(vpif_channel_getfid); | ||
239 | |||
240 | static int __init vpif_probe(struct platform_device *pdev) | ||
241 | { | ||
242 | int status = 0; | ||
243 | |||
244 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
245 | if (!res) | ||
246 | return -ENOENT; | ||
247 | |||
248 | res_len = res->end - res->start + 1; | ||
249 | |||
250 | res = request_mem_region(res->start, res_len, res->name); | ||
251 | if (!res) | ||
252 | return -EBUSY; | ||
253 | |||
254 | vpif_base = ioremap(res->start, res_len); | ||
255 | if (!vpif_base) { | ||
256 | status = -EBUSY; | ||
257 | goto fail; | ||
258 | } | ||
259 | |||
260 | spin_lock_init(&vpif_lock); | ||
261 | dev_info(&pdev->dev, "vpif probe success\n"); | ||
262 | return 0; | ||
263 | |||
264 | fail: | ||
265 | release_mem_region(res->start, res_len); | ||
266 | return status; | ||
267 | } | ||
268 | |||
269 | static int vpif_remove(struct platform_device *pdev) | ||
270 | { | ||
271 | iounmap(vpif_base); | ||
272 | release_mem_region(res->start, res_len); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static struct platform_driver vpif_driver = { | ||
277 | .driver = { | ||
278 | .name = "vpif", | ||
279 | .owner = THIS_MODULE, | ||
280 | }, | ||
281 | .remove = __devexit_p(vpif_remove), | ||
282 | .probe = vpif_probe, | ||
283 | }; | ||
284 | |||
285 | static void vpif_exit(void) | ||
286 | { | ||
287 | platform_driver_unregister(&vpif_driver); | ||
288 | } | ||
289 | |||
290 | static int __init vpif_init(void) | ||
291 | { | ||
292 | return platform_driver_register(&vpif_driver); | ||
293 | } | ||
294 | subsys_initcall(vpif_init); | ||
295 | module_exit(vpif_exit); | ||
296 | |||
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h new file mode 100644 index 000000000000..188841b476e0 --- /dev/null +++ b/drivers/media/video/davinci/vpif.h | |||
@@ -0,0 +1,642 @@ | |||
1 | /* | ||
2 | * VPIF header file | ||
3 | * | ||
4 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef VPIF_H | ||
17 | #define VPIF_H | ||
18 | |||
19 | #include <linux/io.h> | ||
20 | #include <linux/videodev2.h> | ||
21 | #include <mach/hardware.h> | ||
22 | #include <mach/dm646x.h> | ||
23 | |||
24 | /* Maximum channel allowed */ | ||
25 | #define VPIF_NUM_CHANNELS (4) | ||
26 | #define VPIF_CAPTURE_NUM_CHANNELS (2) | ||
27 | #define VPIF_DISPLAY_NUM_CHANNELS (2) | ||
28 | |||
29 | /* Macros to read/write registers */ | ||
30 | extern void __iomem *vpif_base; | ||
31 | extern spinlock_t vpif_lock; | ||
32 | |||
33 | #define regr(reg) readl((reg) + vpif_base) | ||
34 | #define regw(value, reg) writel(value, (reg + vpif_base)) | ||
35 | |||
36 | /* Register Addresss Offsets */ | ||
37 | #define VPIF_PID (0x0000) | ||
38 | #define VPIF_CH0_CTRL (0x0004) | ||
39 | #define VPIF_CH1_CTRL (0x0008) | ||
40 | #define VPIF_CH2_CTRL (0x000C) | ||
41 | #define VPIF_CH3_CTRL (0x0010) | ||
42 | |||
43 | #define VPIF_INTEN (0x0020) | ||
44 | #define VPIF_INTEN_SET (0x0024) | ||
45 | #define VPIF_INTEN_CLR (0x0028) | ||
46 | #define VPIF_STATUS (0x002C) | ||
47 | #define VPIF_STATUS_CLR (0x0030) | ||
48 | #define VPIF_EMULATION_CTRL (0x0034) | ||
49 | #define VPIF_REQ_SIZE (0x0038) | ||
50 | |||
51 | #define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040) | ||
52 | #define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044) | ||
53 | #define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048) | ||
54 | #define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c) | ||
55 | #define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050) | ||
56 | #define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054) | ||
57 | #define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058) | ||
58 | #define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c) | ||
59 | #define VPIF_CH0_SP_CFG (0x0060) | ||
60 | #define VPIF_CH0_IMG_ADD_OFST (0x0064) | ||
61 | #define VPIF_CH0_HANC_ADD_OFST (0x0068) | ||
62 | #define VPIF_CH0_H_CFG (0x006c) | ||
63 | #define VPIF_CH0_V_CFG_00 (0x0070) | ||
64 | #define VPIF_CH0_V_CFG_01 (0x0074) | ||
65 | #define VPIF_CH0_V_CFG_02 (0x0078) | ||
66 | #define VPIF_CH0_V_CFG_03 (0x007c) | ||
67 | |||
68 | #define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080) | ||
69 | #define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084) | ||
70 | #define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088) | ||
71 | #define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c) | ||
72 | #define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090) | ||
73 | #define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094) | ||
74 | #define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098) | ||
75 | #define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c) | ||
76 | #define VPIF_CH1_SP_CFG (0x00a0) | ||
77 | #define VPIF_CH1_IMG_ADD_OFST (0x00a4) | ||
78 | #define VPIF_CH1_HANC_ADD_OFST (0x00a8) | ||
79 | #define VPIF_CH1_H_CFG (0x00ac) | ||
80 | #define VPIF_CH1_V_CFG_00 (0x00b0) | ||
81 | #define VPIF_CH1_V_CFG_01 (0x00b4) | ||
82 | #define VPIF_CH1_V_CFG_02 (0x00b8) | ||
83 | #define VPIF_CH1_V_CFG_03 (0x00bc) | ||
84 | |||
85 | #define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0) | ||
86 | #define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4) | ||
87 | #define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8) | ||
88 | #define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc) | ||
89 | #define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0) | ||
90 | #define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4) | ||
91 | #define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8) | ||
92 | #define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc) | ||
93 | #define VPIF_CH2_SP_CFG (0x00e0) | ||
94 | #define VPIF_CH2_IMG_ADD_OFST (0x00e4) | ||
95 | #define VPIF_CH2_HANC_ADD_OFST (0x00e8) | ||
96 | #define VPIF_CH2_H_CFG (0x00ec) | ||
97 | #define VPIF_CH2_V_CFG_00 (0x00f0) | ||
98 | #define VPIF_CH2_V_CFG_01 (0x00f4) | ||
99 | #define VPIF_CH2_V_CFG_02 (0x00f8) | ||
100 | #define VPIF_CH2_V_CFG_03 (0x00fc) | ||
101 | #define VPIF_CH2_HANC0_STRT (0x0100) | ||
102 | #define VPIF_CH2_HANC0_SIZE (0x0104) | ||
103 | #define VPIF_CH2_HANC1_STRT (0x0108) | ||
104 | #define VPIF_CH2_HANC1_SIZE (0x010c) | ||
105 | #define VPIF_CH2_VANC0_STRT (0x0110) | ||
106 | #define VPIF_CH2_VANC0_SIZE (0x0114) | ||
107 | #define VPIF_CH2_VANC1_STRT (0x0118) | ||
108 | #define VPIF_CH2_VANC1_SIZE (0x011c) | ||
109 | |||
110 | #define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140) | ||
111 | #define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144) | ||
112 | #define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148) | ||
113 | #define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c) | ||
114 | #define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150) | ||
115 | #define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154) | ||
116 | #define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158) | ||
117 | #define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c) | ||
118 | #define VPIF_CH3_SP_CFG (0x0160) | ||
119 | #define VPIF_CH3_IMG_ADD_OFST (0x0164) | ||
120 | #define VPIF_CH3_HANC_ADD_OFST (0x0168) | ||
121 | #define VPIF_CH3_H_CFG (0x016c) | ||
122 | #define VPIF_CH3_V_CFG_00 (0x0170) | ||
123 | #define VPIF_CH3_V_CFG_01 (0x0174) | ||
124 | #define VPIF_CH3_V_CFG_02 (0x0178) | ||
125 | #define VPIF_CH3_V_CFG_03 (0x017c) | ||
126 | #define VPIF_CH3_HANC0_STRT (0x0180) | ||
127 | #define VPIF_CH3_HANC0_SIZE (0x0184) | ||
128 | #define VPIF_CH3_HANC1_STRT (0x0188) | ||
129 | #define VPIF_CH3_HANC1_SIZE (0x018c) | ||
130 | #define VPIF_CH3_VANC0_STRT (0x0190) | ||
131 | #define VPIF_CH3_VANC0_SIZE (0x0194) | ||
132 | #define VPIF_CH3_VANC1_STRT (0x0198) | ||
133 | #define VPIF_CH3_VANC1_SIZE (0x019c) | ||
134 | |||
135 | #define VPIF_IODFT_CTRL (0x01c0) | ||
136 | |||
137 | /* Functions for bit Manipulation */ | ||
138 | static inline void vpif_set_bit(u32 reg, u32 bit) | ||
139 | { | ||
140 | regw((regr(reg)) | (0x01 << bit), reg); | ||
141 | } | ||
142 | |||
143 | static inline void vpif_clr_bit(u32 reg, u32 bit) | ||
144 | { | ||
145 | regw(((regr(reg)) & ~(0x01 << bit)), reg); | ||
146 | } | ||
147 | |||
148 | /* Macro for Generating mask */ | ||
149 | #ifdef GENERATE_MASK | ||
150 | #undef GENERATE_MASK | ||
151 | #endif | ||
152 | |||
153 | #define GENERATE_MASK(bits, pos) \ | ||
154 | ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos) | ||
155 | |||
156 | /* Bit positions in the channel control registers */ | ||
157 | #define VPIF_CH_DATA_MODE_BIT (2) | ||
158 | #define VPIF_CH_YC_MUX_BIT (3) | ||
159 | #define VPIF_CH_SDR_FMT_BIT (4) | ||
160 | #define VPIF_CH_HANC_EN_BIT (8) | ||
161 | #define VPIF_CH_VANC_EN_BIT (9) | ||
162 | |||
163 | #define VPIF_CAPTURE_CH_NIP (10) | ||
164 | #define VPIF_DISPLAY_CH_NIP (11) | ||
165 | |||
166 | #define VPIF_DISPLAY_PIX_EN_BIT (10) | ||
167 | |||
168 | #define VPIF_CH_INPUT_FIELD_FRAME_BIT (12) | ||
169 | |||
170 | #define VPIF_CH_FID_POLARITY_BIT (15) | ||
171 | #define VPIF_CH_V_VALID_POLARITY_BIT (14) | ||
172 | #define VPIF_CH_H_VALID_POLARITY_BIT (13) | ||
173 | #define VPIF_CH_DATA_WIDTH_BIT (28) | ||
174 | |||
175 | #define VPIF_CH_CLK_EDGE_CTRL_BIT (31) | ||
176 | |||
177 | /* Mask various length */ | ||
178 | #define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0) | ||
179 | #define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0) | ||
180 | #define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0) | ||
181 | #define VPIF_CH_LEN_SHIFT (16) | ||
182 | |||
183 | /* VPIF masks for registers */ | ||
184 | #define VPIF_REQ_SIZE_MASK (0x1ff) | ||
185 | |||
186 | /* bit posotion of interrupt vpif_ch_intr register */ | ||
187 | #define VPIF_INTEN_FRAME_CH0 (0x00000001) | ||
188 | #define VPIF_INTEN_FRAME_CH1 (0x00000002) | ||
189 | #define VPIF_INTEN_FRAME_CH2 (0x00000004) | ||
190 | #define VPIF_INTEN_FRAME_CH3 (0x00000008) | ||
191 | |||
192 | /* bit position of clock and channel enable in vpif_chn_ctrl register */ | ||
193 | |||
194 | #define VPIF_CH0_CLK_EN (0x00000002) | ||
195 | #define VPIF_CH0_EN (0x00000001) | ||
196 | #define VPIF_CH1_CLK_EN (0x00000002) | ||
197 | #define VPIF_CH1_EN (0x00000001) | ||
198 | #define VPIF_CH2_CLK_EN (0x00000002) | ||
199 | #define VPIF_CH2_EN (0x00000001) | ||
200 | #define VPIF_CH3_CLK_EN (0x00000002) | ||
201 | #define VPIF_CH3_EN (0x00000001) | ||
202 | #define VPIF_CH_CLK_EN (0x00000002) | ||
203 | #define VPIF_CH_EN (0x00000001) | ||
204 | |||
205 | #define VPIF_INT_TOP (0x00) | ||
206 | #define VPIF_INT_BOTTOM (0x01) | ||
207 | #define VPIF_INT_BOTH (0x02) | ||
208 | |||
209 | #define VPIF_CH0_INT_CTRL_SHIFT (6) | ||
210 | #define VPIF_CH1_INT_CTRL_SHIFT (6) | ||
211 | #define VPIF_CH2_INT_CTRL_SHIFT (6) | ||
212 | #define VPIF_CH3_INT_CTRL_SHIFT (6) | ||
213 | #define VPIF_CH_INT_CTRL_SHIFT (6) | ||
214 | |||
215 | /* enabled interrupt on both the fields on vpid_ch0_ctrl register */ | ||
216 | #define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ | ||
217 | (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) | ||
218 | |||
219 | /* enabled interrupt on both the fields on vpid_ch1_ctrl register */ | ||
220 | #define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\ | ||
221 | (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL)) | ||
222 | |||
223 | /* enabled interrupt on both the fields on vpid_ch0_ctrl register */ | ||
224 | #define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\ | ||
225 | (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL)) | ||
226 | |||
227 | /* enabled interrupt on both the fields on vpid_ch1_ctrl register */ | ||
228 | #define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\ | ||
229 | (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL)) | ||
230 | |||
231 | #define VPIF_CH_FID_MASK (0x20) | ||
232 | #define VPIF_CH_FID_SHIFT (5) | ||
233 | |||
234 | #define VPIF_NTSC_VBI_START_FIELD0 (1) | ||
235 | #define VPIF_NTSC_VBI_START_FIELD1 (263) | ||
236 | #define VPIF_PAL_VBI_START_FIELD0 (624) | ||
237 | #define VPIF_PAL_VBI_START_FIELD1 (311) | ||
238 | |||
239 | #define VPIF_NTSC_HBI_START_FIELD0 (1) | ||
240 | #define VPIF_NTSC_HBI_START_FIELD1 (263) | ||
241 | #define VPIF_PAL_HBI_START_FIELD0 (624) | ||
242 | #define VPIF_PAL_HBI_START_FIELD1 (311) | ||
243 | |||
244 | #define VPIF_NTSC_VBI_COUNT_FIELD0 (20) | ||
245 | #define VPIF_NTSC_VBI_COUNT_FIELD1 (19) | ||
246 | #define VPIF_PAL_VBI_COUNT_FIELD0 (24) | ||
247 | #define VPIF_PAL_VBI_COUNT_FIELD1 (25) | ||
248 | |||
249 | #define VPIF_NTSC_HBI_COUNT_FIELD0 (263) | ||
250 | #define VPIF_NTSC_HBI_COUNT_FIELD1 (262) | ||
251 | #define VPIF_PAL_HBI_COUNT_FIELD0 (312) | ||
252 | #define VPIF_PAL_HBI_COUNT_FIELD1 (313) | ||
253 | |||
254 | #define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720) | ||
255 | #define VPIF_PAL_VBI_SAMPLES_PER_LINE (720) | ||
256 | #define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268) | ||
257 | #define VPIF_PAL_HBI_SAMPLES_PER_LINE (280) | ||
258 | |||
259 | #define VPIF_CH_VANC_EN (0x20) | ||
260 | #define VPIF_DMA_REQ_SIZE (0x080) | ||
261 | #define VPIF_EMULATION_DISABLE (0x01) | ||
262 | |||
263 | extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS]; | ||
264 | |||
265 | /* inline function to enable/disable channel0 */ | ||
266 | static inline void enable_channel0(int enable) | ||
267 | { | ||
268 | if (enable) | ||
269 | regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL); | ||
270 | else | ||
271 | regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL); | ||
272 | } | ||
273 | |||
274 | /* inline function to enable/disable channel1 */ | ||
275 | static inline void enable_channel1(int enable) | ||
276 | { | ||
277 | if (enable) | ||
278 | regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL); | ||
279 | else | ||
280 | regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL); | ||
281 | } | ||
282 | |||
283 | /* inline function to enable interrupt for channel0 */ | ||
284 | static inline void channel0_intr_enable(int enable) | ||
285 | { | ||
286 | unsigned long flags; | ||
287 | |||
288 | spin_lock_irqsave(&vpif_lock, flags); | ||
289 | |||
290 | if (enable) { | ||
291 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
292 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
293 | |||
294 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN); | ||
295 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), | ||
296 | VPIF_INTEN_SET); | ||
297 | } else { | ||
298 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN); | ||
299 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), | ||
300 | VPIF_INTEN_SET); | ||
301 | } | ||
302 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
303 | } | ||
304 | |||
305 | /* inline function to enable interrupt for channel1 */ | ||
306 | static inline void channel1_intr_enable(int enable) | ||
307 | { | ||
308 | unsigned long flags; | ||
309 | |||
310 | spin_lock_irqsave(&vpif_lock, flags); | ||
311 | |||
312 | if (enable) { | ||
313 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
314 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
315 | |||
316 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN); | ||
317 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), | ||
318 | VPIF_INTEN_SET); | ||
319 | } else { | ||
320 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN); | ||
321 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), | ||
322 | VPIF_INTEN_SET); | ||
323 | } | ||
324 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
325 | } | ||
326 | |||
327 | /* inline function to set buffer addresses in case of Y/C non mux mode */ | ||
328 | static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, | ||
329 | unsigned long btm_strt_luma, | ||
330 | unsigned long top_strt_chroma, | ||
331 | unsigned long btm_strt_chroma) | ||
332 | { | ||
333 | regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); | ||
334 | regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); | ||
335 | regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); | ||
336 | regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); | ||
337 | } | ||
338 | |||
339 | /* inline function to set buffer addresses in VPIF registers for video data */ | ||
340 | static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, | ||
341 | unsigned long btm_strt_luma, | ||
342 | unsigned long top_strt_chroma, | ||
343 | unsigned long btm_strt_chroma) | ||
344 | { | ||
345 | regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); | ||
346 | regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); | ||
347 | regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA); | ||
348 | regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA); | ||
349 | } | ||
350 | |||
351 | static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma, | ||
352 | unsigned long btm_strt_luma, | ||
353 | unsigned long top_strt_chroma, | ||
354 | unsigned long btm_strt_chroma) | ||
355 | { | ||
356 | |||
357 | regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA); | ||
358 | regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA); | ||
359 | regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); | ||
360 | regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); | ||
361 | } | ||
362 | |||
363 | static inline void ch0_set_vbi_addr(unsigned long top_vbi, | ||
364 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
365 | { | ||
366 | regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC); | ||
367 | regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC); | ||
368 | } | ||
369 | |||
370 | static inline void ch0_set_hbi_addr(unsigned long top_vbi, | ||
371 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
372 | { | ||
373 | regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC); | ||
374 | regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC); | ||
375 | } | ||
376 | |||
377 | static inline void ch1_set_vbi_addr(unsigned long top_vbi, | ||
378 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
379 | { | ||
380 | regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC); | ||
381 | regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC); | ||
382 | } | ||
383 | |||
384 | static inline void ch1_set_hbi_addr(unsigned long top_vbi, | ||
385 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
386 | { | ||
387 | regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC); | ||
388 | regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC); | ||
389 | } | ||
390 | |||
391 | /* Inline function to enable raw vbi in the given channel */ | ||
392 | static inline void disable_raw_feature(u8 channel_id, u8 index) | ||
393 | { | ||
394 | u32 ctrl_reg; | ||
395 | if (0 == channel_id) | ||
396 | ctrl_reg = VPIF_CH0_CTRL; | ||
397 | else | ||
398 | ctrl_reg = VPIF_CH1_CTRL; | ||
399 | |||
400 | if (1 == index) | ||
401 | vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); | ||
402 | else | ||
403 | vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); | ||
404 | } | ||
405 | |||
406 | static inline void enable_raw_feature(u8 channel_id, u8 index) | ||
407 | { | ||
408 | u32 ctrl_reg; | ||
409 | if (0 == channel_id) | ||
410 | ctrl_reg = VPIF_CH0_CTRL; | ||
411 | else | ||
412 | ctrl_reg = VPIF_CH1_CTRL; | ||
413 | |||
414 | if (1 == index) | ||
415 | vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); | ||
416 | else | ||
417 | vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); | ||
418 | } | ||
419 | |||
420 | /* inline function to enable/disable channel2 */ | ||
421 | static inline void enable_channel2(int enable) | ||
422 | { | ||
423 | if (enable) { | ||
424 | regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); | ||
425 | regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL); | ||
426 | } else { | ||
427 | regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); | ||
428 | regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | /* inline function to enable/disable channel3 */ | ||
433 | static inline void enable_channel3(int enable) | ||
434 | { | ||
435 | if (enable) { | ||
436 | regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); | ||
437 | regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL); | ||
438 | } else { | ||
439 | regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); | ||
440 | regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL); | ||
441 | } | ||
442 | } | ||
443 | |||
444 | /* inline function to enable interrupt for channel2 */ | ||
445 | static inline void channel2_intr_enable(int enable) | ||
446 | { | ||
447 | unsigned long flags; | ||
448 | |||
449 | spin_lock_irqsave(&vpif_lock, flags); | ||
450 | |||
451 | if (enable) { | ||
452 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
453 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
454 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN); | ||
455 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), | ||
456 | VPIF_INTEN_SET); | ||
457 | } else { | ||
458 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN); | ||
459 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), | ||
460 | VPIF_INTEN_SET); | ||
461 | } | ||
462 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
463 | } | ||
464 | |||
465 | /* inline function to enable interrupt for channel3 */ | ||
466 | static inline void channel3_intr_enable(int enable) | ||
467 | { | ||
468 | unsigned long flags; | ||
469 | |||
470 | spin_lock_irqsave(&vpif_lock, flags); | ||
471 | |||
472 | if (enable) { | ||
473 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
474 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
475 | |||
476 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN); | ||
477 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), | ||
478 | VPIF_INTEN_SET); | ||
479 | } else { | ||
480 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN); | ||
481 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), | ||
482 | VPIF_INTEN_SET); | ||
483 | } | ||
484 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
485 | } | ||
486 | |||
487 | /* inline function to enable raw vbi data for channel2 */ | ||
488 | static inline void channel2_raw_enable(int enable, u8 index) | ||
489 | { | ||
490 | u32 mask; | ||
491 | |||
492 | if (1 == index) | ||
493 | mask = VPIF_CH_VANC_EN_BIT; | ||
494 | else | ||
495 | mask = VPIF_CH_HANC_EN_BIT; | ||
496 | |||
497 | if (enable) | ||
498 | vpif_set_bit(VPIF_CH2_CTRL, mask); | ||
499 | else | ||
500 | vpif_clr_bit(VPIF_CH2_CTRL, mask); | ||
501 | } | ||
502 | |||
503 | /* inline function to enable raw vbi data for channel3*/ | ||
504 | static inline void channel3_raw_enable(int enable, u8 index) | ||
505 | { | ||
506 | u32 mask; | ||
507 | |||
508 | if (1 == index) | ||
509 | mask = VPIF_CH_VANC_EN_BIT; | ||
510 | else | ||
511 | mask = VPIF_CH_HANC_EN_BIT; | ||
512 | |||
513 | if (enable) | ||
514 | vpif_set_bit(VPIF_CH3_CTRL, mask); | ||
515 | else | ||
516 | vpif_clr_bit(VPIF_CH3_CTRL, mask); | ||
517 | } | ||
518 | |||
519 | /* inline function to set buffer addresses in case of Y/C non mux mode */ | ||
520 | static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, | ||
521 | unsigned long btm_strt_luma, | ||
522 | unsigned long top_strt_chroma, | ||
523 | unsigned long btm_strt_chroma) | ||
524 | { | ||
525 | regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); | ||
526 | regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); | ||
527 | regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); | ||
528 | regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); | ||
529 | } | ||
530 | |||
531 | /* inline function to set buffer addresses in VPIF registers for video data */ | ||
532 | static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, | ||
533 | unsigned long btm_strt_luma, | ||
534 | unsigned long top_strt_chroma, | ||
535 | unsigned long btm_strt_chroma) | ||
536 | { | ||
537 | regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); | ||
538 | regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); | ||
539 | regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA); | ||
540 | regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA); | ||
541 | } | ||
542 | |||
543 | static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, | ||
544 | unsigned long btm_strt_luma, | ||
545 | unsigned long top_strt_chroma, | ||
546 | unsigned long btm_strt_chroma) | ||
547 | { | ||
548 | regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA); | ||
549 | regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA); | ||
550 | regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); | ||
551 | regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); | ||
552 | } | ||
553 | |||
554 | /* inline function to set buffer addresses in VPIF registers for vbi data */ | ||
555 | static inline void ch2_set_vbi_addr(unsigned long top_strt_luma, | ||
556 | unsigned long btm_strt_luma, | ||
557 | unsigned long top_strt_chroma, | ||
558 | unsigned long btm_strt_chroma) | ||
559 | { | ||
560 | regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC); | ||
561 | regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC); | ||
562 | } | ||
563 | |||
564 | static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, | ||
565 | unsigned long btm_strt_luma, | ||
566 | unsigned long top_strt_chroma, | ||
567 | unsigned long btm_strt_chroma) | ||
568 | { | ||
569 | regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC); | ||
570 | regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); | ||
571 | } | ||
572 | |||
573 | #define VPIF_MAX_NAME (30) | ||
574 | |||
575 | /* This structure will store size parameters as per the mode selected by user */ | ||
576 | struct vpif_channel_config_params { | ||
577 | char name[VPIF_MAX_NAME]; /* Name of the mode */ | ||
578 | u16 width; /* Indicates width of the image */ | ||
579 | u16 height; /* Indicates height of the image */ | ||
580 | u8 fps; | ||
581 | u8 frm_fmt; /* Indicates whether this is interlaced | ||
582 | * or progressive format */ | ||
583 | u8 ycmux_mode; /* Indicates whether this mode requires | ||
584 | * single or two channels */ | ||
585 | u16 eav2sav; /* length of sav 2 eav */ | ||
586 | u16 sav2eav; /* length of sav 2 eav */ | ||
587 | u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */ | ||
588 | u16 vsize; /* Vertical size of the image */ | ||
589 | u8 capture_format; /* Indicates whether capture format | ||
590 | * is in BT or in CCD/CMOS */ | ||
591 | u8 vbi_supported; /* Indicates whether this mode | ||
592 | * supports capturing vbi or not */ | ||
593 | u8 hd_sd; | ||
594 | v4l2_std_id stdid; | ||
595 | }; | ||
596 | |||
597 | struct vpif_video_params; | ||
598 | struct vpif_params; | ||
599 | struct vpif_vbi_params; | ||
600 | |||
601 | int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id); | ||
602 | void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, | ||
603 | u8 channel_id); | ||
604 | int vpif_channel_getfid(u8 channel_id); | ||
605 | |||
606 | enum data_size { | ||
607 | _8BITS = 0, | ||
608 | _10BITS, | ||
609 | _12BITS, | ||
610 | }; | ||
611 | |||
612 | /* Structure for vpif parameters for raw vbi data */ | ||
613 | struct vpif_vbi_params { | ||
614 | __u32 hstart0; /* Horizontal start of raw vbi data for first field */ | ||
615 | __u32 vstart0; /* Vertical start of raw vbi data for first field */ | ||
616 | __u32 hsize0; /* Horizontal size of raw vbi data for first field */ | ||
617 | __u32 vsize0; /* Vertical size of raw vbi data for first field */ | ||
618 | __u32 hstart1; /* Horizontal start of raw vbi data for second field */ | ||
619 | __u32 vstart1; /* Vertical start of raw vbi data for second field */ | ||
620 | __u32 hsize1; /* Horizontal size of raw vbi data for second field */ | ||
621 | __u32 vsize1; /* Vertical size of raw vbi data for second field */ | ||
622 | }; | ||
623 | |||
624 | /* structure for vpif parameters */ | ||
625 | struct vpif_video_params { | ||
626 | __u8 storage_mode; /* Indicates field or frame mode */ | ||
627 | unsigned long hpitch; | ||
628 | v4l2_std_id stdid; | ||
629 | }; | ||
630 | |||
631 | struct vpif_params { | ||
632 | struct vpif_interface iface; | ||
633 | struct vpif_video_params video_params; | ||
634 | struct vpif_channel_config_params std_info; | ||
635 | union param { | ||
636 | struct vpif_vbi_params vbi_params; | ||
637 | enum data_size data_sz; | ||
638 | } params; | ||
639 | }; | ||
640 | |||
641 | #endif /* End of #ifndef VPIF_H */ | ||
642 | |||
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c new file mode 100644 index 000000000000..d947ee5e4eb4 --- /dev/null +++ b/drivers/media/video/davinci/vpif_capture.c | |||
@@ -0,0 +1,2168 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Texas Instruments Inc | ||
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 | * TODO : add support for VBI & HBI data service | ||
19 | * add static buffer allocation | ||
20 | */ | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/videodev2.h> | ||
31 | #include <linux/wait.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <linux/i2c.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/io.h> | ||
36 | #include <linux/version.h> | ||
37 | #include <media/v4l2-device.h> | ||
38 | #include <media/v4l2-ioctl.h> | ||
39 | |||
40 | #include "vpif_capture.h" | ||
41 | #include "vpif.h" | ||
42 | |||
43 | MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) | ||
47 | #define vpif_dbg(level, debug, fmt, arg...) \ | ||
48 | v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) | ||
49 | |||
50 | static int debug = 1; | ||
51 | static u32 ch0_numbuffers = 3; | ||
52 | static u32 ch1_numbuffers = 3; | ||
53 | static u32 ch0_bufsize = 1920 * 1080 * 2; | ||
54 | static u32 ch1_bufsize = 720 * 576 * 2; | ||
55 | |||
56 | module_param(debug, int, 0644); | ||
57 | module_param(ch0_numbuffers, uint, S_IRUGO); | ||
58 | module_param(ch1_numbuffers, uint, S_IRUGO); | ||
59 | module_param(ch0_bufsize, uint, S_IRUGO); | ||
60 | module_param(ch1_bufsize, uint, S_IRUGO); | ||
61 | |||
62 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
63 | MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)"); | ||
64 | MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)"); | ||
65 | MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)"); | ||
66 | MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)"); | ||
67 | |||
68 | static struct vpif_config_params config_params = { | ||
69 | .min_numbuffers = 3, | ||
70 | .numbuffers[0] = 3, | ||
71 | .numbuffers[1] = 3, | ||
72 | .min_bufsize[0] = 720 * 480 * 2, | ||
73 | .min_bufsize[1] = 720 * 480 * 2, | ||
74 | .channel_bufsize[0] = 1920 * 1080 * 2, | ||
75 | .channel_bufsize[1] = 720 * 576 * 2, | ||
76 | }; | ||
77 | |||
78 | /* global variables */ | ||
79 | static struct vpif_device vpif_obj = { {NULL} }; | ||
80 | static struct device *vpif_dev; | ||
81 | |||
82 | /** | ||
83 | * ch_params: video standard configuration parameters for vpif | ||
84 | */ | ||
85 | static const struct vpif_channel_config_params ch_params[] = { | ||
86 | { | ||
87 | "NTSC_M", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, | ||
88 | 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, | ||
89 | }, | ||
90 | { | ||
91 | "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, | ||
92 | 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, | ||
93 | }, | ||
94 | }; | ||
95 | |||
96 | /** | ||
97 | * vpif_uservirt_to_phys : translate user/virtual address to phy address | ||
98 | * @virtp: user/virtual address | ||
99 | * | ||
100 | * This inline function is used to convert user space virtual address to | ||
101 | * physical address. | ||
102 | */ | ||
103 | static inline u32 vpif_uservirt_to_phys(u32 virtp) | ||
104 | { | ||
105 | unsigned long physp = 0; | ||
106 | struct mm_struct *mm = current->mm; | ||
107 | struct vm_area_struct *vma; | ||
108 | |||
109 | vma = find_vma(mm, virtp); | ||
110 | |||
111 | /* For kernel direct-mapped memory, take the easy way */ | ||
112 | if (virtp >= PAGE_OFFSET) | ||
113 | physp = virt_to_phys((void *)virtp); | ||
114 | else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) | ||
115 | /** | ||
116 | * this will catch, kernel-allocated, mmaped-to-usermode | ||
117 | * addresses | ||
118 | */ | ||
119 | physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); | ||
120 | else { | ||
121 | /* otherwise, use get_user_pages() for general userland pages */ | ||
122 | int res, nr_pages = 1; | ||
123 | struct page *pages; | ||
124 | |||
125 | down_read(¤t->mm->mmap_sem); | ||
126 | |||
127 | res = get_user_pages(current, current->mm, | ||
128 | virtp, nr_pages, 1, 0, &pages, NULL); | ||
129 | up_read(¤t->mm->mmap_sem); | ||
130 | |||
131 | if (res == nr_pages) | ||
132 | physp = __pa(page_address(&pages[0]) + | ||
133 | (virtp & ~PAGE_MASK)); | ||
134 | else { | ||
135 | vpif_err("get_user_pages failed\n"); | ||
136 | return 0; | ||
137 | } | ||
138 | } | ||
139 | return physp; | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * buffer_prepare : callback function for buffer prepare | ||
144 | * @q : buffer queue ptr | ||
145 | * @vb: ptr to video buffer | ||
146 | * @field: field info | ||
147 | * | ||
148 | * This is the callback function for buffer prepare when videobuf_qbuf() | ||
149 | * function is called. The buffer is prepared and user space virtual address | ||
150 | * or user address is converted into physical address | ||
151 | */ | ||
152 | static int vpif_buffer_prepare(struct videobuf_queue *q, | ||
153 | struct videobuf_buffer *vb, | ||
154 | enum v4l2_field field) | ||
155 | { | ||
156 | /* Get the file handle object and channel object */ | ||
157 | struct vpif_fh *fh = q->priv_data; | ||
158 | struct channel_obj *ch = fh->channel; | ||
159 | struct common_obj *common; | ||
160 | unsigned long addr; | ||
161 | |||
162 | |||
163 | vpif_dbg(2, debug, "vpif_buffer_prepare\n"); | ||
164 | |||
165 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
166 | |||
167 | /* If buffer is not initialized, initialize it */ | ||
168 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
169 | vb->width = common->width; | ||
170 | vb->height = common->height; | ||
171 | vb->size = vb->width * vb->height; | ||
172 | vb->field = field; | ||
173 | } | ||
174 | vb->state = VIDEOBUF_PREPARED; | ||
175 | /** | ||
176 | * if user pointer memory mechanism is used, get the physical | ||
177 | * address of the buffer | ||
178 | */ | ||
179 | if (V4L2_MEMORY_USERPTR == common->memory) { | ||
180 | if (0 == vb->baddr) { | ||
181 | vpif_dbg(1, debug, "buffer address is 0\n"); | ||
182 | return -EINVAL; | ||
183 | |||
184 | } | ||
185 | vb->boff = vpif_uservirt_to_phys(vb->baddr); | ||
186 | if (!IS_ALIGNED(vb->boff, 8)) | ||
187 | goto exit; | ||
188 | } | ||
189 | |||
190 | addr = vb->boff; | ||
191 | if (q->streaming) { | ||
192 | if (!IS_ALIGNED((addr + common->ytop_off), 8) || | ||
193 | !IS_ALIGNED((addr + common->ybtm_off), 8) || | ||
194 | !IS_ALIGNED((addr + common->ctop_off), 8) || | ||
195 | !IS_ALIGNED((addr + common->cbtm_off), 8)) | ||
196 | goto exit; | ||
197 | } | ||
198 | return 0; | ||
199 | exit: | ||
200 | vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n"); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * vpif_buffer_setup : Callback function for buffer setup. | ||
206 | * @q: buffer queue ptr | ||
207 | * @count: number of buffers | ||
208 | * @size: size of the buffer | ||
209 | * | ||
210 | * This callback function is called when reqbuf() is called to adjust | ||
211 | * the buffer count and buffer size | ||
212 | */ | ||
213 | static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
214 | unsigned int *size) | ||
215 | { | ||
216 | /* Get the file handle object and channel object */ | ||
217 | struct vpif_fh *fh = q->priv_data; | ||
218 | struct channel_obj *ch = fh->channel; | ||
219 | struct common_obj *common; | ||
220 | |||
221 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
222 | |||
223 | vpif_dbg(2, debug, "vpif_buffer_setup\n"); | ||
224 | |||
225 | /* If memory type is not mmap, return */ | ||
226 | if (V4L2_MEMORY_MMAP != common->memory) | ||
227 | return 0; | ||
228 | |||
229 | /* Calculate the size of the buffer */ | ||
230 | *size = config_params.channel_bufsize[ch->channel_id]; | ||
231 | |||
232 | if (*count < config_params.min_numbuffers) | ||
233 | *count = config_params.min_numbuffers; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /** | ||
238 | * vpif_buffer_queue : Callback function to add buffer to DMA queue | ||
239 | * @q: ptr to videobuf_queue | ||
240 | * @vb: ptr to videobuf_buffer | ||
241 | */ | ||
242 | static void vpif_buffer_queue(struct videobuf_queue *q, | ||
243 | struct videobuf_buffer *vb) | ||
244 | { | ||
245 | /* Get the file handle object and channel object */ | ||
246 | struct vpif_fh *fh = q->priv_data; | ||
247 | struct channel_obj *ch = fh->channel; | ||
248 | struct common_obj *common; | ||
249 | |||
250 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
251 | |||
252 | vpif_dbg(2, debug, "vpif_buffer_queue\n"); | ||
253 | |||
254 | /* add the buffer to the DMA queue */ | ||
255 | list_add_tail(&vb->queue, &common->dma_queue); | ||
256 | /* Change state of the buffer */ | ||
257 | vb->state = VIDEOBUF_QUEUED; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * vpif_buffer_release : Callback function to free buffer | ||
262 | * @q: buffer queue ptr | ||
263 | * @vb: ptr to video buffer | ||
264 | * | ||
265 | * This function is called from the videobuf layer to free memory | ||
266 | * allocated to the buffers | ||
267 | */ | ||
268 | static void vpif_buffer_release(struct videobuf_queue *q, | ||
269 | struct videobuf_buffer *vb) | ||
270 | { | ||
271 | /* Get the file handle object and channel object */ | ||
272 | struct vpif_fh *fh = q->priv_data; | ||
273 | struct channel_obj *ch = fh->channel; | ||
274 | struct common_obj *common; | ||
275 | |||
276 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
277 | |||
278 | videobuf_dma_contig_free(q, vb); | ||
279 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
280 | } | ||
281 | |||
282 | static struct videobuf_queue_ops video_qops = { | ||
283 | .buf_setup = vpif_buffer_setup, | ||
284 | .buf_prepare = vpif_buffer_prepare, | ||
285 | .buf_queue = vpif_buffer_queue, | ||
286 | .buf_release = vpif_buffer_release, | ||
287 | }; | ||
288 | |||
289 | static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = | ||
290 | { {1, 1} }; | ||
291 | |||
292 | /** | ||
293 | * vpif_process_buffer_complete: process a completed buffer | ||
294 | * @common: ptr to common channel object | ||
295 | * | ||
296 | * This function time stamp the buffer and mark it as DONE. It also | ||
297 | * wake up any process waiting on the QUEUE and set the next buffer | ||
298 | * as current | ||
299 | */ | ||
300 | static void vpif_process_buffer_complete(struct common_obj *common) | ||
301 | { | ||
302 | do_gettimeofday(&common->cur_frm->ts); | ||
303 | common->cur_frm->state = VIDEOBUF_DONE; | ||
304 | wake_up_interruptible(&common->cur_frm->done); | ||
305 | /* Make curFrm pointing to nextFrm */ | ||
306 | common->cur_frm = common->next_frm; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * vpif_schedule_next_buffer: set next buffer address for capture | ||
311 | * @common : ptr to common channel object | ||
312 | * | ||
313 | * This function will get next buffer from the dma queue and | ||
314 | * set the buffer address in the vpif register for capture. | ||
315 | * the buffer is marked active | ||
316 | */ | ||
317 | static void vpif_schedule_next_buffer(struct common_obj *common) | ||
318 | { | ||
319 | unsigned long addr = 0; | ||
320 | |||
321 | common->next_frm = list_entry(common->dma_queue.next, | ||
322 | struct videobuf_buffer, queue); | ||
323 | /* Remove that buffer from the buffer queue */ | ||
324 | list_del(&common->next_frm->queue); | ||
325 | common->next_frm->state = VIDEOBUF_ACTIVE; | ||
326 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
327 | addr = common->next_frm->boff; | ||
328 | else | ||
329 | addr = videobuf_to_dma_contig(common->next_frm); | ||
330 | |||
331 | /* Set top and bottom field addresses in VPIF registers */ | ||
332 | common->set_addr(addr + common->ytop_off, | ||
333 | addr + common->ybtm_off, | ||
334 | addr + common->ctop_off, | ||
335 | addr + common->cbtm_off); | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * vpif_channel_isr : ISR handler for vpif capture | ||
340 | * @irq: irq number | ||
341 | * @dev_id: dev_id ptr | ||
342 | * | ||
343 | * It changes status of the captured buffer, takes next buffer from the queue | ||
344 | * and sets its address in VPIF registers | ||
345 | */ | ||
346 | static irqreturn_t vpif_channel_isr(int irq, void *dev_id) | ||
347 | { | ||
348 | struct vpif_device *dev = &vpif_obj; | ||
349 | struct common_obj *common; | ||
350 | struct channel_obj *ch; | ||
351 | enum v4l2_field field; | ||
352 | int channel_id = 0; | ||
353 | int fid = -1, i; | ||
354 | |||
355 | channel_id = *(int *)(dev_id); | ||
356 | ch = dev->dev[channel_id]; | ||
357 | |||
358 | field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; | ||
359 | |||
360 | for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { | ||
361 | common = &ch->common[i]; | ||
362 | /* skip If streaming is not started in this channel */ | ||
363 | if (0 == common->started) | ||
364 | continue; | ||
365 | |||
366 | /* Check the field format */ | ||
367 | if (1 == ch->vpifparams.std_info.frm_fmt) { | ||
368 | /* Progressive mode */ | ||
369 | if (list_empty(&common->dma_queue)) | ||
370 | continue; | ||
371 | |||
372 | if (!channel_first_int[i][channel_id]) | ||
373 | vpif_process_buffer_complete(common); | ||
374 | |||
375 | channel_first_int[i][channel_id] = 0; | ||
376 | |||
377 | vpif_schedule_next_buffer(common); | ||
378 | |||
379 | |||
380 | channel_first_int[i][channel_id] = 0; | ||
381 | } else { | ||
382 | /** | ||
383 | * Interlaced mode. If it is first interrupt, ignore | ||
384 | * it | ||
385 | */ | ||
386 | if (channel_first_int[i][channel_id]) { | ||
387 | channel_first_int[i][channel_id] = 0; | ||
388 | continue; | ||
389 | } | ||
390 | if (0 == i) { | ||
391 | ch->field_id ^= 1; | ||
392 | /* Get field id from VPIF registers */ | ||
393 | fid = vpif_channel_getfid(ch->channel_id); | ||
394 | if (fid != ch->field_id) { | ||
395 | /** | ||
396 | * If field id does not match stored | ||
397 | * field id, make them in sync | ||
398 | */ | ||
399 | if (0 == fid) | ||
400 | ch->field_id = fid; | ||
401 | return IRQ_HANDLED; | ||
402 | } | ||
403 | } | ||
404 | /* device field id and local field id are in sync */ | ||
405 | if (0 == fid) { | ||
406 | /* this is even field */ | ||
407 | if (common->cur_frm == common->next_frm) | ||
408 | continue; | ||
409 | |||
410 | /* mark the current buffer as done */ | ||
411 | vpif_process_buffer_complete(common); | ||
412 | } else if (1 == fid) { | ||
413 | /* odd field */ | ||
414 | if (list_empty(&common->dma_queue) || | ||
415 | (common->cur_frm != common->next_frm)) | ||
416 | continue; | ||
417 | |||
418 | vpif_schedule_next_buffer(common); | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | return IRQ_HANDLED; | ||
423 | } | ||
424 | |||
425 | /** | ||
426 | * vpif_update_std_info() - update standard related info | ||
427 | * @ch: ptr to channel object | ||
428 | * | ||
429 | * For a given standard selected by application, update values | ||
430 | * in the device data structures | ||
431 | */ | ||
432 | static int vpif_update_std_info(struct channel_obj *ch) | ||
433 | { | ||
434 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
435 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
436 | const struct vpif_channel_config_params *config; | ||
437 | struct vpif_channel_config_params *std_info; | ||
438 | struct video_obj *vid_ch = &ch->video; | ||
439 | int index; | ||
440 | |||
441 | vpif_dbg(2, debug, "vpif_update_std_info\n"); | ||
442 | |||
443 | std_info = &vpifparams->std_info; | ||
444 | |||
445 | for (index = 0; index < ARRAY_SIZE(ch_params); index++) { | ||
446 | config = &ch_params[index]; | ||
447 | if (config->stdid & vid_ch->stdid) { | ||
448 | memcpy(std_info, config, sizeof(*config)); | ||
449 | break; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | /* standard not found */ | ||
454 | if (index == ARRAY_SIZE(ch_params)) | ||
455 | return -EINVAL; | ||
456 | |||
457 | common->fmt.fmt.pix.width = std_info->width; | ||
458 | common->width = std_info->width; | ||
459 | common->fmt.fmt.pix.height = std_info->height; | ||
460 | common->height = std_info->height; | ||
461 | common->fmt.fmt.pix.bytesperline = std_info->width; | ||
462 | vpifparams->video_params.hpitch = std_info->width; | ||
463 | vpifparams->video_params.storage_mode = std_info->frm_fmt; | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * vpif_calculate_offsets : This function calculates buffers offsets | ||
469 | * @ch : ptr to channel object | ||
470 | * | ||
471 | * This function calculates buffer offsets for Y and C in the top and | ||
472 | * bottom field | ||
473 | */ | ||
474 | static void vpif_calculate_offsets(struct channel_obj *ch) | ||
475 | { | ||
476 | unsigned int hpitch, vpitch, sizeimage; | ||
477 | struct video_obj *vid_ch = &(ch->video); | ||
478 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
479 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
480 | enum v4l2_field field = common->fmt.fmt.pix.field; | ||
481 | |||
482 | vpif_dbg(2, debug, "vpif_calculate_offsets\n"); | ||
483 | |||
484 | if (V4L2_FIELD_ANY == field) { | ||
485 | if (vpifparams->std_info.frm_fmt) | ||
486 | vid_ch->buf_field = V4L2_FIELD_NONE; | ||
487 | else | ||
488 | vid_ch->buf_field = V4L2_FIELD_INTERLACED; | ||
489 | } else | ||
490 | vid_ch->buf_field = common->fmt.fmt.pix.field; | ||
491 | |||
492 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
493 | sizeimage = common->fmt.fmt.pix.sizeimage; | ||
494 | else | ||
495 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
496 | |||
497 | hpitch = common->fmt.fmt.pix.bytesperline; | ||
498 | vpitch = sizeimage / (hpitch * 2); | ||
499 | |||
500 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
501 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { | ||
502 | /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ | ||
503 | common->ytop_off = 0; | ||
504 | common->ybtm_off = hpitch; | ||
505 | common->ctop_off = sizeimage / 2; | ||
506 | common->cbtm_off = sizeimage / 2 + hpitch; | ||
507 | } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { | ||
508 | /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ | ||
509 | common->ytop_off = 0; | ||
510 | common->ybtm_off = sizeimage / 4; | ||
511 | common->ctop_off = sizeimage / 2; | ||
512 | common->cbtm_off = common->ctop_off + sizeimage / 4; | ||
513 | } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { | ||
514 | /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ | ||
515 | common->ybtm_off = 0; | ||
516 | common->ytop_off = sizeimage / 4; | ||
517 | common->cbtm_off = sizeimage / 2; | ||
518 | common->ctop_off = common->cbtm_off + sizeimage / 4; | ||
519 | } | ||
520 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
521 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) | ||
522 | vpifparams->video_params.storage_mode = 1; | ||
523 | else | ||
524 | vpifparams->video_params.storage_mode = 0; | ||
525 | |||
526 | if (1 == vpifparams->std_info.frm_fmt) | ||
527 | vpifparams->video_params.hpitch = | ||
528 | common->fmt.fmt.pix.bytesperline; | ||
529 | else { | ||
530 | if ((field == V4L2_FIELD_ANY) | ||
531 | || (field == V4L2_FIELD_INTERLACED)) | ||
532 | vpifparams->video_params.hpitch = | ||
533 | common->fmt.fmt.pix.bytesperline * 2; | ||
534 | else | ||
535 | vpifparams->video_params.hpitch = | ||
536 | common->fmt.fmt.pix.bytesperline; | ||
537 | } | ||
538 | |||
539 | ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid; | ||
540 | } | ||
541 | |||
542 | /** | ||
543 | * vpif_config_format: configure default frame format in the device | ||
544 | * ch : ptr to channel object | ||
545 | */ | ||
546 | static void vpif_config_format(struct channel_obj *ch) | ||
547 | { | ||
548 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
549 | |||
550 | vpif_dbg(2, debug, "vpif_config_format\n"); | ||
551 | |||
552 | common->fmt.fmt.pix.field = V4L2_FIELD_ANY; | ||
553 | if (config_params.numbuffers[ch->channel_id] == 0) | ||
554 | common->memory = V4L2_MEMORY_USERPTR; | ||
555 | else | ||
556 | common->memory = V4L2_MEMORY_MMAP; | ||
557 | |||
558 | common->fmt.fmt.pix.sizeimage | ||
559 | = config_params.channel_bufsize[ch->channel_id]; | ||
560 | |||
561 | if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) | ||
562 | common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
563 | else | ||
564 | common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; | ||
565 | common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
566 | } | ||
567 | |||
568 | /** | ||
569 | * vpif_get_default_field() - Get default field type based on interface | ||
570 | * @vpif_params - ptr to vpif params | ||
571 | */ | ||
572 | static inline enum v4l2_field vpif_get_default_field( | ||
573 | struct vpif_interface *iface) | ||
574 | { | ||
575 | return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE : | ||
576 | V4L2_FIELD_INTERLACED; | ||
577 | } | ||
578 | |||
579 | /** | ||
580 | * vpif_check_format() - check given pixel format for compatibility | ||
581 | * @ch - channel ptr | ||
582 | * @pixfmt - Given pixel format | ||
583 | * @update - update the values as per hardware requirement | ||
584 | * | ||
585 | * Check the application pixel format for S_FMT and update the input | ||
586 | * values as per hardware limits for TRY_FMT. The default pixel and | ||
587 | * field format is selected based on interface type. | ||
588 | */ | ||
589 | static int vpif_check_format(struct channel_obj *ch, | ||
590 | struct v4l2_pix_format *pixfmt, | ||
591 | int update) | ||
592 | { | ||
593 | struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
594 | struct vpif_params *vpif_params = &ch->vpifparams; | ||
595 | enum v4l2_field field = pixfmt->field; | ||
596 | u32 sizeimage, hpitch, vpitch; | ||
597 | int ret = -EINVAL; | ||
598 | |||
599 | vpif_dbg(2, debug, "vpif_check_format\n"); | ||
600 | /** | ||
601 | * first check for the pixel format. If if_type is Raw bayer, | ||
602 | * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only | ||
603 | * V4L2_PIX_FMT_YUV422P is supported | ||
604 | */ | ||
605 | if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) { | ||
606 | if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) { | ||
607 | if (!update) { | ||
608 | vpif_dbg(2, debug, "invalid pix format\n"); | ||
609 | goto exit; | ||
610 | } | ||
611 | pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
612 | } | ||
613 | } else { | ||
614 | if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) { | ||
615 | if (!update) { | ||
616 | vpif_dbg(2, debug, "invalid pixel format\n"); | ||
617 | goto exit; | ||
618 | } | ||
619 | pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P; | ||
620 | } | ||
621 | } | ||
622 | |||
623 | if (!(VPIF_VALID_FIELD(field))) { | ||
624 | if (!update) { | ||
625 | vpif_dbg(2, debug, "invalid field format\n"); | ||
626 | goto exit; | ||
627 | } | ||
628 | /** | ||
629 | * By default use FIELD_NONE for RAW Bayer capture | ||
630 | * and FIELD_INTERLACED for other interfaces | ||
631 | */ | ||
632 | field = vpif_get_default_field(&vpif_params->iface); | ||
633 | } else if (field == V4L2_FIELD_ANY) | ||
634 | /* unsupported field. Use default */ | ||
635 | field = vpif_get_default_field(&vpif_params->iface); | ||
636 | |||
637 | /* validate the hpitch */ | ||
638 | hpitch = pixfmt->bytesperline; | ||
639 | if (hpitch < vpif_params->std_info.width) { | ||
640 | if (!update) { | ||
641 | vpif_dbg(2, debug, "invalid hpitch\n"); | ||
642 | goto exit; | ||
643 | } | ||
644 | hpitch = vpif_params->std_info.width; | ||
645 | } | ||
646 | |||
647 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
648 | sizeimage = pixfmt->sizeimage; | ||
649 | else | ||
650 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
651 | |||
652 | vpitch = sizeimage / (hpitch * 2); | ||
653 | |||
654 | /* validate the vpitch */ | ||
655 | if (vpitch < vpif_params->std_info.height) { | ||
656 | if (!update) { | ||
657 | vpif_dbg(2, debug, "Invalid vpitch\n"); | ||
658 | goto exit; | ||
659 | } | ||
660 | vpitch = vpif_params->std_info.height; | ||
661 | } | ||
662 | |||
663 | /* Check for 8 byte alignment */ | ||
664 | if (!ALIGN(hpitch, 8)) { | ||
665 | if (!update) { | ||
666 | vpif_dbg(2, debug, "invalid pitch alignment\n"); | ||
667 | goto exit; | ||
668 | } | ||
669 | /* adjust to next 8 byte boundary */ | ||
670 | hpitch = (((hpitch + 7) / 8) * 8); | ||
671 | } | ||
672 | /* if update is set, modify the bytesperline and sizeimage */ | ||
673 | if (update) { | ||
674 | pixfmt->bytesperline = hpitch; | ||
675 | pixfmt->sizeimage = hpitch * vpitch * 2; | ||
676 | } | ||
677 | /** | ||
678 | * Image width and height is always based on current standard width and | ||
679 | * height | ||
680 | */ | ||
681 | pixfmt->width = common->fmt.fmt.pix.width; | ||
682 | pixfmt->height = common->fmt.fmt.pix.height; | ||
683 | return 0; | ||
684 | exit: | ||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | /** | ||
689 | * vpif_config_addr() - function to configure buffer address in vpif | ||
690 | * @ch - channel ptr | ||
691 | * @muxmode - channel mux mode | ||
692 | */ | ||
693 | static void vpif_config_addr(struct channel_obj *ch, int muxmode) | ||
694 | { | ||
695 | struct common_obj *common; | ||
696 | |||
697 | vpif_dbg(2, debug, "vpif_config_addr\n"); | ||
698 | |||
699 | common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
700 | |||
701 | if (VPIF_CHANNEL1_VIDEO == ch->channel_id) | ||
702 | common->set_addr = ch1_set_videobuf_addr; | ||
703 | else if (2 == muxmode) | ||
704 | common->set_addr = ch0_set_videobuf_addr_yc_nmux; | ||
705 | else | ||
706 | common->set_addr = ch0_set_videobuf_addr; | ||
707 | } | ||
708 | |||
709 | /** | ||
710 | * vpfe_mmap : It is used to map kernel space buffers into user spaces | ||
711 | * @filep: file pointer | ||
712 | * @vma: ptr to vm_area_struct | ||
713 | */ | ||
714 | static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) | ||
715 | { | ||
716 | /* Get the channel object and file handle object */ | ||
717 | struct vpif_fh *fh = filep->private_data; | ||
718 | struct channel_obj *ch = fh->channel; | ||
719 | struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
720 | |||
721 | vpif_dbg(2, debug, "vpif_mmap\n"); | ||
722 | |||
723 | return videobuf_mmap_mapper(&common->buffer_queue, vma); | ||
724 | } | ||
725 | |||
726 | /** | ||
727 | * vpif_poll: It is used for select/poll system call | ||
728 | * @filep: file pointer | ||
729 | * @wait: poll table to wait | ||
730 | */ | ||
731 | static unsigned int vpif_poll(struct file *filep, poll_table * wait) | ||
732 | { | ||
733 | int err = 0; | ||
734 | struct vpif_fh *fh = filep->private_data; | ||
735 | struct channel_obj *channel = fh->channel; | ||
736 | struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]); | ||
737 | |||
738 | vpif_dbg(2, debug, "vpif_poll\n"); | ||
739 | |||
740 | if (common->started) | ||
741 | err = videobuf_poll_stream(filep, &common->buffer_queue, wait); | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | /** | ||
747 | * vpif_open : vpif open handler | ||
748 | * @filep: file ptr | ||
749 | * | ||
750 | * It creates object of file handle structure and stores it in private_data | ||
751 | * member of filepointer | ||
752 | */ | ||
753 | static int vpif_open(struct file *filep) | ||
754 | { | ||
755 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
756 | struct video_device *vdev = video_devdata(filep); | ||
757 | struct common_obj *common; | ||
758 | struct video_obj *vid_ch; | ||
759 | struct channel_obj *ch; | ||
760 | struct vpif_fh *fh; | ||
761 | int i, ret = 0; | ||
762 | |||
763 | vpif_dbg(2, debug, "vpif_open\n"); | ||
764 | |||
765 | ch = video_get_drvdata(vdev); | ||
766 | |||
767 | vid_ch = &ch->video; | ||
768 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
769 | |||
770 | if (mutex_lock_interruptible(&common->lock)) | ||
771 | return -ERESTARTSYS; | ||
772 | |||
773 | if (NULL == ch->curr_subdev_info) { | ||
774 | /** | ||
775 | * search through the sub device to see a registered | ||
776 | * sub device and make it as current sub device | ||
777 | */ | ||
778 | for (i = 0; i < config->subdev_count; i++) { | ||
779 | if (vpif_obj.sd[i]) { | ||
780 | /* the sub device is registered */ | ||
781 | ch->curr_subdev_info = &config->subdev_info[i]; | ||
782 | /* make first input as the current input */ | ||
783 | vid_ch->input_idx = 0; | ||
784 | break; | ||
785 | } | ||
786 | } | ||
787 | if (i == config->subdev_count) { | ||
788 | vpif_err("No sub device registered\n"); | ||
789 | ret = -ENOENT; | ||
790 | goto exit; | ||
791 | } | ||
792 | } | ||
793 | |||
794 | /* Allocate memory for the file handle object */ | ||
795 | fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL); | ||
796 | if (NULL == fh) { | ||
797 | vpif_err("unable to allocate memory for file handle object\n"); | ||
798 | ret = -ENOMEM; | ||
799 | goto exit; | ||
800 | } | ||
801 | |||
802 | /* store pointer to fh in private_data member of filep */ | ||
803 | filep->private_data = fh; | ||
804 | fh->channel = ch; | ||
805 | fh->initialized = 0; | ||
806 | /* If decoder is not initialized. initialize it */ | ||
807 | if (!ch->initialized) { | ||
808 | fh->initialized = 1; | ||
809 | ch->initialized = 1; | ||
810 | memset(&(ch->vpifparams), 0, sizeof(struct vpif_params)); | ||
811 | } | ||
812 | /* Increment channel usrs counter */ | ||
813 | ch->usrs++; | ||
814 | /* Set io_allowed member to false */ | ||
815 | fh->io_allowed[VPIF_VIDEO_INDEX] = 0; | ||
816 | /* Initialize priority of this instance to default priority */ | ||
817 | fh->prio = V4L2_PRIORITY_UNSET; | ||
818 | v4l2_prio_open(&ch->prio, &fh->prio); | ||
819 | exit: | ||
820 | mutex_unlock(&common->lock); | ||
821 | return ret; | ||
822 | } | ||
823 | |||
824 | /** | ||
825 | * vpif_release : function to clean up file close | ||
826 | * @filep: file pointer | ||
827 | * | ||
828 | * This function deletes buffer queue, frees the buffers and the vpfe file | ||
829 | * handle | ||
830 | */ | ||
831 | static int vpif_release(struct file *filep) | ||
832 | { | ||
833 | struct vpif_fh *fh = filep->private_data; | ||
834 | struct channel_obj *ch = fh->channel; | ||
835 | struct common_obj *common; | ||
836 | |||
837 | vpif_dbg(2, debug, "vpif_release\n"); | ||
838 | |||
839 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
840 | |||
841 | if (mutex_lock_interruptible(&common->lock)) | ||
842 | return -ERESTARTSYS; | ||
843 | |||
844 | /* if this instance is doing IO */ | ||
845 | if (fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
846 | /* Reset io_usrs member of channel object */ | ||
847 | common->io_usrs = 0; | ||
848 | /* Disable channel as per its device type and channel id */ | ||
849 | if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { | ||
850 | enable_channel0(0); | ||
851 | channel0_intr_enable(0); | ||
852 | } | ||
853 | if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || | ||
854 | (2 == common->started)) { | ||
855 | enable_channel1(0); | ||
856 | channel1_intr_enable(0); | ||
857 | } | ||
858 | common->started = 0; | ||
859 | /* Free buffers allocated */ | ||
860 | videobuf_queue_cancel(&common->buffer_queue); | ||
861 | videobuf_mmap_free(&common->buffer_queue); | ||
862 | } | ||
863 | |||
864 | /* Decrement channel usrs counter */ | ||
865 | ch->usrs--; | ||
866 | |||
867 | /* unlock mutex on channel object */ | ||
868 | mutex_unlock(&common->lock); | ||
869 | |||
870 | /* Close the priority */ | ||
871 | v4l2_prio_close(&ch->prio, &fh->prio); | ||
872 | |||
873 | if (fh->initialized) | ||
874 | ch->initialized = 0; | ||
875 | |||
876 | filep->private_data = NULL; | ||
877 | kfree(fh); | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | /** | ||
882 | * vpif_reqbufs() - request buffer handler | ||
883 | * @file: file ptr | ||
884 | * @priv: file handle | ||
885 | * @reqbuf: request buffer structure ptr | ||
886 | */ | ||
887 | static int vpif_reqbufs(struct file *file, void *priv, | ||
888 | struct v4l2_requestbuffers *reqbuf) | ||
889 | { | ||
890 | struct vpif_fh *fh = priv; | ||
891 | struct channel_obj *ch = fh->channel; | ||
892 | struct common_obj *common; | ||
893 | u8 index = 0; | ||
894 | int ret = 0; | ||
895 | |||
896 | vpif_dbg(2, debug, "vpif_reqbufs\n"); | ||
897 | |||
898 | /** | ||
899 | * This file handle has not initialized the channel, | ||
900 | * It is not allowed to do settings | ||
901 | */ | ||
902 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) | ||
903 | || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
904 | if (!fh->initialized) { | ||
905 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
906 | return -EBUSY; | ||
907 | } | ||
908 | } | ||
909 | |||
910 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) | ||
911 | return -EINVAL; | ||
912 | |||
913 | index = VPIF_VIDEO_INDEX; | ||
914 | |||
915 | common = &ch->common[index]; | ||
916 | |||
917 | if (mutex_lock_interruptible(&common->lock)) | ||
918 | return -ERESTARTSYS; | ||
919 | |||
920 | if (0 != common->io_usrs) { | ||
921 | ret = -EBUSY; | ||
922 | goto reqbuf_exit; | ||
923 | } | ||
924 | |||
925 | /* Initialize videobuf queue as per the buffer type */ | ||
926 | videobuf_queue_dma_contig_init(&common->buffer_queue, | ||
927 | &video_qops, NULL, | ||
928 | &common->irqlock, | ||
929 | reqbuf->type, | ||
930 | common->fmt.fmt.pix.field, | ||
931 | sizeof(struct videobuf_buffer), fh); | ||
932 | |||
933 | /* Set io allowed member of file handle to TRUE */ | ||
934 | fh->io_allowed[index] = 1; | ||
935 | /* Increment io usrs member of channel object to 1 */ | ||
936 | common->io_usrs = 1; | ||
937 | /* Store type of memory requested in channel object */ | ||
938 | common->memory = reqbuf->memory; | ||
939 | INIT_LIST_HEAD(&common->dma_queue); | ||
940 | |||
941 | /* Allocate buffers */ | ||
942 | ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); | ||
943 | |||
944 | reqbuf_exit: | ||
945 | mutex_unlock(&common->lock); | ||
946 | return ret; | ||
947 | } | ||
948 | |||
949 | /** | ||
950 | * vpif_querybuf() - query buffer handler | ||
951 | * @file: file ptr | ||
952 | * @priv: file handle | ||
953 | * @buf: v4l2 buffer structure ptr | ||
954 | */ | ||
955 | static int vpif_querybuf(struct file *file, void *priv, | ||
956 | struct v4l2_buffer *buf) | ||
957 | { | ||
958 | struct vpif_fh *fh = priv; | ||
959 | struct channel_obj *ch = fh->channel; | ||
960 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
961 | |||
962 | vpif_dbg(2, debug, "vpif_querybuf\n"); | ||
963 | |||
964 | if (common->fmt.type != buf->type) | ||
965 | return -EINVAL; | ||
966 | |||
967 | if (common->memory != V4L2_MEMORY_MMAP) { | ||
968 | vpif_dbg(1, debug, "Invalid memory\n"); | ||
969 | return -EINVAL; | ||
970 | } | ||
971 | |||
972 | return videobuf_querybuf(&common->buffer_queue, buf); | ||
973 | } | ||
974 | |||
975 | /** | ||
976 | * vpif_qbuf() - query buffer handler | ||
977 | * @file: file ptr | ||
978 | * @priv: file handle | ||
979 | * @buf: v4l2 buffer structure ptr | ||
980 | */ | ||
981 | static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
982 | { | ||
983 | |||
984 | struct vpif_fh *fh = priv; | ||
985 | struct channel_obj *ch = fh->channel; | ||
986 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
987 | struct v4l2_buffer tbuf = *buf; | ||
988 | struct videobuf_buffer *buf1; | ||
989 | unsigned long addr = 0; | ||
990 | unsigned long flags; | ||
991 | int ret = 0; | ||
992 | |||
993 | vpif_dbg(2, debug, "vpif_qbuf\n"); | ||
994 | |||
995 | if (common->fmt.type != tbuf.type) { | ||
996 | vpif_err("invalid buffer type\n"); | ||
997 | return -EINVAL; | ||
998 | } | ||
999 | |||
1000 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1001 | vpif_err("fh io not allowed \n"); | ||
1002 | return -EACCES; | ||
1003 | } | ||
1004 | |||
1005 | if (!(list_empty(&common->dma_queue)) || | ||
1006 | (common->cur_frm != common->next_frm) || | ||
1007 | !common->started || | ||
1008 | (common->started && (0 == ch->field_id))) | ||
1009 | return videobuf_qbuf(&common->buffer_queue, buf); | ||
1010 | |||
1011 | /* bufferqueue is empty store buffer address in VPIF registers */ | ||
1012 | mutex_lock(&common->buffer_queue.vb_lock); | ||
1013 | buf1 = common->buffer_queue.bufs[tbuf.index]; | ||
1014 | |||
1015 | if ((buf1->state == VIDEOBUF_QUEUED) || | ||
1016 | (buf1->state == VIDEOBUF_ACTIVE)) { | ||
1017 | vpif_err("invalid state\n"); | ||
1018 | goto qbuf_exit; | ||
1019 | } | ||
1020 | |||
1021 | switch (buf1->memory) { | ||
1022 | case V4L2_MEMORY_MMAP: | ||
1023 | if (buf1->baddr == 0) | ||
1024 | goto qbuf_exit; | ||
1025 | break; | ||
1026 | |||
1027 | case V4L2_MEMORY_USERPTR: | ||
1028 | if (tbuf.length < buf1->bsize) | ||
1029 | goto qbuf_exit; | ||
1030 | |||
1031 | if ((VIDEOBUF_NEEDS_INIT != buf1->state) | ||
1032 | && (buf1->baddr != tbuf.m.userptr)) | ||
1033 | vpif_buffer_release(&common->buffer_queue, buf1); | ||
1034 | buf1->baddr = tbuf.m.userptr; | ||
1035 | break; | ||
1036 | |||
1037 | default: | ||
1038 | goto qbuf_exit; | ||
1039 | } | ||
1040 | |||
1041 | local_irq_save(flags); | ||
1042 | ret = vpif_buffer_prepare(&common->buffer_queue, buf1, | ||
1043 | common->buffer_queue.field); | ||
1044 | if (ret < 0) { | ||
1045 | local_irq_restore(flags); | ||
1046 | goto qbuf_exit; | ||
1047 | } | ||
1048 | |||
1049 | buf1->state = VIDEOBUF_ACTIVE; | ||
1050 | |||
1051 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
1052 | addr = buf1->boff; | ||
1053 | else | ||
1054 | addr = videobuf_to_dma_contig(buf1); | ||
1055 | |||
1056 | common->next_frm = buf1; | ||
1057 | common->set_addr(addr + common->ytop_off, | ||
1058 | addr + common->ybtm_off, | ||
1059 | addr + common->ctop_off, | ||
1060 | addr + common->cbtm_off); | ||
1061 | |||
1062 | local_irq_restore(flags); | ||
1063 | list_add_tail(&buf1->stream, &common->buffer_queue.stream); | ||
1064 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
1065 | return 0; | ||
1066 | |||
1067 | qbuf_exit: | ||
1068 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
1069 | return -EINVAL; | ||
1070 | } | ||
1071 | |||
1072 | /** | ||
1073 | * vpif_dqbuf() - query buffer handler | ||
1074 | * @file: file ptr | ||
1075 | * @priv: file handle | ||
1076 | * @buf: v4l2 buffer structure ptr | ||
1077 | */ | ||
1078 | static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1079 | { | ||
1080 | struct vpif_fh *fh = priv; | ||
1081 | struct channel_obj *ch = fh->channel; | ||
1082 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1083 | |||
1084 | vpif_dbg(2, debug, "vpif_dqbuf\n"); | ||
1085 | |||
1086 | return videobuf_dqbuf(&common->buffer_queue, buf, | ||
1087 | file->f_flags & O_NONBLOCK); | ||
1088 | } | ||
1089 | |||
1090 | /** | ||
1091 | * vpif_streamon() - streamon handler | ||
1092 | * @file: file ptr | ||
1093 | * @priv: file handle | ||
1094 | * @buftype: v4l2 buffer type | ||
1095 | */ | ||
1096 | static int vpif_streamon(struct file *file, void *priv, | ||
1097 | enum v4l2_buf_type buftype) | ||
1098 | { | ||
1099 | |||
1100 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1101 | struct vpif_fh *fh = priv; | ||
1102 | struct channel_obj *ch = fh->channel; | ||
1103 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1104 | struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; | ||
1105 | struct vpif_params *vpif; | ||
1106 | unsigned long addr = 0; | ||
1107 | int ret = 0; | ||
1108 | |||
1109 | vpif_dbg(2, debug, "vpif_streamon\n"); | ||
1110 | |||
1111 | vpif = &ch->vpifparams; | ||
1112 | |||
1113 | if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1114 | vpif_dbg(1, debug, "buffer type not supported\n"); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | /* If file handle is not allowed IO, return error */ | ||
1119 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1120 | vpif_dbg(1, debug, "io not allowed\n"); | ||
1121 | return -EACCES; | ||
1122 | } | ||
1123 | |||
1124 | /* If Streaming is already started, return error */ | ||
1125 | if (common->started) { | ||
1126 | vpif_dbg(1, debug, "channel->started\n"); | ||
1127 | return -EBUSY; | ||
1128 | } | ||
1129 | |||
1130 | if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && | ||
1131 | oth_ch->common[VPIF_VIDEO_INDEX].started && | ||
1132 | vpif->std_info.ycmux_mode == 0) || | ||
1133 | ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && | ||
1134 | (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { | ||
1135 | vpif_dbg(1, debug, "other channel is being used\n"); | ||
1136 | return -EBUSY; | ||
1137 | } | ||
1138 | |||
1139 | ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); | ||
1140 | if (ret) | ||
1141 | return ret; | ||
1142 | |||
1143 | /* Enable streamon on the sub device */ | ||
1144 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, | ||
1145 | s_stream, 1); | ||
1146 | |||
1147 | if (ret && (ret != -ENOIOCTLCMD)) { | ||
1148 | vpif_dbg(1, debug, "stream on failed in subdev\n"); | ||
1149 | return ret; | ||
1150 | } | ||
1151 | |||
1152 | /* Call videobuf_streamon to start streaming in videobuf */ | ||
1153 | ret = videobuf_streamon(&common->buffer_queue); | ||
1154 | if (ret) { | ||
1155 | vpif_dbg(1, debug, "videobuf_streamon\n"); | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | if (mutex_lock_interruptible(&common->lock)) { | ||
1160 | ret = -ERESTARTSYS; | ||
1161 | goto streamoff_exit; | ||
1162 | } | ||
1163 | |||
1164 | /* If buffer queue is empty, return error */ | ||
1165 | if (list_empty(&common->dma_queue)) { | ||
1166 | vpif_dbg(1, debug, "buffer queue is empty\n"); | ||
1167 | ret = -EIO; | ||
1168 | goto exit; | ||
1169 | } | ||
1170 | |||
1171 | /* Get the next frame from the buffer queue */ | ||
1172 | common->cur_frm = list_entry(common->dma_queue.next, | ||
1173 | struct videobuf_buffer, queue); | ||
1174 | common->next_frm = common->cur_frm; | ||
1175 | |||
1176 | /* Remove buffer from the buffer queue */ | ||
1177 | list_del(&common->cur_frm->queue); | ||
1178 | /* Mark state of the current frame to active */ | ||
1179 | common->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1180 | /* Initialize field_id and started member */ | ||
1181 | ch->field_id = 0; | ||
1182 | common->started = 1; | ||
1183 | |||
1184 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
1185 | addr = common->cur_frm->boff; | ||
1186 | else | ||
1187 | addr = videobuf_to_dma_contig(common->cur_frm); | ||
1188 | |||
1189 | /* Calculate the offset for Y and C data in the buffer */ | ||
1190 | vpif_calculate_offsets(ch); | ||
1191 | |||
1192 | if ((vpif->std_info.frm_fmt && | ||
1193 | ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && | ||
1194 | (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || | ||
1195 | (!vpif->std_info.frm_fmt && | ||
1196 | (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { | ||
1197 | vpif_dbg(1, debug, "conflict in field format and std format\n"); | ||
1198 | ret = -EINVAL; | ||
1199 | goto exit; | ||
1200 | } | ||
1201 | |||
1202 | /* configure 1 or 2 channel mode */ | ||
1203 | ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); | ||
1204 | |||
1205 | if (ret < 0) { | ||
1206 | vpif_dbg(1, debug, "can't set vpif channel mode\n"); | ||
1207 | goto exit; | ||
1208 | } | ||
1209 | |||
1210 | /* Call vpif_set_params function to set the parameters and addresses */ | ||
1211 | ret = vpif_set_video_params(vpif, ch->channel_id); | ||
1212 | |||
1213 | if (ret < 0) { | ||
1214 | vpif_dbg(1, debug, "can't set video params\n"); | ||
1215 | goto exit; | ||
1216 | } | ||
1217 | |||
1218 | common->started = ret; | ||
1219 | vpif_config_addr(ch, ret); | ||
1220 | |||
1221 | common->set_addr(addr + common->ytop_off, | ||
1222 | addr + common->ybtm_off, | ||
1223 | addr + common->ctop_off, | ||
1224 | addr + common->cbtm_off); | ||
1225 | |||
1226 | /** | ||
1227 | * Set interrupt for both the fields in VPIF Register enable channel in | ||
1228 | * VPIF register | ||
1229 | */ | ||
1230 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { | ||
1231 | channel0_intr_assert(); | ||
1232 | channel0_intr_enable(1); | ||
1233 | enable_channel0(1); | ||
1234 | } | ||
1235 | if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || | ||
1236 | (common->started == 2)) { | ||
1237 | channel1_intr_assert(); | ||
1238 | channel1_intr_enable(1); | ||
1239 | enable_channel1(1); | ||
1240 | } | ||
1241 | channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; | ||
1242 | mutex_unlock(&common->lock); | ||
1243 | return ret; | ||
1244 | |||
1245 | exit: | ||
1246 | mutex_unlock(&common->lock); | ||
1247 | streamoff_exit: | ||
1248 | ret = videobuf_streamoff(&common->buffer_queue); | ||
1249 | return ret; | ||
1250 | } | ||
1251 | |||
1252 | /** | ||
1253 | * vpif_streamoff() - streamoff handler | ||
1254 | * @file: file ptr | ||
1255 | * @priv: file handle | ||
1256 | * @buftype: v4l2 buffer type | ||
1257 | */ | ||
1258 | static int vpif_streamoff(struct file *file, void *priv, | ||
1259 | enum v4l2_buf_type buftype) | ||
1260 | { | ||
1261 | |||
1262 | struct vpif_fh *fh = priv; | ||
1263 | struct channel_obj *ch = fh->channel; | ||
1264 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1265 | int ret; | ||
1266 | |||
1267 | vpif_dbg(2, debug, "vpif_streamoff\n"); | ||
1268 | |||
1269 | if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1270 | vpif_dbg(1, debug, "buffer type not supported\n"); | ||
1271 | return -EINVAL; | ||
1272 | } | ||
1273 | |||
1274 | /* If io is allowed for this file handle, return error */ | ||
1275 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1276 | vpif_dbg(1, debug, "io not allowed\n"); | ||
1277 | return -EACCES; | ||
1278 | } | ||
1279 | |||
1280 | /* If streaming is not started, return error */ | ||
1281 | if (!common->started) { | ||
1282 | vpif_dbg(1, debug, "channel->started\n"); | ||
1283 | return -EINVAL; | ||
1284 | } | ||
1285 | |||
1286 | if (mutex_lock_interruptible(&common->lock)) | ||
1287 | return -ERESTARTSYS; | ||
1288 | |||
1289 | /* disable channel */ | ||
1290 | if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { | ||
1291 | enable_channel0(0); | ||
1292 | channel0_intr_enable(0); | ||
1293 | } else { | ||
1294 | enable_channel1(0); | ||
1295 | channel1_intr_enable(0); | ||
1296 | } | ||
1297 | |||
1298 | common->started = 0; | ||
1299 | |||
1300 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, | ||
1301 | s_stream, 0); | ||
1302 | |||
1303 | if (ret && (ret != -ENOIOCTLCMD)) | ||
1304 | vpif_dbg(1, debug, "stream off failed in subdev\n"); | ||
1305 | |||
1306 | mutex_unlock(&common->lock); | ||
1307 | |||
1308 | return videobuf_streamoff(&common->buffer_queue); | ||
1309 | } | ||
1310 | |||
1311 | /** | ||
1312 | * vpif_map_sub_device_to_input() - Maps sub device to input | ||
1313 | * @ch - ptr to channel | ||
1314 | * @config - ptr to capture configuration | ||
1315 | * @input_index - Given input index from application | ||
1316 | * @sub_device_index - index into sd table | ||
1317 | * | ||
1318 | * lookup the sub device information for a given input index. | ||
1319 | * we report all the inputs to application. inputs table also | ||
1320 | * has sub device name for the each input | ||
1321 | */ | ||
1322 | static struct vpif_subdev_info *vpif_map_sub_device_to_input( | ||
1323 | struct channel_obj *ch, | ||
1324 | struct vpif_capture_config *vpif_cfg, | ||
1325 | int input_index, | ||
1326 | int *sub_device_index) | ||
1327 | { | ||
1328 | struct vpif_capture_chan_config *chan_cfg; | ||
1329 | struct vpif_subdev_info *subdev_info = NULL; | ||
1330 | const char *subdev_name = NULL; | ||
1331 | int i; | ||
1332 | |||
1333 | vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); | ||
1334 | |||
1335 | chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; | ||
1336 | |||
1337 | /** | ||
1338 | * search through the inputs to find the sub device supporting | ||
1339 | * the input | ||
1340 | */ | ||
1341 | for (i = 0; i < chan_cfg->input_count; i++) { | ||
1342 | /* For each sub device, loop through input */ | ||
1343 | if (i == input_index) { | ||
1344 | subdev_name = chan_cfg->inputs[i].subdev_name; | ||
1345 | break; | ||
1346 | } | ||
1347 | } | ||
1348 | |||
1349 | /* if reached maximum. return null */ | ||
1350 | if (i == chan_cfg->input_count || (NULL == subdev_name)) | ||
1351 | return subdev_info; | ||
1352 | |||
1353 | /* loop through the sub device list to get the sub device info */ | ||
1354 | for (i = 0; i < vpif_cfg->subdev_count; i++) { | ||
1355 | subdev_info = &vpif_cfg->subdev_info[i]; | ||
1356 | if (!strcmp(subdev_info->name, subdev_name)) | ||
1357 | break; | ||
1358 | } | ||
1359 | |||
1360 | if (i == vpif_cfg->subdev_count) | ||
1361 | return subdev_info; | ||
1362 | |||
1363 | /* check if the sub device is registered */ | ||
1364 | if (NULL == vpif_obj.sd[i]) | ||
1365 | return NULL; | ||
1366 | |||
1367 | *sub_device_index = i; | ||
1368 | return subdev_info; | ||
1369 | } | ||
1370 | |||
1371 | /** | ||
1372 | * vpif_querystd() - querystd handler | ||
1373 | * @file: file ptr | ||
1374 | * @priv: file handle | ||
1375 | * @std_id: ptr to std id | ||
1376 | * | ||
1377 | * This function is called to detect standard at the selected input | ||
1378 | */ | ||
1379 | static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1380 | { | ||
1381 | struct vpif_fh *fh = priv; | ||
1382 | struct channel_obj *ch = fh->channel; | ||
1383 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1384 | int ret = 0; | ||
1385 | |||
1386 | vpif_dbg(2, debug, "vpif_querystd\n"); | ||
1387 | |||
1388 | if (mutex_lock_interruptible(&common->lock)) | ||
1389 | return -ERESTARTSYS; | ||
1390 | |||
1391 | /* Call querystd function of decoder device */ | ||
1392 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, | ||
1393 | querystd, std_id); | ||
1394 | if (ret < 0) | ||
1395 | vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); | ||
1396 | |||
1397 | mutex_unlock(&common->lock); | ||
1398 | return ret; | ||
1399 | } | ||
1400 | |||
1401 | /** | ||
1402 | * vpif_g_std() - get STD handler | ||
1403 | * @file: file ptr | ||
1404 | * @priv: file handle | ||
1405 | * @std_id: ptr to std id | ||
1406 | */ | ||
1407 | static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
1408 | { | ||
1409 | struct vpif_fh *fh = priv; | ||
1410 | struct channel_obj *ch = fh->channel; | ||
1411 | |||
1412 | vpif_dbg(2, debug, "vpif_g_std\n"); | ||
1413 | |||
1414 | *std = ch->video.stdid; | ||
1415 | return 0; | ||
1416 | } | ||
1417 | |||
1418 | /** | ||
1419 | * vpif_s_std() - set STD handler | ||
1420 | * @file: file ptr | ||
1421 | * @priv: file handle | ||
1422 | * @std_id: ptr to std id | ||
1423 | */ | ||
1424 | static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1425 | { | ||
1426 | struct vpif_fh *fh = priv; | ||
1427 | struct channel_obj *ch = fh->channel; | ||
1428 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1429 | int ret = 0; | ||
1430 | |||
1431 | vpif_dbg(2, debug, "vpif_s_std\n"); | ||
1432 | |||
1433 | if (common->started) { | ||
1434 | vpif_err("streaming in progress\n"); | ||
1435 | return -EBUSY; | ||
1436 | } | ||
1437 | |||
1438 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || | ||
1439 | (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
1440 | if (!fh->initialized) { | ||
1441 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
1442 | return -EBUSY; | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | ret = v4l2_prio_check(&ch->prio, &fh->prio); | ||
1447 | if (0 != ret) | ||
1448 | return ret; | ||
1449 | |||
1450 | fh->initialized = 1; | ||
1451 | |||
1452 | /* Call encoder subdevice function to set the standard */ | ||
1453 | if (mutex_lock_interruptible(&common->lock)) | ||
1454 | return -ERESTARTSYS; | ||
1455 | |||
1456 | ch->video.stdid = *std_id; | ||
1457 | |||
1458 | /* Get the information about the standard */ | ||
1459 | if (vpif_update_std_info(ch)) { | ||
1460 | ret = -EINVAL; | ||
1461 | vpif_err("Error getting the standard info\n"); | ||
1462 | goto s_std_exit; | ||
1463 | } | ||
1464 | |||
1465 | /* Configure the default format information */ | ||
1466 | vpif_config_format(ch); | ||
1467 | |||
1468 | /* set standard in the sub device */ | ||
1469 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, | ||
1470 | s_std, *std_id); | ||
1471 | if (ret < 0) | ||
1472 | vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); | ||
1473 | |||
1474 | s_std_exit: | ||
1475 | mutex_unlock(&common->lock); | ||
1476 | return ret; | ||
1477 | } | ||
1478 | |||
1479 | /** | ||
1480 | * vpif_enum_input() - ENUMINPUT handler | ||
1481 | * @file: file ptr | ||
1482 | * @priv: file handle | ||
1483 | * @input: ptr to input structure | ||
1484 | */ | ||
1485 | static int vpif_enum_input(struct file *file, void *priv, | ||
1486 | struct v4l2_input *input) | ||
1487 | { | ||
1488 | |||
1489 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1490 | struct vpif_capture_chan_config *chan_cfg; | ||
1491 | struct vpif_fh *fh = priv; | ||
1492 | struct channel_obj *ch = fh->channel; | ||
1493 | |||
1494 | chan_cfg = &config->chan_config[ch->channel_id]; | ||
1495 | |||
1496 | if (input->index >= chan_cfg->input_count) { | ||
1497 | vpif_dbg(1, debug, "Invalid input index\n"); | ||
1498 | return -EINVAL; | ||
1499 | } | ||
1500 | |||
1501 | memcpy(input, &chan_cfg->inputs[input->index].input, | ||
1502 | sizeof(*input)); | ||
1503 | return 0; | ||
1504 | } | ||
1505 | |||
1506 | /** | ||
1507 | * vpif_g_input() - Get INPUT handler | ||
1508 | * @file: file ptr | ||
1509 | * @priv: file handle | ||
1510 | * @index: ptr to input index | ||
1511 | */ | ||
1512 | static int vpif_g_input(struct file *file, void *priv, unsigned int *index) | ||
1513 | { | ||
1514 | struct vpif_fh *fh = priv; | ||
1515 | struct channel_obj *ch = fh->channel; | ||
1516 | struct video_obj *vid_ch = &ch->video; | ||
1517 | |||
1518 | *index = vid_ch->input_idx; | ||
1519 | |||
1520 | return 0; | ||
1521 | } | ||
1522 | |||
1523 | /** | ||
1524 | * vpif_s_input() - Set INPUT handler | ||
1525 | * @file: file ptr | ||
1526 | * @priv: file handle | ||
1527 | * @index: input index | ||
1528 | */ | ||
1529 | static int vpif_s_input(struct file *file, void *priv, unsigned int index) | ||
1530 | { | ||
1531 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1532 | struct vpif_capture_chan_config *chan_cfg; | ||
1533 | struct vpif_fh *fh = priv; | ||
1534 | struct channel_obj *ch = fh->channel; | ||
1535 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1536 | struct video_obj *vid_ch = &ch->video; | ||
1537 | struct vpif_subdev_info *subdev_info; | ||
1538 | int ret = 0, sd_index = 0; | ||
1539 | u32 input = 0, output = 0; | ||
1540 | |||
1541 | chan_cfg = &config->chan_config[ch->channel_id]; | ||
1542 | |||
1543 | if (common->started) { | ||
1544 | vpif_err("Streaming in progress\n"); | ||
1545 | return -EBUSY; | ||
1546 | } | ||
1547 | |||
1548 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || | ||
1549 | (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
1550 | if (!fh->initialized) { | ||
1551 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
1552 | return -EBUSY; | ||
1553 | } | ||
1554 | } | ||
1555 | |||
1556 | ret = v4l2_prio_check(&ch->prio, &fh->prio); | ||
1557 | if (0 != ret) | ||
1558 | return ret; | ||
1559 | |||
1560 | fh->initialized = 1; | ||
1561 | subdev_info = vpif_map_sub_device_to_input(ch, config, index, | ||
1562 | &sd_index); | ||
1563 | if (NULL == subdev_info) { | ||
1564 | vpif_dbg(1, debug, | ||
1565 | "couldn't lookup sub device for the input index\n"); | ||
1566 | return -EINVAL; | ||
1567 | } | ||
1568 | |||
1569 | if (mutex_lock_interruptible(&common->lock)) | ||
1570 | return -ERESTARTSYS; | ||
1571 | |||
1572 | /* first setup input path from sub device to vpif */ | ||
1573 | if (config->setup_input_path) { | ||
1574 | ret = config->setup_input_path(ch->channel_id, | ||
1575 | subdev_info->name); | ||
1576 | if (ret < 0) { | ||
1577 | vpif_dbg(1, debug, "couldn't setup input path for the" | ||
1578 | " sub device %s, for input index %d\n", | ||
1579 | subdev_info->name, index); | ||
1580 | goto exit; | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1584 | if (subdev_info->can_route) { | ||
1585 | input = subdev_info->input; | ||
1586 | output = subdev_info->output; | ||
1587 | ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, | ||
1588 | input, output, 0); | ||
1589 | if (ret < 0) { | ||
1590 | vpif_dbg(1, debug, "Failed to set input\n"); | ||
1591 | goto exit; | ||
1592 | } | ||
1593 | } | ||
1594 | vid_ch->input_idx = index; | ||
1595 | ch->curr_subdev_info = subdev_info; | ||
1596 | ch->curr_sd_index = sd_index; | ||
1597 | /* copy interface parameters to vpif */ | ||
1598 | ch->vpifparams.iface = subdev_info->vpif_if; | ||
1599 | |||
1600 | /* update tvnorms from the sub device input info */ | ||
1601 | ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; | ||
1602 | |||
1603 | exit: | ||
1604 | mutex_unlock(&common->lock); | ||
1605 | return ret; | ||
1606 | } | ||
1607 | |||
1608 | /** | ||
1609 | * vpif_enum_fmt_vid_cap() - ENUM_FMT handler | ||
1610 | * @file: file ptr | ||
1611 | * @priv: file handle | ||
1612 | * @index: input index | ||
1613 | */ | ||
1614 | static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, | ||
1615 | struct v4l2_fmtdesc *fmt) | ||
1616 | { | ||
1617 | struct vpif_fh *fh = priv; | ||
1618 | struct channel_obj *ch = fh->channel; | ||
1619 | |||
1620 | if (fmt->index != 0) { | ||
1621 | vpif_dbg(1, debug, "Invalid format index\n"); | ||
1622 | return -EINVAL; | ||
1623 | } | ||
1624 | |||
1625 | /* Fill in the information about format */ | ||
1626 | if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { | ||
1627 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1628 | strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb"); | ||
1629 | fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
1630 | } else { | ||
1631 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1632 | strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); | ||
1633 | fmt->pixelformat = V4L2_PIX_FMT_YUV422P; | ||
1634 | } | ||
1635 | return 0; | ||
1636 | } | ||
1637 | |||
1638 | /** | ||
1639 | * vpif_try_fmt_vid_cap() - TRY_FMT handler | ||
1640 | * @file: file ptr | ||
1641 | * @priv: file handle | ||
1642 | * @fmt: ptr to v4l2 format structure | ||
1643 | */ | ||
1644 | static int vpif_try_fmt_vid_cap(struct file *file, void *priv, | ||
1645 | struct v4l2_format *fmt) | ||
1646 | { | ||
1647 | struct vpif_fh *fh = priv; | ||
1648 | struct channel_obj *ch = fh->channel; | ||
1649 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
1650 | |||
1651 | return vpif_check_format(ch, pixfmt, 1); | ||
1652 | } | ||
1653 | |||
1654 | |||
1655 | /** | ||
1656 | * vpif_g_fmt_vid_cap() - Set INPUT handler | ||
1657 | * @file: file ptr | ||
1658 | * @priv: file handle | ||
1659 | * @fmt: ptr to v4l2 format structure | ||
1660 | */ | ||
1661 | static int vpif_g_fmt_vid_cap(struct file *file, void *priv, | ||
1662 | struct v4l2_format *fmt) | ||
1663 | { | ||
1664 | struct vpif_fh *fh = priv; | ||
1665 | struct channel_obj *ch = fh->channel; | ||
1666 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1667 | |||
1668 | /* Check the validity of the buffer type */ | ||
1669 | if (common->fmt.type != fmt->type) | ||
1670 | return -EINVAL; | ||
1671 | |||
1672 | /* Fill in the information about format */ | ||
1673 | if (mutex_lock_interruptible(&common->lock)) | ||
1674 | return -ERESTARTSYS; | ||
1675 | |||
1676 | *fmt = common->fmt; | ||
1677 | mutex_unlock(&common->lock); | ||
1678 | return 0; | ||
1679 | } | ||
1680 | |||
1681 | /** | ||
1682 | * vpif_s_fmt_vid_cap() - Set FMT handler | ||
1683 | * @file: file ptr | ||
1684 | * @priv: file handle | ||
1685 | * @fmt: ptr to v4l2 format structure | ||
1686 | */ | ||
1687 | static int vpif_s_fmt_vid_cap(struct file *file, void *priv, | ||
1688 | struct v4l2_format *fmt) | ||
1689 | { | ||
1690 | struct vpif_fh *fh = priv; | ||
1691 | struct channel_obj *ch = fh->channel; | ||
1692 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1693 | struct v4l2_pix_format *pixfmt; | ||
1694 | int ret = 0; | ||
1695 | |||
1696 | vpif_dbg(2, debug, "VIDIOC_S_FMT\n"); | ||
1697 | |||
1698 | /* If streaming is started, return error */ | ||
1699 | if (common->started) { | ||
1700 | vpif_dbg(1, debug, "Streaming is started\n"); | ||
1701 | return -EBUSY; | ||
1702 | } | ||
1703 | |||
1704 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || | ||
1705 | (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
1706 | if (!fh->initialized) { | ||
1707 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
1708 | return -EBUSY; | ||
1709 | } | ||
1710 | } | ||
1711 | |||
1712 | ret = v4l2_prio_check(&ch->prio, &fh->prio); | ||
1713 | if (0 != ret) | ||
1714 | return ret; | ||
1715 | |||
1716 | fh->initialized = 1; | ||
1717 | |||
1718 | pixfmt = &fmt->fmt.pix; | ||
1719 | /* Check for valid field format */ | ||
1720 | ret = vpif_check_format(ch, pixfmt, 0); | ||
1721 | |||
1722 | if (ret) | ||
1723 | return ret; | ||
1724 | /* store the format in the channel object */ | ||
1725 | if (mutex_lock_interruptible(&common->lock)) | ||
1726 | return -ERESTARTSYS; | ||
1727 | |||
1728 | common->fmt = *fmt; | ||
1729 | mutex_unlock(&common->lock); | ||
1730 | |||
1731 | return 0; | ||
1732 | } | ||
1733 | |||
1734 | /** | ||
1735 | * vpif_querycap() - QUERYCAP handler | ||
1736 | * @file: file ptr | ||
1737 | * @priv: file handle | ||
1738 | * @cap: ptr to v4l2_capability structure | ||
1739 | */ | ||
1740 | static int vpif_querycap(struct file *file, void *priv, | ||
1741 | struct v4l2_capability *cap) | ||
1742 | { | ||
1743 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1744 | |||
1745 | cap->version = VPIF_CAPTURE_VERSION_CODE; | ||
1746 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1747 | strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); | ||
1748 | strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); | ||
1749 | strlcpy(cap->card, config->card_name, sizeof(cap->card)); | ||
1750 | |||
1751 | return 0; | ||
1752 | } | ||
1753 | |||
1754 | /** | ||
1755 | * vpif_g_priority() - get priority handler | ||
1756 | * @file: file ptr | ||
1757 | * @priv: file handle | ||
1758 | * @prio: ptr to v4l2_priority structure | ||
1759 | */ | ||
1760 | static int vpif_g_priority(struct file *file, void *priv, | ||
1761 | enum v4l2_priority *prio) | ||
1762 | { | ||
1763 | struct vpif_fh *fh = priv; | ||
1764 | struct channel_obj *ch = fh->channel; | ||
1765 | |||
1766 | *prio = v4l2_prio_max(&ch->prio); | ||
1767 | |||
1768 | return 0; | ||
1769 | } | ||
1770 | |||
1771 | /** | ||
1772 | * vpif_s_priority() - set priority handler | ||
1773 | * @file: file ptr | ||
1774 | * @priv: file handle | ||
1775 | * @prio: ptr to v4l2_priority structure | ||
1776 | */ | ||
1777 | static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) | ||
1778 | { | ||
1779 | struct vpif_fh *fh = priv; | ||
1780 | struct channel_obj *ch = fh->channel; | ||
1781 | |||
1782 | return v4l2_prio_change(&ch->prio, &fh->prio, p); | ||
1783 | } | ||
1784 | |||
1785 | /** | ||
1786 | * vpif_cropcap() - cropcap handler | ||
1787 | * @file: file ptr | ||
1788 | * @priv: file handle | ||
1789 | * @crop: ptr to v4l2_cropcap structure | ||
1790 | */ | ||
1791 | static int vpif_cropcap(struct file *file, void *priv, | ||
1792 | struct v4l2_cropcap *crop) | ||
1793 | { | ||
1794 | struct vpif_fh *fh = priv; | ||
1795 | struct channel_obj *ch = fh->channel; | ||
1796 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1797 | |||
1798 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type) | ||
1799 | return -EINVAL; | ||
1800 | |||
1801 | crop->bounds.left = 0; | ||
1802 | crop->bounds.top = 0; | ||
1803 | crop->bounds.height = common->height; | ||
1804 | crop->bounds.width = common->width; | ||
1805 | crop->defrect = crop->bounds; | ||
1806 | return 0; | ||
1807 | } | ||
1808 | |||
1809 | /* vpif capture ioctl operations */ | ||
1810 | static const struct v4l2_ioctl_ops vpif_ioctl_ops = { | ||
1811 | .vidioc_querycap = vpif_querycap, | ||
1812 | .vidioc_g_priority = vpif_g_priority, | ||
1813 | .vidioc_s_priority = vpif_s_priority, | ||
1814 | .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap, | ||
1815 | .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap, | ||
1816 | .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap, | ||
1817 | .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap, | ||
1818 | .vidioc_enum_input = vpif_enum_input, | ||
1819 | .vidioc_s_input = vpif_s_input, | ||
1820 | .vidioc_g_input = vpif_g_input, | ||
1821 | .vidioc_reqbufs = vpif_reqbufs, | ||
1822 | .vidioc_querybuf = vpif_querybuf, | ||
1823 | .vidioc_querystd = vpif_querystd, | ||
1824 | .vidioc_s_std = vpif_s_std, | ||
1825 | .vidioc_g_std = vpif_g_std, | ||
1826 | .vidioc_qbuf = vpif_qbuf, | ||
1827 | .vidioc_dqbuf = vpif_dqbuf, | ||
1828 | .vidioc_streamon = vpif_streamon, | ||
1829 | .vidioc_streamoff = vpif_streamoff, | ||
1830 | .vidioc_cropcap = vpif_cropcap, | ||
1831 | }; | ||
1832 | |||
1833 | /* vpif file operations */ | ||
1834 | static struct v4l2_file_operations vpif_fops = { | ||
1835 | .owner = THIS_MODULE, | ||
1836 | .open = vpif_open, | ||
1837 | .release = vpif_release, | ||
1838 | .ioctl = video_ioctl2, | ||
1839 | .mmap = vpif_mmap, | ||
1840 | .poll = vpif_poll | ||
1841 | }; | ||
1842 | |||
1843 | /* vpif video template */ | ||
1844 | static struct video_device vpif_video_template = { | ||
1845 | .name = "vpif", | ||
1846 | .fops = &vpif_fops, | ||
1847 | .minor = -1, | ||
1848 | .ioctl_ops = &vpif_ioctl_ops, | ||
1849 | }; | ||
1850 | |||
1851 | /** | ||
1852 | * initialize_vpif() - Initialize vpif data structures | ||
1853 | * | ||
1854 | * Allocate memory for data structures and initialize them | ||
1855 | */ | ||
1856 | static int initialize_vpif(void) | ||
1857 | { | ||
1858 | int err = 0, i, j; | ||
1859 | int free_channel_objects_index; | ||
1860 | |||
1861 | /* Default number of buffers should be 3 */ | ||
1862 | if ((ch0_numbuffers > 0) && | ||
1863 | (ch0_numbuffers < config_params.min_numbuffers)) | ||
1864 | ch0_numbuffers = config_params.min_numbuffers; | ||
1865 | if ((ch1_numbuffers > 0) && | ||
1866 | (ch1_numbuffers < config_params.min_numbuffers)) | ||
1867 | ch1_numbuffers = config_params.min_numbuffers; | ||
1868 | |||
1869 | /* Set buffer size to min buffers size if it is invalid */ | ||
1870 | if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]) | ||
1871 | ch0_bufsize = | ||
1872 | config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]; | ||
1873 | if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]) | ||
1874 | ch1_bufsize = | ||
1875 | config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]; | ||
1876 | |||
1877 | config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers; | ||
1878 | config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers; | ||
1879 | if (ch0_numbuffers) { | ||
1880 | config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO] | ||
1881 | = ch0_bufsize; | ||
1882 | } | ||
1883 | if (ch1_numbuffers) { | ||
1884 | config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO] | ||
1885 | = ch1_bufsize; | ||
1886 | } | ||
1887 | |||
1888 | /* Allocate memory for six channel objects */ | ||
1889 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
1890 | vpif_obj.dev[i] = | ||
1891 | kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL); | ||
1892 | /* If memory allocation fails, return error */ | ||
1893 | if (!vpif_obj.dev[i]) { | ||
1894 | free_channel_objects_index = i; | ||
1895 | err = -ENOMEM; | ||
1896 | goto vpif_init_free_channel_objects; | ||
1897 | } | ||
1898 | } | ||
1899 | return 0; | ||
1900 | |||
1901 | vpif_init_free_channel_objects: | ||
1902 | for (j = 0; j < free_channel_objects_index; j++) | ||
1903 | kfree(vpif_obj.dev[j]); | ||
1904 | return err; | ||
1905 | } | ||
1906 | |||
1907 | /** | ||
1908 | * vpif_probe : This function probes the vpif capture driver | ||
1909 | * @pdev: platform device pointer | ||
1910 | * | ||
1911 | * This creates device entries by register itself to the V4L2 driver and | ||
1912 | * initializes fields of each channel objects | ||
1913 | */ | ||
1914 | static __init int vpif_probe(struct platform_device *pdev) | ||
1915 | { | ||
1916 | struct vpif_subdev_info *subdevdata; | ||
1917 | struct vpif_capture_config *config; | ||
1918 | int i, j, k, m, q, err; | ||
1919 | struct i2c_adapter *i2c_adap; | ||
1920 | struct channel_obj *ch; | ||
1921 | struct common_obj *common; | ||
1922 | struct video_device *vfd; | ||
1923 | struct resource *res; | ||
1924 | int subdev_count; | ||
1925 | |||
1926 | vpif_dev = &pdev->dev; | ||
1927 | |||
1928 | err = initialize_vpif(); | ||
1929 | if (err) { | ||
1930 | v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); | ||
1931 | return err; | ||
1932 | } | ||
1933 | |||
1934 | k = 0; | ||
1935 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { | ||
1936 | for (i = res->start; i <= res->end; i++) { | ||
1937 | if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, | ||
1938 | "DM646x_Capture", | ||
1939 | (void *)(&vpif_obj.dev[k]->channel_id))) { | ||
1940 | err = -EBUSY; | ||
1941 | i--; | ||
1942 | goto vpif_int_err; | ||
1943 | } | ||
1944 | } | ||
1945 | k++; | ||
1946 | } | ||
1947 | |||
1948 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
1949 | /* Get the pointer to the channel object */ | ||
1950 | ch = vpif_obj.dev[i]; | ||
1951 | /* Allocate memory for video device */ | ||
1952 | vfd = video_device_alloc(); | ||
1953 | if (NULL == vfd) { | ||
1954 | for (j = 0; j < i; j++) { | ||
1955 | ch = vpif_obj.dev[j]; | ||
1956 | video_device_release(ch->video_dev); | ||
1957 | } | ||
1958 | err = -ENOMEM; | ||
1959 | goto vpif_dev_alloc_err; | ||
1960 | } | ||
1961 | |||
1962 | /* Initialize field of video device */ | ||
1963 | *vfd = vpif_video_template; | ||
1964 | vfd->v4l2_dev = &vpif_obj.v4l2_dev; | ||
1965 | vfd->release = video_device_release; | ||
1966 | snprintf(vfd->name, sizeof(vfd->name), | ||
1967 | "DM646x_VPIFCapture_DRIVER_V%d.%d.%d", | ||
1968 | (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff, | ||
1969 | (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff, | ||
1970 | (VPIF_CAPTURE_VERSION_CODE) & 0xff); | ||
1971 | /* Set video_dev to the video device */ | ||
1972 | ch->video_dev = vfd; | ||
1973 | } | ||
1974 | |||
1975 | for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { | ||
1976 | ch = vpif_obj.dev[j]; | ||
1977 | ch->channel_id = j; | ||
1978 | common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
1979 | spin_lock_init(&common->irqlock); | ||
1980 | mutex_init(&common->lock); | ||
1981 | /* Initialize prio member of channel object */ | ||
1982 | v4l2_prio_init(&ch->prio); | ||
1983 | err = video_register_device(ch->video_dev, | ||
1984 | VFL_TYPE_GRABBER, (j ? 1 : 0)); | ||
1985 | if (err) | ||
1986 | goto probe_out; | ||
1987 | |||
1988 | video_set_drvdata(ch->video_dev, ch); | ||
1989 | |||
1990 | } | ||
1991 | |||
1992 | i2c_adap = i2c_get_adapter(1); | ||
1993 | config = pdev->dev.platform_data; | ||
1994 | |||
1995 | subdev_count = config->subdev_count; | ||
1996 | vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count, | ||
1997 | GFP_KERNEL); | ||
1998 | if (vpif_obj.sd == NULL) { | ||
1999 | vpif_err("unable to allocate memory for subdevice pointers\n"); | ||
2000 | err = -ENOMEM; | ||
2001 | goto probe_out; | ||
2002 | } | ||
2003 | |||
2004 | err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); | ||
2005 | if (err) { | ||
2006 | v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); | ||
2007 | goto probe_subdev_out; | ||
2008 | } | ||
2009 | |||
2010 | for (i = 0; i < subdev_count; i++) { | ||
2011 | subdevdata = &config->subdev_info[i]; | ||
2012 | vpif_obj.sd[i] = | ||
2013 | v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, | ||
2014 | i2c_adap, | ||
2015 | subdevdata->name, | ||
2016 | &subdevdata->board_info, | ||
2017 | NULL); | ||
2018 | |||
2019 | if (!vpif_obj.sd[i]) { | ||
2020 | vpif_err("Error registering v4l2 subdevice\n"); | ||
2021 | goto probe_subdev_out; | ||
2022 | } | ||
2023 | v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", | ||
2024 | subdevdata->name); | ||
2025 | |||
2026 | if (vpif_obj.sd[i]) | ||
2027 | vpif_obj.sd[i]->grp_id = 1 << i; | ||
2028 | } | ||
2029 | v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver" | ||
2030 | " initialized\n"); | ||
2031 | |||
2032 | return 0; | ||
2033 | |||
2034 | probe_subdev_out: | ||
2035 | /* free sub devices memory */ | ||
2036 | kfree(vpif_obj.sd); | ||
2037 | |||
2038 | j = VPIF_CAPTURE_MAX_DEVICES; | ||
2039 | probe_out: | ||
2040 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
2041 | for (k = 0; k < j; k++) { | ||
2042 | /* Get the pointer to the channel object */ | ||
2043 | ch = vpif_obj.dev[k]; | ||
2044 | /* Unregister video device */ | ||
2045 | video_unregister_device(ch->video_dev); | ||
2046 | } | ||
2047 | |||
2048 | vpif_dev_alloc_err: | ||
2049 | k = VPIF_CAPTURE_MAX_DEVICES-1; | ||
2050 | res = platform_get_resource(pdev, IORESOURCE_IRQ, k); | ||
2051 | i = res->end; | ||
2052 | |||
2053 | vpif_int_err: | ||
2054 | for (q = k; q >= 0; q--) { | ||
2055 | for (m = i; m >= (int)res->start; m--) | ||
2056 | free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); | ||
2057 | |||
2058 | res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); | ||
2059 | if (res) | ||
2060 | i = res->end; | ||
2061 | } | ||
2062 | return err; | ||
2063 | } | ||
2064 | |||
2065 | /** | ||
2066 | * vpif_remove() - driver remove handler | ||
2067 | * @device: ptr to platform device structure | ||
2068 | * | ||
2069 | * The vidoe device is unregistered | ||
2070 | */ | ||
2071 | static int vpif_remove(struct platform_device *device) | ||
2072 | { | ||
2073 | int i; | ||
2074 | struct channel_obj *ch; | ||
2075 | |||
2076 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
2077 | |||
2078 | /* un-register device */ | ||
2079 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
2080 | /* Get the pointer to the channel object */ | ||
2081 | ch = vpif_obj.dev[i]; | ||
2082 | /* Unregister video device */ | ||
2083 | video_unregister_device(ch->video_dev); | ||
2084 | } | ||
2085 | return 0; | ||
2086 | } | ||
2087 | |||
2088 | /** | ||
2089 | * vpif_suspend: vpif device suspend | ||
2090 | * | ||
2091 | * TODO: Add suspend code here | ||
2092 | */ | ||
2093 | static int | ||
2094 | vpif_suspend(struct device *dev) | ||
2095 | { | ||
2096 | return -1; | ||
2097 | } | ||
2098 | |||
2099 | /** | ||
2100 | * vpif_resume: vpif device suspend | ||
2101 | * | ||
2102 | * TODO: Add resume code here | ||
2103 | */ | ||
2104 | static int | ||
2105 | vpif_resume(struct device *dev) | ||
2106 | { | ||
2107 | return -1; | ||
2108 | } | ||
2109 | |||
2110 | static struct dev_pm_ops vpif_dev_pm_ops = { | ||
2111 | .suspend = vpif_suspend, | ||
2112 | .resume = vpif_resume, | ||
2113 | }; | ||
2114 | |||
2115 | static struct platform_driver vpif_driver = { | ||
2116 | .driver = { | ||
2117 | .name = "vpif_capture", | ||
2118 | .owner = THIS_MODULE, | ||
2119 | .pm = &vpif_dev_pm_ops, | ||
2120 | }, | ||
2121 | .probe = vpif_probe, | ||
2122 | .remove = vpif_remove, | ||
2123 | }; | ||
2124 | |||
2125 | /** | ||
2126 | * vpif_init: initialize the vpif driver | ||
2127 | * | ||
2128 | * This function registers device and driver to the kernel, requests irq | ||
2129 | * handler and allocates memory | ||
2130 | * for channel objects | ||
2131 | */ | ||
2132 | static __init int vpif_init(void) | ||
2133 | { | ||
2134 | return platform_driver_register(&vpif_driver); | ||
2135 | } | ||
2136 | |||
2137 | /** | ||
2138 | * vpif_cleanup : This function clean up the vpif capture resources | ||
2139 | * | ||
2140 | * This will un-registers device and driver to the kernel, frees | ||
2141 | * requested irq handler and de-allocates memory allocated for channel | ||
2142 | * objects. | ||
2143 | */ | ||
2144 | static void vpif_cleanup(void) | ||
2145 | { | ||
2146 | struct platform_device *pdev; | ||
2147 | struct resource *res; | ||
2148 | int irq_num; | ||
2149 | int i = 0; | ||
2150 | |||
2151 | pdev = container_of(vpif_dev, struct platform_device, dev); | ||
2152 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { | ||
2153 | for (irq_num = res->start; irq_num <= res->end; irq_num++) | ||
2154 | free_irq(irq_num, | ||
2155 | (void *)(&vpif_obj.dev[i]->channel_id)); | ||
2156 | i++; | ||
2157 | } | ||
2158 | |||
2159 | platform_driver_unregister(&vpif_driver); | ||
2160 | |||
2161 | kfree(vpif_obj.sd); | ||
2162 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) | ||
2163 | kfree(vpif_obj.dev[i]); | ||
2164 | } | ||
2165 | |||
2166 | /* Function for module initialization and cleanup */ | ||
2167 | module_init(vpif_init); | ||
2168 | module_exit(vpif_cleanup); | ||
diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h new file mode 100644 index 000000000000..4e12ec8cac6f --- /dev/null +++ b/drivers/media/video/davinci/vpif_capture.h | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Texas Instruments Inc | ||
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 | #ifndef VPIF_CAPTURE_H | ||
20 | #define VPIF_CAPTURE_H | ||
21 | |||
22 | #ifdef __KERNEL__ | ||
23 | |||
24 | /* Header files */ | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <linux/version.h> | ||
27 | #include <media/v4l2-common.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/videobuf-core.h> | ||
30 | #include <media/videobuf-dma-contig.h> | ||
31 | #include <mach/dm646x.h> | ||
32 | |||
33 | #include "vpif.h" | ||
34 | |||
35 | /* Macros */ | ||
36 | #define VPIF_MAJOR_RELEASE 0 | ||
37 | #define VPIF_MINOR_RELEASE 0 | ||
38 | #define VPIF_BUILD 1 | ||
39 | #define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \ | ||
40 | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) | ||
41 | |||
42 | #define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ | ||
43 | (V4L2_FIELD_NONE == field)) || \ | ||
44 | (((V4L2_FIELD_INTERLACED == field) || \ | ||
45 | (V4L2_FIELD_SEQ_TB == field)) || \ | ||
46 | (V4L2_FIELD_SEQ_BT == field))) | ||
47 | |||
48 | #define VPIF_CAPTURE_MAX_DEVICES 2 | ||
49 | #define VPIF_VIDEO_INDEX 0 | ||
50 | #define VPIF_NUMBER_OF_OBJECTS 1 | ||
51 | |||
52 | /* Enumerated data type to give id to each device per channel */ | ||
53 | enum vpif_channel_id { | ||
54 | VPIF_CHANNEL0_VIDEO = 0, | ||
55 | VPIF_CHANNEL1_VIDEO, | ||
56 | }; | ||
57 | |||
58 | struct video_obj { | ||
59 | enum v4l2_field buf_field; | ||
60 | /* Currently selected or default standard */ | ||
61 | v4l2_std_id stdid; | ||
62 | /* This is to track the last input that is passed to application */ | ||
63 | u32 input_idx; | ||
64 | }; | ||
65 | |||
66 | struct common_obj { | ||
67 | /* Pointer pointing to current v4l2_buffer */ | ||
68 | struct videobuf_buffer *cur_frm; | ||
69 | /* Pointer pointing to current v4l2_buffer */ | ||
70 | struct videobuf_buffer *next_frm; | ||
71 | /* | ||
72 | * This field keeps track of type of buffer exchange mechanism | ||
73 | * user has selected | ||
74 | */ | ||
75 | enum v4l2_memory memory; | ||
76 | /* Used to store pixel format */ | ||
77 | struct v4l2_format fmt; | ||
78 | /* Buffer queue used in video-buf */ | ||
79 | struct videobuf_queue buffer_queue; | ||
80 | /* Queue of filled frames */ | ||
81 | struct list_head dma_queue; | ||
82 | /* Used in video-buf */ | ||
83 | spinlock_t irqlock; | ||
84 | /* lock used to access this structure */ | ||
85 | struct mutex lock; | ||
86 | /* number of users performing IO */ | ||
87 | u32 io_usrs; | ||
88 | /* Indicates whether streaming started */ | ||
89 | u8 started; | ||
90 | /* Function pointer to set the addresses */ | ||
91 | void (*set_addr) (unsigned long, unsigned long, unsigned long, | ||
92 | unsigned long); | ||
93 | /* offset where Y top starts from the starting of the buffer */ | ||
94 | u32 ytop_off; | ||
95 | /* offset where Y bottom starts from the starting of the buffer */ | ||
96 | u32 ybtm_off; | ||
97 | /* offset where C top starts from the starting of the buffer */ | ||
98 | u32 ctop_off; | ||
99 | /* offset where C bottom starts from the starting of the buffer */ | ||
100 | u32 cbtm_off; | ||
101 | /* Indicates width of the image data */ | ||
102 | u32 width; | ||
103 | /* Indicates height of the image data */ | ||
104 | u32 height; | ||
105 | }; | ||
106 | |||
107 | struct channel_obj { | ||
108 | /* Identifies video device for this channel */ | ||
109 | struct video_device *video_dev; | ||
110 | /* Used to keep track of state of the priority */ | ||
111 | struct v4l2_prio_state prio; | ||
112 | /* number of open instances of the channel */ | ||
113 | int usrs; | ||
114 | /* Indicates id of the field which is being displayed */ | ||
115 | u32 field_id; | ||
116 | /* flag to indicate whether decoder is initialized */ | ||
117 | u8 initialized; | ||
118 | /* Identifies channel */ | ||
119 | enum vpif_channel_id channel_id; | ||
120 | /* index into sd table */ | ||
121 | int curr_sd_index; | ||
122 | /* ptr to current sub device information */ | ||
123 | struct vpif_subdev_info *curr_subdev_info; | ||
124 | /* vpif configuration params */ | ||
125 | struct vpif_params vpifparams; | ||
126 | /* common object array */ | ||
127 | struct common_obj common[VPIF_NUMBER_OF_OBJECTS]; | ||
128 | /* video object */ | ||
129 | struct video_obj video; | ||
130 | }; | ||
131 | |||
132 | /* File handle structure */ | ||
133 | struct vpif_fh { | ||
134 | /* pointer to channel object for opened device */ | ||
135 | struct channel_obj *channel; | ||
136 | /* Indicates whether this file handle is doing IO */ | ||
137 | u8 io_allowed[VPIF_NUMBER_OF_OBJECTS]; | ||
138 | /* Used to keep track priority of this instance */ | ||
139 | enum v4l2_priority prio; | ||
140 | /* Used to indicate channel is initialize or not */ | ||
141 | u8 initialized; | ||
142 | }; | ||
143 | |||
144 | struct vpif_device { | ||
145 | struct v4l2_device v4l2_dev; | ||
146 | struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS]; | ||
147 | struct v4l2_subdev **sd; | ||
148 | }; | ||
149 | |||
150 | struct vpif_config_params { | ||
151 | u8 min_numbuffers; | ||
152 | u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS]; | ||
153 | s8 device_type; | ||
154 | u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; | ||
155 | u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; | ||
156 | u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; | ||
157 | u8 max_device_type; | ||
158 | }; | ||
159 | /* Struct which keeps track of the line numbers for the sliced vbi service */ | ||
160 | struct vpif_service_line { | ||
161 | u16 service_id; | ||
162 | u16 service_line[2]; | ||
163 | }; | ||
164 | #endif /* End of __KERNEL__ */ | ||
165 | #endif /* VPIF_CAPTURE_H */ | ||
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c new file mode 100644 index 000000000000..c015da813dda --- /dev/null +++ b/drivers/media/video/davinci/vpif_display.c | |||
@@ -0,0 +1,1656 @@ | |||
1 | /* | ||
2 | * vpif-display - VPIF display driver | ||
3 | * Display driver for TI DaVinci VPIF | ||
4 | * | ||
5 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation version 2. | ||
10 | * | ||
11 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
12 | * kind, whether express or implied; without even the implied warranty | ||
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/io.h> | ||
32 | #include <linux/version.h> | ||
33 | |||
34 | #include <asm/irq.h> | ||
35 | #include <asm/page.h> | ||
36 | |||
37 | #include <media/adv7343.h> | ||
38 | #include <media/v4l2-device.h> | ||
39 | #include <media/v4l2-ioctl.h> | ||
40 | |||
41 | #include <mach/dm646x.h> | ||
42 | |||
43 | #include "vpif_display.h" | ||
44 | #include "vpif.h" | ||
45 | |||
46 | MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | |||
49 | #define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) | ||
50 | |||
51 | #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) | ||
52 | #define vpif_dbg(level, debug, fmt, arg...) \ | ||
53 | v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) | ||
54 | |||
55 | static int debug = 1; | ||
56 | static u32 ch2_numbuffers = 3; | ||
57 | static u32 ch3_numbuffers = 3; | ||
58 | static u32 ch2_bufsize = 1920 * 1080 * 2; | ||
59 | static u32 ch3_bufsize = 720 * 576 * 2; | ||
60 | |||
61 | module_param(debug, int, 0644); | ||
62 | module_param(ch2_numbuffers, uint, S_IRUGO); | ||
63 | module_param(ch3_numbuffers, uint, S_IRUGO); | ||
64 | module_param(ch2_bufsize, uint, S_IRUGO); | ||
65 | module_param(ch3_bufsize, uint, S_IRUGO); | ||
66 | |||
67 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
68 | MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)"); | ||
69 | MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)"); | ||
70 | MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)"); | ||
71 | MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)"); | ||
72 | |||
73 | static struct vpif_config_params config_params = { | ||
74 | .min_numbuffers = 3, | ||
75 | .numbuffers[0] = 3, | ||
76 | .numbuffers[1] = 3, | ||
77 | .min_bufsize[0] = 720 * 480 * 2, | ||
78 | .min_bufsize[1] = 720 * 480 * 2, | ||
79 | .channel_bufsize[0] = 1920 * 1080 * 2, | ||
80 | .channel_bufsize[1] = 720 * 576 * 2, | ||
81 | }; | ||
82 | |||
83 | static struct vpif_device vpif_obj = { {NULL} }; | ||
84 | static struct device *vpif_dev; | ||
85 | |||
86 | static const struct vpif_channel_config_params ch_params[] = { | ||
87 | { | ||
88 | "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, | ||
89 | 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, | ||
90 | }, | ||
91 | { | ||
92 | "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, | ||
93 | 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * vpif_uservirt_to_phys: This function is used to convert user | ||
99 | * space virtual address to physical address. | ||
100 | */ | ||
101 | static u32 vpif_uservirt_to_phys(u32 virtp) | ||
102 | { | ||
103 | struct mm_struct *mm = current->mm; | ||
104 | unsigned long physp = 0; | ||
105 | struct vm_area_struct *vma; | ||
106 | |||
107 | vma = find_vma(mm, virtp); | ||
108 | |||
109 | /* For kernel direct-mapped memory, take the easy way */ | ||
110 | if (virtp >= PAGE_OFFSET) { | ||
111 | physp = virt_to_phys((void *)virtp); | ||
112 | } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { | ||
113 | /* this will catch, kernel-allocated, mmaped-to-usermode addr */ | ||
114 | physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); | ||
115 | } else { | ||
116 | /* otherwise, use get_user_pages() for general userland pages */ | ||
117 | int res, nr_pages = 1; | ||
118 | struct page *pages; | ||
119 | down_read(¤t->mm->mmap_sem); | ||
120 | |||
121 | res = get_user_pages(current, current->mm, | ||
122 | virtp, nr_pages, 1, 0, &pages, NULL); | ||
123 | up_read(¤t->mm->mmap_sem); | ||
124 | |||
125 | if (res == nr_pages) { | ||
126 | physp = __pa(page_address(&pages[0]) + | ||
127 | (virtp & ~PAGE_MASK)); | ||
128 | } else { | ||
129 | vpif_err("get_user_pages failed\n"); | ||
130 | return 0; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | return physp; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * buffer_prepare: This is the callback function called from videobuf_qbuf() | ||
139 | * function the buffer is prepared and user space virtual address is converted | ||
140 | * into physical address | ||
141 | */ | ||
142 | static int vpif_buffer_prepare(struct videobuf_queue *q, | ||
143 | struct videobuf_buffer *vb, | ||
144 | enum v4l2_field field) | ||
145 | { | ||
146 | struct vpif_fh *fh = q->priv_data; | ||
147 | struct common_obj *common; | ||
148 | unsigned long addr; | ||
149 | |||
150 | common = &fh->channel->common[VPIF_VIDEO_INDEX]; | ||
151 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
152 | vb->width = common->width; | ||
153 | vb->height = common->height; | ||
154 | vb->size = vb->width * vb->height; | ||
155 | vb->field = field; | ||
156 | } | ||
157 | vb->state = VIDEOBUF_PREPARED; | ||
158 | |||
159 | /* if user pointer memory mechanism is used, get the physical | ||
160 | * address of the buffer */ | ||
161 | if (V4L2_MEMORY_USERPTR == common->memory) { | ||
162 | if (!vb->baddr) { | ||
163 | vpif_err("buffer_address is 0\n"); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | vb->boff = vpif_uservirt_to_phys(vb->baddr); | ||
168 | if (!ISALIGNED(vb->boff)) | ||
169 | goto buf_align_exit; | ||
170 | } | ||
171 | |||
172 | addr = vb->boff; | ||
173 | if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { | ||
174 | if (!ISALIGNED(addr + common->ytop_off) || | ||
175 | !ISALIGNED(addr + common->ybtm_off) || | ||
176 | !ISALIGNED(addr + common->ctop_off) || | ||
177 | !ISALIGNED(addr + common->cbtm_off)) | ||
178 | goto buf_align_exit; | ||
179 | } | ||
180 | return 0; | ||
181 | |||
182 | buf_align_exit: | ||
183 | vpif_err("buffer offset not aligned to 8 bytes\n"); | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * vpif_buffer_setup: This function allocates memory for the buffers | ||
189 | */ | ||
190 | static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
191 | unsigned int *size) | ||
192 | { | ||
193 | struct vpif_fh *fh = q->priv_data; | ||
194 | struct channel_obj *ch = fh->channel; | ||
195 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
196 | |||
197 | if (V4L2_MEMORY_MMAP != common->memory) | ||
198 | return 0; | ||
199 | |||
200 | *size = config_params.channel_bufsize[ch->channel_id]; | ||
201 | if (*count < config_params.min_numbuffers) | ||
202 | *count = config_params.min_numbuffers; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * vpif_buffer_queue: This function adds the buffer to DMA queue | ||
209 | */ | ||
210 | static void vpif_buffer_queue(struct videobuf_queue *q, | ||
211 | struct videobuf_buffer *vb) | ||
212 | { | ||
213 | struct vpif_fh *fh = q->priv_data; | ||
214 | struct common_obj *common; | ||
215 | |||
216 | common = &fh->channel->common[VPIF_VIDEO_INDEX]; | ||
217 | |||
218 | /* add the buffer to the DMA queue */ | ||
219 | list_add_tail(&vb->queue, &common->dma_queue); | ||
220 | vb->state = VIDEOBUF_QUEUED; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * vpif_buffer_release: This function is called from the videobuf layer to | ||
225 | * free memory allocated to the buffers | ||
226 | */ | ||
227 | static void vpif_buffer_release(struct videobuf_queue *q, | ||
228 | struct videobuf_buffer *vb) | ||
229 | { | ||
230 | struct vpif_fh *fh = q->priv_data; | ||
231 | struct channel_obj *ch = fh->channel; | ||
232 | struct common_obj *common; | ||
233 | unsigned int buf_size = 0; | ||
234 | |||
235 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
236 | |||
237 | videobuf_dma_contig_free(q, vb); | ||
238 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
239 | |||
240 | if (V4L2_MEMORY_MMAP != common->memory) | ||
241 | return; | ||
242 | |||
243 | buf_size = config_params.channel_bufsize[ch->channel_id]; | ||
244 | } | ||
245 | |||
246 | static struct videobuf_queue_ops video_qops = { | ||
247 | .buf_setup = vpif_buffer_setup, | ||
248 | .buf_prepare = vpif_buffer_prepare, | ||
249 | .buf_queue = vpif_buffer_queue, | ||
250 | .buf_release = vpif_buffer_release, | ||
251 | }; | ||
252 | static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} }; | ||
253 | |||
254 | static void process_progressive_mode(struct common_obj *common) | ||
255 | { | ||
256 | unsigned long addr = 0; | ||
257 | |||
258 | /* Get the next buffer from buffer queue */ | ||
259 | common->next_frm = list_entry(common->dma_queue.next, | ||
260 | struct videobuf_buffer, queue); | ||
261 | /* Remove that buffer from the buffer queue */ | ||
262 | list_del(&common->next_frm->queue); | ||
263 | /* Mark status of the buffer as active */ | ||
264 | common->next_frm->state = VIDEOBUF_ACTIVE; | ||
265 | |||
266 | /* Set top and bottom field addrs in VPIF registers */ | ||
267 | addr = videobuf_to_dma_contig(common->next_frm); | ||
268 | common->set_addr(addr + common->ytop_off, | ||
269 | addr + common->ybtm_off, | ||
270 | addr + common->ctop_off, | ||
271 | addr + common->cbtm_off); | ||
272 | } | ||
273 | |||
274 | static void process_interlaced_mode(int fid, struct common_obj *common) | ||
275 | { | ||
276 | /* device field id and local field id are in sync */ | ||
277 | /* If this is even field */ | ||
278 | if (0 == fid) { | ||
279 | if (common->cur_frm == common->next_frm) | ||
280 | return; | ||
281 | |||
282 | /* one frame is displayed If next frame is | ||
283 | * available, release cur_frm and move on */ | ||
284 | /* Copy frame display time */ | ||
285 | do_gettimeofday(&common->cur_frm->ts); | ||
286 | /* Change status of the cur_frm */ | ||
287 | common->cur_frm->state = VIDEOBUF_DONE; | ||
288 | /* unlock semaphore on cur_frm */ | ||
289 | wake_up_interruptible(&common->cur_frm->done); | ||
290 | /* Make cur_frm pointing to next_frm */ | ||
291 | common->cur_frm = common->next_frm; | ||
292 | |||
293 | } else if (1 == fid) { /* odd field */ | ||
294 | if (list_empty(&common->dma_queue) | ||
295 | || (common->cur_frm != common->next_frm)) { | ||
296 | return; | ||
297 | } | ||
298 | /* one field is displayed configure the next | ||
299 | * frame if it is available else hold on current | ||
300 | * frame */ | ||
301 | /* Get next from the buffer queue */ | ||
302 | process_progressive_mode(common); | ||
303 | |||
304 | } | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * vpif_channel_isr: It changes status of the displayed buffer, takes next | ||
309 | * buffer from the queue and sets its address in VPIF registers | ||
310 | */ | ||
311 | static irqreturn_t vpif_channel_isr(int irq, void *dev_id) | ||
312 | { | ||
313 | struct vpif_device *dev = &vpif_obj; | ||
314 | struct channel_obj *ch; | ||
315 | struct common_obj *common; | ||
316 | enum v4l2_field field; | ||
317 | int fid = -1, i; | ||
318 | int channel_id = 0; | ||
319 | |||
320 | channel_id = *(int *)(dev_id); | ||
321 | ch = dev->dev[channel_id]; | ||
322 | field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; | ||
323 | for (i = 0; i < VPIF_NUMOBJECTS; i++) { | ||
324 | common = &ch->common[i]; | ||
325 | /* If streaming is started in this channel */ | ||
326 | if (0 == common->started) | ||
327 | continue; | ||
328 | |||
329 | if (1 == ch->vpifparams.std_info.frm_fmt) { | ||
330 | if (list_empty(&common->dma_queue)) | ||
331 | continue; | ||
332 | |||
333 | /* Progressive mode */ | ||
334 | if (!channel_first_int[i][channel_id]) { | ||
335 | /* Mark status of the cur_frm to | ||
336 | * done and unlock semaphore on it */ | ||
337 | do_gettimeofday(&common->cur_frm->ts); | ||
338 | common->cur_frm->state = VIDEOBUF_DONE; | ||
339 | wake_up_interruptible(&common->cur_frm->done); | ||
340 | /* Make cur_frm pointing to next_frm */ | ||
341 | common->cur_frm = common->next_frm; | ||
342 | } | ||
343 | |||
344 | channel_first_int[i][channel_id] = 0; | ||
345 | process_progressive_mode(common); | ||
346 | } else { | ||
347 | /* Interlaced mode */ | ||
348 | /* If it is first interrupt, ignore it */ | ||
349 | |||
350 | if (channel_first_int[i][channel_id]) { | ||
351 | channel_first_int[i][channel_id] = 0; | ||
352 | continue; | ||
353 | } | ||
354 | |||
355 | if (0 == i) { | ||
356 | ch->field_id ^= 1; | ||
357 | /* Get field id from VPIF registers */ | ||
358 | fid = vpif_channel_getfid(ch->channel_id + 2); | ||
359 | /* If fid does not match with stored field id */ | ||
360 | if (fid != ch->field_id) { | ||
361 | /* Make them in sync */ | ||
362 | if (0 == fid) | ||
363 | ch->field_id = fid; | ||
364 | |||
365 | return IRQ_HANDLED; | ||
366 | } | ||
367 | } | ||
368 | process_interlaced_mode(fid, common); | ||
369 | } | ||
370 | } | ||
371 | |||
372 | return IRQ_HANDLED; | ||
373 | } | ||
374 | |||
375 | static int vpif_get_std_info(struct channel_obj *ch) | ||
376 | { | ||
377 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
378 | struct video_obj *vid_ch = &ch->video; | ||
379 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
380 | struct vpif_channel_config_params *std_info = &vpifparams->std_info; | ||
381 | const struct vpif_channel_config_params *config; | ||
382 | |||
383 | int index; | ||
384 | |||
385 | std_info->stdid = vid_ch->stdid; | ||
386 | if (!std_info) | ||
387 | return -1; | ||
388 | |||
389 | for (index = 0; index < ARRAY_SIZE(ch_params); index++) { | ||
390 | config = &ch_params[index]; | ||
391 | if (config->stdid & std_info->stdid) { | ||
392 | memcpy(std_info, config, sizeof(*config)); | ||
393 | break; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | if (index == ARRAY_SIZE(ch_params)) | ||
398 | return -1; | ||
399 | |||
400 | common->fmt.fmt.pix.width = std_info->width; | ||
401 | common->fmt.fmt.pix.height = std_info->height; | ||
402 | vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n", | ||
403 | common->fmt.fmt.pix.width, common->fmt.fmt.pix.height); | ||
404 | |||
405 | /* Set height and width paramateres */ | ||
406 | ch->common[VPIF_VIDEO_INDEX].height = std_info->height; | ||
407 | ch->common[VPIF_VIDEO_INDEX].width = std_info->width; | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * vpif_calculate_offsets: This function calculates buffers offset for Y and C | ||
414 | * in the top and bottom field | ||
415 | */ | ||
416 | static void vpif_calculate_offsets(struct channel_obj *ch) | ||
417 | { | ||
418 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
419 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
420 | enum v4l2_field field = common->fmt.fmt.pix.field; | ||
421 | struct video_obj *vid_ch = &ch->video; | ||
422 | unsigned int hpitch, vpitch, sizeimage; | ||
423 | |||
424 | if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { | ||
425 | if (ch->vpifparams.std_info.frm_fmt) | ||
426 | vid_ch->buf_field = V4L2_FIELD_NONE; | ||
427 | else | ||
428 | vid_ch->buf_field = V4L2_FIELD_INTERLACED; | ||
429 | } else { | ||
430 | vid_ch->buf_field = common->fmt.fmt.pix.field; | ||
431 | } | ||
432 | |||
433 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
434 | sizeimage = common->fmt.fmt.pix.sizeimage; | ||
435 | else | ||
436 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
437 | |||
438 | hpitch = common->fmt.fmt.pix.bytesperline; | ||
439 | vpitch = sizeimage / (hpitch * 2); | ||
440 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
441 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { | ||
442 | common->ytop_off = 0; | ||
443 | common->ybtm_off = hpitch; | ||
444 | common->ctop_off = sizeimage / 2; | ||
445 | common->cbtm_off = sizeimage / 2 + hpitch; | ||
446 | } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { | ||
447 | common->ytop_off = 0; | ||
448 | common->ybtm_off = sizeimage / 4; | ||
449 | common->ctop_off = sizeimage / 2; | ||
450 | common->cbtm_off = common->ctop_off + sizeimage / 4; | ||
451 | } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { | ||
452 | common->ybtm_off = 0; | ||
453 | common->ytop_off = sizeimage / 4; | ||
454 | common->cbtm_off = sizeimage / 2; | ||
455 | common->ctop_off = common->cbtm_off + sizeimage / 4; | ||
456 | } | ||
457 | |||
458 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
459 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { | ||
460 | vpifparams->video_params.storage_mode = 1; | ||
461 | } else { | ||
462 | vpifparams->video_params.storage_mode = 0; | ||
463 | } | ||
464 | |||
465 | if (ch->vpifparams.std_info.frm_fmt == 1) { | ||
466 | vpifparams->video_params.hpitch = | ||
467 | common->fmt.fmt.pix.bytesperline; | ||
468 | } else { | ||
469 | if ((field == V4L2_FIELD_ANY) || | ||
470 | (field == V4L2_FIELD_INTERLACED)) | ||
471 | vpifparams->video_params.hpitch = | ||
472 | common->fmt.fmt.pix.bytesperline * 2; | ||
473 | else | ||
474 | vpifparams->video_params.hpitch = | ||
475 | common->fmt.fmt.pix.bytesperline; | ||
476 | } | ||
477 | |||
478 | ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid; | ||
479 | } | ||
480 | |||
481 | static void vpif_config_format(struct channel_obj *ch) | ||
482 | { | ||
483 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
484 | |||
485 | common->fmt.fmt.pix.field = V4L2_FIELD_ANY; | ||
486 | if (config_params.numbuffers[ch->channel_id] == 0) | ||
487 | common->memory = V4L2_MEMORY_USERPTR; | ||
488 | else | ||
489 | common->memory = V4L2_MEMORY_MMAP; | ||
490 | |||
491 | common->fmt.fmt.pix.sizeimage = | ||
492 | config_params.channel_bufsize[ch->channel_id]; | ||
493 | common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; | ||
494 | common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
495 | } | ||
496 | |||
497 | static int vpif_check_format(struct channel_obj *ch, | ||
498 | struct v4l2_pix_format *pixfmt) | ||
499 | { | ||
500 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
501 | enum v4l2_field field = pixfmt->field; | ||
502 | u32 sizeimage, hpitch, vpitch; | ||
503 | |||
504 | if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) | ||
505 | goto invalid_fmt_exit; | ||
506 | |||
507 | if (!(VPIF_VALID_FIELD(field))) | ||
508 | goto invalid_fmt_exit; | ||
509 | |||
510 | if (pixfmt->bytesperline <= 0) | ||
511 | goto invalid_pitch_exit; | ||
512 | |||
513 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
514 | sizeimage = pixfmt->sizeimage; | ||
515 | else | ||
516 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
517 | |||
518 | if (vpif_get_std_info(ch)) { | ||
519 | vpif_err("Error getting the standard info\n"); | ||
520 | return -EINVAL; | ||
521 | } | ||
522 | |||
523 | hpitch = pixfmt->bytesperline; | ||
524 | vpitch = sizeimage / (hpitch * 2); | ||
525 | |||
526 | /* Check for valid value of pitch */ | ||
527 | if ((hpitch < ch->vpifparams.std_info.width) || | ||
528 | (vpitch < ch->vpifparams.std_info.height)) | ||
529 | goto invalid_pitch_exit; | ||
530 | |||
531 | /* Check for 8 byte alignment */ | ||
532 | if (!ISALIGNED(hpitch)) { | ||
533 | vpif_err("invalid pitch alignment\n"); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | pixfmt->width = common->fmt.fmt.pix.width; | ||
537 | pixfmt->height = common->fmt.fmt.pix.height; | ||
538 | |||
539 | return 0; | ||
540 | |||
541 | invalid_fmt_exit: | ||
542 | vpif_err("invalid field format\n"); | ||
543 | return -EINVAL; | ||
544 | |||
545 | invalid_pitch_exit: | ||
546 | vpif_err("invalid pitch\n"); | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | |||
550 | static void vpif_config_addr(struct channel_obj *ch, int muxmode) | ||
551 | { | ||
552 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
553 | |||
554 | if (VPIF_CHANNEL3_VIDEO == ch->channel_id) { | ||
555 | common->set_addr = ch3_set_videobuf_addr; | ||
556 | } else { | ||
557 | if (2 == muxmode) | ||
558 | common->set_addr = ch2_set_videobuf_addr_yc_nmux; | ||
559 | else | ||
560 | common->set_addr = ch2_set_videobuf_addr; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * vpif_mmap: It is used to map kernel space buffers into user spaces | ||
566 | */ | ||
567 | static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) | ||
568 | { | ||
569 | struct vpif_fh *fh = filep->private_data; | ||
570 | struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX]; | ||
571 | |||
572 | return videobuf_mmap_mapper(&common->buffer_queue, vma); | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | * vpif_poll: It is used for select/poll system call | ||
577 | */ | ||
578 | static unsigned int vpif_poll(struct file *filep, poll_table *wait) | ||
579 | { | ||
580 | struct vpif_fh *fh = filep->private_data; | ||
581 | struct channel_obj *ch = fh->channel; | ||
582 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
583 | |||
584 | if (common->started) | ||
585 | return videobuf_poll_stream(filep, &common->buffer_queue, wait); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | /* | ||
591 | * vpif_open: It creates object of file handle structure and stores it in | ||
592 | * private_data member of filepointer | ||
593 | */ | ||
594 | static int vpif_open(struct file *filep) | ||
595 | { | ||
596 | struct video_device *vdev = video_devdata(filep); | ||
597 | struct channel_obj *ch = NULL; | ||
598 | struct vpif_fh *fh = NULL; | ||
599 | |||
600 | ch = video_get_drvdata(vdev); | ||
601 | /* Allocate memory for the file handle object */ | ||
602 | fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL); | ||
603 | if (fh == NULL) { | ||
604 | vpif_err("unable to allocate memory for file handle object\n"); | ||
605 | return -ENOMEM; | ||
606 | } | ||
607 | |||
608 | /* store pointer to fh in private_data member of filep */ | ||
609 | filep->private_data = fh; | ||
610 | fh->channel = ch; | ||
611 | fh->initialized = 0; | ||
612 | if (!ch->initialized) { | ||
613 | fh->initialized = 1; | ||
614 | ch->initialized = 1; | ||
615 | memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); | ||
616 | } | ||
617 | |||
618 | /* Increment channel usrs counter */ | ||
619 | atomic_inc(&ch->usrs); | ||
620 | /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */ | ||
621 | fh->io_allowed[VPIF_VIDEO_INDEX] = 0; | ||
622 | /* Initialize priority of this instance to default priority */ | ||
623 | fh->prio = V4L2_PRIORITY_UNSET; | ||
624 | v4l2_prio_open(&ch->prio, &fh->prio); | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | /* | ||
630 | * vpif_release: This function deletes buffer queue, frees the buffers and | ||
631 | * the vpif file handle | ||
632 | */ | ||
633 | static int vpif_release(struct file *filep) | ||
634 | { | ||
635 | struct vpif_fh *fh = filep->private_data; | ||
636 | struct channel_obj *ch = fh->channel; | ||
637 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
638 | |||
639 | if (mutex_lock_interruptible(&common->lock)) | ||
640 | return -ERESTARTSYS; | ||
641 | |||
642 | /* if this instance is doing IO */ | ||
643 | if (fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
644 | /* Reset io_usrs member of channel object */ | ||
645 | common->io_usrs = 0; | ||
646 | /* Disable channel */ | ||
647 | if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { | ||
648 | enable_channel2(0); | ||
649 | channel2_intr_enable(0); | ||
650 | } | ||
651 | if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || | ||
652 | (2 == common->started)) { | ||
653 | enable_channel3(0); | ||
654 | channel3_intr_enable(0); | ||
655 | } | ||
656 | common->started = 0; | ||
657 | /* Free buffers allocated */ | ||
658 | videobuf_queue_cancel(&common->buffer_queue); | ||
659 | videobuf_mmap_free(&common->buffer_queue); | ||
660 | common->numbuffers = | ||
661 | config_params.numbuffers[ch->channel_id]; | ||
662 | } | ||
663 | |||
664 | mutex_unlock(&common->lock); | ||
665 | |||
666 | /* Decrement channel usrs counter */ | ||
667 | atomic_dec(&ch->usrs); | ||
668 | /* If this file handle has initialize encoder device, reset it */ | ||
669 | if (fh->initialized) | ||
670 | ch->initialized = 0; | ||
671 | |||
672 | /* Close the priority */ | ||
673 | v4l2_prio_close(&ch->prio, &fh->prio); | ||
674 | filep->private_data = NULL; | ||
675 | fh->initialized = 0; | ||
676 | kfree(fh); | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | /* functions implementing ioctls */ | ||
682 | |||
683 | static int vpif_querycap(struct file *file, void *priv, | ||
684 | struct v4l2_capability *cap) | ||
685 | { | ||
686 | struct vpif_display_config *config = vpif_dev->platform_data; | ||
687 | |||
688 | cap->version = VPIF_DISPLAY_VERSION_CODE; | ||
689 | cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; | ||
690 | strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); | ||
691 | strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); | ||
692 | strlcpy(cap->card, config->card_name, sizeof(cap->card)); | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static int vpif_enum_fmt_vid_out(struct file *file, void *priv, | ||
698 | struct v4l2_fmtdesc *fmt) | ||
699 | { | ||
700 | if (fmt->index != 0) { | ||
701 | vpif_err("Invalid format index\n"); | ||
702 | return -EINVAL; | ||
703 | } | ||
704 | |||
705 | /* Fill in the information about format */ | ||
706 | fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
707 | strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); | ||
708 | fmt->pixelformat = V4L2_PIX_FMT_YUV422P; | ||
709 | |||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | static int vpif_g_fmt_vid_out(struct file *file, void *priv, | ||
714 | struct v4l2_format *fmt) | ||
715 | { | ||
716 | struct vpif_fh *fh = priv; | ||
717 | struct channel_obj *ch = fh->channel; | ||
718 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
719 | |||
720 | /* Check the validity of the buffer type */ | ||
721 | if (common->fmt.type != fmt->type) | ||
722 | return -EINVAL; | ||
723 | |||
724 | /* Fill in the information about format */ | ||
725 | if (mutex_lock_interruptible(&common->lock)) | ||
726 | return -ERESTARTSYS; | ||
727 | |||
728 | if (vpif_get_std_info(ch)) { | ||
729 | vpif_err("Error getting the standard info\n"); | ||
730 | return -EINVAL; | ||
731 | } | ||
732 | |||
733 | *fmt = common->fmt; | ||
734 | mutex_unlock(&common->lock); | ||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static int vpif_s_fmt_vid_out(struct file *file, void *priv, | ||
739 | struct v4l2_format *fmt) | ||
740 | { | ||
741 | struct vpif_fh *fh = priv; | ||
742 | struct v4l2_pix_format *pixfmt; | ||
743 | struct channel_obj *ch = fh->channel; | ||
744 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
745 | int ret = 0; | ||
746 | |||
747 | if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) | ||
748 | || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { | ||
749 | if (!fh->initialized) { | ||
750 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
751 | return -EBUSY; | ||
752 | } | ||
753 | |||
754 | /* Check for the priority */ | ||
755 | ret = v4l2_prio_check(&ch->prio, &fh->prio); | ||
756 | if (0 != ret) | ||
757 | return ret; | ||
758 | fh->initialized = 1; | ||
759 | } | ||
760 | |||
761 | if (common->started) { | ||
762 | vpif_dbg(1, debug, "Streaming in progress\n"); | ||
763 | return -EBUSY; | ||
764 | } | ||
765 | |||
766 | pixfmt = &fmt->fmt.pix; | ||
767 | /* Check for valid field format */ | ||
768 | ret = vpif_check_format(ch, pixfmt); | ||
769 | if (ret) | ||
770 | return ret; | ||
771 | |||
772 | /* store the pix format in the channel object */ | ||
773 | common->fmt.fmt.pix = *pixfmt; | ||
774 | /* store the format in the channel object */ | ||
775 | if (mutex_lock_interruptible(&common->lock)) | ||
776 | return -ERESTARTSYS; | ||
777 | |||
778 | common->fmt = *fmt; | ||
779 | mutex_unlock(&common->lock); | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static int vpif_try_fmt_vid_out(struct file *file, void *priv, | ||
785 | struct v4l2_format *fmt) | ||
786 | { | ||
787 | struct vpif_fh *fh = priv; | ||
788 | struct channel_obj *ch = fh->channel; | ||
789 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
790 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
791 | int ret = 0; | ||
792 | |||
793 | ret = vpif_check_format(ch, pixfmt); | ||
794 | if (ret) { | ||
795 | *pixfmt = common->fmt.fmt.pix; | ||
796 | pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2; | ||
797 | } | ||
798 | |||
799 | return ret; | ||
800 | } | ||
801 | |||
802 | static int vpif_reqbufs(struct file *file, void *priv, | ||
803 | struct v4l2_requestbuffers *reqbuf) | ||
804 | { | ||
805 | struct vpif_fh *fh = priv; | ||
806 | struct channel_obj *ch = fh->channel; | ||
807 | struct common_obj *common; | ||
808 | enum v4l2_field field; | ||
809 | u8 index = 0; | ||
810 | int ret = 0; | ||
811 | |||
812 | /* This file handle has not initialized the channel, | ||
813 | It is not allowed to do settings */ | ||
814 | if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) | ||
815 | || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { | ||
816 | if (!fh->initialized) { | ||
817 | vpif_err("Channel Busy\n"); | ||
818 | return -EBUSY; | ||
819 | } | ||
820 | } | ||
821 | |||
822 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type) | ||
823 | return -EINVAL; | ||
824 | |||
825 | index = VPIF_VIDEO_INDEX; | ||
826 | |||
827 | common = &ch->common[index]; | ||
828 | if (mutex_lock_interruptible(&common->lock)) | ||
829 | return -ERESTARTSYS; | ||
830 | |||
831 | if (common->fmt.type != reqbuf->type) { | ||
832 | ret = -EINVAL; | ||
833 | goto reqbuf_exit; | ||
834 | } | ||
835 | |||
836 | if (0 != common->io_usrs) { | ||
837 | ret = -EBUSY; | ||
838 | goto reqbuf_exit; | ||
839 | } | ||
840 | |||
841 | if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
842 | if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY) | ||
843 | field = V4L2_FIELD_INTERLACED; | ||
844 | else | ||
845 | field = common->fmt.fmt.pix.field; | ||
846 | } else { | ||
847 | field = V4L2_VBI_INTERLACED; | ||
848 | } | ||
849 | |||
850 | /* Initialize videobuf queue as per the buffer type */ | ||
851 | videobuf_queue_dma_contig_init(&common->buffer_queue, | ||
852 | &video_qops, NULL, | ||
853 | &common->irqlock, | ||
854 | reqbuf->type, field, | ||
855 | sizeof(struct videobuf_buffer), fh); | ||
856 | |||
857 | /* Set io allowed member of file handle to TRUE */ | ||
858 | fh->io_allowed[index] = 1; | ||
859 | /* Increment io usrs member of channel object to 1 */ | ||
860 | common->io_usrs = 1; | ||
861 | /* Store type of memory requested in channel object */ | ||
862 | common->memory = reqbuf->memory; | ||
863 | INIT_LIST_HEAD(&common->dma_queue); | ||
864 | |||
865 | /* Allocate buffers */ | ||
866 | ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); | ||
867 | |||
868 | reqbuf_exit: | ||
869 | mutex_unlock(&common->lock); | ||
870 | return ret; | ||
871 | } | ||
872 | |||
873 | static int vpif_querybuf(struct file *file, void *priv, | ||
874 | struct v4l2_buffer *tbuf) | ||
875 | { | ||
876 | struct vpif_fh *fh = priv; | ||
877 | struct channel_obj *ch = fh->channel; | ||
878 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
879 | |||
880 | if (common->fmt.type != tbuf->type) | ||
881 | return -EINVAL; | ||
882 | |||
883 | return videobuf_querybuf(&common->buffer_queue, tbuf); | ||
884 | } | ||
885 | |||
886 | static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
887 | { | ||
888 | |||
889 | struct vpif_fh *fh = priv; | ||
890 | struct channel_obj *ch = fh->channel; | ||
891 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
892 | struct v4l2_buffer tbuf = *buf; | ||
893 | struct videobuf_buffer *buf1; | ||
894 | unsigned long addr = 0; | ||
895 | unsigned long flags; | ||
896 | int ret = 0; | ||
897 | |||
898 | if (common->fmt.type != tbuf.type) | ||
899 | return -EINVAL; | ||
900 | |||
901 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
902 | vpif_err("fh->io_allowed\n"); | ||
903 | return -EACCES; | ||
904 | } | ||
905 | |||
906 | if (!(list_empty(&common->dma_queue)) || | ||
907 | (common->cur_frm != common->next_frm) || | ||
908 | !(common->started) || | ||
909 | (common->started && (0 == ch->field_id))) | ||
910 | return videobuf_qbuf(&common->buffer_queue, buf); | ||
911 | |||
912 | /* bufferqueue is empty store buffer address in VPIF registers */ | ||
913 | mutex_lock(&common->buffer_queue.vb_lock); | ||
914 | buf1 = common->buffer_queue.bufs[tbuf.index]; | ||
915 | if (buf1->memory != tbuf.memory) { | ||
916 | vpif_err("invalid buffer type\n"); | ||
917 | goto qbuf_exit; | ||
918 | } | ||
919 | |||
920 | if ((buf1->state == VIDEOBUF_QUEUED) || | ||
921 | (buf1->state == VIDEOBUF_ACTIVE)) { | ||
922 | vpif_err("invalid state\n"); | ||
923 | goto qbuf_exit; | ||
924 | } | ||
925 | |||
926 | switch (buf1->memory) { | ||
927 | case V4L2_MEMORY_MMAP: | ||
928 | if (buf1->baddr == 0) | ||
929 | goto qbuf_exit; | ||
930 | break; | ||
931 | |||
932 | case V4L2_MEMORY_USERPTR: | ||
933 | if (tbuf.length < buf1->bsize) | ||
934 | goto qbuf_exit; | ||
935 | |||
936 | if ((VIDEOBUF_NEEDS_INIT != buf1->state) | ||
937 | && (buf1->baddr != tbuf.m.userptr)) | ||
938 | vpif_buffer_release(&common->buffer_queue, buf1); | ||
939 | buf1->baddr = tbuf.m.userptr; | ||
940 | break; | ||
941 | |||
942 | default: | ||
943 | goto qbuf_exit; | ||
944 | } | ||
945 | |||
946 | local_irq_save(flags); | ||
947 | ret = vpif_buffer_prepare(&common->buffer_queue, buf1, | ||
948 | common->buffer_queue.field); | ||
949 | if (ret < 0) { | ||
950 | local_irq_restore(flags); | ||
951 | goto qbuf_exit; | ||
952 | } | ||
953 | |||
954 | buf1->state = VIDEOBUF_ACTIVE; | ||
955 | addr = buf1->boff; | ||
956 | common->next_frm = buf1; | ||
957 | if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { | ||
958 | common->set_addr((addr + common->ytop_off), | ||
959 | (addr + common->ybtm_off), | ||
960 | (addr + common->ctop_off), | ||
961 | (addr + common->cbtm_off)); | ||
962 | } | ||
963 | |||
964 | local_irq_restore(flags); | ||
965 | list_add_tail(&buf1->stream, &common->buffer_queue.stream); | ||
966 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
967 | return 0; | ||
968 | |||
969 | qbuf_exit: | ||
970 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
971 | return -EINVAL; | ||
972 | } | ||
973 | |||
974 | static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
975 | { | ||
976 | struct vpif_fh *fh = priv; | ||
977 | struct channel_obj *ch = fh->channel; | ||
978 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
979 | int ret = 0; | ||
980 | |||
981 | if (!(*std_id & DM646X_V4L2_STD)) | ||
982 | return -EINVAL; | ||
983 | |||
984 | if (common->started) { | ||
985 | vpif_err("streaming in progress\n"); | ||
986 | return -EBUSY; | ||
987 | } | ||
988 | |||
989 | /* Call encoder subdevice function to set the standard */ | ||
990 | if (mutex_lock_interruptible(&common->lock)) | ||
991 | return -ERESTARTSYS; | ||
992 | |||
993 | ch->video.stdid = *std_id; | ||
994 | /* Get the information about the standard */ | ||
995 | if (vpif_get_std_info(ch)) { | ||
996 | vpif_err("Error getting the standard info\n"); | ||
997 | return -EINVAL; | ||
998 | } | ||
999 | |||
1000 | if ((ch->vpifparams.std_info.width * | ||
1001 | ch->vpifparams.std_info.height * 2) > | ||
1002 | config_params.channel_bufsize[ch->channel_id]) { | ||
1003 | vpif_err("invalid std for this size\n"); | ||
1004 | ret = -EINVAL; | ||
1005 | goto s_std_exit; | ||
1006 | } | ||
1007 | |||
1008 | common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width; | ||
1009 | /* Configure the default format information */ | ||
1010 | vpif_config_format(ch); | ||
1011 | |||
1012 | ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, | ||
1013 | s_std_output, *std_id); | ||
1014 | if (ret < 0) { | ||
1015 | vpif_err("Failed to set output standard\n"); | ||
1016 | goto s_std_exit; | ||
1017 | } | ||
1018 | |||
1019 | ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, | ||
1020 | s_std, *std_id); | ||
1021 | if (ret < 0) | ||
1022 | vpif_err("Failed to set standard for sub devices\n"); | ||
1023 | |||
1024 | s_std_exit: | ||
1025 | mutex_unlock(&common->lock); | ||
1026 | return ret; | ||
1027 | } | ||
1028 | |||
1029 | static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
1030 | { | ||
1031 | struct vpif_fh *fh = priv; | ||
1032 | struct channel_obj *ch = fh->channel; | ||
1033 | |||
1034 | *std = ch->video.stdid; | ||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
1039 | { | ||
1040 | struct vpif_fh *fh = priv; | ||
1041 | struct channel_obj *ch = fh->channel; | ||
1042 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1043 | |||
1044 | return videobuf_dqbuf(&common->buffer_queue, p, | ||
1045 | (file->f_flags & O_NONBLOCK)); | ||
1046 | } | ||
1047 | |||
1048 | static int vpif_streamon(struct file *file, void *priv, | ||
1049 | enum v4l2_buf_type buftype) | ||
1050 | { | ||
1051 | struct vpif_fh *fh = priv; | ||
1052 | struct channel_obj *ch = fh->channel; | ||
1053 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1054 | struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; | ||
1055 | struct vpif_params *vpif = &ch->vpifparams; | ||
1056 | struct vpif_display_config *vpif_config_data = | ||
1057 | vpif_dev->platform_data; | ||
1058 | unsigned long addr = 0; | ||
1059 | int ret = 0; | ||
1060 | |||
1061 | if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1062 | vpif_err("buffer type not supported\n"); | ||
1063 | return -EINVAL; | ||
1064 | } | ||
1065 | |||
1066 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1067 | vpif_err("fh->io_allowed\n"); | ||
1068 | return -EACCES; | ||
1069 | } | ||
1070 | |||
1071 | /* If Streaming is already started, return error */ | ||
1072 | if (common->started) { | ||
1073 | vpif_err("channel->started\n"); | ||
1074 | return -EBUSY; | ||
1075 | } | ||
1076 | |||
1077 | if ((ch->channel_id == VPIF_CHANNEL2_VIDEO | ||
1078 | && oth_ch->common[VPIF_VIDEO_INDEX].started && | ||
1079 | ch->vpifparams.std_info.ycmux_mode == 0) | ||
1080 | || ((ch->channel_id == VPIF_CHANNEL3_VIDEO) | ||
1081 | && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { | ||
1082 | vpif_err("other channel is using\n"); | ||
1083 | return -EBUSY; | ||
1084 | } | ||
1085 | |||
1086 | ret = vpif_check_format(ch, &common->fmt.fmt.pix); | ||
1087 | if (ret < 0) | ||
1088 | return ret; | ||
1089 | |||
1090 | /* Call videobuf_streamon to start streaming in videobuf */ | ||
1091 | ret = videobuf_streamon(&common->buffer_queue); | ||
1092 | if (ret < 0) { | ||
1093 | vpif_err("videobuf_streamon\n"); | ||
1094 | return ret; | ||
1095 | } | ||
1096 | |||
1097 | if (mutex_lock_interruptible(&common->lock)) | ||
1098 | return -ERESTARTSYS; | ||
1099 | |||
1100 | /* If buffer queue is empty, return error */ | ||
1101 | if (list_empty(&common->dma_queue)) { | ||
1102 | vpif_err("buffer queue is empty\n"); | ||
1103 | ret = -EIO; | ||
1104 | goto streamon_exit; | ||
1105 | } | ||
1106 | |||
1107 | /* Get the next frame from the buffer queue */ | ||
1108 | common->next_frm = common->cur_frm = | ||
1109 | list_entry(common->dma_queue.next, | ||
1110 | struct videobuf_buffer, queue); | ||
1111 | |||
1112 | list_del(&common->cur_frm->queue); | ||
1113 | /* Mark state of the current frame to active */ | ||
1114 | common->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1115 | |||
1116 | /* Initialize field_id and started member */ | ||
1117 | ch->field_id = 0; | ||
1118 | common->started = 1; | ||
1119 | if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1120 | addr = common->cur_frm->boff; | ||
1121 | /* Calculate the offset for Y and C data in the buffer */ | ||
1122 | vpif_calculate_offsets(ch); | ||
1123 | |||
1124 | if ((ch->vpifparams.std_info.frm_fmt && | ||
1125 | ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) | ||
1126 | && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) | ||
1127 | || (!ch->vpifparams.std_info.frm_fmt | ||
1128 | && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { | ||
1129 | vpif_err("conflict in field format and std format\n"); | ||
1130 | ret = -EINVAL; | ||
1131 | goto streamon_exit; | ||
1132 | } | ||
1133 | |||
1134 | /* clock settings */ | ||
1135 | ret = | ||
1136 | vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, | ||
1137 | ch->vpifparams.std_info.hd_sd); | ||
1138 | if (ret < 0) { | ||
1139 | vpif_err("can't set clock\n"); | ||
1140 | goto streamon_exit; | ||
1141 | } | ||
1142 | |||
1143 | /* set the parameters and addresses */ | ||
1144 | ret = vpif_set_video_params(vpif, ch->channel_id + 2); | ||
1145 | if (ret < 0) | ||
1146 | goto streamon_exit; | ||
1147 | |||
1148 | common->started = ret; | ||
1149 | vpif_config_addr(ch, ret); | ||
1150 | common->set_addr((addr + common->ytop_off), | ||
1151 | (addr + common->ybtm_off), | ||
1152 | (addr + common->ctop_off), | ||
1153 | (addr + common->cbtm_off)); | ||
1154 | |||
1155 | /* Set interrupt for both the fields in VPIF | ||
1156 | Register enable channel in VPIF register */ | ||
1157 | if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { | ||
1158 | channel2_intr_assert(); | ||
1159 | channel2_intr_enable(1); | ||
1160 | enable_channel2(1); | ||
1161 | } | ||
1162 | |||
1163 | if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) | ||
1164 | || (common->started == 2)) { | ||
1165 | channel3_intr_assert(); | ||
1166 | channel3_intr_enable(1); | ||
1167 | enable_channel3(1); | ||
1168 | } | ||
1169 | channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; | ||
1170 | } | ||
1171 | |||
1172 | streamon_exit: | ||
1173 | mutex_unlock(&common->lock); | ||
1174 | return ret; | ||
1175 | } | ||
1176 | |||
1177 | static int vpif_streamoff(struct file *file, void *priv, | ||
1178 | enum v4l2_buf_type buftype) | ||
1179 | { | ||
1180 | struct vpif_fh *fh = priv; | ||
1181 | struct channel_obj *ch = fh->channel; | ||
1182 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1183 | |||
1184 | if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1185 | vpif_err("buffer type not supported\n"); | ||
1186 | return -EINVAL; | ||
1187 | } | ||
1188 | |||
1189 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1190 | vpif_err("fh->io_allowed\n"); | ||
1191 | return -EACCES; | ||
1192 | } | ||
1193 | |||
1194 | if (!common->started) { | ||
1195 | vpif_err("channel->started\n"); | ||
1196 | return -EINVAL; | ||
1197 | } | ||
1198 | |||
1199 | if (mutex_lock_interruptible(&common->lock)) | ||
1200 | return -ERESTARTSYS; | ||
1201 | |||
1202 | if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1203 | /* disable channel */ | ||
1204 | if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { | ||
1205 | enable_channel2(0); | ||
1206 | channel2_intr_enable(0); | ||
1207 | } | ||
1208 | if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || | ||
1209 | (2 == common->started)) { | ||
1210 | enable_channel3(0); | ||
1211 | channel3_intr_enable(0); | ||
1212 | } | ||
1213 | } | ||
1214 | |||
1215 | common->started = 0; | ||
1216 | mutex_unlock(&common->lock); | ||
1217 | |||
1218 | return videobuf_streamoff(&common->buffer_queue); | ||
1219 | } | ||
1220 | |||
1221 | static int vpif_cropcap(struct file *file, void *priv, | ||
1222 | struct v4l2_cropcap *crop) | ||
1223 | { | ||
1224 | struct vpif_fh *fh = priv; | ||
1225 | struct channel_obj *ch = fh->channel; | ||
1226 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1227 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type) | ||
1228 | return -EINVAL; | ||
1229 | |||
1230 | crop->bounds.left = crop->bounds.top = 0; | ||
1231 | crop->defrect.left = crop->defrect.top = 0; | ||
1232 | crop->defrect.height = crop->bounds.height = common->height; | ||
1233 | crop->defrect.width = crop->bounds.width = common->width; | ||
1234 | |||
1235 | return 0; | ||
1236 | } | ||
1237 | |||
1238 | static int vpif_enum_output(struct file *file, void *fh, | ||
1239 | struct v4l2_output *output) | ||
1240 | { | ||
1241 | |||
1242 | struct vpif_display_config *config = vpif_dev->platform_data; | ||
1243 | |||
1244 | if (output->index >= config->output_count) { | ||
1245 | vpif_dbg(1, debug, "Invalid output index\n"); | ||
1246 | return -EINVAL; | ||
1247 | } | ||
1248 | |||
1249 | strcpy(output->name, config->output[output->index]); | ||
1250 | output->type = V4L2_OUTPUT_TYPE_ANALOG; | ||
1251 | output->std = DM646X_V4L2_STD; | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | static int vpif_s_output(struct file *file, void *priv, unsigned int i) | ||
1257 | { | ||
1258 | struct vpif_fh *fh = priv; | ||
1259 | struct channel_obj *ch = fh->channel; | ||
1260 | struct video_obj *vid_ch = &ch->video; | ||
1261 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1262 | int ret = 0; | ||
1263 | |||
1264 | if (mutex_lock_interruptible(&common->lock)) | ||
1265 | return -ERESTARTSYS; | ||
1266 | |||
1267 | if (common->started) { | ||
1268 | vpif_err("Streaming in progress\n"); | ||
1269 | ret = -EBUSY; | ||
1270 | goto s_output_exit; | ||
1271 | } | ||
1272 | |||
1273 | ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, | ||
1274 | s_routing, 0, i, 0); | ||
1275 | |||
1276 | if (ret < 0) | ||
1277 | vpif_err("Failed to set output standard\n"); | ||
1278 | |||
1279 | vid_ch->output_id = i; | ||
1280 | |||
1281 | s_output_exit: | ||
1282 | mutex_unlock(&common->lock); | ||
1283 | return ret; | ||
1284 | } | ||
1285 | |||
1286 | static int vpif_g_output(struct file *file, void *priv, unsigned int *i) | ||
1287 | { | ||
1288 | struct vpif_fh *fh = priv; | ||
1289 | struct channel_obj *ch = fh->channel; | ||
1290 | struct video_obj *vid_ch = &ch->video; | ||
1291 | |||
1292 | *i = vid_ch->output_id; | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p) | ||
1298 | { | ||
1299 | struct vpif_fh *fh = priv; | ||
1300 | struct channel_obj *ch = fh->channel; | ||
1301 | |||
1302 | *p = v4l2_prio_max(&ch->prio); | ||
1303 | |||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) | ||
1308 | { | ||
1309 | struct vpif_fh *fh = priv; | ||
1310 | struct channel_obj *ch = fh->channel; | ||
1311 | |||
1312 | return v4l2_prio_change(&ch->prio, &fh->prio, p); | ||
1313 | } | ||
1314 | |||
1315 | /* vpif display ioctl operations */ | ||
1316 | static const struct v4l2_ioctl_ops vpif_ioctl_ops = { | ||
1317 | .vidioc_querycap = vpif_querycap, | ||
1318 | .vidioc_g_priority = vpif_g_priority, | ||
1319 | .vidioc_s_priority = vpif_s_priority, | ||
1320 | .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out, | ||
1321 | .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out, | ||
1322 | .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out, | ||
1323 | .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out, | ||
1324 | .vidioc_reqbufs = vpif_reqbufs, | ||
1325 | .vidioc_querybuf = vpif_querybuf, | ||
1326 | .vidioc_qbuf = vpif_qbuf, | ||
1327 | .vidioc_dqbuf = vpif_dqbuf, | ||
1328 | .vidioc_streamon = vpif_streamon, | ||
1329 | .vidioc_streamoff = vpif_streamoff, | ||
1330 | .vidioc_s_std = vpif_s_std, | ||
1331 | .vidioc_g_std = vpif_g_std, | ||
1332 | .vidioc_enum_output = vpif_enum_output, | ||
1333 | .vidioc_s_output = vpif_s_output, | ||
1334 | .vidioc_g_output = vpif_g_output, | ||
1335 | .vidioc_cropcap = vpif_cropcap, | ||
1336 | }; | ||
1337 | |||
1338 | static const struct v4l2_file_operations vpif_fops = { | ||
1339 | .owner = THIS_MODULE, | ||
1340 | .open = vpif_open, | ||
1341 | .release = vpif_release, | ||
1342 | .ioctl = video_ioctl2, | ||
1343 | .mmap = vpif_mmap, | ||
1344 | .poll = vpif_poll | ||
1345 | }; | ||
1346 | |||
1347 | static struct video_device vpif_video_template = { | ||
1348 | .name = "vpif", | ||
1349 | .fops = &vpif_fops, | ||
1350 | .minor = -1, | ||
1351 | .ioctl_ops = &vpif_ioctl_ops, | ||
1352 | .tvnorms = DM646X_V4L2_STD, | ||
1353 | .current_norm = V4L2_STD_625_50, | ||
1354 | |||
1355 | }; | ||
1356 | |||
1357 | /*Configure the channels, buffer sizei, request irq */ | ||
1358 | static int initialize_vpif(void) | ||
1359 | { | ||
1360 | int free_channel_objects_index; | ||
1361 | int free_buffer_channel_index; | ||
1362 | int free_buffer_index; | ||
1363 | int err = 0, i, j; | ||
1364 | |||
1365 | /* Default number of buffers should be 3 */ | ||
1366 | if ((ch2_numbuffers > 0) && | ||
1367 | (ch2_numbuffers < config_params.min_numbuffers)) | ||
1368 | ch2_numbuffers = config_params.min_numbuffers; | ||
1369 | if ((ch3_numbuffers > 0) && | ||
1370 | (ch3_numbuffers < config_params.min_numbuffers)) | ||
1371 | ch3_numbuffers = config_params.min_numbuffers; | ||
1372 | |||
1373 | /* Set buffer size to min buffers size if invalid buffer size is | ||
1374 | * given */ | ||
1375 | if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]) | ||
1376 | ch2_bufsize = | ||
1377 | config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]; | ||
1378 | if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]) | ||
1379 | ch3_bufsize = | ||
1380 | config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]; | ||
1381 | |||
1382 | config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers; | ||
1383 | |||
1384 | if (ch2_numbuffers) { | ||
1385 | config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] = | ||
1386 | ch2_bufsize; | ||
1387 | } | ||
1388 | config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers; | ||
1389 | |||
1390 | if (ch3_numbuffers) { | ||
1391 | config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] = | ||
1392 | ch3_bufsize; | ||
1393 | } | ||
1394 | |||
1395 | /* Allocate memory for six channel objects */ | ||
1396 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
1397 | vpif_obj.dev[i] = | ||
1398 | kmalloc(sizeof(struct channel_obj), GFP_KERNEL); | ||
1399 | /* If memory allocation fails, return error */ | ||
1400 | if (!vpif_obj.dev[i]) { | ||
1401 | free_channel_objects_index = i; | ||
1402 | err = -ENOMEM; | ||
1403 | goto vpif_init_free_channel_objects; | ||
1404 | } | ||
1405 | } | ||
1406 | |||
1407 | free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES; | ||
1408 | free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS; | ||
1409 | free_buffer_index = config_params.numbuffers[i - 1]; | ||
1410 | |||
1411 | return 0; | ||
1412 | |||
1413 | vpif_init_free_channel_objects: | ||
1414 | for (j = 0; j < free_channel_objects_index; j++) | ||
1415 | kfree(vpif_obj.dev[j]); | ||
1416 | return err; | ||
1417 | } | ||
1418 | |||
1419 | /* | ||
1420 | * vpif_probe: This function creates device entries by register itself to the | ||
1421 | * V4L2 driver and initializes fields of each channel objects | ||
1422 | */ | ||
1423 | static __init int vpif_probe(struct platform_device *pdev) | ||
1424 | { | ||
1425 | struct vpif_subdev_info *subdevdata; | ||
1426 | struct vpif_display_config *config; | ||
1427 | int i, j = 0, k, q, m, err = 0; | ||
1428 | struct i2c_adapter *i2c_adap; | ||
1429 | struct vpif_config *config; | ||
1430 | struct common_obj *common; | ||
1431 | struct channel_obj *ch; | ||
1432 | struct video_device *vfd; | ||
1433 | struct resource *res; | ||
1434 | int subdev_count; | ||
1435 | |||
1436 | vpif_dev = &pdev->dev; | ||
1437 | |||
1438 | err = initialize_vpif(); | ||
1439 | |||
1440 | if (err) { | ||
1441 | v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); | ||
1442 | return err; | ||
1443 | } | ||
1444 | |||
1445 | err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); | ||
1446 | if (err) { | ||
1447 | v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); | ||
1448 | return err; | ||
1449 | } | ||
1450 | |||
1451 | k = 0; | ||
1452 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { | ||
1453 | for (i = res->start; i <= res->end; i++) { | ||
1454 | if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, | ||
1455 | "DM646x_Display", | ||
1456 | (void *)(&vpif_obj.dev[k]->channel_id))) { | ||
1457 | err = -EBUSY; | ||
1458 | goto vpif_int_err; | ||
1459 | } | ||
1460 | } | ||
1461 | k++; | ||
1462 | } | ||
1463 | |||
1464 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
1465 | |||
1466 | /* Get the pointer to the channel object */ | ||
1467 | ch = vpif_obj.dev[i]; | ||
1468 | |||
1469 | /* Allocate memory for video device */ | ||
1470 | vfd = video_device_alloc(); | ||
1471 | if (vfd == NULL) { | ||
1472 | for (j = 0; j < i; j++) { | ||
1473 | ch = vpif_obj.dev[j]; | ||
1474 | video_device_release(ch->video_dev); | ||
1475 | } | ||
1476 | err = -ENOMEM; | ||
1477 | goto vpif_int_err; | ||
1478 | } | ||
1479 | |||
1480 | /* Initialize field of video device */ | ||
1481 | *vfd = vpif_video_template; | ||
1482 | vfd->v4l2_dev = &vpif_obj.v4l2_dev; | ||
1483 | vfd->release = video_device_release; | ||
1484 | snprintf(vfd->name, sizeof(vfd->name), | ||
1485 | "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d", | ||
1486 | (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff, | ||
1487 | (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff, | ||
1488 | (VPIF_DISPLAY_VERSION_CODE) & 0xff); | ||
1489 | |||
1490 | /* Set video_dev to the video device */ | ||
1491 | ch->video_dev = vfd; | ||
1492 | } | ||
1493 | |||
1494 | for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { | ||
1495 | ch = vpif_obj.dev[j]; | ||
1496 | /* Initialize field of the channel objects */ | ||
1497 | atomic_set(&ch->usrs, 0); | ||
1498 | for (k = 0; k < VPIF_NUMOBJECTS; k++) { | ||
1499 | ch->common[k].numbuffers = 0; | ||
1500 | common = &ch->common[k]; | ||
1501 | common->io_usrs = 0; | ||
1502 | common->started = 0; | ||
1503 | spin_lock_init(&common->irqlock); | ||
1504 | mutex_init(&common->lock); | ||
1505 | common->numbuffers = 0; | ||
1506 | common->set_addr = NULL; | ||
1507 | common->ytop_off = common->ybtm_off = 0; | ||
1508 | common->ctop_off = common->cbtm_off = 0; | ||
1509 | common->cur_frm = common->next_frm = NULL; | ||
1510 | memset(&common->fmt, 0, sizeof(common->fmt)); | ||
1511 | common->numbuffers = config_params.numbuffers[k]; | ||
1512 | |||
1513 | } | ||
1514 | ch->initialized = 0; | ||
1515 | ch->channel_id = j; | ||
1516 | if (j < 2) | ||
1517 | ch->common[VPIF_VIDEO_INDEX].numbuffers = | ||
1518 | config_params.numbuffers[ch->channel_id]; | ||
1519 | else | ||
1520 | ch->common[VPIF_VIDEO_INDEX].numbuffers = 0; | ||
1521 | |||
1522 | memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); | ||
1523 | |||
1524 | /* Initialize prio member of channel object */ | ||
1525 | v4l2_prio_init(&ch->prio); | ||
1526 | ch->common[VPIF_VIDEO_INDEX].fmt.type = | ||
1527 | V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
1528 | |||
1529 | /* register video device */ | ||
1530 | vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", | ||
1531 | (int)ch, (int)&ch->video_dev); | ||
1532 | |||
1533 | err = video_register_device(ch->video_dev, | ||
1534 | VFL_TYPE_GRABBER, (j ? 3 : 2)); | ||
1535 | if (err < 0) | ||
1536 | goto probe_out; | ||
1537 | |||
1538 | video_set_drvdata(ch->video_dev, ch); | ||
1539 | } | ||
1540 | |||
1541 | i2c_adap = i2c_get_adapter(1); | ||
1542 | config = pdev->dev.platform_data; | ||
1543 | subdev_count = config->subdev_count; | ||
1544 | subdevdata = config->subdevinfo; | ||
1545 | vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count, | ||
1546 | GFP_KERNEL); | ||
1547 | if (vpif_obj.sd == NULL) { | ||
1548 | vpif_err("unable to allocate memory for subdevice pointers\n"); | ||
1549 | err = -ENOMEM; | ||
1550 | goto probe_out; | ||
1551 | } | ||
1552 | |||
1553 | for (i = 0; i < subdev_count; i++) { | ||
1554 | vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, | ||
1555 | i2c_adap, subdevdata[i].name, | ||
1556 | &subdevdata[i].board_info, | ||
1557 | NULL); | ||
1558 | if (!vpif_obj.sd[i]) { | ||
1559 | vpif_err("Error registering v4l2 subdevice\n"); | ||
1560 | goto probe_subdev_out; | ||
1561 | } | ||
1562 | |||
1563 | if (vpif_obj.sd[i]) | ||
1564 | vpif_obj.sd[i]->grp_id = 1 << i; | ||
1565 | } | ||
1566 | |||
1567 | return 0; | ||
1568 | |||
1569 | probe_subdev_out: | ||
1570 | kfree(vpif_obj.sd); | ||
1571 | probe_out: | ||
1572 | for (k = 0; k < j; k++) { | ||
1573 | ch = vpif_obj.dev[k]; | ||
1574 | video_unregister_device(ch->video_dev); | ||
1575 | video_device_release(ch->video_dev); | ||
1576 | ch->video_dev = NULL; | ||
1577 | } | ||
1578 | vpif_int_err: | ||
1579 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
1580 | vpif_err("VPIF IRQ request failed\n"); | ||
1581 | for (q = k; k >= 0; k--) { | ||
1582 | for (m = i; m >= res->start; m--) | ||
1583 | free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); | ||
1584 | res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); | ||
1585 | m = res->end; | ||
1586 | } | ||
1587 | |||
1588 | return err; | ||
1589 | } | ||
1590 | |||
1591 | /* | ||
1592 | * vpif_remove: It un-register channels from V4L2 driver | ||
1593 | */ | ||
1594 | static int vpif_remove(struct platform_device *device) | ||
1595 | { | ||
1596 | struct channel_obj *ch; | ||
1597 | int i; | ||
1598 | |||
1599 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
1600 | |||
1601 | /* un-register device */ | ||
1602 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
1603 | /* Get the pointer to the channel object */ | ||
1604 | ch = vpif_obj.dev[i]; | ||
1605 | /* Unregister video device */ | ||
1606 | video_unregister_device(ch->video_dev); | ||
1607 | |||
1608 | ch->video_dev = NULL; | ||
1609 | } | ||
1610 | |||
1611 | return 0; | ||
1612 | } | ||
1613 | |||
1614 | static struct platform_driver vpif_driver = { | ||
1615 | .driver = { | ||
1616 | .name = "vpif_display", | ||
1617 | .owner = THIS_MODULE, | ||
1618 | }, | ||
1619 | .probe = vpif_probe, | ||
1620 | .remove = vpif_remove, | ||
1621 | }; | ||
1622 | |||
1623 | static __init int vpif_init(void) | ||
1624 | { | ||
1625 | return platform_driver_register(&vpif_driver); | ||
1626 | } | ||
1627 | |||
1628 | /* | ||
1629 | * vpif_cleanup: This function un-registers device and driver to the kernel, | ||
1630 | * frees requested irq handler and de-allocates memory allocated for channel | ||
1631 | * objects. | ||
1632 | */ | ||
1633 | static void vpif_cleanup(void) | ||
1634 | { | ||
1635 | struct platform_device *pdev; | ||
1636 | struct resource *res; | ||
1637 | int irq_num; | ||
1638 | int i = 0; | ||
1639 | |||
1640 | pdev = container_of(vpif_dev, struct platform_device, dev); | ||
1641 | |||
1642 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { | ||
1643 | for (irq_num = res->start; irq_num <= res->end; irq_num++) | ||
1644 | free_irq(irq_num, | ||
1645 | (void *)(&vpif_obj.dev[i]->channel_id)); | ||
1646 | i++; | ||
1647 | } | ||
1648 | |||
1649 | platform_driver_unregister(&vpif_driver); | ||
1650 | kfree(vpif_obj.sd); | ||
1651 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) | ||
1652 | kfree(vpif_obj.dev[i]); | ||
1653 | } | ||
1654 | |||
1655 | module_init(vpif_init); | ||
1656 | module_exit(vpif_cleanup); | ||
diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h new file mode 100644 index 000000000000..a2a7cd166bbf --- /dev/null +++ b/drivers/media/video/davinci/vpif_display.h | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * DM646x display header file | ||
3 | * | ||
4 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef DAVINCIHD_DISPLAY_H | ||
17 | #define DAVINCIHD_DISPLAY_H | ||
18 | |||
19 | /* Header files */ | ||
20 | #include <linux/videodev2.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <media/v4l2-common.h> | ||
23 | #include <media/v4l2-device.h> | ||
24 | #include <media/videobuf-core.h> | ||
25 | #include <media/videobuf-dma-contig.h> | ||
26 | |||
27 | #include "vpif.h" | ||
28 | |||
29 | /* Macros */ | ||
30 | #define VPIF_MAJOR_RELEASE (0) | ||
31 | #define VPIF_MINOR_RELEASE (0) | ||
32 | #define VPIF_BUILD (1) | ||
33 | |||
34 | #define VPIF_DISPLAY_VERSION_CODE \ | ||
35 | ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) | ||
36 | |||
37 | #define VPIF_VALID_FIELD(field) \ | ||
38 | (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ | ||
39 | (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \ | ||
40 | (V4L2_FIELD_SEQ_BT == field))) | ||
41 | |||
42 | #define VPIF_DISPLAY_MAX_DEVICES (2) | ||
43 | #define VPIF_SLICED_BUF_SIZE (256) | ||
44 | #define VPIF_SLICED_MAX_SERVICES (3) | ||
45 | #define VPIF_VIDEO_INDEX (0) | ||
46 | #define VPIF_VBI_INDEX (1) | ||
47 | #define VPIF_HBI_INDEX (2) | ||
48 | |||
49 | /* Setting it to 1 as HBI/VBI support yet to be added , else 3*/ | ||
50 | #define VPIF_NUMOBJECTS (1) | ||
51 | |||
52 | /* Macros */ | ||
53 | #define ISALIGNED(a) (0 == ((a) & 7)) | ||
54 | |||
55 | /* enumerated data types */ | ||
56 | /* Enumerated data type to give id to each device per channel */ | ||
57 | enum vpif_channel_id { | ||
58 | VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */ | ||
59 | VPIF_CHANNEL3_VIDEO, /* Channel3 Video */ | ||
60 | }; | ||
61 | |||
62 | /* structures */ | ||
63 | |||
64 | struct video_obj { | ||
65 | enum v4l2_field buf_field; | ||
66 | u32 latest_only; /* indicate whether to return | ||
67 | * most recent displayed frame only */ | ||
68 | v4l2_std_id stdid; /* Currently selected or default | ||
69 | * standard */ | ||
70 | u32 output_id; /* Current output id */ | ||
71 | }; | ||
72 | |||
73 | struct vbi_obj { | ||
74 | int num_services; | ||
75 | struct vpif_vbi_params vbiparams; /* vpif parameters for the raw | ||
76 | * vbi data */ | ||
77 | }; | ||
78 | |||
79 | struct common_obj { | ||
80 | /* Buffer specific parameters */ | ||
81 | u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for | ||
82 | * storing frames */ | ||
83 | u32 numbuffers; /* number of buffers */ | ||
84 | struct videobuf_buffer *cur_frm; /* Pointer pointing to current | ||
85 | * videobuf_buffer */ | ||
86 | struct videobuf_buffer *next_frm; /* Pointer pointing to next | ||
87 | * videobuf_buffer */ | ||
88 | enum v4l2_memory memory; /* This field keeps track of | ||
89 | * type of buffer exchange | ||
90 | * method user has selected */ | ||
91 | struct v4l2_format fmt; /* Used to store the format */ | ||
92 | struct videobuf_queue buffer_queue; /* Buffer queue used in | ||
93 | * video-buf */ | ||
94 | struct list_head dma_queue; /* Queue of filled frames */ | ||
95 | spinlock_t irqlock; /* Used in video-buf */ | ||
96 | |||
97 | /* channel specific parameters */ | ||
98 | struct mutex lock; /* lock used to access this | ||
99 | * structure */ | ||
100 | u32 io_usrs; /* number of users performing | ||
101 | * IO */ | ||
102 | u8 started; /* Indicates whether streaming | ||
103 | * started */ | ||
104 | u32 ytop_off; /* offset of Y top from the | ||
105 | * starting of the buffer */ | ||
106 | u32 ybtm_off; /* offset of Y bottom from the | ||
107 | * starting of the buffer */ | ||
108 | u32 ctop_off; /* offset of C top from the | ||
109 | * starting of the buffer */ | ||
110 | u32 cbtm_off; /* offset of C bottom from the | ||
111 | * starting of the buffer */ | ||
112 | /* Function pointer to set the addresses */ | ||
113 | void (*set_addr) (unsigned long, unsigned long, | ||
114 | unsigned long, unsigned long); | ||
115 | u32 height; | ||
116 | u32 width; | ||
117 | }; | ||
118 | |||
119 | struct channel_obj { | ||
120 | /* V4l2 specific parameters */ | ||
121 | struct video_device *video_dev; /* Identifies video device for | ||
122 | * this channel */ | ||
123 | struct v4l2_prio_state prio; /* Used to keep track of state of | ||
124 | * the priority */ | ||
125 | atomic_t usrs; /* number of open instances of | ||
126 | * the channel */ | ||
127 | u32 field_id; /* Indicates id of the field | ||
128 | * which is being displayed */ | ||
129 | u8 initialized; /* flag to indicate whether | ||
130 | * encoder is initialized */ | ||
131 | |||
132 | enum vpif_channel_id channel_id;/* Identifies channel */ | ||
133 | struct vpif_params vpifparams; | ||
134 | struct common_obj common[VPIF_NUMOBJECTS]; | ||
135 | struct video_obj video; | ||
136 | struct vbi_obj vbi; | ||
137 | }; | ||
138 | |||
139 | /* File handle structure */ | ||
140 | struct vpif_fh { | ||
141 | struct channel_obj *channel; /* pointer to channel object for | ||
142 | * opened device */ | ||
143 | u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle | ||
144 | * is doing IO */ | ||
145 | enum v4l2_priority prio; /* Used to keep track priority of | ||
146 | * this instance */ | ||
147 | u8 initialized; /* Used to keep track of whether this | ||
148 | * file handle has initialized | ||
149 | * channel or not */ | ||
150 | }; | ||
151 | |||
152 | /* vpif device structure */ | ||
153 | struct vpif_device { | ||
154 | struct v4l2_device v4l2_dev; | ||
155 | struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS]; | ||
156 | struct v4l2_subdev **sd; | ||
157 | |||
158 | }; | ||
159 | |||
160 | struct vpif_config_params { | ||
161 | u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; | ||
162 | u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; | ||
163 | u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; | ||
164 | u8 min_numbuffers; | ||
165 | }; | ||
166 | |||
167 | /* Struct which keeps track of the line numbers for the sliced vbi service */ | ||
168 | struct vpif_service_line { | ||
169 | u16 service_id; | ||
170 | u16 service_line[2]; | ||
171 | u16 enc_service_id; | ||
172 | u8 bytestowrite; | ||
173 | }; | ||
174 | |||
175 | #endif /* DAVINCIHD_DISPLAY_H */ | ||
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c new file mode 100644 index 000000000000..6d709ca8cfb0 --- /dev/null +++ b/drivers/media/video/davinci/vpss.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Texas Instruments. | ||
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 | * common vpss driver for all video drivers. | ||
19 | */ | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/compiler.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <mach/hardware.h> | ||
29 | #include <media/davinci/vpss.h> | ||
30 | |||
31 | MODULE_LICENSE("GPL"); | ||
32 | MODULE_DESCRIPTION("VPSS Driver"); | ||
33 | MODULE_AUTHOR("Texas Instruments"); | ||
34 | |||
35 | /* DM644x defines */ | ||
36 | #define DM644X_SBL_PCR_VPSS (4) | ||
37 | |||
38 | /* vpss BL register offsets */ | ||
39 | #define DM355_VPSSBL_CCDCMUX 0x1c | ||
40 | /* vpss CLK register offsets */ | ||
41 | #define DM355_VPSSCLK_CLKCTRL 0x04 | ||
42 | /* masks and shifts */ | ||
43 | #define VPSS_HSSISEL_SHIFT 4 | ||
44 | |||
45 | /* | ||
46 | * vpss operations. Depends on platform. Not all functions are available | ||
47 | * on all platforms. The api, first check if a functio is available before | ||
48 | * invoking it. In the probe, the function ptrs are intialized based on | ||
49 | * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. | ||
50 | */ | ||
51 | struct vpss_hw_ops { | ||
52 | /* enable clock */ | ||
53 | int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); | ||
54 | /* select input to ccdc */ | ||
55 | void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); | ||
56 | /* clear wbl overlflow bit */ | ||
57 | int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); | ||
58 | }; | ||
59 | |||
60 | /* vpss configuration */ | ||
61 | struct vpss_oper_config { | ||
62 | __iomem void *vpss_bl_regs_base; | ||
63 | __iomem void *vpss_regs_base; | ||
64 | struct resource *r1; | ||
65 | resource_size_t len1; | ||
66 | struct resource *r2; | ||
67 | resource_size_t len2; | ||
68 | char vpss_name[32]; | ||
69 | spinlock_t vpss_lock; | ||
70 | struct vpss_hw_ops hw_ops; | ||
71 | }; | ||
72 | |||
73 | static struct vpss_oper_config oper_cfg; | ||
74 | |||
75 | /* register access routines */ | ||
76 | static inline u32 bl_regr(u32 offset) | ||
77 | { | ||
78 | return __raw_readl(oper_cfg.vpss_bl_regs_base + offset); | ||
79 | } | ||
80 | |||
81 | static inline void bl_regw(u32 val, u32 offset) | ||
82 | { | ||
83 | __raw_writel(val, oper_cfg.vpss_bl_regs_base + offset); | ||
84 | } | ||
85 | |||
86 | static inline u32 vpss_regr(u32 offset) | ||
87 | { | ||
88 | return __raw_readl(oper_cfg.vpss_regs_base + offset); | ||
89 | } | ||
90 | |||
91 | static inline void vpss_regw(u32 val, u32 offset) | ||
92 | { | ||
93 | __raw_writel(val, oper_cfg.vpss_regs_base + offset); | ||
94 | } | ||
95 | |||
96 | static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) | ||
97 | { | ||
98 | bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); | ||
99 | } | ||
100 | |||
101 | int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) | ||
102 | { | ||
103 | if (!oper_cfg.hw_ops.select_ccdc_source) | ||
104 | return -1; | ||
105 | |||
106 | dm355_select_ccdc_source(src_sel); | ||
107 | return 0; | ||
108 | } | ||
109 | EXPORT_SYMBOL(vpss_select_ccdc_source); | ||
110 | |||
111 | static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) | ||
112 | { | ||
113 | u32 mask = 1, val; | ||
114 | |||
115 | if (wbl_sel < VPSS_PCR_AEW_WBL_0 || | ||
116 | wbl_sel > VPSS_PCR_CCDC_WBL_O) | ||
117 | return -1; | ||
118 | |||
119 | /* writing a 0 clear the overflow */ | ||
120 | mask = ~(mask << wbl_sel); | ||
121 | val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; | ||
122 | bl_regw(val, DM644X_SBL_PCR_VPSS); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) | ||
127 | { | ||
128 | if (!oper_cfg.hw_ops.clear_wbl_overflow) | ||
129 | return -1; | ||
130 | |||
131 | return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); | ||
132 | } | ||
133 | EXPORT_SYMBOL(vpss_clear_wbl_overflow); | ||
134 | |||
135 | /* | ||
136 | * dm355_enable_clock - Enable VPSS Clock | ||
137 | * @clock_sel: CLock to be enabled/disabled | ||
138 | * @en: enable/disable flag | ||
139 | * | ||
140 | * This is called to enable or disable a vpss clock | ||
141 | */ | ||
142 | static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) | ||
143 | { | ||
144 | unsigned long flags; | ||
145 | u32 utemp, mask = 0x1, shift = 0; | ||
146 | |||
147 | switch (clock_sel) { | ||
148 | case VPSS_VPBE_CLOCK: | ||
149 | /* nothing since lsb */ | ||
150 | break; | ||
151 | case VPSS_VENC_CLOCK_SEL: | ||
152 | shift = 2; | ||
153 | break; | ||
154 | case VPSS_CFALD_CLOCK: | ||
155 | shift = 3; | ||
156 | break; | ||
157 | case VPSS_H3A_CLOCK: | ||
158 | shift = 4; | ||
159 | break; | ||
160 | case VPSS_IPIPE_CLOCK: | ||
161 | shift = 5; | ||
162 | break; | ||
163 | case VPSS_CCDC_CLOCK: | ||
164 | shift = 6; | ||
165 | break; | ||
166 | default: | ||
167 | printk(KERN_ERR "dm355_enable_clock:" | ||
168 | " Invalid selector: %d\n", clock_sel); | ||
169 | return -1; | ||
170 | } | ||
171 | |||
172 | spin_lock_irqsave(&oper_cfg.vpss_lock, flags); | ||
173 | utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); | ||
174 | if (!en) | ||
175 | utemp &= ~(mask << shift); | ||
176 | else | ||
177 | utemp |= (mask << shift); | ||
178 | |||
179 | vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); | ||
180 | spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) | ||
185 | { | ||
186 | if (!oper_cfg.hw_ops.enable_clock) | ||
187 | return -1; | ||
188 | |||
189 | return oper_cfg.hw_ops.enable_clock(clock_sel, en); | ||
190 | } | ||
191 | EXPORT_SYMBOL(vpss_enable_clock); | ||
192 | |||
193 | static int __init vpss_probe(struct platform_device *pdev) | ||
194 | { | ||
195 | int status, dm355 = 0; | ||
196 | |||
197 | if (!pdev->dev.platform_data) { | ||
198 | dev_err(&pdev->dev, "no platform data\n"); | ||
199 | return -ENOENT; | ||
200 | } | ||
201 | strcpy(oper_cfg.vpss_name, pdev->dev.platform_data); | ||
202 | |||
203 | if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) | ||
204 | dm355 = 1; | ||
205 | else if (strcmp(oper_cfg.vpss_name, "dm644x_vpss")) { | ||
206 | dev_err(&pdev->dev, "vpss driver not supported on" | ||
207 | " this platform\n"); | ||
208 | return -ENODEV; | ||
209 | } | ||
210 | |||
211 | dev_info(&pdev->dev, "%s vpss probed\n", oper_cfg.vpss_name); | ||
212 | oper_cfg.r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
213 | if (!oper_cfg.r1) | ||
214 | return -ENOENT; | ||
215 | |||
216 | oper_cfg.len1 = oper_cfg.r1->end - oper_cfg.r1->start + 1; | ||
217 | |||
218 | oper_cfg.r1 = request_mem_region(oper_cfg.r1->start, oper_cfg.len1, | ||
219 | oper_cfg.r1->name); | ||
220 | if (!oper_cfg.r1) | ||
221 | return -EBUSY; | ||
222 | |||
223 | oper_cfg.vpss_bl_regs_base = ioremap(oper_cfg.r1->start, oper_cfg.len1); | ||
224 | if (!oper_cfg.vpss_bl_regs_base) { | ||
225 | status = -EBUSY; | ||
226 | goto fail1; | ||
227 | } | ||
228 | |||
229 | if (dm355) { | ||
230 | oper_cfg.r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
231 | if (!oper_cfg.r2) { | ||
232 | status = -ENOENT; | ||
233 | goto fail2; | ||
234 | } | ||
235 | oper_cfg.len2 = oper_cfg.r2->end - oper_cfg.r2->start + 1; | ||
236 | oper_cfg.r2 = request_mem_region(oper_cfg.r2->start, | ||
237 | oper_cfg.len2, | ||
238 | oper_cfg.r2->name); | ||
239 | if (!oper_cfg.r2) { | ||
240 | status = -EBUSY; | ||
241 | goto fail2; | ||
242 | } | ||
243 | |||
244 | oper_cfg.vpss_regs_base = ioremap(oper_cfg.r2->start, | ||
245 | oper_cfg.len2); | ||
246 | if (!oper_cfg.vpss_regs_base) { | ||
247 | status = -EBUSY; | ||
248 | goto fail3; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | if (dm355) { | ||
253 | oper_cfg.hw_ops.enable_clock = dm355_enable_clock; | ||
254 | oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; | ||
255 | } else | ||
256 | oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; | ||
257 | |||
258 | spin_lock_init(&oper_cfg.vpss_lock); | ||
259 | dev_info(&pdev->dev, "%s vpss probe success\n", oper_cfg.vpss_name); | ||
260 | return 0; | ||
261 | |||
262 | fail3: | ||
263 | release_mem_region(oper_cfg.r2->start, oper_cfg.len2); | ||
264 | fail2: | ||
265 | iounmap(oper_cfg.vpss_bl_regs_base); | ||
266 | fail1: | ||
267 | release_mem_region(oper_cfg.r1->start, oper_cfg.len1); | ||
268 | return status; | ||
269 | } | ||
270 | |||
271 | static int vpss_remove(struct platform_device *pdev) | ||
272 | { | ||
273 | iounmap(oper_cfg.vpss_bl_regs_base); | ||
274 | release_mem_region(oper_cfg.r1->start, oper_cfg.len1); | ||
275 | if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) { | ||
276 | iounmap(oper_cfg.vpss_regs_base); | ||
277 | release_mem_region(oper_cfg.r2->start, oper_cfg.len2); | ||
278 | } | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static struct platform_driver vpss_driver = { | ||
283 | .driver = { | ||
284 | .name = "vpss", | ||
285 | .owner = THIS_MODULE, | ||
286 | }, | ||
287 | .remove = __devexit_p(vpss_remove), | ||
288 | .probe = vpss_probe, | ||
289 | }; | ||
290 | |||
291 | static void vpss_exit(void) | ||
292 | { | ||
293 | platform_driver_unregister(&vpss_driver); | ||
294 | } | ||
295 | |||
296 | static int __init vpss_init(void) | ||
297 | { | ||
298 | return platform_driver_register(&vpss_driver); | ||
299 | } | ||
300 | subsys_initcall(vpss_init); | ||
301 | module_exit(vpss_exit); | ||
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 6524b493e033..c7be0e097828 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig | |||
@@ -36,6 +36,7 @@ config VIDEO_EM28XX_DVB | |||
36 | depends on VIDEO_EM28XX && DVB_CORE | 36 | depends on VIDEO_EM28XX && DVB_CORE |
37 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | 37 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE |
38 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE | 38 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE |
39 | select DVB_TDA10023 if !DVB_FE_CUSTOMISE | ||
39 | select VIDEOBUF_DVB | 40 | select VIDEOBUF_DVB |
40 | ---help--- | 41 | ---help--- |
41 | This adds support for DVB cards based on the | 42 | This adds support for DVB cards based on the |
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 8137a8c94bfc..d0f093d1d0df 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ | 1 | em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ |
2 | em28xx-input.o | 2 | em28xx-input.o em28xx-vbi.o |
3 | 3 | ||
4 | em28xx-alsa-objs := em28xx-audio.o | 4 | em28xx-alsa-objs := em28xx-audio.o |
5 | 5 | ||
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 7e3c78239fa9..bdb249bd9d5d 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -170,6 +170,19 @@ static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { | |||
170 | { -1, -1, -1, -1}, | 170 | { -1, -1, -1, -1}, |
171 | }; | 171 | }; |
172 | 172 | ||
173 | /* eb1a:2868 Reddo DVB-C USB TV Box | ||
174 | GPIO4 - CU1216L NIM | ||
175 | Other GPIOs seems to be don't care. */ | ||
176 | static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { | ||
177 | {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, | ||
178 | {EM28XX_R08_GPIO, 0xde, 0xff, 10}, | ||
179 | {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, | ||
180 | {EM28XX_R08_GPIO, 0xff, 0xff, 10}, | ||
181 | {EM28XX_R08_GPIO, 0x7f, 0xff, 10}, | ||
182 | {EM28XX_R08_GPIO, 0x6f, 0xff, 10}, | ||
183 | {EM28XX_R08_GPIO, 0xff, 0xff, 10}, | ||
184 | {-1, -1, -1, -1}, | ||
185 | }; | ||
173 | 186 | ||
174 | /* Callback for the most boards */ | 187 | /* Callback for the most boards */ |
175 | static struct em28xx_reg_seq default_tuner_gpio[] = { | 188 | static struct em28xx_reg_seq default_tuner_gpio[] = { |
@@ -1566,6 +1579,14 @@ struct em28xx_board em28xx_boards[] = { | |||
1566 | .gpio = evga_indtube_analog, | 1579 | .gpio = evga_indtube_analog, |
1567 | } }, | 1580 | } }, |
1568 | }, | 1581 | }, |
1582 | /* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 + | ||
1583 | Infineon TUA6034) */ | ||
1584 | [EM2870_BOARD_REDDO_DVB_C_USB_BOX] = { | ||
1585 | .name = "Reddo DVB-C USB TV Box", | ||
1586 | .tuner_type = TUNER_ABSENT, | ||
1587 | .has_dvb = 1, | ||
1588 | .dvb_gpio = reddo_dvb_c_usb_box, | ||
1589 | }, | ||
1569 | }; | 1590 | }; |
1570 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); | 1591 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); |
1571 | 1592 | ||
@@ -1593,6 +1614,8 @@ struct usb_device_id em28xx_id_table[] = { | |||
1593 | .driver_info = EM2820_BOARD_UNKNOWN }, | 1614 | .driver_info = EM2820_BOARD_UNKNOWN }, |
1594 | { USB_DEVICE(0xeb1a, 0x2883), | 1615 | { USB_DEVICE(0xeb1a, 0x2883), |
1595 | .driver_info = EM2820_BOARD_UNKNOWN }, | 1616 | .driver_info = EM2820_BOARD_UNKNOWN }, |
1617 | { USB_DEVICE(0xeb1a, 0x2868), | ||
1618 | .driver_info = EM2820_BOARD_UNKNOWN }, | ||
1596 | { USB_DEVICE(0xeb1a, 0xe300), | 1619 | { USB_DEVICE(0xeb1a, 0xe300), |
1597 | .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, | 1620 | .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, |
1598 | { USB_DEVICE(0xeb1a, 0xe303), | 1621 | { USB_DEVICE(0xeb1a, 0xe303), |
@@ -1696,6 +1719,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = { | |||
1696 | {0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, | 1719 | {0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, |
1697 | {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028}, | 1720 | {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028}, |
1698 | {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028}, | 1721 | {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028}, |
1722 | {0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT}, | ||
1699 | }; | 1723 | }; |
1700 | 1724 | ||
1701 | /* I2C devicelist hash table for devices with generic USB IDs */ | 1725 | /* I2C devicelist hash table for devices with generic USB IDs */ |
@@ -2348,55 +2372,55 @@ void em28xx_card_setup(struct em28xx *dev) | |||
2348 | 2372 | ||
2349 | /* request some modules */ | 2373 | /* request some modules */ |
2350 | if (dev->board.has_msp34xx) | 2374 | if (dev->board.has_msp34xx) |
2351 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2375 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
2352 | "msp3400", "msp3400", msp3400_addrs); | 2376 | "msp3400", "msp3400", 0, msp3400_addrs); |
2353 | 2377 | ||
2354 | if (dev->board.decoder == EM28XX_SAA711X) | 2378 | if (dev->board.decoder == EM28XX_SAA711X) |
2355 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2379 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
2356 | "saa7115", "saa7115_auto", saa711x_addrs); | 2380 | "saa7115", "saa7115_auto", 0, saa711x_addrs); |
2357 | 2381 | ||
2358 | if (dev->board.decoder == EM28XX_TVP5150) | 2382 | if (dev->board.decoder == EM28XX_TVP5150) |
2359 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2383 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
2360 | "tvp5150", "tvp5150", tvp5150_addrs); | 2384 | "tvp5150", "tvp5150", 0, tvp5150_addrs); |
2361 | 2385 | ||
2362 | if (dev->em28xx_sensor == EM28XX_MT9V011) { | 2386 | if (dev->em28xx_sensor == EM28XX_MT9V011) { |
2363 | struct v4l2_subdev *sd; | 2387 | struct v4l2_subdev *sd; |
2364 | 2388 | ||
2365 | sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, | 2389 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
2366 | &dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs); | 2390 | &dev->i2c_adap, "mt9v011", "mt9v011", 0, mt9v011_addrs); |
2367 | v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal); | 2391 | v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal); |
2368 | } | 2392 | } |
2369 | 2393 | ||
2370 | 2394 | ||
2371 | if (dev->board.adecoder == EM28XX_TVAUDIO) | 2395 | if (dev->board.adecoder == EM28XX_TVAUDIO) |
2372 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2396 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
2373 | "tvaudio", "tvaudio", dev->board.tvaudio_addr); | 2397 | "tvaudio", "tvaudio", dev->board.tvaudio_addr, NULL); |
2374 | 2398 | ||
2375 | if (dev->board.tuner_type != TUNER_ABSENT) { | 2399 | if (dev->board.tuner_type != TUNER_ABSENT) { |
2376 | int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); | 2400 | int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); |
2377 | 2401 | ||
2378 | if (dev->board.radio.type) | 2402 | if (dev->board.radio.type) |
2379 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2403 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
2380 | "tuner", "tuner", dev->board.radio_addr); | 2404 | "tuner", "tuner", dev->board.radio_addr, NULL); |
2381 | 2405 | ||
2382 | if (has_demod) | 2406 | if (has_demod) |
2383 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, | 2407 | v4l2_i2c_new_subdev(&dev->v4l2_dev, |
2384 | &dev->i2c_adap, "tuner", "tuner", | 2408 | &dev->i2c_adap, "tuner", "tuner", |
2385 | v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | 2409 | 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); |
2386 | if (dev->tuner_addr == 0) { | 2410 | if (dev->tuner_addr == 0) { |
2387 | enum v4l2_i2c_tuner_type type = | 2411 | enum v4l2_i2c_tuner_type type = |
2388 | has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; | 2412 | has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; |
2389 | struct v4l2_subdev *sd; | 2413 | struct v4l2_subdev *sd; |
2390 | 2414 | ||
2391 | sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, | 2415 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
2392 | &dev->i2c_adap, "tuner", "tuner", | 2416 | &dev->i2c_adap, "tuner", "tuner", |
2393 | v4l2_i2c_tuner_addrs(type)); | 2417 | 0, v4l2_i2c_tuner_addrs(type)); |
2394 | 2418 | ||
2395 | if (sd) | 2419 | if (sd) |
2396 | dev->tuner_addr = v4l2_i2c_subdev_addr(sd); | 2420 | dev->tuner_addr = v4l2_i2c_subdev_addr(sd); |
2397 | } else { | 2421 | } else { |
2398 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2422 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
2399 | "tuner", "tuner", dev->tuner_addr); | 2423 | "tuner", "tuner", dev->tuner_addr, NULL); |
2400 | } | 2424 | } |
2401 | } | 2425 | } |
2402 | 2426 | ||
@@ -2570,7 +2594,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
2570 | * Default format, used for tvp5150 or saa711x output formats | 2594 | * Default format, used for tvp5150 or saa711x output formats |
2571 | */ | 2595 | */ |
2572 | dev->vinmode = 0x10; | 2596 | dev->vinmode = 0x10; |
2573 | dev->vinctl = 0x11; | 2597 | dev->vinctl = EM28XX_VINCTRL_INTERLACED | |
2598 | EM28XX_VINCTRL_CCIR656_ENABLE; | ||
2574 | 2599 | ||
2575 | /* Do board specific init and eeprom reading */ | 2600 | /* Do board specific init and eeprom reading */ |
2576 | em28xx_card_setup(dev); | 2601 | em28xx_card_setup(dev); |
@@ -2589,6 +2614,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
2589 | /* init video dma queues */ | 2614 | /* init video dma queues */ |
2590 | INIT_LIST_HEAD(&dev->vidq.active); | 2615 | INIT_LIST_HEAD(&dev->vidq.active); |
2591 | INIT_LIST_HEAD(&dev->vidq.queued); | 2616 | INIT_LIST_HEAD(&dev->vidq.queued); |
2617 | INIT_LIST_HEAD(&dev->vbiq.active); | ||
2618 | INIT_LIST_HEAD(&dev->vbiq.queued); | ||
2592 | 2619 | ||
2593 | 2620 | ||
2594 | if (dev->board.has_msp34xx) { | 2621 | if (dev->board.has_msp34xx) { |
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 98e140b5d95e..a88257a7d94f 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c | |||
@@ -54,6 +54,10 @@ static int alt = EM28XX_PINOUT; | |||
54 | module_param(alt, int, 0644); | 54 | module_param(alt, int, 0644); |
55 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); | 55 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); |
56 | 56 | ||
57 | static unsigned int disable_vbi; | ||
58 | module_param(disable_vbi, int, 0644); | ||
59 | MODULE_PARM_DESC(disable_vbi, "disable vbi support"); | ||
60 | |||
57 | /* FIXME */ | 61 | /* FIXME */ |
58 | #define em28xx_isocdbg(fmt, arg...) do {\ | 62 | #define em28xx_isocdbg(fmt, arg...) do {\ |
59 | if (core_debug) \ | 63 | if (core_debug) \ |
@@ -648,9 +652,24 @@ int em28xx_capture_start(struct em28xx *dev, int start) | |||
648 | return rc; | 652 | return rc; |
649 | } | 653 | } |
650 | 654 | ||
655 | int em28xx_vbi_supported(struct em28xx *dev) | ||
656 | { | ||
657 | /* Modprobe option to manually disable */ | ||
658 | if (disable_vbi == 1) | ||
659 | return 0; | ||
660 | |||
661 | if (dev->chip_id == CHIP_ID_EM2860 || | ||
662 | dev->chip_id == CHIP_ID_EM2883) | ||
663 | return 1; | ||
664 | |||
665 | /* Version of em28xx that does not support VBI */ | ||
666 | return 0; | ||
667 | } | ||
668 | |||
651 | int em28xx_set_outfmt(struct em28xx *dev) | 669 | int em28xx_set_outfmt(struct em28xx *dev) |
652 | { | 670 | { |
653 | int ret; | 671 | int ret; |
672 | u8 vinctrl; | ||
654 | 673 | ||
655 | ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, | 674 | ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, |
656 | dev->format->reg | 0x20, 0xff); | 675 | dev->format->reg | 0x20, 0xff); |
@@ -661,7 +680,16 @@ int em28xx_set_outfmt(struct em28xx *dev) | |||
661 | if (ret < 0) | 680 | if (ret < 0) |
662 | return ret; | 681 | return ret; |
663 | 682 | ||
664 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, dev->vinctl); | 683 | vinctrl = dev->vinctl; |
684 | if (em28xx_vbi_supported(dev) == 1) { | ||
685 | vinctrl |= EM28XX_VINCTRL_VBI_RAW; | ||
686 | em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); | ||
687 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); | ||
688 | em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, 0xb4); | ||
689 | em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, 0x0c); | ||
690 | } | ||
691 | |||
692 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); | ||
665 | } | 693 | } |
666 | 694 | ||
667 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, | 695 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, |
@@ -732,7 +760,14 @@ int em28xx_resolution_set(struct em28xx *dev) | |||
732 | 760 | ||
733 | 761 | ||
734 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); | 762 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); |
735 | em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); | 763 | |
764 | /* If we don't set the start position to 4 in VBI mode, we end up | ||
765 | with line 21 being YUYV encoded instead of being in 8-bit | ||
766 | greyscale */ | ||
767 | if (em28xx_vbi_supported(dev) == 1) | ||
768 | em28xx_capture_area_set(dev, 0, 4, width >> 2, height >> 2); | ||
769 | else | ||
770 | em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); | ||
736 | 771 | ||
737 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); | 772 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); |
738 | } | 773 | } |
@@ -844,8 +879,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode); | |||
844 | */ | 879 | */ |
845 | static void em28xx_irq_callback(struct urb *urb) | 880 | static void em28xx_irq_callback(struct urb *urb) |
846 | { | 881 | { |
847 | struct em28xx_dmaqueue *dma_q = urb->context; | 882 | struct em28xx *dev = urb->context; |
848 | struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); | ||
849 | int rc, i; | 883 | int rc, i; |
850 | 884 | ||
851 | switch (urb->status) { | 885 | switch (urb->status) { |
@@ -930,6 +964,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, | |||
930 | int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) | 964 | int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) |
931 | { | 965 | { |
932 | struct em28xx_dmaqueue *dma_q = &dev->vidq; | 966 | struct em28xx_dmaqueue *dma_q = &dev->vidq; |
967 | struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; | ||
933 | int i; | 968 | int i; |
934 | int sb_size, pipe; | 969 | int sb_size, pipe; |
935 | struct urb *urb; | 970 | struct urb *urb; |
@@ -959,7 +994,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, | |||
959 | } | 994 | } |
960 | 995 | ||
961 | dev->isoc_ctl.max_pkt_size = max_pkt_size; | 996 | dev->isoc_ctl.max_pkt_size = max_pkt_size; |
962 | dev->isoc_ctl.buf = NULL; | 997 | dev->isoc_ctl.vid_buf = NULL; |
998 | dev->isoc_ctl.vbi_buf = NULL; | ||
963 | 999 | ||
964 | sb_size = max_packets * dev->isoc_ctl.max_pkt_size; | 1000 | sb_size = max_packets * dev->isoc_ctl.max_pkt_size; |
965 | 1001 | ||
@@ -994,7 +1030,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, | |||
994 | 1030 | ||
995 | usb_fill_int_urb(urb, dev->udev, pipe, | 1031 | usb_fill_int_urb(urb, dev->udev, pipe, |
996 | dev->isoc_ctl.transfer_buffer[i], sb_size, | 1032 | dev->isoc_ctl.transfer_buffer[i], sb_size, |
997 | em28xx_irq_callback, dma_q, 1); | 1033 | em28xx_irq_callback, dev, 1); |
998 | 1034 | ||
999 | urb->number_of_packets = max_packets; | 1035 | urb->number_of_packets = max_packets; |
1000 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | 1036 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; |
@@ -1009,6 +1045,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, | |||
1009 | } | 1045 | } |
1010 | 1046 | ||
1011 | init_waitqueue_head(&dma_q->wq); | 1047 | init_waitqueue_head(&dma_q->wq); |
1048 | init_waitqueue_head(&vbi_dma_q->wq); | ||
1012 | 1049 | ||
1013 | em28xx_capture_start(dev, 1); | 1050 | em28xx_capture_start(dev, 1); |
1014 | 1051 | ||
@@ -1094,7 +1131,7 @@ struct em28xx *em28xx_get_device(int minor, | |||
1094 | list_for_each_entry(h, &em28xx_devlist, devlist) { | 1131 | list_for_each_entry(h, &em28xx_devlist, devlist) { |
1095 | if (h->vdev->minor == minor) | 1132 | if (h->vdev->minor == minor) |
1096 | dev = h; | 1133 | dev = h; |
1097 | if (h->vbi_dev->minor == minor) { | 1134 | if (h->vbi_dev && h->vbi_dev->minor == minor) { |
1098 | dev = h; | 1135 | dev = h; |
1099 | *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; | 1136 | *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1100 | } | 1137 | } |
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index d603575431b4..db749461e5c6 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "s5h1409.h" | 33 | #include "s5h1409.h" |
34 | #include "mt352.h" | 34 | #include "mt352.h" |
35 | #include "mt352_priv.h" /* FIXME */ | 35 | #include "mt352_priv.h" /* FIXME */ |
36 | #include "tda1002x.h" | ||
36 | 37 | ||
37 | MODULE_DESCRIPTION("driver for em28xx based DVB cards"); | 38 | MODULE_DESCRIPTION("driver for em28xx based DVB cards"); |
38 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | 39 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); |
@@ -295,6 +296,11 @@ static struct mt352_config terratec_xs_mt352_cfg = { | |||
295 | .demod_init = mt352_terratec_xs_init, | 296 | .demod_init = mt352_terratec_xs_init, |
296 | }; | 297 | }; |
297 | 298 | ||
299 | static struct tda10023_config em28xx_tda10023_config = { | ||
300 | .demod_address = 0x0c, | ||
301 | .invert = 1, | ||
302 | }; | ||
303 | |||
298 | /* ------------------------------------------------------------------ */ | 304 | /* ------------------------------------------------------------------ */ |
299 | 305 | ||
300 | static int attach_xc3028(u8 addr, struct em28xx *dev) | 306 | static int attach_xc3028(u8 addr, struct em28xx *dev) |
@@ -549,6 +555,19 @@ static int dvb_init(struct em28xx *dev) | |||
549 | } | 555 | } |
550 | break; | 556 | break; |
551 | #endif | 557 | #endif |
558 | case EM2870_BOARD_REDDO_DVB_C_USB_BOX: | ||
559 | /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ | ||
560 | dvb->frontend = dvb_attach(tda10023_attach, | ||
561 | &em28xx_tda10023_config, | ||
562 | &dev->i2c_adap, 0x48); | ||
563 | if (dvb->frontend) { | ||
564 | if (!dvb_attach(simple_tuner_attach, dvb->frontend, | ||
565 | &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { | ||
566 | result = -EINVAL; | ||
567 | goto out_free; | ||
568 | } | ||
569 | } | ||
570 | break; | ||
552 | default: | 571 | default: |
553 | printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" | 572 | printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" |
554 | " isn't supported yet\n", | 573 | " isn't supported yet\n", |
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 6bf84bd787df..ed12e7ffcbd0 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h | |||
@@ -86,7 +86,19 @@ | |||
86 | #define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b | 86 | #define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b |
87 | 87 | ||
88 | #define EM28XX_R10_VINMODE 0x10 | 88 | #define EM28XX_R10_VINMODE 0x10 |
89 | |||
89 | #define EM28XX_R11_VINCTRL 0x11 | 90 | #define EM28XX_R11_VINCTRL 0x11 |
91 | |||
92 | /* em28xx Video Input Control Register 0x11 */ | ||
93 | #define EM28XX_VINCTRL_VBI_SLICED 0x80 | ||
94 | #define EM28XX_VINCTRL_VBI_RAW 0x40 | ||
95 | #define EM28XX_VINCTRL_VOUT_MODE_IN 0x20 /* HREF,VREF,VACT in output */ | ||
96 | #define EM28XX_VINCTRL_CCIR656_ENABLE 0x10 | ||
97 | #define EM28XX_VINCTRL_VBI_16BIT_RAW 0x08 /* otherwise 8-bit raw */ | ||
98 | #define EM28XX_VINCTRL_FID_ON_HREF 0x04 | ||
99 | #define EM28XX_VINCTRL_DUAL_EDGE_STROBE 0x02 | ||
100 | #define EM28XX_VINCTRL_INTERLACED 0x01 | ||
101 | |||
90 | #define EM28XX_R12_VINENABLE 0x12 /* */ | 102 | #define EM28XX_R12_VINENABLE 0x12 /* */ |
91 | 103 | ||
92 | #define EM28XX_R14_GAMMA 0x14 | 104 | #define EM28XX_R14_GAMMA 0x14 |
@@ -135,6 +147,10 @@ | |||
135 | #define EM28XX_R31_HSCALEHIGH 0x31 | 147 | #define EM28XX_R31_HSCALEHIGH 0x31 |
136 | #define EM28XX_R32_VSCALELOW 0x32 | 148 | #define EM28XX_R32_VSCALELOW 0x32 |
137 | #define EM28XX_R33_VSCALEHIGH 0x33 | 149 | #define EM28XX_R33_VSCALEHIGH 0x33 |
150 | #define EM28XX_R34_VBI_START_H 0x34 | ||
151 | #define EM28XX_R35_VBI_START_V 0x35 | ||
152 | #define EM28XX_R36_VBI_WIDTH 0x36 | ||
153 | #define EM28XX_R37_VBI_HEIGHT 0x37 | ||
138 | 154 | ||
139 | #define EM28XX_R40_AC97LSB 0x40 | 155 | #define EM28XX_R40_AC97LSB 0x40 |
140 | #define EM28XX_R41_AC97MSB 0x41 | 156 | #define EM28XX_R41_AC97MSB 0x41 |
diff --git a/drivers/media/video/em28xx/em28xx-vbi.c b/drivers/media/video/em28xx/em28xx-vbi.c new file mode 100644 index 000000000000..94943e5a1529 --- /dev/null +++ b/drivers/media/video/em28xx/em28xx-vbi.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | em28xx-vbi.c - VBI driver for em28xx | ||
3 | |||
4 | Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
5 | |||
6 | This work was sponsored by EyeMagnet Limited. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include "em28xx.h" | ||
30 | |||
31 | static unsigned int vbibufs = 5; | ||
32 | module_param(vbibufs, int, 0644); | ||
33 | MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); | ||
34 | |||
35 | static unsigned int vbi_debug; | ||
36 | module_param(vbi_debug, int, 0644); | ||
37 | MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); | ||
38 | |||
39 | #define dprintk(level, fmt, arg...) if (vbi_debug >= level) \ | ||
40 | printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) | ||
41 | |||
42 | /* ------------------------------------------------------------------ */ | ||
43 | |||
44 | static void | ||
45 | free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) | ||
46 | { | ||
47 | struct em28xx_fh *fh = vq->priv_data; | ||
48 | struct em28xx *dev = fh->dev; | ||
49 | unsigned long flags = 0; | ||
50 | if (in_interrupt()) | ||
51 | BUG(); | ||
52 | |||
53 | /* We used to wait for the buffer to finish here, but this didn't work | ||
54 | because, as we were keeping the state as VIDEOBUF_QUEUED, | ||
55 | videobuf_queue_cancel marked it as finished for us. | ||
56 | (Also, it could wedge forever if the hardware was misconfigured.) | ||
57 | |||
58 | This should be safe; by the time we get here, the buffer isn't | ||
59 | queued anymore. If we ever start marking the buffers as | ||
60 | VIDEOBUF_ACTIVE, it won't be, though. | ||
61 | */ | ||
62 | spin_lock_irqsave(&dev->slock, flags); | ||
63 | if (dev->isoc_ctl.vbi_buf == buf) | ||
64 | dev->isoc_ctl.vbi_buf = NULL; | ||
65 | spin_unlock_irqrestore(&dev->slock, flags); | ||
66 | |||
67 | videobuf_vmalloc_free(&buf->vb); | ||
68 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
73 | { | ||
74 | *size = 720 * 12 * 2; | ||
75 | if (0 == *count) | ||
76 | *count = vbibufs; | ||
77 | if (*count < 2) | ||
78 | *count = 2; | ||
79 | if (*count > 32) | ||
80 | *count = 32; | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
86 | enum v4l2_field field) | ||
87 | { | ||
88 | struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); | ||
89 | int rc = 0; | ||
90 | unsigned int size; | ||
91 | |||
92 | size = 720 * 12 * 2; | ||
93 | |||
94 | buf->vb.size = size; | ||
95 | |||
96 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
97 | return -EINVAL; | ||
98 | |||
99 | buf->vb.width = 720; | ||
100 | buf->vb.height = 12; | ||
101 | buf->vb.field = field; | ||
102 | |||
103 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
104 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
105 | if (rc < 0) | ||
106 | goto fail; | ||
107 | } | ||
108 | |||
109 | buf->vb.state = VIDEOBUF_PREPARED; | ||
110 | return 0; | ||
111 | |||
112 | fail: | ||
113 | free_buffer(q, buf); | ||
114 | return rc; | ||
115 | } | ||
116 | |||
117 | static void | ||
118 | vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
119 | { | ||
120 | struct em28xx_buffer *buf = container_of(vb, | ||
121 | struct em28xx_buffer, | ||
122 | vb); | ||
123 | struct em28xx_fh *fh = vq->priv_data; | ||
124 | struct em28xx *dev = fh->dev; | ||
125 | struct em28xx_dmaqueue *vbiq = &dev->vbiq; | ||
126 | |||
127 | buf->vb.state = VIDEOBUF_QUEUED; | ||
128 | list_add_tail(&buf->vb.queue, &vbiq->active); | ||
129 | } | ||
130 | |||
131 | static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
132 | { | ||
133 | struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); | ||
134 | free_buffer(q, buf); | ||
135 | } | ||
136 | |||
137 | struct videobuf_queue_ops em28xx_vbi_qops = { | ||
138 | .buf_setup = vbi_setup, | ||
139 | .buf_prepare = vbi_prepare, | ||
140 | .buf_queue = vbi_queue, | ||
141 | .buf_release = vbi_release, | ||
142 | }; | ||
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index a6bdbc21410e..3a1dfb7726f8 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -163,7 +163,24 @@ static inline void buffer_filled(struct em28xx *dev, | |||
163 | buf->vb.field_count++; | 163 | buf->vb.field_count++; |
164 | do_gettimeofday(&buf->vb.ts); | 164 | do_gettimeofday(&buf->vb.ts); |
165 | 165 | ||
166 | dev->isoc_ctl.buf = NULL; | 166 | dev->isoc_ctl.vid_buf = NULL; |
167 | |||
168 | list_del(&buf->vb.queue); | ||
169 | wake_up(&buf->vb.done); | ||
170 | } | ||
171 | |||
172 | static inline void vbi_buffer_filled(struct em28xx *dev, | ||
173 | struct em28xx_dmaqueue *dma_q, | ||
174 | struct em28xx_buffer *buf) | ||
175 | { | ||
176 | /* Advice that buffer was filled */ | ||
177 | em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); | ||
178 | |||
179 | buf->vb.state = VIDEOBUF_DONE; | ||
180 | buf->vb.field_count++; | ||
181 | do_gettimeofday(&buf->vb.ts); | ||
182 | |||
183 | dev->isoc_ctl.vbi_buf = NULL; | ||
167 | 184 | ||
168 | list_del(&buf->vb.queue); | 185 | list_del(&buf->vb.queue); |
169 | wake_up(&buf->vb.done); | 186 | wake_up(&buf->vb.done); |
@@ -239,7 +256,8 @@ static void em28xx_copy_video(struct em28xx *dev, | |||
239 | 256 | ||
240 | if ((char *)startwrite + lencopy > (char *)outp + | 257 | if ((char *)startwrite + lencopy > (char *)outp + |
241 | buf->vb.size) { | 258 | buf->vb.size) { |
242 | em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n", | 259 | em28xx_isocdbg("Overflow of %zi bytes past buffer end" |
260 | "(2)\n", | ||
243 | ((char *)startwrite + lencopy) - | 261 | ((char *)startwrite + lencopy) - |
244 | ((char *)outp + buf->vb.size)); | 262 | ((char *)outp + buf->vb.size)); |
245 | lencopy = remain = (char *)outp + buf->vb.size - | 263 | lencopy = remain = (char *)outp + buf->vb.size - |
@@ -256,6 +274,63 @@ static void em28xx_copy_video(struct em28xx *dev, | |||
256 | dma_q->pos += len; | 274 | dma_q->pos += len; |
257 | } | 275 | } |
258 | 276 | ||
277 | static void em28xx_copy_vbi(struct em28xx *dev, | ||
278 | struct em28xx_dmaqueue *dma_q, | ||
279 | struct em28xx_buffer *buf, | ||
280 | unsigned char *p, | ||
281 | unsigned char *outp, unsigned long len) | ||
282 | { | ||
283 | void *startwrite, *startread; | ||
284 | int offset; | ||
285 | int bytesperline = 720; | ||
286 | |||
287 | if (dev == NULL) { | ||
288 | em28xx_isocdbg("dev is null\n"); | ||
289 | return; | ||
290 | } | ||
291 | |||
292 | if (dma_q == NULL) { | ||
293 | em28xx_isocdbg("dma_q is null\n"); | ||
294 | return; | ||
295 | } | ||
296 | if (buf == NULL) { | ||
297 | return; | ||
298 | } | ||
299 | if (p == NULL) { | ||
300 | em28xx_isocdbg("p is null\n"); | ||
301 | return; | ||
302 | } | ||
303 | if (outp == NULL) { | ||
304 | em28xx_isocdbg("outp is null\n"); | ||
305 | return; | ||
306 | } | ||
307 | |||
308 | if (dma_q->pos + len > buf->vb.size) | ||
309 | len = buf->vb.size - dma_q->pos; | ||
310 | |||
311 | if ((p[0] == 0x33 && p[1] == 0x95) || | ||
312 | (p[0] == 0x88 && p[1] == 0x88)) { | ||
313 | /* Header field, advance past it */ | ||
314 | p += 4; | ||
315 | } else { | ||
316 | len += 4; | ||
317 | } | ||
318 | |||
319 | startread = p; | ||
320 | |||
321 | startwrite = outp + dma_q->pos; | ||
322 | offset = dma_q->pos; | ||
323 | |||
324 | /* Make sure the bottom field populates the second half of the frame */ | ||
325 | if (buf->top_field == 0) { | ||
326 | startwrite += bytesperline * 0x0c; | ||
327 | offset += bytesperline * 0x0c; | ||
328 | } | ||
329 | |||
330 | memcpy(startwrite, startread, len); | ||
331 | dma_q->pos += len; | ||
332 | } | ||
333 | |||
259 | static inline void print_err_status(struct em28xx *dev, | 334 | static inline void print_err_status(struct em28xx *dev, |
260 | int packet, int status) | 335 | int packet, int status) |
261 | { | 336 | { |
@@ -306,7 +381,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, | |||
306 | 381 | ||
307 | if (list_empty(&dma_q->active)) { | 382 | if (list_empty(&dma_q->active)) { |
308 | em28xx_isocdbg("No active queue to serve\n"); | 383 | em28xx_isocdbg("No active queue to serve\n"); |
309 | dev->isoc_ctl.buf = NULL; | 384 | dev->isoc_ctl.vid_buf = NULL; |
310 | *buf = NULL; | 385 | *buf = NULL; |
311 | return; | 386 | return; |
312 | } | 387 | } |
@@ -318,7 +393,34 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, | |||
318 | outp = videobuf_to_vmalloc(&(*buf)->vb); | 393 | outp = videobuf_to_vmalloc(&(*buf)->vb); |
319 | memset(outp, 0, (*buf)->vb.size); | 394 | memset(outp, 0, (*buf)->vb.size); |
320 | 395 | ||
321 | dev->isoc_ctl.buf = *buf; | 396 | dev->isoc_ctl.vid_buf = *buf; |
397 | |||
398 | return; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * video-buf generic routine to get the next available VBI buffer | ||
403 | */ | ||
404 | static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q, | ||
405 | struct em28xx_buffer **buf) | ||
406 | { | ||
407 | struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq); | ||
408 | char *outp; | ||
409 | |||
410 | if (list_empty(&dma_q->active)) { | ||
411 | em28xx_isocdbg("No active queue to serve\n"); | ||
412 | dev->isoc_ctl.vbi_buf = NULL; | ||
413 | *buf = NULL; | ||
414 | return; | ||
415 | } | ||
416 | |||
417 | /* Get the next buffer */ | ||
418 | *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); | ||
419 | /* Cleans up buffer - Usefull for testing for frame/URB loss */ | ||
420 | outp = videobuf_to_vmalloc(&(*buf)->vb); | ||
421 | memset(outp, 0x00, (*buf)->vb.size); | ||
422 | |||
423 | dev->isoc_ctl.vbi_buf = *buf; | ||
322 | 424 | ||
323 | return; | 425 | return; |
324 | } | 426 | } |
@@ -329,7 +431,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, | |||
329 | static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) | 431 | static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) |
330 | { | 432 | { |
331 | struct em28xx_buffer *buf; | 433 | struct em28xx_buffer *buf; |
332 | struct em28xx_dmaqueue *dma_q = urb->context; | 434 | struct em28xx_dmaqueue *dma_q = &dev->vidq; |
333 | unsigned char *outp = NULL; | 435 | unsigned char *outp = NULL; |
334 | int i, len = 0, rc = 1; | 436 | int i, len = 0, rc = 1; |
335 | unsigned char *p; | 437 | unsigned char *p; |
@@ -346,7 +448,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) | |||
346 | return 0; | 448 | return 0; |
347 | } | 449 | } |
348 | 450 | ||
349 | buf = dev->isoc_ctl.buf; | 451 | buf = dev->isoc_ctl.vid_buf; |
350 | if (buf != NULL) | 452 | if (buf != NULL) |
351 | outp = videobuf_to_vmalloc(&buf->vb); | 453 | outp = videobuf_to_vmalloc(&buf->vb); |
352 | 454 | ||
@@ -410,6 +512,153 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) | |||
410 | return rc; | 512 | return rc; |
411 | } | 513 | } |
412 | 514 | ||
515 | /* Version of isoc handler that takes into account a mixture of video and | ||
516 | VBI data */ | ||
517 | static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) | ||
518 | { | ||
519 | struct em28xx_buffer *buf, *vbi_buf; | ||
520 | struct em28xx_dmaqueue *dma_q = &dev->vidq; | ||
521 | struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; | ||
522 | unsigned char *outp = NULL; | ||
523 | unsigned char *vbioutp = NULL; | ||
524 | int i, len = 0, rc = 1; | ||
525 | unsigned char *p; | ||
526 | int vbi_size; | ||
527 | |||
528 | if (!dev) | ||
529 | return 0; | ||
530 | |||
531 | if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) | ||
532 | return 0; | ||
533 | |||
534 | if (urb->status < 0) { | ||
535 | print_err_status(dev, -1, urb->status); | ||
536 | if (urb->status == -ENOENT) | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | buf = dev->isoc_ctl.vid_buf; | ||
541 | if (buf != NULL) | ||
542 | outp = videobuf_to_vmalloc(&buf->vb); | ||
543 | |||
544 | vbi_buf = dev->isoc_ctl.vbi_buf; | ||
545 | if (vbi_buf != NULL) | ||
546 | vbioutp = videobuf_to_vmalloc(&vbi_buf->vb); | ||
547 | |||
548 | for (i = 0; i < urb->number_of_packets; i++) { | ||
549 | int status = urb->iso_frame_desc[i].status; | ||
550 | |||
551 | if (status < 0) { | ||
552 | print_err_status(dev, i, status); | ||
553 | if (urb->iso_frame_desc[i].status != -EPROTO) | ||
554 | continue; | ||
555 | } | ||
556 | |||
557 | len = urb->iso_frame_desc[i].actual_length - 4; | ||
558 | |||
559 | if (urb->iso_frame_desc[i].actual_length <= 0) { | ||
560 | /* em28xx_isocdbg("packet %d is empty",i); - spammy */ | ||
561 | continue; | ||
562 | } | ||
563 | if (urb->iso_frame_desc[i].actual_length > | ||
564 | dev->max_pkt_size) { | ||
565 | em28xx_isocdbg("packet bigger than packet size"); | ||
566 | continue; | ||
567 | } | ||
568 | |||
569 | p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
570 | |||
571 | /* capture type 0 = vbi start | ||
572 | capture type 1 = video start | ||
573 | capture type 2 = video in progress */ | ||
574 | if (p[0] == 0x33 && p[1] == 0x95) { | ||
575 | dev->capture_type = 0; | ||
576 | dev->vbi_read = 0; | ||
577 | em28xx_isocdbg("VBI START HEADER!!!\n"); | ||
578 | dev->cur_field = p[2]; | ||
579 | } | ||
580 | |||
581 | /* FIXME: get rid of hard-coded value */ | ||
582 | vbi_size = 720 * 0x0c; | ||
583 | |||
584 | if (dev->capture_type == 0) { | ||
585 | if (dev->vbi_read >= vbi_size) { | ||
586 | /* We've already read all the VBI data, so | ||
587 | treat the rest as video */ | ||
588 | em28xx_isocdbg("dev->vbi_read > vbi_size\n"); | ||
589 | } else if ((dev->vbi_read + len) < vbi_size) { | ||
590 | /* This entire frame is VBI data */ | ||
591 | if (dev->vbi_read == 0 && | ||
592 | (!(dev->cur_field & 1))) { | ||
593 | /* Brand new frame */ | ||
594 | if (vbi_buf != NULL) | ||
595 | vbi_buffer_filled(dev, | ||
596 | vbi_dma_q, | ||
597 | vbi_buf); | ||
598 | vbi_get_next_buf(vbi_dma_q, &vbi_buf); | ||
599 | if (vbi_buf == NULL) | ||
600 | vbioutp = NULL; | ||
601 | else | ||
602 | vbioutp = videobuf_to_vmalloc( | ||
603 | &vbi_buf->vb); | ||
604 | } | ||
605 | |||
606 | if (dev->vbi_read == 0) { | ||
607 | vbi_dma_q->pos = 0; | ||
608 | if (vbi_buf != NULL) { | ||
609 | if (dev->cur_field & 1) | ||
610 | vbi_buf->top_field = 0; | ||
611 | else | ||
612 | vbi_buf->top_field = 1; | ||
613 | } | ||
614 | } | ||
615 | |||
616 | dev->vbi_read += len; | ||
617 | em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p, | ||
618 | vbioutp, len); | ||
619 | } else { | ||
620 | /* Some of this frame is VBI data and some is | ||
621 | video data */ | ||
622 | int vbi_data_len = vbi_size - dev->vbi_read; | ||
623 | dev->vbi_read += vbi_data_len; | ||
624 | em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p, | ||
625 | vbioutp, vbi_data_len); | ||
626 | dev->capture_type = 1; | ||
627 | p += vbi_data_len; | ||
628 | len -= vbi_data_len; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | if (dev->capture_type == 1) { | ||
633 | dev->capture_type = 2; | ||
634 | em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], | ||
635 | len, (p[2] & 1) ? "odd" : "even"); | ||
636 | |||
637 | if (dev->progressive || !(dev->cur_field & 1)) { | ||
638 | if (buf != NULL) | ||
639 | buffer_filled(dev, dma_q, buf); | ||
640 | get_next_buf(dma_q, &buf); | ||
641 | if (buf == NULL) | ||
642 | outp = NULL; | ||
643 | else | ||
644 | outp = videobuf_to_vmalloc(&buf->vb); | ||
645 | } | ||
646 | if (buf != NULL) { | ||
647 | if (dev->cur_field & 1) | ||
648 | buf->top_field = 0; | ||
649 | else | ||
650 | buf->top_field = 1; | ||
651 | } | ||
652 | |||
653 | dma_q->pos = 0; | ||
654 | } | ||
655 | if (buf != NULL && dev->capture_type == 2) | ||
656 | em28xx_copy_video(dev, dma_q, buf, p, outp, len); | ||
657 | } | ||
658 | return rc; | ||
659 | } | ||
660 | |||
661 | |||
413 | /* ------------------------------------------------------------------ | 662 | /* ------------------------------------------------------------------ |
414 | Videobuf operations | 663 | Videobuf operations |
415 | ------------------------------------------------------------------*/ | 664 | ------------------------------------------------------------------*/ |
@@ -421,7 +670,8 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) | |||
421 | struct em28xx *dev = fh->dev; | 670 | struct em28xx *dev = fh->dev; |
422 | struct v4l2_frequency f; | 671 | struct v4l2_frequency f; |
423 | 672 | ||
424 | *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3; | 673 | *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) |
674 | >> 3; | ||
425 | 675 | ||
426 | if (0 == *count) | 676 | if (0 == *count) |
427 | *count = EM28XX_DEF_BUF; | 677 | *count = EM28XX_DEF_BUF; |
@@ -458,8 +708,8 @@ static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) | |||
458 | VIDEOBUF_ACTIVE, it won't be, though. | 708 | VIDEOBUF_ACTIVE, it won't be, though. |
459 | */ | 709 | */ |
460 | spin_lock_irqsave(&dev->slock, flags); | 710 | spin_lock_irqsave(&dev->slock, flags); |
461 | if (dev->isoc_ctl.buf == buf) | 711 | if (dev->isoc_ctl.vid_buf == buf) |
462 | dev->isoc_ctl.buf = NULL; | 712 | dev->isoc_ctl.vid_buf = NULL; |
463 | spin_unlock_irqrestore(&dev->slock, flags); | 713 | spin_unlock_irqrestore(&dev->slock, flags); |
464 | 714 | ||
465 | videobuf_vmalloc_free(&buf->vb); | 715 | videobuf_vmalloc_free(&buf->vb); |
@@ -475,7 +725,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |||
475 | struct em28xx *dev = fh->dev; | 725 | struct em28xx *dev = fh->dev; |
476 | int rc = 0, urb_init = 0; | 726 | int rc = 0, urb_init = 0; |
477 | 727 | ||
478 | buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3; | 728 | buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth |
729 | + 7) >> 3; | ||
479 | 730 | ||
480 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | 731 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) |
481 | return -EINVAL; | 732 | return -EINVAL; |
@@ -494,9 +745,16 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |||
494 | urb_init = 1; | 745 | urb_init = 1; |
495 | 746 | ||
496 | if (urb_init) { | 747 | if (urb_init) { |
497 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, | 748 | if (em28xx_vbi_supported(dev) == 1) |
498 | EM28XX_NUM_BUFS, dev->max_pkt_size, | 749 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, |
499 | em28xx_isoc_copy); | 750 | EM28XX_NUM_BUFS, |
751 | dev->max_pkt_size, | ||
752 | em28xx_isoc_copy_vbi); | ||
753 | else | ||
754 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, | ||
755 | EM28XX_NUM_BUFS, | ||
756 | dev->max_pkt_size, | ||
757 | em28xx_isoc_copy); | ||
500 | if (rc < 0) | 758 | if (rc < 0) |
501 | goto fail; | 759 | goto fail; |
502 | } | 760 | } |
@@ -578,34 +836,63 @@ static void video_mux(struct em28xx *dev, int index) | |||
578 | } | 836 | } |
579 | 837 | ||
580 | /* Usage lock check functions */ | 838 | /* Usage lock check functions */ |
581 | static int res_get(struct em28xx_fh *fh) | 839 | static int res_get(struct em28xx_fh *fh, unsigned int bit) |
582 | { | 840 | { |
583 | struct em28xx *dev = fh->dev; | 841 | struct em28xx *dev = fh->dev; |
584 | int rc = 0; | ||
585 | 842 | ||
586 | /* This instance already has stream_on */ | 843 | if (fh->resources & bit) |
587 | if (fh->stream_on) | 844 | /* have it already allocated */ |
588 | return rc; | 845 | return 1; |
589 | 846 | ||
590 | if (dev->stream_on) | 847 | /* is it free? */ |
591 | return -EBUSY; | 848 | mutex_lock(&dev->lock); |
849 | if (dev->resources & bit) { | ||
850 | /* no, someone else uses it */ | ||
851 | mutex_unlock(&dev->lock); | ||
852 | return 0; | ||
853 | } | ||
854 | /* it's free, grab it */ | ||
855 | fh->resources |= bit; | ||
856 | dev->resources |= bit; | ||
857 | em28xx_videodbg("res: get %d\n", bit); | ||
858 | mutex_unlock(&dev->lock); | ||
859 | return 1; | ||
860 | } | ||
592 | 861 | ||
593 | dev->stream_on = 1; | 862 | static int res_check(struct em28xx_fh *fh, unsigned int bit) |
594 | fh->stream_on = 1; | 863 | { |
595 | return rc; | 864 | return fh->resources & bit; |
596 | } | 865 | } |
597 | 866 | ||
598 | static int res_check(struct em28xx_fh *fh) | 867 | static int res_locked(struct em28xx *dev, unsigned int bit) |
599 | { | 868 | { |
600 | return fh->stream_on; | 869 | return dev->resources & bit; |
601 | } | 870 | } |
602 | 871 | ||
603 | static void res_free(struct em28xx_fh *fh) | 872 | static void res_free(struct em28xx_fh *fh, unsigned int bits) |
604 | { | 873 | { |
605 | struct em28xx *dev = fh->dev; | 874 | struct em28xx *dev = fh->dev; |
606 | 875 | ||
607 | fh->stream_on = 0; | 876 | BUG_ON((fh->resources & bits) != bits); |
608 | dev->stream_on = 0; | 877 | |
878 | mutex_lock(&dev->lock); | ||
879 | fh->resources &= ~bits; | ||
880 | dev->resources &= ~bits; | ||
881 | em28xx_videodbg("res: put %d\n", bits); | ||
882 | mutex_unlock(&dev->lock); | ||
883 | } | ||
884 | |||
885 | static int get_ressource(struct em28xx_fh *fh) | ||
886 | { | ||
887 | switch (fh->type) { | ||
888 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
889 | return EM28XX_RESOURCE_VIDEO; | ||
890 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
891 | return EM28XX_RESOURCE_VBI; | ||
892 | default: | ||
893 | BUG(); | ||
894 | return 0; | ||
895 | } | ||
609 | } | 896 | } |
610 | 897 | ||
611 | /* | 898 | /* |
@@ -782,7 +1069,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | |||
782 | } else { | 1069 | } else { |
783 | /* width must even because of the YUYV format | 1070 | /* width must even because of the YUYV format |
784 | height must be even because of interlacing */ | 1071 | height must be even because of interlacing */ |
785 | v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0); | 1072 | v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, |
1073 | 1, 0); | ||
786 | } | 1074 | } |
787 | 1075 | ||
788 | get_scale(dev, width, height, &hscale, &vscale); | 1076 | get_scale(dev, width, height, &hscale, &vscale); |
@@ -848,12 +1136,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
848 | goto out; | 1136 | goto out; |
849 | } | 1137 | } |
850 | 1138 | ||
851 | if (dev->stream_on && !fh->stream_on) { | ||
852 | em28xx_errdev("%s device in use by another fh\n", __func__); | ||
853 | rc = -EBUSY; | ||
854 | goto out; | ||
855 | } | ||
856 | |||
857 | rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat, | 1139 | rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat, |
858 | f->fmt.pix.width, f->fmt.pix.height); | 1140 | f->fmt.pix.width, f->fmt.pix.height); |
859 | 1141 | ||
@@ -862,6 +1144,21 @@ out: | |||
862 | return rc; | 1144 | return rc; |
863 | } | 1145 | } |
864 | 1146 | ||
1147 | static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) | ||
1148 | { | ||
1149 | struct em28xx_fh *fh = priv; | ||
1150 | struct em28xx *dev = fh->dev; | ||
1151 | int rc; | ||
1152 | |||
1153 | rc = check_dev(dev); | ||
1154 | if (rc < 0) | ||
1155 | return rc; | ||
1156 | |||
1157 | *norm = dev->norm; | ||
1158 | |||
1159 | return 0; | ||
1160 | } | ||
1161 | |||
865 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) | 1162 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) |
866 | { | 1163 | { |
867 | struct em28xx_fh *fh = priv; | 1164 | struct em28xx_fh *fh = priv; |
@@ -1413,20 +1710,25 @@ static int vidioc_streamon(struct file *file, void *priv, | |||
1413 | { | 1710 | { |
1414 | struct em28xx_fh *fh = priv; | 1711 | struct em28xx_fh *fh = priv; |
1415 | struct em28xx *dev = fh->dev; | 1712 | struct em28xx *dev = fh->dev; |
1416 | int rc; | 1713 | int rc = -EINVAL; |
1417 | 1714 | ||
1418 | rc = check_dev(dev); | 1715 | rc = check_dev(dev); |
1419 | if (rc < 0) | 1716 | if (rc < 0) |
1420 | return rc; | 1717 | return rc; |
1421 | 1718 | ||
1719 | if (unlikely(type != fh->type)) | ||
1720 | return -EINVAL; | ||
1422 | 1721 | ||
1423 | mutex_lock(&dev->lock); | 1722 | em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n", |
1424 | rc = res_get(fh); | 1723 | fh, type, fh->resources, dev->resources); |
1425 | 1724 | ||
1426 | if (likely(rc >= 0)) | 1725 | if (unlikely(!res_get(fh, get_ressource(fh)))) |
1427 | rc = videobuf_streamon(&fh->vb_vidq); | 1726 | return -EBUSY; |
1428 | 1727 | ||
1429 | mutex_unlock(&dev->lock); | 1728 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1729 | rc = videobuf_streamon(&fh->vb_vidq); | ||
1730 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1731 | rc = videobuf_streamon(&fh->vb_vbiq); | ||
1430 | 1732 | ||
1431 | return rc; | 1733 | return rc; |
1432 | } | 1734 | } |
@@ -1442,17 +1744,22 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1442 | if (rc < 0) | 1744 | if (rc < 0) |
1443 | return rc; | 1745 | return rc; |
1444 | 1746 | ||
1445 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1747 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1748 | fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1446 | return -EINVAL; | 1749 | return -EINVAL; |
1447 | if (type != fh->type) | 1750 | if (type != fh->type) |
1448 | return -EINVAL; | 1751 | return -EINVAL; |
1449 | 1752 | ||
1450 | mutex_lock(&dev->lock); | 1753 | em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n", |
1754 | fh, type, fh->resources, dev->resources); | ||
1451 | 1755 | ||
1452 | videobuf_streamoff(&fh->vb_vidq); | 1756 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
1453 | res_free(fh); | 1757 | videobuf_streamoff(&fh->vb_vidq); |
1454 | 1758 | res_free(fh, EM28XX_RESOURCE_VIDEO); | |
1455 | mutex_unlock(&dev->lock); | 1759 | } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
1760 | videobuf_streamoff(&fh->vb_vbiq); | ||
1761 | res_free(fh, EM28XX_RESOURCE_VBI); | ||
1762 | } | ||
1456 | 1763 | ||
1457 | return 0; | 1764 | return 0; |
1458 | } | 1765 | } |
@@ -1474,6 +1781,9 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
1474 | V4L2_CAP_VIDEO_CAPTURE | | 1781 | V4L2_CAP_VIDEO_CAPTURE | |
1475 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; | 1782 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; |
1476 | 1783 | ||
1784 | if (dev->vbi_dev) | ||
1785 | cap->capabilities |= V4L2_CAP_VBI_CAPTURE; | ||
1786 | |||
1477 | if (dev->audio_mode.has_audio) | 1787 | if (dev->audio_mode.has_audio) |
1478 | cap->capabilities |= V4L2_CAP_AUDIO; | 1788 | cap->capabilities |= V4L2_CAP_AUDIO; |
1479 | 1789 | ||
@@ -1541,6 +1851,45 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, | |||
1541 | return 0; | 1851 | return 0; |
1542 | } | 1852 | } |
1543 | 1853 | ||
1854 | /* RAW VBI ioctls */ | ||
1855 | |||
1856 | static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, | ||
1857 | struct v4l2_format *format) | ||
1858 | { | ||
1859 | format->fmt.vbi.samples_per_line = 720; | ||
1860 | format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
1861 | format->fmt.vbi.offset = 0; | ||
1862 | format->fmt.vbi.flags = 0; | ||
1863 | |||
1864 | /* Varies by video standard (NTSC, PAL, etc.) */ | ||
1865 | /* FIXME: hard-coded for NTSC support */ | ||
1866 | format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */ | ||
1867 | format->fmt.vbi.count[0] = 12; | ||
1868 | format->fmt.vbi.count[1] = 12; | ||
1869 | format->fmt.vbi.start[0] = 10; | ||
1870 | format->fmt.vbi.start[1] = 273; | ||
1871 | |||
1872 | return 0; | ||
1873 | } | ||
1874 | |||
1875 | static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, | ||
1876 | struct v4l2_format *format) | ||
1877 | { | ||
1878 | format->fmt.vbi.samples_per_line = 720; | ||
1879 | format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
1880 | format->fmt.vbi.offset = 0; | ||
1881 | format->fmt.vbi.flags = 0; | ||
1882 | |||
1883 | /* Varies by video standard (NTSC, PAL, etc.) */ | ||
1884 | /* FIXME: hard-coded for NTSC support */ | ||
1885 | format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */ | ||
1886 | format->fmt.vbi.count[0] = 12; | ||
1887 | format->fmt.vbi.count[1] = 12; | ||
1888 | format->fmt.vbi.start[0] = 10; | ||
1889 | format->fmt.vbi.start[1] = 273; | ||
1890 | |||
1891 | return 0; | ||
1892 | } | ||
1544 | 1893 | ||
1545 | static int vidioc_reqbufs(struct file *file, void *priv, | 1894 | static int vidioc_reqbufs(struct file *file, void *priv, |
1546 | struct v4l2_requestbuffers *rb) | 1895 | struct v4l2_requestbuffers *rb) |
@@ -1553,7 +1902,10 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
1553 | if (rc < 0) | 1902 | if (rc < 0) |
1554 | return rc; | 1903 | return rc; |
1555 | 1904 | ||
1556 | return videobuf_reqbufs(&fh->vb_vidq, rb); | 1905 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1906 | return videobuf_reqbufs(&fh->vb_vidq, rb); | ||
1907 | else | ||
1908 | return videobuf_reqbufs(&fh->vb_vbiq, rb); | ||
1557 | } | 1909 | } |
1558 | 1910 | ||
1559 | static int vidioc_querybuf(struct file *file, void *priv, | 1911 | static int vidioc_querybuf(struct file *file, void *priv, |
@@ -1567,7 +1919,18 @@ static int vidioc_querybuf(struct file *file, void *priv, | |||
1567 | if (rc < 0) | 1919 | if (rc < 0) |
1568 | return rc; | 1920 | return rc; |
1569 | 1921 | ||
1570 | return videobuf_querybuf(&fh->vb_vidq, b); | 1922 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1923 | return videobuf_querybuf(&fh->vb_vidq, b); | ||
1924 | else { | ||
1925 | /* FIXME: I'm not sure yet whether this is a bug in zvbi or | ||
1926 | the videobuf framework, but we probably shouldn't be | ||
1927 | returning a buffer larger than that which was asked for. | ||
1928 | At a minimum, it causes a crash in zvbi since it does | ||
1929 | a memcpy based on the source buffer length */ | ||
1930 | int result = videobuf_querybuf(&fh->vb_vbiq, b); | ||
1931 | b->length = 17280; | ||
1932 | return result; | ||
1933 | } | ||
1571 | } | 1934 | } |
1572 | 1935 | ||
1573 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 1936 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
@@ -1580,7 +1943,10 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | |||
1580 | if (rc < 0) | 1943 | if (rc < 0) |
1581 | return rc; | 1944 | return rc; |
1582 | 1945 | ||
1583 | return videobuf_qbuf(&fh->vb_vidq, b); | 1946 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1947 | return videobuf_qbuf(&fh->vb_vidq, b); | ||
1948 | else | ||
1949 | return videobuf_qbuf(&fh->vb_vbiq, b); | ||
1584 | } | 1950 | } |
1585 | 1951 | ||
1586 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 1952 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
@@ -1593,7 +1959,12 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | |||
1593 | if (rc < 0) | 1959 | if (rc < 0) |
1594 | return rc; | 1960 | return rc; |
1595 | 1961 | ||
1596 | return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); | 1962 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1963 | return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & | ||
1964 | O_NONBLOCK); | ||
1965 | else | ||
1966 | return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & | ||
1967 | O_NONBLOCK); | ||
1597 | } | 1968 | } |
1598 | 1969 | ||
1599 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1970 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
@@ -1601,7 +1972,10 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) | |||
1601 | { | 1972 | { |
1602 | struct em28xx_fh *fh = priv; | 1973 | struct em28xx_fh *fh = priv; |
1603 | 1974 | ||
1604 | return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); | 1975 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1976 | return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); | ||
1977 | else | ||
1978 | return videobuf_cgmbuf(&fh->vb_vbiq, mbuf, 8); | ||
1605 | } | 1979 | } |
1606 | #endif | 1980 | #endif |
1607 | 1981 | ||
@@ -1766,8 +2140,15 @@ static int em28xx_v4l2_open(struct file *filp) | |||
1766 | field = V4L2_FIELD_INTERLACED; | 2140 | field = V4L2_FIELD_INTERLACED; |
1767 | 2141 | ||
1768 | videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, | 2142 | videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, |
1769 | NULL, &dev->slock, fh->type, field, | 2143 | NULL, &dev->slock, |
1770 | sizeof(struct em28xx_buffer), fh); | 2144 | V4L2_BUF_TYPE_VIDEO_CAPTURE, field, |
2145 | sizeof(struct em28xx_buffer), fh); | ||
2146 | |||
2147 | videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops, | ||
2148 | NULL, &dev->slock, | ||
2149 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
2150 | V4L2_FIELD_SEQ_TB, | ||
2151 | sizeof(struct em28xx_buffer), fh); | ||
1771 | 2152 | ||
1772 | mutex_unlock(&dev->lock); | 2153 | mutex_unlock(&dev->lock); |
1773 | 2154 | ||
@@ -1824,20 +2205,21 @@ static int em28xx_v4l2_close(struct file *filp) | |||
1824 | 2205 | ||
1825 | em28xx_videodbg("users=%d\n", dev->users); | 2206 | em28xx_videodbg("users=%d\n", dev->users); |
1826 | 2207 | ||
2208 | if (res_check(fh, EM28XX_RESOURCE_VIDEO)) { | ||
2209 | videobuf_stop(&fh->vb_vidq); | ||
2210 | res_free(fh, EM28XX_RESOURCE_VIDEO); | ||
2211 | } | ||
1827 | 2212 | ||
1828 | mutex_lock(&dev->lock); | 2213 | if (res_check(fh, EM28XX_RESOURCE_VBI)) { |
1829 | if (res_check(fh)) | 2214 | videobuf_stop(&fh->vb_vbiq); |
1830 | res_free(fh); | 2215 | res_free(fh, EM28XX_RESOURCE_VBI); |
2216 | } | ||
1831 | 2217 | ||
1832 | if (dev->users == 1) { | 2218 | if (dev->users == 1) { |
1833 | videobuf_stop(&fh->vb_vidq); | ||
1834 | videobuf_mmap_free(&fh->vb_vidq); | ||
1835 | |||
1836 | /* the device is already disconnect, | 2219 | /* the device is already disconnect, |
1837 | free the remaining resources */ | 2220 | free the remaining resources */ |
1838 | if (dev->state & DEV_DISCONNECTED) { | 2221 | if (dev->state & DEV_DISCONNECTED) { |
1839 | em28xx_release_resources(dev); | 2222 | em28xx_release_resources(dev); |
1840 | mutex_unlock(&dev->lock); | ||
1841 | kfree(dev); | 2223 | kfree(dev); |
1842 | return 0; | 2224 | return 0; |
1843 | } | 2225 | } |
@@ -1858,10 +2240,12 @@ static int em28xx_v4l2_close(struct file *filp) | |||
1858 | "0 (error=%i)\n", errCode); | 2240 | "0 (error=%i)\n", errCode); |
1859 | } | 2241 | } |
1860 | } | 2242 | } |
2243 | |||
2244 | videobuf_mmap_free(&fh->vb_vidq); | ||
2245 | videobuf_mmap_free(&fh->vb_vbiq); | ||
1861 | kfree(fh); | 2246 | kfree(fh); |
1862 | dev->users--; | 2247 | dev->users--; |
1863 | wake_up_interruptible_nr(&dev->open, 1); | 2248 | wake_up_interruptible_nr(&dev->open, 1); |
1864 | mutex_unlock(&dev->lock); | ||
1865 | return 0; | 2249 | return 0; |
1866 | } | 2250 | } |
1867 | 2251 | ||
@@ -1886,16 +2270,22 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, | |||
1886 | */ | 2270 | */ |
1887 | 2271 | ||
1888 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 2272 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
1889 | mutex_lock(&dev->lock); | 2273 | if (res_locked(dev, EM28XX_RESOURCE_VIDEO)) |
1890 | rc = res_get(fh); | 2274 | return -EBUSY; |
1891 | mutex_unlock(&dev->lock); | ||
1892 | |||
1893 | if (unlikely(rc < 0)) | ||
1894 | return rc; | ||
1895 | 2275 | ||
1896 | return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, | 2276 | return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, |
1897 | filp->f_flags & O_NONBLOCK); | 2277 | filp->f_flags & O_NONBLOCK); |
1898 | } | 2278 | } |
2279 | |||
2280 | |||
2281 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | ||
2282 | if (!res_get(fh, EM28XX_RESOURCE_VBI)) | ||
2283 | return -EBUSY; | ||
2284 | |||
2285 | return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, | ||
2286 | filp->f_flags & O_NONBLOCK); | ||
2287 | } | ||
2288 | |||
1899 | return 0; | 2289 | return 0; |
1900 | } | 2290 | } |
1901 | 2291 | ||
@@ -1913,17 +2303,17 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait) | |||
1913 | if (rc < 0) | 2303 | if (rc < 0) |
1914 | return rc; | 2304 | return rc; |
1915 | 2305 | ||
1916 | mutex_lock(&dev->lock); | 2306 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
1917 | rc = res_get(fh); | 2307 | if (!res_get(fh, EM28XX_RESOURCE_VIDEO)) |
1918 | mutex_unlock(&dev->lock); | 2308 | return POLLERR; |
1919 | 2309 | return videobuf_poll_stream(filp, &fh->vb_vidq, wait); | |
1920 | if (unlikely(rc < 0)) | 2310 | } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
1921 | return POLLERR; | 2311 | if (!res_get(fh, EM28XX_RESOURCE_VBI)) |
1922 | 2312 | return POLLERR; | |
1923 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) | 2313 | return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); |
2314 | } else { | ||
1924 | return POLLERR; | 2315 | return POLLERR; |
1925 | 2316 | } | |
1926 | return videobuf_poll_stream(filp, &fh->vb_vidq, wait); | ||
1927 | } | 2317 | } |
1928 | 2318 | ||
1929 | /* | 2319 | /* |
@@ -1939,14 +2329,10 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
1939 | if (rc < 0) | 2329 | if (rc < 0) |
1940 | return rc; | 2330 | return rc; |
1941 | 2331 | ||
1942 | mutex_lock(&dev->lock); | 2332 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1943 | rc = res_get(fh); | 2333 | rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); |
1944 | mutex_unlock(&dev->lock); | 2334 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
1945 | 2335 | rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma); | |
1946 | if (unlikely(rc < 0)) | ||
1947 | return rc; | ||
1948 | |||
1949 | rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); | ||
1950 | 2336 | ||
1951 | em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", | 2337 | em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", |
1952 | (unsigned long)vma->vm_start, | 2338 | (unsigned long)vma->vm_start, |
@@ -1972,6 +2358,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1972 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | 2358 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, |
1973 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | 2359 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, |
1974 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | 2360 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, |
2361 | .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, | ||
2362 | .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, | ||
1975 | .vidioc_g_audio = vidioc_g_audio, | 2363 | .vidioc_g_audio = vidioc_g_audio, |
1976 | .vidioc_s_audio = vidioc_s_audio, | 2364 | .vidioc_s_audio = vidioc_s_audio, |
1977 | .vidioc_cropcap = vidioc_cropcap, | 2365 | .vidioc_cropcap = vidioc_cropcap, |
@@ -1984,6 +2372,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1984 | .vidioc_querybuf = vidioc_querybuf, | 2372 | .vidioc_querybuf = vidioc_querybuf, |
1985 | .vidioc_qbuf = vidioc_qbuf, | 2373 | .vidioc_qbuf = vidioc_qbuf, |
1986 | .vidioc_dqbuf = vidioc_dqbuf, | 2374 | .vidioc_dqbuf = vidioc_dqbuf, |
2375 | .vidioc_g_std = vidioc_g_std, | ||
1987 | .vidioc_s_std = vidioc_s_std, | 2376 | .vidioc_s_std = vidioc_s_std, |
1988 | .vidioc_g_parm = vidioc_g_parm, | 2377 | .vidioc_g_parm = vidioc_g_parm, |
1989 | .vidioc_s_parm = vidioc_s_parm, | 2378 | .vidioc_s_parm = vidioc_s_parm, |
@@ -2105,13 +2494,10 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
2105 | dev->mute = 1; | 2494 | dev->mute = 1; |
2106 | dev->volume = 0x1f; | 2495 | dev->volume = 0x1f; |
2107 | 2496 | ||
2108 | /* enable vbi capturing */ | ||
2109 | |||
2110 | /* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ | 2497 | /* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ |
2111 | val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK); | 2498 | val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK); |
2112 | em28xx_write_reg(dev, EM28XX_R0F_XCLK, | 2499 | em28xx_write_reg(dev, EM28XX_R0F_XCLK, |
2113 | (EM28XX_XCLK_AUDIO_UNMUTE | val)); | 2500 | (EM28XX_XCLK_AUDIO_UNMUTE | val)); |
2114 | em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51); | ||
2115 | 2501 | ||
2116 | em28xx_set_outfmt(dev); | 2502 | em28xx_set_outfmt(dev); |
2117 | em28xx_colorlevels_set_default(dev); | 2503 | em28xx_colorlevels_set_default(dev); |
@@ -2134,14 +2520,17 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
2134 | } | 2520 | } |
2135 | 2521 | ||
2136 | /* Allocate and fill vbi video_device struct */ | 2522 | /* Allocate and fill vbi video_device struct */ |
2137 | dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); | 2523 | if (em28xx_vbi_supported(dev) == 1) { |
2524 | dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, | ||
2525 | "vbi"); | ||
2138 | 2526 | ||
2139 | /* register v4l2 vbi video_device */ | 2527 | /* register v4l2 vbi video_device */ |
2140 | ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, | 2528 | ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, |
2141 | vbi_nr[dev->devno]); | 2529 | vbi_nr[dev->devno]); |
2142 | if (ret < 0) { | 2530 | if (ret < 0) { |
2143 | em28xx_errdev("unable to register vbi device\n"); | 2531 | em28xx_errdev("unable to register vbi device\n"); |
2144 | return ret; | 2532 | return ret; |
2533 | } | ||
2145 | } | 2534 | } |
2146 | 2535 | ||
2147 | if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { | 2536 | if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { |
@@ -2161,8 +2550,12 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
2161 | dev->radio_dev->num); | 2550 | dev->radio_dev->num); |
2162 | } | 2551 | } |
2163 | 2552 | ||
2164 | em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", | 2553 | em28xx_info("V4L2 video device registered as /dev/video%d\n", |
2165 | dev->vdev->num, dev->vbi_dev->num); | 2554 | dev->vdev->num); |
2555 | |||
2556 | if (dev->vbi_dev) | ||
2557 | em28xx_info("V4L2 VBI device registered as /dev/vbi%d\n", | ||
2558 | dev->vbi_dev->num); | ||
2166 | 2559 | ||
2167 | return 0; | 2560 | return 0; |
2168 | } | 2561 | } |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 0f2ba9a40d17..0a73e8bf0d6e 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -109,6 +109,7 @@ | |||
109 | #define EM2882_BOARD_EVGA_INDTUBE 70 | 109 | #define EM2882_BOARD_EVGA_INDTUBE 70 |
110 | #define EM2820_BOARD_SILVERCREST_WEBCAM 71 | 110 | #define EM2820_BOARD_SILVERCREST_WEBCAM 71 |
111 | #define EM2861_BOARD_GADMEI_UTV330PLUS 72 | 111 | #define EM2861_BOARD_GADMEI_UTV330PLUS 72 |
112 | #define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73 | ||
112 | 113 | ||
113 | /* Limits minimum and default number of buffers */ | 114 | /* Limits minimum and default number of buffers */ |
114 | #define EM28XX_MIN_BUF 4 | 115 | #define EM28XX_MIN_BUF 4 |
@@ -214,7 +215,8 @@ struct em28xx_usb_isoc_ctl { | |||
214 | int tmp_buf_len; | 215 | int tmp_buf_len; |
215 | 216 | ||
216 | /* Stores already requested buffers */ | 217 | /* Stores already requested buffers */ |
217 | struct em28xx_buffer *buf; | 218 | struct em28xx_buffer *vid_buf; |
219 | struct em28xx_buffer *vbi_buf; | ||
218 | 220 | ||
219 | /* Stores the number of received fields */ | 221 | /* Stores the number of received fields */ |
220 | int nfields; | 222 | int nfields; |
@@ -443,6 +445,10 @@ enum em28xx_dev_state { | |||
443 | #define EM28XX_AUDIO 0x10 | 445 | #define EM28XX_AUDIO 0x10 |
444 | #define EM28XX_DVB 0x20 | 446 | #define EM28XX_DVB 0x20 |
445 | 447 | ||
448 | /* em28xx resource types (used for res_get/res_lock etc */ | ||
449 | #define EM28XX_RESOURCE_VIDEO 0x01 | ||
450 | #define EM28XX_RESOURCE_VBI 0x02 | ||
451 | |||
446 | struct em28xx_audio { | 452 | struct em28xx_audio { |
447 | char name[50]; | 453 | char name[50]; |
448 | char *transfer_buffer[EM28XX_AUDIO_BUFS]; | 454 | char *transfer_buffer[EM28XX_AUDIO_BUFS]; |
@@ -463,10 +469,11 @@ struct em28xx; | |||
463 | 469 | ||
464 | struct em28xx_fh { | 470 | struct em28xx_fh { |
465 | struct em28xx *dev; | 471 | struct em28xx *dev; |
466 | unsigned int stream_on:1; /* Locks streams */ | ||
467 | int radio; | 472 | int radio; |
473 | unsigned int resources; | ||
468 | 474 | ||
469 | struct videobuf_queue vb_vidq; | 475 | struct videobuf_queue vb_vidq; |
476 | struct videobuf_queue vb_vbiq; | ||
470 | 477 | ||
471 | enum v4l2_buf_type type; | 478 | enum v4l2_buf_type type; |
472 | }; | 479 | }; |
@@ -493,7 +500,6 @@ struct em28xx { | |||
493 | /* Vinmode/Vinctl used at the driver */ | 500 | /* Vinmode/Vinctl used at the driver */ |
494 | int vinmode, vinctl; | 501 | int vinmode, vinctl; |
495 | 502 | ||
496 | unsigned int stream_on:1; /* Locks streams */ | ||
497 | unsigned int has_audio_class:1; | 503 | unsigned int has_audio_class:1; |
498 | unsigned int has_alsa_audio:1; | 504 | unsigned int has_alsa_audio:1; |
499 | 505 | ||
@@ -544,6 +550,12 @@ struct em28xx { | |||
544 | enum em28xx_dev_state state; | 550 | enum em28xx_dev_state state; |
545 | enum em28xx_io_method io; | 551 | enum em28xx_io_method io; |
546 | 552 | ||
553 | /* vbi related state tracking */ | ||
554 | int capture_type; | ||
555 | int vbi_read; | ||
556 | unsigned char cur_field; | ||
557 | |||
558 | |||
547 | struct work_struct request_module_wk; | 559 | struct work_struct request_module_wk; |
548 | 560 | ||
549 | /* locks */ | 561 | /* locks */ |
@@ -555,10 +567,14 @@ struct em28xx { | |||
555 | struct video_device *vbi_dev; | 567 | struct video_device *vbi_dev; |
556 | struct video_device *radio_dev; | 568 | struct video_device *radio_dev; |
557 | 569 | ||
570 | /* resources in use */ | ||
571 | unsigned int resources; | ||
572 | |||
558 | unsigned char eedata[256]; | 573 | unsigned char eedata[256]; |
559 | 574 | ||
560 | /* Isoc control struct */ | 575 | /* Isoc control struct */ |
561 | struct em28xx_dmaqueue vidq; | 576 | struct em28xx_dmaqueue vidq; |
577 | struct em28xx_dmaqueue vbiq; | ||
562 | struct em28xx_usb_isoc_ctl isoc_ctl; | 578 | struct em28xx_usb_isoc_ctl isoc_ctl; |
563 | spinlock_t slock; | 579 | spinlock_t slock; |
564 | 580 | ||
@@ -639,6 +655,7 @@ int em28xx_audio_setup(struct em28xx *dev); | |||
639 | 655 | ||
640 | int em28xx_colorlevels_set_default(struct em28xx *dev); | 656 | int em28xx_colorlevels_set_default(struct em28xx *dev); |
641 | int em28xx_capture_start(struct em28xx *dev, int start); | 657 | int em28xx_capture_start(struct em28xx *dev, int start); |
658 | int em28xx_vbi_supported(struct em28xx *dev); | ||
642 | int em28xx_set_outfmt(struct em28xx *dev); | 659 | int em28xx_set_outfmt(struct em28xx *dev); |
643 | int em28xx_resolution_set(struct em28xx *dev); | 660 | int em28xx_resolution_set(struct em28xx *dev); |
644 | int em28xx_set_alternate(struct em28xx *dev); | 661 | int em28xx_set_alternate(struct em28xx *dev); |
@@ -686,6 +703,9 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev); | |||
686 | int em28xx_ir_init(struct em28xx *dev); | 703 | int em28xx_ir_init(struct em28xx *dev); |
687 | int em28xx_ir_fini(struct em28xx *dev); | 704 | int em28xx_ir_fini(struct em28xx *dev); |
688 | 705 | ||
706 | /* Provided by em28xx-vbi.c */ | ||
707 | extern struct videobuf_queue_ops em28xx_vbi_qops; | ||
708 | |||
689 | /* printk macros */ | 709 | /* printk macros */ |
690 | 710 | ||
691 | #define em28xx_err(fmt, arg...) do {\ | 711 | #define em28xx_err(fmt, arg...) do {\ |
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index d1c1e457f0b9..74092f436be6 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c | |||
@@ -1379,8 +1379,10 @@ et61x251_read(struct file* filp, char __user * buf, | |||
1379 | (!list_empty(&cam->outqueue)) || | 1379 | (!list_empty(&cam->outqueue)) || |
1380 | (cam->state & DEV_DISCONNECTED) || | 1380 | (cam->state & DEV_DISCONNECTED) || |
1381 | (cam->state & DEV_MISCONFIGURED), | 1381 | (cam->state & DEV_MISCONFIGURED), |
1382 | cam->module_param.frame_timeout * | 1382 | msecs_to_jiffies( |
1383 | 1000 * msecs_to_jiffies(1) ); | 1383 | cam->module_param.frame_timeout * 1000 |
1384 | ) | ||
1385 | ); | ||
1384 | if (timeout < 0) { | 1386 | if (timeout < 0) { |
1385 | mutex_unlock(&cam->fileop_mutex); | 1387 | mutex_unlock(&cam->fileop_mutex); |
1386 | return timeout; | 1388 | return timeout; |
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 8897283b0bb4..fe2e490ebc52 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig | |||
@@ -19,6 +19,7 @@ if USB_GSPCA && VIDEO_V4L2 | |||
19 | 19 | ||
20 | source "drivers/media/video/gspca/m5602/Kconfig" | 20 | source "drivers/media/video/gspca/m5602/Kconfig" |
21 | source "drivers/media/video/gspca/stv06xx/Kconfig" | 21 | source "drivers/media/video/gspca/stv06xx/Kconfig" |
22 | source "drivers/media/video/gspca/gl860/Kconfig" | ||
22 | 23 | ||
23 | config USB_GSPCA_CONEX | 24 | config USB_GSPCA_CONEX |
24 | tristate "Conexant Camera Driver" | 25 | tristate "Conexant Camera Driver" |
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 035616b5e867..b7420818037e 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile | |||
@@ -58,3 +58,4 @@ gspca_zc3xx-objs := zc3xx.o | |||
58 | 58 | ||
59 | obj-$(CONFIG_USB_M5602) += m5602/ | 59 | obj-$(CONFIG_USB_M5602) += m5602/ |
60 | obj-$(CONFIG_USB_STV06XX) += stv06xx/ | 60 | obj-$(CONFIG_USB_STV06XX) += stv06xx/ |
61 | obj-$(CONFIG_USB_GL860) += gl860/ | ||
diff --git a/drivers/media/video/gspca/gl860/Kconfig b/drivers/media/video/gspca/gl860/Kconfig new file mode 100644 index 000000000000..22772f53ec7b --- /dev/null +++ b/drivers/media/video/gspca/gl860/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | config USB_GL860 | ||
2 | tristate "GL860 USB Camera Driver" | ||
3 | depends on VIDEO_V4L2 && USB_GSPCA | ||
4 | help | ||
5 | Say Y here if you want support for cameras based on the GL860 chip. | ||
6 | |||
7 | To compile this driver as a module, choose M here: the | ||
8 | module will be called gspca_gl860. | ||
diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile new file mode 100644 index 000000000000..13c9403cc87d --- /dev/null +++ b/drivers/media/video/gspca/gl860/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | obj-$(CONFIG_USB_GL860) += gspca_gl860.o | ||
2 | |||
3 | gspca_gl860-objs := gl860.o \ | ||
4 | gl860-mi1320.o \ | ||
5 | gl860-ov2640.o \ | ||
6 | gl860-ov9655.o \ | ||
7 | gl860-mi2020.o | ||
8 | |||
9 | EXTRA_CFLAGS += -Idrivers/media/video/gspca | ||
10 | |||
diff --git a/drivers/media/video/gspca/gl860/gl860-mi1320.c b/drivers/media/video/gspca/gl860/gl860-mi1320.c new file mode 100644 index 000000000000..39f6261c1a0c --- /dev/null +++ b/drivers/media/video/gspca/gl860/gl860-mi1320.c | |||
@@ -0,0 +1,537 @@ | |||
1 | /* @file gl860-mi1320.c | ||
2 | * @author Olivier LORIN from my logs | ||
3 | * @date 2009-08-27 | ||
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 | * any later version. | ||
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, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /* Sensor : MI1320 */ | ||
20 | |||
21 | #include "gl860.h" | ||
22 | |||
23 | static struct validx tbl_common[] = { | ||
24 | {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba51, 0x0066}, {0xba02, 0x00f1}, | ||
25 | {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, | ||
26 | {0xffff, 0xffff}, | ||
27 | {0xba00, 0x00f0}, {0xba02, 0x00f1}, {0xbafa, 0x0028}, {0xba02, 0x00f1}, | ||
28 | {0xba00, 0x00f0}, {0xba01, 0x00f1}, {0xbaf0, 0x0006}, {0xba0e, 0x00f1}, | ||
29 | {0xba70, 0x0006}, {0xba0e, 0x00f1}, | ||
30 | {0xffff, 0xffff}, | ||
31 | {0xba74, 0x0006}, {0xba0e, 0x00f1}, | ||
32 | {0xffff, 0xffff}, | ||
33 | {0x0061, 0x0000}, {0x0068, 0x000d}, | ||
34 | }; | ||
35 | |||
36 | static struct validx tbl_init_at_startup[] = { | ||
37 | {0x0000, 0x0000}, {0x0010, 0x0010}, | ||
38 | {35, 0xffff}, | ||
39 | {0x0008, 0x00c0}, {0x0001, 0x00c1}, {0x0001, 0x00c2}, {0x0020, 0x0006}, | ||
40 | {0x006a, 0x000d}, | ||
41 | }; | ||
42 | |||
43 | static struct validx tbl_sensor_settings_common[] = { | ||
44 | {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0040, 0x0000}, | ||
45 | {0x006a, 0x0007}, {0x006a, 0x000d}, {0x0063, 0x0006}, | ||
46 | }; | ||
47 | static struct validx tbl_sensor_settings_1280[] = { | ||
48 | {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1}, | ||
49 | {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1}, | ||
50 | }; | ||
51 | static struct validx tbl_sensor_settings_800[] = { | ||
52 | {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1}, | ||
53 | {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1}, | ||
54 | }; | ||
55 | static struct validx tbl_sensor_settings_640[] = { | ||
56 | {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, | ||
57 | {0xba51, 0x0066}, {0xba02, 0x00f1}, {0xba05, 0x0067}, {0xba05, 0x00f1}, | ||
58 | {0xba20, 0x0065}, {0xba00, 0x00f1}, | ||
59 | }; | ||
60 | static struct validx tbl_post_unset_alt[] = { | ||
61 | {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, | ||
62 | {0x0061, 0x0000}, {0x0068, 0x000d}, | ||
63 | }; | ||
64 | |||
65 | static u8 *tbl_1280[] = { | ||
66 | "\x0d\x80\xf1\x08\x03\x04\xf1\x00" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" | ||
67 | "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" | ||
68 | "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" | ||
69 | "\xa9\x04\xf1\x00\xa1\x05\xf1\x00" "\xa4\x04\xf1\x00\xae\x0a\xf1\x08" | ||
70 | , | ||
71 | "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" | ||
72 | "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" | ||
73 | "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" | ||
74 | , | ||
75 | "\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1" | ||
76 | }; | ||
77 | |||
78 | static u8 *tbl_800[] = { | ||
79 | "\x0d\x80\xf1\x08\x03\x03\xf1\xc0" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" | ||
80 | "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" | ||
81 | "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" | ||
82 | "\xa9\x03\xf1\xc0\xa1\x03\xf1\x20" "\xa4\x02\xf1\x5a\xae\x0a\xf1\x08" | ||
83 | , | ||
84 | "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" | ||
85 | "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" | ||
86 | "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" | ||
87 | , | ||
88 | "\xd3\x02\xd4\x18\xd5\x21\xd0\x02" "\xd1\x10\xd2\x59" | ||
89 | }; | ||
90 | |||
91 | static u8 *tbl_640[] = { | ||
92 | "\x0d\x80\xf1\x08\x03\x04\xf1\x04" "\x04\x05\xf1\x02\x07\x01\xf1\x7c" | ||
93 | "\x08\x00\xf1\x0e\x21\x80\xf1\x00" "\x0d\x00\xf1\x08\xf0\x00\xf1\x01" | ||
94 | "\x34\x10\xf1\x10\x3a\x43\xf1\x00" "\xa6\x05\xf1\x02\xa9\x04\xf1\x04" | ||
95 | "\xa7\x02\xf1\x81\xaa\x01\xf1\xe2" "\xae\x0c\xf1\x09" | ||
96 | , | ||
97 | "\xf0\x00\xf1\x02\x39\x03\xf1\xfc" "\x3b\x04\xf1\x04\x57\x01\xf1\xb6" | ||
98 | "\x58\x02\xf1\x0d\x5c\x1f\xf1\x19" "\x5d\x24\xf1\x1e\x64\x5e\xf1\x1c" | ||
99 | "\xd2\x00\xf1\x00\xcb\x00\xf1\x01" | ||
100 | , | ||
101 | "\xd3\x02\xd4\x10\xd5\x81\xd0\x02" "\xd1\x08\xd2\xe1" | ||
102 | }; | ||
103 | |||
104 | static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d}; | ||
105 | static s32 tbl_bright[] = {0, 8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70}; | ||
106 | static s32 tbl_backlight[] = {0x0e, 0x06, 0x02}; | ||
107 | |||
108 | static s32 tbl_cntr1[] = { | ||
109 | 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xe0, 0xf0}; | ||
110 | static s32 tbl_cntr2[] = { | ||
111 | 0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40, 0x38, 0x30, 0x20, 0x10}; | ||
112 | |||
113 | static u8 dat_wbalNL[] = | ||
114 | "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x3b\x04\xf1\x2a\x47\x10\xf1\x10" | ||
115 | "\x9d\x3c\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\x91\xf1\x20" | ||
116 | "\x9c\x91\xf1\x20\x37\x03\xf1\x00" "\x9d\xc5\xf1\x0f\xf0\x00\xf1\x00"; | ||
117 | |||
118 | static u8 dat_wbalLL[] = | ||
119 | "\xf0\x00\xf1\x01\x05\x00\xf1\x0c" "\x3b\x04\xf1\x2a\x47\x40\xf1\x40" | ||
120 | "\x9d\x20\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\xd1\xf1\x00" | ||
121 | "\x9c\xd1\xf1\x00\x37\x03\xf1\x00" "\x9d\xc5\xf1\x3f\xf0\x00\xf1\x00"; | ||
122 | |||
123 | static u8 dat_wbalBL[] = | ||
124 | "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x47\x10\xf1\x30\x9d\x3c\xf1\xae" | ||
125 | "\xaf\x10\xf1\x00\xf0\x00\xf1\x02" "\x2f\x91\xf1\x20\x9c\x91\xf1\x20" | ||
126 | "\x37\x03\xf1\x00\x9d\xc5\xf1\x2f" "\xf0\x00\xf1\x00"; | ||
127 | |||
128 | static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00}; | ||
129 | |||
130 | static u8 s000[] = | ||
131 | "\x00\x01\x07\x6a\x06\x63\x0d\x6a" "\xc0\x00\x10\x10\xc1\x03\xc2\x42" | ||
132 | "\xd8\x04\x58\x00\x04\x02"; | ||
133 | static u8 s001[] = | ||
134 | "\x0d\x00\xf1\x0b\x0d\x00\xf1\x08" "\x35\x00\xf1\x22\x68\x00\xf1\x5d" | ||
135 | "\xf0\x00\xf1\x01\x06\x70\xf1\x0e" "\xf0\x00\xf1\x02\xdd\x18\xf1\xe0"; | ||
136 | static u8 s002[] = | ||
137 | "\x05\x01\xf1\x84\x06\x00\xf1\x44" "\x07\x00\xf1\xbe\x08\x00\xf1\x1e" | ||
138 | "\x20\x01\xf1\x03\x21\x84\xf1\x00" "\x22\x0d\xf1\x0f\x24\x80\xf1\x00" | ||
139 | "\x34\x18\xf1\x2d\x35\x00\xf1\x22" "\x43\x83\xf1\x83\x59\x00\xf1\xff"; | ||
140 | static u8 s003[] = | ||
141 | "\xf0\x00\xf1\x02\x39\x06\xf1\x8c" "\x3a\x06\xf1\x8c\x3b\x03\xf1\xda" | ||
142 | "\x3c\x05\xf1\x30\x57\x01\xf1\x0c" "\x58\x01\xf1\x42\x59\x01\xf1\x0c" | ||
143 | "\x5a\x01\xf1\x42\x5c\x13\xf1\x0e" "\x5d\x17\xf1\x12\x64\x1e\xf1\x1c"; | ||
144 | static u8 s004[] = | ||
145 | "\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43"; | ||
146 | static u8 s005[] = | ||
147 | "\x02\x00\xf1\xee\x03\x29\xf1\x1a" "\x04\x02\xf1\xa4\x09\x00\xf1\x68" | ||
148 | "\x0a\x00\xf1\x2a\x0b\x00\xf1\x04" "\x0c\x00\xf1\x93\x0d\x00\xf1\x82" | ||
149 | "\x0e\x00\xf1\x40\x0f\x00\xf1\x5f" "\x10\x00\xf1\x4e\x11\x00\xf1\x5b"; | ||
150 | static u8 s006[] = | ||
151 | "\x15\x00\xf1\xc9\x16\x00\xf1\x5e" "\x17\x00\xf1\x9d\x18\x00\xf1\x06" | ||
152 | "\x19\x00\xf1\x89\x1a\x00\xf1\x12" "\x1b\x00\xf1\xa1\x1c\x00\xf1\xe4" | ||
153 | "\x1d\x00\xf1\x7a\x1e\x00\xf1\x64" "\xf6\x00\xf1\x5f"; | ||
154 | static u8 s007[] = | ||
155 | "\xf0\x00\xf1\x01\x53\x09\xf1\x03" "\x54\x3d\xf1\x1c\x55\x99\xf1\x72" | ||
156 | "\x56\xc1\xf1\xb1\x57\xd8\xf1\xce" "\x58\xe0\xf1\x00\xdc\x0a\xf1\x03" | ||
157 | "\xdd\x45\xf1\x20\xde\xae\xf1\x82" "\xdf\xdc\xf1\xc9\xe0\xf6\xf1\xea" | ||
158 | "\xe1\xff\xf1\x00"; | ||
159 | static u8 s008[] = | ||
160 | "\xf0\x00\xf1\x01\x80\x00\xf1\x06" "\x81\xf6\xf1\x08\x82\xfb\xf1\xf7" | ||
161 | "\x83\x00\xf1\xfe\xb6\x07\xf1\x03" "\xb7\x18\xf1\x0c\x84\xfb\xf1\x06" | ||
162 | "\x85\xfb\xf1\xf9\x86\x00\xf1\xff" "\xb8\x07\xf1\x04\xb9\x16\xf1\x0a"; | ||
163 | static u8 s009[] = | ||
164 | "\x87\xfa\xf1\x05\x88\xfc\xf1\xf9" "\x89\x00\xf1\xff\xba\x06\xf1\x03" | ||
165 | "\xbb\x17\xf1\x09\x8a\xe8\xf1\x14" "\x8b\xf7\xf1\xf0\x8c\xfd\xf1\xfa" | ||
166 | "\x8d\x00\xf1\x00\xbc\x05\xf1\x01" "\xbd\x0c\xf1\x08\xbe\x00\xf1\x14"; | ||
167 | static u8 s010[] = | ||
168 | "\x8e\xea\xf1\x13\x8f\xf7\xf1\xf2" "\x90\xfd\xf1\xfa\x91\x00\xf1\x00" | ||
169 | "\xbf\x05\xf1\x01\xc0\x0a\xf1\x08" "\xc1\x00\xf1\x0c\x92\xed\xf1\x0f" | ||
170 | "\x93\xf9\xf1\xf4\x94\xfe\xf1\xfb" "\x95\x00\xf1\x00\xc2\x04\xf1\x01" | ||
171 | "\xc3\x0a\xf1\x07\xc4\x00\xf1\x10"; | ||
172 | static u8 s011[] = | ||
173 | "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x25\x00\xf1\x55\x34\x10\xf1\x10" | ||
174 | "\x35\xf0\xf1\x10\x3a\x02\xf1\x03" "\x3b\x04\xf1\x2a\x9b\x43\xf1\x00" | ||
175 | "\xa4\x03\xf1\xc0\xa7\x02\xf1\x81"; | ||
176 | |||
177 | static int mi1320_init_at_startup(struct gspca_dev *gspca_dev); | ||
178 | static int mi1320_configure_alt(struct gspca_dev *gspca_dev); | ||
179 | static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev); | ||
180 | static int mi1320_init_post_alt(struct gspca_dev *gspca_dev); | ||
181 | static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev); | ||
182 | static int mi1320_sensor_settings(struct gspca_dev *gspca_dev); | ||
183 | static int mi1320_camera_settings(struct gspca_dev *gspca_dev); | ||
184 | /*==========================================================================*/ | ||
185 | |||
186 | void mi1320_init_settings(struct gspca_dev *gspca_dev) | ||
187 | { | ||
188 | struct sd *sd = (struct sd *) gspca_dev; | ||
189 | |||
190 | sd->vcur.backlight = 0; | ||
191 | sd->vcur.brightness = 0; | ||
192 | sd->vcur.sharpness = 6; | ||
193 | sd->vcur.contrast = 10; | ||
194 | sd->vcur.gamma = 20; | ||
195 | sd->vcur.hue = 0; | ||
196 | sd->vcur.saturation = 6; | ||
197 | sd->vcur.whitebal = 0; | ||
198 | sd->vcur.mirror = 0; | ||
199 | sd->vcur.flip = 0; | ||
200 | sd->vcur.AC50Hz = 1; | ||
201 | |||
202 | sd->vmax.backlight = 2; | ||
203 | sd->vmax.brightness = 8; | ||
204 | sd->vmax.sharpness = 7; | ||
205 | sd->vmax.contrast = 0; /* 10 but not working with tihs driver */ | ||
206 | sd->vmax.gamma = 40; | ||
207 | sd->vmax.hue = 5 + 1; | ||
208 | sd->vmax.saturation = 8; | ||
209 | sd->vmax.whitebal = 2; | ||
210 | sd->vmax.mirror = 1; | ||
211 | sd->vmax.flip = 1; | ||
212 | sd->vmax.AC50Hz = 1; | ||
213 | |||
214 | sd->dev_camera_settings = mi1320_camera_settings; | ||
215 | sd->dev_init_at_startup = mi1320_init_at_startup; | ||
216 | sd->dev_configure_alt = mi1320_configure_alt; | ||
217 | sd->dev_init_pre_alt = mi1320_init_pre_alt; | ||
218 | sd->dev_post_unset_alt = mi1320_post_unset_alt; | ||
219 | } | ||
220 | |||
221 | /*==========================================================================*/ | ||
222 | |||
223 | static void common(struct gspca_dev *gspca_dev) | ||
224 | { | ||
225 | s32 n; /* reserved for FETCH macros */ | ||
226 | |||
227 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, s000); | ||
228 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); | ||
229 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, s001); | ||
230 | n = fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common)); | ||
231 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s002); | ||
232 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s003); | ||
233 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, s004); | ||
234 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s005); | ||
235 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, s006); | ||
236 | keep_on_fetching_validx(gspca_dev, tbl_common, | ||
237 | ARRAY_SIZE(tbl_common), n); | ||
238 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, s007); | ||
239 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s008); | ||
240 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s009); | ||
241 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, s010); | ||
242 | keep_on_fetching_validx(gspca_dev, tbl_common, | ||
243 | ARRAY_SIZE(tbl_common), n); | ||
244 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, s011); | ||
245 | keep_on_fetching_validx(gspca_dev, tbl_common, | ||
246 | ARRAY_SIZE(tbl_common), n); | ||
247 | } | ||
248 | |||
249 | static int mi1320_init_at_startup(struct gspca_dev *gspca_dev) | ||
250 | { | ||
251 | fetch_validx(gspca_dev, tbl_init_at_startup, | ||
252 | ARRAY_SIZE(tbl_init_at_startup)); | ||
253 | |||
254 | common(gspca_dev); | ||
255 | |||
256 | /* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev) | ||
262 | { | ||
263 | struct sd *sd = (struct sd *) gspca_dev; | ||
264 | |||
265 | sd->mirrorMask = 0; | ||
266 | |||
267 | sd->vold.backlight = -1; | ||
268 | sd->vold.brightness = -1; | ||
269 | sd->vold.sharpness = -1; | ||
270 | sd->vold.contrast = -1; | ||
271 | sd->vold.saturation = -1; | ||
272 | sd->vold.gamma = -1; | ||
273 | sd->vold.hue = -1; | ||
274 | sd->vold.whitebal = -1; | ||
275 | sd->vold.mirror = -1; | ||
276 | sd->vold.flip = -1; | ||
277 | sd->vold.AC50Hz = -1; | ||
278 | |||
279 | common(gspca_dev); | ||
280 | |||
281 | mi1320_sensor_settings(gspca_dev); | ||
282 | |||
283 | mi1320_init_post_alt(gspca_dev); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int mi1320_init_post_alt(struct gspca_dev *gspca_dev) | ||
289 | { | ||
290 | mi1320_camera_settings(gspca_dev); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int mi1320_sensor_settings(struct gspca_dev *gspca_dev) | ||
296 | { | ||
297 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
298 | |||
299 | ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); | ||
300 | |||
301 | fetch_validx(gspca_dev, tbl_sensor_settings_common, | ||
302 | ARRAY_SIZE(tbl_sensor_settings_common)); | ||
303 | |||
304 | switch (reso) { | ||
305 | case IMAGE_1280: | ||
306 | fetch_validx(gspca_dev, tbl_sensor_settings_1280, | ||
307 | ARRAY_SIZE(tbl_sensor_settings_1280)); | ||
308 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_1280[0]); | ||
309 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_1280[1]); | ||
310 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_1280[2]); | ||
311 | break; | ||
312 | |||
313 | case IMAGE_800: | ||
314 | fetch_validx(gspca_dev, tbl_sensor_settings_800, | ||
315 | ARRAY_SIZE(tbl_sensor_settings_800)); | ||
316 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_800[0]); | ||
317 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_800[1]); | ||
318 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_800[2]); | ||
319 | break; | ||
320 | |||
321 | default: | ||
322 | fetch_validx(gspca_dev, tbl_sensor_settings_640, | ||
323 | ARRAY_SIZE(tbl_sensor_settings_640)); | ||
324 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 60, tbl_640[0]); | ||
325 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_640[1]); | ||
326 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_640[2]); | ||
327 | break; | ||
328 | } | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int mi1320_configure_alt(struct gspca_dev *gspca_dev) | ||
333 | { | ||
334 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
335 | |||
336 | switch (reso) { | ||
337 | case IMAGE_640: | ||
338 | gspca_dev->alt = 3 + 1; | ||
339 | break; | ||
340 | |||
341 | case IMAGE_800: | ||
342 | case IMAGE_1280: | ||
343 | gspca_dev->alt = 1 + 1; | ||
344 | break; | ||
345 | } | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | int mi1320_camera_settings(struct gspca_dev *gspca_dev) | ||
350 | { | ||
351 | struct sd *sd = (struct sd *) gspca_dev; | ||
352 | |||
353 | s32 backlight = sd->vcur.backlight; | ||
354 | s32 bright = sd->vcur.brightness; | ||
355 | s32 sharp = sd->vcur.sharpness; | ||
356 | s32 cntr = sd->vcur.contrast; | ||
357 | s32 gam = sd->vcur.gamma; | ||
358 | s32 hue = sd->vcur.hue; | ||
359 | s32 sat = sd->vcur.saturation; | ||
360 | s32 wbal = sd->vcur.whitebal; | ||
361 | s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); | ||
362 | s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); | ||
363 | s32 freq = (sd->vcur.AC50Hz > 0); | ||
364 | s32 i; | ||
365 | |||
366 | if (freq != sd->vold.AC50Hz) { | ||
367 | sd->vold.AC50Hz = freq; | ||
368 | |||
369 | freq = 2 * (freq == 0); | ||
370 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
371 | ctrl_out(gspca_dev, 0x40, 1, 0xba02, 0x00f1, 0, NULL); | ||
372 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x005b, 0, NULL); | ||
373 | ctrl_out(gspca_dev, 0x40, 1, 0xba01 + freq, 0x00f1, 0, NULL); | ||
374 | } | ||
375 | |||
376 | if (wbal != sd->vold.whitebal) { | ||
377 | sd->vold.whitebal = wbal; | ||
378 | if (wbal < 0 || wbal > sd->vmax.whitebal) | ||
379 | wbal = 0; | ||
380 | |||
381 | for (i = 0; i < 2; i++) { | ||
382 | if (wbal == 0) { /* Normal light */ | ||
383 | ctrl_out(gspca_dev, 0x40, 1, | ||
384 | 0x0010, 0x0010, 0, NULL); | ||
385 | ctrl_out(gspca_dev, 0x40, 1, | ||
386 | 0x0003, 0x00c1, 0, NULL); | ||
387 | ctrl_out(gspca_dev, 0x40, 1, | ||
388 | 0x0042, 0x00c2, 0, NULL); | ||
389 | ctrl_out(gspca_dev, 0x40, 3, | ||
390 | 0xba00, 0x0200, 48, dat_wbalNL); | ||
391 | } | ||
392 | |||
393 | if (wbal == 1) { /* Low light */ | ||
394 | ctrl_out(gspca_dev, 0x40, 1, | ||
395 | 0x0010, 0x0010, 0, NULL); | ||
396 | ctrl_out(gspca_dev, 0x40, 1, | ||
397 | 0x0004, 0x00c1, 0, NULL); | ||
398 | ctrl_out(gspca_dev, 0x40, 1, | ||
399 | 0x0043, 0x00c2, 0, NULL); | ||
400 | ctrl_out(gspca_dev, 0x40, 3, | ||
401 | 0xba00, 0x0200, 48, dat_wbalLL); | ||
402 | } | ||
403 | |||
404 | if (wbal == 2) { /* Back light */ | ||
405 | ctrl_out(gspca_dev, 0x40, 1, | ||
406 | 0x0010, 0x0010, 0, NULL); | ||
407 | ctrl_out(gspca_dev, 0x40, 1, | ||
408 | 0x0003, 0x00c1, 0, NULL); | ||
409 | ctrl_out(gspca_dev, 0x40, 1, | ||
410 | 0x0042, 0x00c2, 0, NULL); | ||
411 | ctrl_out(gspca_dev, 0x40, 3, | ||
412 | 0xba00, 0x0200, 44, dat_wbalBL); | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
417 | if (bright != sd->vold.brightness) { | ||
418 | sd->vold.brightness = bright; | ||
419 | if (bright < 0 || bright > sd->vmax.brightness) | ||
420 | bright = 0; | ||
421 | |||
422 | bright = tbl_bright[bright]; | ||
423 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
424 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
425 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x0034, 0, NULL); | ||
426 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x00f1, 0, NULL); | ||
427 | } | ||
428 | |||
429 | if (sat != sd->vold.saturation) { | ||
430 | sd->vold.saturation = sat; | ||
431 | if (sat < 0 || sat > sd->vmax.saturation) | ||
432 | sat = 0; | ||
433 | |||
434 | sat = tbl_sat[sat]; | ||
435 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
436 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
437 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0025, 0, NULL); | ||
438 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sat, 0x00f1, 0, NULL); | ||
439 | } | ||
440 | |||
441 | if (sharp != sd->vold.sharpness) { | ||
442 | sd->vold.sharpness = sharp; | ||
443 | if (sharp < 0 || sharp > sd->vmax.sharpness) | ||
444 | sharp = 0; | ||
445 | |||
446 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
447 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
448 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0005, 0, NULL); | ||
449 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sharp, 0x00f1, 0, NULL); | ||
450 | } | ||
451 | |||
452 | if (hue != sd->vold.hue) { | ||
453 | /* 0=normal 1=NB 2="sepia" 3=negative 4=other 5=other2 */ | ||
454 | if (hue < 0 || hue > sd->vmax.hue) | ||
455 | hue = 0; | ||
456 | if (hue == sd->vmax.hue) | ||
457 | sd->swapRB = 1; | ||
458 | else | ||
459 | sd->swapRB = 0; | ||
460 | |||
461 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
462 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
463 | ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL); | ||
464 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1, | ||
465 | 0, NULL); | ||
466 | } | ||
467 | |||
468 | if (backlight != sd->vold.backlight) { | ||
469 | sd->vold.backlight = backlight; | ||
470 | if (backlight < 0 || backlight > sd->vmax.backlight) | ||
471 | backlight = 0; | ||
472 | |||
473 | backlight = tbl_backlight[backlight]; | ||
474 | for (i = 0; i < 2; i++) { | ||
475 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
476 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
477 | ctrl_out(gspca_dev, 0x40, 1, 0xba74, 0x0006, 0, NULL); | ||
478 | ctrl_out(gspca_dev, 0x40, 1, 0xba80 + backlight, 0x00f1, | ||
479 | 0, NULL); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | if (hue != sd->vold.hue) { | ||
484 | sd->vold.hue = hue; | ||
485 | |||
486 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
487 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
488 | ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL); | ||
489 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1, | ||
490 | 0, NULL); | ||
491 | } | ||
492 | |||
493 | if (mirror != sd->vold.mirror || flip != sd->vold.flip) { | ||
494 | u8 dat_hvflip2[4] = {0x20, 0x01, 0xf1, 0x00}; | ||
495 | sd->vold.mirror = mirror; | ||
496 | sd->vold.flip = flip; | ||
497 | |||
498 | dat_hvflip2[3] = flip + 2 * mirror; | ||
499 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip1); | ||
500 | ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip2); | ||
501 | } | ||
502 | |||
503 | if (gam != sd->vold.gamma) { | ||
504 | sd->vold.gamma = gam; | ||
505 | if (gam < 0 || gam > sd->vmax.gamma) | ||
506 | gam = 0; | ||
507 | |||
508 | gam = 2 * gam; | ||
509 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
510 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
511 | ctrl_out(gspca_dev, 0x40, 1, 0xba04 , 0x003b, 0, NULL); | ||
512 | ctrl_out(gspca_dev, 0x40, 1, 0xba02 + gam, 0x00f1, 0, NULL); | ||
513 | } | ||
514 | |||
515 | if (cntr != sd->vold.contrast) { | ||
516 | sd->vold.contrast = cntr; | ||
517 | if (cntr < 0 || cntr > sd->vmax.contrast) | ||
518 | cntr = 0; | ||
519 | |||
520 | ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); | ||
521 | ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); | ||
522 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr1[cntr], 0x0035, | ||
523 | 0, NULL); | ||
524 | ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr2[cntr], 0x00f1, | ||
525 | 0, NULL); | ||
526 | } | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev) | ||
532 | { | ||
533 | ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); | ||
534 | |||
535 | fetch_validx(gspca_dev, tbl_post_unset_alt, | ||
536 | ARRAY_SIZE(tbl_post_unset_alt)); | ||
537 | } | ||
diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c new file mode 100644 index 000000000000..ffb09fed3e8c --- /dev/null +++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c | |||
@@ -0,0 +1,937 @@ | |||
1 | /* @file gl860-mi2020.c | ||
2 | * @author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's | ||
3 | * logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist. | ||
4 | * @date 2009-08-27 | ||
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 | * 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 | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | /* Sensor : MI2020 */ | ||
21 | |||
22 | #include "gl860.h" | ||
23 | |||
24 | static u8 dat_bright1[] = {0x8c, 0xa2, 0x06}; | ||
25 | static u8 dat_bright3[] = {0x8c, 0xa1, 0x02}; | ||
26 | static u8 dat_bright4[] = {0x90, 0x00, 0x0f}; | ||
27 | static u8 dat_bright5[] = {0x8c, 0xa1, 0x03}; | ||
28 | static u8 dat_bright6[] = {0x90, 0x00, 0x05}; | ||
29 | |||
30 | static u8 dat_dummy1[] = {0x90, 0x00, 0x06}; | ||
31 | /*static u8 dummy2[] = {0x8c, 0xa1, 0x02};*/ | ||
32 | /*static u8 dummy3[] = {0x90, 0x00, 0x1f};*/ | ||
33 | |||
34 | static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19}; | ||
35 | static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b}; | ||
36 | static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03}; | ||
37 | static u8 dat_hvflip6[] = {0x90, 0x00, 0x06}; | ||
38 | |||
39 | static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 }; | ||
40 | |||
41 | static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 }; | ||
42 | static u8 dat_multi6[] = { 0x90, 0x00, 0x05 }; | ||
43 | |||
44 | static struct validx tbl_common_a[] = { | ||
45 | {0x0000, 0x0000}, | ||
46 | {1, 0xffff}, /* msleep(35); */ | ||
47 | {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0}, | ||
48 | {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0004, 0x00d8}, | ||
49 | {0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000}, | ||
50 | }; | ||
51 | |||
52 | static struct validx tbl_common_b[] = { | ||
53 | {0x006a, 0x0007}, | ||
54 | {35, 0xffff}, | ||
55 | {0x00ef, 0x0006}, | ||
56 | {35, 0xffff}, | ||
57 | {0x006a, 0x000d}, | ||
58 | {35, 0xffff}, | ||
59 | {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, | ||
60 | {0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000}, | ||
61 | }; | ||
62 | |||
63 | static struct idxdata tbl_common_c[] = { | ||
64 | {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"}, | ||
65 | {6, "\xff\xff\xff"}, /* 12 */ | ||
66 | {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, | ||
67 | {2, "\xff\xff\xff"}, /* - */ | ||
68 | {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"}, | ||
69 | {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"}, | ||
70 | {0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"}, | ||
71 | {0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"}, | ||
72 | {0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"}, | ||
73 | {0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"}, | ||
74 | {0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"}, | ||
75 | {0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"}, | ||
76 | {0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, | ||
77 | {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, | ||
78 | {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, | ||
79 | {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, | ||
80 | {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, | ||
81 | {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, | ||
82 | {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, | ||
83 | {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, | ||
84 | {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, | ||
85 | {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, | ||
86 | {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, | ||
87 | {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, | ||
88 | {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, | ||
89 | {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, | ||
90 | {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, | ||
91 | {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, | ||
92 | {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, | ||
93 | {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, | ||
94 | {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, | ||
95 | {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, | ||
96 | {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, | ||
97 | {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, | ||
98 | {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, | ||
99 | {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, | ||
100 | {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, | ||
101 | {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, | ||
102 | {1, "\xff\xff\xff"}, | ||
103 | {0x33, "\x78\x00\x00"}, | ||
104 | {1, "\xff\xff\xff"}, | ||
105 | {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"}, | ||
106 | {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"}, | ||
107 | {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"}, | ||
108 | {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"}, | ||
109 | {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, | ||
110 | }; | ||
111 | |||
112 | static struct idxdata tbl_common_d[] = { | ||
113 | {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"}, | ||
114 | {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"}, | ||
115 | {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"}, | ||
116 | {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa0"}, | ||
117 | {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc0"}, {0x33, "\x8c\x24\x15"}, | ||
118 | {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"}, | ||
119 | }; | ||
120 | |||
121 | static struct idxdata tbl_common_e[] = { | ||
122 | {0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, | ||
123 | {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, | ||
124 | {0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, | ||
125 | {0x33, "\x90\x00\x04"}, {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, | ||
126 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, | ||
127 | /* msleep(53); */ | ||
128 | {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, | ||
129 | {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, | ||
130 | {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, | ||
131 | {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, | ||
132 | {0x33, "\x90\x02\x84"}, {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, | ||
133 | {0x33, "\x8c\x27\x07"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, | ||
134 | {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, | ||
135 | {0x33, "\x8c\x27\x0f"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, | ||
136 | {0x33, "\x90\x04\xbd"}, {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, | ||
137 | {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, | ||
138 | {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, | ||
139 | {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, | ||
140 | {0x33, "\x90\x01\x02"}, {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, | ||
141 | {0x33, "\x8c\x27\x21"}, {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, | ||
142 | {0x33, "\x90\x02\x85"}, {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, | ||
143 | {0x33, "\x8c\x27\x27"}, {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, | ||
144 | {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, | ||
145 | {0x33, "\x8c\x27\x2d"}, {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, | ||
146 | {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, | ||
147 | {0x33, "\x8c\x27\x33"}, {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, | ||
148 | {0x33, "\x90\x06\x4b"}, {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, | ||
149 | {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, | ||
150 | {0x33, "\x90\x00\x24"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, | ||
151 | {0x33, "\x8c\x27\x41"}, {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, | ||
152 | {0x33, "\x90\x04\xed"}, {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, | ||
153 | {0x33, "\x8c\x27\x51"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, | ||
154 | {0x33, "\x90\x03\x20"}, {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, | ||
155 | {0x33, "\x8c\x27\x57"}, {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, | ||
156 | {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, | ||
157 | {0x33, "\x8c\x27\x63"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, | ||
158 | {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, | ||
159 | {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, | ||
160 | {0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, | ||
161 | {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, | ||
162 | {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, | ||
163 | {0x33, "\x8c\x24\x15"}, | ||
164 | }; | ||
165 | |||
166 | static struct validx tbl_init_at_startup[] = { | ||
167 | {0x0000, 0x0000}, | ||
168 | {53, 0xffff}, | ||
169 | {0x0010, 0x0010}, | ||
170 | {53, 0xffff}, | ||
171 | {0x0008, 0x00c0}, | ||
172 | {53, 0xffff}, | ||
173 | {0x0001, 0x00c1}, | ||
174 | {53, 0xffff}, | ||
175 | {0x0001, 0x00c2}, | ||
176 | {53, 0xffff}, | ||
177 | {0x0020, 0x0006}, | ||
178 | {53, 0xffff}, | ||
179 | {0x006a, 0x000d}, | ||
180 | {53, 0xffff}, | ||
181 | }; | ||
182 | |||
183 | static struct idxdata tbl_init_post_alt_low_a[] = { | ||
184 | {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"}, | ||
185 | {0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"}, | ||
186 | {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"}, | ||
187 | {0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"}, | ||
188 | {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"}, | ||
189 | {0x33, "\x90\x00\x9b"}, | ||
190 | }; | ||
191 | |||
192 | static struct idxdata tbl_init_post_alt_low_b[] = { | ||
193 | {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"}, | ||
194 | {0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, | ||
195 | {2, "\xff\xff\xff"}, | ||
196 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, | ||
197 | {2, "\xff\xff\xff"}, | ||
198 | }; | ||
199 | |||
200 | static struct idxdata tbl_init_post_alt_low_c[] = { | ||
201 | {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, | ||
202 | {2, "\xff\xff\xff"}, | ||
203 | {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"}, | ||
204 | {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, | ||
205 | {0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, | ||
206 | {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"}, | ||
207 | {2, "\xff\xff\xff"}, | ||
208 | {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, | ||
209 | {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, | ||
210 | {2, "\xff\xff\xff"}, | ||
211 | {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, | ||
212 | {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, | ||
213 | {2, "\xff\xff\xff"}, /* - * */ | ||
214 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, | ||
215 | {2, "\xff\xff\xff"}, | ||
216 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, | ||
217 | {2, "\xff\xff\xff"}, | ||
218 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, | ||
219 | {2, "\xff\xff\xff"}, | ||
220 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, | ||
221 | {1, "\xff\xff\xff"}, | ||
222 | }; | ||
223 | |||
224 | static struct idxdata tbl_init_post_alt_low_d[] = { | ||
225 | {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, | ||
226 | {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, | ||
227 | {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, | ||
228 | {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, | ||
229 | {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, | ||
230 | {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, | ||
231 | {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, | ||
232 | {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, | ||
233 | {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, | ||
234 | {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, | ||
235 | {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, | ||
236 | {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, | ||
237 | {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, | ||
238 | {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, | ||
239 | {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, | ||
240 | {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, | ||
241 | {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, | ||
242 | {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, | ||
243 | {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, | ||
244 | {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, | ||
245 | {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, | ||
246 | {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, | ||
247 | {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, | ||
248 | {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, | ||
249 | {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, | ||
250 | {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, | ||
251 | /* Flip/Mirror h/v=1 */ | ||
252 | {0x33, "\x90\x00\x3c"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, | ||
253 | {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, {0x33, "\x8c\xa1\x03"}, | ||
254 | {0x33, "\x90\x00\x06"}, | ||
255 | {130, "\xff\xff\xff"}, | ||
256 | {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, | ||
257 | {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, | ||
258 | {100, "\xff\xff\xff"}, | ||
259 | /* ?? */ | ||
260 | {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, | ||
261 | {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, | ||
262 | {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, | ||
263 | /* Brigthness=70 */ | ||
264 | {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x46"}, {0x33, "\x8c\xa1\x02"}, | ||
265 | {0x33, "\x90\x00\x0f"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, | ||
266 | /* Sharpness=20 */ | ||
267 | {0x32, "\x6c\x14\x08"}, | ||
268 | }; | ||
269 | |||
270 | static struct idxdata tbl_init_post_alt_big_a[] = { | ||
271 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, | ||
272 | {2, "\xff\xff\xff"}, | ||
273 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, | ||
274 | {2, "\xff\xff\xff"}, | ||
275 | {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, | ||
276 | {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"}, | ||
277 | {0x33, "\x90\x00\x05"}, | ||
278 | {2, "\xff\xff\xff"}, | ||
279 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, | ||
280 | {2, "\xff\xff\xff"}, | ||
281 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, | ||
282 | {2, "\xff\xff\xff"}, | ||
283 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"}, | ||
284 | {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"}, | ||
285 | {0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"}, | ||
286 | {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"}, | ||
287 | {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"}, | ||
288 | {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, | ||
289 | }; | ||
290 | |||
291 | static struct idxdata tbl_init_post_alt_big_b[] = { | ||
292 | {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, | ||
293 | {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, | ||
294 | {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, | ||
295 | {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, | ||
296 | {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, | ||
297 | {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, | ||
298 | {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, | ||
299 | {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, | ||
300 | {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, | ||
301 | {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, | ||
302 | {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, | ||
303 | {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, | ||
304 | {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, | ||
305 | {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, | ||
306 | {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, | ||
307 | {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, | ||
308 | {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, | ||
309 | {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, | ||
310 | {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, | ||
311 | {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, | ||
312 | {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, | ||
313 | {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, | ||
314 | {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, | ||
315 | {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, | ||
316 | {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, | ||
317 | {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, | ||
318 | }; | ||
319 | |||
320 | static struct idxdata tbl_init_post_alt_big_c[] = { | ||
321 | {0x33, "\x8c\xa1\x02"}, | ||
322 | {0x33, "\x90\x00\x1f"}, | ||
323 | {0x33, "\x8c\xa1\x02"}, | ||
324 | {0x33, "\x90\x00\x1f"}, | ||
325 | {0x33, "\x8c\xa1\x02"}, | ||
326 | {0x33, "\x90\x00\x1f"}, | ||
327 | {0x33, "\x8c\xa1\x02"}, | ||
328 | {0x33, "\x90\x00\x1f"}, | ||
329 | }; | ||
330 | |||
331 | static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81"; | ||
332 | static u8 *dat_800 = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21"; | ||
333 | static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01"; | ||
334 | static u8 *dat_1600 = "\xd0\x02\xd1\x20\xd2\xaf\xd3\x02\xd4\x30\xd5\x41"; | ||
335 | |||
336 | static int mi2020_init_at_startup(struct gspca_dev *gspca_dev); | ||
337 | static int mi2020_configure_alt(struct gspca_dev *gspca_dev); | ||
338 | static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev); | ||
339 | static int mi2020_init_post_alt(struct gspca_dev *gspca_dev); | ||
340 | static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev); | ||
341 | static int mi2020_camera_settings(struct gspca_dev *gspca_dev); | ||
342 | /*==========================================================================*/ | ||
343 | |||
344 | void mi2020_init_settings(struct gspca_dev *gspca_dev) | ||
345 | { | ||
346 | struct sd *sd = (struct sd *) gspca_dev; | ||
347 | |||
348 | sd->vcur.backlight = 0; | ||
349 | sd->vcur.brightness = 70; | ||
350 | sd->vcur.sharpness = 20; | ||
351 | sd->vcur.contrast = 0; | ||
352 | sd->vcur.gamma = 0; | ||
353 | sd->vcur.hue = 0; | ||
354 | sd->vcur.saturation = 60; | ||
355 | sd->vcur.whitebal = 50; | ||
356 | sd->vcur.mirror = 0; | ||
357 | sd->vcur.flip = 0; | ||
358 | sd->vcur.AC50Hz = 1; | ||
359 | |||
360 | sd->vmax.backlight = 64; | ||
361 | sd->vmax.brightness = 128; | ||
362 | sd->vmax.sharpness = 40; | ||
363 | sd->vmax.contrast = 3; | ||
364 | sd->vmax.gamma = 2; | ||
365 | sd->vmax.hue = 0 + 1; /* 200 */ | ||
366 | sd->vmax.saturation = 0; /* 100 */ | ||
367 | sd->vmax.whitebal = 0; /* 100 */ | ||
368 | sd->vmax.mirror = 1; | ||
369 | sd->vmax.flip = 1; | ||
370 | sd->vmax.AC50Hz = 1; | ||
371 | if (_MI2020b_) { | ||
372 | sd->vmax.contrast = 0; | ||
373 | sd->vmax.gamma = 0; | ||
374 | sd->vmax.backlight = 0; | ||
375 | } | ||
376 | |||
377 | sd->dev_camera_settings = mi2020_camera_settings; | ||
378 | sd->dev_init_at_startup = mi2020_init_at_startup; | ||
379 | sd->dev_configure_alt = mi2020_configure_alt; | ||
380 | sd->dev_init_pre_alt = mi2020_init_pre_alt; | ||
381 | sd->dev_post_unset_alt = mi2020_post_unset_alt; | ||
382 | } | ||
383 | |||
384 | /*==========================================================================*/ | ||
385 | |||
386 | static void common(struct gspca_dev *gspca_dev) | ||
387 | { | ||
388 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
389 | |||
390 | if (_MI2020b_) { | ||
391 | fetch_validx(gspca_dev, tbl_common_a, ARRAY_SIZE(tbl_common_a)); | ||
392 | } else { | ||
393 | if (_MI2020_) | ||
394 | ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x0004, 0, NULL); | ||
395 | else | ||
396 | ctrl_out(gspca_dev, 0x40, 1, 0x0002, 0x0004, 0, NULL); | ||
397 | msleep(35); | ||
398 | fetch_validx(gspca_dev, tbl_common_b, ARRAY_SIZE(tbl_common_b)); | ||
399 | } | ||
400 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x01"); | ||
401 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x00"); | ||
402 | msleep(2); /* - * */ | ||
403 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0030, 3, "\x1a\x0a\xcc"); | ||
404 | if (reso == IMAGE_1600) | ||
405 | msleep(2); /* 1600 */ | ||
406 | fetch_idxdata(gspca_dev, tbl_common_c, ARRAY_SIZE(tbl_common_c)); | ||
407 | |||
408 | if (_MI2020b_ || _MI2020_) | ||
409 | fetch_idxdata(gspca_dev, tbl_common_d, | ||
410 | ARRAY_SIZE(tbl_common_d)); | ||
411 | |||
412 | fetch_idxdata(gspca_dev, tbl_common_e, ARRAY_SIZE(tbl_common_e)); | ||
413 | if (_MI2020b_ || _MI2020_) { | ||
414 | /* Different from fret */ | ||
415 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78"); | ||
416 | /* Same as fret */ | ||
417 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17"); | ||
418 | /* Different from fret */ | ||
419 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x90"); | ||
420 | } else { | ||
421 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x6a"); | ||
422 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17"); | ||
423 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x80"); | ||
424 | } | ||
425 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); | ||
426 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x05"); | ||
427 | msleep(2); | ||
428 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); | ||
429 | if (reso == IMAGE_1600) | ||
430 | msleep(14); /* 1600 */ | ||
431 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x06"); | ||
432 | msleep(2); | ||
433 | } | ||
434 | |||
435 | static int mi2020_init_at_startup(struct gspca_dev *gspca_dev) | ||
436 | { | ||
437 | u8 c; | ||
438 | |||
439 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c); | ||
440 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c); | ||
441 | |||
442 | fetch_validx(gspca_dev, tbl_init_at_startup, | ||
443 | ARRAY_SIZE(tbl_init_at_startup)); | ||
444 | |||
445 | common(gspca_dev); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev) | ||
451 | { | ||
452 | struct sd *sd = (struct sd *) gspca_dev; | ||
453 | |||
454 | sd->mirrorMask = 0; | ||
455 | |||
456 | sd->vold.backlight = -1; | ||
457 | sd->vold.brightness = -1; | ||
458 | sd->vold.sharpness = -1; | ||
459 | sd->vold.contrast = -1; | ||
460 | sd->vold.gamma = -1; | ||
461 | sd->vold.hue = -1; | ||
462 | sd->vold.mirror = -1; | ||
463 | sd->vold.flip = -1; | ||
464 | sd->vold.AC50Hz = -1; | ||
465 | |||
466 | mi2020_init_post_alt(gspca_dev); | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) | ||
472 | { | ||
473 | struct sd *sd = (struct sd *) gspca_dev; | ||
474 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
475 | |||
476 | s32 backlight = sd->vcur.backlight; | ||
477 | s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); | ||
478 | s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); | ||
479 | s32 freq = (sd->vcur.AC50Hz > 0); | ||
480 | |||
481 | u8 dat_freq2[] = {0x90, 0x00, 0x80}; | ||
482 | u8 dat_multi1[] = {0x8c, 0xa7, 0x00}; | ||
483 | u8 dat_multi2[] = {0x90, 0x00, 0x00}; | ||
484 | u8 dat_multi3[] = {0x8c, 0xa7, 0x00}; | ||
485 | u8 dat_multi4[] = {0x90, 0x00, 0x00}; | ||
486 | u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; | ||
487 | u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; | ||
488 | u8 c; | ||
489 | |||
490 | sd->nbIm = -1; | ||
491 | |||
492 | dat_freq2[2] = freq ? 0xc0 : 0x80; | ||
493 | dat_multi1[2] = 0x9d; | ||
494 | dat_multi3[2] = dat_multi1[2] + 1; | ||
495 | dat_multi4[2] = dat_multi2[2] = backlight; | ||
496 | dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); | ||
497 | dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); | ||
498 | |||
499 | msleep(200); | ||
500 | |||
501 | ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); | ||
502 | msleep(3); /* 35 * */ | ||
503 | |||
504 | common(gspca_dev); | ||
505 | |||
506 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); | ||
507 | msleep(70); | ||
508 | |||
509 | if (_MI2020b_) | ||
510 | ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); | ||
511 | |||
512 | ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); | ||
513 | ctrl_out(gspca_dev, 0x40, 1, 0x0003, 0x00c1, 0, NULL); | ||
514 | ctrl_out(gspca_dev, 0x40, 1, 0x0042, 0x00c2, 0, NULL); | ||
515 | ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL); | ||
516 | |||
517 | switch (reso) { | ||
518 | case IMAGE_640: | ||
519 | case IMAGE_800: | ||
520 | if (reso != IMAGE_800) | ||
521 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
522 | 12, dat_640); | ||
523 | else | ||
524 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
525 | 12, dat_800); | ||
526 | |||
527 | if (_MI2020c_) | ||
528 | fetch_idxdata(gspca_dev, tbl_init_post_alt_low_a, | ||
529 | ARRAY_SIZE(tbl_init_post_alt_low_a)); | ||
530 | |||
531 | if (reso == IMAGE_800) | ||
532 | fetch_idxdata(gspca_dev, tbl_init_post_alt_low_b, | ||
533 | ARRAY_SIZE(tbl_init_post_alt_low_b)); | ||
534 | |||
535 | fetch_idxdata(gspca_dev, tbl_init_post_alt_low_c, | ||
536 | ARRAY_SIZE(tbl_init_post_alt_low_c)); | ||
537 | |||
538 | if (_MI2020b_) { | ||
539 | ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); | ||
540 | ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); | ||
541 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); | ||
542 | msleep(150); | ||
543 | } else if (_MI2020c_) { | ||
544 | ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); | ||
545 | ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); | ||
546 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); | ||
547 | msleep(120); | ||
548 | ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); | ||
549 | msleep(30); | ||
550 | } else if (_MI2020_) { | ||
551 | ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); | ||
552 | ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); | ||
553 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); | ||
554 | msleep(120); | ||
555 | ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); | ||
556 | msleep(30); | ||
557 | } | ||
558 | |||
559 | /* AC power frequency */ | ||
560 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); | ||
561 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); | ||
562 | msleep(20); | ||
563 | /* backlight */ | ||
564 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); | ||
565 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); | ||
566 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); | ||
567 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); | ||
568 | /* at init time but not after */ | ||
569 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c"); | ||
570 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17"); | ||
571 | /* finish the backlight */ | ||
572 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); | ||
573 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); | ||
574 | msleep(5);/* " */ | ||
575 | |||
576 | if (_MI2020c_) { | ||
577 | fetch_idxdata(gspca_dev, tbl_init_post_alt_low_d, | ||
578 | ARRAY_SIZE(tbl_init_post_alt_low_d)); | ||
579 | } else { | ||
580 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c); | ||
581 | msleep(14); /* 0xd8 */ | ||
582 | |||
583 | /* flip/mirror */ | ||
584 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
585 | 3, dat_hvflip1); | ||
586 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
587 | 3, dat_hvflip2); | ||
588 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
589 | 3, dat_hvflip3); | ||
590 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
591 | 3, dat_hvflip4); | ||
592 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
593 | 3, dat_hvflip5); | ||
594 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
595 | 3, dat_hvflip6); | ||
596 | msleep(21); | ||
597 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
598 | 3, dat_dummy1); | ||
599 | msleep(5); | ||
600 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
601 | 3, dat_dummy1); | ||
602 | msleep(5); | ||
603 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
604 | 3, dat_dummy1); | ||
605 | msleep(5); | ||
606 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
607 | 3, dat_dummy1); | ||
608 | msleep(5); | ||
609 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
610 | 3, dat_dummy1); | ||
611 | msleep(5); | ||
612 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
613 | 3, dat_dummy1); | ||
614 | /* end of flip/mirror main part */ | ||
615 | msleep(246); /* 146 */ | ||
616 | |||
617 | sd->nbIm = 0; | ||
618 | } | ||
619 | break; | ||
620 | |||
621 | case IMAGE_1280: | ||
622 | case IMAGE_1600: | ||
623 | if (reso == IMAGE_1280) { | ||
624 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
625 | 12, dat_1280); | ||
626 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
627 | 3, "\x8c\x27\x07"); | ||
628 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
629 | 3, "\x90\x05\x04"); | ||
630 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
631 | 3, "\x8c\x27\x09"); | ||
632 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
633 | 3, "\x90\x04\x02"); | ||
634 | } else { | ||
635 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
636 | 12, dat_1600); | ||
637 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
638 | 3, "\x8c\x27\x07"); | ||
639 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
640 | 3, "\x90\x06\x40"); | ||
641 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
642 | 3, "\x8c\x27\x09"); | ||
643 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, | ||
644 | 3, "\x90\x04\xb0"); | ||
645 | } | ||
646 | |||
647 | fetch_idxdata(gspca_dev, tbl_init_post_alt_big_a, | ||
648 | ARRAY_SIZE(tbl_init_post_alt_big_a)); | ||
649 | |||
650 | if (reso == IMAGE_1600) | ||
651 | msleep(13); /* 1600 */ | ||
652 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x27\x97"); | ||
653 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x01\x00"); | ||
654 | msleep(53); | ||
655 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); | ||
656 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); | ||
657 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); | ||
658 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); | ||
659 | if (reso == IMAGE_1600) | ||
660 | msleep(13); /* 1600 */ | ||
661 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); | ||
662 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); | ||
663 | msleep(53); | ||
664 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); | ||
665 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72"); | ||
666 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); | ||
667 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02"); | ||
668 | if (reso == IMAGE_1600) | ||
669 | msleep(13); /* 1600 */ | ||
670 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); | ||
671 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); | ||
672 | msleep(53); | ||
673 | |||
674 | if (_MI2020b_) { | ||
675 | ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); | ||
676 | if (reso == IMAGE_1600) | ||
677 | msleep(500); /* 1600 */ | ||
678 | ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); | ||
679 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); | ||
680 | msleep(1850); | ||
681 | } else if (_MI2020c_ || _MI2020_) { | ||
682 | ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); | ||
683 | ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); | ||
684 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); | ||
685 | msleep(1850); | ||
686 | ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); | ||
687 | msleep(30); | ||
688 | } | ||
689 | |||
690 | /* AC power frequency */ | ||
691 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); | ||
692 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); | ||
693 | msleep(20); | ||
694 | /* backlight */ | ||
695 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); | ||
696 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); | ||
697 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); | ||
698 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); | ||
699 | /* at init time but not after */ | ||
700 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c"); | ||
701 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17"); | ||
702 | /* finish the backlight */ | ||
703 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); | ||
704 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); | ||
705 | msleep(6); /* " */ | ||
706 | |||
707 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c); | ||
708 | msleep(14); | ||
709 | |||
710 | if (_MI2020c_) | ||
711 | fetch_idxdata(gspca_dev, tbl_init_post_alt_big_b, | ||
712 | ARRAY_SIZE(tbl_init_post_alt_big_b)); | ||
713 | |||
714 | /* flip/mirror */ | ||
715 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); | ||
716 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); | ||
717 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); | ||
718 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); | ||
719 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); | ||
720 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); | ||
721 | /* end of flip/mirror main part */ | ||
722 | msleep(16); | ||
723 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); | ||
724 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); | ||
725 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); | ||
726 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); | ||
727 | if (reso == IMAGE_1600) | ||
728 | msleep(25); /* 1600 */ | ||
729 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); | ||
730 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); | ||
731 | msleep(103); | ||
732 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); | ||
733 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02"); | ||
734 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); | ||
735 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72"); | ||
736 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); | ||
737 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); | ||
738 | sd->nbIm = 0; | ||
739 | |||
740 | if (_MI2020c_) | ||
741 | fetch_idxdata(gspca_dev, tbl_init_post_alt_big_c, | ||
742 | ARRAY_SIZE(tbl_init_post_alt_big_c)); | ||
743 | } | ||
744 | |||
745 | sd->vold.mirror = mirror; | ||
746 | sd->vold.flip = flip; | ||
747 | sd->vold.AC50Hz = freq; | ||
748 | sd->vold.backlight = backlight; | ||
749 | |||
750 | mi2020_camera_settings(gspca_dev); | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | static int mi2020_configure_alt(struct gspca_dev *gspca_dev) | ||
756 | { | ||
757 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
758 | |||
759 | switch (reso) { | ||
760 | case IMAGE_640: | ||
761 | gspca_dev->alt = 3 + 1; | ||
762 | break; | ||
763 | |||
764 | case IMAGE_800: | ||
765 | case IMAGE_1280: | ||
766 | case IMAGE_1600: | ||
767 | gspca_dev->alt = 1 + 1; | ||
768 | break; | ||
769 | } | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | int mi2020_camera_settings(struct gspca_dev *gspca_dev) | ||
774 | { | ||
775 | struct sd *sd = (struct sd *) gspca_dev; | ||
776 | |||
777 | s32 backlight = sd->vcur.backlight; | ||
778 | s32 bright = sd->vcur.brightness; | ||
779 | s32 sharp = sd->vcur.sharpness; | ||
780 | s32 cntr = sd->vcur.contrast; | ||
781 | s32 gam = sd->vcur.gamma; | ||
782 | s32 hue = (sd->vcur.hue > 0); | ||
783 | s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); | ||
784 | s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); | ||
785 | s32 freq = (sd->vcur.AC50Hz > 0); | ||
786 | |||
787 | u8 dat_sharp[] = {0x6c, 0x00, 0x08}; | ||
788 | u8 dat_bright2[] = {0x90, 0x00, 0x00}; | ||
789 | u8 dat_freq2[] = {0x90, 0x00, 0x80}; | ||
790 | u8 dat_multi1[] = {0x8c, 0xa7, 0x00}; | ||
791 | u8 dat_multi2[] = {0x90, 0x00, 0x00}; | ||
792 | u8 dat_multi3[] = {0x8c, 0xa7, 0x00}; | ||
793 | u8 dat_multi4[] = {0x90, 0x00, 0x00}; | ||
794 | u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; | ||
795 | u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; | ||
796 | |||
797 | /* Less than 4 images received -> too early to set the settings */ | ||
798 | if (sd->nbIm < 4) { | ||
799 | sd->waitSet = 1; | ||
800 | return 0; | ||
801 | } | ||
802 | sd->waitSet = 0; | ||
803 | |||
804 | if (freq != sd->vold.AC50Hz) { | ||
805 | sd->vold.AC50Hz = freq; | ||
806 | |||
807 | dat_freq2[2] = freq ? 0xc0 : 0x80; | ||
808 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); | ||
809 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); | ||
810 | msleep(20); | ||
811 | } | ||
812 | |||
813 | if (mirror != sd->vold.mirror || flip != sd->vold.flip) { | ||
814 | sd->vold.mirror = mirror; | ||
815 | sd->vold.flip = flip; | ||
816 | |||
817 | dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); | ||
818 | dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); | ||
819 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); | ||
820 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); | ||
821 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); | ||
822 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); | ||
823 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); | ||
824 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); | ||
825 | msleep(130); | ||
826 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); | ||
827 | msleep(6); | ||
828 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); | ||
829 | msleep(6); | ||
830 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); | ||
831 | msleep(6); | ||
832 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); | ||
833 | msleep(6); | ||
834 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); | ||
835 | msleep(6); | ||
836 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); | ||
837 | msleep(6); | ||
838 | |||
839 | /* Sometimes present, sometimes not, useful? */ | ||
840 | /* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); | ||
841 | * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3); | ||
842 | * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); | ||
843 | * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3); | ||
844 | * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); | ||
845 | * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3); | ||
846 | * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); | ||
847 | * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);*/ | ||
848 | } | ||
849 | |||
850 | if (backlight != sd->vold.backlight) { | ||
851 | sd->vold.backlight = backlight; | ||
852 | if (backlight < 0 || backlight > sd->vmax.backlight) | ||
853 | backlight = 0; | ||
854 | |||
855 | dat_multi1[2] = 0x9d; | ||
856 | dat_multi3[2] = dat_multi1[2] + 1; | ||
857 | dat_multi4[2] = dat_multi2[2] = backlight; | ||
858 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); | ||
859 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); | ||
860 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); | ||
861 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); | ||
862 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); | ||
863 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); | ||
864 | } | ||
865 | |||
866 | if (gam != sd->vold.gamma) { | ||
867 | sd->vold.gamma = gam; | ||
868 | if (gam < 0 || gam > sd->vmax.gamma) | ||
869 | gam = 0; | ||
870 | |||
871 | dat_multi1[2] = 0x6d; | ||
872 | dat_multi3[2] = dat_multi1[2] + 1; | ||
873 | dat_multi4[2] = dat_multi2[2] = 0x40 + gam; | ||
874 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); | ||
875 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); | ||
876 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); | ||
877 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); | ||
878 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); | ||
879 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); | ||
880 | } | ||
881 | |||
882 | if (cntr != sd->vold.contrast) { | ||
883 | sd->vold.contrast = cntr; | ||
884 | if (cntr < 0 || cntr > sd->vmax.contrast) | ||
885 | cntr = 0; | ||
886 | |||
887 | dat_multi1[2] = 0x6d; | ||
888 | dat_multi3[2] = dat_multi1[2] + 1; | ||
889 | dat_multi4[2] = dat_multi2[2] = 0x12 + 16 * cntr; | ||
890 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); | ||
891 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); | ||
892 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); | ||
893 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); | ||
894 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); | ||
895 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); | ||
896 | } | ||
897 | |||
898 | if (bright != sd->vold.brightness) { | ||
899 | sd->vold.brightness = bright; | ||
900 | if (bright < 0 || bright > sd->vmax.brightness) | ||
901 | bright = 0; | ||
902 | |||
903 | dat_bright2[2] = bright; | ||
904 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1); | ||
905 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2); | ||
906 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3); | ||
907 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4); | ||
908 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5); | ||
909 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6); | ||
910 | } | ||
911 | |||
912 | if (sharp != sd->vold.sharpness) { | ||
913 | sd->vold.sharpness = sharp; | ||
914 | if (sharp < 0 || sharp > sd->vmax.sharpness) | ||
915 | sharp = 0; | ||
916 | |||
917 | dat_sharp[1] = sharp; | ||
918 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0032, 3, dat_sharp); | ||
919 | } | ||
920 | |||
921 | if (hue != sd->vold.hue) { | ||
922 | sd->swapRB = hue; | ||
923 | sd->vold.hue = hue; | ||
924 | } | ||
925 | |||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev) | ||
930 | { | ||
931 | ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); | ||
932 | msleep(20); | ||
933 | if (_MI2020c_ || _MI2020_) | ||
934 | ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); | ||
935 | else | ||
936 | ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); | ||
937 | } | ||
diff --git a/drivers/media/video/gspca/gl860/gl860-ov2640.c b/drivers/media/video/gspca/gl860/gl860-ov2640.c new file mode 100644 index 000000000000..14b9c373f9f7 --- /dev/null +++ b/drivers/media/video/gspca/gl860/gl860-ov2640.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* @file gl860-ov2640.c | ||
2 | * @author Olivier LORIN, from Malmostoso's logs | ||
3 | * @date 2009-08-27 | ||
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 | * any later version. | ||
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, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /* Sensor : OV2640 */ | ||
20 | |||
21 | #include "gl860.h" | ||
22 | |||
23 | static u8 dat_init1[] = "\x00\x41\x07\x6a\x06\x61\x0d\x6a" "\x10\x10\xc1\x01"; | ||
24 | static u8 dat_init2[] = {0x61}; /* expected */ | ||
25 | static u8 dat_init3[] = {0x51}; /* expected */ | ||
26 | |||
27 | static u8 dat_post[] = | ||
28 | "\x00\x41\x07\x6a\x06\xef\x0d\x6a" "\x10\x10\xc1\x01"; | ||
29 | |||
30 | static u8 dat_640[] = "\xd0\x01\xd1\x08\xd2\xe0\xd3\x02\xd4\x10\xd5\x81"; | ||
31 | static u8 dat_800[] = "\xd0\x01\xd1\x10\xd2\x58\xd3\x02\xd4\x18\xd5\x21"; | ||
32 | static u8 dat_1280[] = "\xd0\x01\xd1\x18\xd2\xc0\xd3\x02\xd4\x28\xd5\x01"; | ||
33 | static u8 dat_1600[] = "\xd0\x01\xd1\x20\xd2\xb0\xd3\x02\xd4\x30\xd5\x41"; | ||
34 | |||
35 | static u8 c50[] = {0x50}; /* expected */ | ||
36 | static u8 c28[] = {0x28}; /* expected */ | ||
37 | static u8 ca8[] = {0xa8}; /* expected */ | ||
38 | |||
39 | static struct validx tbl_init_at_startup[] = { | ||
40 | {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, | ||
41 | {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, | ||
42 | {0x0050, 0x0000}, {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0061, 0x0006}, | ||
43 | {0x006a, 0x000d}, {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, | ||
44 | {0x0041, 0x00c2}, {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, | ||
45 | {0x0041, 0x0000}, {0x0061, 0x0000}, | ||
46 | }; | ||
47 | |||
48 | static struct validx tbl_common[] = { | ||
49 | {0x6000, 0x00ff}, {0x60ff, 0x002c}, {0x60df, 0x002e}, {0x6001, 0x00ff}, | ||
50 | {0x6080, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010}, | ||
51 | {0x6035, 0x003c}, {0x6000, 0x0011}, {0x6028, 0x0004}, {0x60e5, 0x0013}, | ||
52 | {0x6088, 0x0014}, {0x600c, 0x002c}, {0x6078, 0x0033}, {0x60f7, 0x003b}, | ||
53 | {0x6000, 0x003e}, {0x6011, 0x0043}, {0x6010, 0x0016}, {0x6082, 0x0039}, | ||
54 | {0x6088, 0x0035}, {0x600a, 0x0022}, {0x6040, 0x0037}, {0x6000, 0x0023}, | ||
55 | {0x60a0, 0x0034}, {0x601a, 0x0036}, {0x6002, 0x0006}, {0x60c0, 0x0007}, | ||
56 | {0x60b7, 0x000d}, {0x6001, 0x000e}, {0x6000, 0x004c}, {0x6081, 0x004a}, | ||
57 | {0x6099, 0x0021}, {0x6002, 0x0009}, {0x603e, 0x0024}, {0x6034, 0x0025}, | ||
58 | {0x6081, 0x0026}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010}, | ||
59 | {0x6000, 0x005c}, {0x6000, 0x0063}, {0x6000, 0x007c}, {0x6070, 0x0061}, | ||
60 | {0x6080, 0x0062}, {0x6080, 0x0020}, {0x6030, 0x0028}, {0x6000, 0x006c}, | ||
61 | {0x6000, 0x006e}, {0x6002, 0x0070}, {0x6094, 0x0071}, {0x60c1, 0x0073}, | ||
62 | {0x6034, 0x003d}, {0x6057, 0x005a}, {0x60bb, 0x004f}, {0x609c, 0x0050}, | ||
63 | {0x6080, 0x006d}, {0x6002, 0x0039}, {0x6033, 0x003a}, {0x60f1, 0x003b}, | ||
64 | {0x6031, 0x003c}, {0x6000, 0x00ff}, {0x6014, 0x00e0}, {0x60ff, 0x0076}, | ||
65 | {0x60a0, 0x0033}, {0x6020, 0x0042}, {0x6018, 0x0043}, {0x6000, 0x004c}, | ||
66 | {0x60d0, 0x0087}, {0x600f, 0x0088}, {0x6003, 0x00d7}, {0x6010, 0x00d9}, | ||
67 | {0x6005, 0x00da}, {0x6082, 0x00d3}, {0x60c0, 0x00f9}, {0x6006, 0x0044}, | ||
68 | {0x6007, 0x00d1}, {0x6002, 0x00d2}, {0x6000, 0x00d2}, {0x6011, 0x00d8}, | ||
69 | {0x6008, 0x00c8}, {0x6080, 0x00c9}, {0x6008, 0x007c}, {0x6020, 0x007d}, | ||
70 | {0x6020, 0x007d}, {0x6000, 0x0090}, {0x600e, 0x0091}, {0x601a, 0x0091}, | ||
71 | {0x6031, 0x0091}, {0x605a, 0x0091}, {0x6069, 0x0091}, {0x6075, 0x0091}, | ||
72 | {0x607e, 0x0091}, {0x6088, 0x0091}, {0x608f, 0x0091}, {0x6096, 0x0091}, | ||
73 | {0x60a3, 0x0091}, {0x60af, 0x0091}, {0x60c4, 0x0091}, {0x60d7, 0x0091}, | ||
74 | {0x60e8, 0x0091}, {0x6020, 0x0091}, {0x6000, 0x0092}, {0x6006, 0x0093}, | ||
75 | {0x60e3, 0x0093}, {0x6005, 0x0093}, {0x6005, 0x0093}, {0x6000, 0x0093}, | ||
76 | {0x6004, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, | ||
77 | {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, | ||
78 | {0x6000, 0x0096}, {0x6008, 0x0097}, {0x6019, 0x0097}, {0x6002, 0x0097}, | ||
79 | {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, {0x6028, 0x0097}, | ||
80 | {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6098, 0x0097}, {0x6080, 0x0097}, | ||
81 | {0x6000, 0x0097}, {0x6000, 0x0097}, {0x60ed, 0x00c3}, {0x609a, 0x00c4}, | ||
82 | {0x6000, 0x00a4}, {0x6011, 0x00c5}, {0x6051, 0x00c6}, {0x6010, 0x00c7}, | ||
83 | {0x6066, 0x00b6}, {0x60a5, 0x00b8}, {0x6064, 0x00b7}, {0x607c, 0x00b9}, | ||
84 | {0x60af, 0x00b3}, {0x6097, 0x00b4}, {0x60ff, 0x00b5}, {0x60c5, 0x00b0}, | ||
85 | {0x6094, 0x00b1}, {0x600f, 0x00b2}, {0x605c, 0x00c4}, {0x6000, 0x00a8}, | ||
86 | {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x601d, 0x0086}, {0x6000, 0x0050}, | ||
87 | {0x6090, 0x0051}, {0x6018, 0x0052}, {0x6000, 0x0053}, {0x6000, 0x0054}, | ||
88 | {0x6088, 0x0055}, {0x6000, 0x0057}, {0x6090, 0x005a}, {0x6018, 0x005b}, | ||
89 | {0x6005, 0x005c}, {0x60ed, 0x00c3}, {0x6000, 0x007f}, {0x6005, 0x00da}, | ||
90 | {0x601f, 0x00e5}, {0x6067, 0x00e1}, {0x6000, 0x00e0}, {0x60ff, 0x00dd}, | ||
91 | {0x6000, 0x0005}, {0x6001, 0x00ff}, {0x6000, 0x0000}, {0x6000, 0x0045}, | ||
92 | {0x6000, 0x0010}, | ||
93 | }; | ||
94 | |||
95 | static struct validx tbl_sensor_settings_common_a[] = { | ||
96 | {0x0041, 0x0000}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d}, | ||
97 | {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2}, | ||
98 | {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0041, 0x0000}, | ||
99 | {50, 0xffff}, | ||
100 | {0x0061, 0x0000}, | ||
101 | {0xffff, 0xffff}, | ||
102 | {0x6000, 0x00ff}, {0x6000, 0x007c}, {0x6007, 0x007d}, | ||
103 | {30, 0xffff}, | ||
104 | {0x0040, 0x0000}, | ||
105 | }; | ||
106 | |||
107 | static struct validx tbl_sensor_settings_common_b[] = { | ||
108 | {0x6001, 0x00ff}, {0x6038, 0x000c}, | ||
109 | {10, 0xffff}, | ||
110 | {0x6000, 0x0011}, | ||
111 | /* backlight=31/64 */ | ||
112 | {0x6001, 0x00ff}, {0x603e, 0x0024}, {0x6034, 0x0025}, | ||
113 | /* bright=0/256 */ | ||
114 | {0x6000, 0x00ff}, {0x6009, 0x007c}, {0x6000, 0x007d}, | ||
115 | /* wbal=64/128 */ | ||
116 | {0x6000, 0x00ff}, {0x6003, 0x007c}, {0x6040, 0x007d}, | ||
117 | /* cntr=0/256 */ | ||
118 | {0x6000, 0x00ff}, {0x6007, 0x007c}, {0x6000, 0x007d}, | ||
119 | /* sat=128/256 */ | ||
120 | {0x6000, 0x00ff}, {0x6001, 0x007c}, {0x6080, 0x007d}, | ||
121 | /* sharpness=0/32 */ | ||
122 | {0x6000, 0x00ff}, {0x6001, 0x0092}, {0x60c0, 0x0093}, | ||
123 | /* hue=0/256 */ | ||
124 | {0x6000, 0x00ff}, {0x6002, 0x007c}, {0x6000, 0x007d}, | ||
125 | /* gam=32/64 */ | ||
126 | {0x6000, 0x00ff}, {0x6008, 0x007c}, {0x6020, 0x007d}, | ||
127 | /* image right up */ | ||
128 | {0xffff, 0xffff}, | ||
129 | {15, 0xffff}, | ||
130 | {0x6001, 0x00ff}, {0x6000, 0x8004}, | ||
131 | {0xffff, 0xffff}, | ||
132 | {0x60a8, 0x0004}, | ||
133 | {15, 0xffff}, | ||
134 | {0x6001, 0x00ff}, {0x6000, 0x8004}, | ||
135 | {0xffff, 0xffff}, | ||
136 | {0x60f8, 0x0004}, | ||
137 | /* image right up */ | ||
138 | {0xffff, 0xffff}, | ||
139 | /* backlight=31/64 */ | ||
140 | {0x6001, 0x00ff}, {0x603e, 0x0024}, {0x6034, 0x0025}, | ||
141 | }; | ||
142 | |||
143 | static struct validx tbl_640[] = { | ||
144 | {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1}, | ||
145 | {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, | ||
146 | {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017}, | ||
147 | {0x6075, 0x0018}, {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, | ||
148 | {0x60bb, 0x004f}, {0x6057, 0x005a}, {0x609c, 0x0050}, {0x6080, 0x006d}, | ||
149 | {0x6092, 0x0026}, {0x60ff, 0x0020}, {0x6000, 0x0027}, {0x6000, 0x00ff}, | ||
150 | {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, {0x603d, 0x0086}, | ||
151 | {0x6089, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, {0x6000, 0x0053}, | ||
152 | {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, {0x60a0, 0x005a}, | ||
153 | {0x6078, 0x005b}, {0x6000, 0x005c}, {0x6004, 0x00d3}, {0x6000, 0x00e0}, | ||
154 | {0x60ff, 0x00dd}, {0x60a1, 0x005a}, | ||
155 | }; | ||
156 | |||
157 | static struct validx tbl_800[] = { | ||
158 | {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1}, | ||
159 | {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, | ||
160 | {0x6001, 0x00ff}, {0x6040, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017}, | ||
161 | {0x6043, 0x0018}, {0x6000, 0x0019}, {0x604b, 0x001a}, {0x6009, 0x0032}, | ||
162 | {0x60ca, 0x004f}, {0x60a8, 0x0050}, {0x6000, 0x006d}, {0x6038, 0x003d}, | ||
163 | {0x60c8, 0x0035}, {0x6000, 0x0022}, {0x6092, 0x0026}, {0x60ff, 0x0020}, | ||
164 | {0x6000, 0x0027}, {0x6000, 0x00ff}, {0x6064, 0x00c0}, {0x604b, 0x00c1}, | ||
165 | {0x6000, 0x008c}, {0x601d, 0x0086}, {0x6082, 0x00d3}, {0x6000, 0x00e0}, | ||
166 | {0x60ff, 0x00dd}, {0x6020, 0x008c}, {0x6001, 0x00ff}, {0x6044, 0x0018}, | ||
167 | }; | ||
168 | |||
169 | static struct validx tbl_big_a[] = { | ||
170 | {0x0002, 0x00c1}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, | ||
171 | {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, | ||
172 | {0x6000, 0x0010}, {0x6000, 0x0011}, {0x6011, 0x0017}, {0x6075, 0x0018}, | ||
173 | {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, {0x60bb, 0x004f}, | ||
174 | {0x609c, 0x0050}, {0x6057, 0x005a}, {0x6080, 0x006d}, {0x6043, 0x000f}, | ||
175 | {0x608f, 0x0003}, {0x6005, 0x007c}, {0x6081, 0x0026}, {0x6000, 0x00ff}, | ||
176 | {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, | ||
177 | }; | ||
178 | |||
179 | static struct validx tbl_big_b[] = { | ||
180 | {0x603d, 0x0086}, {0x6000, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, | ||
181 | {0x6000, 0x0053}, {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, | ||
182 | {0x6040, 0x005a}, {0x60f0, 0x005b}, {0x6001, 0x005c}, {0x6082, 0x00d3}, | ||
183 | {0x6000, 0x008e}, | ||
184 | }; | ||
185 | |||
186 | static struct validx tbl_big_c[] = { | ||
187 | {0x6004, 0x00da}, {0x6000, 0x00e0}, {0x6067, 0x00e1}, {0x60ff, 0x00dd}, | ||
188 | {0x6001, 0x00ff}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, | ||
189 | {0x6001, 0x00ff}, {0x6000, 0x0011}, {0x6000, 0x00ff}, {0x6010, 0x00c7}, | ||
190 | {0x6000, 0x0092}, {0x6006, 0x0093}, {0x60e3, 0x0093}, {0x6005, 0x0093}, | ||
191 | {0x6005, 0x0093}, {0x60ed, 0x00c3}, {0x6000, 0x00a4}, {0x60d0, 0x0087}, | ||
192 | {0x6003, 0x0096}, {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, | ||
193 | {0x6028, 0x0097}, {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6001, 0x00ff}, | ||
194 | {0x6043, 0x000f}, {0x608f, 0x0003}, {0x6000, 0x002d}, {0x6000, 0x002e}, | ||
195 | {0x600a, 0x0022}, {0x6002, 0x0070}, {0x6008, 0x0014}, {0x6048, 0x0014}, | ||
196 | {0x6000, 0x00ff}, {0x6000, 0x00e0}, {0x60ff, 0x00dd}, | ||
197 | }; | ||
198 | |||
199 | static struct validx tbl_post_unset_alt[] = { | ||
200 | {0x006a, 0x000d}, {0x6001, 0x00ff}, {0x6081, 0x0026}, {0x6000, 0x0000}, | ||
201 | {0x6000, 0x0045}, {0x6000, 0x0010}, {0x6068, 0x000d}, | ||
202 | {50, 0xffff}, | ||
203 | {0x0021, 0x0000}, | ||
204 | }; | ||
205 | |||
206 | static int ov2640_init_at_startup(struct gspca_dev *gspca_dev); | ||
207 | static int ov2640_configure_alt(struct gspca_dev *gspca_dev); | ||
208 | static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev); | ||
209 | static int ov2640_init_post_alt(struct gspca_dev *gspca_dev); | ||
210 | static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev); | ||
211 | static int ov2640_camera_settings(struct gspca_dev *gspca_dev); | ||
212 | /*==========================================================================*/ | ||
213 | |||
214 | void ov2640_init_settings(struct gspca_dev *gspca_dev) | ||
215 | { | ||
216 | struct sd *sd = (struct sd *) gspca_dev; | ||
217 | |||
218 | sd->vcur.backlight = 32; | ||
219 | sd->vcur.brightness = 0; | ||
220 | sd->vcur.sharpness = 6; | ||
221 | sd->vcur.contrast = 0; | ||
222 | sd->vcur.gamma = 32; | ||
223 | sd->vcur.hue = 0; | ||
224 | sd->vcur.saturation = 128; | ||
225 | sd->vcur.whitebal = 64; | ||
226 | |||
227 | sd->vmax.backlight = 64; | ||
228 | sd->vmax.brightness = 255; | ||
229 | sd->vmax.sharpness = 31; | ||
230 | sd->vmax.contrast = 255; | ||
231 | sd->vmax.gamma = 64; | ||
232 | sd->vmax.hue = 255 + 1; | ||
233 | sd->vmax.saturation = 255; | ||
234 | sd->vmax.whitebal = 128; | ||
235 | sd->vmax.mirror = 0; | ||
236 | sd->vmax.flip = 0; | ||
237 | sd->vmax.AC50Hz = 0; | ||
238 | |||
239 | sd->dev_camera_settings = ov2640_camera_settings; | ||
240 | sd->dev_init_at_startup = ov2640_init_at_startup; | ||
241 | sd->dev_configure_alt = ov2640_configure_alt; | ||
242 | sd->dev_init_pre_alt = ov2640_init_pre_alt; | ||
243 | sd->dev_post_unset_alt = ov2640_post_unset_alt; | ||
244 | } | ||
245 | |||
246 | /*==========================================================================*/ | ||
247 | |||
248 | static void common(struct gspca_dev *gspca_dev) | ||
249 | { | ||
250 | fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common)); | ||
251 | } | ||
252 | |||
253 | static int ov2640_init_at_startup(struct gspca_dev *gspca_dev) | ||
254 | { | ||
255 | fetch_validx(gspca_dev, tbl_init_at_startup, | ||
256 | ARRAY_SIZE(tbl_init_at_startup)); | ||
257 | |||
258 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_init1); | ||
259 | |||
260 | common(gspca_dev); | ||
261 | |||
262 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, dat_init2); | ||
263 | |||
264 | ctrl_out(gspca_dev, 0x40, 1, 0x00ef, 0x0006, 0, NULL); | ||
265 | |||
266 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, dat_init3); | ||
267 | |||
268 | ctrl_out(gspca_dev, 0x40, 1, 0x0051, 0x0000, 0, NULL); | ||
269 | /* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev) | ||
275 | { | ||
276 | struct sd *sd = (struct sd *) gspca_dev; | ||
277 | |||
278 | sd->vold.backlight = -1; | ||
279 | sd->vold.brightness = -1; | ||
280 | sd->vold.sharpness = -1; | ||
281 | sd->vold.contrast = -1; | ||
282 | sd->vold.saturation = -1; | ||
283 | sd->vold.gamma = -1; | ||
284 | sd->vold.hue = -1; | ||
285 | sd->vold.whitebal = -1; | ||
286 | |||
287 | ov2640_init_post_alt(gspca_dev); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int ov2640_init_post_alt(struct gspca_dev *gspca_dev) | ||
293 | { | ||
294 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
295 | s32 n; /* reserved for FETCH macros */ | ||
296 | |||
297 | ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); | ||
298 | |||
299 | n = fetch_validx(gspca_dev, tbl_sensor_settings_common_a, | ||
300 | ARRAY_SIZE(tbl_sensor_settings_common_a)); | ||
301 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_post); | ||
302 | common(gspca_dev); | ||
303 | keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_a, | ||
304 | ARRAY_SIZE(tbl_sensor_settings_common_a), n); | ||
305 | |||
306 | switch (reso) { | ||
307 | case IMAGE_640: | ||
308 | n = fetch_validx(gspca_dev, tbl_640, ARRAY_SIZE(tbl_640)); | ||
309 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_640); | ||
310 | break; | ||
311 | |||
312 | case IMAGE_800: | ||
313 | n = fetch_validx(gspca_dev, tbl_800, ARRAY_SIZE(tbl_800)); | ||
314 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_800); | ||
315 | break; | ||
316 | |||
317 | case IMAGE_1600: | ||
318 | case IMAGE_1280: | ||
319 | n = fetch_validx(gspca_dev, tbl_big_a, ARRAY_SIZE(tbl_big_a)); | ||
320 | |||
321 | if (reso == IMAGE_1280) { | ||
322 | n = fetch_validx(gspca_dev, tbl_big_b, | ||
323 | ARRAY_SIZE(tbl_big_b)); | ||
324 | } else { | ||
325 | ctrl_out(gspca_dev, 0x40, 1, 0x601d, 0x0086, 0, NULL); | ||
326 | ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00d7, 0, NULL); | ||
327 | ctrl_out(gspca_dev, 0x40, 1, 0x6082, 0x00d3, 0, NULL); | ||
328 | } | ||
329 | |||
330 | n = fetch_validx(gspca_dev, tbl_big_c, ARRAY_SIZE(tbl_big_c)); | ||
331 | |||
332 | if (reso == IMAGE_1280) { | ||
333 | ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); | ||
334 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
335 | 12, dat_1280); | ||
336 | } else { | ||
337 | ctrl_out(gspca_dev, 0x40, 1, 0x6020, 0x008c, 0, NULL); | ||
338 | ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); | ||
339 | ctrl_out(gspca_dev, 0x40, 1, 0x6076, 0x0018, 0, NULL); | ||
340 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
341 | 12, dat_1600); | ||
342 | } | ||
343 | break; | ||
344 | } | ||
345 | |||
346 | n = fetch_validx(gspca_dev, tbl_sensor_settings_common_b, | ||
347 | ARRAY_SIZE(tbl_sensor_settings_common_b)); | ||
348 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50); | ||
349 | keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b, | ||
350 | ARRAY_SIZE(tbl_sensor_settings_common_b), n); | ||
351 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28); | ||
352 | keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b, | ||
353 | ARRAY_SIZE(tbl_sensor_settings_common_b), n); | ||
354 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8); | ||
355 | keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b, | ||
356 | ARRAY_SIZE(tbl_sensor_settings_common_b), n); | ||
357 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50); | ||
358 | keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b, | ||
359 | ARRAY_SIZE(tbl_sensor_settings_common_b), n); | ||
360 | |||
361 | ov2640_camera_settings(gspca_dev); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int ov2640_configure_alt(struct gspca_dev *gspca_dev) | ||
367 | { | ||
368 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
369 | |||
370 | switch (reso) { | ||
371 | case IMAGE_640: | ||
372 | gspca_dev->alt = 3 + 1; | ||
373 | break; | ||
374 | |||
375 | case IMAGE_800: | ||
376 | case IMAGE_1280: | ||
377 | case IMAGE_1600: | ||
378 | gspca_dev->alt = 1 + 1; | ||
379 | break; | ||
380 | } | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int ov2640_camera_settings(struct gspca_dev *gspca_dev) | ||
385 | { | ||
386 | struct sd *sd = (struct sd *) gspca_dev; | ||
387 | |||
388 | s32 backlight = sd->vcur.backlight; | ||
389 | s32 bright = sd->vcur.brightness; | ||
390 | s32 sharp = sd->vcur.sharpness; | ||
391 | s32 gam = sd->vcur.gamma; | ||
392 | s32 cntr = sd->vcur.contrast; | ||
393 | s32 sat = sd->vcur.saturation; | ||
394 | s32 hue = sd->vcur.hue; | ||
395 | s32 wbal = sd->vcur.whitebal; | ||
396 | |||
397 | if (backlight != sd->vold.backlight) { | ||
398 | if (backlight < 0 || backlight > sd->vmax.backlight) | ||
399 | backlight = 0; | ||
400 | |||
401 | ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff, | ||
402 | 0, NULL); | ||
403 | ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight , 0x0024, | ||
404 | 0, NULL); | ||
405 | ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight - 10, 0x0025, | ||
406 | 0, NULL); | ||
407 | /* No sd->vold.backlight=backlight; (to be done again later) */ | ||
408 | } | ||
409 | |||
410 | if (bright != sd->vold.brightness) { | ||
411 | sd->vold.brightness = bright; | ||
412 | if (bright < 0 || bright > sd->vmax.brightness) | ||
413 | bright = 0; | ||
414 | |||
415 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); | ||
416 | ctrl_out(gspca_dev, 0x40, 1, 0x6009 , 0x007c, 0, NULL); | ||
417 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 + bright, 0x007d, 0, NULL); | ||
418 | } | ||
419 | |||
420 | if (wbal != sd->vold.whitebal) { | ||
421 | sd->vold.whitebal = wbal; | ||
422 | if (wbal < 0 || wbal > sd->vmax.whitebal) | ||
423 | wbal = 0; | ||
424 | |||
425 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); | ||
426 | ctrl_out(gspca_dev, 0x40, 1, 0x6003 , 0x007c, 0, NULL); | ||
427 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 + wbal, 0x007d, 0, NULL); | ||
428 | } | ||
429 | |||
430 | if (cntr != sd->vold.contrast) { | ||
431 | sd->vold.contrast = cntr; | ||
432 | if (cntr < 0 || cntr > sd->vmax.contrast) | ||
433 | cntr = 0; | ||
434 | |||
435 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); | ||
436 | ctrl_out(gspca_dev, 0x40, 1, 0x6007 , 0x007c, 0, NULL); | ||
437 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 + cntr, 0x007d, 0, NULL); | ||
438 | } | ||
439 | |||
440 | if (sat != sd->vold.saturation) { | ||
441 | sd->vold.saturation = sat; | ||
442 | if (sat < 0 || sat > sd->vmax.saturation) | ||
443 | sat = 0; | ||
444 | |||
445 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); | ||
446 | ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x007c, 0, NULL); | ||
447 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 + sat, 0x007d, 0, NULL); | ||
448 | } | ||
449 | |||
450 | if (sharp != sd->vold.sharpness) { | ||
451 | sd->vold.sharpness = sharp; | ||
452 | if (sharp < 0 || sharp > sd->vmax.sharpness) | ||
453 | sharp = 0; | ||
454 | |||
455 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); | ||
456 | ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x0092, 0, NULL); | ||
457 | ctrl_out(gspca_dev, 0x40, 1, 0x60c0 + sharp, 0x0093, 0, NULL); | ||
458 | } | ||
459 | |||
460 | if (hue != sd->vold.hue) { | ||
461 | sd->vold.hue = hue; | ||
462 | if (hue < 0 || hue > sd->vmax.hue) | ||
463 | hue = 0; | ||
464 | |||
465 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); | ||
466 | ctrl_out(gspca_dev, 0x40, 1, 0x6002 , 0x007c, 0, NULL); | ||
467 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 + hue * (hue < 255), 0x007d, | ||
468 | 0, NULL); | ||
469 | if (hue >= sd->vmax.hue) | ||
470 | sd->swapRB = 1; | ||
471 | else | ||
472 | sd->swapRB = 0; | ||
473 | } | ||
474 | |||
475 | if (gam != sd->vold.gamma) { | ||
476 | sd->vold.gamma = gam; | ||
477 | if (gam < 0 || gam > sd->vmax.gamma) | ||
478 | gam = 0; | ||
479 | |||
480 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); | ||
481 | ctrl_out(gspca_dev, 0x40, 1, 0x6008 , 0x007c, 0, NULL); | ||
482 | ctrl_out(gspca_dev, 0x40, 1, 0x6000 + gam, 0x007d, 0, NULL); | ||
483 | } | ||
484 | |||
485 | if (backlight != sd->vold.backlight) { | ||
486 | sd->vold.backlight = backlight; | ||
487 | |||
488 | ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff, | ||
489 | 0, NULL); | ||
490 | ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight , 0x0024, | ||
491 | 0, NULL); | ||
492 | ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight - 10, 0x0025, | ||
493 | 0, NULL); | ||
494 | } | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev) | ||
500 | { | ||
501 | ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); | ||
502 | msleep(20); | ||
503 | fetch_validx(gspca_dev, tbl_post_unset_alt, | ||
504 | ARRAY_SIZE(tbl_post_unset_alt)); | ||
505 | } | ||
diff --git a/drivers/media/video/gspca/gl860/gl860-ov9655.c b/drivers/media/video/gspca/gl860/gl860-ov9655.c new file mode 100644 index 000000000000..eda3346f939c --- /dev/null +++ b/drivers/media/video/gspca/gl860/gl860-ov9655.c | |||
@@ -0,0 +1,337 @@ | |||
1 | /* @file gl860-ov9655.c | ||
2 | * @author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt | ||
3 | * on dsd's weblog | ||
4 | * @date 2009-08-27 | ||
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 | * 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 | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | /* Sensor : OV9655 */ | ||
21 | |||
22 | #include "gl860.h" | ||
23 | |||
24 | static struct validx tbl_init_at_startup[] = { | ||
25 | {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, | ||
26 | {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, | ||
27 | |||
28 | {0x0040, 0x0000}, | ||
29 | }; | ||
30 | |||
31 | static struct validx tbl_commmon[] = { | ||
32 | {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, | ||
33 | {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2}, | ||
34 | {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0040, 0x0000}, | ||
35 | {0x00f3, 0x0006}, {0x0058, 0x0000}, {0x0048, 0x0000}, {0x0061, 0x0000}, | ||
36 | }; | ||
37 | |||
38 | static s32 tbl_length[] = {12, 56, 52, 54, 56, 42, 32, 12}; | ||
39 | |||
40 | static u8 *tbl_640[] = { | ||
41 | "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" | ||
42 | , | ||
43 | "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x03\x0b\x57\x0e\x61" | ||
44 | "\x0f\x42\x11\x01\x12\x60\x13\x00" "\x14\x3a\x16\x24\x17\x14\x18\x00" | ||
45 | "\x19\x01\x1a\x3d\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" | ||
46 | "\x29\x15\x2a\x00\x2b\x00\x2c\x08" | ||
47 | , | ||
48 | "\x32\xff\x33\x00\x34\x3d\x35\x00" "\x36\xfa\x38\x72\x39\x57\x3a\x00" | ||
49 | "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc1" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" | ||
50 | "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xee\x4b\xe7\x4c\xe7" | ||
51 | "\x4d\xe7\x4e\xe7" | ||
52 | , | ||
53 | "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" | ||
54 | "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" | ||
55 | "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x0a\x6b\x5a\x6c\x04" | ||
56 | "\x6d\x55\x6e\x00\x6f\x9d" | ||
57 | , | ||
58 | "\x70\x15\x71\x78\x72\x00\x73\x00" "\x74\x3a\x75\x35\x76\x01\x77\x02" | ||
59 | "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" | ||
60 | "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" | ||
61 | "\x8a\x23\x8c\x8d\x90\x7c\x91\x7b" | ||
62 | , | ||
63 | "\x9d\x02\x9e\x02\x9f\x74\xa0\x73" "\xa1\x40\xa4\x50\xa5\x68\xa6\x70" | ||
64 | "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" | ||
65 | "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" | ||
66 | , | ||
67 | "\xbb\xae\xbc\x4f\xbd\x4e\xbe\x6a" "\xbf\x68\xc0\xaa\xc1\xc0\xc2\x01" | ||
68 | "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" | ||
69 | , | ||
70 | "\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80" | ||
71 | }; | ||
72 | |||
73 | static u8 *tbl_800[] = { | ||
74 | "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" | ||
75 | , | ||
76 | "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61" | ||
77 | "\x0f\x42\x11\x00\x12\x00\x13\x00" "\x14\x3a\x16\x24\x17\x1b\x18\xbb" | ||
78 | "\x19\x01\x1a\x81\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" | ||
79 | "\x29\x15\x2a\x00\x2b\x00\x2c\x08" | ||
80 | , | ||
81 | "\x32\xa4\x33\x00\x34\x3d\x35\x00" "\x36\xf8\x38\x72\x39\x57\x3a\x00" | ||
82 | "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc2" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" | ||
83 | "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xec\x4b\xe8\x4c\xe8" | ||
84 | "\x4d\xe8\x4e\xe8" | ||
85 | , | ||
86 | "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" | ||
87 | "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" | ||
88 | "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x02\x6b\x5a\x6c\x04" | ||
89 | "\x6d\x55\x6e\x00\x6f\x9d" | ||
90 | , | ||
91 | "\x70\x08\x71\x78\x72\x00\x73\x01" "\x74\x3a\x75\x35\x76\x01\x77\x02" | ||
92 | "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" | ||
93 | "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" | ||
94 | "\x8a\x23\x8c\x0d\x90\x90\x91\x90" | ||
95 | , | ||
96 | "\x9d\x02\x9e\x02\x9f\x94\xa0\x94" "\xa1\x01\xa4\x50\xa5\x68\xa6\x70" | ||
97 | "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" | ||
98 | "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" | ||
99 | , | ||
100 | "\xbb\xae\xbc\x38\xbd\x39\xbe\x01" "\xbf\x01\xc0\xe2\xc1\xc0\xc2\x01" | ||
101 | "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" | ||
102 | , | ||
103 | "\xd0\x21\xd1\x18\xd2\xe0\xd3\x01" "\xd4\x28\xd5\x00" | ||
104 | }; | ||
105 | |||
106 | static u8 c04[] = {0x04}; | ||
107 | static u8 dat_post_1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02"; | ||
108 | static u8 dat_post_2[] = "\x10\x10\xc1\x02"; | ||
109 | static u8 dat_post_3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04"; | ||
110 | static u8 dat_post_4[] = "\x10\x02\xc1\x06"; | ||
111 | static u8 dat_post_5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08"; | ||
112 | static u8 dat_post_6[] = "\x10\x10\xc1\x05"; | ||
113 | static u8 dat_post_7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08"; | ||
114 | static u8 dat_post_8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09"; | ||
115 | |||
116 | static struct validx tbl_init_post_alt[] = { | ||
117 | {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x603c, 0x00ff}, | ||
118 | {0x6003, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6001, 0x00ff}, | ||
119 | {0x6000, 0x801e}, | ||
120 | {0xffff, 0xffff}, | ||
121 | {0x6004, 0x001e}, {0x6000, 0x801e}, | ||
122 | {0xffff, 0xffff}, | ||
123 | {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e}, | ||
124 | {0xffff, 0xffff}, | ||
125 | {0x6004, 0x001e}, {0x6000, 0x801e}, | ||
126 | {0xffff, 0xffff}, | ||
127 | {0x6004, 0x001e}, {0x6012, 0x0003}, | ||
128 | {0xffff, 0xffff}, | ||
129 | {0x6000, 0x801e}, | ||
130 | {0xffff, 0xffff}, | ||
131 | {0x6004, 0x001e}, {0x6000, 0x801e}, | ||
132 | {0xffff, 0xffff}, | ||
133 | {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e}, | ||
134 | {0xffff, 0xffff}, | ||
135 | {0x6004, 0x001e}, {0x6000, 0x801e}, | ||
136 | {0xffff, 0xffff}, | ||
137 | {0x6004, 0x001e}, {0x6012, 0x0003}, | ||
138 | {0xffff, 0xffff}, | ||
139 | {0x6000, 0x801e}, | ||
140 | {0xffff, 0xffff}, | ||
141 | {0x6004, 0x001e}, {0x6000, 0x801e}, | ||
142 | {0xffff, 0xffff}, | ||
143 | {0x6004, 0x001e}, {0x6012, 0x0003}, | ||
144 | }; | ||
145 | |||
146 | static int ov9655_init_at_startup(struct gspca_dev *gspca_dev); | ||
147 | static int ov9655_configure_alt(struct gspca_dev *gspca_dev); | ||
148 | static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev); | ||
149 | static int ov9655_init_post_alt(struct gspca_dev *gspca_dev); | ||
150 | static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev); | ||
151 | static int ov9655_camera_settings(struct gspca_dev *gspca_dev); | ||
152 | /*==========================================================================*/ | ||
153 | |||
154 | void ov9655_init_settings(struct gspca_dev *gspca_dev) | ||
155 | { | ||
156 | struct sd *sd = (struct sd *) gspca_dev; | ||
157 | |||
158 | sd->vcur.backlight = 0; | ||
159 | sd->vcur.brightness = 128; | ||
160 | sd->vcur.sharpness = 0; | ||
161 | sd->vcur.contrast = 0; | ||
162 | sd->vcur.gamma = 0; | ||
163 | sd->vcur.hue = 0; | ||
164 | sd->vcur.saturation = 0; | ||
165 | sd->vcur.whitebal = 0; | ||
166 | |||
167 | sd->vmax.backlight = 0; | ||
168 | sd->vmax.brightness = 255; | ||
169 | sd->vmax.sharpness = 0; | ||
170 | sd->vmax.contrast = 0; | ||
171 | sd->vmax.gamma = 0; | ||
172 | sd->vmax.hue = 0 + 1; | ||
173 | sd->vmax.saturation = 0; | ||
174 | sd->vmax.whitebal = 0; | ||
175 | sd->vmax.mirror = 0; | ||
176 | sd->vmax.flip = 0; | ||
177 | sd->vmax.AC50Hz = 0; | ||
178 | |||
179 | sd->dev_camera_settings = ov9655_camera_settings; | ||
180 | sd->dev_init_at_startup = ov9655_init_at_startup; | ||
181 | sd->dev_configure_alt = ov9655_configure_alt; | ||
182 | sd->dev_init_pre_alt = ov9655_init_pre_alt; | ||
183 | sd->dev_post_unset_alt = ov9655_post_unset_alt; | ||
184 | } | ||
185 | |||
186 | /*==========================================================================*/ | ||
187 | |||
188 | static int ov9655_init_at_startup(struct gspca_dev *gspca_dev) | ||
189 | { | ||
190 | fetch_validx(gspca_dev, tbl_init_at_startup, | ||
191 | ARRAY_SIZE(tbl_init_at_startup)); | ||
192 | fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon)); | ||
193 | /* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL);*/ | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev) | ||
199 | { | ||
200 | struct sd *sd = (struct sd *) gspca_dev; | ||
201 | |||
202 | sd->vold.brightness = -1; | ||
203 | sd->vold.hue = -1; | ||
204 | |||
205 | fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon)); | ||
206 | |||
207 | ov9655_init_post_alt(gspca_dev); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int ov9655_init_post_alt(struct gspca_dev *gspca_dev) | ||
213 | { | ||
214 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
215 | s32 n; /* reserved for FETCH macros */ | ||
216 | s32 i; | ||
217 | u8 **tbl; | ||
218 | |||
219 | ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); | ||
220 | |||
221 | tbl = (reso == IMAGE_640) ? tbl_640 : tbl_800; | ||
222 | |||
223 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
224 | tbl_length[0], tbl[0]); | ||
225 | for (i = 1; i < 7; i++) | ||
226 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, | ||
227 | tbl_length[i], tbl[i]); | ||
228 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, | ||
229 | tbl_length[7], tbl[7]); | ||
230 | |||
231 | n = fetch_validx(gspca_dev, tbl_init_post_alt, | ||
232 | ARRAY_SIZE(tbl_init_post_alt)); | ||
233 | |||
234 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
235 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
236 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
237 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
238 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
239 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
240 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
241 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
242 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
243 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
244 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
245 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
246 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1); | ||
247 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
248 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
249 | |||
250 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
251 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
252 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
253 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
254 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
255 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
256 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
257 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
258 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
259 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
260 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
261 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
262 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1); | ||
263 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
264 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
265 | |||
266 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
267 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
268 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
269 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); | ||
270 | keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, | ||
271 | ARRAY_SIZE(tbl_init_post_alt), n); | ||
272 | |||
273 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1); | ||
274 | |||
275 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_2); | ||
276 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_3); | ||
277 | |||
278 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_4); | ||
279 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_5); | ||
280 | |||
281 | ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_6); | ||
282 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_7); | ||
283 | |||
284 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_8); | ||
285 | |||
286 | ov9655_camera_settings(gspca_dev); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int ov9655_configure_alt(struct gspca_dev *gspca_dev) | ||
292 | { | ||
293 | s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; | ||
294 | |||
295 | switch (reso) { | ||
296 | case IMAGE_640: | ||
297 | gspca_dev->alt = 1 + 1; | ||
298 | break; | ||
299 | |||
300 | default: | ||
301 | gspca_dev->alt = 1 + 1; | ||
302 | break; | ||
303 | } | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int ov9655_camera_settings(struct gspca_dev *gspca_dev) | ||
308 | { | ||
309 | struct sd *sd = (struct sd *) gspca_dev; | ||
310 | |||
311 | u8 dat_bright[] = "\x04\x00\x10\x7c\xa1\x00\x00\x70"; | ||
312 | |||
313 | s32 bright = sd->vcur.brightness; | ||
314 | s32 hue = sd->vcur.hue; | ||
315 | |||
316 | if (bright != sd->vold.brightness) { | ||
317 | sd->vold.brightness = bright; | ||
318 | if (bright < 0 || bright > sd->vmax.brightness) | ||
319 | bright = 0; | ||
320 | |||
321 | dat_bright[3] = bright; | ||
322 | ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_bright); | ||
323 | } | ||
324 | |||
325 | if (hue != sd->vold.hue) { | ||
326 | sd->vold.hue = hue; | ||
327 | sd->swapRB = (hue != 0); | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev) | ||
334 | { | ||
335 | ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); | ||
336 | ctrl_out(gspca_dev, 0x40, 1, 0x0061, 0x0000, 0, NULL); | ||
337 | } | ||
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c new file mode 100644 index 000000000000..6ef59ac7f502 --- /dev/null +++ b/drivers/media/video/gspca/gl860/gl860.c | |||
@@ -0,0 +1,785 @@ | |||
1 | /* @file gl860.c | ||
2 | * @date 2009-08-27 | ||
3 | * | ||
4 | * Genesys Logic webcam with gl860 subdrivers | ||
5 | * | ||
6 | * Driver by Olivier Lorin <o.lorin@laposte.net> | ||
7 | * GSPCA by Jean-Francois Moine <http://moinejf.free.fr> | ||
8 | * Thanks BUGabundo and Malmostoso for your amazing help! | ||
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 | * 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, see <http://www.gnu.org/licenses/>. | ||
22 | */ | ||
23 | #include "gspca.h" | ||
24 | #include "gl860.h" | ||
25 | |||
26 | MODULE_AUTHOR("Olivier Lorin <lorin@laposte.net>"); | ||
27 | MODULE_DESCRIPTION("GSPCA/Genesys Logic GL860 USB Camera Driver"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | /*======================== static function declarations ====================*/ | ||
31 | |||
32 | static void (*dev_init_settings)(struct gspca_dev *gspca_dev); | ||
33 | |||
34 | static int sd_config(struct gspca_dev *gspca_dev, | ||
35 | const struct usb_device_id *id); | ||
36 | static int sd_init(struct gspca_dev *gspca_dev); | ||
37 | static int sd_isoc_init(struct gspca_dev *gspca_dev); | ||
38 | static int sd_start(struct gspca_dev *gspca_dev); | ||
39 | static void sd_stop0(struct gspca_dev *gspca_dev); | ||
40 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
41 | struct gspca_frame *frame, u8 *data, s32 len); | ||
42 | static void sd_callback(struct gspca_dev *gspca_dev); | ||
43 | |||
44 | static int gl860_guess_sensor(struct gspca_dev *gspca_dev, | ||
45 | s32 vendor_id, s32 product_id); | ||
46 | |||
47 | /*============================ driver options ==============================*/ | ||
48 | |||
49 | static s32 AC50Hz = 0xff; | ||
50 | module_param(AC50Hz, int, 0644); | ||
51 | MODULE_PARM_DESC(AC50Hz, " Does AC power frequency is 50Hz? (0/1)"); | ||
52 | |||
53 | static char sensor[7]; | ||
54 | module_param_string(sensor, sensor, sizeof(sensor), 0644); | ||
55 | MODULE_PARM_DESC(sensor, | ||
56 | " Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640'/'')"); | ||
57 | |||
58 | /*============================ webcam controls =============================*/ | ||
59 | |||
60 | /* Functions to get and set a control value */ | ||
61 | #define SD_SETGET(thename) \ | ||
62 | static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\ | ||
63 | {\ | ||
64 | struct sd *sd = (struct sd *) gspca_dev;\ | ||
65 | \ | ||
66 | sd->vcur.thename = val;\ | ||
67 | if (gspca_dev->streaming)\ | ||
68 | sd->dev_camera_settings(gspca_dev);\ | ||
69 | return 0;\ | ||
70 | } \ | ||
71 | static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\ | ||
72 | {\ | ||
73 | struct sd *sd = (struct sd *) gspca_dev;\ | ||
74 | \ | ||
75 | *val = sd->vcur.thename;\ | ||
76 | return 0;\ | ||
77 | } | ||
78 | |||
79 | SD_SETGET(mirror) | ||
80 | SD_SETGET(flip) | ||
81 | SD_SETGET(AC50Hz) | ||
82 | SD_SETGET(backlight) | ||
83 | SD_SETGET(brightness) | ||
84 | SD_SETGET(gamma) | ||
85 | SD_SETGET(hue) | ||
86 | SD_SETGET(saturation) | ||
87 | SD_SETGET(sharpness) | ||
88 | SD_SETGET(whitebal) | ||
89 | SD_SETGET(contrast) | ||
90 | |||
91 | #define GL860_NCTRLS 11 | ||
92 | |||
93 | /* control table */ | ||
94 | static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS]; | ||
95 | static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS]; | ||
96 | static struct ctrl sd_ctrls_mi2020b[GL860_NCTRLS]; | ||
97 | static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS]; | ||
98 | static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS]; | ||
99 | |||
100 | #define SET_MY_CTRL(theid, \ | ||
101 | thetype, thelabel, thename) \ | ||
102 | if (sd->vmax.thename != 0) {\ | ||
103 | sd_ctrls[nCtrls].qctrl.id = theid;\ | ||
104 | sd_ctrls[nCtrls].qctrl.type = thetype;\ | ||
105 | strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\ | ||
106 | sd_ctrls[nCtrls].qctrl.minimum = 0;\ | ||
107 | sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\ | ||
108 | sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\ | ||
109 | sd_ctrls[nCtrls].qctrl.step = \ | ||
110 | (sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\ | ||
111 | sd_ctrls[nCtrls].set = sd_set_##thename;\ | ||
112 | sd_ctrls[nCtrls].get = sd_get_##thename;\ | ||
113 | nCtrls++;\ | ||
114 | } | ||
115 | |||
116 | static int gl860_build_control_table(struct gspca_dev *gspca_dev) | ||
117 | { | ||
118 | struct sd *sd = (struct sd *) gspca_dev; | ||
119 | struct ctrl *sd_ctrls; | ||
120 | int nCtrls = 0; | ||
121 | |||
122 | if (_MI1320_) | ||
123 | sd_ctrls = sd_ctrls_mi1320; | ||
124 | else if (_MI2020_) | ||
125 | sd_ctrls = sd_ctrls_mi2020; | ||
126 | else if (_MI2020b_) | ||
127 | sd_ctrls = sd_ctrls_mi2020b; | ||
128 | else if (_OV2640_) | ||
129 | sd_ctrls = sd_ctrls_ov2640; | ||
130 | else if (_OV9655_) | ||
131 | sd_ctrls = sd_ctrls_ov9655; | ||
132 | else | ||
133 | return 0; | ||
134 | |||
135 | memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl)); | ||
136 | |||
137 | SET_MY_CTRL(V4L2_CID_BRIGHTNESS, | ||
138 | V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness) | ||
139 | SET_MY_CTRL(V4L2_CID_SHARPNESS, | ||
140 | V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness) | ||
141 | SET_MY_CTRL(V4L2_CID_CONTRAST, | ||
142 | V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast) | ||
143 | SET_MY_CTRL(V4L2_CID_GAMMA, | ||
144 | V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma) | ||
145 | SET_MY_CTRL(V4L2_CID_HUE, | ||
146 | V4L2_CTRL_TYPE_INTEGER, "Palette", hue) | ||
147 | SET_MY_CTRL(V4L2_CID_SATURATION, | ||
148 | V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation) | ||
149 | SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE, | ||
150 | V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal) | ||
151 | SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION, | ||
152 | V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight) | ||
153 | |||
154 | SET_MY_CTRL(V4L2_CID_HFLIP, | ||
155 | V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror) | ||
156 | SET_MY_CTRL(V4L2_CID_VFLIP, | ||
157 | V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip) | ||
158 | SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY, | ||
159 | V4L2_CTRL_TYPE_BOOLEAN, "50Hz", AC50Hz) | ||
160 | |||
161 | return nCtrls; | ||
162 | } | ||
163 | |||
164 | /*==================== sud-driver structure initialisation =================*/ | ||
165 | |||
166 | static struct sd_desc sd_desc_mi1320 = { | ||
167 | .name = MODULE_NAME, | ||
168 | .ctrls = sd_ctrls_mi1320, | ||
169 | .nctrls = GL860_NCTRLS, | ||
170 | .config = sd_config, | ||
171 | .init = sd_init, | ||
172 | .isoc_init = sd_isoc_init, | ||
173 | .start = sd_start, | ||
174 | .stop0 = sd_stop0, | ||
175 | .pkt_scan = sd_pkt_scan, | ||
176 | .dq_callback = sd_callback, | ||
177 | }; | ||
178 | |||
179 | static struct sd_desc sd_desc_mi2020 = { | ||
180 | .name = MODULE_NAME, | ||
181 | .ctrls = sd_ctrls_mi2020, | ||
182 | .nctrls = GL860_NCTRLS, | ||
183 | .config = sd_config, | ||
184 | .init = sd_init, | ||
185 | .isoc_init = sd_isoc_init, | ||
186 | .start = sd_start, | ||
187 | .stop0 = sd_stop0, | ||
188 | .pkt_scan = sd_pkt_scan, | ||
189 | .dq_callback = sd_callback, | ||
190 | }; | ||
191 | |||
192 | static struct sd_desc sd_desc_mi2020b = { | ||
193 | .name = MODULE_NAME, | ||
194 | .ctrls = sd_ctrls_mi2020b, | ||
195 | .nctrls = GL860_NCTRLS, | ||
196 | .config = sd_config, | ||
197 | .init = sd_init, | ||
198 | .isoc_init = sd_isoc_init, | ||
199 | .start = sd_start, | ||
200 | .stop0 = sd_stop0, | ||
201 | .pkt_scan = sd_pkt_scan, | ||
202 | .dq_callback = sd_callback, | ||
203 | }; | ||
204 | |||
205 | static struct sd_desc sd_desc_ov2640 = { | ||
206 | .name = MODULE_NAME, | ||
207 | .ctrls = sd_ctrls_ov2640, | ||
208 | .nctrls = GL860_NCTRLS, | ||
209 | .config = sd_config, | ||
210 | .init = sd_init, | ||
211 | .isoc_init = sd_isoc_init, | ||
212 | .start = sd_start, | ||
213 | .stop0 = sd_stop0, | ||
214 | .pkt_scan = sd_pkt_scan, | ||
215 | .dq_callback = sd_callback, | ||
216 | }; | ||
217 | |||
218 | static struct sd_desc sd_desc_ov9655 = { | ||
219 | .name = MODULE_NAME, | ||
220 | .ctrls = sd_ctrls_ov9655, | ||
221 | .nctrls = GL860_NCTRLS, | ||
222 | .config = sd_config, | ||
223 | .init = sd_init, | ||
224 | .isoc_init = sd_isoc_init, | ||
225 | .start = sd_start, | ||
226 | .stop0 = sd_stop0, | ||
227 | .pkt_scan = sd_pkt_scan, | ||
228 | .dq_callback = sd_callback, | ||
229 | }; | ||
230 | |||
231 | /*=========================== sub-driver image sizes =======================*/ | ||
232 | |||
233 | static struct v4l2_pix_format mi2020_mode[] = { | ||
234 | { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
235 | .bytesperline = 640, | ||
236 | .sizeimage = 640 * 480, | ||
237 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
238 | .priv = 0 | ||
239 | }, | ||
240 | { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
241 | .bytesperline = 800, | ||
242 | .sizeimage = 800 * 600, | ||
243 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
244 | .priv = 1 | ||
245 | }, | ||
246 | {1280, 1024, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
247 | .bytesperline = 1280, | ||
248 | .sizeimage = 1280 * 1024, | ||
249 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
250 | .priv = 2 | ||
251 | }, | ||
252 | {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
253 | .bytesperline = 1600, | ||
254 | .sizeimage = 1600 * 1200, | ||
255 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
256 | .priv = 3 | ||
257 | }, | ||
258 | }; | ||
259 | |||
260 | static struct v4l2_pix_format ov2640_mode[] = { | ||
261 | { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
262 | .bytesperline = 640, | ||
263 | .sizeimage = 640 * 480, | ||
264 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
265 | .priv = 0 | ||
266 | }, | ||
267 | { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
268 | .bytesperline = 800, | ||
269 | .sizeimage = 800 * 600, | ||
270 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
271 | .priv = 1 | ||
272 | }, | ||
273 | {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
274 | .bytesperline = 1280, | ||
275 | .sizeimage = 1280 * 960, | ||
276 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
277 | .priv = 2 | ||
278 | }, | ||
279 | {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
280 | .bytesperline = 1600, | ||
281 | .sizeimage = 1600 * 1200, | ||
282 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
283 | .priv = 3 | ||
284 | }, | ||
285 | }; | ||
286 | |||
287 | static struct v4l2_pix_format mi1320_mode[] = { | ||
288 | { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
289 | .bytesperline = 640, | ||
290 | .sizeimage = 640 * 480, | ||
291 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
292 | .priv = 0 | ||
293 | }, | ||
294 | { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
295 | .bytesperline = 800, | ||
296 | .sizeimage = 800 * 600, | ||
297 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
298 | .priv = 1 | ||
299 | }, | ||
300 | {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
301 | .bytesperline = 1280, | ||
302 | .sizeimage = 1280 * 960, | ||
303 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
304 | .priv = 2 | ||
305 | }, | ||
306 | }; | ||
307 | |||
308 | static struct v4l2_pix_format ov9655_mode[] = { | ||
309 | { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
310 | .bytesperline = 640, | ||
311 | .sizeimage = 640 * 480, | ||
312 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
313 | .priv = 0 | ||
314 | }, | ||
315 | {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, | ||
316 | .bytesperline = 1280, | ||
317 | .sizeimage = 1280 * 960, | ||
318 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
319 | .priv = 1 | ||
320 | }, | ||
321 | }; | ||
322 | |||
323 | /*========================= sud-driver functions ===========================*/ | ||
324 | |||
325 | /* This function is called at probe time */ | ||
326 | static int sd_config(struct gspca_dev *gspca_dev, | ||
327 | const struct usb_device_id *id) | ||
328 | { | ||
329 | struct sd *sd = (struct sd *) gspca_dev; | ||
330 | struct cam *cam; | ||
331 | s32 vendor_id, product_id; | ||
332 | |||
333 | /* Get USB VendorID and ProductID */ | ||
334 | vendor_id = le16_to_cpu(id->idVendor); | ||
335 | product_id = le16_to_cpu(id->idProduct); | ||
336 | |||
337 | sd->nbRightUp = 1; | ||
338 | sd->nbIm = -1; | ||
339 | |||
340 | sd->sensor = 0xff; | ||
341 | if (strcmp(sensor, "MI1320") == 0) | ||
342 | sd->sensor = ID_MI1320; | ||
343 | else if (strcmp(sensor, "OV2640") == 0) | ||
344 | sd->sensor = ID_OV2640; | ||
345 | else if (strcmp(sensor, "OV9655") == 0) | ||
346 | sd->sensor = ID_OV9655; | ||
347 | else if (strcmp(sensor, "MI2020") == 0) | ||
348 | sd->sensor = ID_MI2020; | ||
349 | else if (strcmp(sensor, "MI2020b") == 0) | ||
350 | sd->sensor = ID_MI2020b; | ||
351 | |||
352 | /* Get sensor and set the suitable init/start/../stop functions */ | ||
353 | if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1) | ||
354 | return -1; | ||
355 | |||
356 | cam = &gspca_dev->cam; | ||
357 | gspca_dev->nbalt = 4; | ||
358 | |||
359 | switch (sd->sensor) { | ||
360 | case ID_MI1320: | ||
361 | gspca_dev->sd_desc = &sd_desc_mi1320; | ||
362 | cam->cam_mode = mi1320_mode; | ||
363 | cam->nmodes = ARRAY_SIZE(mi1320_mode); | ||
364 | dev_init_settings = mi1320_init_settings; | ||
365 | break; | ||
366 | |||
367 | case ID_MI2020: | ||
368 | gspca_dev->sd_desc = &sd_desc_mi2020; | ||
369 | cam->cam_mode = mi2020_mode; | ||
370 | cam->nmodes = ARRAY_SIZE(mi2020_mode); | ||
371 | dev_init_settings = mi2020_init_settings; | ||
372 | break; | ||
373 | |||
374 | case ID_MI2020b: | ||
375 | gspca_dev->sd_desc = &sd_desc_mi2020b; | ||
376 | cam->cam_mode = mi2020_mode; | ||
377 | cam->nmodes = ARRAY_SIZE(mi2020_mode); | ||
378 | dev_init_settings = mi2020_init_settings; | ||
379 | break; | ||
380 | |||
381 | case ID_OV2640: | ||
382 | gspca_dev->sd_desc = &sd_desc_ov2640; | ||
383 | cam->cam_mode = ov2640_mode; | ||
384 | cam->nmodes = ARRAY_SIZE(ov2640_mode); | ||
385 | dev_init_settings = ov2640_init_settings; | ||
386 | break; | ||
387 | |||
388 | case ID_OV9655: | ||
389 | gspca_dev->sd_desc = &sd_desc_ov9655; | ||
390 | cam->cam_mode = ov9655_mode; | ||
391 | cam->nmodes = ARRAY_SIZE(ov9655_mode); | ||
392 | dev_init_settings = ov9655_init_settings; | ||
393 | break; | ||
394 | } | ||
395 | |||
396 | dev_init_settings(gspca_dev); | ||
397 | if (AC50Hz != 0xff) | ||
398 | ((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz; | ||
399 | gl860_build_control_table(gspca_dev); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | /* This function is called at probe time after sd_config */ | ||
405 | static int sd_init(struct gspca_dev *gspca_dev) | ||
406 | { | ||
407 | struct sd *sd = (struct sd *) gspca_dev; | ||
408 | |||
409 | return sd->dev_init_at_startup(gspca_dev); | ||
410 | } | ||
411 | |||
412 | /* This function is called before to choose the alt setting */ | ||
413 | static int sd_isoc_init(struct gspca_dev *gspca_dev) | ||
414 | { | ||
415 | struct sd *sd = (struct sd *) gspca_dev; | ||
416 | |||
417 | return sd->dev_configure_alt(gspca_dev); | ||
418 | } | ||
419 | |||
420 | /* This function is called to start the webcam */ | ||
421 | static int sd_start(struct gspca_dev *gspca_dev) | ||
422 | { | ||
423 | struct sd *sd = (struct sd *) gspca_dev; | ||
424 | |||
425 | return sd->dev_init_pre_alt(gspca_dev); | ||
426 | } | ||
427 | |||
428 | /* This function is called to stop the webcam */ | ||
429 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
430 | { | ||
431 | struct sd *sd = (struct sd *) gspca_dev; | ||
432 | |||
433 | return sd->dev_post_unset_alt(gspca_dev); | ||
434 | } | ||
435 | |||
436 | /* This function is called when an image is being received */ | ||
437 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
438 | struct gspca_frame *frame, u8 *data, s32 len) | ||
439 | { | ||
440 | struct sd *sd = (struct sd *) gspca_dev; | ||
441 | static s32 nSkipped; | ||
442 | |||
443 | s32 mode = (s32) gspca_dev->curr_mode; | ||
444 | s32 nToSkip = | ||
445 | sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1); | ||
446 | |||
447 | /* Test only against 0202h, so endianess does not matter */ | ||
448 | switch (*(s16 *) data) { | ||
449 | case 0x0202: /* End of frame, start a new one */ | ||
450 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); | ||
451 | nSkipped = 0; | ||
452 | if (sd->nbIm >= 0 && sd->nbIm < 10) | ||
453 | sd->nbIm++; | ||
454 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0); | ||
455 | break; | ||
456 | |||
457 | default: | ||
458 | data += 2; | ||
459 | len -= 2; | ||
460 | if (nSkipped + len <= nToSkip) | ||
461 | nSkipped += len; | ||
462 | else { | ||
463 | if (nSkipped < nToSkip && nSkipped + len > nToSkip) { | ||
464 | data += nToSkip - nSkipped; | ||
465 | len -= nToSkip - nSkipped; | ||
466 | nSkipped = nToSkip + 1; | ||
467 | } | ||
468 | gspca_frame_add(gspca_dev, | ||
469 | INTER_PACKET, frame, data, len); | ||
470 | } | ||
471 | break; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | /* This function is called when an image has been read */ | ||
476 | /* This function is used to monitor webcam orientation */ | ||
477 | static void sd_callback(struct gspca_dev *gspca_dev) | ||
478 | { | ||
479 | struct sd *sd = (struct sd *) gspca_dev; | ||
480 | |||
481 | if (!_OV9655_) { | ||
482 | u8 state; | ||
483 | u8 upsideDown; | ||
484 | |||
485 | /* Probe sensor orientation */ | ||
486 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, (void *)&state); | ||
487 | |||
488 | /* C8/40 means upside-down (looking backwards) */ | ||
489 | /* D8/50 means right-up (looking onwards) */ | ||
490 | upsideDown = (state == 0xc8 || state == 0x40); | ||
491 | |||
492 | if (upsideDown && sd->nbRightUp > -4) { | ||
493 | if (sd->nbRightUp > 0) | ||
494 | sd->nbRightUp = 0; | ||
495 | if (sd->nbRightUp == -3) { | ||
496 | sd->mirrorMask = 1; | ||
497 | sd->waitSet = 1; | ||
498 | } | ||
499 | sd->nbRightUp--; | ||
500 | } | ||
501 | if (!upsideDown && sd->nbRightUp < 4) { | ||
502 | if (sd->nbRightUp < 0) | ||
503 | sd->nbRightUp = 0; | ||
504 | if (sd->nbRightUp == 3) { | ||
505 | sd->mirrorMask = 0; | ||
506 | sd->waitSet = 1; | ||
507 | } | ||
508 | sd->nbRightUp++; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | if (sd->waitSet) | ||
513 | sd->dev_camera_settings(gspca_dev); | ||
514 | } | ||
515 | |||
516 | /*=================== USB driver structure initialisation ==================*/ | ||
517 | |||
518 | static const __devinitdata struct usb_device_id device_table[] = { | ||
519 | {USB_DEVICE(0x05e3, 0x0503)}, | ||
520 | {USB_DEVICE(0x05e3, 0xf191)}, | ||
521 | {} | ||
522 | }; | ||
523 | |||
524 | MODULE_DEVICE_TABLE(usb, device_table); | ||
525 | |||
526 | static int sd_probe(struct usb_interface *intf, | ||
527 | const struct usb_device_id *id) | ||
528 | { | ||
529 | struct gspca_dev *gspca_dev; | ||
530 | s32 ret; | ||
531 | |||
532 | ret = gspca_dev_probe(intf, id, | ||
533 | &sd_desc_mi1320, sizeof(struct sd), THIS_MODULE); | ||
534 | |||
535 | if (ret >= 0) { | ||
536 | gspca_dev = usb_get_intfdata(intf); | ||
537 | |||
538 | PDEBUG(D_PROBE, | ||
539 | "Camera is now controlling video device /dev/video%d", | ||
540 | gspca_dev->vdev.minor); | ||
541 | } | ||
542 | |||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | static void sd_disconnect(struct usb_interface *intf) | ||
547 | { | ||
548 | gspca_disconnect(intf); | ||
549 | } | ||
550 | |||
551 | static struct usb_driver sd_driver = { | ||
552 | .name = MODULE_NAME, | ||
553 | .id_table = device_table, | ||
554 | .probe = sd_probe, | ||
555 | .disconnect = sd_disconnect, | ||
556 | #ifdef CONFIG_PM | ||
557 | .suspend = gspca_suspend, | ||
558 | .resume = gspca_resume, | ||
559 | #endif | ||
560 | }; | ||
561 | |||
562 | /*====================== Init and Exit module functions ====================*/ | ||
563 | |||
564 | static int __init sd_mod_init(void) | ||
565 | { | ||
566 | PDEBUG(D_PROBE, "driver startup - version %s", DRIVER_VERSION); | ||
567 | |||
568 | if (usb_register(&sd_driver) < 0) | ||
569 | return -1; | ||
570 | PDEBUG(D_PROBE, "driver registered"); | ||
571 | |||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static void __exit sd_mod_exit(void) | ||
576 | { | ||
577 | usb_deregister(&sd_driver); | ||
578 | PDEBUG(D_PROBE, "driver deregistered"); | ||
579 | } | ||
580 | |||
581 | module_init(sd_mod_init); | ||
582 | module_exit(sd_mod_exit); | ||
583 | |||
584 | /*==========================================================================*/ | ||
585 | |||
586 | int gl860_RTx(struct gspca_dev *gspca_dev, | ||
587 | unsigned char pref, u32 req, u16 val, u16 index, | ||
588 | s32 len, void *pdata) | ||
589 | { | ||
590 | struct usb_device *udev = gspca_dev->dev; | ||
591 | s32 r = 0; | ||
592 | |||
593 | if (pref == 0x40) { /* Send */ | ||
594 | if (len > 0) { | ||
595 | memcpy(gspca_dev->usb_buf, pdata, len); | ||
596 | r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
597 | req, pref, val, index, | ||
598 | gspca_dev->usb_buf, | ||
599 | len, 400 + 200 * (len > 1)); | ||
600 | } else { | ||
601 | r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
602 | req, pref, val, index, NULL, len, 400); | ||
603 | } | ||
604 | } else { /* Receive */ | ||
605 | if (len > 0) { | ||
606 | r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
607 | req, pref, val, index, | ||
608 | gspca_dev->usb_buf, | ||
609 | len, 400 + 200 * (len > 1)); | ||
610 | memcpy(pdata, gspca_dev->usb_buf, len); | ||
611 | } else { | ||
612 | r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
613 | req, pref, val, index, NULL, len, 400); | ||
614 | } | ||
615 | } | ||
616 | |||
617 | if (r < 0) | ||
618 | PDEBUG(D_ERR, | ||
619 | "ctrl transfer failed %4d " | ||
620 | "[p%02x r%d v%04x i%04x len%d]", | ||
621 | r, pref, req, val, index, len); | ||
622 | else if (len > 1 && r < len) | ||
623 | PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len); | ||
624 | |||
625 | if ((_MI2020_ || _MI2020b_ || _MI2020c_) && (val || index)) | ||
626 | msleep(1); | ||
627 | if (_OV2640_) | ||
628 | msleep(1); | ||
629 | |||
630 | return r; | ||
631 | } | ||
632 | |||
633 | int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len) | ||
634 | { | ||
635 | int n; | ||
636 | |||
637 | for (n = 0; n < len; n++) { | ||
638 | if (tbl[n].idx != 0xffff) | ||
639 | ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, | ||
640 | tbl[n].idx, 0, NULL); | ||
641 | else if (tbl[n].val == 0xffff) | ||
642 | break; | ||
643 | else | ||
644 | msleep(tbl[n].val); | ||
645 | } | ||
646 | return n; | ||
647 | } | ||
648 | |||
649 | int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl, | ||
650 | int len, int n) | ||
651 | { | ||
652 | while (++n < len) { | ||
653 | if (tbl[n].idx != 0xffff) | ||
654 | ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, tbl[n].idx, | ||
655 | 0, NULL); | ||
656 | else if (tbl[n].val == 0xffff) | ||
657 | break; | ||
658 | else | ||
659 | msleep(tbl[n].val); | ||
660 | } | ||
661 | return n; | ||
662 | } | ||
663 | |||
664 | void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len) | ||
665 | { | ||
666 | int n; | ||
667 | |||
668 | for (n = 0; n < len; n++) { | ||
669 | if (memcmp(tbl[n].data, "\xff\xff\xff", 3) != 0) | ||
670 | ctrl_out(gspca_dev, 0x40, 3, 0x7a00, tbl[n].idx, | ||
671 | 3, tbl[n].data); | ||
672 | else | ||
673 | msleep(tbl[n].idx); | ||
674 | } | ||
675 | } | ||
676 | |||
677 | static int gl860_guess_sensor(struct gspca_dev *gspca_dev, | ||
678 | s32 vendor_id, s32 product_id) | ||
679 | { | ||
680 | struct sd *sd = (struct sd *) gspca_dev; | ||
681 | u8 probe, nb26, nb96, nOV, ntry; | ||
682 | |||
683 | if (product_id == 0xf191) | ||
684 | sd->sensor = ID_MI1320; | ||
685 | |||
686 | if (sd->sensor == 0xff) { | ||
687 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe); | ||
688 | ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe); | ||
689 | |||
690 | ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x0000, 0, NULL); | ||
691 | msleep(3); | ||
692 | ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); | ||
693 | msleep(3); | ||
694 | ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x00c0, 0, NULL); | ||
695 | msleep(3); | ||
696 | ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c1, 0, NULL); | ||
697 | msleep(3); | ||
698 | ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c2, 0, NULL); | ||
699 | msleep(3); | ||
700 | ctrl_out(gspca_dev, 0x40, 1, 0x0020, 0x0006, 0, NULL); | ||
701 | msleep(3); | ||
702 | ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL); | ||
703 | msleep(56); | ||
704 | |||
705 | nOV = 0; | ||
706 | for (ntry = 0; ntry < 4; ntry++) { | ||
707 | ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); | ||
708 | msleep(3); | ||
709 | ctrl_out(gspca_dev, 0x40, 1, 0x0063, 0x0006, 0, NULL); | ||
710 | msleep(3); | ||
711 | ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL); | ||
712 | msleep(10); | ||
713 | ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &probe); | ||
714 | PDEBUG(D_PROBE, "1st probe=%02x", probe); | ||
715 | if (probe == 0xff) | ||
716 | nOV++; | ||
717 | } | ||
718 | |||
719 | if (nOV) { | ||
720 | PDEBUG(D_PROBE, "0xff -> sensor OVXXXX"); | ||
721 | PDEBUG(D_PROBE, "Probing for sensor OV2640 or OV9655"); | ||
722 | |||
723 | nb26 = nb96 = 0; | ||
724 | for (ntry = 0; ntry < 4; ntry++) { | ||
725 | ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, | ||
726 | 0, NULL); | ||
727 | msleep(3); | ||
728 | ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x800a, | ||
729 | 0, NULL); | ||
730 | msleep(10); | ||
731 | /* Wait for 26(OV2640) or 96(OV9655) */ | ||
732 | ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x800a, | ||
733 | 1, &probe); | ||
734 | |||
735 | PDEBUG(D_PROBE, "2nd probe=%02x", probe); | ||
736 | if (probe == 0x00) | ||
737 | nb26++; | ||
738 | if (probe == 0x26 || probe == 0x40) { | ||
739 | sd->sensor = ID_OV2640; | ||
740 | nb26 += 4; | ||
741 | break; | ||
742 | } | ||
743 | if (probe == 0x96 || probe == 0x55) { | ||
744 | sd->sensor = ID_OV9655; | ||
745 | nb96 += 4; | ||
746 | break; | ||
747 | } | ||
748 | if (probe == 0xff) | ||
749 | nb96++; | ||
750 | msleep(3); | ||
751 | } | ||
752 | if (nb26 < 4 && nb96 < 4) { | ||
753 | PDEBUG(D_PROBE, "No relevant answer "); | ||
754 | PDEBUG(D_PROBE, "* 1.3Mpixels -> use OV9655"); | ||
755 | PDEBUG(D_PROBE, "* 2.0Mpixels -> use OV2640"); | ||
756 | PDEBUG(D_PROBE, | ||
757 | "To force a sensor, add that line to " | ||
758 | "/etc/modprobe.d/options.conf:"); | ||
759 | PDEBUG(D_PROBE, "options gspca_gl860 " | ||
760 | "sensor=\"OV2640\" or \"OV9655\""); | ||
761 | return -1; | ||
762 | } | ||
763 | } else { /* probe = 0 */ | ||
764 | PDEBUG(D_PROBE, "No 0xff -> sensor MI2020"); | ||
765 | sd->sensor = ID_MI2020; | ||
766 | } | ||
767 | } | ||
768 | |||
769 | if (_MI1320_) { | ||
770 | PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)"); | ||
771 | } else if (_MI2020_) { | ||
772 | PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)"); | ||
773 | } else if (_MI2020b_) { | ||
774 | PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 alt. driver (2.0M)"); | ||
775 | } else if (_OV9655_) { | ||
776 | PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)"); | ||
777 | } else if (_OV2640_) { | ||
778 | PDEBUG(D_PROBE, "05e3:0503 sensor OV2640 (2.0M)"); | ||
779 | } else { | ||
780 | PDEBUG(D_PROBE, "***** Unknown sensor *****"); | ||
781 | return -1; | ||
782 | } | ||
783 | |||
784 | return 0; | ||
785 | } | ||
diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h new file mode 100644 index 000000000000..cef4e24c1e61 --- /dev/null +++ b/drivers/media/video/gspca/gl860/gl860.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* @file gl860.h | ||
2 | * @author Olivier LORIN, tiré du pilote Syntek par Nicolas VIVIEN | ||
3 | * @date 2009-08-27 | ||
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 | * any later version. | ||
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, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #ifndef GL860_DEV_H | ||
19 | #define GL860_DEV_H | ||
20 | #include <linux/version.h> | ||
21 | |||
22 | #include "gspca.h" | ||
23 | |||
24 | #define MODULE_NAME "gspca_gl860" | ||
25 | #define DRIVER_VERSION "0.9d10" | ||
26 | |||
27 | #define ctrl_in gl860_RTx | ||
28 | #define ctrl_out gl860_RTx | ||
29 | |||
30 | #define ID_MI1320 1 | ||
31 | #define ID_OV2640 2 | ||
32 | #define ID_OV9655 4 | ||
33 | #define ID_MI2020 8 | ||
34 | #define ID_MI2020b 16 | ||
35 | |||
36 | #define _MI1320_ (((struct sd *) gspca_dev)->sensor == ID_MI1320) | ||
37 | #define _MI2020_ (((struct sd *) gspca_dev)->sensor == ID_MI2020) | ||
38 | #define _MI2020b_ (((struct sd *) gspca_dev)->sensor == ID_MI2020b) | ||
39 | #define _MI2020c_ 0 | ||
40 | #define _OV2640_ (((struct sd *) gspca_dev)->sensor == ID_OV2640) | ||
41 | #define _OV9655_ (((struct sd *) gspca_dev)->sensor == ID_OV9655) | ||
42 | |||
43 | #define IMAGE_640 0 | ||
44 | #define IMAGE_800 1 | ||
45 | #define IMAGE_1280 2 | ||
46 | #define IMAGE_1600 3 | ||
47 | |||
48 | struct sd_gl860 { | ||
49 | u16 backlight; | ||
50 | u16 brightness; | ||
51 | u16 sharpness; | ||
52 | u16 contrast; | ||
53 | u16 gamma; | ||
54 | u16 hue; | ||
55 | u16 saturation; | ||
56 | u16 whitebal; | ||
57 | u8 mirror; | ||
58 | u8 flip; | ||
59 | u8 AC50Hz; | ||
60 | }; | ||
61 | |||
62 | /* Specific webcam descriptor */ | ||
63 | struct sd { | ||
64 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
65 | |||
66 | struct sd_gl860 vcur; | ||
67 | struct sd_gl860 vold; | ||
68 | struct sd_gl860 vmax; | ||
69 | |||
70 | int (*dev_configure_alt) (struct gspca_dev *); | ||
71 | int (*dev_init_at_startup)(struct gspca_dev *); | ||
72 | int (*dev_init_pre_alt) (struct gspca_dev *); | ||
73 | void (*dev_post_unset_alt) (struct gspca_dev *); | ||
74 | int (*dev_camera_settings)(struct gspca_dev *); | ||
75 | |||
76 | u8 swapRB; | ||
77 | u8 mirrorMask; | ||
78 | u8 sensor; | ||
79 | s32 nbIm; | ||
80 | s32 nbRightUp; | ||
81 | u8 waitSet; | ||
82 | }; | ||
83 | |||
84 | struct validx { | ||
85 | u16 val; | ||
86 | u16 idx; | ||
87 | }; | ||
88 | |||
89 | struct idxdata { | ||
90 | u8 idx; | ||
91 | u8 data[3]; | ||
92 | }; | ||
93 | |||
94 | int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len); | ||
95 | int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl, | ||
96 | int len, int n); | ||
97 | void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len); | ||
98 | |||
99 | int gl860_RTx(struct gspca_dev *gspca_dev, | ||
100 | unsigned char pref, u32 req, u16 val, u16 index, | ||
101 | s32 len, void *pdata); | ||
102 | |||
103 | void mi1320_init_settings(struct gspca_dev *); | ||
104 | void ov2640_init_settings(struct gspca_dev *); | ||
105 | void ov9655_init_settings(struct gspca_dev *); | ||
106 | void mi2020_init_settings(struct gspca_dev *); | ||
107 | |||
108 | #endif | ||
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index dbfa3ed6e8ef..a11c97ebeb0f 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c | |||
@@ -312,6 +312,8 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
312 | 312 | ||
313 | /* create the JPEG header */ | 313 | /* create the JPEG header */ |
314 | dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); | 314 | dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); |
315 | if (dev->jpeg_hdr == NULL) | ||
316 | return -ENOMEM; | ||
315 | jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, | 317 | jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, |
316 | 0x21); /* JPEG 422 */ | 318 | 0x21); /* JPEG 422 */ |
317 | jpeg_set_qual(dev->jpeg_hdr, dev->quality); | 319 | jpeg_set_qual(dev->jpeg_hdr, dev->quality); |
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c index 7aafeb7cfa07..2a28b74cb3f9 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov7660.c +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.c | |||
@@ -20,6 +20,18 @@ | |||
20 | 20 | ||
21 | static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); | 21 | static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); |
22 | static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); | 22 | static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); |
23 | static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, | ||
24 | __s32 *val); | ||
25 | static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, | ||
26 | __s32 val); | ||
27 | static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); | ||
28 | static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); | ||
29 | static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
30 | static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); | ||
31 | static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
32 | static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val); | ||
33 | static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
34 | static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val); | ||
23 | 35 | ||
24 | const static struct ctrl ov7660_ctrls[] = { | 36 | const static struct ctrl ov7660_ctrls[] = { |
25 | #define GAIN_IDX 1 | 37 | #define GAIN_IDX 1 |
@@ -37,6 +49,79 @@ const static struct ctrl ov7660_ctrls[] = { | |||
37 | .set = ov7660_set_gain, | 49 | .set = ov7660_set_gain, |
38 | .get = ov7660_get_gain | 50 | .get = ov7660_get_gain |
39 | }, | 51 | }, |
52 | #define BLUE_BALANCE_IDX 2 | ||
53 | #define RED_BALANCE_IDX 3 | ||
54 | #define AUTO_WHITE_BALANCE_IDX 4 | ||
55 | { | ||
56 | { | ||
57 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
58 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
59 | .name = "auto white balance", | ||
60 | .minimum = 0, | ||
61 | .maximum = 1, | ||
62 | .step = 1, | ||
63 | .default_value = 1 | ||
64 | }, | ||
65 | .set = ov7660_set_auto_white_balance, | ||
66 | .get = ov7660_get_auto_white_balance | ||
67 | }, | ||
68 | #define AUTO_GAIN_CTRL_IDX 5 | ||
69 | { | ||
70 | { | ||
71 | .id = V4L2_CID_AUTOGAIN, | ||
72 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
73 | .name = "auto gain control", | ||
74 | .minimum = 0, | ||
75 | .maximum = 1, | ||
76 | .step = 1, | ||
77 | .default_value = 1 | ||
78 | }, | ||
79 | .set = ov7660_set_auto_gain, | ||
80 | .get = ov7660_get_auto_gain | ||
81 | }, | ||
82 | #define AUTO_EXPOSURE_IDX 6 | ||
83 | { | ||
84 | { | ||
85 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
86 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
87 | .name = "auto exposure", | ||
88 | .minimum = 0, | ||
89 | .maximum = 1, | ||
90 | .step = 1, | ||
91 | .default_value = 1 | ||
92 | }, | ||
93 | .set = ov7660_set_auto_exposure, | ||
94 | .get = ov7660_get_auto_exposure | ||
95 | }, | ||
96 | #define HFLIP_IDX 7 | ||
97 | { | ||
98 | { | ||
99 | .id = V4L2_CID_HFLIP, | ||
100 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
101 | .name = "horizontal flip", | ||
102 | .minimum = 0, | ||
103 | .maximum = 1, | ||
104 | .step = 1, | ||
105 | .default_value = 0 | ||
106 | }, | ||
107 | .set = ov7660_set_hflip, | ||
108 | .get = ov7660_get_hflip | ||
109 | }, | ||
110 | #define VFLIP_IDX 8 | ||
111 | { | ||
112 | { | ||
113 | .id = V4L2_CID_VFLIP, | ||
114 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
115 | .name = "vertical flip", | ||
116 | .minimum = 0, | ||
117 | .maximum = 1, | ||
118 | .step = 1, | ||
119 | .default_value = 0 | ||
120 | }, | ||
121 | .set = ov7660_set_vflip, | ||
122 | .get = ov7660_get_vflip | ||
123 | }, | ||
124 | |||
40 | }; | 125 | }; |
41 | 126 | ||
42 | static struct v4l2_pix_format ov7660_modes[] = { | 127 | static struct v4l2_pix_format ov7660_modes[] = { |
@@ -137,7 +222,7 @@ int ov7660_init(struct sd *sd) | |||
137 | } else { | 222 | } else { |
138 | data[0] = init_ov7660[i][2]; | 223 | data[0] = init_ov7660[i][2]; |
139 | err = m5602_write_sensor(sd, | 224 | err = m5602_write_sensor(sd, |
140 | init_ov7660[i][1], data, 1); | 225 | init_ov7660[i][1], data, 1); |
141 | } | 226 | } |
142 | } | 227 | } |
143 | 228 | ||
@@ -148,6 +233,28 @@ int ov7660_init(struct sd *sd) | |||
148 | if (err < 0) | 233 | if (err < 0) |
149 | return err; | 234 | return err; |
150 | 235 | ||
236 | err = ov7660_set_auto_white_balance(&sd->gspca_dev, | ||
237 | sensor_settings[AUTO_WHITE_BALANCE_IDX]); | ||
238 | if (err < 0) | ||
239 | return err; | ||
240 | |||
241 | err = ov7660_set_auto_gain(&sd->gspca_dev, | ||
242 | sensor_settings[AUTO_GAIN_CTRL_IDX]); | ||
243 | if (err < 0) | ||
244 | return err; | ||
245 | |||
246 | err = ov7660_set_auto_exposure(&sd->gspca_dev, | ||
247 | sensor_settings[AUTO_EXPOSURE_IDX]); | ||
248 | if (err < 0) | ||
249 | return err; | ||
250 | err = ov7660_set_hflip(&sd->gspca_dev, | ||
251 | sensor_settings[HFLIP_IDX]); | ||
252 | if (err < 0) | ||
253 | return err; | ||
254 | |||
255 | err = ov7660_set_vflip(&sd->gspca_dev, | ||
256 | sensor_settings[VFLIP_IDX]); | ||
257 | |||
151 | return err; | 258 | return err; |
152 | } | 259 | } |
153 | 260 | ||
@@ -194,6 +301,159 @@ static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) | |||
194 | return err; | 301 | return err; |
195 | } | 302 | } |
196 | 303 | ||
304 | |||
305 | static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, | ||
306 | __s32 *val) | ||
307 | { | ||
308 | struct sd *sd = (struct sd *) gspca_dev; | ||
309 | s32 *sensor_settings = sd->sensor_priv; | ||
310 | |||
311 | *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, | ||
316 | __s32 val) | ||
317 | { | ||
318 | int err; | ||
319 | u8 i2c_data; | ||
320 | struct sd *sd = (struct sd *) gspca_dev; | ||
321 | s32 *sensor_settings = sd->sensor_priv; | ||
322 | |||
323 | PDEBUG(D_V4L2, "Set auto white balance to %d", val); | ||
324 | |||
325 | sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; | ||
326 | err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); | ||
327 | if (err < 0) | ||
328 | return err; | ||
329 | |||
330 | i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); | ||
331 | err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); | ||
332 | |||
333 | return err; | ||
334 | } | ||
335 | |||
336 | static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) | ||
337 | { | ||
338 | struct sd *sd = (struct sd *) gspca_dev; | ||
339 | s32 *sensor_settings = sd->sensor_priv; | ||
340 | |||
341 | *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; | ||
342 | PDEBUG(D_V4L2, "Read auto gain control %d", *val); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) | ||
347 | { | ||
348 | int err; | ||
349 | u8 i2c_data; | ||
350 | struct sd *sd = (struct sd *) gspca_dev; | ||
351 | s32 *sensor_settings = sd->sensor_priv; | ||
352 | |||
353 | PDEBUG(D_V4L2, "Set auto gain control to %d", val); | ||
354 | |||
355 | sensor_settings[AUTO_GAIN_CTRL_IDX] = val; | ||
356 | err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); | ||
357 | if (err < 0) | ||
358 | return err; | ||
359 | |||
360 | i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); | ||
361 | |||
362 | return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); | ||
363 | } | ||
364 | |||
365 | static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
366 | { | ||
367 | struct sd *sd = (struct sd *) gspca_dev; | ||
368 | s32 *sensor_settings = sd->sensor_priv; | ||
369 | |||
370 | *val = sensor_settings[AUTO_EXPOSURE_IDX]; | ||
371 | PDEBUG(D_V4L2, "Read auto exposure control %d", *val); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, | ||
376 | __s32 val) | ||
377 | { | ||
378 | int err; | ||
379 | u8 i2c_data; | ||
380 | struct sd *sd = (struct sd *) gspca_dev; | ||
381 | s32 *sensor_settings = sd->sensor_priv; | ||
382 | |||
383 | PDEBUG(D_V4L2, "Set auto exposure control to %d", val); | ||
384 | |||
385 | sensor_settings[AUTO_EXPOSURE_IDX] = val; | ||
386 | err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); | ||
387 | if (err < 0) | ||
388 | return err; | ||
389 | |||
390 | i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); | ||
391 | |||
392 | return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); | ||
393 | } | ||
394 | |||
395 | static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
396 | { | ||
397 | struct sd *sd = (struct sd *) gspca_dev; | ||
398 | s32 *sensor_settings = sd->sensor_priv; | ||
399 | |||
400 | *val = sensor_settings[HFLIP_IDX]; | ||
401 | PDEBUG(D_V4L2, "Read horizontal flip %d", *val); | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | ||
406 | { | ||
407 | int err; | ||
408 | u8 i2c_data; | ||
409 | struct sd *sd = (struct sd *) gspca_dev; | ||
410 | s32 *sensor_settings = sd->sensor_priv; | ||
411 | |||
412 | PDEBUG(D_V4L2, "Set horizontal flip to %d", val); | ||
413 | |||
414 | sensor_settings[HFLIP_IDX] = val; | ||
415 | |||
416 | i2c_data = ((val & 0x01) << 5) | | ||
417 | (sensor_settings[VFLIP_IDX] << 4); | ||
418 | |||
419 | err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); | ||
420 | |||
421 | return err; | ||
422 | } | ||
423 | |||
424 | static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
425 | { | ||
426 | struct sd *sd = (struct sd *) gspca_dev; | ||
427 | s32 *sensor_settings = sd->sensor_priv; | ||
428 | |||
429 | *val = sensor_settings[VFLIP_IDX]; | ||
430 | PDEBUG(D_V4L2, "Read vertical flip %d", *val); | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | ||
436 | { | ||
437 | int err; | ||
438 | u8 i2c_data; | ||
439 | struct sd *sd = (struct sd *) gspca_dev; | ||
440 | s32 *sensor_settings = sd->sensor_priv; | ||
441 | |||
442 | PDEBUG(D_V4L2, "Set vertical flip to %d", val); | ||
443 | sensor_settings[VFLIP_IDX] = val; | ||
444 | |||
445 | i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); | ||
446 | err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); | ||
447 | if (err < 0) | ||
448 | return err; | ||
449 | |||
450 | /* When vflip is toggled we need to readjust the bridge hsync/vsync */ | ||
451 | if (gspca_dev->streaming) | ||
452 | err = ov7660_start(sd); | ||
453 | |||
454 | return err; | ||
455 | } | ||
456 | |||
197 | static void ov7660_dump_registers(struct sd *sd) | 457 | static void ov7660_dump_registers(struct sd *sd) |
198 | { | 458 | { |
199 | int address; | 459 | int address; |
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h index 3f2c169a93ea..f5588ebe667c 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov7660.h +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h | |||
@@ -66,23 +66,23 @@ | |||
66 | #define OV7660_RBIAS 0x2c | 66 | #define OV7660_RBIAS 0x2c |
67 | #define OV7660_HREF 0x32 | 67 | #define OV7660_HREF 0x32 |
68 | #define OV7660_ADC 0x37 | 68 | #define OV7660_ADC 0x37 |
69 | #define OV7660_OFON 0x39 | 69 | #define OV7660_OFON 0x39 |
70 | #define OV7660_TSLB 0x3a | 70 | #define OV7660_TSLB 0x3a |
71 | #define OV7660_COM12 0x3c | 71 | #define OV7660_COM12 0x3c |
72 | #define OV7660_COM13 0x3d | 72 | #define OV7660_COM13 0x3d |
73 | #define OV7660_LCC1 0x62 | 73 | #define OV7660_LCC1 0x62 |
74 | #define OV7660_LCC2 0x63 | 74 | #define OV7660_LCC2 0x63 |
75 | #define OV7660_LCC3 0x64 | 75 | #define OV7660_LCC3 0x64 |
76 | #define OV7660_LCC4 0x65 | 76 | #define OV7660_LCC4 0x65 |
77 | #define OV7660_LCC5 0x66 | 77 | #define OV7660_LCC5 0x66 |
78 | #define OV7660_HV 0x69 | 78 | #define OV7660_HV 0x69 |
79 | #define OV7660_RSVDA1 0xa1 | 79 | #define OV7660_RSVDA1 0xa1 |
80 | 80 | ||
81 | #define OV7660_DEFAULT_GAIN 0x0e | 81 | #define OV7660_DEFAULT_GAIN 0x0e |
82 | #define OV7660_DEFAULT_RED_GAIN 0x80 | 82 | #define OV7660_DEFAULT_RED_GAIN 0x80 |
83 | #define OV7660_DEFAULT_BLUE_GAIN 0x80 | 83 | #define OV7660_DEFAULT_BLUE_GAIN 0x80 |
84 | #define OV7660_DEFAULT_SATURATION 0x00 | 84 | #define OV7660_DEFAULT_SATURATION 0x00 |
85 | #define OV7660_DEFAULT_EXPOSURE 0x20 | 85 | #define OV7660_DEFAULT_EXPOSURE 0x20 |
86 | 86 | ||
87 | /* Kernel module parameters */ | 87 | /* Kernel module parameters */ |
88 | extern int force_sensor; | 88 | extern int force_sensor; |
@@ -149,45 +149,8 @@ static const unsigned char init_ov7660[][4] = | |||
149 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, | 149 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, |
150 | {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, | 150 | {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, |
151 | {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, | 151 | {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, |
152 | {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, | ||
153 | {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, | ||
154 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, | ||
155 | {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, | ||
156 | |||
157 | {SENSOR, OV7660_OFON, 0x0c}, | ||
158 | {SENSOR, OV7660_COM2, 0x11}, | ||
159 | {SENSOR, OV7660_COM7, 0x05}, | ||
160 | |||
161 | {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, | 152 | {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, |
162 | {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, | ||
163 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
164 | {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, | ||
165 | {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, | ||
166 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, | ||
167 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
168 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, | ||
169 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
170 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, | ||
171 | {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, | ||
172 | {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, | ||
173 | {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, | ||
174 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
175 | {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, | ||
176 | |||
177 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x02}, | ||
178 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
179 | |||
180 | {SENSOR, OV7660_AECH, OV7660_DEFAULT_EXPOSURE}, | ||
181 | {SENSOR, OV7660_COM1, 0x00}, | ||
182 | |||
183 | {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, | 153 | {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, |
184 | {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, | ||
185 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
186 | {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, | ||
187 | {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, | ||
188 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, | ||
189 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
190 | |||
191 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, | 154 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, |
192 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | 155 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, |
193 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, | 156 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, |
@@ -196,11 +159,8 @@ static const unsigned char init_ov7660[][4] = | |||
196 | {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, | 159 | {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, |
197 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | 160 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, |
198 | {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, | 161 | {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, |
199 | |||
200 | {SENSOR, OV7660_COM7, 0x80}, | 162 | {SENSOR, OV7660_COM7, 0x80}, |
201 | {SENSOR, OV7660_CLKRC, 0x80}, | 163 | {SENSOR, OV7660_CLKRC, 0x80}, |
202 | {SENSOR, OV7660_BLUE_GAIN, 0x80}, | ||
203 | {SENSOR, OV7660_RED_GAIN, 0x80}, | ||
204 | {SENSOR, OV7660_COM9, 0x4c}, | 164 | {SENSOR, OV7660_COM9, 0x4c}, |
205 | {SENSOR, OV7660_OFON, 0x43}, | 165 | {SENSOR, OV7660_OFON, 0x43}, |
206 | {SENSOR, OV7660_COM12, 0x28}, | 166 | {SENSOR, OV7660_COM12, 0x28}, |
@@ -212,17 +172,17 @@ static const unsigned char init_ov7660[][4] = | |||
212 | {SENSOR, OV7660_PSHFT, 0x0b}, | 172 | {SENSOR, OV7660_PSHFT, 0x0b}, |
213 | {SENSOR, OV7660_VSTART, 0x01}, | 173 | {SENSOR, OV7660_VSTART, 0x01}, |
214 | {SENSOR, OV7660_VSTOP, 0x7a}, | 174 | {SENSOR, OV7660_VSTOP, 0x7a}, |
215 | {SENSOR, OV7660_VREF, 0x00}, | 175 | {SENSOR, OV7660_VSTOP, 0x00}, |
216 | {SENSOR, OV7660_COM7, 0x05}, | 176 | {SENSOR, OV7660_COM7, 0x05}, |
217 | {SENSOR, OV7660_COM6, 0x4b}, | 177 | {SENSOR, OV7660_COM6, 0x42}, |
218 | {SENSOR, OV7660_BBIAS, 0x98}, | 178 | {SENSOR, OV7660_BBIAS, 0x94}, |
219 | {SENSOR, OV7660_GbBIAS, 0x98}, | 179 | {SENSOR, OV7660_GbBIAS, 0x94}, |
220 | {SENSOR, OV7660_RSVD29, 0x98}, | 180 | {SENSOR, OV7660_RSVD29, 0x94}, |
221 | {SENSOR, OV7660_RBIAS, 0x98}, | 181 | {SENSOR, OV7660_RBIAS, 0x94}, |
222 | {SENSOR, OV7660_COM1, 0x00}, | 182 | {SENSOR, OV7660_COM1, 0x00}, |
223 | {SENSOR, OV7660_AECH, 0x00}, | 183 | {SENSOR, OV7660_AECH, 0x00}, |
224 | {SENSOR, OV7660_AECHH, 0x00}, | 184 | {SENSOR, OV7660_AECHH, 0x00}, |
225 | {SENSOR, OV7660_ADC, 0x04}, | 185 | {SENSOR, OV7660_ADC, 0x05}, |
226 | {SENSOR, OV7660_COM13, 0x00}, | 186 | {SENSOR, OV7660_COM13, 0x00}, |
227 | {SENSOR, OV7660_RSVDA1, 0x23}, | 187 | {SENSOR, OV7660_RSVDA1, 0x23}, |
228 | {SENSOR, OV7660_TSLB, 0x0d}, | 188 | {SENSOR, OV7660_TSLB, 0x0d}, |
@@ -233,6 +193,47 @@ static const unsigned char init_ov7660[][4] = | |||
233 | {SENSOR, OV7660_LCC4, 0x40}, | 193 | {SENSOR, OV7660_LCC4, 0x40}, |
234 | {SENSOR, OV7660_LCC5, 0x01}, | 194 | {SENSOR, OV7660_LCC5, 0x01}, |
235 | 195 | ||
196 | {SENSOR, OV7660_AECH, 0x20}, | ||
197 | {SENSOR, OV7660_COM1, 0x00}, | ||
198 | {SENSOR, OV7660_OFON, 0x0c}, | ||
199 | {SENSOR, OV7660_COM2, 0x11}, | ||
200 | {SENSOR, OV7660_COM7, 0x05}, | ||
201 | {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, | ||
202 | {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, | ||
203 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
204 | {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, | ||
205 | {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, | ||
206 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, | ||
207 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
208 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, | ||
209 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
210 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, | ||
211 | {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, | ||
212 | {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, | ||
213 | {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, | ||
214 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
215 | {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, | ||
216 | {SENSOR, OV7660_AECH, 0x5f}, | ||
217 | {SENSOR, OV7660_COM1, 0x03}, | ||
218 | {SENSOR, OV7660_OFON, 0x0c}, | ||
219 | {SENSOR, OV7660_COM2, 0x11}, | ||
220 | {SENSOR, OV7660_COM7, 0x05}, | ||
221 | {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, | ||
222 | {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, | ||
223 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
224 | {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, | ||
225 | {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, | ||
226 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, | ||
227 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
228 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, | ||
229 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | ||
230 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, | ||
231 | {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, | ||
232 | {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, | ||
233 | {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, | ||
234 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
235 | {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, | ||
236 | |||
236 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, | 237 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, |
237 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | 238 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, |
238 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, | 239 | {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, |
@@ -245,35 +246,18 @@ static const unsigned char init_ov7660[][4] = | |||
245 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, | 246 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, |
246 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, | 247 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, |
247 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, | 248 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, |
248 | {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */ | 249 | {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, |
249 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, | 250 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, |
250 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, | 251 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, |
251 | {BRIDGE, M5602_XB_SIG_INI, 0x00}, | 252 | {BRIDGE, M5602_XB_SIG_INI, 0x00}, |
252 | {BRIDGE, M5602_XB_SIG_INI, 0x02}, | 253 | {BRIDGE, M5602_XB_SIG_INI, 0x02}, |
253 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, | 254 | {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, |
254 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x27}, /* 39 */ | 255 | {BRIDGE, M5602_XB_HSYNC_PARA, 0x27}, |
255 | {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, | 256 | {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, |
256 | {BRIDGE, M5602_XB_VSYNC_PARA, 0xa7}, /* 679 */ | 257 | {BRIDGE, M5602_XB_HSYNC_PARA, 0xa7}, |
257 | {BRIDGE, M5602_XB_SIG_INI, 0x00}, | 258 | {BRIDGE, M5602_XB_SIG_INI, 0x00}, |
258 | |||
259 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, | 259 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, |
260 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, | 260 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, |
261 | |||
262 | {SENSOR, OV7660_AECH, 0x20}, | ||
263 | {SENSOR, OV7660_COM1, 0x00}, | ||
264 | {SENSOR, OV7660_OFON, 0x0c}, | ||
265 | {SENSOR, OV7660_COM2, 0x11}, | ||
266 | {SENSOR, OV7660_COM7, 0x05}, | ||
267 | {SENSOR, OV7660_BLUE_GAIN, 0x80}, | ||
268 | {SENSOR, OV7660_RED_GAIN, 0x80}, | ||
269 | |||
270 | {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, | ||
271 | {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, | ||
272 | {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, | ||
273 | {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, | ||
274 | {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, | ||
275 | {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, | ||
276 | {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0} | ||
277 | }; | 261 | }; |
278 | 262 | ||
279 | #endif | 263 | #endif |
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index 0163903d1c0f..59400e858965 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c | |||
@@ -47,6 +47,12 @@ static | |||
47 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") | 47 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") |
48 | } | 48 | } |
49 | }, { | 49 | }, { |
50 | .ident = "Fujitsu-Siemens Amilo Pa 2548", | ||
51 | .matches = { | ||
52 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | ||
53 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") | ||
54 | } | ||
55 | }, { | ||
50 | .ident = "MSI GX700", | 56 | .ident = "MSI GX700", |
51 | .matches = { | 57 | .matches = { |
52 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), | 58 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), |
@@ -54,6 +60,13 @@ static | |||
54 | DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") | 60 | DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") |
55 | } | 61 | } |
56 | }, { | 62 | }, { |
63 | .ident = "MSI GX700", | ||
64 | .matches = { | ||
65 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), | ||
66 | DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), | ||
67 | DMI_MATCH(DMI_BIOS_DATE, "07/19/2007") | ||
68 | } | ||
69 | }, { | ||
57 | .ident = "MSI GX700/GX705/EX700", | 70 | .ident = "MSI GX700/GX705/EX700", |
58 | .matches = { | 71 | .matches = { |
59 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), | 72 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index 7af511b5e9c2..65489d6b0d89 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c | |||
@@ -50,7 +50,6 @@ int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) | |||
50 | 0x04, 0x40, address, 0, buf, len, | 50 | 0x04, 0x40, address, 0, buf, len, |
51 | STV06XX_URB_MSG_TIMEOUT); | 51 | STV06XX_URB_MSG_TIMEOUT); |
52 | 52 | ||
53 | |||
54 | PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d", | 53 | PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d", |
55 | i2c_data, address, err); | 54 | i2c_data, address, err); |
56 | 55 | ||
@@ -69,7 +68,7 @@ int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data) | |||
69 | 68 | ||
70 | *i2c_data = buf[0]; | 69 | *i2c_data = buf[0]; |
71 | 70 | ||
72 | PDEBUG(D_CONF, "Read 0x%x from address 0x%x, status %d", | 71 | PDEBUG(D_CONF, "Reading 0x%x from address 0x%x, status %d", |
73 | *i2c_data, address, err); | 72 | *i2c_data, address, err); |
74 | 73 | ||
75 | return (err < 0) ? err : 0; | 74 | return (err < 0) ? err : 0; |
@@ -111,14 +110,14 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) | |||
111 | struct usb_device *udev = sd->gspca_dev.dev; | 110 | struct usb_device *udev = sd->gspca_dev.dev; |
112 | __u8 *buf = sd->gspca_dev.usb_buf; | 111 | __u8 *buf = sd->gspca_dev.usb_buf; |
113 | 112 | ||
114 | PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len); | 113 | PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); |
115 | for (i = 0; i < len;) { | 114 | for (i = 0; i < len;) { |
116 | /* Build the command buffer */ | 115 | /* Build the command buffer */ |
117 | memset(buf, 0, I2C_BUFFER_LENGTH); | 116 | memset(buf, 0, I2C_BUFFER_LENGTH); |
118 | for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) { | 117 | for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) { |
119 | buf[j] = data[2*i]; | 118 | buf[j] = data[2*i]; |
120 | buf[0x10 + j] = data[2*i+1]; | 119 | buf[0x10 + j] = data[2*i+1]; |
121 | PDEBUG(D_USBO, "I2C: Writing 0x%02x to reg 0x%02x", | 120 | PDEBUG(D_CONF, "I2C: Writing 0x%02x to reg 0x%02x", |
122 | data[2*i+1], data[2*i]); | 121 | data[2*i+1], data[2*i]); |
123 | } | 122 | } |
124 | buf[0x20] = sd->sensor->i2c_addr; | 123 | buf[0x20] = sd->sensor->i2c_addr; |
@@ -128,8 +127,8 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) | |||
128 | 0x04, 0x40, 0x0400, 0, buf, | 127 | 0x04, 0x40, 0x0400, 0, buf, |
129 | I2C_BUFFER_LENGTH, | 128 | I2C_BUFFER_LENGTH, |
130 | STV06XX_URB_MSG_TIMEOUT); | 129 | STV06XX_URB_MSG_TIMEOUT); |
131 | if (err < 0) | 130 | if (err < 0) |
132 | return err; | 131 | return err; |
133 | } | 132 | } |
134 | return stv06xx_write_sensor_finish(sd); | 133 | return stv06xx_write_sensor_finish(sd); |
135 | } | 134 | } |
@@ -140,7 +139,7 @@ int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) | |||
140 | struct usb_device *udev = sd->gspca_dev.dev; | 139 | struct usb_device *udev = sd->gspca_dev.dev; |
141 | __u8 *buf = sd->gspca_dev.usb_buf; | 140 | __u8 *buf = sd->gspca_dev.usb_buf; |
142 | 141 | ||
143 | PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len); | 142 | PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); |
144 | 143 | ||
145 | for (i = 0; i < len;) { | 144 | for (i = 0; i < len;) { |
146 | /* Build the command buffer */ | 145 | /* Build the command buffer */ |
@@ -149,7 +148,7 @@ int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) | |||
149 | buf[j] = data[2*i]; | 148 | buf[j] = data[2*i]; |
150 | buf[0x10 + j * 2] = data[2*i+1]; | 149 | buf[0x10 + j * 2] = data[2*i+1]; |
151 | buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8; | 150 | buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8; |
152 | PDEBUG(D_USBO, "I2C: Writing 0x%04x to reg 0x%02x", | 151 | PDEBUG(D_CONF, "I2C: Writing 0x%04x to reg 0x%02x", |
153 | data[2*i+1], data[2*i]); | 152 | data[2*i+1], data[2*i]); |
154 | } | 153 | } |
155 | buf[0x20] = sd->sensor->i2c_addr; | 154 | buf[0x20] = sd->sensor->i2c_addr; |
@@ -189,7 +188,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) | |||
189 | 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, | 188 | 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, |
190 | STV06XX_URB_MSG_TIMEOUT); | 189 | STV06XX_URB_MSG_TIMEOUT); |
191 | if (err < 0) { | 190 | if (err < 0) { |
192 | PDEBUG(D_ERR, "I2C Read: error writing address: %d", err); | 191 | PDEBUG(D_ERR, "I2C: Read error writing address: %d", err); |
193 | return err; | 192 | return err; |
194 | } | 193 | } |
195 | 194 | ||
@@ -201,7 +200,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) | |||
201 | else | 200 | else |
202 | *value = buf[0]; | 201 | *value = buf[0]; |
203 | 202 | ||
204 | PDEBUG(D_USBO, "I2C: Read 0x%x from address 0x%x, status: %d", | 203 | PDEBUG(D_CONF, "I2C: Read 0x%x from address 0x%x, status: %d", |
205 | *value, address, err); | 204 | *value, address, err); |
206 | 205 | ||
207 | return (err < 0) ? err : 0; | 206 | return (err < 0) ? err : 0; |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index e5024c8496ef..706e08dc5254 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | |||
@@ -37,7 +37,7 @@ static const struct ctrl hdcs1x00_ctrl[] = { | |||
37 | .type = V4L2_CTRL_TYPE_INTEGER, | 37 | .type = V4L2_CTRL_TYPE_INTEGER, |
38 | .name = "exposure", | 38 | .name = "exposure", |
39 | .minimum = 0x00, | 39 | .minimum = 0x00, |
40 | .maximum = 0xffff, | 40 | .maximum = 0xff, |
41 | .step = 0x1, | 41 | .step = 0x1, |
42 | .default_value = HDCS_DEFAULT_EXPOSURE, | 42 | .default_value = HDCS_DEFAULT_EXPOSURE, |
43 | .flags = V4L2_CTRL_FLAG_SLIDER | 43 | .flags = V4L2_CTRL_FLAG_SLIDER |
@@ -74,7 +74,35 @@ static struct v4l2_pix_format hdcs1x00_mode[] = { | |||
74 | } | 74 | } |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static const struct ctrl hdcs1020_ctrl[] = {}; | 77 | static const struct ctrl hdcs1020_ctrl[] = { |
78 | { | ||
79 | { | ||
80 | .id = V4L2_CID_EXPOSURE, | ||
81 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
82 | .name = "exposure", | ||
83 | .minimum = 0x00, | ||
84 | .maximum = 0xffff, | ||
85 | .step = 0x1, | ||
86 | .default_value = HDCS_DEFAULT_EXPOSURE, | ||
87 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
88 | }, | ||
89 | .set = hdcs_set_exposure, | ||
90 | .get = hdcs_get_exposure | ||
91 | }, { | ||
92 | { | ||
93 | .id = V4L2_CID_GAIN, | ||
94 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
95 | .name = "gain", | ||
96 | .minimum = 0x00, | ||
97 | .maximum = 0xff, | ||
98 | .step = 0x1, | ||
99 | .default_value = HDCS_DEFAULT_GAIN, | ||
100 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
101 | }, | ||
102 | .set = hdcs_set_gain, | ||
103 | .get = hdcs_get_gain | ||
104 | } | ||
105 | }; | ||
78 | 106 | ||
79 | static struct v4l2_pix_format hdcs1020_mode[] = { | 107 | static struct v4l2_pix_format hdcs1020_mode[] = { |
80 | { | 108 | { |
@@ -120,6 +148,7 @@ struct hdcs { | |||
120 | } exp; | 148 | } exp; |
121 | 149 | ||
122 | int psmp; | 150 | int psmp; |
151 | u8 exp_cache, gain_cache; | ||
123 | }; | 152 | }; |
124 | 153 | ||
125 | static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) | 154 | static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) |
@@ -205,34 +234,8 @@ static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | |||
205 | struct sd *sd = (struct sd *) gspca_dev; | 234 | struct sd *sd = (struct sd *) gspca_dev; |
206 | struct hdcs *hdcs = sd->sensor_priv; | 235 | struct hdcs *hdcs = sd->sensor_priv; |
207 | 236 | ||
208 | /* Column time period */ | 237 | *val = hdcs->exp_cache; |
209 | int ct; | ||
210 | /* Column processing period */ | ||
211 | int cp; | ||
212 | /* Row processing period */ | ||
213 | int rp; | ||
214 | int cycles; | ||
215 | int err; | ||
216 | int rowexp; | ||
217 | u16 data[2]; | ||
218 | |||
219 | err = stv06xx_read_sensor(sd, HDCS_ROWEXPL, &data[0]); | ||
220 | if (err < 0) | ||
221 | return err; | ||
222 | |||
223 | err = stv06xx_read_sensor(sd, HDCS_ROWEXPH, &data[1]); | ||
224 | if (err < 0) | ||
225 | return err; | ||
226 | |||
227 | rowexp = (data[1] << 8) | data[0]; | ||
228 | |||
229 | ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); | ||
230 | cp = hdcs->exp.cto + (hdcs->w * ct / 2); | ||
231 | rp = hdcs->exp.rs + cp; | ||
232 | 238 | ||
233 | cycles = rp * rowexp; | ||
234 | *val = cycles / HDCS_CLK_FREQ_MHZ; | ||
235 | PDEBUG(D_V4L2, "Read exposure %d", *val); | ||
236 | return 0; | 239 | return 0; |
237 | } | 240 | } |
238 | 241 | ||
@@ -252,9 +255,12 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | |||
252 | within the column processing period */ | 255 | within the column processing period */ |
253 | int mnct; | 256 | int mnct; |
254 | int cycles, err; | 257 | int cycles, err; |
255 | u8 exp[4]; | 258 | u8 exp[14]; |
256 | 259 | ||
257 | cycles = val * HDCS_CLK_FREQ_MHZ; | 260 | val &= 0xff; |
261 | hdcs->exp_cache = val; | ||
262 | |||
263 | cycles = val * HDCS_CLK_FREQ_MHZ * 257; | ||
258 | 264 | ||
259 | ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); | 265 | ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); |
260 | cp = hdcs->exp.cto + (hdcs->w * ct / 2); | 266 | cp = hdcs->exp.cto + (hdcs->w * ct / 2); |
@@ -288,73 +294,79 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | |||
288 | srowexp = max_srowexp; | 294 | srowexp = max_srowexp; |
289 | 295 | ||
290 | if (IS_1020(sd)) { | 296 | if (IS_1020(sd)) { |
291 | exp[0] = rowexp & 0xff; | 297 | exp[0] = HDCS20_CONTROL; |
292 | exp[1] = rowexp >> 8; | 298 | exp[1] = 0x00; /* Stop streaming */ |
293 | exp[2] = (srowexp >> 2) & 0xff; | 299 | exp[2] = HDCS_ROWEXPL; |
294 | /* this clears exposure error flag */ | 300 | exp[3] = rowexp & 0xff; |
295 | exp[3] = 0x1; | 301 | exp[4] = HDCS_ROWEXPH; |
296 | err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4); | 302 | exp[5] = rowexp >> 8; |
303 | exp[6] = HDCS20_SROWEXP; | ||
304 | exp[7] = (srowexp >> 2) & 0xff; | ||
305 | exp[8] = HDCS20_ERROR; | ||
306 | exp[9] = 0x10; /* Clear exposure error flag*/ | ||
307 | exp[10] = HDCS20_CONTROL; | ||
308 | exp[11] = 0x04; /* Restart streaming */ | ||
309 | err = stv06xx_write_sensor_bytes(sd, exp, 6); | ||
297 | } else { | 310 | } else { |
298 | exp[0] = rowexp & 0xff; | 311 | exp[0] = HDCS00_CONTROL; |
299 | exp[1] = rowexp >> 8; | 312 | exp[1] = 0x00; /* Stop streaming */ |
300 | exp[2] = srowexp & 0xff; | 313 | exp[2] = HDCS_ROWEXPL; |
301 | exp[3] = srowexp >> 8; | 314 | exp[3] = rowexp & 0xff; |
302 | err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4); | 315 | exp[4] = HDCS_ROWEXPH; |
316 | exp[5] = rowexp >> 8; | ||
317 | exp[6] = HDCS00_SROWEXPL; | ||
318 | exp[7] = srowexp & 0xff; | ||
319 | exp[8] = HDCS00_SROWEXPH; | ||
320 | exp[9] = srowexp >> 8; | ||
321 | exp[10] = HDCS_STATUS; | ||
322 | exp[11] = 0x10; /* Clear exposure error flag*/ | ||
323 | exp[12] = HDCS00_CONTROL; | ||
324 | exp[13] = 0x04; /* Restart streaming */ | ||
325 | err = stv06xx_write_sensor_bytes(sd, exp, 7); | ||
303 | if (err < 0) | 326 | if (err < 0) |
304 | return err; | 327 | return err; |
305 | |||
306 | /* clear exposure error flag */ | ||
307 | err = stv06xx_write_sensor(sd, | ||
308 | HDCS_STATUS, BIT(4)); | ||
309 | } | 328 | } |
310 | PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d", | 329 | PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d", |
311 | val, rowexp, srowexp); | 330 | val, rowexp, srowexp); |
312 | return err; | 331 | return err; |
313 | } | 332 | } |
314 | 333 | ||
315 | static int hdcs_set_gains(struct sd *sd, u8 r, u8 g, u8 b) | 334 | static int hdcs_set_gains(struct sd *sd, u8 g) |
316 | { | 335 | { |
336 | struct hdcs *hdcs = sd->sensor_priv; | ||
337 | int err; | ||
317 | u8 gains[4]; | 338 | u8 gains[4]; |
318 | 339 | ||
340 | hdcs->gain_cache = g; | ||
341 | |||
319 | /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ | 342 | /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ |
320 | if (r > 127) | ||
321 | r = 0x80 | (r / 2); | ||
322 | if (g > 127) | 343 | if (g > 127) |
323 | g = 0x80 | (g / 2); | 344 | g = 0x80 | (g / 2); |
324 | if (b > 127) | ||
325 | b = 0x80 | (b / 2); | ||
326 | 345 | ||
327 | gains[0] = g; | 346 | gains[0] = g; |
328 | gains[1] = r; | 347 | gains[1] = g; |
329 | gains[2] = b; | 348 | gains[2] = g; |
330 | gains[3] = g; | 349 | gains[3] = g; |
331 | 350 | ||
332 | return hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); | 351 | err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); |
352 | return err; | ||
333 | } | 353 | } |
334 | 354 | ||
335 | static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | 355 | static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val) |
336 | { | 356 | { |
337 | struct sd *sd = (struct sd *) gspca_dev; | 357 | struct sd *sd = (struct sd *) gspca_dev; |
338 | int err; | 358 | struct hdcs *hdcs = sd->sensor_priv; |
339 | u16 data; | ||
340 | |||
341 | err = stv06xx_read_sensor(sd, HDCS_ERECPGA, &data); | ||
342 | 359 | ||
343 | /* Bit 7 doubles the gain */ | 360 | *val = hdcs->gain_cache; |
344 | if (data & 0x80) | ||
345 | *val = (data & 0x7f) * 2; | ||
346 | else | ||
347 | *val = data; | ||
348 | 361 | ||
349 | PDEBUG(D_V4L2, "Read gain %d", *val); | 362 | return 0; |
350 | return err; | ||
351 | } | 363 | } |
352 | 364 | ||
353 | static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) | 365 | static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) |
354 | { | 366 | { |
355 | PDEBUG(D_V4L2, "Writing gain %d", val); | 367 | PDEBUG(D_V4L2, "Writing gain %d", val); |
356 | return hdcs_set_gains((struct sd *) gspca_dev, | 368 | return hdcs_set_gains((struct sd *) gspca_dev, |
357 | val & 0xff, val & 0xff, val & 0xff); | 369 | val & 0xff); |
358 | } | 370 | } |
359 | 371 | ||
360 | static int hdcs_set_size(struct sd *sd, | 372 | static int hdcs_set_size(struct sd *sd, |
@@ -572,16 +584,15 @@ static int hdcs_init(struct sd *sd) | |||
572 | if (err < 0) | 584 | if (err < 0) |
573 | return err; | 585 | return err; |
574 | 586 | ||
575 | err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN, HDCS_DEFAULT_GAIN, | 587 | err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN); |
576 | HDCS_DEFAULT_GAIN); | ||
577 | if (err < 0) | 588 | if (err < 0) |
578 | return err; | 589 | return err; |
579 | 590 | ||
580 | err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE); | 591 | err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); |
581 | if (err < 0) | 592 | if (err < 0) |
582 | return err; | 593 | return err; |
583 | 594 | ||
584 | err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); | 595 | err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE); |
585 | return err; | 596 | return err; |
586 | } | 597 | } |
587 | 598 | ||
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h index 412f06cf3d5c..37b31c99d956 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h | |||
@@ -124,7 +124,7 @@ | |||
124 | #define HDCS_RUN_ENABLE (1 << 2) | 124 | #define HDCS_RUN_ENABLE (1 << 2) |
125 | #define HDCS_SLEEP_MODE (1 << 1) | 125 | #define HDCS_SLEEP_MODE (1 << 1) |
126 | 126 | ||
127 | #define HDCS_DEFAULT_EXPOSURE 5000 | 127 | #define HDCS_DEFAULT_EXPOSURE 48 |
128 | #define HDCS_DEFAULT_GAIN 128 | 128 | #define HDCS_DEFAULT_GAIN 128 |
129 | 129 | ||
130 | static int hdcs_probe_1x00(struct sd *sd); | 130 | static int hdcs_probe_1x00(struct sd *sd); |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c index 87cb5b9ddfa7..c11f06e4ae76 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c | |||
@@ -166,7 +166,7 @@ static int st6422_init(struct sd *sd) | |||
166 | /* 10 compressed? */ | 166 | /* 10 compressed? */ |
167 | 167 | ||
168 | { 0x1439, 0x00 }, | 168 | { 0x1439, 0x00 }, |
169 | /* antiflimmer?? 0xa2 ger perfekt bild mot monitor */ | 169 | /* anti-noise? 0xa2 gives a perfect image */ |
170 | 170 | ||
171 | { 0x143b, 0x05 }, | 171 | { 0x143b, 0x05 }, |
172 | { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ | 172 | { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ |
@@ -197,15 +197,14 @@ static int st6422_init(struct sd *sd) | |||
197 | { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ | 197 | { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ |
198 | 198 | ||
199 | { 0x1501, 0xaf }, | 199 | { 0x1501, 0xaf }, |
200 | /* high val-> ljus area blir morkare. */ | 200 | /* high val-> light area gets darker */ |
201 | /* low val -> ljus area blir ljusare. */ | 201 | /* low val -> light area gets lighter */ |
202 | { 0x1502, 0xc2 }, | 202 | { 0x1502, 0xc2 }, |
203 | /* high val-> ljus area blir morkare. */ | 203 | /* high val-> light area gets darker */ |
204 | /* low val -> ljus area blir ljusare. */ | 204 | /* low val -> light area gets lighter */ |
205 | { 0x1503, 0x45 }, | 205 | { 0x1503, 0x45 }, |
206 | /* high val-> ljus area blir morkare. */ | 206 | /* high val-> light area gets darker */ |
207 | /* low val -> ljus area blir ljusare. */ | 207 | /* low val -> light area gets lighter */ |
208 | |||
209 | { 0x1505, 0x02 }, | 208 | { 0x1505, 0x02 }, |
210 | /* 2 : 324x248 80352 bytes */ | 209 | /* 2 : 324x248 80352 bytes */ |
211 | /* 7 : 248x162 40176 bytes */ | 210 | /* 7 : 248x162 40176 bytes */ |
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 619250e70718..589042f6adbe 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c | |||
@@ -2946,7 +2946,8 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
2946 | reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000); | 2946 | reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000); |
2947 | break; | 2947 | break; |
2948 | default: | 2948 | default: |
2949 | reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff); | 2949 | if (!(sd->flags & FL_SAMSUNG)) |
2950 | reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff); | ||
2950 | break; | 2951 | break; |
2951 | } | 2952 | } |
2952 | msleep(100); | 2953 | msleep(100); |
@@ -2964,7 +2965,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
2964 | 2965 | ||
2965 | if (sd->sensor == SENSOR_MI1310_SOC) | 2966 | if (sd->sensor == SENSOR_MI1310_SOC) |
2966 | reg_w(dev, 0x89, 0x058c, 0x00ff); | 2967 | reg_w(dev, 0x89, 0x058c, 0x00ff); |
2967 | else | 2968 | else if (!(sd->flags & FL_SAMSUNG)) |
2968 | reg_w(dev, 0x89, 0xffff, 0xffff); | 2969 | reg_w(dev, 0x89, 0xffff, 0xffff); |
2969 | reg_w(dev, 0xa0, 0x01, 0xb301); | 2970 | reg_w(dev, 0xa0, 0x01, 0xb301); |
2970 | reg_w(dev, 0xa0, 0x09, 0xb003); | 2971 | reg_w(dev, 0xa0, 0x09, 0xb003); |
@@ -2981,7 +2982,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
2981 | /*fixme: is this useful?*/ | 2982 | /*fixme: is this useful?*/ |
2982 | if (sd->sensor == SENSOR_MI1310_SOC) | 2983 | if (sd->sensor == SENSOR_MI1310_SOC) |
2983 | reg_w(dev, 0x89, 0x058c, 0x00ff); | 2984 | reg_w(dev, 0x89, 0x058c, 0x00ff); |
2984 | else | 2985 | else if (!(sd->flags & FL_SAMSUNG)) |
2985 | reg_w(dev, 0x89, 0xffff, 0xffff); | 2986 | reg_w(dev, 0x89, 0xffff, 0xffff); |
2986 | } | 2987 | } |
2987 | 2988 | ||
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 63ea0fb66063..463ec3457d7b 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -246,7 +246,7 @@ MODULE_PARM_DESC(newi2c, | |||
246 | "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" | 246 | "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" |
247 | "\t\t\tDefault is autodetect"); | 247 | "\t\t\tDefault is autodetect"); |
248 | 248 | ||
249 | MODULE_PARM_DESC(ivtv_first_minor, "Set kernel number assigned to first card"); | 249 | MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first card"); |
250 | 250 | ||
251 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); | 251 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); |
252 | MODULE_DESCRIPTION("CX23415/CX23416 driver"); | 252 | MODULE_DESCRIPTION("CX23415/CX23416 driver"); |
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 8f15a31d3f66..b9c71e61f7d6 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c | |||
@@ -161,19 +161,19 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) | |||
161 | return -1; | 161 | return -1; |
162 | if (hw == IVTV_HW_TUNER) { | 162 | if (hw == IVTV_HW_TUNER) { |
163 | /* special tuner handling */ | 163 | /* special tuner handling */ |
164 | sd = v4l2_i2c_new_probed_subdev(&itv->v4l2_dev, | 164 | sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, |
165 | adap, mod, type, | 165 | adap, mod, type, |
166 | itv->card_i2c->radio); | 166 | 0, itv->card_i2c->radio); |
167 | if (sd) | 167 | if (sd) |
168 | sd->grp_id = 1 << idx; | 168 | sd->grp_id = 1 << idx; |
169 | sd = v4l2_i2c_new_probed_subdev(&itv->v4l2_dev, | 169 | sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, |
170 | adap, mod, type, | 170 | adap, mod, type, |
171 | itv->card_i2c->demod); | 171 | 0, itv->card_i2c->demod); |
172 | if (sd) | 172 | if (sd) |
173 | sd->grp_id = 1 << idx; | 173 | sd->grp_id = 1 << idx; |
174 | sd = v4l2_i2c_new_probed_subdev(&itv->v4l2_dev, | 174 | sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, |
175 | adap, mod, type, | 175 | adap, mod, type, |
176 | itv->card_i2c->tv); | 176 | 0, itv->card_i2c->tv); |
177 | if (sd) | 177 | if (sd) |
178 | sd->grp_id = 1 << idx; | 178 | sd->grp_id = 1 << idx; |
179 | return sd ? 0 : -1; | 179 | return sd ? 0 : -1; |
@@ -181,11 +181,11 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) | |||
181 | if (!hw_addrs[idx]) | 181 | if (!hw_addrs[idx]) |
182 | return -1; | 182 | return -1; |
183 | if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) { | 183 | if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) { |
184 | sd = v4l2_i2c_new_probed_subdev_addr(&itv->v4l2_dev, | 184 | sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, |
185 | adap, mod, type, hw_addrs[idx]); | 185 | adap, mod, type, 0, I2C_ADDRS(hw_addrs[idx])); |
186 | } else { | 186 | } else { |
187 | sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, | 187 | sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, |
188 | adap, mod, type, hw_addrs[idx]); | 188 | adap, mod, type, hw_addrs[idx], NULL); |
189 | } | 189 | } |
190 | if (sd) | 190 | if (sd) |
191 | sd->grp_id = 1 << idx; | 191 | sd->grp_id = 1 << idx; |
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 15da01710efc..67699e3f2aaa 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -261,8 +261,8 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) | |||
261 | video_set_drvdata(s->vdev, s); | 261 | video_set_drvdata(s->vdev, s); |
262 | 262 | ||
263 | /* Register device. First try the desired minor, then any free one. */ | 263 | /* Register device. First try the desired minor, then any free one. */ |
264 | if (video_register_device(s->vdev, vfl_type, num)) { | 264 | if (video_register_device_no_warn(s->vdev, vfl_type, num)) { |
265 | IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n", | 265 | IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", |
266 | s->name, num); | 266 | s->name, num); |
267 | video_device_release(s->vdev); | 267 | video_device_release(s->vdev); |
268 | s->vdev = NULL; | 268 | s->vdev = NULL; |
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 4d794b42d6cd..45388d2ce2fd 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c | |||
@@ -13,13 +13,13 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/log2.h> | 14 | #include <linux/log2.h> |
15 | 15 | ||
16 | #include <media/v4l2-common.h> | 16 | #include <media/v4l2-subdev.h> |
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | 19 | ||
20 | /* mt9m001 i2c address 0x5d | 20 | /* mt9m001 i2c address 0x5d |
21 | * The platform has to define i2c_board_info | 21 | * The platform has to define ctruct i2c_board_info objects and link to them |
22 | * and call i2c_register_board_info() */ | 22 | * from struct soc_camera_link */ |
23 | 23 | ||
24 | /* mt9m001 selected register addresses */ | 24 | /* mt9m001 selected register addresses */ |
25 | #define MT9M001_CHIP_VERSION 0x00 | 25 | #define MT9M001_CHIP_VERSION 0x00 |
@@ -39,6 +39,13 @@ | |||
39 | #define MT9M001_GLOBAL_GAIN 0x35 | 39 | #define MT9M001_GLOBAL_GAIN 0x35 |
40 | #define MT9M001_CHIP_ENABLE 0xF1 | 40 | #define MT9M001_CHIP_ENABLE 0xF1 |
41 | 41 | ||
42 | #define MT9M001_MAX_WIDTH 1280 | ||
43 | #define MT9M001_MAX_HEIGHT 1024 | ||
44 | #define MT9M001_MIN_WIDTH 48 | ||
45 | #define MT9M001_MIN_HEIGHT 32 | ||
46 | #define MT9M001_COLUMN_SKIP 20 | ||
47 | #define MT9M001_ROW_SKIP 12 | ||
48 | |||
42 | static const struct soc_camera_data_format mt9m001_colour_formats[] = { | 49 | static const struct soc_camera_data_format mt9m001_colour_formats[] = { |
43 | /* Order important: first natively supported, | 50 | /* Order important: first natively supported, |
44 | * second supported with a GPIO extender */ | 51 | * second supported with a GPIO extender */ |
@@ -69,12 +76,20 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = { | |||
69 | }; | 76 | }; |
70 | 77 | ||
71 | struct mt9m001 { | 78 | struct mt9m001 { |
72 | struct i2c_client *client; | 79 | struct v4l2_subdev subdev; |
73 | struct soc_camera_device icd; | 80 | struct v4l2_rect rect; /* Sensor window */ |
81 | __u32 fourcc; | ||
74 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ | 82 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ |
83 | unsigned int gain; | ||
84 | unsigned int exposure; | ||
75 | unsigned char autoexposure; | 85 | unsigned char autoexposure; |
76 | }; | 86 | }; |
77 | 87 | ||
88 | static struct mt9m001 *to_mt9m001(const struct i2c_client *client) | ||
89 | { | ||
90 | return container_of(i2c_get_clientdata(client), struct mt9m001, subdev); | ||
91 | } | ||
92 | |||
78 | static int reg_read(struct i2c_client *client, const u8 reg) | 93 | static int reg_read(struct i2c_client *client, const u8 reg) |
79 | { | 94 | { |
80 | s32 data = i2c_smbus_read_word_data(client, reg); | 95 | s32 data = i2c_smbus_read_word_data(client, reg); |
@@ -109,35 +124,20 @@ static int reg_clear(struct i2c_client *client, const u8 reg, | |||
109 | return reg_write(client, reg, ret & ~data); | 124 | return reg_write(client, reg, ret & ~data); |
110 | } | 125 | } |
111 | 126 | ||
112 | static int mt9m001_init(struct soc_camera_device *icd) | 127 | static int mt9m001_init(struct i2c_client *client) |
113 | { | 128 | { |
114 | struct i2c_client *client = to_i2c_client(icd->control); | ||
115 | struct soc_camera_link *icl = client->dev.platform_data; | ||
116 | int ret; | 129 | int ret; |
117 | 130 | ||
118 | dev_dbg(icd->vdev->parent, "%s\n", __func__); | 131 | dev_dbg(&client->dev, "%s\n", __func__); |
119 | 132 | ||
120 | if (icl->power) { | 133 | /* |
121 | ret = icl->power(&client->dev, 1); | 134 | * We don't know, whether platform provides reset, issue a soft reset |
122 | if (ret < 0) { | 135 | * too. This returns all registers to their default values. |
123 | dev_err(icd->vdev->parent, | 136 | */ |
124 | "Platform failed to power-on the camera.\n"); | 137 | ret = reg_write(client, MT9M001_RESET, 1); |
125 | return ret; | 138 | if (!ret) |
126 | } | 139 | ret = reg_write(client, MT9M001_RESET, 0); |
127 | } | ||
128 | |||
129 | /* The camera could have been already on, we reset it additionally */ | ||
130 | if (icl->reset) | ||
131 | ret = icl->reset(&client->dev); | ||
132 | else | ||
133 | ret = -ENODEV; | ||
134 | 140 | ||
135 | if (ret < 0) { | ||
136 | /* Either no platform reset, or platform reset failed */ | ||
137 | ret = reg_write(client, MT9M001_RESET, 1); | ||
138 | if (!ret) | ||
139 | ret = reg_write(client, MT9M001_RESET, 0); | ||
140 | } | ||
141 | /* Disable chip, synchronous option update */ | 141 | /* Disable chip, synchronous option update */ |
142 | if (!ret) | 142 | if (!ret) |
143 | ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); | 143 | ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); |
@@ -145,36 +145,12 @@ static int mt9m001_init(struct soc_camera_device *icd) | |||
145 | return ret; | 145 | return ret; |
146 | } | 146 | } |
147 | 147 | ||
148 | static int mt9m001_release(struct soc_camera_device *icd) | 148 | static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) |
149 | { | 149 | { |
150 | struct i2c_client *client = to_i2c_client(icd->control); | 150 | struct i2c_client *client = sd->priv; |
151 | struct soc_camera_link *icl = client->dev.platform_data; | ||
152 | |||
153 | /* Disable the chip */ | ||
154 | reg_write(client, MT9M001_OUTPUT_CONTROL, 0); | ||
155 | |||
156 | if (icl->power) | ||
157 | icl->power(&client->dev, 0); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | 151 | ||
162 | static int mt9m001_start_capture(struct soc_camera_device *icd) | 152 | /* Switch to master "normal" mode or stop sensor readout */ |
163 | { | 153 | if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0) |
164 | struct i2c_client *client = to_i2c_client(icd->control); | ||
165 | |||
166 | /* Switch to master "normal" mode */ | ||
167 | if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0) | ||
168 | return -EIO; | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int mt9m001_stop_capture(struct soc_camera_device *icd) | ||
173 | { | ||
174 | struct i2c_client *client = to_i2c_client(icd->control); | ||
175 | |||
176 | /* Stop sensor readout */ | ||
177 | if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0) | ||
178 | return -EIO; | 154 | return -EIO; |
179 | return 0; | 155 | return 0; |
180 | } | 156 | } |
@@ -182,8 +158,7 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd) | |||
182 | static int mt9m001_set_bus_param(struct soc_camera_device *icd, | 158 | static int mt9m001_set_bus_param(struct soc_camera_device *icd, |
183 | unsigned long flags) | 159 | unsigned long flags) |
184 | { | 160 | { |
185 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 161 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
186 | struct soc_camera_link *icl = mt9m001->client->dev.platform_data; | ||
187 | unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; | 162 | unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; |
188 | 163 | ||
189 | /* Only one width bit may be set */ | 164 | /* Only one width bit may be set */ |
@@ -205,8 +180,7 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd, | |||
205 | 180 | ||
206 | static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) | 181 | static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) |
207 | { | 182 | { |
208 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 183 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
209 | struct soc_camera_link *icl = mt9m001->client->dev.platform_data; | ||
210 | /* MT9M001 has all capture_format parameters fixed */ | 184 | /* MT9M001 has all capture_format parameters fixed */ |
211 | unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | | 185 | unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | |
212 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | 186 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | |
@@ -220,13 +194,35 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) | |||
220 | return soc_camera_apply_sensor_flags(icl, flags); | 194 | return soc_camera_apply_sensor_flags(icl, flags); |
221 | } | 195 | } |
222 | 196 | ||
223 | static int mt9m001_set_crop(struct soc_camera_device *icd, | 197 | static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
224 | struct v4l2_rect *rect) | ||
225 | { | 198 | { |
226 | struct i2c_client *client = to_i2c_client(icd->control); | 199 | struct i2c_client *client = sd->priv; |
227 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 200 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
201 | struct v4l2_rect rect = a->c; | ||
202 | struct soc_camera_device *icd = client->dev.platform_data; | ||
228 | int ret; | 203 | int ret; |
229 | const u16 hblank = 9, vblank = 25; | 204 | const u16 hblank = 9, vblank = 25; |
205 | unsigned int total_h; | ||
206 | |||
207 | if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 || | ||
208 | mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16) | ||
209 | /* | ||
210 | * Bayer format - even number of rows for simplicity, | ||
211 | * but let the user play with the top row. | ||
212 | */ | ||
213 | rect.height = ALIGN(rect.height, 2); | ||
214 | |||
215 | /* Datasheet requirement: see register description */ | ||
216 | rect.width = ALIGN(rect.width, 2); | ||
217 | rect.left = ALIGN(rect.left, 2); | ||
218 | |||
219 | soc_camera_limit_side(&rect.left, &rect.width, | ||
220 | MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH); | ||
221 | |||
222 | soc_camera_limit_side(&rect.top, &rect.height, | ||
223 | MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); | ||
224 | |||
225 | total_h = rect.height + icd->y_skip_top + vblank; | ||
230 | 226 | ||
231 | /* Blanking and start values - default... */ | 227 | /* Blanking and start values - default... */ |
232 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); | 228 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); |
@@ -236,66 +232,126 @@ static int mt9m001_set_crop(struct soc_camera_device *icd, | |||
236 | /* The caller provides a supported format, as verified per | 232 | /* The caller provides a supported format, as verified per |
237 | * call to icd->try_fmt() */ | 233 | * call to icd->try_fmt() */ |
238 | if (!ret) | 234 | if (!ret) |
239 | ret = reg_write(client, MT9M001_COLUMN_START, rect->left); | 235 | ret = reg_write(client, MT9M001_COLUMN_START, rect.left); |
240 | if (!ret) | 236 | if (!ret) |
241 | ret = reg_write(client, MT9M001_ROW_START, rect->top); | 237 | ret = reg_write(client, MT9M001_ROW_START, rect.top); |
242 | if (!ret) | 238 | if (!ret) |
243 | ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1); | 239 | ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); |
244 | if (!ret) | 240 | if (!ret) |
245 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, | 241 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, |
246 | rect->height + icd->y_skip_top - 1); | 242 | rect.height + icd->y_skip_top - 1); |
247 | if (!ret && mt9m001->autoexposure) { | 243 | if (!ret && mt9m001->autoexposure) { |
248 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, | 244 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); |
249 | rect->height + icd->y_skip_top + vblank); | ||
250 | if (!ret) { | 245 | if (!ret) { |
251 | const struct v4l2_queryctrl *qctrl = | 246 | const struct v4l2_queryctrl *qctrl = |
252 | soc_camera_find_qctrl(icd->ops, | 247 | soc_camera_find_qctrl(icd->ops, |
253 | V4L2_CID_EXPOSURE); | 248 | V4L2_CID_EXPOSURE); |
254 | icd->exposure = (524 + (rect->height + icd->y_skip_top + | 249 | mt9m001->exposure = (524 + (total_h - 1) * |
255 | vblank - 1) * | 250 | (qctrl->maximum - qctrl->minimum)) / |
256 | (qctrl->maximum - qctrl->minimum)) / | ||
257 | 1048 + qctrl->minimum; | 251 | 1048 + qctrl->minimum; |
258 | } | 252 | } |
259 | } | 253 | } |
260 | 254 | ||
255 | if (!ret) | ||
256 | mt9m001->rect = rect; | ||
257 | |||
261 | return ret; | 258 | return ret; |
262 | } | 259 | } |
263 | 260 | ||
264 | static int mt9m001_set_fmt(struct soc_camera_device *icd, | 261 | static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
265 | struct v4l2_format *f) | 262 | { |
263 | struct i2c_client *client = sd->priv; | ||
264 | struct mt9m001 *mt9m001 = to_mt9m001(client); | ||
265 | |||
266 | a->c = mt9m001->rect; | ||
267 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
273 | { | ||
274 | a->bounds.left = MT9M001_COLUMN_SKIP; | ||
275 | a->bounds.top = MT9M001_ROW_SKIP; | ||
276 | a->bounds.width = MT9M001_MAX_WIDTH; | ||
277 | a->bounds.height = MT9M001_MAX_HEIGHT; | ||
278 | a->defrect = a->bounds; | ||
279 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
280 | a->pixelaspect.numerator = 1; | ||
281 | a->pixelaspect.denominator = 1; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int mt9m001_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
266 | { | 287 | { |
267 | struct v4l2_rect rect = { | 288 | struct i2c_client *client = sd->priv; |
268 | .left = icd->x_current, | 289 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
269 | .top = icd->y_current, | 290 | struct v4l2_pix_format *pix = &f->fmt.pix; |
270 | .width = f->fmt.pix.width, | 291 | |
271 | .height = f->fmt.pix.height, | 292 | pix->width = mt9m001->rect.width; |
293 | pix->height = mt9m001->rect.height; | ||
294 | pix->pixelformat = mt9m001->fourcc; | ||
295 | pix->field = V4L2_FIELD_NONE; | ||
296 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
302 | { | ||
303 | struct i2c_client *client = sd->priv; | ||
304 | struct mt9m001 *mt9m001 = to_mt9m001(client); | ||
305 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
306 | struct v4l2_crop a = { | ||
307 | .c = { | ||
308 | .left = mt9m001->rect.left, | ||
309 | .top = mt9m001->rect.top, | ||
310 | .width = pix->width, | ||
311 | .height = pix->height, | ||
312 | }, | ||
272 | }; | 313 | }; |
314 | int ret; | ||
273 | 315 | ||
274 | /* No support for scaling so far, just crop. TODO: use skipping */ | 316 | /* No support for scaling so far, just crop. TODO: use skipping */ |
275 | return mt9m001_set_crop(icd, &rect); | 317 | ret = mt9m001_s_crop(sd, &a); |
318 | if (!ret) { | ||
319 | pix->width = mt9m001->rect.width; | ||
320 | pix->height = mt9m001->rect.height; | ||
321 | mt9m001->fourcc = pix->pixelformat; | ||
322 | } | ||
323 | |||
324 | return ret; | ||
276 | } | 325 | } |
277 | 326 | ||
278 | static int mt9m001_try_fmt(struct soc_camera_device *icd, | 327 | static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
279 | struct v4l2_format *f) | ||
280 | { | 328 | { |
329 | struct i2c_client *client = sd->priv; | ||
330 | struct soc_camera_device *icd = client->dev.platform_data; | ||
281 | struct v4l2_pix_format *pix = &f->fmt.pix; | 331 | struct v4l2_pix_format *pix = &f->fmt.pix; |
282 | 332 | ||
283 | v4l_bound_align_image(&pix->width, 48, 1280, 1, | 333 | v4l_bound_align_image(&pix->width, MT9M001_MIN_WIDTH, |
284 | &pix->height, 32 + icd->y_skip_top, | 334 | MT9M001_MAX_WIDTH, 1, |
285 | 1024 + icd->y_skip_top, 0, 0); | 335 | &pix->height, MT9M001_MIN_HEIGHT + icd->y_skip_top, |
336 | MT9M001_MAX_HEIGHT + icd->y_skip_top, 0, 0); | ||
337 | |||
338 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | ||
339 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16) | ||
340 | pix->height = ALIGN(pix->height - 1, 2); | ||
286 | 341 | ||
287 | return 0; | 342 | return 0; |
288 | } | 343 | } |
289 | 344 | ||
290 | static int mt9m001_get_chip_id(struct soc_camera_device *icd, | 345 | static int mt9m001_g_chip_ident(struct v4l2_subdev *sd, |
291 | struct v4l2_dbg_chip_ident *id) | 346 | struct v4l2_dbg_chip_ident *id) |
292 | { | 347 | { |
293 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 348 | struct i2c_client *client = sd->priv; |
349 | struct mt9m001 *mt9m001 = to_mt9m001(client); | ||
294 | 350 | ||
295 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 351 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
296 | return -EINVAL; | 352 | return -EINVAL; |
297 | 353 | ||
298 | if (id->match.addr != mt9m001->client->addr) | 354 | if (id->match.addr != client->addr) |
299 | return -ENODEV; | 355 | return -ENODEV; |
300 | 356 | ||
301 | id->ident = mt9m001->model; | 357 | id->ident = mt9m001->model; |
@@ -305,10 +361,10 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd, | |||
305 | } | 361 | } |
306 | 362 | ||
307 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 363 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
308 | static int mt9m001_get_register(struct soc_camera_device *icd, | 364 | static int mt9m001_g_register(struct v4l2_subdev *sd, |
309 | struct v4l2_dbg_register *reg) | 365 | struct v4l2_dbg_register *reg) |
310 | { | 366 | { |
311 | struct i2c_client *client = to_i2c_client(icd->control); | 367 | struct i2c_client *client = sd->priv; |
312 | 368 | ||
313 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 369 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
314 | return -EINVAL; | 370 | return -EINVAL; |
@@ -325,10 +381,10 @@ static int mt9m001_get_register(struct soc_camera_device *icd, | |||
325 | return 0; | 381 | return 0; |
326 | } | 382 | } |
327 | 383 | ||
328 | static int mt9m001_set_register(struct soc_camera_device *icd, | 384 | static int mt9m001_s_register(struct v4l2_subdev *sd, |
329 | struct v4l2_dbg_register *reg) | 385 | struct v4l2_dbg_register *reg) |
330 | { | 386 | { |
331 | struct i2c_client *client = to_i2c_client(icd->control); | 387 | struct i2c_client *client = sd->priv; |
332 | 388 | ||
333 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 389 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
334 | return -EINVAL; | 390 | return -EINVAL; |
@@ -381,39 +437,17 @@ static const struct v4l2_queryctrl mt9m001_controls[] = { | |||
381 | } | 437 | } |
382 | }; | 438 | }; |
383 | 439 | ||
384 | static int mt9m001_video_probe(struct soc_camera_device *); | ||
385 | static void mt9m001_video_remove(struct soc_camera_device *); | ||
386 | static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *); | ||
387 | static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *); | ||
388 | |||
389 | static struct soc_camera_ops mt9m001_ops = { | 440 | static struct soc_camera_ops mt9m001_ops = { |
390 | .owner = THIS_MODULE, | ||
391 | .probe = mt9m001_video_probe, | ||
392 | .remove = mt9m001_video_remove, | ||
393 | .init = mt9m001_init, | ||
394 | .release = mt9m001_release, | ||
395 | .start_capture = mt9m001_start_capture, | ||
396 | .stop_capture = mt9m001_stop_capture, | ||
397 | .set_crop = mt9m001_set_crop, | ||
398 | .set_fmt = mt9m001_set_fmt, | ||
399 | .try_fmt = mt9m001_try_fmt, | ||
400 | .set_bus_param = mt9m001_set_bus_param, | 441 | .set_bus_param = mt9m001_set_bus_param, |
401 | .query_bus_param = mt9m001_query_bus_param, | 442 | .query_bus_param = mt9m001_query_bus_param, |
402 | .controls = mt9m001_controls, | 443 | .controls = mt9m001_controls, |
403 | .num_controls = ARRAY_SIZE(mt9m001_controls), | 444 | .num_controls = ARRAY_SIZE(mt9m001_controls), |
404 | .get_control = mt9m001_get_control, | ||
405 | .set_control = mt9m001_set_control, | ||
406 | .get_chip_id = mt9m001_get_chip_id, | ||
407 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
408 | .get_register = mt9m001_get_register, | ||
409 | .set_register = mt9m001_set_register, | ||
410 | #endif | ||
411 | }; | 445 | }; |
412 | 446 | ||
413 | static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 447 | static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
414 | { | 448 | { |
415 | struct i2c_client *client = to_i2c_client(icd->control); | 449 | struct i2c_client *client = sd->priv; |
416 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 450 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
417 | int data; | 451 | int data; |
418 | 452 | ||
419 | switch (ctrl->id) { | 453 | switch (ctrl->id) { |
@@ -426,14 +460,21 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro | |||
426 | case V4L2_CID_EXPOSURE_AUTO: | 460 | case V4L2_CID_EXPOSURE_AUTO: |
427 | ctrl->value = mt9m001->autoexposure; | 461 | ctrl->value = mt9m001->autoexposure; |
428 | break; | 462 | break; |
463 | case V4L2_CID_GAIN: | ||
464 | ctrl->value = mt9m001->gain; | ||
465 | break; | ||
466 | case V4L2_CID_EXPOSURE: | ||
467 | ctrl->value = mt9m001->exposure; | ||
468 | break; | ||
429 | } | 469 | } |
430 | return 0; | 470 | return 0; |
431 | } | 471 | } |
432 | 472 | ||
433 | static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 473 | static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
434 | { | 474 | { |
435 | struct i2c_client *client = to_i2c_client(icd->control); | 475 | struct i2c_client *client = sd->priv; |
436 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 476 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
477 | struct soc_camera_device *icd = client->dev.platform_data; | ||
437 | const struct v4l2_queryctrl *qctrl; | 478 | const struct v4l2_queryctrl *qctrl; |
438 | int data; | 479 | int data; |
439 | 480 | ||
@@ -460,7 +501,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
460 | unsigned long range = qctrl->default_value - qctrl->minimum; | 501 | unsigned long range = qctrl->default_value - qctrl->minimum; |
461 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 502 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; |
462 | 503 | ||
463 | dev_dbg(&icd->dev, "Setting gain %d\n", data); | 504 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
464 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); | 505 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); |
465 | if (data < 0) | 506 | if (data < 0) |
466 | return -EIO; | 507 | return -EIO; |
@@ -478,7 +519,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
478 | else | 519 | else |
479 | data = ((gain - 64) * 7 + 28) / 56 + 96; | 520 | data = ((gain - 64) * 7 + 28) / 56 + 96; |
480 | 521 | ||
481 | dev_dbg(&icd->dev, "Setting gain from %d to %d\n", | 522 | dev_dbg(&client->dev, "Setting gain from %d to %d\n", |
482 | reg_read(client, MT9M001_GLOBAL_GAIN), data); | 523 | reg_read(client, MT9M001_GLOBAL_GAIN), data); |
483 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); | 524 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); |
484 | if (data < 0) | 525 | if (data < 0) |
@@ -486,7 +527,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
486 | } | 527 | } |
487 | 528 | ||
488 | /* Success */ | 529 | /* Success */ |
489 | icd->gain = ctrl->value; | 530 | mt9m001->gain = ctrl->value; |
490 | break; | 531 | break; |
491 | case V4L2_CID_EXPOSURE: | 532 | case V4L2_CID_EXPOSURE: |
492 | /* mt9m001 has maximum == default */ | 533 | /* mt9m001 has maximum == default */ |
@@ -497,23 +538,27 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
497 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + | 538 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + |
498 | range / 2) / range + 1; | 539 | range / 2) / range + 1; |
499 | 540 | ||
500 | dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n", | 541 | dev_dbg(&client->dev, |
501 | reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); | 542 | "Setting shutter width from %d to %lu\n", |
543 | reg_read(client, MT9M001_SHUTTER_WIDTH), | ||
544 | shutter); | ||
502 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) | 545 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) |
503 | return -EIO; | 546 | return -EIO; |
504 | icd->exposure = ctrl->value; | 547 | mt9m001->exposure = ctrl->value; |
505 | mt9m001->autoexposure = 0; | 548 | mt9m001->autoexposure = 0; |
506 | } | 549 | } |
507 | break; | 550 | break; |
508 | case V4L2_CID_EXPOSURE_AUTO: | 551 | case V4L2_CID_EXPOSURE_AUTO: |
509 | if (ctrl->value) { | 552 | if (ctrl->value) { |
510 | const u16 vblank = 25; | 553 | const u16 vblank = 25; |
511 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height + | 554 | unsigned int total_h = mt9m001->rect.height + |
512 | icd->y_skip_top + vblank) < 0) | 555 | icd->y_skip_top + vblank; |
556 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, | ||
557 | total_h) < 0) | ||
513 | return -EIO; | 558 | return -EIO; |
514 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | 559 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); |
515 | icd->exposure = (524 + (icd->height + icd->y_skip_top + vblank - 1) * | 560 | mt9m001->exposure = (524 + (total_h - 1) * |
516 | (qctrl->maximum - qctrl->minimum)) / | 561 | (qctrl->maximum - qctrl->minimum)) / |
517 | 1048 + qctrl->minimum; | 562 | 1048 + qctrl->minimum; |
518 | mt9m001->autoexposure = 1; | 563 | mt9m001->autoexposure = 1; |
519 | } else | 564 | } else |
@@ -525,14 +570,14 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
525 | 570 | ||
526 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 571 | /* Interface active, can use i2c. If it fails, it can indeed mean, that |
527 | * this wasn't our capture interface, so, we wait for the right one */ | 572 | * this wasn't our capture interface, so, we wait for the right one */ |
528 | static int mt9m001_video_probe(struct soc_camera_device *icd) | 573 | static int mt9m001_video_probe(struct soc_camera_device *icd, |
574 | struct i2c_client *client) | ||
529 | { | 575 | { |
530 | struct i2c_client *client = to_i2c_client(icd->control); | 576 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
531 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 577 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
532 | struct soc_camera_link *icl = client->dev.platform_data; | ||
533 | s32 data; | 578 | s32 data; |
534 | int ret; | ||
535 | unsigned long flags; | 579 | unsigned long flags; |
580 | int ret; | ||
536 | 581 | ||
537 | /* We must have a parent by now. And it cannot be a wrong one. | 582 | /* We must have a parent by now. And it cannot be a wrong one. |
538 | * So this entire test is completely redundant. */ | 583 | * So this entire test is completely redundant. */ |
@@ -542,7 +587,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) | |||
542 | 587 | ||
543 | /* Enable the chip */ | 588 | /* Enable the chip */ |
544 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); | 589 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); |
545 | dev_dbg(&icd->dev, "write: %d\n", data); | 590 | dev_dbg(&client->dev, "write: %d\n", data); |
546 | 591 | ||
547 | /* Read out the chip version register */ | 592 | /* Read out the chip version register */ |
548 | data = reg_read(client, MT9M001_CHIP_VERSION); | 593 | data = reg_read(client, MT9M001_CHIP_VERSION); |
@@ -559,10 +604,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) | |||
559 | icd->formats = mt9m001_monochrome_formats; | 604 | icd->formats = mt9m001_monochrome_formats; |
560 | break; | 605 | break; |
561 | default: | 606 | default: |
562 | ret = -ENODEV; | 607 | dev_err(&client->dev, |
563 | dev_err(&icd->dev, | ||
564 | "No MT9M001 chip detected, register read %x\n", data); | 608 | "No MT9M001 chip detected, register read %x\n", data); |
565 | goto ei2c; | 609 | return -ENODEV; |
566 | } | 610 | } |
567 | 611 | ||
568 | icd->num_formats = 0; | 612 | icd->num_formats = 0; |
@@ -585,42 +629,72 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) | |||
585 | if (flags & SOCAM_DATAWIDTH_8) | 629 | if (flags & SOCAM_DATAWIDTH_8) |
586 | icd->num_formats++; | 630 | icd->num_formats++; |
587 | 631 | ||
588 | dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, | 632 | mt9m001->fourcc = icd->formats->fourcc; |
633 | |||
634 | dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, | ||
589 | data == 0x8431 ? "C12STM" : "C12ST"); | 635 | data == 0x8431 ? "C12STM" : "C12ST"); |
590 | 636 | ||
591 | /* Now that we know the model, we can start video */ | 637 | ret = mt9m001_init(client); |
592 | ret = soc_camera_video_start(icd); | 638 | if (ret < 0) |
593 | if (ret) | 639 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
594 | goto eisis; | ||
595 | 640 | ||
596 | return 0; | 641 | /* mt9m001_init() has reset the chip, returning registers to defaults */ |
642 | mt9m001->gain = 64; | ||
643 | mt9m001->exposure = 255; | ||
597 | 644 | ||
598 | eisis: | ||
599 | ei2c: | ||
600 | return ret; | 645 | return ret; |
601 | } | 646 | } |
602 | 647 | ||
603 | static void mt9m001_video_remove(struct soc_camera_device *icd) | 648 | static void mt9m001_video_remove(struct soc_camera_device *icd) |
604 | { | 649 | { |
605 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 650 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
606 | struct soc_camera_link *icl = mt9m001->client->dev.platform_data; | ||
607 | 651 | ||
608 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr, | 652 | dev_dbg(&icd->dev, "Video removed: %p, %p\n", |
609 | icd->dev.parent, icd->vdev); | 653 | icd->dev.parent, icd->vdev); |
610 | soc_camera_video_stop(icd); | ||
611 | if (icl->free_bus) | 654 | if (icl->free_bus) |
612 | icl->free_bus(icl); | 655 | icl->free_bus(icl); |
613 | } | 656 | } |
614 | 657 | ||
658 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { | ||
659 | .g_ctrl = mt9m001_g_ctrl, | ||
660 | .s_ctrl = mt9m001_s_ctrl, | ||
661 | .g_chip_ident = mt9m001_g_chip_ident, | ||
662 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
663 | .g_register = mt9m001_g_register, | ||
664 | .s_register = mt9m001_s_register, | ||
665 | #endif | ||
666 | }; | ||
667 | |||
668 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | ||
669 | .s_stream = mt9m001_s_stream, | ||
670 | .s_fmt = mt9m001_s_fmt, | ||
671 | .g_fmt = mt9m001_g_fmt, | ||
672 | .try_fmt = mt9m001_try_fmt, | ||
673 | .s_crop = mt9m001_s_crop, | ||
674 | .g_crop = mt9m001_g_crop, | ||
675 | .cropcap = mt9m001_cropcap, | ||
676 | }; | ||
677 | |||
678 | static struct v4l2_subdev_ops mt9m001_subdev_ops = { | ||
679 | .core = &mt9m001_subdev_core_ops, | ||
680 | .video = &mt9m001_subdev_video_ops, | ||
681 | }; | ||
682 | |||
615 | static int mt9m001_probe(struct i2c_client *client, | 683 | static int mt9m001_probe(struct i2c_client *client, |
616 | const struct i2c_device_id *did) | 684 | const struct i2c_device_id *did) |
617 | { | 685 | { |
618 | struct mt9m001 *mt9m001; | 686 | struct mt9m001 *mt9m001; |
619 | struct soc_camera_device *icd; | 687 | struct soc_camera_device *icd = client->dev.platform_data; |
620 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 688 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
621 | struct soc_camera_link *icl = client->dev.platform_data; | 689 | struct soc_camera_link *icl; |
622 | int ret; | 690 | int ret; |
623 | 691 | ||
692 | if (!icd) { | ||
693 | dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); | ||
694 | return -EINVAL; | ||
695 | } | ||
696 | |||
697 | icl = to_soc_camera_link(icd); | ||
624 | if (!icl) { | 698 | if (!icl) { |
625 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); | 699 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); |
626 | return -EINVAL; | 700 | return -EINVAL; |
@@ -636,43 +710,40 @@ static int mt9m001_probe(struct i2c_client *client, | |||
636 | if (!mt9m001) | 710 | if (!mt9m001) |
637 | return -ENOMEM; | 711 | return -ENOMEM; |
638 | 712 | ||
639 | mt9m001->client = client; | 713 | v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); |
640 | i2c_set_clientdata(client, mt9m001); | ||
641 | 714 | ||
642 | /* Second stage probe - when a capture adapter is there */ | 715 | /* Second stage probe - when a capture adapter is there */ |
643 | icd = &mt9m001->icd; | 716 | icd->ops = &mt9m001_ops; |
644 | icd->ops = &mt9m001_ops; | 717 | icd->y_skip_top = 0; |
645 | icd->control = &client->dev; | 718 | |
646 | icd->x_min = 20; | 719 | mt9m001->rect.left = MT9M001_COLUMN_SKIP; |
647 | icd->y_min = 12; | 720 | mt9m001->rect.top = MT9M001_ROW_SKIP; |
648 | icd->x_current = 20; | 721 | mt9m001->rect.width = MT9M001_MAX_WIDTH; |
649 | icd->y_current = 12; | 722 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; |
650 | icd->width_min = 48; | 723 | |
651 | icd->width_max = 1280; | ||
652 | icd->height_min = 32; | ||
653 | icd->height_max = 1024; | ||
654 | icd->y_skip_top = 1; | ||
655 | icd->iface = icl->bus_id; | ||
656 | /* Simulated autoexposure. If enabled, we calculate shutter width | 724 | /* Simulated autoexposure. If enabled, we calculate shutter width |
657 | * ourselves in the driver based on vertical blanking and frame width */ | 725 | * ourselves in the driver based on vertical blanking and frame width */ |
658 | mt9m001->autoexposure = 1; | 726 | mt9m001->autoexposure = 1; |
659 | 727 | ||
660 | ret = soc_camera_device_register(icd); | 728 | ret = mt9m001_video_probe(icd, client); |
661 | if (ret) | 729 | if (ret) { |
662 | goto eisdr; | 730 | icd->ops = NULL; |
663 | 731 | i2c_set_clientdata(client, NULL); | |
664 | return 0; | 732 | kfree(mt9m001); |
733 | } | ||
665 | 734 | ||
666 | eisdr: | ||
667 | kfree(mt9m001); | ||
668 | return ret; | 735 | return ret; |
669 | } | 736 | } |
670 | 737 | ||
671 | static int mt9m001_remove(struct i2c_client *client) | 738 | static int mt9m001_remove(struct i2c_client *client) |
672 | { | 739 | { |
673 | struct mt9m001 *mt9m001 = i2c_get_clientdata(client); | 740 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
741 | struct soc_camera_device *icd = client->dev.platform_data; | ||
674 | 742 | ||
675 | soc_camera_device_unregister(&mt9m001->icd); | 743 | icd->ops = NULL; |
744 | mt9m001_video_remove(icd); | ||
745 | i2c_set_clientdata(client, NULL); | ||
746 | client->driver = NULL; | ||
676 | kfree(mt9m001); | 747 | kfree(mt9m001); |
677 | 748 | ||
678 | return 0; | 749 | return 0; |
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index fc5e2de03766..90da699601ea 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -148,12 +148,12 @@ enum mt9m111_context { | |||
148 | }; | 148 | }; |
149 | 149 | ||
150 | struct mt9m111 { | 150 | struct mt9m111 { |
151 | struct i2c_client *client; | 151 | struct v4l2_subdev subdev; |
152 | struct soc_camera_device icd; | ||
153 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ | 152 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ |
154 | enum mt9m111_context context; | 153 | enum mt9m111_context context; |
155 | struct v4l2_rect rect; | 154 | struct v4l2_rect rect; |
156 | u32 pixfmt; | 155 | u32 pixfmt; |
156 | unsigned int gain; | ||
157 | unsigned char autoexposure; | 157 | unsigned char autoexposure; |
158 | unsigned char datawidth; | 158 | unsigned char datawidth; |
159 | unsigned int powered:1; | 159 | unsigned int powered:1; |
@@ -166,6 +166,11 @@ struct mt9m111 { | |||
166 | unsigned int autowhitebalance:1; | 166 | unsigned int autowhitebalance:1; |
167 | }; | 167 | }; |
168 | 168 | ||
169 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) | ||
170 | { | ||
171 | return container_of(i2c_get_clientdata(client), struct mt9m111, subdev); | ||
172 | } | ||
173 | |||
169 | static int reg_page_map_set(struct i2c_client *client, const u16 reg) | 174 | static int reg_page_map_set(struct i2c_client *client, const u16 reg) |
170 | { | 175 | { |
171 | int ret; | 176 | int ret; |
@@ -190,7 +195,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) | |||
190 | 195 | ||
191 | ret = reg_page_map_set(client, reg); | 196 | ret = reg_page_map_set(client, reg); |
192 | if (!ret) | 197 | if (!ret) |
193 | ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff))); | 198 | ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff)); |
194 | 199 | ||
195 | dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); | 200 | dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); |
196 | return ret; | 201 | return ret; |
@@ -203,7 +208,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, | |||
203 | 208 | ||
204 | ret = reg_page_map_set(client, reg); | 209 | ret = reg_page_map_set(client, reg); |
205 | if (!ret) | 210 | if (!ret) |
206 | ret = i2c_smbus_write_word_data(client, (reg & 0xff), | 211 | ret = i2c_smbus_write_word_data(client, reg & 0xff, |
207 | swab16(data)); | 212 | swab16(data)); |
208 | dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); | 213 | dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); |
209 | return ret; | 214 | return ret; |
@@ -229,10 +234,9 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg, | |||
229 | return mt9m111_reg_write(client, reg, ret & ~data); | 234 | return mt9m111_reg_write(client, reg, ret & ~data); |
230 | } | 235 | } |
231 | 236 | ||
232 | static int mt9m111_set_context(struct soc_camera_device *icd, | 237 | static int mt9m111_set_context(struct i2c_client *client, |
233 | enum mt9m111_context ctxt) | 238 | enum mt9m111_context ctxt) |
234 | { | 239 | { |
235 | struct i2c_client *client = to_i2c_client(icd->control); | ||
236 | int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B | 240 | int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B |
237 | | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B | 241 | | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B |
238 | | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B | 242 | | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B |
@@ -246,17 +250,16 @@ static int mt9m111_set_context(struct soc_camera_device *icd, | |||
246 | return reg_write(CONTEXT_CONTROL, valA); | 250 | return reg_write(CONTEXT_CONTROL, valA); |
247 | } | 251 | } |
248 | 252 | ||
249 | static int mt9m111_setup_rect(struct soc_camera_device *icd, | 253 | static int mt9m111_setup_rect(struct i2c_client *client, |
250 | struct v4l2_rect *rect) | 254 | struct v4l2_rect *rect) |
251 | { | 255 | { |
252 | struct i2c_client *client = to_i2c_client(icd->control); | 256 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
253 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
254 | int ret, is_raw_format; | 257 | int ret, is_raw_format; |
255 | int width = rect->width; | 258 | int width = rect->width; |
256 | int height = rect->height; | 259 | int height = rect->height; |
257 | 260 | ||
258 | if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8) | 261 | if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || |
259 | || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)) | 262 | mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) |
260 | is_raw_format = 1; | 263 | is_raw_format = 1; |
261 | else | 264 | else |
262 | is_raw_format = 0; | 265 | is_raw_format = 0; |
@@ -292,9 +295,8 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd, | |||
292 | return ret; | 295 | return ret; |
293 | } | 296 | } |
294 | 297 | ||
295 | static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) | 298 | static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) |
296 | { | 299 | { |
297 | struct i2c_client *client = to_i2c_client(icd->control); | ||
298 | int ret; | 300 | int ret; |
299 | 301 | ||
300 | ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); | 302 | ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); |
@@ -303,19 +305,19 @@ static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) | |||
303 | return ret; | 305 | return ret; |
304 | } | 306 | } |
305 | 307 | ||
306 | static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd) | 308 | static int mt9m111_setfmt_bayer8(struct i2c_client *client) |
307 | { | 309 | { |
308 | return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER); | 310 | return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER); |
309 | } | 311 | } |
310 | 312 | ||
311 | static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd) | 313 | static int mt9m111_setfmt_bayer10(struct i2c_client *client) |
312 | { | 314 | { |
313 | return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP); | 315 | return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP); |
314 | } | 316 | } |
315 | 317 | ||
316 | static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd) | 318 | static int mt9m111_setfmt_rgb565(struct i2c_client *client) |
317 | { | 319 | { |
318 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 320 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
319 | int val = 0; | 321 | int val = 0; |
320 | 322 | ||
321 | if (mt9m111->swap_rgb_red_blue) | 323 | if (mt9m111->swap_rgb_red_blue) |
@@ -324,12 +326,12 @@ static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd) | |||
324 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; | 326 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; |
325 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; | 327 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; |
326 | 328 | ||
327 | return mt9m111_setup_pixfmt(icd, val); | 329 | return mt9m111_setup_pixfmt(client, val); |
328 | } | 330 | } |
329 | 331 | ||
330 | static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd) | 332 | static int mt9m111_setfmt_rgb555(struct i2c_client *client) |
331 | { | 333 | { |
332 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 334 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
333 | int val = 0; | 335 | int val = 0; |
334 | 336 | ||
335 | if (mt9m111->swap_rgb_red_blue) | 337 | if (mt9m111->swap_rgb_red_blue) |
@@ -338,12 +340,12 @@ static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd) | |||
338 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; | 340 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; |
339 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; | 341 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; |
340 | 342 | ||
341 | return mt9m111_setup_pixfmt(icd, val); | 343 | return mt9m111_setup_pixfmt(client, val); |
342 | } | 344 | } |
343 | 345 | ||
344 | static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) | 346 | static int mt9m111_setfmt_yuv(struct i2c_client *client) |
345 | { | 347 | { |
346 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 348 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
347 | int val = 0; | 349 | int val = 0; |
348 | 350 | ||
349 | if (mt9m111->swap_yuv_cb_cr) | 351 | if (mt9m111->swap_yuv_cb_cr) |
@@ -351,52 +353,22 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) | |||
351 | if (mt9m111->swap_yuv_y_chromas) | 353 | if (mt9m111->swap_yuv_y_chromas) |
352 | val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; | 354 | val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; |
353 | 355 | ||
354 | return mt9m111_setup_pixfmt(icd, val); | 356 | return mt9m111_setup_pixfmt(client, val); |
355 | } | 357 | } |
356 | 358 | ||
357 | static int mt9m111_enable(struct soc_camera_device *icd) | 359 | static int mt9m111_enable(struct i2c_client *client) |
358 | { | 360 | { |
359 | struct i2c_client *client = to_i2c_client(icd->control); | 361 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
360 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
361 | struct soc_camera_link *icl = client->dev.platform_data; | ||
362 | int ret; | 362 | int ret; |
363 | 363 | ||
364 | if (icl->power) { | ||
365 | ret = icl->power(&client->dev, 1); | ||
366 | if (ret < 0) { | ||
367 | dev_err(icd->vdev->parent, | ||
368 | "Platform failed to power-on the camera.\n"); | ||
369 | return ret; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); | 364 | ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); |
374 | if (!ret) | 365 | if (!ret) |
375 | mt9m111->powered = 1; | 366 | mt9m111->powered = 1; |
376 | return ret; | 367 | return ret; |
377 | } | 368 | } |
378 | 369 | ||
379 | static int mt9m111_disable(struct soc_camera_device *icd) | 370 | static int mt9m111_reset(struct i2c_client *client) |
380 | { | ||
381 | struct i2c_client *client = to_i2c_client(icd->control); | ||
382 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
383 | struct soc_camera_link *icl = client->dev.platform_data; | ||
384 | int ret; | ||
385 | |||
386 | ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); | ||
387 | if (!ret) | ||
388 | mt9m111->powered = 0; | ||
389 | |||
390 | if (icl->power) | ||
391 | icl->power(&client->dev, 0); | ||
392 | |||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | static int mt9m111_reset(struct soc_camera_device *icd) | ||
397 | { | 371 | { |
398 | struct i2c_client *client = to_i2c_client(icd->control); | ||
399 | struct soc_camera_link *icl = client->dev.platform_data; | ||
400 | int ret; | 372 | int ret; |
401 | 373 | ||
402 | ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); | 374 | ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); |
@@ -406,26 +378,12 @@ static int mt9m111_reset(struct soc_camera_device *icd) | |||
406 | ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE | 378 | ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE |
407 | | MT9M111_RESET_RESET_SOC); | 379 | | MT9M111_RESET_RESET_SOC); |
408 | 380 | ||
409 | if (icl->reset) | ||
410 | icl->reset(&client->dev); | ||
411 | |||
412 | return ret; | 381 | return ret; |
413 | } | 382 | } |
414 | 383 | ||
415 | static int mt9m111_start_capture(struct soc_camera_device *icd) | ||
416 | { | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int mt9m111_stop_capture(struct soc_camera_device *icd) | ||
421 | { | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) | 384 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) |
426 | { | 385 | { |
427 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 386 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
428 | struct soc_camera_link *icl = mt9m111->client->dev.platform_data; | ||
429 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | 387 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | |
430 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | 388 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | |
431 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | 389 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; |
@@ -438,62 +396,126 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | |||
438 | return 0; | 396 | return 0; |
439 | } | 397 | } |
440 | 398 | ||
441 | static int mt9m111_set_crop(struct soc_camera_device *icd, | 399 | static int mt9m111_make_rect(struct i2c_client *client, |
442 | struct v4l2_rect *rect) | 400 | struct v4l2_rect *rect) |
443 | { | 401 | { |
444 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 402 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
403 | |||
404 | if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || | ||
405 | mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) { | ||
406 | /* Bayer format - even size lengths */ | ||
407 | rect->width = ALIGN(rect->width, 2); | ||
408 | rect->height = ALIGN(rect->height, 2); | ||
409 | /* Let the user play with the starting pixel */ | ||
410 | } | ||
411 | |||
412 | /* FIXME: the datasheet doesn't specify minimum sizes */ | ||
413 | soc_camera_limit_side(&rect->left, &rect->width, | ||
414 | MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH); | ||
415 | |||
416 | soc_camera_limit_side(&rect->top, &rect->height, | ||
417 | MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); | ||
418 | |||
419 | return mt9m111_setup_rect(client, rect); | ||
420 | } | ||
421 | |||
422 | static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
423 | { | ||
424 | struct v4l2_rect rect = a->c; | ||
425 | struct i2c_client *client = sd->priv; | ||
426 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
445 | int ret; | 427 | int ret; |
446 | 428 | ||
447 | dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n", | 429 | dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", |
448 | __func__, rect->left, rect->top, rect->width, | 430 | __func__, rect.left, rect.top, rect.width, rect.height); |
449 | rect->height); | ||
450 | 431 | ||
451 | ret = mt9m111_setup_rect(icd, rect); | 432 | ret = mt9m111_make_rect(client, &rect); |
452 | if (!ret) | 433 | if (!ret) |
453 | mt9m111->rect = *rect; | 434 | mt9m111->rect = rect; |
454 | return ret; | 435 | return ret; |
455 | } | 436 | } |
456 | 437 | ||
457 | static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | 438 | static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
458 | { | 439 | { |
459 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 440 | struct i2c_client *client = sd->priv; |
441 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
442 | |||
443 | a->c = mt9m111->rect; | ||
444 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
450 | { | ||
451 | a->bounds.left = MT9M111_MIN_DARK_COLS; | ||
452 | a->bounds.top = MT9M111_MIN_DARK_ROWS; | ||
453 | a->bounds.width = MT9M111_MAX_WIDTH; | ||
454 | a->bounds.height = MT9M111_MAX_HEIGHT; | ||
455 | a->defrect = a->bounds; | ||
456 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
457 | a->pixelaspect.numerator = 1; | ||
458 | a->pixelaspect.denominator = 1; | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
464 | { | ||
465 | struct i2c_client *client = sd->priv; | ||
466 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
467 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
468 | |||
469 | pix->width = mt9m111->rect.width; | ||
470 | pix->height = mt9m111->rect.height; | ||
471 | pix->pixelformat = mt9m111->pixfmt; | ||
472 | pix->field = V4L2_FIELD_NONE; | ||
473 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt) | ||
479 | { | ||
480 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
460 | int ret; | 481 | int ret; |
461 | 482 | ||
462 | switch (pixfmt) { | 483 | switch (pixfmt) { |
463 | case V4L2_PIX_FMT_SBGGR8: | 484 | case V4L2_PIX_FMT_SBGGR8: |
464 | ret = mt9m111_setfmt_bayer8(icd); | 485 | ret = mt9m111_setfmt_bayer8(client); |
465 | break; | 486 | break; |
466 | case V4L2_PIX_FMT_SBGGR16: | 487 | case V4L2_PIX_FMT_SBGGR16: |
467 | ret = mt9m111_setfmt_bayer10(icd); | 488 | ret = mt9m111_setfmt_bayer10(client); |
468 | break; | 489 | break; |
469 | case V4L2_PIX_FMT_RGB555: | 490 | case V4L2_PIX_FMT_RGB555: |
470 | ret = mt9m111_setfmt_rgb555(icd); | 491 | ret = mt9m111_setfmt_rgb555(client); |
471 | break; | 492 | break; |
472 | case V4L2_PIX_FMT_RGB565: | 493 | case V4L2_PIX_FMT_RGB565: |
473 | ret = mt9m111_setfmt_rgb565(icd); | 494 | ret = mt9m111_setfmt_rgb565(client); |
474 | break; | 495 | break; |
475 | case V4L2_PIX_FMT_UYVY: | 496 | case V4L2_PIX_FMT_UYVY: |
476 | mt9m111->swap_yuv_y_chromas = 0; | 497 | mt9m111->swap_yuv_y_chromas = 0; |
477 | mt9m111->swap_yuv_cb_cr = 0; | 498 | mt9m111->swap_yuv_cb_cr = 0; |
478 | ret = mt9m111_setfmt_yuv(icd); | 499 | ret = mt9m111_setfmt_yuv(client); |
479 | break; | 500 | break; |
480 | case V4L2_PIX_FMT_VYUY: | 501 | case V4L2_PIX_FMT_VYUY: |
481 | mt9m111->swap_yuv_y_chromas = 0; | 502 | mt9m111->swap_yuv_y_chromas = 0; |
482 | mt9m111->swap_yuv_cb_cr = 1; | 503 | mt9m111->swap_yuv_cb_cr = 1; |
483 | ret = mt9m111_setfmt_yuv(icd); | 504 | ret = mt9m111_setfmt_yuv(client); |
484 | break; | 505 | break; |
485 | case V4L2_PIX_FMT_YUYV: | 506 | case V4L2_PIX_FMT_YUYV: |
486 | mt9m111->swap_yuv_y_chromas = 1; | 507 | mt9m111->swap_yuv_y_chromas = 1; |
487 | mt9m111->swap_yuv_cb_cr = 0; | 508 | mt9m111->swap_yuv_cb_cr = 0; |
488 | ret = mt9m111_setfmt_yuv(icd); | 509 | ret = mt9m111_setfmt_yuv(client); |
489 | break; | 510 | break; |
490 | case V4L2_PIX_FMT_YVYU: | 511 | case V4L2_PIX_FMT_YVYU: |
491 | mt9m111->swap_yuv_y_chromas = 1; | 512 | mt9m111->swap_yuv_y_chromas = 1; |
492 | mt9m111->swap_yuv_cb_cr = 1; | 513 | mt9m111->swap_yuv_cb_cr = 1; |
493 | ret = mt9m111_setfmt_yuv(icd); | 514 | ret = mt9m111_setfmt_yuv(client); |
494 | break; | 515 | break; |
495 | default: | 516 | default: |
496 | dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt); | 517 | dev_err(&client->dev, "Pixel format not handled : %x\n", |
518 | pixfmt); | ||
497 | ret = -EINVAL; | 519 | ret = -EINVAL; |
498 | } | 520 | } |
499 | 521 | ||
@@ -503,10 +525,10 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | |||
503 | return ret; | 525 | return ret; |
504 | } | 526 | } |
505 | 527 | ||
506 | static int mt9m111_set_fmt(struct soc_camera_device *icd, | 528 | static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
507 | struct v4l2_format *f) | ||
508 | { | 529 | { |
509 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 530 | struct i2c_client *client = sd->priv; |
531 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
510 | struct v4l2_pix_format *pix = &f->fmt.pix; | 532 | struct v4l2_pix_format *pix = &f->fmt.pix; |
511 | struct v4l2_rect rect = { | 533 | struct v4l2_rect rect = { |
512 | .left = mt9m111->rect.left, | 534 | .left = mt9m111->rect.left, |
@@ -516,40 +538,56 @@ static int mt9m111_set_fmt(struct soc_camera_device *icd, | |||
516 | }; | 538 | }; |
517 | int ret; | 539 | int ret; |
518 | 540 | ||
519 | dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", | 541 | dev_dbg(&client->dev, |
520 | __func__, pix->pixelformat, rect.left, rect.top, rect.width, | 542 | "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__, |
521 | rect.height); | 543 | pix->pixelformat, rect.left, rect.top, rect.width, rect.height); |
522 | 544 | ||
523 | ret = mt9m111_setup_rect(icd, &rect); | 545 | ret = mt9m111_make_rect(client, &rect); |
524 | if (!ret) | 546 | if (!ret) |
525 | ret = mt9m111_set_pixfmt(icd, pix->pixelformat); | 547 | ret = mt9m111_set_pixfmt(client, pix->pixelformat); |
526 | if (!ret) | 548 | if (!ret) |
527 | mt9m111->rect = rect; | 549 | mt9m111->rect = rect; |
528 | return ret; | 550 | return ret; |
529 | } | 551 | } |
530 | 552 | ||
531 | static int mt9m111_try_fmt(struct soc_camera_device *icd, | 553 | static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
532 | struct v4l2_format *f) | ||
533 | { | 554 | { |
534 | struct v4l2_pix_format *pix = &f->fmt.pix; | 555 | struct v4l2_pix_format *pix = &f->fmt.pix; |
556 | bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | ||
557 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16; | ||
558 | |||
559 | /* | ||
560 | * With Bayer format enforce even side lengths, but let the user play | ||
561 | * with the starting pixel | ||
562 | */ | ||
535 | 563 | ||
536 | if (pix->height > MT9M111_MAX_HEIGHT) | 564 | if (pix->height > MT9M111_MAX_HEIGHT) |
537 | pix->height = MT9M111_MAX_HEIGHT; | 565 | pix->height = MT9M111_MAX_HEIGHT; |
566 | else if (pix->height < 2) | ||
567 | pix->height = 2; | ||
568 | else if (bayer) | ||
569 | pix->height = ALIGN(pix->height, 2); | ||
570 | |||
538 | if (pix->width > MT9M111_MAX_WIDTH) | 571 | if (pix->width > MT9M111_MAX_WIDTH) |
539 | pix->width = MT9M111_MAX_WIDTH; | 572 | pix->width = MT9M111_MAX_WIDTH; |
573 | else if (pix->width < 2) | ||
574 | pix->width = 2; | ||
575 | else if (bayer) | ||
576 | pix->width = ALIGN(pix->width, 2); | ||
540 | 577 | ||
541 | return 0; | 578 | return 0; |
542 | } | 579 | } |
543 | 580 | ||
544 | static int mt9m111_get_chip_id(struct soc_camera_device *icd, | 581 | static int mt9m111_g_chip_ident(struct v4l2_subdev *sd, |
545 | struct v4l2_dbg_chip_ident *id) | 582 | struct v4l2_dbg_chip_ident *id) |
546 | { | 583 | { |
547 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 584 | struct i2c_client *client = sd->priv; |
585 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
548 | 586 | ||
549 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 587 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
550 | return -EINVAL; | 588 | return -EINVAL; |
551 | 589 | ||
552 | if (id->match.addr != mt9m111->client->addr) | 590 | if (id->match.addr != client->addr) |
553 | return -ENODEV; | 591 | return -ENODEV; |
554 | 592 | ||
555 | id->ident = mt9m111->model; | 593 | id->ident = mt9m111->model; |
@@ -559,11 +597,11 @@ static int mt9m111_get_chip_id(struct soc_camera_device *icd, | |||
559 | } | 597 | } |
560 | 598 | ||
561 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 599 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
562 | static int mt9m111_get_register(struct soc_camera_device *icd, | 600 | static int mt9m111_g_register(struct v4l2_subdev *sd, |
563 | struct v4l2_dbg_register *reg) | 601 | struct v4l2_dbg_register *reg) |
564 | { | 602 | { |
603 | struct i2c_client *client = sd->priv; | ||
565 | int val; | 604 | int val; |
566 | struct i2c_client *client = to_i2c_client(icd->control); | ||
567 | 605 | ||
568 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) | 606 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) |
569 | return -EINVAL; | 607 | return -EINVAL; |
@@ -580,10 +618,10 @@ static int mt9m111_get_register(struct soc_camera_device *icd, | |||
580 | return 0; | 618 | return 0; |
581 | } | 619 | } |
582 | 620 | ||
583 | static int mt9m111_set_register(struct soc_camera_device *icd, | 621 | static int mt9m111_s_register(struct v4l2_subdev *sd, |
584 | struct v4l2_dbg_register *reg) | 622 | struct v4l2_dbg_register *reg) |
585 | { | 623 | { |
586 | struct i2c_client *client = to_i2c_client(icd->control); | 624 | struct i2c_client *client = sd->priv; |
587 | 625 | ||
588 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) | 626 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) |
589 | return -EINVAL; | 627 | return -EINVAL; |
@@ -635,45 +673,21 @@ static const struct v4l2_queryctrl mt9m111_controls[] = { | |||
635 | } | 673 | } |
636 | }; | 674 | }; |
637 | 675 | ||
638 | static int mt9m111_video_probe(struct soc_camera_device *); | ||
639 | static void mt9m111_video_remove(struct soc_camera_device *); | ||
640 | static int mt9m111_get_control(struct soc_camera_device *, | ||
641 | struct v4l2_control *); | ||
642 | static int mt9m111_set_control(struct soc_camera_device *, | ||
643 | struct v4l2_control *); | ||
644 | static int mt9m111_resume(struct soc_camera_device *icd); | 676 | static int mt9m111_resume(struct soc_camera_device *icd); |
645 | static int mt9m111_init(struct soc_camera_device *icd); | 677 | static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state); |
646 | static int mt9m111_release(struct soc_camera_device *icd); | ||
647 | 678 | ||
648 | static struct soc_camera_ops mt9m111_ops = { | 679 | static struct soc_camera_ops mt9m111_ops = { |
649 | .owner = THIS_MODULE, | 680 | .suspend = mt9m111_suspend, |
650 | .probe = mt9m111_video_probe, | ||
651 | .remove = mt9m111_video_remove, | ||
652 | .init = mt9m111_init, | ||
653 | .resume = mt9m111_resume, | 681 | .resume = mt9m111_resume, |
654 | .release = mt9m111_release, | ||
655 | .start_capture = mt9m111_start_capture, | ||
656 | .stop_capture = mt9m111_stop_capture, | ||
657 | .set_crop = mt9m111_set_crop, | ||
658 | .set_fmt = mt9m111_set_fmt, | ||
659 | .try_fmt = mt9m111_try_fmt, | ||
660 | .query_bus_param = mt9m111_query_bus_param, | 682 | .query_bus_param = mt9m111_query_bus_param, |
661 | .set_bus_param = mt9m111_set_bus_param, | 683 | .set_bus_param = mt9m111_set_bus_param, |
662 | .controls = mt9m111_controls, | 684 | .controls = mt9m111_controls, |
663 | .num_controls = ARRAY_SIZE(mt9m111_controls), | 685 | .num_controls = ARRAY_SIZE(mt9m111_controls), |
664 | .get_control = mt9m111_get_control, | ||
665 | .set_control = mt9m111_set_control, | ||
666 | .get_chip_id = mt9m111_get_chip_id, | ||
667 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
668 | .get_register = mt9m111_get_register, | ||
669 | .set_register = mt9m111_set_register, | ||
670 | #endif | ||
671 | }; | 686 | }; |
672 | 687 | ||
673 | static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) | 688 | static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask) |
674 | { | 689 | { |
675 | struct i2c_client *client = to_i2c_client(icd->control); | 690 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
676 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
677 | int ret; | 691 | int ret; |
678 | 692 | ||
679 | if (mt9m111->context == HIGHPOWER) { | 693 | if (mt9m111->context == HIGHPOWER) { |
@@ -691,9 +705,8 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) | |||
691 | return ret; | 705 | return ret; |
692 | } | 706 | } |
693 | 707 | ||
694 | static int mt9m111_get_global_gain(struct soc_camera_device *icd) | 708 | static int mt9m111_get_global_gain(struct i2c_client *client) |
695 | { | 709 | { |
696 | struct i2c_client *client = to_i2c_client(icd->control); | ||
697 | int data; | 710 | int data; |
698 | 711 | ||
699 | data = reg_read(GLOBAL_GAIN); | 712 | data = reg_read(GLOBAL_GAIN); |
@@ -703,15 +716,15 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd) | |||
703 | return data; | 716 | return data; |
704 | } | 717 | } |
705 | 718 | ||
706 | static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) | 719 | static int mt9m111_set_global_gain(struct i2c_client *client, int gain) |
707 | { | 720 | { |
708 | struct i2c_client *client = to_i2c_client(icd->control); | 721 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
709 | u16 val; | 722 | u16 val; |
710 | 723 | ||
711 | if (gain > 63 * 2 * 2) | 724 | if (gain > 63 * 2 * 2) |
712 | return -EINVAL; | 725 | return -EINVAL; |
713 | 726 | ||
714 | icd->gain = gain; | 727 | mt9m111->gain = gain; |
715 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) | 728 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) |
716 | val = (1 << 10) | (1 << 9) | (gain / 4); | 729 | val = (1 << 10) | (1 << 9) | (gain / 4); |
717 | else if ((gain >= 64) && (gain < 64 * 2)) | 730 | else if ((gain >= 64) && (gain < 64 * 2)) |
@@ -722,10 +735,9 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) | |||
722 | return reg_write(GLOBAL_GAIN, val); | 735 | return reg_write(GLOBAL_GAIN, val); |
723 | } | 736 | } |
724 | 737 | ||
725 | static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) | 738 | static int mt9m111_set_autoexposure(struct i2c_client *client, int on) |
726 | { | 739 | { |
727 | struct i2c_client *client = to_i2c_client(icd->control); | 740 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
728 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
729 | int ret; | 741 | int ret; |
730 | 742 | ||
731 | if (on) | 743 | if (on) |
@@ -739,10 +751,9 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) | |||
739 | return ret; | 751 | return ret; |
740 | } | 752 | } |
741 | 753 | ||
742 | static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) | 754 | static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on) |
743 | { | 755 | { |
744 | struct i2c_client *client = to_i2c_client(icd->control); | 756 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
745 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
746 | int ret; | 757 | int ret; |
747 | 758 | ||
748 | if (on) | 759 | if (on) |
@@ -756,11 +767,10 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) | |||
756 | return ret; | 767 | return ret; |
757 | } | 768 | } |
758 | 769 | ||
759 | static int mt9m111_get_control(struct soc_camera_device *icd, | 770 | static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
760 | struct v4l2_control *ctrl) | ||
761 | { | 771 | { |
762 | struct i2c_client *client = to_i2c_client(icd->control); | 772 | struct i2c_client *client = sd->priv; |
763 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 773 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
764 | int data; | 774 | int data; |
765 | 775 | ||
766 | switch (ctrl->id) { | 776 | switch (ctrl->id) { |
@@ -785,7 +795,7 @@ static int mt9m111_get_control(struct soc_camera_device *icd, | |||
785 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); | 795 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); |
786 | break; | 796 | break; |
787 | case V4L2_CID_GAIN: | 797 | case V4L2_CID_GAIN: |
788 | data = mt9m111_get_global_gain(icd); | 798 | data = mt9m111_get_global_gain(client); |
789 | if (data < 0) | 799 | if (data < 0) |
790 | return data; | 800 | return data; |
791 | ctrl->value = data; | 801 | ctrl->value = data; |
@@ -800,37 +810,36 @@ static int mt9m111_get_control(struct soc_camera_device *icd, | |||
800 | return 0; | 810 | return 0; |
801 | } | 811 | } |
802 | 812 | ||
803 | static int mt9m111_set_control(struct soc_camera_device *icd, | 813 | static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
804 | struct v4l2_control *ctrl) | ||
805 | { | 814 | { |
806 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 815 | struct i2c_client *client = sd->priv; |
816 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
807 | const struct v4l2_queryctrl *qctrl; | 817 | const struct v4l2_queryctrl *qctrl; |
808 | int ret; | 818 | int ret; |
809 | 819 | ||
810 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); | 820 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); |
811 | |||
812 | if (!qctrl) | 821 | if (!qctrl) |
813 | return -EINVAL; | 822 | return -EINVAL; |
814 | 823 | ||
815 | switch (ctrl->id) { | 824 | switch (ctrl->id) { |
816 | case V4L2_CID_VFLIP: | 825 | case V4L2_CID_VFLIP: |
817 | mt9m111->vflip = ctrl->value; | 826 | mt9m111->vflip = ctrl->value; |
818 | ret = mt9m111_set_flip(icd, ctrl->value, | 827 | ret = mt9m111_set_flip(client, ctrl->value, |
819 | MT9M111_RMB_MIRROR_ROWS); | 828 | MT9M111_RMB_MIRROR_ROWS); |
820 | break; | 829 | break; |
821 | case V4L2_CID_HFLIP: | 830 | case V4L2_CID_HFLIP: |
822 | mt9m111->hflip = ctrl->value; | 831 | mt9m111->hflip = ctrl->value; |
823 | ret = mt9m111_set_flip(icd, ctrl->value, | 832 | ret = mt9m111_set_flip(client, ctrl->value, |
824 | MT9M111_RMB_MIRROR_COLS); | 833 | MT9M111_RMB_MIRROR_COLS); |
825 | break; | 834 | break; |
826 | case V4L2_CID_GAIN: | 835 | case V4L2_CID_GAIN: |
827 | ret = mt9m111_set_global_gain(icd, ctrl->value); | 836 | ret = mt9m111_set_global_gain(client, ctrl->value); |
828 | break; | 837 | break; |
829 | case V4L2_CID_EXPOSURE_AUTO: | 838 | case V4L2_CID_EXPOSURE_AUTO: |
830 | ret = mt9m111_set_autoexposure(icd, ctrl->value); | 839 | ret = mt9m111_set_autoexposure(client, ctrl->value); |
831 | break; | 840 | break; |
832 | case V4L2_CID_AUTO_WHITE_BALANCE: | 841 | case V4L2_CID_AUTO_WHITE_BALANCE: |
833 | ret = mt9m111_set_autowhitebalance(icd, ctrl->value); | 842 | ret = mt9m111_set_autowhitebalance(client, ctrl->value); |
834 | break; | 843 | break; |
835 | default: | 844 | default: |
836 | ret = -EINVAL; | 845 | ret = -EINVAL; |
@@ -839,62 +848,62 @@ static int mt9m111_set_control(struct soc_camera_device *icd, | |||
839 | return ret; | 848 | return ret; |
840 | } | 849 | } |
841 | 850 | ||
842 | static int mt9m111_restore_state(struct soc_camera_device *icd) | 851 | static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state) |
843 | { | 852 | { |
844 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 853 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
845 | 854 | struct mt9m111 *mt9m111 = to_mt9m111(client); | |
846 | mt9m111_set_context(icd, mt9m111->context); | 855 | |
847 | mt9m111_set_pixfmt(icd, mt9m111->pixfmt); | 856 | mt9m111->gain = mt9m111_get_global_gain(client); |
848 | mt9m111_setup_rect(icd, &mt9m111->rect); | 857 | |
849 | mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | 858 | return 0; |
850 | mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | 859 | } |
851 | mt9m111_set_global_gain(icd, icd->gain); | 860 | |
852 | mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | 861 | static int mt9m111_restore_state(struct i2c_client *client) |
853 | mt9m111_set_autowhitebalance(icd, mt9m111->autowhitebalance); | 862 | { |
863 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
864 | |||
865 | mt9m111_set_context(client, mt9m111->context); | ||
866 | mt9m111_set_pixfmt(client, mt9m111->pixfmt); | ||
867 | mt9m111_setup_rect(client, &mt9m111->rect); | ||
868 | mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | ||
869 | mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | ||
870 | mt9m111_set_global_gain(client, mt9m111->gain); | ||
871 | mt9m111_set_autoexposure(client, mt9m111->autoexposure); | ||
872 | mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance); | ||
854 | return 0; | 873 | return 0; |
855 | } | 874 | } |
856 | 875 | ||
857 | static int mt9m111_resume(struct soc_camera_device *icd) | 876 | static int mt9m111_resume(struct soc_camera_device *icd) |
858 | { | 877 | { |
859 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 878 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
879 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
860 | int ret = 0; | 880 | int ret = 0; |
861 | 881 | ||
862 | if (mt9m111->powered) { | 882 | if (mt9m111->powered) { |
863 | ret = mt9m111_enable(icd); | 883 | ret = mt9m111_enable(client); |
864 | if (!ret) | 884 | if (!ret) |
865 | ret = mt9m111_reset(icd); | 885 | ret = mt9m111_reset(client); |
866 | if (!ret) | 886 | if (!ret) |
867 | ret = mt9m111_restore_state(icd); | 887 | ret = mt9m111_restore_state(client); |
868 | } | 888 | } |
869 | return ret; | 889 | return ret; |
870 | } | 890 | } |
871 | 891 | ||
872 | static int mt9m111_init(struct soc_camera_device *icd) | 892 | static int mt9m111_init(struct i2c_client *client) |
873 | { | 893 | { |
874 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 894 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
875 | int ret; | 895 | int ret; |
876 | 896 | ||
877 | mt9m111->context = HIGHPOWER; | 897 | mt9m111->context = HIGHPOWER; |
878 | ret = mt9m111_enable(icd); | 898 | ret = mt9m111_enable(client); |
879 | if (!ret) | 899 | if (!ret) |
880 | ret = mt9m111_reset(icd); | 900 | ret = mt9m111_reset(client); |
881 | if (!ret) | 901 | if (!ret) |
882 | ret = mt9m111_set_context(icd, mt9m111->context); | 902 | ret = mt9m111_set_context(client, mt9m111->context); |
883 | if (!ret) | 903 | if (!ret) |
884 | ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | 904 | ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure); |
885 | if (ret) | 905 | if (ret) |
886 | dev_err(&icd->dev, "mt9m11x init failed: %d\n", ret); | 906 | dev_err(&client->dev, "mt9m11x init failed: %d\n", ret); |
887 | return ret; | ||
888 | } | ||
889 | |||
890 | static int mt9m111_release(struct soc_camera_device *icd) | ||
891 | { | ||
892 | int ret; | ||
893 | |||
894 | ret = mt9m111_disable(icd); | ||
895 | if (ret < 0) | ||
896 | dev_err(&icd->dev, "mt9m11x release failed: %d\n", ret); | ||
897 | |||
898 | return ret; | 907 | return ret; |
899 | } | 908 | } |
900 | 909 | ||
@@ -902,10 +911,10 @@ static int mt9m111_release(struct soc_camera_device *icd) | |||
902 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 911 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
903 | * this wasn't our capture interface, so, we wait for the right one | 912 | * this wasn't our capture interface, so, we wait for the right one |
904 | */ | 913 | */ |
905 | static int mt9m111_video_probe(struct soc_camera_device *icd) | 914 | static int mt9m111_video_probe(struct soc_camera_device *icd, |
915 | struct i2c_client *client) | ||
906 | { | 916 | { |
907 | struct i2c_client *client = to_i2c_client(icd->control); | 917 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
908 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
909 | s32 data; | 918 | s32 data; |
910 | int ret; | 919 | int ret; |
911 | 920 | ||
@@ -917,10 +926,13 @@ static int mt9m111_video_probe(struct soc_camera_device *icd) | |||
917 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | 926 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) |
918 | return -ENODEV; | 927 | return -ENODEV; |
919 | 928 | ||
920 | ret = mt9m111_enable(icd); | 929 | mt9m111->autoexposure = 1; |
921 | if (ret) | 930 | mt9m111->autowhitebalance = 1; |
922 | goto ei2c; | 931 | |
923 | ret = mt9m111_reset(icd); | 932 | mt9m111->swap_rgb_even_odd = 1; |
933 | mt9m111->swap_rgb_red_blue = 1; | ||
934 | |||
935 | ret = mt9m111_init(client); | ||
924 | if (ret) | 936 | if (ret) |
925 | goto ei2c; | 937 | goto ei2c; |
926 | 938 | ||
@@ -935,7 +947,7 @@ static int mt9m111_video_probe(struct soc_camera_device *icd) | |||
935 | break; | 947 | break; |
936 | default: | 948 | default: |
937 | ret = -ENODEV; | 949 | ret = -ENODEV; |
938 | dev_err(&icd->dev, | 950 | dev_err(&client->dev, |
939 | "No MT9M11x chip detected, register read %x\n", data); | 951 | "No MT9M11x chip detected, register read %x\n", data); |
940 | goto ei2c; | 952 | goto ei2c; |
941 | } | 953 | } |
@@ -943,42 +955,51 @@ static int mt9m111_video_probe(struct soc_camera_device *icd) | |||
943 | icd->formats = mt9m111_colour_formats; | 955 | icd->formats = mt9m111_colour_formats; |
944 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); | 956 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); |
945 | 957 | ||
946 | dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data); | 958 | dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data); |
947 | 959 | ||
948 | ret = soc_camera_video_start(icd); | ||
949 | if (ret) | ||
950 | goto eisis; | ||
951 | |||
952 | mt9m111->autoexposure = 1; | ||
953 | mt9m111->autowhitebalance = 1; | ||
954 | |||
955 | mt9m111->swap_rgb_even_odd = 1; | ||
956 | mt9m111->swap_rgb_red_blue = 1; | ||
957 | |||
958 | return 0; | ||
959 | eisis: | ||
960 | ei2c: | 960 | ei2c: |
961 | return ret; | 961 | return ret; |
962 | } | 962 | } |
963 | 963 | ||
964 | static void mt9m111_video_remove(struct soc_camera_device *icd) | 964 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { |
965 | { | 965 | .g_ctrl = mt9m111_g_ctrl, |
966 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 966 | .s_ctrl = mt9m111_s_ctrl, |
967 | .g_chip_ident = mt9m111_g_chip_ident, | ||
968 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
969 | .g_register = mt9m111_g_register, | ||
970 | .s_register = mt9m111_s_register, | ||
971 | #endif | ||
972 | }; | ||
967 | 973 | ||
968 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr, | 974 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { |
969 | mt9m111->icd.dev.parent, mt9m111->icd.vdev); | 975 | .s_fmt = mt9m111_s_fmt, |
970 | soc_camera_video_stop(&mt9m111->icd); | 976 | .g_fmt = mt9m111_g_fmt, |
971 | } | 977 | .try_fmt = mt9m111_try_fmt, |
978 | .s_crop = mt9m111_s_crop, | ||
979 | .g_crop = mt9m111_g_crop, | ||
980 | .cropcap = mt9m111_cropcap, | ||
981 | }; | ||
982 | |||
983 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { | ||
984 | .core = &mt9m111_subdev_core_ops, | ||
985 | .video = &mt9m111_subdev_video_ops, | ||
986 | }; | ||
972 | 987 | ||
973 | static int mt9m111_probe(struct i2c_client *client, | 988 | static int mt9m111_probe(struct i2c_client *client, |
974 | const struct i2c_device_id *did) | 989 | const struct i2c_device_id *did) |
975 | { | 990 | { |
976 | struct mt9m111 *mt9m111; | 991 | struct mt9m111 *mt9m111; |
977 | struct soc_camera_device *icd; | 992 | struct soc_camera_device *icd = client->dev.platform_data; |
978 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 993 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
979 | struct soc_camera_link *icl = client->dev.platform_data; | 994 | struct soc_camera_link *icl; |
980 | int ret; | 995 | int ret; |
981 | 996 | ||
997 | if (!icd) { | ||
998 | dev_err(&client->dev, "MT9M11x: missing soc-camera data!\n"); | ||
999 | return -EINVAL; | ||
1000 | } | ||
1001 | |||
1002 | icl = to_soc_camera_link(icd); | ||
982 | if (!icl) { | 1003 | if (!icl) { |
983 | dev_err(&client->dev, "MT9M11x driver needs platform data\n"); | 1004 | dev_err(&client->dev, "MT9M11x driver needs platform data\n"); |
984 | return -EINVAL; | 1005 | return -EINVAL; |
@@ -994,38 +1015,35 @@ static int mt9m111_probe(struct i2c_client *client, | |||
994 | if (!mt9m111) | 1015 | if (!mt9m111) |
995 | return -ENOMEM; | 1016 | return -ENOMEM; |
996 | 1017 | ||
997 | mt9m111->client = client; | 1018 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); |
998 | i2c_set_clientdata(client, mt9m111); | ||
999 | 1019 | ||
1000 | /* Second stage probe - when a capture adapter is there */ | 1020 | /* Second stage probe - when a capture adapter is there */ |
1001 | icd = &mt9m111->icd; | 1021 | icd->ops = &mt9m111_ops; |
1002 | icd->ops = &mt9m111_ops; | 1022 | icd->y_skip_top = 0; |
1003 | icd->control = &client->dev; | 1023 | |
1004 | icd->x_min = MT9M111_MIN_DARK_COLS; | 1024 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; |
1005 | icd->y_min = MT9M111_MIN_DARK_ROWS; | 1025 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; |
1006 | icd->x_current = icd->x_min; | 1026 | mt9m111->rect.width = MT9M111_MAX_WIDTH; |
1007 | icd->y_current = icd->y_min; | 1027 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; |
1008 | icd->width_min = MT9M111_MIN_DARK_ROWS; | 1028 | |
1009 | icd->width_max = MT9M111_MAX_WIDTH; | 1029 | ret = mt9m111_video_probe(icd, client); |
1010 | icd->height_min = MT9M111_MIN_DARK_COLS; | 1030 | if (ret) { |
1011 | icd->height_max = MT9M111_MAX_HEIGHT; | 1031 | icd->ops = NULL; |
1012 | icd->y_skip_top = 0; | 1032 | i2c_set_clientdata(client, NULL); |
1013 | icd->iface = icl->bus_id; | 1033 | kfree(mt9m111); |
1014 | 1034 | } | |
1015 | ret = soc_camera_device_register(icd); | ||
1016 | if (ret) | ||
1017 | goto eisdr; | ||
1018 | return 0; | ||
1019 | 1035 | ||
1020 | eisdr: | ||
1021 | kfree(mt9m111); | ||
1022 | return ret; | 1036 | return ret; |
1023 | } | 1037 | } |
1024 | 1038 | ||
1025 | static int mt9m111_remove(struct i2c_client *client) | 1039 | static int mt9m111_remove(struct i2c_client *client) |
1026 | { | 1040 | { |
1027 | struct mt9m111 *mt9m111 = i2c_get_clientdata(client); | 1041 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
1028 | soc_camera_device_unregister(&mt9m111->icd); | 1042 | struct soc_camera_device *icd = client->dev.platform_data; |
1043 | |||
1044 | icd->ops = NULL; | ||
1045 | i2c_set_clientdata(client, NULL); | ||
1046 | client->driver = NULL; | ||
1029 | kfree(mt9m111); | 1047 | kfree(mt9m111); |
1030 | 1048 | ||
1031 | return 0; | 1049 | return 0; |
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 4207fb342670..6966f644977e 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -13,13 +13,13 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/log2.h> | 14 | #include <linux/log2.h> |
15 | 15 | ||
16 | #include <media/v4l2-common.h> | 16 | #include <media/v4l2-subdev.h> |
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | 19 | ||
20 | /* mt9t031 i2c address 0x5d | 20 | /* mt9t031 i2c address 0x5d |
21 | * The platform has to define i2c_board_info | 21 | * The platform has to define i2c_board_info and link to it from |
22 | * and call i2c_register_board_info() */ | 22 | * struct soc_camera_link */ |
23 | 23 | ||
24 | /* mt9t031 selected register addresses */ | 24 | /* mt9t031 selected register addresses */ |
25 | #define MT9T031_CHIP_VERSION 0x00 | 25 | #define MT9T031_CHIP_VERSION 0x00 |
@@ -47,7 +47,7 @@ | |||
47 | #define MT9T031_MAX_HEIGHT 1536 | 47 | #define MT9T031_MAX_HEIGHT 1536 |
48 | #define MT9T031_MAX_WIDTH 2048 | 48 | #define MT9T031_MAX_WIDTH 2048 |
49 | #define MT9T031_MIN_HEIGHT 2 | 49 | #define MT9T031_MIN_HEIGHT 2 |
50 | #define MT9T031_MIN_WIDTH 2 | 50 | #define MT9T031_MIN_WIDTH 18 |
51 | #define MT9T031_HORIZONTAL_BLANK 142 | 51 | #define MT9T031_HORIZONTAL_BLANK 142 |
52 | #define MT9T031_VERTICAL_BLANK 25 | 52 | #define MT9T031_VERTICAL_BLANK 25 |
53 | #define MT9T031_COLUMN_SKIP 32 | 53 | #define MT9T031_COLUMN_SKIP 32 |
@@ -68,14 +68,21 @@ static const struct soc_camera_data_format mt9t031_colour_formats[] = { | |||
68 | }; | 68 | }; |
69 | 69 | ||
70 | struct mt9t031 { | 70 | struct mt9t031 { |
71 | struct i2c_client *client; | 71 | struct v4l2_subdev subdev; |
72 | struct soc_camera_device icd; | 72 | struct v4l2_rect rect; /* Sensor window */ |
73 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ | 73 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ |
74 | unsigned char autoexposure; | ||
75 | u16 xskip; | 74 | u16 xskip; |
76 | u16 yskip; | 75 | u16 yskip; |
76 | unsigned int gain; | ||
77 | unsigned int exposure; | ||
78 | unsigned char autoexposure; | ||
77 | }; | 79 | }; |
78 | 80 | ||
81 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) | ||
82 | { | ||
83 | return container_of(i2c_get_clientdata(client), struct mt9t031, subdev); | ||
84 | } | ||
85 | |||
79 | static int reg_read(struct i2c_client *client, const u8 reg) | 86 | static int reg_read(struct i2c_client *client, const u8 reg) |
80 | { | 87 | { |
81 | s32 data = i2c_smbus_read_word_data(client, reg); | 88 | s32 data = i2c_smbus_read_word_data(client, reg); |
@@ -136,21 +143,10 @@ static int get_shutter(struct i2c_client *client, u32 *data) | |||
136 | return ret < 0 ? ret : 0; | 143 | return ret < 0 ? ret : 0; |
137 | } | 144 | } |
138 | 145 | ||
139 | static int mt9t031_init(struct soc_camera_device *icd) | 146 | static int mt9t031_idle(struct i2c_client *client) |
140 | { | 147 | { |
141 | struct i2c_client *client = to_i2c_client(icd->control); | ||
142 | struct soc_camera_link *icl = client->dev.platform_data; | ||
143 | int ret; | 148 | int ret; |
144 | 149 | ||
145 | if (icl->power) { | ||
146 | ret = icl->power(&client->dev, 1); | ||
147 | if (ret < 0) { | ||
148 | dev_err(icd->vdev->parent, | ||
149 | "Platform failed to power-on the camera.\n"); | ||
150 | return ret; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* Disable chip output, synchronous option update */ | 150 | /* Disable chip output, synchronous option update */ |
155 | ret = reg_write(client, MT9T031_RESET, 1); | 151 | ret = reg_write(client, MT9T031_RESET, 1); |
156 | if (ret >= 0) | 152 | if (ret >= 0) |
@@ -158,50 +154,39 @@ static int mt9t031_init(struct soc_camera_device *icd) | |||
158 | if (ret >= 0) | 154 | if (ret >= 0) |
159 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); | 155 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); |
160 | 156 | ||
161 | if (ret < 0 && icl->power) | ||
162 | icl->power(&client->dev, 0); | ||
163 | |||
164 | return ret >= 0 ? 0 : -EIO; | 157 | return ret >= 0 ? 0 : -EIO; |
165 | } | 158 | } |
166 | 159 | ||
167 | static int mt9t031_release(struct soc_camera_device *icd) | 160 | static int mt9t031_disable(struct i2c_client *client) |
168 | { | 161 | { |
169 | struct i2c_client *client = to_i2c_client(icd->control); | ||
170 | struct soc_camera_link *icl = client->dev.platform_data; | ||
171 | |||
172 | /* Disable the chip */ | 162 | /* Disable the chip */ |
173 | reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); | 163 | reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); |
174 | 164 | ||
175 | if (icl->power) | ||
176 | icl->power(&client->dev, 0); | ||
177 | |||
178 | return 0; | 165 | return 0; |
179 | } | 166 | } |
180 | 167 | ||
181 | static int mt9t031_start_capture(struct soc_camera_device *icd) | 168 | static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) |
182 | { | 169 | { |
183 | struct i2c_client *client = to_i2c_client(icd->control); | 170 | struct i2c_client *client = sd->priv; |
184 | 171 | int ret; | |
185 | /* Switch to master "normal" mode */ | ||
186 | if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0) | ||
187 | return -EIO; | ||
188 | return 0; | ||
189 | } | ||
190 | 172 | ||
191 | static int mt9t031_stop_capture(struct soc_camera_device *icd) | 173 | if (enable) |
192 | { | 174 | /* Switch to master "normal" mode */ |
193 | struct i2c_client *client = to_i2c_client(icd->control); | 175 | ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2); |
176 | else | ||
177 | /* Stop sensor readout */ | ||
178 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); | ||
194 | 179 | ||
195 | /* Stop sensor readout */ | 180 | if (ret < 0) |
196 | if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0) | ||
197 | return -EIO; | 181 | return -EIO; |
182 | |||
198 | return 0; | 183 | return 0; |
199 | } | 184 | } |
200 | 185 | ||
201 | static int mt9t031_set_bus_param(struct soc_camera_device *icd, | 186 | static int mt9t031_set_bus_param(struct soc_camera_device *icd, |
202 | unsigned long flags) | 187 | unsigned long flags) |
203 | { | 188 | { |
204 | struct i2c_client *client = to_i2c_client(icd->control); | 189 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
205 | 190 | ||
206 | /* The caller should have queried our parameters, check anyway */ | 191 | /* The caller should have queried our parameters, check anyway */ |
207 | if (flags & ~MT9T031_BUS_PARAM) | 192 | if (flags & ~MT9T031_BUS_PARAM) |
@@ -217,69 +202,73 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd, | |||
217 | 202 | ||
218 | static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) | 203 | static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) |
219 | { | 204 | { |
220 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 205 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
221 | struct soc_camera_link *icl = mt9t031->client->dev.platform_data; | ||
222 | 206 | ||
223 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); | 207 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); |
224 | } | 208 | } |
225 | 209 | ||
226 | /* Round up minima and round down maxima */ | 210 | /* target must be _even_ */ |
227 | static void recalculate_limits(struct soc_camera_device *icd, | 211 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) |
228 | u16 xskip, u16 yskip) | ||
229 | { | 212 | { |
230 | icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip; | 213 | unsigned int skip; |
231 | icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip; | 214 | |
232 | icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip; | 215 | if (*source < target + target / 2) { |
233 | icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip; | 216 | *source = target; |
234 | icd->width_max = MT9T031_MAX_WIDTH / xskip; | 217 | return 1; |
235 | icd->height_max = MT9T031_MAX_HEIGHT / yskip; | 218 | } |
219 | |||
220 | skip = min(max, *source + target / 2) / target; | ||
221 | if (skip > 8) | ||
222 | skip = 8; | ||
223 | *source = target * skip; | ||
224 | |||
225 | return skip; | ||
236 | } | 226 | } |
237 | 227 | ||
228 | /* rect is the sensor rectangle, the caller guarantees parameter validity */ | ||
238 | static int mt9t031_set_params(struct soc_camera_device *icd, | 229 | static int mt9t031_set_params(struct soc_camera_device *icd, |
239 | struct v4l2_rect *rect, u16 xskip, u16 yskip) | 230 | struct v4l2_rect *rect, u16 xskip, u16 yskip) |
240 | { | 231 | { |
241 | struct i2c_client *client = to_i2c_client(icd->control); | 232 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
242 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 233 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
243 | int ret; | 234 | int ret; |
244 | u16 xbin, ybin, width, height, left, top; | 235 | u16 xbin, ybin; |
245 | const u16 hblank = MT9T031_HORIZONTAL_BLANK, | 236 | const u16 hblank = MT9T031_HORIZONTAL_BLANK, |
246 | vblank = MT9T031_VERTICAL_BLANK; | 237 | vblank = MT9T031_VERTICAL_BLANK; |
247 | 238 | ||
248 | /* Make sure we don't exceed sensor limits */ | ||
249 | if (rect->left + rect->width > icd->width_max) | ||
250 | rect->left = (icd->width_max - rect->width) / 2 + icd->x_min; | ||
251 | |||
252 | if (rect->top + rect->height > icd->height_max) | ||
253 | rect->top = (icd->height_max - rect->height) / 2 + icd->y_min; | ||
254 | |||
255 | width = rect->width * xskip; | ||
256 | height = rect->height * yskip; | ||
257 | left = rect->left * xskip; | ||
258 | top = rect->top * yskip; | ||
259 | |||
260 | xbin = min(xskip, (u16)3); | 239 | xbin = min(xskip, (u16)3); |
261 | ybin = min(yskip, (u16)3); | 240 | ybin = min(yskip, (u16)3); |
262 | 241 | ||
263 | dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n", | 242 | /* |
264 | xskip, width, rect->width, yskip, height, rect->height); | 243 | * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper. |
265 | 244 | * There is always a valid suitably aligned value. The worst case is | |
266 | /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */ | 245 | * xbin = 3, width = 2048. Then we will start at 36, the last read out |
246 | * pixel will be 2083, which is < 2085 - first black pixel. | ||
247 | * | ||
248 | * MT9T031 datasheet imposes window left border alignment, depending on | ||
249 | * the selected xskip. Failing to conform to this requirement produces | ||
250 | * dark horizontal stripes in the image. However, even obeying to this | ||
251 | * requirement doesn't eliminate the stripes in all configurations. They | ||
252 | * appear "locally reproducibly," but can differ between tests under | ||
253 | * different lighting conditions. | ||
254 | */ | ||
267 | switch (xbin) { | 255 | switch (xbin) { |
268 | case 2: | 256 | case 1: |
269 | left = (left + 3) & ~3; | 257 | rect->left &= ~1; |
270 | break; | 258 | break; |
271 | case 3: | ||
272 | left = roundup(left, 6); | ||
273 | } | ||
274 | |||
275 | switch (ybin) { | ||
276 | case 2: | 259 | case 2: |
277 | top = (top + 3) & ~3; | 260 | rect->left &= ~3; |
278 | break; | 261 | break; |
279 | case 3: | 262 | case 3: |
280 | top = roundup(top, 6); | 263 | rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ? |
264 | (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6); | ||
281 | } | 265 | } |
282 | 266 | ||
267 | rect->top &= ~1; | ||
268 | |||
269 | dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n", | ||
270 | xskip, yskip, rect->width, rect->height, rect->left, rect->top); | ||
271 | |||
283 | /* Disable register update, reconfigure atomically */ | 272 | /* Disable register update, reconfigure atomically */ |
284 | ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); | 273 | ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); |
285 | if (ret < 0) | 274 | if (ret < 0) |
@@ -299,29 +288,30 @@ static int mt9t031_set_params(struct soc_camera_device *icd, | |||
299 | ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, | 288 | ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, |
300 | ((ybin - 1) << 4) | (yskip - 1)); | 289 | ((ybin - 1) << 4) | (yskip - 1)); |
301 | } | 290 | } |
302 | dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top); | 291 | dev_dbg(&client->dev, "new physical left %u, top %u\n", |
292 | rect->left, rect->top); | ||
303 | 293 | ||
304 | /* The caller provides a supported format, as guaranteed by | 294 | /* The caller provides a supported format, as guaranteed by |
305 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ | 295 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ |
306 | if (ret >= 0) | 296 | if (ret >= 0) |
307 | ret = reg_write(client, MT9T031_COLUMN_START, left); | 297 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); |
308 | if (ret >= 0) | 298 | if (ret >= 0) |
309 | ret = reg_write(client, MT9T031_ROW_START, top); | 299 | ret = reg_write(client, MT9T031_ROW_START, rect->top); |
310 | if (ret >= 0) | 300 | if (ret >= 0) |
311 | ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1); | 301 | ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); |
312 | if (ret >= 0) | 302 | if (ret >= 0) |
313 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, | 303 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, |
314 | height + icd->y_skip_top - 1); | 304 | rect->height + icd->y_skip_top - 1); |
315 | if (ret >= 0 && mt9t031->autoexposure) { | 305 | if (ret >= 0 && mt9t031->autoexposure) { |
316 | ret = set_shutter(client, height + icd->y_skip_top + vblank); | 306 | unsigned int total_h = rect->height + icd->y_skip_top + vblank; |
307 | ret = set_shutter(client, total_h); | ||
317 | if (ret >= 0) { | 308 | if (ret >= 0) { |
318 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 309 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; |
319 | const struct v4l2_queryctrl *qctrl = | 310 | const struct v4l2_queryctrl *qctrl = |
320 | soc_camera_find_qctrl(icd->ops, | 311 | soc_camera_find_qctrl(icd->ops, |
321 | V4L2_CID_EXPOSURE); | 312 | V4L2_CID_EXPOSURE); |
322 | icd->exposure = (shutter_max / 2 + (height + | 313 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * |
323 | icd->y_skip_top + vblank - 1) * | 314 | (qctrl->maximum - qctrl->minimum)) / |
324 | (qctrl->maximum - qctrl->minimum)) / | ||
325 | shutter_max + qctrl->minimum; | 315 | shutter_max + qctrl->minimum; |
326 | } | 316 | } |
327 | } | 317 | } |
@@ -330,58 +320,99 @@ static int mt9t031_set_params(struct soc_camera_device *icd, | |||
330 | if (ret >= 0) | 320 | if (ret >= 0) |
331 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); | 321 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); |
332 | 322 | ||
323 | if (ret >= 0) { | ||
324 | mt9t031->rect = *rect; | ||
325 | mt9t031->xskip = xskip; | ||
326 | mt9t031->yskip = yskip; | ||
327 | } | ||
328 | |||
333 | return ret < 0 ? ret : 0; | 329 | return ret < 0 ? ret : 0; |
334 | } | 330 | } |
335 | 331 | ||
336 | static int mt9t031_set_crop(struct soc_camera_device *icd, | 332 | static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
337 | struct v4l2_rect *rect) | ||
338 | { | 333 | { |
339 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 334 | struct v4l2_rect rect = a->c; |
335 | struct i2c_client *client = sd->priv; | ||
336 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
337 | struct soc_camera_device *icd = client->dev.platform_data; | ||
338 | |||
339 | rect.width = ALIGN(rect.width, 2); | ||
340 | rect.height = ALIGN(rect.height, 2); | ||
341 | |||
342 | soc_camera_limit_side(&rect.left, &rect.width, | ||
343 | MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH); | ||
344 | |||
345 | soc_camera_limit_side(&rect.top, &rect.height, | ||
346 | MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); | ||
340 | 347 | ||
341 | /* CROP - no change in scaling, or in limits */ | 348 | return mt9t031_set_params(icd, &rect, mt9t031->xskip, mt9t031->yskip); |
342 | return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip); | ||
343 | } | 349 | } |
344 | 350 | ||
345 | static int mt9t031_set_fmt(struct soc_camera_device *icd, | 351 | static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
346 | struct v4l2_format *f) | ||
347 | { | 352 | { |
348 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 353 | struct i2c_client *client = sd->priv; |
349 | int ret; | 354 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
350 | u16 xskip, yskip; | ||
351 | struct v4l2_rect rect = { | ||
352 | .left = icd->x_current, | ||
353 | .top = icd->y_current, | ||
354 | .width = f->fmt.pix.width, | ||
355 | .height = f->fmt.pix.height, | ||
356 | }; | ||
357 | 355 | ||
358 | /* | 356 | a->c = mt9t031->rect; |
359 | * try_fmt has put rectangle within limits. | 357 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
360 | * S_FMT - use binning and skipping for scaling, recalculate | ||
361 | * limits, used for cropping | ||
362 | */ | ||
363 | /* Is this more optimal than just a division? */ | ||
364 | for (xskip = 8; xskip > 1; xskip--) | ||
365 | if (rect.width * xskip <= MT9T031_MAX_WIDTH) | ||
366 | break; | ||
367 | 358 | ||
368 | for (yskip = 8; yskip > 1; yskip--) | 359 | return 0; |
369 | if (rect.height * yskip <= MT9T031_MAX_HEIGHT) | 360 | } |
370 | break; | ||
371 | 361 | ||
372 | recalculate_limits(icd, xskip, yskip); | 362 | static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
363 | { | ||
364 | a->bounds.left = MT9T031_COLUMN_SKIP; | ||
365 | a->bounds.top = MT9T031_ROW_SKIP; | ||
366 | a->bounds.width = MT9T031_MAX_WIDTH; | ||
367 | a->bounds.height = MT9T031_MAX_HEIGHT; | ||
368 | a->defrect = a->bounds; | ||
369 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
370 | a->pixelaspect.numerator = 1; | ||
371 | a->pixelaspect.denominator = 1; | ||
373 | 372 | ||
374 | ret = mt9t031_set_params(icd, &rect, xskip, yskip); | 373 | return 0; |
375 | if (!ret) { | 374 | } |
376 | mt9t031->xskip = xskip; | ||
377 | mt9t031->yskip = yskip; | ||
378 | } | ||
379 | 375 | ||
380 | return ret; | 376 | static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
377 | { | ||
378 | struct i2c_client *client = sd->priv; | ||
379 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
380 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
381 | |||
382 | pix->width = mt9t031->rect.width / mt9t031->xskip; | ||
383 | pix->height = mt9t031->rect.height / mt9t031->yskip; | ||
384 | pix->pixelformat = V4L2_PIX_FMT_SGRBG10; | ||
385 | pix->field = V4L2_FIELD_NONE; | ||
386 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
392 | { | ||
393 | struct i2c_client *client = sd->priv; | ||
394 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
395 | struct soc_camera_device *icd = client->dev.platform_data; | ||
396 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
397 | u16 xskip, yskip; | ||
398 | struct v4l2_rect rect = mt9t031->rect; | ||
399 | |||
400 | /* | ||
401 | * try_fmt has put width and height within limits. | ||
402 | * S_FMT: use binning and skipping for scaling | ||
403 | */ | ||
404 | xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH); | ||
405 | yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT); | ||
406 | |||
407 | /* mt9t031_set_params() doesn't change width and height */ | ||
408 | return mt9t031_set_params(icd, &rect, xskip, yskip); | ||
381 | } | 409 | } |
382 | 410 | ||
383 | static int mt9t031_try_fmt(struct soc_camera_device *icd, | 411 | /* |
384 | struct v4l2_format *f) | 412 | * If a user window larger than sensor window is requested, we'll increase the |
413 | * sensor window. | ||
414 | */ | ||
415 | static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
385 | { | 416 | { |
386 | struct v4l2_pix_format *pix = &f->fmt.pix; | 417 | struct v4l2_pix_format *pix = &f->fmt.pix; |
387 | 418 | ||
@@ -392,15 +423,16 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd, | |||
392 | return 0; | 423 | return 0; |
393 | } | 424 | } |
394 | 425 | ||
395 | static int mt9t031_get_chip_id(struct soc_camera_device *icd, | 426 | static int mt9t031_g_chip_ident(struct v4l2_subdev *sd, |
396 | struct v4l2_dbg_chip_ident *id) | 427 | struct v4l2_dbg_chip_ident *id) |
397 | { | 428 | { |
398 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 429 | struct i2c_client *client = sd->priv; |
430 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
399 | 431 | ||
400 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 432 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
401 | return -EINVAL; | 433 | return -EINVAL; |
402 | 434 | ||
403 | if (id->match.addr != mt9t031->client->addr) | 435 | if (id->match.addr != client->addr) |
404 | return -ENODEV; | 436 | return -ENODEV; |
405 | 437 | ||
406 | id->ident = mt9t031->model; | 438 | id->ident = mt9t031->model; |
@@ -410,10 +442,10 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd, | |||
410 | } | 442 | } |
411 | 443 | ||
412 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 444 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
413 | static int mt9t031_get_register(struct soc_camera_device *icd, | 445 | static int mt9t031_g_register(struct v4l2_subdev *sd, |
414 | struct v4l2_dbg_register *reg) | 446 | struct v4l2_dbg_register *reg) |
415 | { | 447 | { |
416 | struct i2c_client *client = to_i2c_client(icd->control); | 448 | struct i2c_client *client = sd->priv; |
417 | 449 | ||
418 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 450 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
419 | return -EINVAL; | 451 | return -EINVAL; |
@@ -429,10 +461,10 @@ static int mt9t031_get_register(struct soc_camera_device *icd, | |||
429 | return 0; | 461 | return 0; |
430 | } | 462 | } |
431 | 463 | ||
432 | static int mt9t031_set_register(struct soc_camera_device *icd, | 464 | static int mt9t031_s_register(struct v4l2_subdev *sd, |
433 | struct v4l2_dbg_register *reg) | 465 | struct v4l2_dbg_register *reg) |
434 | { | 466 | { |
435 | struct i2c_client *client = to_i2c_client(icd->control); | 467 | struct i2c_client *client = sd->priv; |
436 | 468 | ||
437 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 469 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
438 | return -EINVAL; | 470 | return -EINVAL; |
@@ -493,39 +525,17 @@ static const struct v4l2_queryctrl mt9t031_controls[] = { | |||
493 | } | 525 | } |
494 | }; | 526 | }; |
495 | 527 | ||
496 | static int mt9t031_video_probe(struct soc_camera_device *); | ||
497 | static void mt9t031_video_remove(struct soc_camera_device *); | ||
498 | static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *); | ||
499 | static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *); | ||
500 | |||
501 | static struct soc_camera_ops mt9t031_ops = { | 528 | static struct soc_camera_ops mt9t031_ops = { |
502 | .owner = THIS_MODULE, | ||
503 | .probe = mt9t031_video_probe, | ||
504 | .remove = mt9t031_video_remove, | ||
505 | .init = mt9t031_init, | ||
506 | .release = mt9t031_release, | ||
507 | .start_capture = mt9t031_start_capture, | ||
508 | .stop_capture = mt9t031_stop_capture, | ||
509 | .set_crop = mt9t031_set_crop, | ||
510 | .set_fmt = mt9t031_set_fmt, | ||
511 | .try_fmt = mt9t031_try_fmt, | ||
512 | .set_bus_param = mt9t031_set_bus_param, | 529 | .set_bus_param = mt9t031_set_bus_param, |
513 | .query_bus_param = mt9t031_query_bus_param, | 530 | .query_bus_param = mt9t031_query_bus_param, |
514 | .controls = mt9t031_controls, | 531 | .controls = mt9t031_controls, |
515 | .num_controls = ARRAY_SIZE(mt9t031_controls), | 532 | .num_controls = ARRAY_SIZE(mt9t031_controls), |
516 | .get_control = mt9t031_get_control, | ||
517 | .set_control = mt9t031_set_control, | ||
518 | .get_chip_id = mt9t031_get_chip_id, | ||
519 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
520 | .get_register = mt9t031_get_register, | ||
521 | .set_register = mt9t031_set_register, | ||
522 | #endif | ||
523 | }; | 533 | }; |
524 | 534 | ||
525 | static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 535 | static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
526 | { | 536 | { |
527 | struct i2c_client *client = to_i2c_client(icd->control); | 537 | struct i2c_client *client = sd->priv; |
528 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 538 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
529 | int data; | 539 | int data; |
530 | 540 | ||
531 | switch (ctrl->id) { | 541 | switch (ctrl->id) { |
@@ -544,14 +554,21 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro | |||
544 | case V4L2_CID_EXPOSURE_AUTO: | 554 | case V4L2_CID_EXPOSURE_AUTO: |
545 | ctrl->value = mt9t031->autoexposure; | 555 | ctrl->value = mt9t031->autoexposure; |
546 | break; | 556 | break; |
557 | case V4L2_CID_GAIN: | ||
558 | ctrl->value = mt9t031->gain; | ||
559 | break; | ||
560 | case V4L2_CID_EXPOSURE: | ||
561 | ctrl->value = mt9t031->exposure; | ||
562 | break; | ||
547 | } | 563 | } |
548 | return 0; | 564 | return 0; |
549 | } | 565 | } |
550 | 566 | ||
551 | static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 567 | static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
552 | { | 568 | { |
553 | struct i2c_client *client = to_i2c_client(icd->control); | 569 | struct i2c_client *client = sd->priv; |
554 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 570 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
571 | struct soc_camera_device *icd = client->dev.platform_data; | ||
555 | const struct v4l2_queryctrl *qctrl; | 572 | const struct v4l2_queryctrl *qctrl; |
556 | int data; | 573 | int data; |
557 | 574 | ||
@@ -586,7 +603,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
586 | unsigned long range = qctrl->default_value - qctrl->minimum; | 603 | unsigned long range = qctrl->default_value - qctrl->minimum; |
587 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 604 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; |
588 | 605 | ||
589 | dev_dbg(&icd->dev, "Setting gain %d\n", data); | 606 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
590 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); | 607 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); |
591 | if (data < 0) | 608 | if (data < 0) |
592 | return -EIO; | 609 | return -EIO; |
@@ -606,7 +623,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
606 | /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ | 623 | /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ |
607 | data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; | 624 | data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; |
608 | 625 | ||
609 | dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n", | 626 | dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n", |
610 | reg_read(client, MT9T031_GLOBAL_GAIN), data); | 627 | reg_read(client, MT9T031_GLOBAL_GAIN), data); |
611 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); | 628 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); |
612 | if (data < 0) | 629 | if (data < 0) |
@@ -614,7 +631,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
614 | } | 631 | } |
615 | 632 | ||
616 | /* Success */ | 633 | /* Success */ |
617 | icd->gain = ctrl->value; | 634 | mt9t031->gain = ctrl->value; |
618 | break; | 635 | break; |
619 | case V4L2_CID_EXPOSURE: | 636 | case V4L2_CID_EXPOSURE: |
620 | /* mt9t031 has maximum == default */ | 637 | /* mt9t031 has maximum == default */ |
@@ -627,11 +644,11 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
627 | u32 old; | 644 | u32 old; |
628 | 645 | ||
629 | get_shutter(client, &old); | 646 | get_shutter(client, &old); |
630 | dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n", | 647 | dev_dbg(&client->dev, "Set shutter from %u to %u\n", |
631 | old, shutter); | 648 | old, shutter); |
632 | if (set_shutter(client, shutter) < 0) | 649 | if (set_shutter(client, shutter) < 0) |
633 | return -EIO; | 650 | return -EIO; |
634 | icd->exposure = ctrl->value; | 651 | mt9t031->exposure = ctrl->value; |
635 | mt9t031->autoexposure = 0; | 652 | mt9t031->autoexposure = 0; |
636 | } | 653 | } |
637 | break; | 654 | break; |
@@ -639,13 +656,14 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
639 | if (ctrl->value) { | 656 | if (ctrl->value) { |
640 | const u16 vblank = MT9T031_VERTICAL_BLANK; | 657 | const u16 vblank = MT9T031_VERTICAL_BLANK; |
641 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 658 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; |
642 | if (set_shutter(client, icd->height + | 659 | unsigned int total_h = mt9t031->rect.height + |
643 | icd->y_skip_top + vblank) < 0) | 660 | icd->y_skip_top + vblank; |
661 | |||
662 | if (set_shutter(client, total_h) < 0) | ||
644 | return -EIO; | 663 | return -EIO; |
645 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | 664 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); |
646 | icd->exposure = (shutter_max / 2 + (icd->height + | 665 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * |
647 | icd->y_skip_top + vblank - 1) * | 666 | (qctrl->maximum - qctrl->minimum)) / |
648 | (qctrl->maximum - qctrl->minimum)) / | ||
649 | shutter_max + qctrl->minimum; | 667 | shutter_max + qctrl->minimum; |
650 | mt9t031->autoexposure = 1; | 668 | mt9t031->autoexposure = 1; |
651 | } else | 669 | } else |
@@ -657,22 +675,16 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
657 | 675 | ||
658 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 676 | /* Interface active, can use i2c. If it fails, it can indeed mean, that |
659 | * this wasn't our capture interface, so, we wait for the right one */ | 677 | * this wasn't our capture interface, so, we wait for the right one */ |
660 | static int mt9t031_video_probe(struct soc_camera_device *icd) | 678 | static int mt9t031_video_probe(struct i2c_client *client) |
661 | { | 679 | { |
662 | struct i2c_client *client = to_i2c_client(icd->control); | 680 | struct soc_camera_device *icd = client->dev.platform_data; |
663 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 681 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
664 | s32 data; | 682 | s32 data; |
665 | int ret; | 683 | int ret; |
666 | 684 | ||
667 | /* We must have a parent by now. And it cannot be a wrong one. | ||
668 | * So this entire test is completely redundant. */ | ||
669 | if (!icd->dev.parent || | ||
670 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | ||
671 | return -ENODEV; | ||
672 | |||
673 | /* Enable the chip */ | 685 | /* Enable the chip */ |
674 | data = reg_write(client, MT9T031_CHIP_ENABLE, 1); | 686 | data = reg_write(client, MT9T031_CHIP_ENABLE, 1); |
675 | dev_dbg(&icd->dev, "write: %d\n", data); | 687 | dev_dbg(&client->dev, "write: %d\n", data); |
676 | 688 | ||
677 | /* Read out the chip version register */ | 689 | /* Read out the chip version register */ |
678 | data = reg_read(client, MT9T031_CHIP_VERSION); | 690 | data = reg_read(client, MT9T031_CHIP_VERSION); |
@@ -684,44 +696,64 @@ static int mt9t031_video_probe(struct soc_camera_device *icd) | |||
684 | icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats); | 696 | icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats); |
685 | break; | 697 | break; |
686 | default: | 698 | default: |
687 | ret = -ENODEV; | 699 | dev_err(&client->dev, |
688 | dev_err(&icd->dev, | ||
689 | "No MT9T031 chip detected, register read %x\n", data); | 700 | "No MT9T031 chip detected, register read %x\n", data); |
690 | goto ei2c; | 701 | return -ENODEV; |
691 | } | 702 | } |
692 | 703 | ||
693 | dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data); | 704 | dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); |
694 | 705 | ||
695 | /* Now that we know the model, we can start video */ | 706 | ret = mt9t031_idle(client); |
696 | ret = soc_camera_video_start(icd); | 707 | if (ret < 0) |
697 | if (ret) | 708 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
698 | goto evstart; | ||
699 | 709 | ||
700 | return 0; | 710 | /* mt9t031_idle() has reset the chip to default. */ |
711 | mt9t031->exposure = 255; | ||
712 | mt9t031->gain = 64; | ||
701 | 713 | ||
702 | evstart: | ||
703 | ei2c: | ||
704 | return ret; | 714 | return ret; |
705 | } | 715 | } |
706 | 716 | ||
707 | static void mt9t031_video_remove(struct soc_camera_device *icd) | 717 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { |
708 | { | 718 | .g_ctrl = mt9t031_g_ctrl, |
709 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 719 | .s_ctrl = mt9t031_s_ctrl, |
720 | .g_chip_ident = mt9t031_g_chip_ident, | ||
721 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
722 | .g_register = mt9t031_g_register, | ||
723 | .s_register = mt9t031_s_register, | ||
724 | #endif | ||
725 | }; | ||
710 | 726 | ||
711 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr, | 727 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { |
712 | icd->dev.parent, icd->vdev); | 728 | .s_stream = mt9t031_s_stream, |
713 | soc_camera_video_stop(icd); | 729 | .s_fmt = mt9t031_s_fmt, |
714 | } | 730 | .g_fmt = mt9t031_g_fmt, |
731 | .try_fmt = mt9t031_try_fmt, | ||
732 | .s_crop = mt9t031_s_crop, | ||
733 | .g_crop = mt9t031_g_crop, | ||
734 | .cropcap = mt9t031_cropcap, | ||
735 | }; | ||
736 | |||
737 | static struct v4l2_subdev_ops mt9t031_subdev_ops = { | ||
738 | .core = &mt9t031_subdev_core_ops, | ||
739 | .video = &mt9t031_subdev_video_ops, | ||
740 | }; | ||
715 | 741 | ||
716 | static int mt9t031_probe(struct i2c_client *client, | 742 | static int mt9t031_probe(struct i2c_client *client, |
717 | const struct i2c_device_id *did) | 743 | const struct i2c_device_id *did) |
718 | { | 744 | { |
719 | struct mt9t031 *mt9t031; | 745 | struct mt9t031 *mt9t031; |
720 | struct soc_camera_device *icd; | 746 | struct soc_camera_device *icd = client->dev.platform_data; |
721 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 747 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
722 | struct soc_camera_link *icl = client->dev.platform_data; | 748 | struct soc_camera_link *icl; |
723 | int ret; | 749 | int ret; |
724 | 750 | ||
751 | if (!icd) { | ||
752 | dev_err(&client->dev, "MT9T031: missing soc-camera data!\n"); | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | icl = to_soc_camera_link(icd); | ||
725 | if (!icl) { | 757 | if (!icl) { |
726 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); | 758 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); |
727 | return -EINVAL; | 759 | return -EINVAL; |
@@ -737,23 +769,17 @@ static int mt9t031_probe(struct i2c_client *client, | |||
737 | if (!mt9t031) | 769 | if (!mt9t031) |
738 | return -ENOMEM; | 770 | return -ENOMEM; |
739 | 771 | ||
740 | mt9t031->client = client; | 772 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); |
741 | i2c_set_clientdata(client, mt9t031); | ||
742 | 773 | ||
743 | /* Second stage probe - when a capture adapter is there */ | 774 | /* Second stage probe - when a capture adapter is there */ |
744 | icd = &mt9t031->icd; | 775 | icd->ops = &mt9t031_ops; |
745 | icd->ops = &mt9t031_ops; | 776 | icd->y_skip_top = 0; |
746 | icd->control = &client->dev; | 777 | |
747 | icd->x_min = MT9T031_COLUMN_SKIP; | 778 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; |
748 | icd->y_min = MT9T031_ROW_SKIP; | 779 | mt9t031->rect.top = MT9T031_ROW_SKIP; |
749 | icd->x_current = icd->x_min; | 780 | mt9t031->rect.width = MT9T031_MAX_WIDTH; |
750 | icd->y_current = icd->y_min; | 781 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; |
751 | icd->width_min = MT9T031_MIN_WIDTH; | 782 | |
752 | icd->width_max = MT9T031_MAX_WIDTH; | ||
753 | icd->height_min = MT9T031_MIN_HEIGHT; | ||
754 | icd->height_max = MT9T031_MAX_HEIGHT; | ||
755 | icd->y_skip_top = 0; | ||
756 | icd->iface = icl->bus_id; | ||
757 | /* Simulated autoexposure. If enabled, we calculate shutter width | 783 | /* Simulated autoexposure. If enabled, we calculate shutter width |
758 | * ourselves in the driver based on vertical blanking and frame width */ | 784 | * ourselves in the driver based on vertical blanking and frame width */ |
759 | mt9t031->autoexposure = 1; | 785 | mt9t031->autoexposure = 1; |
@@ -761,24 +787,29 @@ static int mt9t031_probe(struct i2c_client *client, | |||
761 | mt9t031->xskip = 1; | 787 | mt9t031->xskip = 1; |
762 | mt9t031->yskip = 1; | 788 | mt9t031->yskip = 1; |
763 | 789 | ||
764 | ret = soc_camera_device_register(icd); | 790 | mt9t031_idle(client); |
765 | if (ret) | ||
766 | goto eisdr; | ||
767 | 791 | ||
768 | return 0; | 792 | ret = mt9t031_video_probe(client); |
793 | |||
794 | mt9t031_disable(client); | ||
795 | |||
796 | if (ret) { | ||
797 | icd->ops = NULL; | ||
798 | i2c_set_clientdata(client, NULL); | ||
799 | kfree(mt9t031); | ||
800 | } | ||
769 | 801 | ||
770 | eisdr: | ||
771 | i2c_set_clientdata(client, NULL); | ||
772 | kfree(mt9t031); | ||
773 | return ret; | 802 | return ret; |
774 | } | 803 | } |
775 | 804 | ||
776 | static int mt9t031_remove(struct i2c_client *client) | 805 | static int mt9t031_remove(struct i2c_client *client) |
777 | { | 806 | { |
778 | struct mt9t031 *mt9t031 = i2c_get_clientdata(client); | 807 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
808 | struct soc_camera_device *icd = client->dev.platform_data; | ||
779 | 809 | ||
780 | soc_camera_device_unregister(&mt9t031->icd); | 810 | icd->ops = NULL; |
781 | i2c_set_clientdata(client, NULL); | 811 | i2c_set_clientdata(client, NULL); |
812 | client->driver = NULL; | ||
782 | kfree(mt9t031); | 813 | kfree(mt9t031); |
783 | 814 | ||
784 | return 0; | 815 | return 0; |
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index dbdcc86ae50d..995607f9d3ba 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -14,13 +14,13 @@ | |||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
16 | 16 | ||
17 | #include <media/v4l2-common.h> | 17 | #include <media/v4l2-subdev.h> |
18 | #include <media/v4l2-chip-ident.h> | 18 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
20 | 20 | ||
21 | /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 21 | /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c |
22 | * The platform has to define i2c_board_info | 22 | * The platform has to define ctruct i2c_board_info objects and link to them |
23 | * and call i2c_register_board_info() */ | 23 | * from struct soc_camera_link */ |
24 | 24 | ||
25 | static char *sensor_type; | 25 | static char *sensor_type; |
26 | module_param(sensor_type, charp, S_IRUGO); | 26 | module_param(sensor_type, charp, S_IRUGO); |
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); | |||
45 | #define MT9V022_PIXEL_OPERATION_MODE 0x0f | 45 | #define MT9V022_PIXEL_OPERATION_MODE 0x0f |
46 | #define MT9V022_LED_OUT_CONTROL 0x1b | 46 | #define MT9V022_LED_OUT_CONTROL 0x1b |
47 | #define MT9V022_ADC_MODE_CONTROL 0x1c | 47 | #define MT9V022_ADC_MODE_CONTROL 0x1c |
48 | #define MT9V022_ANALOG_GAIN 0x34 | 48 | #define MT9V022_ANALOG_GAIN 0x35 |
49 | #define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 | 49 | #define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 |
50 | #define MT9V022_PIXCLK_FV_LV 0x74 | 50 | #define MT9V022_PIXCLK_FV_LV 0x74 |
51 | #define MT9V022_DIGITAL_TEST_PATTERN 0x7f | 51 | #define MT9V022_DIGITAL_TEST_PATTERN 0x7f |
@@ -55,6 +55,13 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); | |||
55 | /* Progressive scan, master, defaults */ | 55 | /* Progressive scan, master, defaults */ |
56 | #define MT9V022_CHIP_CONTROL_DEFAULT 0x188 | 56 | #define MT9V022_CHIP_CONTROL_DEFAULT 0x188 |
57 | 57 | ||
58 | #define MT9V022_MAX_WIDTH 752 | ||
59 | #define MT9V022_MAX_HEIGHT 480 | ||
60 | #define MT9V022_MIN_WIDTH 48 | ||
61 | #define MT9V022_MIN_HEIGHT 32 | ||
62 | #define MT9V022_COLUMN_SKIP 1 | ||
63 | #define MT9V022_ROW_SKIP 4 | ||
64 | |||
58 | static const struct soc_camera_data_format mt9v022_colour_formats[] = { | 65 | static const struct soc_camera_data_format mt9v022_colour_formats[] = { |
59 | /* Order important: first natively supported, | 66 | /* Order important: first natively supported, |
60 | * second supported with a GPIO extender */ | 67 | * second supported with a GPIO extender */ |
@@ -85,12 +92,18 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = { | |||
85 | }; | 92 | }; |
86 | 93 | ||
87 | struct mt9v022 { | 94 | struct mt9v022 { |
88 | struct i2c_client *client; | 95 | struct v4l2_subdev subdev; |
89 | struct soc_camera_device icd; | 96 | struct v4l2_rect rect; /* Sensor window */ |
97 | __u32 fourcc; | ||
90 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ | 98 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ |
91 | u16 chip_control; | 99 | u16 chip_control; |
92 | }; | 100 | }; |
93 | 101 | ||
102 | static struct mt9v022 *to_mt9v022(const struct i2c_client *client) | ||
103 | { | ||
104 | return container_of(i2c_get_clientdata(client), struct mt9v022, subdev); | ||
105 | } | ||
106 | |||
94 | static int reg_read(struct i2c_client *client, const u8 reg) | 107 | static int reg_read(struct i2c_client *client, const u8 reg) |
95 | { | 108 | { |
96 | s32 data = i2c_smbus_read_word_data(client, reg); | 109 | s32 data = i2c_smbus_read_word_data(client, reg); |
@@ -125,29 +138,11 @@ static int reg_clear(struct i2c_client *client, const u8 reg, | |||
125 | return reg_write(client, reg, ret & ~data); | 138 | return reg_write(client, reg, ret & ~data); |
126 | } | 139 | } |
127 | 140 | ||
128 | static int mt9v022_init(struct soc_camera_device *icd) | 141 | static int mt9v022_init(struct i2c_client *client) |
129 | { | 142 | { |
130 | struct i2c_client *client = to_i2c_client(icd->control); | 143 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
131 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | ||
132 | struct soc_camera_link *icl = client->dev.platform_data; | ||
133 | int ret; | 144 | int ret; |
134 | 145 | ||
135 | if (icl->power) { | ||
136 | ret = icl->power(&client->dev, 1); | ||
137 | if (ret < 0) { | ||
138 | dev_err(icd->vdev->parent, | ||
139 | "Platform failed to power-on the camera.\n"); | ||
140 | return ret; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * The camera could have been already on, we hard-reset it additionally, | ||
146 | * if available. Soft reset is done in video_probe(). | ||
147 | */ | ||
148 | if (icl->reset) | ||
149 | icl->reset(&client->dev); | ||
150 | |||
151 | /* Almost the default mode: master, parallel, simultaneous, and an | 146 | /* Almost the default mode: master, parallel, simultaneous, and an |
152 | * undocumented bit 0x200, which is present in table 7, but not in 8, | 147 | * undocumented bit 0x200, which is present in table 7, but not in 8, |
153 | * plus snapshot mode to disable scan for now */ | 148 | * plus snapshot mode to disable scan for now */ |
@@ -161,6 +156,10 @@ static int mt9v022_init(struct soc_camera_device *icd) | |||
161 | /* AEC, AGC on */ | 156 | /* AEC, AGC on */ |
162 | ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); | 157 | ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); |
163 | if (!ret) | 158 | if (!ret) |
159 | ret = reg_write(client, MT9V022_ANALOG_GAIN, 16); | ||
160 | if (!ret) | ||
161 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); | ||
162 | if (!ret) | ||
164 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); | 163 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); |
165 | if (!ret) | 164 | if (!ret) |
166 | /* default - auto */ | 165 | /* default - auto */ |
@@ -171,37 +170,19 @@ static int mt9v022_init(struct soc_camera_device *icd) | |||
171 | return ret; | 170 | return ret; |
172 | } | 171 | } |
173 | 172 | ||
174 | static int mt9v022_release(struct soc_camera_device *icd) | 173 | static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) |
175 | { | 174 | { |
176 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 175 | struct i2c_client *client = sd->priv; |
177 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | 176 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
178 | |||
179 | if (icl->power) | ||
180 | icl->power(&mt9v022->client->dev, 0); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | 177 | ||
185 | static int mt9v022_start_capture(struct soc_camera_device *icd) | 178 | if (enable) |
186 | { | 179 | /* Switch to master "normal" mode */ |
187 | struct i2c_client *client = to_i2c_client(icd->control); | 180 | mt9v022->chip_control &= ~0x10; |
188 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 181 | else |
189 | /* Switch to master "normal" mode */ | 182 | /* Switch to snapshot mode */ |
190 | mt9v022->chip_control &= ~0x10; | 183 | mt9v022->chip_control |= 0x10; |
191 | if (reg_write(client, MT9V022_CHIP_CONTROL, | ||
192 | mt9v022->chip_control) < 0) | ||
193 | return -EIO; | ||
194 | return 0; | ||
195 | } | ||
196 | 184 | ||
197 | static int mt9v022_stop_capture(struct soc_camera_device *icd) | 185 | if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) |
198 | { | ||
199 | struct i2c_client *client = to_i2c_client(icd->control); | ||
200 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | ||
201 | /* Switch to snapshot mode */ | ||
202 | mt9v022->chip_control |= 0x10; | ||
203 | if (reg_write(client, MT9V022_CHIP_CONTROL, | ||
204 | mt9v022->chip_control) < 0) | ||
205 | return -EIO; | 186 | return -EIO; |
206 | return 0; | 187 | return 0; |
207 | } | 188 | } |
@@ -209,9 +190,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd) | |||
209 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, | 190 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, |
210 | unsigned long flags) | 191 | unsigned long flags) |
211 | { | 192 | { |
212 | struct i2c_client *client = to_i2c_client(icd->control); | 193 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
213 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 194 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
214 | struct soc_camera_link *icl = client->dev.platform_data; | 195 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
215 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; | 196 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; |
216 | int ret; | 197 | int ret; |
217 | u16 pixclk = 0; | 198 | u16 pixclk = 0; |
@@ -255,7 +236,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
255 | if (ret < 0) | 236 | if (ret < 0) |
256 | return ret; | 237 | return ret; |
257 | 238 | ||
258 | dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | 239 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", |
259 | pixclk, mt9v022->chip_control); | 240 | pixclk, mt9v022->chip_control); |
260 | 241 | ||
261 | return 0; | 242 | return 0; |
@@ -263,8 +244,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
263 | 244 | ||
264 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | 245 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) |
265 | { | 246 | { |
266 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 247 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
267 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | ||
268 | unsigned int width_flag; | 248 | unsigned int width_flag; |
269 | 249 | ||
270 | if (icl->query_bus_param) | 250 | if (icl->query_bus_param) |
@@ -280,60 +260,121 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | |||
280 | width_flag; | 260 | width_flag; |
281 | } | 261 | } |
282 | 262 | ||
283 | static int mt9v022_set_crop(struct soc_camera_device *icd, | 263 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
284 | struct v4l2_rect *rect) | ||
285 | { | 264 | { |
286 | struct i2c_client *client = to_i2c_client(icd->control); | 265 | struct i2c_client *client = sd->priv; |
266 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
267 | struct v4l2_rect rect = a->c; | ||
268 | struct soc_camera_device *icd = client->dev.platform_data; | ||
287 | int ret; | 269 | int ret; |
288 | 270 | ||
271 | /* Bayer format - even size lengths */ | ||
272 | if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 || | ||
273 | mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) { | ||
274 | rect.width = ALIGN(rect.width, 2); | ||
275 | rect.height = ALIGN(rect.height, 2); | ||
276 | /* Let the user play with the starting pixel */ | ||
277 | } | ||
278 | |||
279 | soc_camera_limit_side(&rect.left, &rect.width, | ||
280 | MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH); | ||
281 | |||
282 | soc_camera_limit_side(&rect.top, &rect.height, | ||
283 | MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT); | ||
284 | |||
289 | /* Like in example app. Contradicts the datasheet though */ | 285 | /* Like in example app. Contradicts the datasheet though */ |
290 | ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); | 286 | ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); |
291 | if (ret >= 0) { | 287 | if (ret >= 0) { |
292 | if (ret & 1) /* Autoexposure */ | 288 | if (ret & 1) /* Autoexposure */ |
293 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, | 289 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, |
294 | rect->height + icd->y_skip_top + 43); | 290 | rect.height + icd->y_skip_top + 43); |
295 | else | 291 | else |
296 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 292 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
297 | rect->height + icd->y_skip_top + 43); | 293 | rect.height + icd->y_skip_top + 43); |
298 | } | 294 | } |
299 | /* Setup frame format: defaults apart from width and height */ | 295 | /* Setup frame format: defaults apart from width and height */ |
300 | if (!ret) | 296 | if (!ret) |
301 | ret = reg_write(client, MT9V022_COLUMN_START, rect->left); | 297 | ret = reg_write(client, MT9V022_COLUMN_START, rect.left); |
302 | if (!ret) | 298 | if (!ret) |
303 | ret = reg_write(client, MT9V022_ROW_START, rect->top); | 299 | ret = reg_write(client, MT9V022_ROW_START, rect.top); |
304 | if (!ret) | 300 | if (!ret) |
305 | /* Default 94, Phytec driver says: | 301 | /* Default 94, Phytec driver says: |
306 | * "width + horizontal blank >= 660" */ | 302 | * "width + horizontal blank >= 660" */ |
307 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, | 303 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, |
308 | rect->width > 660 - 43 ? 43 : | 304 | rect.width > 660 - 43 ? 43 : |
309 | 660 - rect->width); | 305 | 660 - rect.width); |
310 | if (!ret) | 306 | if (!ret) |
311 | ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); | 307 | ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); |
312 | if (!ret) | 308 | if (!ret) |
313 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width); | 309 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); |
314 | if (!ret) | 310 | if (!ret) |
315 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, | 311 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, |
316 | rect->height + icd->y_skip_top); | 312 | rect.height + icd->y_skip_top); |
317 | 313 | ||
318 | if (ret < 0) | 314 | if (ret < 0) |
319 | return ret; | 315 | return ret; |
320 | 316 | ||
321 | dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height); | 317 | dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect.width, rect.height); |
318 | |||
319 | mt9v022->rect = rect; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
325 | { | ||
326 | struct i2c_client *client = sd->priv; | ||
327 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
328 | |||
329 | a->c = mt9v022->rect; | ||
330 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
322 | 331 | ||
323 | return 0; | 332 | return 0; |
324 | } | 333 | } |
325 | 334 | ||
326 | static int mt9v022_set_fmt(struct soc_camera_device *icd, | 335 | static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
327 | struct v4l2_format *f) | ||
328 | { | 336 | { |
329 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 337 | a->bounds.left = MT9V022_COLUMN_SKIP; |
338 | a->bounds.top = MT9V022_ROW_SKIP; | ||
339 | a->bounds.width = MT9V022_MAX_WIDTH; | ||
340 | a->bounds.height = MT9V022_MAX_HEIGHT; | ||
341 | a->defrect = a->bounds; | ||
342 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
343 | a->pixelaspect.numerator = 1; | ||
344 | a->pixelaspect.denominator = 1; | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
350 | { | ||
351 | struct i2c_client *client = sd->priv; | ||
352 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
330 | struct v4l2_pix_format *pix = &f->fmt.pix; | 353 | struct v4l2_pix_format *pix = &f->fmt.pix; |
331 | struct v4l2_rect rect = { | 354 | |
332 | .left = icd->x_current, | 355 | pix->width = mt9v022->rect.width; |
333 | .top = icd->y_current, | 356 | pix->height = mt9v022->rect.height; |
334 | .width = pix->width, | 357 | pix->pixelformat = mt9v022->fourcc; |
335 | .height = pix->height, | 358 | pix->field = V4L2_FIELD_NONE; |
359 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
365 | { | ||
366 | struct i2c_client *client = sd->priv; | ||
367 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
368 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
369 | struct v4l2_crop a = { | ||
370 | .c = { | ||
371 | .left = mt9v022->rect.left, | ||
372 | .top = mt9v022->rect.top, | ||
373 | .width = pix->width, | ||
374 | .height = pix->height, | ||
375 | }, | ||
336 | }; | 376 | }; |
377 | int ret; | ||
337 | 378 | ||
338 | /* The caller provides a supported format, as verified per call to | 379 | /* The caller provides a supported format, as verified per call to |
339 | * icd->try_fmt(), datawidth is from our supported format list */ | 380 | * icd->try_fmt(), datawidth is from our supported format list */ |
@@ -356,30 +397,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd, | |||
356 | } | 397 | } |
357 | 398 | ||
358 | /* No support for scaling on this camera, just crop. */ | 399 | /* No support for scaling on this camera, just crop. */ |
359 | return mt9v022_set_crop(icd, &rect); | 400 | ret = mt9v022_s_crop(sd, &a); |
401 | if (!ret) { | ||
402 | pix->width = mt9v022->rect.width; | ||
403 | pix->height = mt9v022->rect.height; | ||
404 | mt9v022->fourcc = pix->pixelformat; | ||
405 | } | ||
406 | |||
407 | return ret; | ||
360 | } | 408 | } |
361 | 409 | ||
362 | static int mt9v022_try_fmt(struct soc_camera_device *icd, | 410 | static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
363 | struct v4l2_format *f) | ||
364 | { | 411 | { |
412 | struct i2c_client *client = sd->priv; | ||
413 | struct soc_camera_device *icd = client->dev.platform_data; | ||
365 | struct v4l2_pix_format *pix = &f->fmt.pix; | 414 | struct v4l2_pix_format *pix = &f->fmt.pix; |
415 | int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | ||
416 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16; | ||
366 | 417 | ||
367 | v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */, | 418 | v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH, |
368 | &pix->height, 32 + icd->y_skip_top, | 419 | MT9V022_MAX_WIDTH, align, |
369 | 480 + icd->y_skip_top, 0, 0); | 420 | &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top, |
421 | MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0); | ||
370 | 422 | ||
371 | return 0; | 423 | return 0; |
372 | } | 424 | } |
373 | 425 | ||
374 | static int mt9v022_get_chip_id(struct soc_camera_device *icd, | 426 | static int mt9v022_g_chip_ident(struct v4l2_subdev *sd, |
375 | struct v4l2_dbg_chip_ident *id) | 427 | struct v4l2_dbg_chip_ident *id) |
376 | { | 428 | { |
377 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 429 | struct i2c_client *client = sd->priv; |
430 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
378 | 431 | ||
379 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 432 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
380 | return -EINVAL; | 433 | return -EINVAL; |
381 | 434 | ||
382 | if (id->match.addr != mt9v022->client->addr) | 435 | if (id->match.addr != client->addr) |
383 | return -ENODEV; | 436 | return -ENODEV; |
384 | 437 | ||
385 | id->ident = mt9v022->model; | 438 | id->ident = mt9v022->model; |
@@ -389,10 +442,10 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd, | |||
389 | } | 442 | } |
390 | 443 | ||
391 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 444 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
392 | static int mt9v022_get_register(struct soc_camera_device *icd, | 445 | static int mt9v022_g_register(struct v4l2_subdev *sd, |
393 | struct v4l2_dbg_register *reg) | 446 | struct v4l2_dbg_register *reg) |
394 | { | 447 | { |
395 | struct i2c_client *client = to_i2c_client(icd->control); | 448 | struct i2c_client *client = sd->priv; |
396 | 449 | ||
397 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 450 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
398 | return -EINVAL; | 451 | return -EINVAL; |
@@ -409,10 +462,10 @@ static int mt9v022_get_register(struct soc_camera_device *icd, | |||
409 | return 0; | 462 | return 0; |
410 | } | 463 | } |
411 | 464 | ||
412 | static int mt9v022_set_register(struct soc_camera_device *icd, | 465 | static int mt9v022_s_register(struct v4l2_subdev *sd, |
413 | struct v4l2_dbg_register *reg) | 466 | struct v4l2_dbg_register *reg) |
414 | { | 467 | { |
415 | struct i2c_client *client = to_i2c_client(icd->control); | 468 | struct i2c_client *client = sd->priv; |
416 | 469 | ||
417 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 470 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
418 | return -EINVAL; | 471 | return -EINVAL; |
@@ -481,41 +534,22 @@ static const struct v4l2_queryctrl mt9v022_controls[] = { | |||
481 | } | 534 | } |
482 | }; | 535 | }; |
483 | 536 | ||
484 | static int mt9v022_video_probe(struct soc_camera_device *); | ||
485 | static void mt9v022_video_remove(struct soc_camera_device *); | ||
486 | static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *); | ||
487 | static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *); | ||
488 | |||
489 | static struct soc_camera_ops mt9v022_ops = { | 537 | static struct soc_camera_ops mt9v022_ops = { |
490 | .owner = THIS_MODULE, | ||
491 | .probe = mt9v022_video_probe, | ||
492 | .remove = mt9v022_video_remove, | ||
493 | .init = mt9v022_init, | ||
494 | .release = mt9v022_release, | ||
495 | .start_capture = mt9v022_start_capture, | ||
496 | .stop_capture = mt9v022_stop_capture, | ||
497 | .set_crop = mt9v022_set_crop, | ||
498 | .set_fmt = mt9v022_set_fmt, | ||
499 | .try_fmt = mt9v022_try_fmt, | ||
500 | .set_bus_param = mt9v022_set_bus_param, | 538 | .set_bus_param = mt9v022_set_bus_param, |
501 | .query_bus_param = mt9v022_query_bus_param, | 539 | .query_bus_param = mt9v022_query_bus_param, |
502 | .controls = mt9v022_controls, | 540 | .controls = mt9v022_controls, |
503 | .num_controls = ARRAY_SIZE(mt9v022_controls), | 541 | .num_controls = ARRAY_SIZE(mt9v022_controls), |
504 | .get_control = mt9v022_get_control, | ||
505 | .set_control = mt9v022_set_control, | ||
506 | .get_chip_id = mt9v022_get_chip_id, | ||
507 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
508 | .get_register = mt9v022_get_register, | ||
509 | .set_register = mt9v022_set_register, | ||
510 | #endif | ||
511 | }; | 542 | }; |
512 | 543 | ||
513 | static int mt9v022_get_control(struct soc_camera_device *icd, | 544 | static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
514 | struct v4l2_control *ctrl) | ||
515 | { | 545 | { |
516 | struct i2c_client *client = to_i2c_client(icd->control); | 546 | struct i2c_client *client = sd->priv; |
547 | const struct v4l2_queryctrl *qctrl; | ||
548 | unsigned long range; | ||
517 | int data; | 549 | int data; |
518 | 550 | ||
551 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
552 | |||
519 | switch (ctrl->id) { | 553 | switch (ctrl->id) { |
520 | case V4L2_CID_VFLIP: | 554 | case V4L2_CID_VFLIP: |
521 | data = reg_read(client, MT9V022_READ_MODE); | 555 | data = reg_read(client, MT9V022_READ_MODE); |
@@ -541,19 +575,35 @@ static int mt9v022_get_control(struct soc_camera_device *icd, | |||
541 | return -EIO; | 575 | return -EIO; |
542 | ctrl->value = !!(data & 0x2); | 576 | ctrl->value = !!(data & 0x2); |
543 | break; | 577 | break; |
578 | case V4L2_CID_GAIN: | ||
579 | data = reg_read(client, MT9V022_ANALOG_GAIN); | ||
580 | if (data < 0) | ||
581 | return -EIO; | ||
582 | |||
583 | range = qctrl->maximum - qctrl->minimum; | ||
584 | ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; | ||
585 | |||
586 | break; | ||
587 | case V4L2_CID_EXPOSURE: | ||
588 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); | ||
589 | if (data < 0) | ||
590 | return -EIO; | ||
591 | |||
592 | range = qctrl->maximum - qctrl->minimum; | ||
593 | ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; | ||
594 | |||
595 | break; | ||
544 | } | 596 | } |
545 | return 0; | 597 | return 0; |
546 | } | 598 | } |
547 | 599 | ||
548 | static int mt9v022_set_control(struct soc_camera_device *icd, | 600 | static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
549 | struct v4l2_control *ctrl) | ||
550 | { | 601 | { |
551 | int data; | 602 | int data; |
552 | struct i2c_client *client = to_i2c_client(icd->control); | 603 | struct i2c_client *client = sd->priv; |
553 | const struct v4l2_queryctrl *qctrl; | 604 | const struct v4l2_queryctrl *qctrl; |
554 | 605 | ||
555 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | 606 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); |
556 | |||
557 | if (!qctrl) | 607 | if (!qctrl) |
558 | return -EINVAL; | 608 | return -EINVAL; |
559 | 609 | ||
@@ -580,12 +630,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
580 | return -EINVAL; | 630 | return -EINVAL; |
581 | else { | 631 | else { |
582 | unsigned long range = qctrl->maximum - qctrl->minimum; | 632 | unsigned long range = qctrl->maximum - qctrl->minimum; |
583 | /* Datasheet says 16 to 64. autogain only works properly | 633 | /* Valid values 16 to 64, 32 to 64 must be even. */ |
584 | * after setting gain to maximum 14. Larger values | ||
585 | * produce "white fly" noise effect. On the whole, | ||
586 | * manually setting analog gain does no good. */ | ||
587 | unsigned long gain = ((ctrl->value - qctrl->minimum) * | 634 | unsigned long gain = ((ctrl->value - qctrl->minimum) * |
588 | 10 + range / 2) / range + 4; | 635 | 48 + range / 2) / range + 16; |
589 | if (gain >= 32) | 636 | if (gain >= 32) |
590 | gain &= ~1; | 637 | gain &= ~1; |
591 | /* The user wants to set gain manually, hope, she | 638 | /* The user wants to set gain manually, hope, she |
@@ -594,11 +641,10 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
594 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) | 641 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
595 | return -EIO; | 642 | return -EIO; |
596 | 643 | ||
597 | dev_info(&icd->dev, "Setting gain from %d to %lu\n", | 644 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", |
598 | reg_read(client, MT9V022_ANALOG_GAIN), gain); | 645 | reg_read(client, MT9V022_ANALOG_GAIN), gain); |
599 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) | 646 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) |
600 | return -EIO; | 647 | return -EIO; |
601 | icd->gain = ctrl->value; | ||
602 | } | 648 | } |
603 | break; | 649 | break; |
604 | case V4L2_CID_EXPOSURE: | 650 | case V4L2_CID_EXPOSURE: |
@@ -615,13 +661,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
615 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) | 661 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) |
616 | return -EIO; | 662 | return -EIO; |
617 | 663 | ||
618 | dev_dbg(&icd->dev, "Shutter width from %d to %lu\n", | 664 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", |
619 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), | 665 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), |
620 | shutter); | 666 | shutter); |
621 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 667 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
622 | shutter) < 0) | 668 | shutter) < 0) |
623 | return -EIO; | 669 | return -EIO; |
624 | icd->exposure = ctrl->value; | ||
625 | } | 670 | } |
626 | break; | 671 | break; |
627 | case V4L2_CID_AUTOGAIN: | 672 | case V4L2_CID_AUTOGAIN: |
@@ -646,11 +691,11 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
646 | 691 | ||
647 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 692 | /* Interface active, can use i2c. If it fails, it can indeed mean, that |
648 | * this wasn't our capture interface, so, we wait for the right one */ | 693 | * this wasn't our capture interface, so, we wait for the right one */ |
649 | static int mt9v022_video_probe(struct soc_camera_device *icd) | 694 | static int mt9v022_video_probe(struct soc_camera_device *icd, |
695 | struct i2c_client *client) | ||
650 | { | 696 | { |
651 | struct i2c_client *client = to_i2c_client(icd->control); | 697 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
652 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 698 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
653 | struct soc_camera_link *icl = client->dev.platform_data; | ||
654 | s32 data; | 699 | s32 data; |
655 | int ret; | 700 | int ret; |
656 | unsigned long flags; | 701 | unsigned long flags; |
@@ -665,7 +710,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
665 | /* must be 0x1311 or 0x1313 */ | 710 | /* must be 0x1311 or 0x1313 */ |
666 | if (data != 0x1311 && data != 0x1313) { | 711 | if (data != 0x1311 && data != 0x1313) { |
667 | ret = -ENODEV; | 712 | ret = -ENODEV; |
668 | dev_info(&icd->dev, "No MT9V022 detected, ID register 0x%x\n", | 713 | dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", |
669 | data); | 714 | data); |
670 | goto ei2c; | 715 | goto ei2c; |
671 | } | 716 | } |
@@ -677,7 +722,9 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
677 | /* 15 clock cycles */ | 722 | /* 15 clock cycles */ |
678 | udelay(200); | 723 | udelay(200); |
679 | if (reg_read(client, MT9V022_RESET)) { | 724 | if (reg_read(client, MT9V022_RESET)) { |
680 | dev_err(&icd->dev, "Resetting MT9V022 failed!\n"); | 725 | dev_err(&client->dev, "Resetting MT9V022 failed!\n"); |
726 | if (ret > 0) | ||
727 | ret = -EIO; | ||
681 | goto ei2c; | 728 | goto ei2c; |
682 | } | 729 | } |
683 | 730 | ||
@@ -694,7 +741,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
694 | } | 741 | } |
695 | 742 | ||
696 | if (ret < 0) | 743 | if (ret < 0) |
697 | goto eisis; | 744 | goto ei2c; |
698 | 745 | ||
699 | icd->num_formats = 0; | 746 | icd->num_formats = 0; |
700 | 747 | ||
@@ -716,42 +763,70 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
716 | if (flags & SOCAM_DATAWIDTH_8) | 763 | if (flags & SOCAM_DATAWIDTH_8) |
717 | icd->num_formats++; | 764 | icd->num_formats++; |
718 | 765 | ||
719 | ret = soc_camera_video_start(icd); | 766 | mt9v022->fourcc = icd->formats->fourcc; |
720 | if (ret < 0) | ||
721 | goto eisis; | ||
722 | 767 | ||
723 | dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", | 768 | dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", |
724 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? | 769 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? |
725 | "monochrome" : "colour"); | 770 | "monochrome" : "colour"); |
726 | 771 | ||
727 | return 0; | 772 | ret = mt9v022_init(client); |
773 | if (ret < 0) | ||
774 | dev_err(&client->dev, "Failed to initialise the camera\n"); | ||
728 | 775 | ||
729 | eisis: | ||
730 | ei2c: | 776 | ei2c: |
731 | return ret; | 777 | return ret; |
732 | } | 778 | } |
733 | 779 | ||
734 | static void mt9v022_video_remove(struct soc_camera_device *icd) | 780 | static void mt9v022_video_remove(struct soc_camera_device *icd) |
735 | { | 781 | { |
736 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 782 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
737 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | ||
738 | 783 | ||
739 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr, | 784 | dev_dbg(&icd->dev, "Video removed: %p, %p\n", |
740 | icd->dev.parent, icd->vdev); | 785 | icd->dev.parent, icd->vdev); |
741 | soc_camera_video_stop(icd); | ||
742 | if (icl->free_bus) | 786 | if (icl->free_bus) |
743 | icl->free_bus(icl); | 787 | icl->free_bus(icl); |
744 | } | 788 | } |
745 | 789 | ||
790 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | ||
791 | .g_ctrl = mt9v022_g_ctrl, | ||
792 | .s_ctrl = mt9v022_s_ctrl, | ||
793 | .g_chip_ident = mt9v022_g_chip_ident, | ||
794 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
795 | .g_register = mt9v022_g_register, | ||
796 | .s_register = mt9v022_s_register, | ||
797 | #endif | ||
798 | }; | ||
799 | |||
800 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | ||
801 | .s_stream = mt9v022_s_stream, | ||
802 | .s_fmt = mt9v022_s_fmt, | ||
803 | .g_fmt = mt9v022_g_fmt, | ||
804 | .try_fmt = mt9v022_try_fmt, | ||
805 | .s_crop = mt9v022_s_crop, | ||
806 | .g_crop = mt9v022_g_crop, | ||
807 | .cropcap = mt9v022_cropcap, | ||
808 | }; | ||
809 | |||
810 | static struct v4l2_subdev_ops mt9v022_subdev_ops = { | ||
811 | .core = &mt9v022_subdev_core_ops, | ||
812 | .video = &mt9v022_subdev_video_ops, | ||
813 | }; | ||
814 | |||
746 | static int mt9v022_probe(struct i2c_client *client, | 815 | static int mt9v022_probe(struct i2c_client *client, |
747 | const struct i2c_device_id *did) | 816 | const struct i2c_device_id *did) |
748 | { | 817 | { |
749 | struct mt9v022 *mt9v022; | 818 | struct mt9v022 *mt9v022; |
750 | struct soc_camera_device *icd; | 819 | struct soc_camera_device *icd = client->dev.platform_data; |
751 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 820 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
752 | struct soc_camera_link *icl = client->dev.platform_data; | 821 | struct soc_camera_link *icl; |
753 | int ret; | 822 | int ret; |
754 | 823 | ||
824 | if (!icd) { | ||
825 | dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); | ||
826 | return -EINVAL; | ||
827 | } | ||
828 | |||
829 | icl = to_soc_camera_link(icd); | ||
755 | if (!icl) { | 830 | if (!icl) { |
756 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); | 831 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); |
757 | return -EINVAL; | 832 | return -EINVAL; |
@@ -767,40 +842,41 @@ static int mt9v022_probe(struct i2c_client *client, | |||
767 | if (!mt9v022) | 842 | if (!mt9v022) |
768 | return -ENOMEM; | 843 | return -ENOMEM; |
769 | 844 | ||
845 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); | ||
846 | |||
770 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; | 847 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; |
771 | mt9v022->client = client; | ||
772 | i2c_set_clientdata(client, mt9v022); | ||
773 | |||
774 | icd = &mt9v022->icd; | ||
775 | icd->ops = &mt9v022_ops; | ||
776 | icd->control = &client->dev; | ||
777 | icd->x_min = 1; | ||
778 | icd->y_min = 4; | ||
779 | icd->x_current = 1; | ||
780 | icd->y_current = 4; | ||
781 | icd->width_min = 48; | ||
782 | icd->width_max = 752; | ||
783 | icd->height_min = 32; | ||
784 | icd->height_max = 480; | ||
785 | icd->y_skip_top = 1; | ||
786 | icd->iface = icl->bus_id; | ||
787 | |||
788 | ret = soc_camera_device_register(icd); | ||
789 | if (ret) | ||
790 | goto eisdr; | ||
791 | 848 | ||
792 | return 0; | 849 | icd->ops = &mt9v022_ops; |
850 | /* | ||
851 | * MT9V022 _really_ corrupts the first read out line. | ||
852 | * TODO: verify on i.MX31 | ||
853 | */ | ||
854 | icd->y_skip_top = 1; | ||
855 | |||
856 | mt9v022->rect.left = MT9V022_COLUMN_SKIP; | ||
857 | mt9v022->rect.top = MT9V022_ROW_SKIP; | ||
858 | mt9v022->rect.width = MT9V022_MAX_WIDTH; | ||
859 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; | ||
860 | |||
861 | ret = mt9v022_video_probe(icd, client); | ||
862 | if (ret) { | ||
863 | icd->ops = NULL; | ||
864 | i2c_set_clientdata(client, NULL); | ||
865 | kfree(mt9v022); | ||
866 | } | ||
793 | 867 | ||
794 | eisdr: | ||
795 | kfree(mt9v022); | ||
796 | return ret; | 868 | return ret; |
797 | } | 869 | } |
798 | 870 | ||
799 | static int mt9v022_remove(struct i2c_client *client) | 871 | static int mt9v022_remove(struct i2c_client *client) |
800 | { | 872 | { |
801 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); | 873 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
874 | struct soc_camera_device *icd = client->dev.platform_data; | ||
802 | 875 | ||
803 | soc_camera_device_unregister(&mt9v022->icd); | 876 | icd->ops = NULL; |
877 | mt9v022_video_remove(icd); | ||
878 | i2c_set_clientdata(client, NULL); | ||
879 | client->driver = NULL; | ||
804 | kfree(mt9v022); | 880 | kfree(mt9v022); |
805 | 881 | ||
806 | return 0; | 882 | return 0; |
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 736c31d23194..5f37952c75cf 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c | |||
@@ -126,7 +126,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
126 | { | 126 | { |
127 | struct soc_camera_device *icd = vq->priv_data; | 127 | struct soc_camera_device *icd = vq->priv_data; |
128 | 128 | ||
129 | *size = icd->width * icd->height * | 129 | *size = icd->user_width * icd->user_height * |
130 | ((icd->current_fmt->depth + 7) >> 3); | 130 | ((icd->current_fmt->depth + 7) >> 3); |
131 | 131 | ||
132 | if (!*count) | 132 | if (!*count) |
@@ -135,7 +135,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
135 | while (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) | 135 | while (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) |
136 | (*count)--; | 136 | (*count)--; |
137 | 137 | ||
138 | dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); | 138 | dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); |
139 | 139 | ||
140 | return 0; | 140 | return 0; |
141 | } | 141 | } |
@@ -147,7 +147,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) | |||
147 | 147 | ||
148 | BUG_ON(in_interrupt()); | 148 | BUG_ON(in_interrupt()); |
149 | 149 | ||
150 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 150 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
151 | vb, vb->baddr, vb->bsize); | 151 | vb, vb->baddr, vb->bsize); |
152 | 152 | ||
153 | /* This waits until this buffer is out of danger, i.e., until it is no | 153 | /* This waits until this buffer is out of danger, i.e., until it is no |
@@ -165,7 +165,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, | |||
165 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); | 165 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); |
166 | int ret; | 166 | int ret; |
167 | 167 | ||
168 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 168 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
169 | vb, vb->baddr, vb->bsize); | 169 | vb, vb->baddr, vb->bsize); |
170 | 170 | ||
171 | /* Added list head initialization on alloc */ | 171 | /* Added list head initialization on alloc */ |
@@ -178,12 +178,12 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, | |||
178 | buf->inwork = 1; | 178 | buf->inwork = 1; |
179 | 179 | ||
180 | if (buf->fmt != icd->current_fmt || | 180 | if (buf->fmt != icd->current_fmt || |
181 | vb->width != icd->width || | 181 | vb->width != icd->user_width || |
182 | vb->height != icd->height || | 182 | vb->height != icd->user_height || |
183 | vb->field != field) { | 183 | vb->field != field) { |
184 | buf->fmt = icd->current_fmt; | 184 | buf->fmt = icd->current_fmt; |
185 | vb->width = icd->width; | 185 | vb->width = icd->user_width; |
186 | vb->height = icd->height; | 186 | vb->height = icd->user_height; |
187 | vb->field = field; | 187 | vb->field = field; |
188 | vb->state = VIDEOBUF_NEEDS_INIT; | 188 | vb->state = VIDEOBUF_NEEDS_INIT; |
189 | } | 189 | } |
@@ -216,10 +216,11 @@ out: | |||
216 | static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) | 216 | static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) |
217 | { | 217 | { |
218 | struct videobuf_buffer *vbuf = &pcdev->active->vb; | 218 | struct videobuf_buffer *vbuf = &pcdev->active->vb; |
219 | struct device *dev = pcdev->icd->dev.parent; | ||
219 | int ret; | 220 | int ret; |
220 | 221 | ||
221 | if (unlikely(!pcdev->active)) { | 222 | if (unlikely(!pcdev->active)) { |
222 | dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n"); | 223 | dev_err(dev, "DMA End IRQ with no active buffer\n"); |
223 | return -EFAULT; | 224 | return -EFAULT; |
224 | } | 225 | } |
225 | 226 | ||
@@ -229,7 +230,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) | |||
229 | vbuf->size, pcdev->res->start + | 230 | vbuf->size, pcdev->res->start + |
230 | CSIRXR, DMA_MODE_READ); | 231 | CSIRXR, DMA_MODE_READ); |
231 | if (unlikely(ret)) | 232 | if (unlikely(ret)) |
232 | dev_err(pcdev->soc_host.dev, "Failed to setup DMA sg list\n"); | 233 | dev_err(dev, "Failed to setup DMA sg list\n"); |
233 | 234 | ||
234 | return ret; | 235 | return ret; |
235 | } | 236 | } |
@@ -243,7 +244,7 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq, | |||
243 | struct mx1_camera_dev *pcdev = ici->priv; | 244 | struct mx1_camera_dev *pcdev = ici->priv; |
244 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); | 245 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); |
245 | 246 | ||
246 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 247 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
247 | vb, vb->baddr, vb->bsize); | 248 | vb, vb->baddr, vb->bsize); |
248 | 249 | ||
249 | list_add_tail(&vb->queue, &pcdev->capture); | 250 | list_add_tail(&vb->queue, &pcdev->capture); |
@@ -270,22 +271,23 @@ static void mx1_videobuf_release(struct videobuf_queue *vq, | |||
270 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); | 271 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); |
271 | #ifdef DEBUG | 272 | #ifdef DEBUG |
272 | struct soc_camera_device *icd = vq->priv_data; | 273 | struct soc_camera_device *icd = vq->priv_data; |
274 | struct device *dev = icd->dev.parent; | ||
273 | 275 | ||
274 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 276 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
275 | vb, vb->baddr, vb->bsize); | 277 | vb, vb->baddr, vb->bsize); |
276 | 278 | ||
277 | switch (vb->state) { | 279 | switch (vb->state) { |
278 | case VIDEOBUF_ACTIVE: | 280 | case VIDEOBUF_ACTIVE: |
279 | dev_dbg(&icd->dev, "%s (active)\n", __func__); | 281 | dev_dbg(dev, "%s (active)\n", __func__); |
280 | break; | 282 | break; |
281 | case VIDEOBUF_QUEUED: | 283 | case VIDEOBUF_QUEUED: |
282 | dev_dbg(&icd->dev, "%s (queued)\n", __func__); | 284 | dev_dbg(dev, "%s (queued)\n", __func__); |
283 | break; | 285 | break; |
284 | case VIDEOBUF_PREPARED: | 286 | case VIDEOBUF_PREPARED: |
285 | dev_dbg(&icd->dev, "%s (prepared)\n", __func__); | 287 | dev_dbg(dev, "%s (prepared)\n", __func__); |
286 | break; | 288 | break; |
287 | default: | 289 | default: |
288 | dev_dbg(&icd->dev, "%s (unknown)\n", __func__); | 290 | dev_dbg(dev, "%s (unknown)\n", __func__); |
289 | break; | 291 | break; |
290 | } | 292 | } |
291 | #endif | 293 | #endif |
@@ -325,6 +327,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev, | |||
325 | static void mx1_camera_dma_irq(int channel, void *data) | 327 | static void mx1_camera_dma_irq(int channel, void *data) |
326 | { | 328 | { |
327 | struct mx1_camera_dev *pcdev = data; | 329 | struct mx1_camera_dev *pcdev = data; |
330 | struct device *dev = pcdev->icd->dev.parent; | ||
328 | struct mx1_buffer *buf; | 331 | struct mx1_buffer *buf; |
329 | struct videobuf_buffer *vb; | 332 | struct videobuf_buffer *vb; |
330 | unsigned long flags; | 333 | unsigned long flags; |
@@ -334,14 +337,14 @@ static void mx1_camera_dma_irq(int channel, void *data) | |||
334 | imx_dma_disable(channel); | 337 | imx_dma_disable(channel); |
335 | 338 | ||
336 | if (unlikely(!pcdev->active)) { | 339 | if (unlikely(!pcdev->active)) { |
337 | dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n"); | 340 | dev_err(dev, "DMA End IRQ with no active buffer\n"); |
338 | goto out; | 341 | goto out; |
339 | } | 342 | } |
340 | 343 | ||
341 | vb = &pcdev->active->vb; | 344 | vb = &pcdev->active->vb; |
342 | buf = container_of(vb, struct mx1_buffer, vb); | 345 | buf = container_of(vb, struct mx1_buffer, vb); |
343 | WARN_ON(buf->inwork || list_empty(&vb->queue)); | 346 | WARN_ON(buf->inwork || list_empty(&vb->queue)); |
344 | dev_dbg(pcdev->soc_host.dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 347 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
345 | vb, vb->baddr, vb->bsize); | 348 | vb, vb->baddr, vb->bsize); |
346 | 349 | ||
347 | mx1_camera_wakeup(pcdev, vb, buf); | 350 | mx1_camera_wakeup(pcdev, vb, buf); |
@@ -362,7 +365,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q, | |||
362 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 365 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
363 | struct mx1_camera_dev *pcdev = ici->priv; | 366 | struct mx1_camera_dev *pcdev = ici->priv; |
364 | 367 | ||
365 | videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, ici->dev, | 368 | videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent, |
366 | &pcdev->lock, | 369 | &pcdev->lock, |
367 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 370 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
368 | V4L2_FIELD_NONE, | 371 | V4L2_FIELD_NONE, |
@@ -381,8 +384,9 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev) | |||
381 | * they get a nice Oops */ | 384 | * they get a nice Oops */ |
382 | div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; | 385 | div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; |
383 | 386 | ||
384 | dev_dbg(pcdev->soc_host.dev, "System clock %lukHz, target freq %dkHz, " | 387 | dev_dbg(pcdev->icd->dev.parent, |
385 | "divisor %lu\n", lcdclk / 1000, mclk / 1000, div); | 388 | "System clock %lukHz, target freq %dkHz, divisor %lu\n", |
389 | lcdclk / 1000, mclk / 1000, div); | ||
386 | 390 | ||
387 | return div; | 391 | return div; |
388 | } | 392 | } |
@@ -391,7 +395,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) | |||
391 | { | 395 | { |
392 | unsigned int csicr1 = CSICR1_EN; | 396 | unsigned int csicr1 = CSICR1_EN; |
393 | 397 | ||
394 | dev_dbg(pcdev->soc_host.dev, "Activate device\n"); | 398 | dev_dbg(pcdev->icd->dev.parent, "Activate device\n"); |
395 | 399 | ||
396 | clk_enable(pcdev->clk); | 400 | clk_enable(pcdev->clk); |
397 | 401 | ||
@@ -407,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) | |||
407 | 411 | ||
408 | static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) | 412 | static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) |
409 | { | 413 | { |
410 | dev_dbg(pcdev->soc_host.dev, "Deactivate device\n"); | 414 | dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n"); |
411 | 415 | ||
412 | /* Disable all CSI interface */ | 416 | /* Disable all CSI interface */ |
413 | __raw_writel(0x00, pcdev->base + CSICR1); | 417 | __raw_writel(0x00, pcdev->base + CSICR1); |
@@ -428,14 +432,12 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) | |||
428 | goto ebusy; | 432 | goto ebusy; |
429 | } | 433 | } |
430 | 434 | ||
431 | dev_info(&icd->dev, "MX1 Camera driver attached to camera %d\n", | 435 | dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n", |
432 | icd->devnum); | 436 | icd->devnum); |
433 | 437 | ||
434 | mx1_camera_activate(pcdev); | 438 | mx1_camera_activate(pcdev); |
435 | ret = icd->ops->init(icd); | ||
436 | 439 | ||
437 | if (!ret) | 440 | pcdev->icd = icd; |
438 | pcdev->icd = icd; | ||
439 | 441 | ||
440 | ebusy: | 442 | ebusy: |
441 | return ret; | 443 | return ret; |
@@ -456,20 +458,20 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd) | |||
456 | /* Stop DMA engine */ | 458 | /* Stop DMA engine */ |
457 | imx_dma_disable(pcdev->dma_chan); | 459 | imx_dma_disable(pcdev->dma_chan); |
458 | 460 | ||
459 | dev_info(&icd->dev, "MX1 Camera driver detached from camera %d\n", | 461 | dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n", |
460 | icd->devnum); | 462 | icd->devnum); |
461 | 463 | ||
462 | icd->ops->release(icd); | ||
463 | |||
464 | mx1_camera_deactivate(pcdev); | 464 | mx1_camera_deactivate(pcdev); |
465 | 465 | ||
466 | pcdev->icd = NULL; | 466 | pcdev->icd = NULL; |
467 | } | 467 | } |
468 | 468 | ||
469 | static int mx1_camera_set_crop(struct soc_camera_device *icd, | 469 | static int mx1_camera_set_crop(struct soc_camera_device *icd, |
470 | struct v4l2_rect *rect) | 470 | struct v4l2_crop *a) |
471 | { | 471 | { |
472 | return icd->ops->set_crop(icd, rect); | 472 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
473 | |||
474 | return v4l2_subdev_call(sd, video, s_crop, a); | ||
473 | } | 475 | } |
474 | 476 | ||
475 | static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 477 | static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
@@ -539,18 +541,19 @@ static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
539 | static int mx1_camera_set_fmt(struct soc_camera_device *icd, | 541 | static int mx1_camera_set_fmt(struct soc_camera_device *icd, |
540 | struct v4l2_format *f) | 542 | struct v4l2_format *f) |
541 | { | 543 | { |
542 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 544 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
543 | const struct soc_camera_format_xlate *xlate; | 545 | const struct soc_camera_format_xlate *xlate; |
544 | struct v4l2_pix_format *pix = &f->fmt.pix; | 546 | struct v4l2_pix_format *pix = &f->fmt.pix; |
545 | int ret; | 547 | int ret; |
546 | 548 | ||
547 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 549 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
548 | if (!xlate) { | 550 | if (!xlate) { |
549 | dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); | 551 | dev_warn(icd->dev.parent, "Format %x not found\n", |
552 | pix->pixelformat); | ||
550 | return -EINVAL; | 553 | return -EINVAL; |
551 | } | 554 | } |
552 | 555 | ||
553 | ret = icd->ops->set_fmt(icd, f); | 556 | ret = v4l2_subdev_call(sd, video, s_fmt, f); |
554 | if (!ret) { | 557 | if (!ret) { |
555 | icd->buswidth = xlate->buswidth; | 558 | icd->buswidth = xlate->buswidth; |
556 | icd->current_fmt = xlate->host_fmt; | 559 | icd->current_fmt = xlate->host_fmt; |
@@ -562,10 +565,11 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, | |||
562 | static int mx1_camera_try_fmt(struct soc_camera_device *icd, | 565 | static int mx1_camera_try_fmt(struct soc_camera_device *icd, |
563 | struct v4l2_format *f) | 566 | struct v4l2_format *f) |
564 | { | 567 | { |
568 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
565 | /* TODO: limit to mx1 hardware capabilities */ | 569 | /* TODO: limit to mx1 hardware capabilities */ |
566 | 570 | ||
567 | /* limit to sensor capabilities */ | 571 | /* limit to sensor capabilities */ |
568 | return icd->ops->try_fmt(icd, f); | 572 | return v4l2_subdev_call(sd, video, try_fmt, f); |
569 | } | 573 | } |
570 | 574 | ||
571 | static int mx1_camera_reqbufs(struct soc_camera_file *icf, | 575 | static int mx1_camera_reqbufs(struct soc_camera_file *icf, |
@@ -737,7 +741,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev) | |||
737 | pcdev->soc_host.drv_name = DRIVER_NAME; | 741 | pcdev->soc_host.drv_name = DRIVER_NAME; |
738 | pcdev->soc_host.ops = &mx1_soc_camera_host_ops; | 742 | pcdev->soc_host.ops = &mx1_soc_camera_host_ops; |
739 | pcdev->soc_host.priv = pcdev; | 743 | pcdev->soc_host.priv = pcdev; |
740 | pcdev->soc_host.dev = &pdev->dev; | 744 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; |
741 | pcdev->soc_host.nr = pdev->id; | 745 | pcdev->soc_host.nr = pdev->id; |
742 | err = soc_camera_host_register(&pcdev->soc_host); | 746 | err = soc_camera_host_register(&pcdev->soc_host); |
743 | if (err) | 747 | if (err) |
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 9770cb7932ca..dff2e5e2d8c6 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
@@ -178,7 +178,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf | |||
178 | 178 | ||
179 | BUG_ON(in_interrupt()); | 179 | BUG_ON(in_interrupt()); |
180 | 180 | ||
181 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 181 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
182 | vb, vb->baddr, vb->bsize); | 182 | vb, vb->baddr, vb->bsize); |
183 | 183 | ||
184 | /* | 184 | /* |
@@ -220,7 +220,7 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
220 | if (!mx3_cam->idmac_channel[0]) | 220 | if (!mx3_cam->idmac_channel[0]) |
221 | return -EINVAL; | 221 | return -EINVAL; |
222 | 222 | ||
223 | *size = icd->width * icd->height * bpp; | 223 | *size = icd->user_width * icd->user_height * bpp; |
224 | 224 | ||
225 | if (!*count) | 225 | if (!*count) |
226 | *count = 32; | 226 | *count = 32; |
@@ -241,7 +241,7 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq, | |||
241 | struct mx3_camera_buffer *buf = | 241 | struct mx3_camera_buffer *buf = |
242 | container_of(vb, struct mx3_camera_buffer, vb); | 242 | container_of(vb, struct mx3_camera_buffer, vb); |
243 | /* current_fmt _must_ always be set */ | 243 | /* current_fmt _must_ always be set */ |
244 | size_t new_size = icd->width * icd->height * | 244 | size_t new_size = icd->user_width * icd->user_height * |
245 | ((icd->current_fmt->depth + 7) >> 3); | 245 | ((icd->current_fmt->depth + 7) >> 3); |
246 | int ret; | 246 | int ret; |
247 | 247 | ||
@@ -251,12 +251,12 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq, | |||
251 | */ | 251 | */ |
252 | 252 | ||
253 | if (buf->fmt != icd->current_fmt || | 253 | if (buf->fmt != icd->current_fmt || |
254 | vb->width != icd->width || | 254 | vb->width != icd->user_width || |
255 | vb->height != icd->height || | 255 | vb->height != icd->user_height || |
256 | vb->field != field) { | 256 | vb->field != field) { |
257 | buf->fmt = icd->current_fmt; | 257 | buf->fmt = icd->current_fmt; |
258 | vb->width = icd->width; | 258 | vb->width = icd->user_width; |
259 | vb->height = icd->height; | 259 | vb->height = icd->user_height; |
260 | vb->field = field; | 260 | vb->field = field; |
261 | if (vb->state != VIDEOBUF_NEEDS_INIT) | 261 | if (vb->state != VIDEOBUF_NEEDS_INIT) |
262 | free_buffer(vq, buf); | 262 | free_buffer(vq, buf); |
@@ -354,9 +354,9 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, | |||
354 | 354 | ||
355 | /* This is the configuration of one sg-element */ | 355 | /* This is the configuration of one sg-element */ |
356 | video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); | 356 | video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); |
357 | video->out_width = icd->width; | 357 | video->out_width = icd->user_width; |
358 | video->out_height = icd->height; | 358 | video->out_height = icd->user_height; |
359 | video->out_stride = icd->width; | 359 | video->out_stride = icd->user_width; |
360 | 360 | ||
361 | #ifdef DEBUG | 361 | #ifdef DEBUG |
362 | /* helps to see what DMA actually has written */ | 362 | /* helps to see what DMA actually has written */ |
@@ -375,7 +375,8 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, | |||
375 | spin_unlock_irq(&mx3_cam->lock); | 375 | spin_unlock_irq(&mx3_cam->lock); |
376 | 376 | ||
377 | cookie = txd->tx_submit(txd); | 377 | cookie = txd->tx_submit(txd); |
378 | dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg)); | 378 | dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n", |
379 | cookie, sg_dma_address(&buf->sg)); | ||
379 | 380 | ||
380 | spin_lock_irq(&mx3_cam->lock); | 381 | spin_lock_irq(&mx3_cam->lock); |
381 | 382 | ||
@@ -402,9 +403,10 @@ static void mx3_videobuf_release(struct videobuf_queue *vq, | |||
402 | container_of(vb, struct mx3_camera_buffer, vb); | 403 | container_of(vb, struct mx3_camera_buffer, vb); |
403 | unsigned long flags; | 404 | unsigned long flags; |
404 | 405 | ||
405 | dev_dbg(&icd->dev, "Release%s DMA 0x%08x (state %d), queue %sempty\n", | 406 | dev_dbg(icd->dev.parent, |
407 | "Release%s DMA 0x%08x (state %d), queue %sempty\n", | ||
406 | mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), | 408 | mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), |
407 | vb->state, list_empty(&vb->queue) ? "" : "not "); | 409 | vb->state, list_empty(&vb->queue) ? "" : "not "); |
408 | spin_lock_irqsave(&mx3_cam->lock, flags); | 410 | spin_lock_irqsave(&mx3_cam->lock, flags); |
409 | if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && | 411 | if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && |
410 | !list_empty(&vb->queue)) { | 412 | !list_empty(&vb->queue)) { |
@@ -431,7 +433,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q, | |||
431 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 433 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
432 | struct mx3_camera_dev *mx3_cam = ici->priv; | 434 | struct mx3_camera_dev *mx3_cam = ici->priv; |
433 | 435 | ||
434 | videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, ici->dev, | 436 | videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, icd->dev.parent, |
435 | &mx3_cam->lock, | 437 | &mx3_cam->lock, |
436 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 438 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
437 | V4L2_FIELD_NONE, | 439 | V4L2_FIELD_NONE, |
@@ -484,7 +486,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, | |||
484 | 486 | ||
485 | clk_enable(mx3_cam->clk); | 487 | clk_enable(mx3_cam->clk); |
486 | rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); | 488 | rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); |
487 | dev_dbg(&icd->dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate); | 489 | dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate); |
488 | if (rate) | 490 | if (rate) |
489 | clk_set_rate(mx3_cam->clk, rate); | 491 | clk_set_rate(mx3_cam->clk, rate); |
490 | } | 492 | } |
@@ -494,29 +496,18 @@ static int mx3_camera_add_device(struct soc_camera_device *icd) | |||
494 | { | 496 | { |
495 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 497 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
496 | struct mx3_camera_dev *mx3_cam = ici->priv; | 498 | struct mx3_camera_dev *mx3_cam = ici->priv; |
497 | int ret; | ||
498 | 499 | ||
499 | if (mx3_cam->icd) { | 500 | if (mx3_cam->icd) |
500 | ret = -EBUSY; | 501 | return -EBUSY; |
501 | goto ebusy; | ||
502 | } | ||
503 | 502 | ||
504 | mx3_camera_activate(mx3_cam, icd); | 503 | mx3_camera_activate(mx3_cam, icd); |
505 | ret = icd->ops->init(icd); | ||
506 | if (ret < 0) { | ||
507 | clk_disable(mx3_cam->clk); | ||
508 | goto einit; | ||
509 | } | ||
510 | 504 | ||
511 | mx3_cam->icd = icd; | 505 | mx3_cam->icd = icd; |
512 | 506 | ||
513 | einit: | 507 | dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n", |
514 | ebusy: | 508 | icd->devnum); |
515 | if (!ret) | ||
516 | dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n", | ||
517 | icd->devnum); | ||
518 | 509 | ||
519 | return ret; | 510 | return 0; |
520 | } | 511 | } |
521 | 512 | ||
522 | /* Called with .video_lock held */ | 513 | /* Called with .video_lock held */ |
@@ -533,13 +524,11 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd) | |||
533 | *ichan = NULL; | 524 | *ichan = NULL; |
534 | } | 525 | } |
535 | 526 | ||
536 | icd->ops->release(icd); | ||
537 | |||
538 | clk_disable(mx3_cam->clk); | 527 | clk_disable(mx3_cam->clk); |
539 | 528 | ||
540 | mx3_cam->icd = NULL; | 529 | mx3_cam->icd = NULL; |
541 | 530 | ||
542 | dev_info(&icd->dev, "MX3 Camera driver detached from camera %d\n", | 531 | dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n", |
543 | icd->devnum); | 532 | icd->devnum); |
544 | } | 533 | } |
545 | 534 | ||
@@ -551,7 +540,8 @@ static bool channel_change_requested(struct soc_camera_device *icd, | |||
551 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | 540 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; |
552 | 541 | ||
553 | /* Do buffers have to be re-allocated or channel re-configured? */ | 542 | /* Do buffers have to be re-allocated or channel re-configured? */ |
554 | return ichan && rect->width * rect->height > icd->width * icd->height; | 543 | return ichan && rect->width * rect->height > |
544 | icd->user_width * icd->user_height; | ||
555 | } | 545 | } |
556 | 546 | ||
557 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, | 547 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, |
@@ -599,8 +589,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
599 | *flags |= SOCAM_DATAWIDTH_4; | 589 | *flags |= SOCAM_DATAWIDTH_4; |
600 | break; | 590 | break; |
601 | default: | 591 | default: |
602 | dev_info(mx3_cam->soc_host.dev, "Unsupported bus width %d\n", | 592 | dev_warn(mx3_cam->soc_host.v4l2_dev.dev, |
603 | buswidth); | 593 | "Unsupported bus width %d\n", buswidth); |
604 | return -EINVAL; | 594 | return -EINVAL; |
605 | } | 595 | } |
606 | 596 | ||
@@ -615,7 +605,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | |||
615 | unsigned long bus_flags, camera_flags; | 605 | unsigned long bus_flags, camera_flags; |
616 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); | 606 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); |
617 | 607 | ||
618 | dev_dbg(ici->dev, "requested bus width %d bit: %d\n", depth, ret); | 608 | dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret); |
619 | 609 | ||
620 | if (ret < 0) | 610 | if (ret < 0) |
621 | return ret; | 611 | return ret; |
@@ -624,7 +614,8 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | |||
624 | 614 | ||
625 | ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 615 | ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); |
626 | if (ret < 0) | 616 | if (ret < 0) |
627 | dev_warn(&icd->dev, "Flags incompatible: camera %lx, host %lx\n", | 617 | dev_warn(icd->dev.parent, |
618 | "Flags incompatible: camera %lx, host %lx\n", | ||
628 | camera_flags, bus_flags); | 619 | camera_flags, bus_flags); |
629 | 620 | ||
630 | return ret; | 621 | return ret; |
@@ -638,7 +629,7 @@ static bool chan_filter(struct dma_chan *chan, void *arg) | |||
638 | if (!rq) | 629 | if (!rq) |
639 | return false; | 630 | return false; |
640 | 631 | ||
641 | pdata = rq->mx3_cam->soc_host.dev->platform_data; | 632 | pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data; |
642 | 633 | ||
643 | return rq->id == chan->chan_id && | 634 | return rq->id == chan->chan_id && |
644 | pdata->dma_dev == chan->device->dev; | 635 | pdata->dma_dev == chan->device->dev; |
@@ -698,7 +689,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
698 | xlate->cam_fmt = icd->formats + idx; | 689 | xlate->cam_fmt = icd->formats + idx; |
699 | xlate->buswidth = buswidth; | 690 | xlate->buswidth = buswidth; |
700 | xlate++; | 691 | xlate++; |
701 | dev_dbg(ici->dev, "Providing format %s using %s\n", | 692 | dev_dbg(icd->dev.parent, |
693 | "Providing format %s using %s\n", | ||
702 | mx3_camera_formats[0].name, | 694 | mx3_camera_formats[0].name, |
703 | icd->formats[idx].name); | 695 | icd->formats[idx].name); |
704 | } | 696 | } |
@@ -710,7 +702,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
710 | xlate->cam_fmt = icd->formats + idx; | 702 | xlate->cam_fmt = icd->formats + idx; |
711 | xlate->buswidth = buswidth; | 703 | xlate->buswidth = buswidth; |
712 | xlate++; | 704 | xlate++; |
713 | dev_dbg(ici->dev, "Providing format %s using %s\n", | 705 | dev_dbg(icd->dev.parent, |
706 | "Providing format %s using %s\n", | ||
714 | mx3_camera_formats[0].name, | 707 | mx3_camera_formats[0].name, |
715 | icd->formats[idx].name); | 708 | icd->formats[idx].name); |
716 | } | 709 | } |
@@ -723,7 +716,7 @@ passthrough: | |||
723 | xlate->cam_fmt = icd->formats + idx; | 716 | xlate->cam_fmt = icd->formats + idx; |
724 | xlate->buswidth = buswidth; | 717 | xlate->buswidth = buswidth; |
725 | xlate++; | 718 | xlate++; |
726 | dev_dbg(ici->dev, | 719 | dev_dbg(icd->dev.parent, |
727 | "Providing format %s in pass-through mode\n", | 720 | "Providing format %s in pass-through mode\n", |
728 | icd->formats[idx].name); | 721 | icd->formats[idx].name); |
729 | } | 722 | } |
@@ -733,13 +726,13 @@ passthrough: | |||
733 | } | 726 | } |
734 | 727 | ||
735 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, | 728 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, |
736 | struct v4l2_rect *rect) | 729 | unsigned int width, unsigned int height) |
737 | { | 730 | { |
738 | u32 ctrl, width_field, height_field; | 731 | u32 ctrl, width_field, height_field; |
739 | 732 | ||
740 | /* Setup frame size - this cannot be changed on-the-fly... */ | 733 | /* Setup frame size - this cannot be changed on-the-fly... */ |
741 | width_field = rect->width - 1; | 734 | width_field = width - 1; |
742 | height_field = rect->height - 1; | 735 | height_field = height - 1; |
743 | csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); | 736 | csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); |
744 | 737 | ||
745 | csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); | 738 | csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); |
@@ -751,11 +744,6 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam, | |||
751 | ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; | 744 | ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; |
752 | /* Sensor does the cropping */ | 745 | /* Sensor does the cropping */ |
753 | csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); | 746 | csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); |
754 | |||
755 | /* | ||
756 | * No need to free resources here if we fail, we'll see if we need to | ||
757 | * do this next time we are called | ||
758 | */ | ||
759 | } | 747 | } |
760 | 748 | ||
761 | static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | 749 | static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) |
@@ -792,25 +780,74 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | |||
792 | return 0; | 780 | return 0; |
793 | } | 781 | } |
794 | 782 | ||
783 | /* | ||
784 | * FIXME: learn to use stride != width, then we can keep stride properly aligned | ||
785 | * and support arbitrary (even) widths. | ||
786 | */ | ||
787 | static inline void stride_align(__s32 *width) | ||
788 | { | ||
789 | if (((*width + 7) & ~7) < 4096) | ||
790 | *width = (*width + 7) & ~7; | ||
791 | else | ||
792 | *width = *width & ~7; | ||
793 | } | ||
794 | |||
795 | /* | ||
796 | * As long as we don't implement host-side cropping and scaling, we can use | ||
797 | * default g_crop and cropcap from soc_camera.c | ||
798 | */ | ||
795 | static int mx3_camera_set_crop(struct soc_camera_device *icd, | 799 | static int mx3_camera_set_crop(struct soc_camera_device *icd, |
796 | struct v4l2_rect *rect) | 800 | struct v4l2_crop *a) |
797 | { | 801 | { |
802 | struct v4l2_rect *rect = &a->c; | ||
798 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 803 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
799 | struct mx3_camera_dev *mx3_cam = ici->priv; | 804 | struct mx3_camera_dev *mx3_cam = ici->priv; |
805 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
806 | struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; | ||
807 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
808 | int ret; | ||
800 | 809 | ||
801 | /* | 810 | soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); |
802 | * We now know pixel formats and can decide upon DMA-channel(s) | 811 | soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); |
803 | * So far only direct camera-to-memory is supported | 812 | |
804 | */ | 813 | ret = v4l2_subdev_call(sd, video, s_crop, a); |
805 | if (channel_change_requested(icd, rect)) { | 814 | if (ret < 0) |
806 | int ret = acquire_dma_channel(mx3_cam); | 815 | return ret; |
816 | |||
817 | /* The capture device might have changed its output */ | ||
818 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
819 | if (ret < 0) | ||
820 | return ret; | ||
821 | |||
822 | if (pix->width & 7) { | ||
823 | /* Ouch! We can only handle 8-byte aligned width... */ | ||
824 | stride_align(&pix->width); | ||
825 | ret = v4l2_subdev_call(sd, video, s_fmt, &f); | ||
807 | if (ret < 0) | 826 | if (ret < 0) |
808 | return ret; | 827 | return ret; |
809 | } | 828 | } |
810 | 829 | ||
811 | configure_geometry(mx3_cam, rect); | 830 | if (pix->width != icd->user_width || pix->height != icd->user_height) { |
831 | /* | ||
832 | * We now know pixel formats and can decide upon DMA-channel(s) | ||
833 | * So far only direct camera-to-memory is supported | ||
834 | */ | ||
835 | if (channel_change_requested(icd, rect)) { | ||
836 | int ret = acquire_dma_channel(mx3_cam); | ||
837 | if (ret < 0) | ||
838 | return ret; | ||
839 | } | ||
840 | |||
841 | configure_geometry(mx3_cam, pix->width, pix->height); | ||
842 | } | ||
843 | |||
844 | dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", | ||
845 | pix->width, pix->height); | ||
812 | 846 | ||
813 | return icd->ops->set_crop(icd, rect); | 847 | icd->user_width = pix->width; |
848 | icd->user_height = pix->height; | ||
849 | |||
850 | return ret; | ||
814 | } | 851 | } |
815 | 852 | ||
816 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | 853 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, |
@@ -818,22 +855,21 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, | |||
818 | { | 855 | { |
819 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 856 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
820 | struct mx3_camera_dev *mx3_cam = ici->priv; | 857 | struct mx3_camera_dev *mx3_cam = ici->priv; |
858 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
821 | const struct soc_camera_format_xlate *xlate; | 859 | const struct soc_camera_format_xlate *xlate; |
822 | struct v4l2_pix_format *pix = &f->fmt.pix; | 860 | struct v4l2_pix_format *pix = &f->fmt.pix; |
823 | struct v4l2_rect rect = { | ||
824 | .left = icd->x_current, | ||
825 | .top = icd->y_current, | ||
826 | .width = pix->width, | ||
827 | .height = pix->height, | ||
828 | }; | ||
829 | int ret; | 861 | int ret; |
830 | 862 | ||
831 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 863 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
832 | if (!xlate) { | 864 | if (!xlate) { |
833 | dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); | 865 | dev_warn(icd->dev.parent, "Format %x not found\n", |
866 | pix->pixelformat); | ||
834 | return -EINVAL; | 867 | return -EINVAL; |
835 | } | 868 | } |
836 | 869 | ||
870 | stride_align(&pix->width); | ||
871 | dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height); | ||
872 | |||
837 | ret = acquire_dma_channel(mx3_cam); | 873 | ret = acquire_dma_channel(mx3_cam); |
838 | if (ret < 0) | 874 | if (ret < 0) |
839 | return ret; | 875 | return ret; |
@@ -844,21 +880,23 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, | |||
844 | * mxc_v4l2_s_fmt() | 880 | * mxc_v4l2_s_fmt() |
845 | */ | 881 | */ |
846 | 882 | ||
847 | configure_geometry(mx3_cam, &rect); | 883 | configure_geometry(mx3_cam, pix->width, pix->height); |
848 | 884 | ||
849 | ret = icd->ops->set_fmt(icd, f); | 885 | ret = v4l2_subdev_call(sd, video, s_fmt, f); |
850 | if (!ret) { | 886 | if (!ret) { |
851 | icd->buswidth = xlate->buswidth; | 887 | icd->buswidth = xlate->buswidth; |
852 | icd->current_fmt = xlate->host_fmt; | 888 | icd->current_fmt = xlate->host_fmt; |
853 | } | 889 | } |
854 | 890 | ||
891 | dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); | ||
892 | |||
855 | return ret; | 893 | return ret; |
856 | } | 894 | } |
857 | 895 | ||
858 | static int mx3_camera_try_fmt(struct soc_camera_device *icd, | 896 | static int mx3_camera_try_fmt(struct soc_camera_device *icd, |
859 | struct v4l2_format *f) | 897 | struct v4l2_format *f) |
860 | { | 898 | { |
861 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 899 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
862 | const struct soc_camera_format_xlate *xlate; | 900 | const struct soc_camera_format_xlate *xlate; |
863 | struct v4l2_pix_format *pix = &f->fmt.pix; | 901 | struct v4l2_pix_format *pix = &f->fmt.pix; |
864 | __u32 pixfmt = pix->pixelformat; | 902 | __u32 pixfmt = pix->pixelformat; |
@@ -867,7 +905,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, | |||
867 | 905 | ||
868 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 906 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
869 | if (pixfmt && !xlate) { | 907 | if (pixfmt && !xlate) { |
870 | dev_warn(ici->dev, "Format %x not found\n", pixfmt); | 908 | dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); |
871 | return -EINVAL; | 909 | return -EINVAL; |
872 | } | 910 | } |
873 | 911 | ||
@@ -884,7 +922,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, | |||
884 | /* camera has to see its format, but the user the original one */ | 922 | /* camera has to see its format, but the user the original one */ |
885 | pix->pixelformat = xlate->cam_fmt->fourcc; | 923 | pix->pixelformat = xlate->cam_fmt->fourcc; |
886 | /* limit to sensor capabilities */ | 924 | /* limit to sensor capabilities */ |
887 | ret = icd->ops->try_fmt(icd, f); | 925 | ret = v4l2_subdev_call(sd, video, try_fmt, f); |
888 | pix->pixelformat = xlate->host_fmt->fourcc; | 926 | pix->pixelformat = xlate->host_fmt->fourcc; |
889 | 927 | ||
890 | field = pix->field; | 928 | field = pix->field; |
@@ -892,7 +930,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, | |||
892 | if (field == V4L2_FIELD_ANY) { | 930 | if (field == V4L2_FIELD_ANY) { |
893 | pix->field = V4L2_FIELD_NONE; | 931 | pix->field = V4L2_FIELD_NONE; |
894 | } else if (field != V4L2_FIELD_NONE) { | 932 | } else if (field != V4L2_FIELD_NONE) { |
895 | dev_err(&icd->dev, "Field type %d unsupported.\n", field); | 933 | dev_err(icd->dev.parent, "Field type %d unsupported.\n", field); |
896 | return -EINVAL; | 934 | return -EINVAL; |
897 | } | 935 | } |
898 | 936 | ||
@@ -931,14 +969,15 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
931 | u32 dw, sens_conf; | 969 | u32 dw, sens_conf; |
932 | int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags); | 970 | int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags); |
933 | const struct soc_camera_format_xlate *xlate; | 971 | const struct soc_camera_format_xlate *xlate; |
972 | struct device *dev = icd->dev.parent; | ||
934 | 973 | ||
935 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 974 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
936 | if (!xlate) { | 975 | if (!xlate) { |
937 | dev_warn(ici->dev, "Format %x not found\n", pixfmt); | 976 | dev_warn(dev, "Format %x not found\n", pixfmt); |
938 | return -EINVAL; | 977 | return -EINVAL; |
939 | } | 978 | } |
940 | 979 | ||
941 | dev_dbg(ici->dev, "requested bus width %d bit: %d\n", | 980 | dev_dbg(dev, "requested bus width %d bit: %d\n", |
942 | icd->buswidth, ret); | 981 | icd->buswidth, ret); |
943 | 982 | ||
944 | if (ret < 0) | 983 | if (ret < 0) |
@@ -947,9 +986,10 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
947 | camera_flags = icd->ops->query_bus_param(icd); | 986 | camera_flags = icd->ops->query_bus_param(icd); |
948 | 987 | ||
949 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 988 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); |
989 | dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", | ||
990 | camera_flags, bus_flags, common_flags); | ||
950 | if (!common_flags) { | 991 | if (!common_flags) { |
951 | dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n", | 992 | dev_dbg(dev, "no common flags"); |
952 | camera_flags, bus_flags); | ||
953 | return -EINVAL; | 993 | return -EINVAL; |
954 | } | 994 | } |
955 | 995 | ||
@@ -1002,8 +1042,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1002 | SOCAM_DATAWIDTH_4; | 1042 | SOCAM_DATAWIDTH_4; |
1003 | 1043 | ||
1004 | ret = icd->ops->set_bus_param(icd, common_flags); | 1044 | ret = icd->ops->set_bus_param(icd, common_flags); |
1005 | if (ret < 0) | 1045 | if (ret < 0) { |
1046 | dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", | ||
1047 | common_flags, ret); | ||
1006 | return ret; | 1048 | return ret; |
1049 | } | ||
1007 | 1050 | ||
1008 | /* | 1051 | /* |
1009 | * So far only gated clock mode is supported. Add a line | 1052 | * So far only gated clock mode is supported. Add a line |
@@ -1055,7 +1098,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1055 | 1098 | ||
1056 | csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); | 1099 | csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); |
1057 | 1100 | ||
1058 | dev_dbg(ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw); | 1101 | dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw); |
1059 | 1102 | ||
1060 | return 0; | 1103 | return 0; |
1061 | } | 1104 | } |
@@ -1127,8 +1170,9 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) | |||
1127 | INIT_LIST_HEAD(&mx3_cam->capture); | 1170 | INIT_LIST_HEAD(&mx3_cam->capture); |
1128 | spin_lock_init(&mx3_cam->lock); | 1171 | spin_lock_init(&mx3_cam->lock); |
1129 | 1172 | ||
1130 | base = ioremap(res->start, res->end - res->start + 1); | 1173 | base = ioremap(res->start, resource_size(res)); |
1131 | if (!base) { | 1174 | if (!base) { |
1175 | pr_err("Couldn't map %x@%x\n", resource_size(res), res->start); | ||
1132 | err = -ENOMEM; | 1176 | err = -ENOMEM; |
1133 | goto eioremap; | 1177 | goto eioremap; |
1134 | } | 1178 | } |
@@ -1139,7 +1183,7 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) | |||
1139 | soc_host->drv_name = MX3_CAM_DRV_NAME; | 1183 | soc_host->drv_name = MX3_CAM_DRV_NAME; |
1140 | soc_host->ops = &mx3_soc_camera_host_ops; | 1184 | soc_host->ops = &mx3_soc_camera_host_ops; |
1141 | soc_host->priv = mx3_cam; | 1185 | soc_host->priv = mx3_cam; |
1142 | soc_host->dev = &pdev->dev; | 1186 | soc_host->v4l2_dev.dev = &pdev->dev; |
1143 | soc_host->nr = pdev->id; | 1187 | soc_host->nr = pdev->id; |
1144 | 1188 | ||
1145 | err = soc_camera_host_register(soc_host); | 1189 | err = soc_camera_host_register(soc_host); |
@@ -1215,3 +1259,4 @@ module_exit(mx3_camera_exit); | |||
1215 | MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); | 1259 | MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); |
1216 | MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); | 1260 | MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); |
1217 | MODULE_LICENSE("GPL v2"); | 1261 | MODULE_LICENSE("GPL v2"); |
1262 | MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME); | ||
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 35890e8b2431..3454070e63f0 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c | |||
@@ -186,19 +186,19 @@ static int mxb_probe(struct saa7146_dev *dev) | |||
186 | } | 186 | } |
187 | 187 | ||
188 | mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | 188 | mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, |
189 | "saa7115", "saa7111", I2C_SAA7111A); | 189 | "saa7115", "saa7111", I2C_SAA7111A, NULL); |
190 | mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | 190 | mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, |
191 | "tea6420", "tea6420", I2C_TEA6420_1); | 191 | "tea6420", "tea6420", I2C_TEA6420_1, NULL); |
192 | mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | 192 | mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, |
193 | "tea6420", "tea6420", I2C_TEA6420_2); | 193 | "tea6420", "tea6420", I2C_TEA6420_2, NULL); |
194 | mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | 194 | mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, |
195 | "tea6415c", "tea6415c", I2C_TEA6415C); | 195 | "tea6415c", "tea6415c", I2C_TEA6415C, NULL); |
196 | mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | 196 | mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, |
197 | "tda9840", "tda9840", I2C_TDA9840); | 197 | "tda9840", "tda9840", I2C_TDA9840, NULL); |
198 | mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | 198 | mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, |
199 | "tuner", "tuner", I2C_TUNER); | 199 | "tuner", "tuner", I2C_TUNER, NULL); |
200 | if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | 200 | if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, |
201 | "saa5246a", "saa5246a", I2C_SAA5246A)) { | 201 | "saa5246a", "saa5246a", I2C_SAA5246A, NULL)) { |
202 | printk(KERN_INFO "mxb: found teletext decoder\n"); | 202 | printk(KERN_INFO "mxb: found teletext decoder\n"); |
203 | } | 203 | } |
204 | 204 | ||
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 0bce255168bd..eccb40ab7fec 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/videodev2.h> | 23 | #include <linux/videodev2.h> |
24 | #include <media/v4l2-chip-ident.h> | 24 | #include <media/v4l2-chip-ident.h> |
25 | #include <media/v4l2-common.h> | 25 | #include <media/v4l2-subdev.h> |
26 | #include <media/soc_camera.h> | 26 | #include <media/soc_camera.h> |
27 | #include <media/ov772x.h> | 27 | #include <media/ov772x.h> |
28 | 28 | ||
@@ -382,11 +382,10 @@ struct regval_list { | |||
382 | }; | 382 | }; |
383 | 383 | ||
384 | struct ov772x_color_format { | 384 | struct ov772x_color_format { |
385 | char *name; | 385 | const struct soc_camera_data_format *format; |
386 | __u32 fourcc; | 386 | u8 dsp3; |
387 | u8 dsp3; | 387 | u8 com3; |
388 | u8 com3; | 388 | u8 com7; |
389 | u8 com7; | ||
390 | }; | 389 | }; |
391 | 390 | ||
392 | struct ov772x_win_size { | 391 | struct ov772x_win_size { |
@@ -398,14 +397,15 @@ struct ov772x_win_size { | |||
398 | }; | 397 | }; |
399 | 398 | ||
400 | struct ov772x_priv { | 399 | struct ov772x_priv { |
400 | struct v4l2_subdev subdev; | ||
401 | struct ov772x_camera_info *info; | 401 | struct ov772x_camera_info *info; |
402 | struct i2c_client *client; | ||
403 | struct soc_camera_device icd; | ||
404 | const struct ov772x_color_format *fmt; | 402 | const struct ov772x_color_format *fmt; |
405 | const struct ov772x_win_size *win; | 403 | const struct ov772x_win_size *win; |
406 | int model; | 404 | int model; |
407 | unsigned int flag_vflip:1; | 405 | unsigned short flag_vflip:1; |
408 | unsigned int flag_hflip:1; | 406 | unsigned short flag_hflip:1; |
407 | /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ | ||
408 | unsigned short band_filter; | ||
409 | }; | 409 | }; |
410 | 410 | ||
411 | #define ENDMARKER { 0xff, 0xff } | 411 | #define ENDMARKER { 0xff, 0xff } |
@@ -481,43 +481,43 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = { | |||
481 | */ | 481 | */ |
482 | static const struct ov772x_color_format ov772x_cfmts[] = { | 482 | static const struct ov772x_color_format ov772x_cfmts[] = { |
483 | { | 483 | { |
484 | SETFOURCC(YUYV), | 484 | .format = &ov772x_fmt_lists[0], |
485 | .dsp3 = 0x0, | 485 | .dsp3 = 0x0, |
486 | .com3 = SWAP_YUV, | 486 | .com3 = SWAP_YUV, |
487 | .com7 = OFMT_YUV, | 487 | .com7 = OFMT_YUV, |
488 | }, | 488 | }, |
489 | { | 489 | { |
490 | SETFOURCC(YVYU), | 490 | .format = &ov772x_fmt_lists[1], |
491 | .dsp3 = UV_ON, | 491 | .dsp3 = UV_ON, |
492 | .com3 = SWAP_YUV, | 492 | .com3 = SWAP_YUV, |
493 | .com7 = OFMT_YUV, | 493 | .com7 = OFMT_YUV, |
494 | }, | 494 | }, |
495 | { | 495 | { |
496 | SETFOURCC(UYVY), | 496 | .format = &ov772x_fmt_lists[2], |
497 | .dsp3 = 0x0, | 497 | .dsp3 = 0x0, |
498 | .com3 = 0x0, | 498 | .com3 = 0x0, |
499 | .com7 = OFMT_YUV, | 499 | .com7 = OFMT_YUV, |
500 | }, | 500 | }, |
501 | { | 501 | { |
502 | SETFOURCC(RGB555), | 502 | .format = &ov772x_fmt_lists[3], |
503 | .dsp3 = 0x0, | 503 | .dsp3 = 0x0, |
504 | .com3 = SWAP_RGB, | 504 | .com3 = SWAP_RGB, |
505 | .com7 = FMT_RGB555 | OFMT_RGB, | 505 | .com7 = FMT_RGB555 | OFMT_RGB, |
506 | }, | 506 | }, |
507 | { | 507 | { |
508 | SETFOURCC(RGB555X), | 508 | .format = &ov772x_fmt_lists[4], |
509 | .dsp3 = 0x0, | 509 | .dsp3 = 0x0, |
510 | .com3 = 0x0, | 510 | .com3 = 0x0, |
511 | .com7 = FMT_RGB555 | OFMT_RGB, | 511 | .com7 = FMT_RGB555 | OFMT_RGB, |
512 | }, | 512 | }, |
513 | { | 513 | { |
514 | SETFOURCC(RGB565), | 514 | .format = &ov772x_fmt_lists[5], |
515 | .dsp3 = 0x0, | 515 | .dsp3 = 0x0, |
516 | .com3 = SWAP_RGB, | 516 | .com3 = SWAP_RGB, |
517 | .com7 = FMT_RGB565 | OFMT_RGB, | 517 | .com7 = FMT_RGB565 | OFMT_RGB, |
518 | }, | 518 | }, |
519 | { | 519 | { |
520 | SETFOURCC(RGB565X), | 520 | .format = &ov772x_fmt_lists[6], |
521 | .dsp3 = 0x0, | 521 | .dsp3 = 0x0, |
522 | .com3 = 0x0, | 522 | .com3 = 0x0, |
523 | .com7 = FMT_RGB565 | OFMT_RGB, | 523 | .com7 = FMT_RGB565 | OFMT_RGB, |
@@ -570,6 +570,15 @@ static const struct v4l2_queryctrl ov772x_controls[] = { | |||
570 | .step = 1, | 570 | .step = 1, |
571 | .default_value = 0, | 571 | .default_value = 0, |
572 | }, | 572 | }, |
573 | { | ||
574 | .id = V4L2_CID_BAND_STOP_FILTER, | ||
575 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
576 | .name = "Band-stop filter", | ||
577 | .minimum = 0, | ||
578 | .maximum = 256, | ||
579 | .step = 1, | ||
580 | .default_value = 0, | ||
581 | }, | ||
573 | }; | 582 | }; |
574 | 583 | ||
575 | 584 | ||
@@ -577,6 +586,12 @@ static const struct v4l2_queryctrl ov772x_controls[] = { | |||
577 | * general function | 586 | * general function |
578 | */ | 587 | */ |
579 | 588 | ||
589 | static struct ov772x_priv *to_ov772x(const struct i2c_client *client) | ||
590 | { | ||
591 | return container_of(i2c_get_clientdata(client), struct ov772x_priv, | ||
592 | subdev); | ||
593 | } | ||
594 | |||
580 | static int ov772x_write_array(struct i2c_client *client, | 595 | static int ov772x_write_array(struct i2c_client *client, |
581 | const struct regval_list *vals) | 596 | const struct regval_list *vals) |
582 | { | 597 | { |
@@ -617,58 +632,29 @@ static int ov772x_reset(struct i2c_client *client) | |||
617 | * soc_camera_ops function | 632 | * soc_camera_ops function |
618 | */ | 633 | */ |
619 | 634 | ||
620 | static int ov772x_init(struct soc_camera_device *icd) | 635 | static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) |
621 | { | 636 | { |
622 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 637 | struct i2c_client *client = sd->priv; |
623 | int ret = 0; | 638 | struct ov772x_priv *priv = to_ov772x(client); |
624 | 639 | ||
625 | if (priv->info->link.power) { | 640 | if (!enable) { |
626 | ret = priv->info->link.power(&priv->client->dev, 1); | 641 | ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); |
627 | if (ret < 0) | 642 | return 0; |
628 | return ret; | ||
629 | } | 643 | } |
630 | 644 | ||
631 | if (priv->info->link.reset) | ||
632 | ret = priv->info->link.reset(&priv->client->dev); | ||
633 | |||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | static int ov772x_release(struct soc_camera_device *icd) | ||
638 | { | ||
639 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
640 | int ret = 0; | ||
641 | |||
642 | if (priv->info->link.power) | ||
643 | ret = priv->info->link.power(&priv->client->dev, 0); | ||
644 | |||
645 | return ret; | ||
646 | } | ||
647 | |||
648 | static int ov772x_start_capture(struct soc_camera_device *icd) | ||
649 | { | ||
650 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
651 | |||
652 | if (!priv->win || !priv->fmt) { | 645 | if (!priv->win || !priv->fmt) { |
653 | dev_err(&icd->dev, "norm or win select error\n"); | 646 | dev_err(&client->dev, "norm or win select error\n"); |
654 | return -EPERM; | 647 | return -EPERM; |
655 | } | 648 | } |
656 | 649 | ||
657 | ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0); | 650 | ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); |
658 | 651 | ||
659 | dev_dbg(&icd->dev, | 652 | dev_dbg(&client->dev, "format %s, win %s\n", |
660 | "format %s, win %s\n", priv->fmt->name, priv->win->name); | 653 | priv->fmt->format->name, priv->win->name); |
661 | 654 | ||
662 | return 0; | 655 | return 0; |
663 | } | 656 | } |
664 | 657 | ||
665 | static int ov772x_stop_capture(struct soc_camera_device *icd) | ||
666 | { | ||
667 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
668 | ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int ov772x_set_bus_param(struct soc_camera_device *icd, | 658 | static int ov772x_set_bus_param(struct soc_camera_device *icd, |
673 | unsigned long flags) | 659 | unsigned long flags) |
674 | { | 660 | { |
@@ -677,8 +663,9 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd, | |||
677 | 663 | ||
678 | static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) | 664 | static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) |
679 | { | 665 | { |
680 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 666 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
681 | struct soc_camera_link *icl = &priv->info->link; | 667 | struct ov772x_priv *priv = i2c_get_clientdata(client); |
668 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
682 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | 669 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | |
683 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | 670 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | |
684 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; | 671 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; |
@@ -686,10 +673,10 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) | |||
686 | return soc_camera_apply_sensor_flags(icl, flags); | 673 | return soc_camera_apply_sensor_flags(icl, flags); |
687 | } | 674 | } |
688 | 675 | ||
689 | static int ov772x_get_control(struct soc_camera_device *icd, | 676 | static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
690 | struct v4l2_control *ctrl) | ||
691 | { | 677 | { |
692 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 678 | struct i2c_client *client = sd->priv; |
679 | struct ov772x_priv *priv = to_ov772x(client); | ||
693 | 680 | ||
694 | switch (ctrl->id) { | 681 | switch (ctrl->id) { |
695 | case V4L2_CID_VFLIP: | 682 | case V4L2_CID_VFLIP: |
@@ -698,14 +685,17 @@ static int ov772x_get_control(struct soc_camera_device *icd, | |||
698 | case V4L2_CID_HFLIP: | 685 | case V4L2_CID_HFLIP: |
699 | ctrl->value = priv->flag_hflip; | 686 | ctrl->value = priv->flag_hflip; |
700 | break; | 687 | break; |
688 | case V4L2_CID_BAND_STOP_FILTER: | ||
689 | ctrl->value = priv->band_filter; | ||
690 | break; | ||
701 | } | 691 | } |
702 | return 0; | 692 | return 0; |
703 | } | 693 | } |
704 | 694 | ||
705 | static int ov772x_set_control(struct soc_camera_device *icd, | 695 | static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
706 | struct v4l2_control *ctrl) | ||
707 | { | 696 | { |
708 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 697 | struct i2c_client *client = sd->priv; |
698 | struct ov772x_priv *priv = to_ov772x(client); | ||
709 | int ret = 0; | 699 | int ret = 0; |
710 | u8 val; | 700 | u8 val; |
711 | 701 | ||
@@ -715,24 +705,48 @@ static int ov772x_set_control(struct soc_camera_device *icd, | |||
715 | priv->flag_vflip = ctrl->value; | 705 | priv->flag_vflip = ctrl->value; |
716 | if (priv->info->flags & OV772X_FLAG_VFLIP) | 706 | if (priv->info->flags & OV772X_FLAG_VFLIP) |
717 | val ^= VFLIP_IMG; | 707 | val ^= VFLIP_IMG; |
718 | ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val); | 708 | ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val); |
719 | break; | 709 | break; |
720 | case V4L2_CID_HFLIP: | 710 | case V4L2_CID_HFLIP: |
721 | val = ctrl->value ? HFLIP_IMG : 0x00; | 711 | val = ctrl->value ? HFLIP_IMG : 0x00; |
722 | priv->flag_hflip = ctrl->value; | 712 | priv->flag_hflip = ctrl->value; |
723 | if (priv->info->flags & OV772X_FLAG_HFLIP) | 713 | if (priv->info->flags & OV772X_FLAG_HFLIP) |
724 | val ^= HFLIP_IMG; | 714 | val ^= HFLIP_IMG; |
725 | ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val); | 715 | ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val); |
716 | break; | ||
717 | case V4L2_CID_BAND_STOP_FILTER: | ||
718 | if ((unsigned)ctrl->value > 256) | ||
719 | ctrl->value = 256; | ||
720 | if (ctrl->value == priv->band_filter) | ||
721 | break; | ||
722 | if (!ctrl->value) { | ||
723 | /* Switch the filter off, it is on now */ | ||
724 | ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); | ||
725 | if (!ret) | ||
726 | ret = ov772x_mask_set(client, COM8, | ||
727 | BNDF_ON_OFF, 0); | ||
728 | } else { | ||
729 | /* Switch the filter on, set AEC low limit */ | ||
730 | val = 256 - ctrl->value; | ||
731 | ret = ov772x_mask_set(client, COM8, | ||
732 | BNDF_ON_OFF, BNDF_ON_OFF); | ||
733 | if (!ret) | ||
734 | ret = ov772x_mask_set(client, BDBASE, | ||
735 | 0xff, val); | ||
736 | } | ||
737 | if (!ret) | ||
738 | priv->band_filter = ctrl->value; | ||
726 | break; | 739 | break; |
727 | } | 740 | } |
728 | 741 | ||
729 | return ret; | 742 | return ret; |
730 | } | 743 | } |
731 | 744 | ||
732 | static int ov772x_get_chip_id(struct soc_camera_device *icd, | 745 | static int ov772x_g_chip_ident(struct v4l2_subdev *sd, |
733 | struct v4l2_dbg_chip_ident *id) | 746 | struct v4l2_dbg_chip_ident *id) |
734 | { | 747 | { |
735 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 748 | struct i2c_client *client = sd->priv; |
749 | struct ov772x_priv *priv = to_ov772x(client); | ||
736 | 750 | ||
737 | id->ident = priv->model; | 751 | id->ident = priv->model; |
738 | id->revision = 0; | 752 | id->revision = 0; |
@@ -741,17 +755,17 @@ static int ov772x_get_chip_id(struct soc_camera_device *icd, | |||
741 | } | 755 | } |
742 | 756 | ||
743 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 757 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
744 | static int ov772x_get_register(struct soc_camera_device *icd, | 758 | static int ov772x_g_register(struct v4l2_subdev *sd, |
745 | struct v4l2_dbg_register *reg) | 759 | struct v4l2_dbg_register *reg) |
746 | { | 760 | { |
747 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 761 | struct i2c_client *client = sd->priv; |
748 | int ret; | 762 | int ret; |
749 | 763 | ||
750 | reg->size = 1; | 764 | reg->size = 1; |
751 | if (reg->reg > 0xff) | 765 | if (reg->reg > 0xff) |
752 | return -EINVAL; | 766 | return -EINVAL; |
753 | 767 | ||
754 | ret = i2c_smbus_read_byte_data(priv->client, reg->reg); | 768 | ret = i2c_smbus_read_byte_data(client, reg->reg); |
755 | if (ret < 0) | 769 | if (ret < 0) |
756 | return ret; | 770 | return ret; |
757 | 771 | ||
@@ -760,21 +774,20 @@ static int ov772x_get_register(struct soc_camera_device *icd, | |||
760 | return 0; | 774 | return 0; |
761 | } | 775 | } |
762 | 776 | ||
763 | static int ov772x_set_register(struct soc_camera_device *icd, | 777 | static int ov772x_s_register(struct v4l2_subdev *sd, |
764 | struct v4l2_dbg_register *reg) | 778 | struct v4l2_dbg_register *reg) |
765 | { | 779 | { |
766 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 780 | struct i2c_client *client = sd->priv; |
767 | 781 | ||
768 | if (reg->reg > 0xff || | 782 | if (reg->reg > 0xff || |
769 | reg->val > 0xff) | 783 | reg->val > 0xff) |
770 | return -EINVAL; | 784 | return -EINVAL; |
771 | 785 | ||
772 | return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val); | 786 | return i2c_smbus_write_byte_data(client, reg->reg, reg->val); |
773 | } | 787 | } |
774 | #endif | 788 | #endif |
775 | 789 | ||
776 | static const struct ov772x_win_size* | 790 | static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) |
777 | ov772x_select_win(u32 width, u32 height) | ||
778 | { | 791 | { |
779 | __u32 diff; | 792 | __u32 diff; |
780 | const struct ov772x_win_size *win; | 793 | const struct ov772x_win_size *win; |
@@ -793,9 +806,10 @@ ov772x_select_win(u32 width, u32 height) | |||
793 | return win; | 806 | return win; |
794 | } | 807 | } |
795 | 808 | ||
796 | static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | 809 | static int ov772x_set_params(struct i2c_client *client, |
797 | u32 pixfmt) | 810 | u32 *width, u32 *height, u32 pixfmt) |
798 | { | 811 | { |
812 | struct ov772x_priv *priv = to_ov772x(client); | ||
799 | int ret = -EINVAL; | 813 | int ret = -EINVAL; |
800 | u8 val; | 814 | u8 val; |
801 | int i; | 815 | int i; |
@@ -805,7 +819,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
805 | */ | 819 | */ |
806 | priv->fmt = NULL; | 820 | priv->fmt = NULL; |
807 | for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { | 821 | for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { |
808 | if (pixfmt == ov772x_cfmts[i].fourcc) { | 822 | if (pixfmt == ov772x_cfmts[i].format->fourcc) { |
809 | priv->fmt = ov772x_cfmts + i; | 823 | priv->fmt = ov772x_cfmts + i; |
810 | break; | 824 | break; |
811 | } | 825 | } |
@@ -816,12 +830,12 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
816 | /* | 830 | /* |
817 | * select win | 831 | * select win |
818 | */ | 832 | */ |
819 | priv->win = ov772x_select_win(width, height); | 833 | priv->win = ov772x_select_win(*width, *height); |
820 | 834 | ||
821 | /* | 835 | /* |
822 | * reset hardware | 836 | * reset hardware |
823 | */ | 837 | */ |
824 | ov772x_reset(priv->client); | 838 | ov772x_reset(client); |
825 | 839 | ||
826 | /* | 840 | /* |
827 | * Edge Ctrl | 841 | * Edge Ctrl |
@@ -835,17 +849,17 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
835 | * Remove it when manual mode. | 849 | * Remove it when manual mode. |
836 | */ | 850 | */ |
837 | 851 | ||
838 | ret = ov772x_mask_set(priv->client, DSPAUTO, EDGE_ACTRL, 0x00); | 852 | ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00); |
839 | if (ret < 0) | 853 | if (ret < 0) |
840 | goto ov772x_set_fmt_error; | 854 | goto ov772x_set_fmt_error; |
841 | 855 | ||
842 | ret = ov772x_mask_set(priv->client, | 856 | ret = ov772x_mask_set(client, |
843 | EDGE_TRSHLD, EDGE_THRESHOLD_MASK, | 857 | EDGE_TRSHLD, EDGE_THRESHOLD_MASK, |
844 | priv->info->edgectrl.threshold); | 858 | priv->info->edgectrl.threshold); |
845 | if (ret < 0) | 859 | if (ret < 0) |
846 | goto ov772x_set_fmt_error; | 860 | goto ov772x_set_fmt_error; |
847 | 861 | ||
848 | ret = ov772x_mask_set(priv->client, | 862 | ret = ov772x_mask_set(client, |
849 | EDGE_STRNGT, EDGE_STRENGTH_MASK, | 863 | EDGE_STRNGT, EDGE_STRENGTH_MASK, |
850 | priv->info->edgectrl.strength); | 864 | priv->info->edgectrl.strength); |
851 | if (ret < 0) | 865 | if (ret < 0) |
@@ -857,13 +871,13 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
857 | * | 871 | * |
858 | * set upper and lower limit | 872 | * set upper and lower limit |
859 | */ | 873 | */ |
860 | ret = ov772x_mask_set(priv->client, | 874 | ret = ov772x_mask_set(client, |
861 | EDGE_UPPER, EDGE_UPPER_MASK, | 875 | EDGE_UPPER, EDGE_UPPER_MASK, |
862 | priv->info->edgectrl.upper); | 876 | priv->info->edgectrl.upper); |
863 | if (ret < 0) | 877 | if (ret < 0) |
864 | goto ov772x_set_fmt_error; | 878 | goto ov772x_set_fmt_error; |
865 | 879 | ||
866 | ret = ov772x_mask_set(priv->client, | 880 | ret = ov772x_mask_set(client, |
867 | EDGE_LOWER, EDGE_LOWER_MASK, | 881 | EDGE_LOWER, EDGE_LOWER_MASK, |
868 | priv->info->edgectrl.lower); | 882 | priv->info->edgectrl.lower); |
869 | if (ret < 0) | 883 | if (ret < 0) |
@@ -873,7 +887,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
873 | /* | 887 | /* |
874 | * set size format | 888 | * set size format |
875 | */ | 889 | */ |
876 | ret = ov772x_write_array(priv->client, priv->win->regs); | 890 | ret = ov772x_write_array(client, priv->win->regs); |
877 | if (ret < 0) | 891 | if (ret < 0) |
878 | goto ov772x_set_fmt_error; | 892 | goto ov772x_set_fmt_error; |
879 | 893 | ||
@@ -882,7 +896,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
882 | */ | 896 | */ |
883 | val = priv->fmt->dsp3; | 897 | val = priv->fmt->dsp3; |
884 | if (val) { | 898 | if (val) { |
885 | ret = ov772x_mask_set(priv->client, | 899 | ret = ov772x_mask_set(client, |
886 | DSP_CTRL3, UV_MASK, val); | 900 | DSP_CTRL3, UV_MASK, val); |
887 | if (ret < 0) | 901 | if (ret < 0) |
888 | goto ov772x_set_fmt_error; | 902 | goto ov772x_set_fmt_error; |
@@ -901,7 +915,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
901 | if (priv->flag_hflip) | 915 | if (priv->flag_hflip) |
902 | val ^= HFLIP_IMG; | 916 | val ^= HFLIP_IMG; |
903 | 917 | ||
904 | ret = ov772x_mask_set(priv->client, | 918 | ret = ov772x_mask_set(client, |
905 | COM3, SWAP_MASK | IMG_MASK, val); | 919 | COM3, SWAP_MASK | IMG_MASK, val); |
906 | if (ret < 0) | 920 | if (ret < 0) |
907 | goto ov772x_set_fmt_error; | 921 | goto ov772x_set_fmt_error; |
@@ -910,47 +924,99 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
910 | * set COM7 | 924 | * set COM7 |
911 | */ | 925 | */ |
912 | val = priv->win->com7_bit | priv->fmt->com7; | 926 | val = priv->win->com7_bit | priv->fmt->com7; |
913 | ret = ov772x_mask_set(priv->client, | 927 | ret = ov772x_mask_set(client, |
914 | COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK), | 928 | COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK), |
915 | val); | 929 | val); |
916 | if (ret < 0) | 930 | if (ret < 0) |
917 | goto ov772x_set_fmt_error; | 931 | goto ov772x_set_fmt_error; |
918 | 932 | ||
933 | /* | ||
934 | * set COM8 | ||
935 | */ | ||
936 | if (priv->band_filter) { | ||
937 | ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); | ||
938 | if (!ret) | ||
939 | ret = ov772x_mask_set(client, BDBASE, | ||
940 | 0xff, 256 - priv->band_filter); | ||
941 | if (ret < 0) | ||
942 | goto ov772x_set_fmt_error; | ||
943 | } | ||
944 | |||
945 | *width = priv->win->width; | ||
946 | *height = priv->win->height; | ||
947 | |||
919 | return ret; | 948 | return ret; |
920 | 949 | ||
921 | ov772x_set_fmt_error: | 950 | ov772x_set_fmt_error: |
922 | 951 | ||
923 | ov772x_reset(priv->client); | 952 | ov772x_reset(client); |
924 | priv->win = NULL; | 953 | priv->win = NULL; |
925 | priv->fmt = NULL; | 954 | priv->fmt = NULL; |
926 | 955 | ||
927 | return ret; | 956 | return ret; |
928 | } | 957 | } |
929 | 958 | ||
930 | static int ov772x_set_crop(struct soc_camera_device *icd, | 959 | static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
931 | struct v4l2_rect *rect) | ||
932 | { | 960 | { |
933 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 961 | a->c.left = 0; |
962 | a->c.top = 0; | ||
963 | a->c.width = VGA_WIDTH; | ||
964 | a->c.height = VGA_HEIGHT; | ||
965 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
934 | 966 | ||
935 | if (!priv->fmt) | 967 | return 0; |
936 | return -EINVAL; | 968 | } |
937 | 969 | ||
938 | return ov772x_set_params(priv, rect->width, rect->height, | 970 | static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
939 | priv->fmt->fourcc); | 971 | { |
972 | a->bounds.left = 0; | ||
973 | a->bounds.top = 0; | ||
974 | a->bounds.width = VGA_WIDTH; | ||
975 | a->bounds.height = VGA_HEIGHT; | ||
976 | a->defrect = a->bounds; | ||
977 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
978 | a->pixelaspect.numerator = 1; | ||
979 | a->pixelaspect.denominator = 1; | ||
980 | |||
981 | return 0; | ||
940 | } | 982 | } |
941 | 983 | ||
942 | static int ov772x_set_fmt(struct soc_camera_device *icd, | 984 | static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
943 | struct v4l2_format *f) | 985 | { |
986 | struct i2c_client *client = sd->priv; | ||
987 | struct ov772x_priv *priv = to_ov772x(client); | ||
988 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
989 | |||
990 | if (!priv->win || !priv->fmt) { | ||
991 | u32 width = VGA_WIDTH, height = VGA_HEIGHT; | ||
992 | int ret = ov772x_set_params(client, &width, &height, | ||
993 | V4L2_PIX_FMT_YUYV); | ||
994 | if (ret < 0) | ||
995 | return ret; | ||
996 | } | ||
997 | |||
998 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
999 | |||
1000 | pix->width = priv->win->width; | ||
1001 | pix->height = priv->win->height; | ||
1002 | pix->pixelformat = priv->fmt->format->fourcc; | ||
1003 | pix->colorspace = priv->fmt->format->colorspace; | ||
1004 | pix->field = V4L2_FIELD_NONE; | ||
1005 | |||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
944 | { | 1010 | { |
945 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 1011 | struct i2c_client *client = sd->priv; |
946 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1012 | struct v4l2_pix_format *pix = &f->fmt.pix; |
947 | 1013 | ||
948 | return ov772x_set_params(priv, pix->width, pix->height, | 1014 | return ov772x_set_params(client, &pix->width, &pix->height, |
949 | pix->pixelformat); | 1015 | pix->pixelformat); |
950 | } | 1016 | } |
951 | 1017 | ||
952 | static int ov772x_try_fmt(struct soc_camera_device *icd, | 1018 | static int ov772x_try_fmt(struct v4l2_subdev *sd, |
953 | struct v4l2_format *f) | 1019 | struct v4l2_format *f) |
954 | { | 1020 | { |
955 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1021 | struct v4l2_pix_format *pix = &f->fmt.pix; |
956 | const struct ov772x_win_size *win; | 1022 | const struct ov772x_win_size *win; |
@@ -967,9 +1033,10 @@ static int ov772x_try_fmt(struct soc_camera_device *icd, | |||
967 | return 0; | 1033 | return 0; |
968 | } | 1034 | } |
969 | 1035 | ||
970 | static int ov772x_video_probe(struct soc_camera_device *icd) | 1036 | static int ov772x_video_probe(struct soc_camera_device *icd, |
1037 | struct i2c_client *client) | ||
971 | { | 1038 | { |
972 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 1039 | struct ov772x_priv *priv = to_ov772x(client); |
973 | u8 pid, ver; | 1040 | u8 pid, ver; |
974 | const char *devname; | 1041 | const char *devname; |
975 | 1042 | ||
@@ -986,7 +1053,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd) | |||
986 | */ | 1053 | */ |
987 | if (SOCAM_DATAWIDTH_10 != priv->info->buswidth && | 1054 | if (SOCAM_DATAWIDTH_10 != priv->info->buswidth && |
988 | SOCAM_DATAWIDTH_8 != priv->info->buswidth) { | 1055 | SOCAM_DATAWIDTH_8 != priv->info->buswidth) { |
989 | dev_err(&icd->dev, "bus width error\n"); | 1056 | dev_err(&client->dev, "bus width error\n"); |
990 | return -ENODEV; | 1057 | return -ENODEV; |
991 | } | 1058 | } |
992 | 1059 | ||
@@ -996,8 +1063,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd) | |||
996 | /* | 1063 | /* |
997 | * check and show product ID and manufacturer ID | 1064 | * check and show product ID and manufacturer ID |
998 | */ | 1065 | */ |
999 | pid = i2c_smbus_read_byte_data(priv->client, PID); | 1066 | pid = i2c_smbus_read_byte_data(client, PID); |
1000 | ver = i2c_smbus_read_byte_data(priv->client, VER); | 1067 | ver = i2c_smbus_read_byte_data(client, VER); |
1001 | 1068 | ||
1002 | switch (VERSION(pid, ver)) { | 1069 | switch (VERSION(pid, ver)) { |
1003 | case OV7720: | 1070 | case OV7720: |
@@ -1009,69 +1076,77 @@ static int ov772x_video_probe(struct soc_camera_device *icd) | |||
1009 | priv->model = V4L2_IDENT_OV7725; | 1076 | priv->model = V4L2_IDENT_OV7725; |
1010 | break; | 1077 | break; |
1011 | default: | 1078 | default: |
1012 | dev_err(&icd->dev, | 1079 | dev_err(&client->dev, |
1013 | "Product ID error %x:%x\n", pid, ver); | 1080 | "Product ID error %x:%x\n", pid, ver); |
1014 | return -ENODEV; | 1081 | return -ENODEV; |
1015 | } | 1082 | } |
1016 | 1083 | ||
1017 | dev_info(&icd->dev, | 1084 | dev_info(&client->dev, |
1018 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", | 1085 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
1019 | devname, | 1086 | devname, |
1020 | pid, | 1087 | pid, |
1021 | ver, | 1088 | ver, |
1022 | i2c_smbus_read_byte_data(priv->client, MIDH), | 1089 | i2c_smbus_read_byte_data(client, MIDH), |
1023 | i2c_smbus_read_byte_data(priv->client, MIDL)); | 1090 | i2c_smbus_read_byte_data(client, MIDL)); |
1024 | |||
1025 | return soc_camera_video_start(icd); | ||
1026 | } | ||
1027 | 1091 | ||
1028 | static void ov772x_video_remove(struct soc_camera_device *icd) | 1092 | return 0; |
1029 | { | ||
1030 | soc_camera_video_stop(icd); | ||
1031 | } | 1093 | } |
1032 | 1094 | ||
1033 | static struct soc_camera_ops ov772x_ops = { | 1095 | static struct soc_camera_ops ov772x_ops = { |
1034 | .owner = THIS_MODULE, | ||
1035 | .probe = ov772x_video_probe, | ||
1036 | .remove = ov772x_video_remove, | ||
1037 | .init = ov772x_init, | ||
1038 | .release = ov772x_release, | ||
1039 | .start_capture = ov772x_start_capture, | ||
1040 | .stop_capture = ov772x_stop_capture, | ||
1041 | .set_crop = ov772x_set_crop, | ||
1042 | .set_fmt = ov772x_set_fmt, | ||
1043 | .try_fmt = ov772x_try_fmt, | ||
1044 | .set_bus_param = ov772x_set_bus_param, | 1096 | .set_bus_param = ov772x_set_bus_param, |
1045 | .query_bus_param = ov772x_query_bus_param, | 1097 | .query_bus_param = ov772x_query_bus_param, |
1046 | .controls = ov772x_controls, | 1098 | .controls = ov772x_controls, |
1047 | .num_controls = ARRAY_SIZE(ov772x_controls), | 1099 | .num_controls = ARRAY_SIZE(ov772x_controls), |
1048 | .get_control = ov772x_get_control, | 1100 | }; |
1049 | .set_control = ov772x_set_control, | 1101 | |
1050 | .get_chip_id = ov772x_get_chip_id, | 1102 | static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { |
1103 | .g_ctrl = ov772x_g_ctrl, | ||
1104 | .s_ctrl = ov772x_s_ctrl, | ||
1105 | .g_chip_ident = ov772x_g_chip_ident, | ||
1051 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1106 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1052 | .get_register = ov772x_get_register, | 1107 | .g_register = ov772x_g_register, |
1053 | .set_register = ov772x_set_register, | 1108 | .s_register = ov772x_s_register, |
1054 | #endif | 1109 | #endif |
1055 | }; | 1110 | }; |
1056 | 1111 | ||
1112 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | ||
1113 | .s_stream = ov772x_s_stream, | ||
1114 | .g_fmt = ov772x_g_fmt, | ||
1115 | .s_fmt = ov772x_s_fmt, | ||
1116 | .try_fmt = ov772x_try_fmt, | ||
1117 | .cropcap = ov772x_cropcap, | ||
1118 | .g_crop = ov772x_g_crop, | ||
1119 | }; | ||
1120 | |||
1121 | static struct v4l2_subdev_ops ov772x_subdev_ops = { | ||
1122 | .core = &ov772x_subdev_core_ops, | ||
1123 | .video = &ov772x_subdev_video_ops, | ||
1124 | }; | ||
1125 | |||
1057 | /* | 1126 | /* |
1058 | * i2c_driver function | 1127 | * i2c_driver function |
1059 | */ | 1128 | */ |
1060 | 1129 | ||
1061 | static int ov772x_probe(struct i2c_client *client, | 1130 | static int ov772x_probe(struct i2c_client *client, |
1062 | const struct i2c_device_id *did) | 1131 | const struct i2c_device_id *did) |
1063 | { | 1132 | { |
1064 | struct ov772x_priv *priv; | 1133 | struct ov772x_priv *priv; |
1065 | struct ov772x_camera_info *info; | 1134 | struct ov772x_camera_info *info; |
1066 | struct soc_camera_device *icd; | 1135 | struct soc_camera_device *icd = client->dev.platform_data; |
1067 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1136 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1137 | struct soc_camera_link *icl; | ||
1068 | int ret; | 1138 | int ret; |
1069 | 1139 | ||
1070 | if (!client->dev.platform_data) | 1140 | if (!icd) { |
1141 | dev_err(&client->dev, "OV772X: missing soc-camera data!\n"); | ||
1071 | return -EINVAL; | 1142 | return -EINVAL; |
1143 | } | ||
1072 | 1144 | ||
1073 | info = container_of(client->dev.platform_data, | 1145 | icl = to_soc_camera_link(icd); |
1074 | struct ov772x_camera_info, link); | 1146 | if (!icl) |
1147 | return -EINVAL; | ||
1148 | |||
1149 | info = container_of(icl, struct ov772x_camera_info, link); | ||
1075 | 1150 | ||
1076 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 1151 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
1077 | dev_err(&adapter->dev, | 1152 | dev_err(&adapter->dev, |
@@ -1084,20 +1159,15 @@ static int ov772x_probe(struct i2c_client *client, | |||
1084 | if (!priv) | 1159 | if (!priv) |
1085 | return -ENOMEM; | 1160 | return -ENOMEM; |
1086 | 1161 | ||
1087 | priv->info = info; | 1162 | priv->info = info; |
1088 | priv->client = client; | ||
1089 | i2c_set_clientdata(client, priv); | ||
1090 | 1163 | ||
1091 | icd = &priv->icd; | 1164 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); |
1092 | icd->ops = &ov772x_ops; | ||
1093 | icd->control = &client->dev; | ||
1094 | icd->width_max = MAX_WIDTH; | ||
1095 | icd->height_max = MAX_HEIGHT; | ||
1096 | icd->iface = priv->info->link.bus_id; | ||
1097 | 1165 | ||
1098 | ret = soc_camera_device_register(icd); | 1166 | icd->ops = &ov772x_ops; |
1099 | 1167 | ||
1168 | ret = ov772x_video_probe(icd, client); | ||
1100 | if (ret) { | 1169 | if (ret) { |
1170 | icd->ops = NULL; | ||
1101 | i2c_set_clientdata(client, NULL); | 1171 | i2c_set_clientdata(client, NULL); |
1102 | kfree(priv); | 1172 | kfree(priv); |
1103 | } | 1173 | } |
@@ -1107,9 +1177,10 @@ static int ov772x_probe(struct i2c_client *client, | |||
1107 | 1177 | ||
1108 | static int ov772x_remove(struct i2c_client *client) | 1178 | static int ov772x_remove(struct i2c_client *client) |
1109 | { | 1179 | { |
1110 | struct ov772x_priv *priv = i2c_get_clientdata(client); | 1180 | struct ov772x_priv *priv = to_ov772x(client); |
1181 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1111 | 1182 | ||
1112 | soc_camera_device_unregister(&priv->icd); | 1183 | icd->ops = NULL; |
1113 | i2c_set_clientdata(client, NULL); | 1184 | i2c_set_clientdata(client, NULL); |
1114 | kfree(priv); | 1185 | kfree(priv); |
1115 | return 0; | 1186 | return 0; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 336a20eded0f..e4d7c13cab87 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c | |||
@@ -298,6 +298,7 @@ static struct tda829x_config tda829x_no_probe = { | |||
298 | 298 | ||
299 | static struct tda18271_config hauppauge_tda18271_dvb_config = { | 299 | static struct tda18271_config hauppauge_tda18271_dvb_config = { |
300 | .gate = TDA18271_GATE_ANALOG, | 300 | .gate = TDA18271_GATE_ANALOG, |
301 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
301 | }; | 302 | }; |
302 | 303 | ||
303 | static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) | 304 | static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) |
@@ -393,6 +394,7 @@ static struct tda18271_std_map hauppauge_tda18271_std_map = { | |||
393 | static struct tda18271_config hauppauge_tda18271_config = { | 394 | static struct tda18271_config hauppauge_tda18271_config = { |
394 | .std_map = &hauppauge_tda18271_std_map, | 395 | .std_map = &hauppauge_tda18271_std_map, |
395 | .gate = TDA18271_GATE_ANALOG, | 396 | .gate = TDA18271_GATE_ANALOG, |
397 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
396 | }; | 398 | }; |
397 | 399 | ||
398 | static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) | 400 | static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index cbc388729d77..13639b302700 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c | |||
@@ -2063,8 +2063,8 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, | |||
2063 | return -EINVAL; | 2063 | return -EINVAL; |
2064 | } | 2064 | } |
2065 | 2065 | ||
2066 | /* Note how the 2nd and 3rd arguments are the same for both | 2066 | /* Note how the 2nd and 3rd arguments are the same for |
2067 | * v4l2_i2c_new_subdev() and v4l2_i2c_new_probed_subdev(). Why? | 2067 | * v4l2_i2c_new_subdev(). Why? |
2068 | * Well the 2nd argument is the module name to load, while the 3rd | 2068 | * Well the 2nd argument is the module name to load, while the 3rd |
2069 | * argument is documented in the framework as being the "chipid" - | 2069 | * argument is documented in the framework as being the "chipid" - |
2070 | * and every other place where I can find examples of this, the | 2070 | * and every other place where I can find examples of this, the |
@@ -2077,15 +2077,15 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, | |||
2077 | mid, i2caddr[0]); | 2077 | mid, i2caddr[0]); |
2078 | sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, | 2078 | sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, |
2079 | fname, fname, | 2079 | fname, fname, |
2080 | i2caddr[0]); | 2080 | i2caddr[0], NULL); |
2081 | } else { | 2081 | } else { |
2082 | pvr2_trace(PVR2_TRACE_INIT, | 2082 | pvr2_trace(PVR2_TRACE_INIT, |
2083 | "Module ID %u:" | 2083 | "Module ID %u:" |
2084 | " Setting up with address probe list", | 2084 | " Setting up with address probe list", |
2085 | mid); | 2085 | mid); |
2086 | sd = v4l2_i2c_new_probed_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, | 2086 | sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, |
2087 | fname, fname, | 2087 | fname, fname, |
2088 | i2caddr); | 2088 | 0, i2caddr); |
2089 | } | 2089 | } |
2090 | 2090 | ||
2091 | if (!sd) { | 2091 | if (!sd) { |
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 016bb45ba0c3..6952e9602d5d 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -225,6 +225,10 @@ struct pxa_camera_dev { | |||
225 | u32 save_cicr[5]; | 225 | u32 save_cicr[5]; |
226 | }; | 226 | }; |
227 | 227 | ||
228 | struct pxa_cam { | ||
229 | unsigned long flags; | ||
230 | }; | ||
231 | |||
228 | static const char *pxa_cam_driver_description = "PXA_Camera"; | 232 | static const char *pxa_cam_driver_description = "PXA_Camera"; |
229 | 233 | ||
230 | static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ | 234 | static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ |
@@ -237,9 +241,9 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
237 | { | 241 | { |
238 | struct soc_camera_device *icd = vq->priv_data; | 242 | struct soc_camera_device *icd = vq->priv_data; |
239 | 243 | ||
240 | dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); | 244 | dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); |
241 | 245 | ||
242 | *size = roundup(icd->width * icd->height * | 246 | *size = roundup(icd->user_width * icd->user_height * |
243 | ((icd->current_fmt->depth + 7) >> 3), 8); | 247 | ((icd->current_fmt->depth + 7) >> 3), 8); |
244 | 248 | ||
245 | if (0 == *count) | 249 | if (0 == *count) |
@@ -259,7 +263,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) | |||
259 | 263 | ||
260 | BUG_ON(in_interrupt()); | 264 | BUG_ON(in_interrupt()); |
261 | 265 | ||
262 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 266 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
263 | &buf->vb, buf->vb.baddr, buf->vb.bsize); | 267 | &buf->vb, buf->vb.baddr, buf->vb.bsize); |
264 | 268 | ||
265 | /* This waits until this buffer is out of danger, i.e., until it is no | 269 | /* This waits until this buffer is out of danger, i.e., until it is no |
@@ -270,7 +274,8 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) | |||
270 | 274 | ||
271 | for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { | 275 | for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { |
272 | if (buf->dmas[i].sg_cpu) | 276 | if (buf->dmas[i].sg_cpu) |
273 | dma_free_coherent(ici->dev, buf->dmas[i].sg_size, | 277 | dma_free_coherent(ici->v4l2_dev.dev, |
278 | buf->dmas[i].sg_size, | ||
274 | buf->dmas[i].sg_cpu, | 279 | buf->dmas[i].sg_cpu, |
275 | buf->dmas[i].sg_dma); | 280 | buf->dmas[i].sg_dma); |
276 | buf->dmas[i].sg_cpu = NULL; | 281 | buf->dmas[i].sg_cpu = NULL; |
@@ -325,19 +330,20 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | |||
325 | struct scatterlist **sg_first, int *sg_first_ofs) | 330 | struct scatterlist **sg_first, int *sg_first_ofs) |
326 | { | 331 | { |
327 | struct pxa_cam_dma *pxa_dma = &buf->dmas[channel]; | 332 | struct pxa_cam_dma *pxa_dma = &buf->dmas[channel]; |
333 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
328 | struct scatterlist *sg; | 334 | struct scatterlist *sg; |
329 | int i, offset, sglen; | 335 | int i, offset, sglen; |
330 | int dma_len = 0, xfer_len = 0; | 336 | int dma_len = 0, xfer_len = 0; |
331 | 337 | ||
332 | if (pxa_dma->sg_cpu) | 338 | if (pxa_dma->sg_cpu) |
333 | dma_free_coherent(pcdev->soc_host.dev, pxa_dma->sg_size, | 339 | dma_free_coherent(dev, pxa_dma->sg_size, |
334 | pxa_dma->sg_cpu, pxa_dma->sg_dma); | 340 | pxa_dma->sg_cpu, pxa_dma->sg_dma); |
335 | 341 | ||
336 | sglen = calculate_dma_sglen(*sg_first, dma->sglen, | 342 | sglen = calculate_dma_sglen(*sg_first, dma->sglen, |
337 | *sg_first_ofs, size); | 343 | *sg_first_ofs, size); |
338 | 344 | ||
339 | pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); | 345 | pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); |
340 | pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->soc_host.dev, pxa_dma->sg_size, | 346 | pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size, |
341 | &pxa_dma->sg_dma, GFP_KERNEL); | 347 | &pxa_dma->sg_dma, GFP_KERNEL); |
342 | if (!pxa_dma->sg_cpu) | 348 | if (!pxa_dma->sg_cpu) |
343 | return -ENOMEM; | 349 | return -ENOMEM; |
@@ -345,7 +351,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | |||
345 | pxa_dma->sglen = sglen; | 351 | pxa_dma->sglen = sglen; |
346 | offset = *sg_first_ofs; | 352 | offset = *sg_first_ofs; |
347 | 353 | ||
348 | dev_dbg(pcdev->soc_host.dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", | 354 | dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", |
349 | *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma); | 355 | *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma); |
350 | 356 | ||
351 | 357 | ||
@@ -368,7 +374,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | |||
368 | pxa_dma->sg_cpu[i].ddadr = | 374 | pxa_dma->sg_cpu[i].ddadr = |
369 | pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); | 375 | pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); |
370 | 376 | ||
371 | dev_vdbg(pcdev->soc_host.dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", | 377 | dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", |
372 | pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc), | 378 | pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc), |
373 | sg_dma_address(sg) + offset, xfer_len); | 379 | sg_dma_address(sg) + offset, xfer_len); |
374 | offset = 0; | 380 | offset = 0; |
@@ -418,11 +424,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
418 | struct soc_camera_device *icd = vq->priv_data; | 424 | struct soc_camera_device *icd = vq->priv_data; |
419 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 425 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
420 | struct pxa_camera_dev *pcdev = ici->priv; | 426 | struct pxa_camera_dev *pcdev = ici->priv; |
427 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
421 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 428 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
422 | int ret; | 429 | int ret; |
423 | int size_y, size_u = 0, size_v = 0; | 430 | int size_y, size_u = 0, size_v = 0; |
424 | 431 | ||
425 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 432 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
426 | vb, vb->baddr, vb->bsize); | 433 | vb, vb->baddr, vb->bsize); |
427 | 434 | ||
428 | /* Added list head initialization on alloc */ | 435 | /* Added list head initialization on alloc */ |
@@ -441,12 +448,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
441 | buf->inwork = 1; | 448 | buf->inwork = 1; |
442 | 449 | ||
443 | if (buf->fmt != icd->current_fmt || | 450 | if (buf->fmt != icd->current_fmt || |
444 | vb->width != icd->width || | 451 | vb->width != icd->user_width || |
445 | vb->height != icd->height || | 452 | vb->height != icd->user_height || |
446 | vb->field != field) { | 453 | vb->field != field) { |
447 | buf->fmt = icd->current_fmt; | 454 | buf->fmt = icd->current_fmt; |
448 | vb->width = icd->width; | 455 | vb->width = icd->user_width; |
449 | vb->height = icd->height; | 456 | vb->height = icd->user_height; |
450 | vb->field = field; | 457 | vb->field = field; |
451 | vb->state = VIDEOBUF_NEEDS_INIT; | 458 | vb->state = VIDEOBUF_NEEDS_INIT; |
452 | } | 459 | } |
@@ -480,8 +487,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
480 | ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y, | 487 | ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y, |
481 | &sg, &next_ofs); | 488 | &sg, &next_ofs); |
482 | if (ret) { | 489 | if (ret) { |
483 | dev_err(pcdev->soc_host.dev, | 490 | dev_err(dev, "DMA initialization for Y/RGB failed\n"); |
484 | "DMA initialization for Y/RGB failed\n"); | ||
485 | goto fail; | 491 | goto fail; |
486 | } | 492 | } |
487 | 493 | ||
@@ -490,8 +496,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
490 | ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1, | 496 | ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1, |
491 | size_u, &sg, &next_ofs); | 497 | size_u, &sg, &next_ofs); |
492 | if (ret) { | 498 | if (ret) { |
493 | dev_err(pcdev->soc_host.dev, | 499 | dev_err(dev, "DMA initialization for U failed\n"); |
494 | "DMA initialization for U failed\n"); | ||
495 | goto fail_u; | 500 | goto fail_u; |
496 | } | 501 | } |
497 | 502 | ||
@@ -500,8 +505,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
500 | ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2, | 505 | ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2, |
501 | size_v, &sg, &next_ofs); | 506 | size_v, &sg, &next_ofs); |
502 | if (ret) { | 507 | if (ret) { |
503 | dev_err(pcdev->soc_host.dev, | 508 | dev_err(dev, "DMA initialization for V failed\n"); |
504 | "DMA initialization for V failed\n"); | ||
505 | goto fail_v; | 509 | goto fail_v; |
506 | } | 510 | } |
507 | 511 | ||
@@ -514,10 +518,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
514 | return 0; | 518 | return 0; |
515 | 519 | ||
516 | fail_v: | 520 | fail_v: |
517 | dma_free_coherent(pcdev->soc_host.dev, buf->dmas[1].sg_size, | 521 | dma_free_coherent(dev, buf->dmas[1].sg_size, |
518 | buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); | 522 | buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); |
519 | fail_u: | 523 | fail_u: |
520 | dma_free_coherent(pcdev->soc_host.dev, buf->dmas[0].sg_size, | 524 | dma_free_coherent(dev, buf->dmas[0].sg_size, |
521 | buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); | 525 | buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); |
522 | fail: | 526 | fail: |
523 | free_buffer(vq, buf); | 527 | free_buffer(vq, buf); |
@@ -541,7 +545,8 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) | |||
541 | active = pcdev->active; | 545 | active = pcdev->active; |
542 | 546 | ||
543 | for (i = 0; i < pcdev->channels; i++) { | 547 | for (i = 0; i < pcdev->channels; i++) { |
544 | dev_dbg(pcdev->soc_host.dev, "%s (channel=%d) ddadr=%08x\n", __func__, | 548 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, |
549 | "%s (channel=%d) ddadr=%08x\n", __func__, | ||
545 | i, active->dmas[i].sg_dma); | 550 | i, active->dmas[i].sg_dma); |
546 | DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; | 551 | DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; |
547 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | 552 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; |
@@ -553,7 +558,8 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) | |||
553 | int i; | 558 | int i; |
554 | 559 | ||
555 | for (i = 0; i < pcdev->channels; i++) { | 560 | for (i = 0; i < pcdev->channels; i++) { |
556 | dev_dbg(pcdev->soc_host.dev, "%s (channel=%d)\n", __func__, i); | 561 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, |
562 | "%s (channel=%d)\n", __func__, i); | ||
557 | DCSR(pcdev->dma_chans[i]) = 0; | 563 | DCSR(pcdev->dma_chans[i]) = 0; |
558 | } | 564 | } |
559 | } | 565 | } |
@@ -589,7 +595,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) | |||
589 | { | 595 | { |
590 | unsigned long cicr0, cifr; | 596 | unsigned long cicr0, cifr; |
591 | 597 | ||
592 | dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); | 598 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); |
593 | /* Reset the FIFOs */ | 599 | /* Reset the FIFOs */ |
594 | cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; | 600 | cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; |
595 | __raw_writel(cifr, pcdev->base + CIFR); | 601 | __raw_writel(cifr, pcdev->base + CIFR); |
@@ -609,7 +615,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) | |||
609 | __raw_writel(cicr0, pcdev->base + CICR0); | 615 | __raw_writel(cicr0, pcdev->base + CICR0); |
610 | 616 | ||
611 | pcdev->active = NULL; | 617 | pcdev->active = NULL; |
612 | dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); | 618 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); |
613 | } | 619 | } |
614 | 620 | ||
615 | /* Called under spinlock_irqsave(&pcdev->lock, ...) */ | 621 | /* Called under spinlock_irqsave(&pcdev->lock, ...) */ |
@@ -621,8 +627,8 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
621 | struct pxa_camera_dev *pcdev = ici->priv; | 627 | struct pxa_camera_dev *pcdev = ici->priv; |
622 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 628 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
623 | 629 | ||
624 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__, | 630 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n", |
625 | vb, vb->baddr, vb->bsize, pcdev->active); | 631 | __func__, vb, vb->baddr, vb->bsize, pcdev->active); |
626 | 632 | ||
627 | list_add_tail(&vb->queue, &pcdev->capture); | 633 | list_add_tail(&vb->queue, &pcdev->capture); |
628 | 634 | ||
@@ -639,22 +645,23 @@ static void pxa_videobuf_release(struct videobuf_queue *vq, | |||
639 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 645 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
640 | #ifdef DEBUG | 646 | #ifdef DEBUG |
641 | struct soc_camera_device *icd = vq->priv_data; | 647 | struct soc_camera_device *icd = vq->priv_data; |
648 | struct device *dev = icd->dev.parent; | ||
642 | 649 | ||
643 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 650 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
644 | vb, vb->baddr, vb->bsize); | 651 | vb, vb->baddr, vb->bsize); |
645 | 652 | ||
646 | switch (vb->state) { | 653 | switch (vb->state) { |
647 | case VIDEOBUF_ACTIVE: | 654 | case VIDEOBUF_ACTIVE: |
648 | dev_dbg(&icd->dev, "%s (active)\n", __func__); | 655 | dev_dbg(dev, "%s (active)\n", __func__); |
649 | break; | 656 | break; |
650 | case VIDEOBUF_QUEUED: | 657 | case VIDEOBUF_QUEUED: |
651 | dev_dbg(&icd->dev, "%s (queued)\n", __func__); | 658 | dev_dbg(dev, "%s (queued)\n", __func__); |
652 | break; | 659 | break; |
653 | case VIDEOBUF_PREPARED: | 660 | case VIDEOBUF_PREPARED: |
654 | dev_dbg(&icd->dev, "%s (prepared)\n", __func__); | 661 | dev_dbg(dev, "%s (prepared)\n", __func__); |
655 | break; | 662 | break; |
656 | default: | 663 | default: |
657 | dev_dbg(&icd->dev, "%s (unknown)\n", __func__); | 664 | dev_dbg(dev, "%s (unknown)\n", __func__); |
658 | break; | 665 | break; |
659 | } | 666 | } |
660 | #endif | 667 | #endif |
@@ -674,7 +681,8 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, | |||
674 | do_gettimeofday(&vb->ts); | 681 | do_gettimeofday(&vb->ts); |
675 | vb->field_count++; | 682 | vb->field_count++; |
676 | wake_up(&vb->done); | 683 | wake_up(&vb->done); |
677 | dev_dbg(pcdev->soc_host.dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb); | 684 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n", |
685 | __func__, vb); | ||
678 | 686 | ||
679 | if (list_empty(&pcdev->capture)) { | 687 | if (list_empty(&pcdev->capture)) { |
680 | pxa_camera_stop_capture(pcdev); | 688 | pxa_camera_stop_capture(pcdev); |
@@ -710,7 +718,8 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev) | |||
710 | for (i = 0; i < pcdev->channels; i++) | 718 | for (i = 0; i < pcdev->channels; i++) |
711 | if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP) | 719 | if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP) |
712 | is_dma_stopped = 0; | 720 | is_dma_stopped = 0; |
713 | dev_dbg(pcdev->soc_host.dev, "%s : top queued buffer=%p, dma_stopped=%d\n", | 721 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, |
722 | "%s : top queued buffer=%p, dma_stopped=%d\n", | ||
714 | __func__, pcdev->active, is_dma_stopped); | 723 | __func__, pcdev->active, is_dma_stopped); |
715 | if (pcdev->active && is_dma_stopped) | 724 | if (pcdev->active && is_dma_stopped) |
716 | pxa_camera_start_capture(pcdev); | 725 | pxa_camera_start_capture(pcdev); |
@@ -719,6 +728,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev) | |||
719 | static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | 728 | static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, |
720 | enum pxa_camera_active_dma act_dma) | 729 | enum pxa_camera_active_dma act_dma) |
721 | { | 730 | { |
731 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
722 | struct pxa_buffer *buf; | 732 | struct pxa_buffer *buf; |
723 | unsigned long flags; | 733 | unsigned long flags; |
724 | u32 status, camera_status, overrun; | 734 | u32 status, camera_status, overrun; |
@@ -735,13 +745,13 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | |||
735 | overrun |= CISR_IFO_1 | CISR_IFO_2; | 745 | overrun |= CISR_IFO_1 | CISR_IFO_2; |
736 | 746 | ||
737 | if (status & DCSR_BUSERR) { | 747 | if (status & DCSR_BUSERR) { |
738 | dev_err(pcdev->soc_host.dev, "DMA Bus Error IRQ!\n"); | 748 | dev_err(dev, "DMA Bus Error IRQ!\n"); |
739 | goto out; | 749 | goto out; |
740 | } | 750 | } |
741 | 751 | ||
742 | if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { | 752 | if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { |
743 | dev_err(pcdev->soc_host.dev, "Unknown DMA IRQ source, " | 753 | dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n", |
744 | "status: 0x%08x\n", status); | 754 | status); |
745 | goto out; | 755 | goto out; |
746 | } | 756 | } |
747 | 757 | ||
@@ -764,7 +774,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | |||
764 | buf = container_of(vb, struct pxa_buffer, vb); | 774 | buf = container_of(vb, struct pxa_buffer, vb); |
765 | WARN_ON(buf->inwork || list_empty(&vb->queue)); | 775 | WARN_ON(buf->inwork || list_empty(&vb->queue)); |
766 | 776 | ||
767 | dev_dbg(pcdev->soc_host.dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", | 777 | dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", |
768 | __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", | 778 | __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", |
769 | status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); | 779 | status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); |
770 | 780 | ||
@@ -775,7 +785,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | |||
775 | */ | 785 | */ |
776 | if (camera_status & overrun && | 786 | if (camera_status & overrun && |
777 | !list_is_last(pcdev->capture.next, &pcdev->capture)) { | 787 | !list_is_last(pcdev->capture.next, &pcdev->capture)) { |
778 | dev_dbg(pcdev->soc_host.dev, "FIFO overrun! CISR: %x\n", | 788 | dev_dbg(dev, "FIFO overrun! CISR: %x\n", |
779 | camera_status); | 789 | camera_status); |
780 | pxa_camera_stop_capture(pcdev); | 790 | pxa_camera_stop_capture(pcdev); |
781 | pxa_camera_start_capture(pcdev); | 791 | pxa_camera_start_capture(pcdev); |
@@ -830,9 +840,11 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q, | |||
830 | sizeof(struct pxa_buffer), icd); | 840 | sizeof(struct pxa_buffer), icd); |
831 | } | 841 | } |
832 | 842 | ||
833 | static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) | 843 | static u32 mclk_get_divisor(struct platform_device *pdev, |
844 | struct pxa_camera_dev *pcdev) | ||
834 | { | 845 | { |
835 | unsigned long mclk = pcdev->mclk; | 846 | unsigned long mclk = pcdev->mclk; |
847 | struct device *dev = &pdev->dev; | ||
836 | u32 div; | 848 | u32 div; |
837 | unsigned long lcdclk; | 849 | unsigned long lcdclk; |
838 | 850 | ||
@@ -842,7 +854,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) | |||
842 | /* mclk <= ciclk / 4 (27.4.2) */ | 854 | /* mclk <= ciclk / 4 (27.4.2) */ |
843 | if (mclk > lcdclk / 4) { | 855 | if (mclk > lcdclk / 4) { |
844 | mclk = lcdclk / 4; | 856 | mclk = lcdclk / 4; |
845 | dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk); | 857 | dev_warn(dev, "Limiting master clock to %lu\n", mclk); |
846 | } | 858 | } |
847 | 859 | ||
848 | /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ | 860 | /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ |
@@ -852,8 +864,8 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) | |||
852 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | 864 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) |
853 | pcdev->mclk = lcdclk / (2 * (div + 1)); | 865 | pcdev->mclk = lcdclk / (2 * (div + 1)); |
854 | 866 | ||
855 | dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, " | 867 | dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n", |
856 | "divisor %u\n", lcdclk, mclk, div); | 868 | lcdclk, mclk, div); |
857 | 869 | ||
858 | return div; | 870 | return div; |
859 | } | 871 | } |
@@ -870,14 +882,15 @@ static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev, | |||
870 | static void pxa_camera_activate(struct pxa_camera_dev *pcdev) | 882 | static void pxa_camera_activate(struct pxa_camera_dev *pcdev) |
871 | { | 883 | { |
872 | struct pxacamera_platform_data *pdata = pcdev->pdata; | 884 | struct pxacamera_platform_data *pdata = pcdev->pdata; |
885 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
873 | u32 cicr4 = 0; | 886 | u32 cicr4 = 0; |
874 | 887 | ||
875 | dev_dbg(pcdev->soc_host.dev, "Registered platform device at %p data %p\n", | 888 | dev_dbg(dev, "Registered platform device at %p data %p\n", |
876 | pcdev, pdata); | 889 | pcdev, pdata); |
877 | 890 | ||
878 | if (pdata && pdata->init) { | 891 | if (pdata && pdata->init) { |
879 | dev_dbg(pcdev->soc_host.dev, "%s: Init gpios\n", __func__); | 892 | dev_dbg(dev, "%s: Init gpios\n", __func__); |
880 | pdata->init(pcdev->soc_host.dev); | 893 | pdata->init(dev); |
881 | } | 894 | } |
882 | 895 | ||
883 | /* disable all interrupts */ | 896 | /* disable all interrupts */ |
@@ -919,7 +932,8 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) | |||
919 | struct videobuf_buffer *vb; | 932 | struct videobuf_buffer *vb; |
920 | 933 | ||
921 | status = __raw_readl(pcdev->base + CISR); | 934 | status = __raw_readl(pcdev->base + CISR); |
922 | dev_dbg(pcdev->soc_host.dev, "Camera interrupt status 0x%lx\n", status); | 935 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, |
936 | "Camera interrupt status 0x%lx\n", status); | ||
923 | 937 | ||
924 | if (!status) | 938 | if (!status) |
925 | return IRQ_NONE; | 939 | return IRQ_NONE; |
@@ -951,24 +965,18 @@ static int pxa_camera_add_device(struct soc_camera_device *icd) | |||
951 | { | 965 | { |
952 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 966 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
953 | struct pxa_camera_dev *pcdev = ici->priv; | 967 | struct pxa_camera_dev *pcdev = ici->priv; |
954 | int ret; | ||
955 | 968 | ||
956 | if (pcdev->icd) { | 969 | if (pcdev->icd) |
957 | ret = -EBUSY; | 970 | return -EBUSY; |
958 | goto ebusy; | ||
959 | } | ||
960 | |||
961 | dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n", | ||
962 | icd->devnum); | ||
963 | 971 | ||
964 | pxa_camera_activate(pcdev); | 972 | pxa_camera_activate(pcdev); |
965 | ret = icd->ops->init(icd); | ||
966 | 973 | ||
967 | if (!ret) | 974 | pcdev->icd = icd; |
968 | pcdev->icd = icd; | ||
969 | 975 | ||
970 | ebusy: | 976 | dev_info(icd->dev.parent, "PXA Camera driver attached to camera %d\n", |
971 | return ret; | 977 | icd->devnum); |
978 | |||
979 | return 0; | ||
972 | } | 980 | } |
973 | 981 | ||
974 | /* Called with .video_lock held */ | 982 | /* Called with .video_lock held */ |
@@ -979,7 +987,7 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd) | |||
979 | 987 | ||
980 | BUG_ON(icd != pcdev->icd); | 988 | BUG_ON(icd != pcdev->icd); |
981 | 989 | ||
982 | dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n", | 990 | dev_info(icd->dev.parent, "PXA Camera driver detached from camera %d\n", |
983 | icd->devnum); | 991 | icd->devnum); |
984 | 992 | ||
985 | /* disable capture, disable interrupts */ | 993 | /* disable capture, disable interrupts */ |
@@ -990,8 +998,6 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd) | |||
990 | DCSR(pcdev->dma_chans[1]) = 0; | 998 | DCSR(pcdev->dma_chans[1]) = 0; |
991 | DCSR(pcdev->dma_chans[2]) = 0; | 999 | DCSR(pcdev->dma_chans[2]) = 0; |
992 | 1000 | ||
993 | icd->ops->release(icd); | ||
994 | |||
995 | pxa_camera_deactivate(pcdev); | 1001 | pxa_camera_deactivate(pcdev); |
996 | 1002 | ||
997 | pcdev->icd = NULL; | 1003 | pcdev->icd = NULL; |
@@ -1039,57 +1045,17 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, | |||
1039 | return 0; | 1045 | return 0; |
1040 | } | 1046 | } |
1041 | 1047 | ||
1042 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 1048 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, |
1049 | unsigned long flags, __u32 pixfmt) | ||
1043 | { | 1050 | { |
1044 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1051 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1045 | struct pxa_camera_dev *pcdev = ici->priv; | 1052 | struct pxa_camera_dev *pcdev = ici->priv; |
1046 | unsigned long dw, bpp, bus_flags, camera_flags, common_flags; | 1053 | unsigned long dw, bpp; |
1047 | u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0; | 1054 | u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0; |
1048 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); | ||
1049 | |||
1050 | if (ret < 0) | ||
1051 | return ret; | ||
1052 | |||
1053 | camera_flags = icd->ops->query_bus_param(icd); | ||
1054 | |||
1055 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | ||
1056 | if (!common_flags) | ||
1057 | return -EINVAL; | ||
1058 | |||
1059 | pcdev->channels = 1; | ||
1060 | |||
1061 | /* Make choises, based on platform preferences */ | ||
1062 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | ||
1063 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | ||
1064 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | ||
1065 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | ||
1066 | else | ||
1067 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | ||
1068 | } | ||
1069 | |||
1070 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | ||
1071 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | ||
1072 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | ||
1073 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | ||
1074 | else | ||
1075 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | ||
1076 | } | ||
1077 | |||
1078 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | ||
1079 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | ||
1080 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | ||
1081 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | ||
1082 | else | ||
1083 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | ||
1084 | } | ||
1085 | |||
1086 | ret = icd->ops->set_bus_param(icd, common_flags); | ||
1087 | if (ret < 0) | ||
1088 | return ret; | ||
1089 | 1055 | ||
1090 | /* Datawidth is now guaranteed to be equal to one of the three values. | 1056 | /* Datawidth is now guaranteed to be equal to one of the three values. |
1091 | * We fix bit-per-pixel equal to data-width... */ | 1057 | * We fix bit-per-pixel equal to data-width... */ |
1092 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { | 1058 | switch (flags & SOCAM_DATAWIDTH_MASK) { |
1093 | case SOCAM_DATAWIDTH_10: | 1059 | case SOCAM_DATAWIDTH_10: |
1094 | dw = 4; | 1060 | dw = 4; |
1095 | bpp = 0x40; | 1061 | bpp = 0x40; |
@@ -1110,18 +1076,18 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1110 | cicr4 |= CICR4_PCLK_EN; | 1076 | cicr4 |= CICR4_PCLK_EN; |
1111 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | 1077 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) |
1112 | cicr4 |= CICR4_MCLK_EN; | 1078 | cicr4 |= CICR4_MCLK_EN; |
1113 | if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) | 1079 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) |
1114 | cicr4 |= CICR4_PCP; | 1080 | cicr4 |= CICR4_PCP; |
1115 | if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) | 1081 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) |
1116 | cicr4 |= CICR4_HSP; | 1082 | cicr4 |= CICR4_HSP; |
1117 | if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) | 1083 | if (flags & SOCAM_VSYNC_ACTIVE_LOW) |
1118 | cicr4 |= CICR4_VSP; | 1084 | cicr4 |= CICR4_VSP; |
1119 | 1085 | ||
1120 | cicr0 = __raw_readl(pcdev->base + CICR0); | 1086 | cicr0 = __raw_readl(pcdev->base + CICR0); |
1121 | if (cicr0 & CICR0_ENB) | 1087 | if (cicr0 & CICR0_ENB) |
1122 | __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); | 1088 | __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); |
1123 | 1089 | ||
1124 | cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw; | 1090 | cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw; |
1125 | 1091 | ||
1126 | switch (pixfmt) { | 1092 | switch (pixfmt) { |
1127 | case V4L2_PIX_FMT_YUV422P: | 1093 | case V4L2_PIX_FMT_YUV422P: |
@@ -1150,7 +1116,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1150 | } | 1116 | } |
1151 | 1117 | ||
1152 | cicr2 = 0; | 1118 | cicr2 = 0; |
1153 | cicr3 = CICR3_LPF_VAL(icd->height - 1) | | 1119 | cicr3 = CICR3_LPF_VAL(icd->user_height - 1) | |
1154 | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); | 1120 | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); |
1155 | cicr4 |= pcdev->mclk_divisor; | 1121 | cicr4 |= pcdev->mclk_divisor; |
1156 | 1122 | ||
@@ -1164,6 +1130,59 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1164 | CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)); | 1130 | CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)); |
1165 | cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK; | 1131 | cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK; |
1166 | __raw_writel(cicr0, pcdev->base + CICR0); | 1132 | __raw_writel(cicr0, pcdev->base + CICR0); |
1133 | } | ||
1134 | |||
1135 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | ||
1136 | { | ||
1137 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1138 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1139 | unsigned long bus_flags, camera_flags, common_flags; | ||
1140 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); | ||
1141 | struct pxa_cam *cam = icd->host_priv; | ||
1142 | |||
1143 | if (ret < 0) | ||
1144 | return ret; | ||
1145 | |||
1146 | camera_flags = icd->ops->query_bus_param(icd); | ||
1147 | |||
1148 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | ||
1149 | if (!common_flags) | ||
1150 | return -EINVAL; | ||
1151 | |||
1152 | pcdev->channels = 1; | ||
1153 | |||
1154 | /* Make choises, based on platform preferences */ | ||
1155 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | ||
1156 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | ||
1157 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | ||
1158 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | ||
1159 | else | ||
1160 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | ||
1161 | } | ||
1162 | |||
1163 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | ||
1164 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | ||
1165 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | ||
1166 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | ||
1167 | else | ||
1168 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | ||
1169 | } | ||
1170 | |||
1171 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | ||
1172 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | ||
1173 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | ||
1174 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | ||
1175 | else | ||
1176 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | ||
1177 | } | ||
1178 | |||
1179 | cam->flags = common_flags; | ||
1180 | |||
1181 | ret = icd->ops->set_bus_param(icd, common_flags); | ||
1182 | if (ret < 0) | ||
1183 | return ret; | ||
1184 | |||
1185 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); | ||
1167 | 1186 | ||
1168 | return 0; | 1187 | return 0; |
1169 | } | 1188 | } |
@@ -1227,8 +1246,9 @@ static int required_buswidth(const struct soc_camera_data_format *fmt) | |||
1227 | static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | 1246 | static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, |
1228 | struct soc_camera_format_xlate *xlate) | 1247 | struct soc_camera_format_xlate *xlate) |
1229 | { | 1248 | { |
1230 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1249 | struct device *dev = icd->dev.parent; |
1231 | int formats = 0, buswidth, ret; | 1250 | int formats = 0, buswidth, ret; |
1251 | struct pxa_cam *cam; | ||
1232 | 1252 | ||
1233 | buswidth = required_buswidth(icd->formats + idx); | 1253 | buswidth = required_buswidth(icd->formats + idx); |
1234 | 1254 | ||
@@ -1239,6 +1259,16 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
1239 | if (ret < 0) | 1259 | if (ret < 0) |
1240 | return 0; | 1260 | return 0; |
1241 | 1261 | ||
1262 | if (!icd->host_priv) { | ||
1263 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
1264 | if (!cam) | ||
1265 | return -ENOMEM; | ||
1266 | |||
1267 | icd->host_priv = cam; | ||
1268 | } else { | ||
1269 | cam = icd->host_priv; | ||
1270 | } | ||
1271 | |||
1242 | switch (icd->formats[idx].fourcc) { | 1272 | switch (icd->formats[idx].fourcc) { |
1243 | case V4L2_PIX_FMT_UYVY: | 1273 | case V4L2_PIX_FMT_UYVY: |
1244 | formats++; | 1274 | formats++; |
@@ -1247,7 +1277,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
1247 | xlate->cam_fmt = icd->formats + idx; | 1277 | xlate->cam_fmt = icd->formats + idx; |
1248 | xlate->buswidth = buswidth; | 1278 | xlate->buswidth = buswidth; |
1249 | xlate++; | 1279 | xlate++; |
1250 | dev_dbg(ici->dev, "Providing format %s using %s\n", | 1280 | dev_dbg(dev, "Providing format %s using %s\n", |
1251 | pxa_camera_formats[0].name, | 1281 | pxa_camera_formats[0].name, |
1252 | icd->formats[idx].name); | 1282 | icd->formats[idx].name); |
1253 | } | 1283 | } |
@@ -1262,7 +1292,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
1262 | xlate->cam_fmt = icd->formats + idx; | 1292 | xlate->cam_fmt = icd->formats + idx; |
1263 | xlate->buswidth = buswidth; | 1293 | xlate->buswidth = buswidth; |
1264 | xlate++; | 1294 | xlate++; |
1265 | dev_dbg(ici->dev, "Providing format %s packed\n", | 1295 | dev_dbg(dev, "Providing format %s packed\n", |
1266 | icd->formats[idx].name); | 1296 | icd->formats[idx].name); |
1267 | } | 1297 | } |
1268 | break; | 1298 | break; |
@@ -1274,7 +1304,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
1274 | xlate->cam_fmt = icd->formats + idx; | 1304 | xlate->cam_fmt = icd->formats + idx; |
1275 | xlate->buswidth = icd->formats[idx].depth; | 1305 | xlate->buswidth = icd->formats[idx].depth; |
1276 | xlate++; | 1306 | xlate++; |
1277 | dev_dbg(ici->dev, | 1307 | dev_dbg(dev, |
1278 | "Providing format %s in pass-through mode\n", | 1308 | "Providing format %s in pass-through mode\n", |
1279 | icd->formats[idx].name); | 1309 | icd->formats[idx].name); |
1280 | } | 1310 | } |
@@ -1283,31 +1313,80 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
1283 | return formats; | 1313 | return formats; |
1284 | } | 1314 | } |
1285 | 1315 | ||
1316 | static void pxa_camera_put_formats(struct soc_camera_device *icd) | ||
1317 | { | ||
1318 | kfree(icd->host_priv); | ||
1319 | icd->host_priv = NULL; | ||
1320 | } | ||
1321 | |||
1322 | static int pxa_camera_check_frame(struct v4l2_pix_format *pix) | ||
1323 | { | ||
1324 | /* limit to pxa hardware capabilities */ | ||
1325 | return pix->height < 32 || pix->height > 2048 || pix->width < 48 || | ||
1326 | pix->width > 2048 || (pix->width & 0x01); | ||
1327 | } | ||
1328 | |||
1286 | static int pxa_camera_set_crop(struct soc_camera_device *icd, | 1329 | static int pxa_camera_set_crop(struct soc_camera_device *icd, |
1287 | struct v4l2_rect *rect) | 1330 | struct v4l2_crop *a) |
1288 | { | 1331 | { |
1332 | struct v4l2_rect *rect = &a->c; | ||
1289 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1333 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1290 | struct pxa_camera_dev *pcdev = ici->priv; | 1334 | struct pxa_camera_dev *pcdev = ici->priv; |
1335 | struct device *dev = icd->dev.parent; | ||
1336 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1291 | struct soc_camera_sense sense = { | 1337 | struct soc_camera_sense sense = { |
1292 | .master_clock = pcdev->mclk, | 1338 | .master_clock = pcdev->mclk, |
1293 | .pixel_clock_max = pcdev->ciclk / 4, | 1339 | .pixel_clock_max = pcdev->ciclk / 4, |
1294 | }; | 1340 | }; |
1341 | struct v4l2_format f; | ||
1342 | struct v4l2_pix_format *pix = &f.fmt.pix, pix_tmp; | ||
1343 | struct pxa_cam *cam = icd->host_priv; | ||
1295 | int ret; | 1344 | int ret; |
1296 | 1345 | ||
1297 | /* If PCLK is used to latch data from the sensor, check sense */ | 1346 | /* If PCLK is used to latch data from the sensor, check sense */ |
1298 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | 1347 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) |
1299 | icd->sense = &sense; | 1348 | icd->sense = &sense; |
1300 | 1349 | ||
1301 | ret = icd->ops->set_crop(icd, rect); | 1350 | ret = v4l2_subdev_call(sd, video, s_crop, a); |
1302 | 1351 | ||
1303 | icd->sense = NULL; | 1352 | icd->sense = NULL; |
1304 | 1353 | ||
1305 | if (ret < 0) { | 1354 | if (ret < 0) { |
1306 | dev_warn(ici->dev, "Failed to crop to %ux%u@%u:%u\n", | 1355 | dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n", |
1307 | rect->width, rect->height, rect->left, rect->top); | 1356 | rect->width, rect->height, rect->left, rect->top); |
1308 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | 1357 | return ret; |
1358 | } | ||
1359 | |||
1360 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1361 | |||
1362 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
1363 | if (ret < 0) | ||
1364 | return ret; | ||
1365 | |||
1366 | pix_tmp = *pix; | ||
1367 | if (pxa_camera_check_frame(pix)) { | ||
1368 | /* | ||
1369 | * Camera cropping produced a frame beyond our capabilities. | ||
1370 | * FIXME: just extract a subframe, that we can process. | ||
1371 | */ | ||
1372 | v4l_bound_align_image(&pix->width, 48, 2048, 1, | ||
1373 | &pix->height, 32, 2048, 0, | ||
1374 | icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? | ||
1375 | 4 : 0); | ||
1376 | ret = v4l2_subdev_call(sd, video, s_fmt, &f); | ||
1377 | if (ret < 0) | ||
1378 | return ret; | ||
1379 | |||
1380 | if (pxa_camera_check_frame(pix)) { | ||
1381 | dev_warn(icd->dev.parent, | ||
1382 | "Inconsistent state. Use S_FMT to repair\n"); | ||
1383 | return -EINVAL; | ||
1384 | } | ||
1385 | } | ||
1386 | |||
1387 | if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | ||
1309 | if (sense.pixel_clock > sense.pixel_clock_max) { | 1388 | if (sense.pixel_clock > sense.pixel_clock_max) { |
1310 | dev_err(ici->dev, | 1389 | dev_err(dev, |
1311 | "pixel clock %lu set by the camera too high!", | 1390 | "pixel clock %lu set by the camera too high!", |
1312 | sense.pixel_clock); | 1391 | sense.pixel_clock); |
1313 | return -EIO; | 1392 | return -EIO; |
@@ -1315,6 +1394,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, | |||
1315 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | 1394 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); |
1316 | } | 1395 | } |
1317 | 1396 | ||
1397 | icd->user_width = pix->width; | ||
1398 | icd->user_height = pix->height; | ||
1399 | |||
1400 | pxa_camera_setup_cicr(icd, cam->flags, icd->current_fmt->fourcc); | ||
1401 | |||
1318 | return ret; | 1402 | return ret; |
1319 | } | 1403 | } |
1320 | 1404 | ||
@@ -1323,6 +1407,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1323 | { | 1407 | { |
1324 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1408 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1325 | struct pxa_camera_dev *pcdev = ici->priv; | 1409 | struct pxa_camera_dev *pcdev = ici->priv; |
1410 | struct device *dev = icd->dev.parent; | ||
1411 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1326 | const struct soc_camera_data_format *cam_fmt = NULL; | 1412 | const struct soc_camera_data_format *cam_fmt = NULL; |
1327 | const struct soc_camera_format_xlate *xlate = NULL; | 1413 | const struct soc_camera_format_xlate *xlate = NULL; |
1328 | struct soc_camera_sense sense = { | 1414 | struct soc_camera_sense sense = { |
@@ -1335,7 +1421,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1335 | 1421 | ||
1336 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 1422 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
1337 | if (!xlate) { | 1423 | if (!xlate) { |
1338 | dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); | 1424 | dev_warn(dev, "Format %x not found\n", pix->pixelformat); |
1339 | return -EINVAL; | 1425 | return -EINVAL; |
1340 | } | 1426 | } |
1341 | 1427 | ||
@@ -1346,16 +1432,21 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1346 | icd->sense = &sense; | 1432 | icd->sense = &sense; |
1347 | 1433 | ||
1348 | cam_f.fmt.pix.pixelformat = cam_fmt->fourcc; | 1434 | cam_f.fmt.pix.pixelformat = cam_fmt->fourcc; |
1349 | ret = icd->ops->set_fmt(icd, &cam_f); | 1435 | ret = v4l2_subdev_call(sd, video, s_fmt, f); |
1350 | 1436 | ||
1351 | icd->sense = NULL; | 1437 | icd->sense = NULL; |
1352 | 1438 | ||
1353 | if (ret < 0) { | 1439 | if (ret < 0) { |
1354 | dev_warn(ici->dev, "Failed to configure for format %x\n", | 1440 | dev_warn(dev, "Failed to configure for format %x\n", |
1355 | pix->pixelformat); | 1441 | pix->pixelformat); |
1442 | } else if (pxa_camera_check_frame(pix)) { | ||
1443 | dev_warn(dev, | ||
1444 | "Camera driver produced an unsupported frame %dx%d\n", | ||
1445 | pix->width, pix->height); | ||
1446 | ret = -EINVAL; | ||
1356 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | 1447 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { |
1357 | if (sense.pixel_clock > sense.pixel_clock_max) { | 1448 | if (sense.pixel_clock > sense.pixel_clock_max) { |
1358 | dev_err(ici->dev, | 1449 | dev_err(dev, |
1359 | "pixel clock %lu set by the camera too high!", | 1450 | "pixel clock %lu set by the camera too high!", |
1360 | sense.pixel_clock); | 1451 | sense.pixel_clock); |
1361 | return -EIO; | 1452 | return -EIO; |
@@ -1375,6 +1466,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, | |||
1375 | struct v4l2_format *f) | 1466 | struct v4l2_format *f) |
1376 | { | 1467 | { |
1377 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1468 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1469 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1378 | const struct soc_camera_format_xlate *xlate; | 1470 | const struct soc_camera_format_xlate *xlate; |
1379 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1471 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1380 | __u32 pixfmt = pix->pixelformat; | 1472 | __u32 pixfmt = pix->pixelformat; |
@@ -1383,7 +1475,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, | |||
1383 | 1475 | ||
1384 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1476 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
1385 | if (!xlate) { | 1477 | if (!xlate) { |
1386 | dev_warn(ici->dev, "Format %x not found\n", pixfmt); | 1478 | dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt); |
1387 | return -EINVAL; | 1479 | return -EINVAL; |
1388 | } | 1480 | } |
1389 | 1481 | ||
@@ -1395,7 +1487,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, | |||
1395 | */ | 1487 | */ |
1396 | v4l_bound_align_image(&pix->width, 48, 2048, 1, | 1488 | v4l_bound_align_image(&pix->width, 48, 2048, 1, |
1397 | &pix->height, 32, 2048, 0, | 1489 | &pix->height, 32, 2048, 0, |
1398 | xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); | 1490 | pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); |
1399 | 1491 | ||
1400 | pix->bytesperline = pix->width * | 1492 | pix->bytesperline = pix->width * |
1401 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); | 1493 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); |
@@ -1404,15 +1496,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, | |||
1404 | /* camera has to see its format, but the user the original one */ | 1496 | /* camera has to see its format, but the user the original one */ |
1405 | pix->pixelformat = xlate->cam_fmt->fourcc; | 1497 | pix->pixelformat = xlate->cam_fmt->fourcc; |
1406 | /* limit to sensor capabilities */ | 1498 | /* limit to sensor capabilities */ |
1407 | ret = icd->ops->try_fmt(icd, f); | 1499 | ret = v4l2_subdev_call(sd, video, try_fmt, f); |
1408 | pix->pixelformat = xlate->host_fmt->fourcc; | 1500 | pix->pixelformat = pixfmt; |
1409 | 1501 | ||
1410 | field = pix->field; | 1502 | field = pix->field; |
1411 | 1503 | ||
1412 | if (field == V4L2_FIELD_ANY) { | 1504 | if (field == V4L2_FIELD_ANY) { |
1413 | pix->field = V4L2_FIELD_NONE; | 1505 | pix->field = V4L2_FIELD_NONE; |
1414 | } else if (field != V4L2_FIELD_NONE) { | 1506 | } else if (field != V4L2_FIELD_NONE) { |
1415 | dev_err(&icd->dev, "Field type %d unsupported.\n", field); | 1507 | dev_err(icd->dev.parent, "Field type %d unsupported.\n", field); |
1416 | return -EINVAL; | 1508 | return -EINVAL; |
1417 | } | 1509 | } |
1418 | 1510 | ||
@@ -1518,6 +1610,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { | |||
1518 | .resume = pxa_camera_resume, | 1610 | .resume = pxa_camera_resume, |
1519 | .set_crop = pxa_camera_set_crop, | 1611 | .set_crop = pxa_camera_set_crop, |
1520 | .get_formats = pxa_camera_get_formats, | 1612 | .get_formats = pxa_camera_get_formats, |
1613 | .put_formats = pxa_camera_put_formats, | ||
1521 | .set_fmt = pxa_camera_set_fmt, | 1614 | .set_fmt = pxa_camera_set_fmt, |
1522 | .try_fmt = pxa_camera_try_fmt, | 1615 | .try_fmt = pxa_camera_try_fmt, |
1523 | .init_videobuf = pxa_camera_init_videobuf, | 1616 | .init_videobuf = pxa_camera_init_videobuf, |
@@ -1575,8 +1668,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) | |||
1575 | pcdev->mclk = 20000000; | 1668 | pcdev->mclk = 20000000; |
1576 | } | 1669 | } |
1577 | 1670 | ||
1578 | pcdev->soc_host.dev = &pdev->dev; | 1671 | pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev); |
1579 | pcdev->mclk_divisor = mclk_get_divisor(pcdev); | ||
1580 | 1672 | ||
1581 | INIT_LIST_HEAD(&pcdev->capture); | 1673 | INIT_LIST_HEAD(&pcdev->capture); |
1582 | spin_lock_init(&pcdev->lock); | 1674 | spin_lock_init(&pcdev->lock); |
@@ -1641,6 +1733,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) | |||
1641 | pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; | 1733 | pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; |
1642 | pcdev->soc_host.ops = &pxa_soc_camera_host_ops; | 1734 | pcdev->soc_host.ops = &pxa_soc_camera_host_ops; |
1643 | pcdev->soc_host.priv = pcdev; | 1735 | pcdev->soc_host.priv = pcdev; |
1736 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
1644 | pcdev->soc_host.nr = pdev->id; | 1737 | pcdev->soc_host.nr = pdev->id; |
1645 | 1738 | ||
1646 | err = soc_camera_host_register(&pcdev->soc_host); | 1739 | err = soc_camera_host_register(&pcdev->soc_host); |
@@ -1722,3 +1815,4 @@ module_exit(pxa_camera_exit); | |||
1722 | MODULE_DESCRIPTION("PXA27x SoC Camera Host driver"); | 1815 | MODULE_DESCRIPTION("PXA27x SoC Camera Host driver"); |
1723 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | 1816 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); |
1724 | MODULE_LICENSE("GPL"); | 1817 | MODULE_LICENSE("GPL"); |
1818 | MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME); | ||
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 1b29487fd254..71145bff94fa 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -4164,7 +4164,7 @@ struct saa7134_board saa7134_boards[] = { | |||
4164 | /*Dmitry Belimov <d.belimov@gmail.com> */ | 4164 | /*Dmitry Belimov <d.belimov@gmail.com> */ |
4165 | .name = "Beholder BeholdTV 505 RDS", | 4165 | .name = "Beholder BeholdTV 505 RDS", |
4166 | .audio_clock = 0x00200000, | 4166 | .audio_clock = 0x00200000, |
4167 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ | 4167 | .tuner_type = TUNER_PHILIPS_FM1216MK5, |
4168 | .radio_type = UNSET, | 4168 | .radio_type = UNSET, |
4169 | .tuner_addr = ADDR_UNSET, | 4169 | .tuner_addr = ADDR_UNSET, |
4170 | .radio_addr = ADDR_UNSET, | 4170 | .radio_addr = ADDR_UNSET, |
@@ -4229,7 +4229,7 @@ struct saa7134_board saa7134_boards[] = { | |||
4229 | /*Dmitry Belimov <d.belimov@gmail.com> */ | 4229 | /*Dmitry Belimov <d.belimov@gmail.com> */ |
4230 | .name = "Beholder BeholdTV 507 RDS", | 4230 | .name = "Beholder BeholdTV 507 RDS", |
4231 | .audio_clock = 0x00187de7, | 4231 | .audio_clock = 0x00187de7, |
4232 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ | 4232 | .tuner_type = TUNER_PHILIPS_FM1216MK5, |
4233 | .radio_type = UNSET, | 4233 | .radio_type = UNSET, |
4234 | .tuner_addr = ADDR_UNSET, | 4234 | .tuner_addr = ADDR_UNSET, |
4235 | .radio_addr = ADDR_UNSET, | 4235 | .radio_addr = ADDR_UNSET, |
@@ -4380,7 +4380,7 @@ struct saa7134_board saa7134_boards[] = { | |||
4380 | /* Andrey Melnikoff <temnota@kmv.ru> */ | 4380 | /* Andrey Melnikoff <temnota@kmv.ru> */ |
4381 | .name = "Beholder BeholdTV 607 FM", | 4381 | .name = "Beholder BeholdTV 607 FM", |
4382 | .audio_clock = 0x00187de7, | 4382 | .audio_clock = 0x00187de7, |
4383 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ | 4383 | .tuner_type = TUNER_PHILIPS_FM1216MK5, |
4384 | .radio_type = UNSET, | 4384 | .radio_type = UNSET, |
4385 | .tuner_addr = ADDR_UNSET, | 4385 | .tuner_addr = ADDR_UNSET, |
4386 | .radio_addr = ADDR_UNSET, | 4386 | .radio_addr = ADDR_UNSET, |
@@ -4408,7 +4408,7 @@ struct saa7134_board saa7134_boards[] = { | |||
4408 | /* Andrey Melnikoff <temnota@kmv.ru> */ | 4408 | /* Andrey Melnikoff <temnota@kmv.ru> */ |
4409 | .name = "Beholder BeholdTV 609 FM", | 4409 | .name = "Beholder BeholdTV 609 FM", |
4410 | .audio_clock = 0x00187de7, | 4410 | .audio_clock = 0x00187de7, |
4411 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ | 4411 | .tuner_type = TUNER_PHILIPS_FM1216MK5, |
4412 | .radio_type = UNSET, | 4412 | .radio_type = UNSET, |
4413 | .tuner_addr = ADDR_UNSET, | 4413 | .tuner_addr = ADDR_UNSET, |
4414 | .radio_addr = ADDR_UNSET, | 4414 | .radio_addr = ADDR_UNSET, |
@@ -4494,7 +4494,7 @@ struct saa7134_board saa7134_boards[] = { | |||
4494 | /* Andrey Melnikoff <temnota@kmv.ru> */ | 4494 | /* Andrey Melnikoff <temnota@kmv.ru> */ |
4495 | .name = "Beholder BeholdTV 607 RDS", | 4495 | .name = "Beholder BeholdTV 607 RDS", |
4496 | .audio_clock = 0x00187de7, | 4496 | .audio_clock = 0x00187de7, |
4497 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ | 4497 | .tuner_type = TUNER_PHILIPS_FM1216MK5, |
4498 | .radio_type = UNSET, | 4498 | .radio_type = UNSET, |
4499 | .tuner_addr = ADDR_UNSET, | 4499 | .tuner_addr = ADDR_UNSET, |
4500 | .radio_addr = ADDR_UNSET, | 4500 | .radio_addr = ADDR_UNSET, |
@@ -4523,7 +4523,7 @@ struct saa7134_board saa7134_boards[] = { | |||
4523 | /* Andrey Melnikoff <temnota@kmv.ru> */ | 4523 | /* Andrey Melnikoff <temnota@kmv.ru> */ |
4524 | .name = "Beholder BeholdTV 609 RDS", | 4524 | .name = "Beholder BeholdTV 609 RDS", |
4525 | .audio_clock = 0x00187de7, | 4525 | .audio_clock = 0x00187de7, |
4526 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ | 4526 | .tuner_type = TUNER_PHILIPS_FM1216MK5, |
4527 | .radio_type = UNSET, | 4527 | .radio_type = UNSET, |
4528 | .tuner_addr = ADDR_UNSET, | 4528 | .tuner_addr = ADDR_UNSET, |
4529 | .radio_addr = ADDR_UNSET, | 4529 | .radio_addr = ADDR_UNSET, |
@@ -4630,7 +4630,7 @@ struct saa7134_board saa7134_boards[] = { | |||
4630 | /* Alexey Osipov <lion-simba@pridelands.ru> */ | 4630 | /* Alexey Osipov <lion-simba@pridelands.ru> */ |
4631 | .name = "Beholder BeholdTV M6 Extra", | 4631 | .name = "Beholder BeholdTV M6 Extra", |
4632 | .audio_clock = 0x00187de7, | 4632 | .audio_clock = 0x00187de7, |
4633 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ | 4633 | .tuner_type = TUNER_PHILIPS_FM1216MK5, |
4634 | .radio_type = UNSET, | 4634 | .radio_type = UNSET, |
4635 | .tuner_addr = ADDR_UNSET, | 4635 | .tuner_addr = ADDR_UNSET, |
4636 | .radio_addr = ADDR_UNSET, | 4636 | .radio_addr = ADDR_UNSET, |
@@ -5257,6 +5257,27 @@ struct saa7134_board saa7134_boards[] = { | |||
5257 | .amux = TV, | 5257 | .amux = TV, |
5258 | }, | 5258 | }, |
5259 | }, | 5259 | }, |
5260 | [SAA7134_BOARD_ZOLID_HYBRID_PCI] = { | ||
5261 | .name = "Zolid Hybrid TV Tuner PCI", | ||
5262 | .audio_clock = 0x00187de7, | ||
5263 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
5264 | .radio_type = UNSET, | ||
5265 | .tuner_addr = ADDR_UNSET, | ||
5266 | .radio_addr = ADDR_UNSET, | ||
5267 | .tuner_config = 0, | ||
5268 | .mpeg = SAA7134_MPEG_DVB, | ||
5269 | .ts_type = SAA7134_MPEG_TS_PARALLEL, | ||
5270 | .inputs = {{ | ||
5271 | .name = name_tv, | ||
5272 | .vmux = 1, | ||
5273 | .amux = TV, | ||
5274 | .tv = 1, | ||
5275 | } }, | ||
5276 | .radio = { /* untested */ | ||
5277 | .name = name_radio, | ||
5278 | .amux = TV, | ||
5279 | }, | ||
5280 | }, | ||
5260 | 5281 | ||
5261 | }; | 5282 | }; |
5262 | 5283 | ||
@@ -6390,6 +6411,12 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
6390 | .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ | 6411 | .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ |
6391 | .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, | 6412 | .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, |
6392 | }, { | 6413 | }, { |
6414 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
6415 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
6416 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
6417 | .subdevice = 0x2004, | ||
6418 | .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, | ||
6419 | }, { | ||
6393 | /* --- boards without eeprom + subsystem ID --- */ | 6420 | /* --- boards without eeprom + subsystem ID --- */ |
6394 | .vendor = PCI_VENDOR_ID_PHILIPS, | 6421 | .vendor = PCI_VENDOR_ID_PHILIPS, |
6395 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | 6422 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, |
@@ -7208,22 +7235,22 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
7208 | if (dev->radio_type != UNSET) | 7235 | if (dev->radio_type != UNSET) |
7209 | v4l2_i2c_new_subdev(&dev->v4l2_dev, | 7236 | v4l2_i2c_new_subdev(&dev->v4l2_dev, |
7210 | &dev->i2c_adap, "tuner", "tuner", | 7237 | &dev->i2c_adap, "tuner", "tuner", |
7211 | dev->radio_addr); | 7238 | dev->radio_addr, NULL); |
7212 | if (has_demod) | 7239 | if (has_demod) |
7213 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, | 7240 | v4l2_i2c_new_subdev(&dev->v4l2_dev, |
7214 | &dev->i2c_adap, "tuner", "tuner", | 7241 | &dev->i2c_adap, "tuner", "tuner", |
7215 | v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | 7242 | 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); |
7216 | if (dev->tuner_addr == ADDR_UNSET) { | 7243 | if (dev->tuner_addr == ADDR_UNSET) { |
7217 | enum v4l2_i2c_tuner_type type = | 7244 | enum v4l2_i2c_tuner_type type = |
7218 | has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; | 7245 | has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; |
7219 | 7246 | ||
7220 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, | 7247 | v4l2_i2c_new_subdev(&dev->v4l2_dev, |
7221 | &dev->i2c_adap, "tuner", "tuner", | 7248 | &dev->i2c_adap, "tuner", "tuner", |
7222 | v4l2_i2c_tuner_addrs(type)); | 7249 | 0, v4l2_i2c_tuner_addrs(type)); |
7223 | } else { | 7250 | } else { |
7224 | v4l2_i2c_new_subdev(&dev->v4l2_dev, | 7251 | v4l2_i2c_new_subdev(&dev->v4l2_dev, |
7225 | &dev->i2c_adap, "tuner", "tuner", | 7252 | &dev->i2c_adap, "tuner", "tuner", |
7226 | dev->tuner_addr); | 7253 | dev->tuner_addr, NULL); |
7227 | } | 7254 | } |
7228 | } | 7255 | } |
7229 | 7256 | ||
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index cb78c956d810..f87757fccc72 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c | |||
@@ -1000,7 +1000,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1000 | struct v4l2_subdev *sd = | 1000 | struct v4l2_subdev *sd = |
1001 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 1001 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
1002 | "saa6752hs", "saa6752hs", | 1002 | "saa6752hs", "saa6752hs", |
1003 | saa7134_boards[dev->board].empress_addr); | 1003 | saa7134_boards[dev->board].empress_addr, NULL); |
1004 | 1004 | ||
1005 | if (sd) | 1005 | if (sd) |
1006 | sd->grp_id = GRP_EMPRESS; | 1006 | sd->grp_id = GRP_EMPRESS; |
@@ -1009,9 +1009,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1009 | if (saa7134_boards[dev->board].rds_addr) { | 1009 | if (saa7134_boards[dev->board].rds_addr) { |
1010 | struct v4l2_subdev *sd; | 1010 | struct v4l2_subdev *sd; |
1011 | 1011 | ||
1012 | sd = v4l2_i2c_new_probed_subdev_addr(&dev->v4l2_dev, | 1012 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
1013 | &dev->i2c_adap, "saa6588", "saa6588", | 1013 | &dev->i2c_adap, "saa6588", "saa6588", |
1014 | saa7134_boards[dev->board].rds_addr); | 1014 | 0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr)); |
1015 | if (sd) { | 1015 | if (sd) { |
1016 | printk(KERN_INFO "%s: found RDS decoder\n", dev->name); | 1016 | printk(KERN_INFO "%s: found RDS decoder\n", dev->name); |
1017 | dev->has_rds = 1; | 1017 | dev->has_rds = 1; |
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index ebde21dba7e3..a26e997a9ce6 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c | |||
@@ -1007,12 +1007,29 @@ static struct tda18271_config hcw_tda18271_config = { | |||
1007 | .std_map = &hauppauge_tda18271_std_map, | 1007 | .std_map = &hauppauge_tda18271_std_map, |
1008 | .gate = TDA18271_GATE_ANALOG, | 1008 | .gate = TDA18271_GATE_ANALOG, |
1009 | .config = 3, | 1009 | .config = 3, |
1010 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
1010 | }; | 1011 | }; |
1011 | 1012 | ||
1012 | static struct tda829x_config tda829x_no_probe = { | 1013 | static struct tda829x_config tda829x_no_probe = { |
1013 | .probe_tuner = TDA829X_DONT_PROBE, | 1014 | .probe_tuner = TDA829X_DONT_PROBE, |
1014 | }; | 1015 | }; |
1015 | 1016 | ||
1017 | static struct tda10048_config zolid_tda10048_config = { | ||
1018 | .demod_address = 0x10 >> 1, | ||
1019 | .output_mode = TDA10048_PARALLEL_OUTPUT, | ||
1020 | .fwbulkwritelen = TDA10048_BULKWRITE_200, | ||
1021 | .inversion = TDA10048_INVERSION_ON, | ||
1022 | .dtv6_if_freq_khz = TDA10048_IF_3300, | ||
1023 | .dtv7_if_freq_khz = TDA10048_IF_3500, | ||
1024 | .dtv8_if_freq_khz = TDA10048_IF_4000, | ||
1025 | .clk_freq_khz = TDA10048_CLK_16000, | ||
1026 | .disable_gate_access = 1, | ||
1027 | }; | ||
1028 | |||
1029 | static struct tda18271_config zolid_tda18271_config = { | ||
1030 | .gate = TDA18271_GATE_ANALOG, | ||
1031 | }; | ||
1032 | |||
1016 | /* ================================================================== | 1033 | /* ================================================================== |
1017 | * Core code | 1034 | * Core code |
1018 | */ | 1035 | */ |
@@ -1488,6 +1505,19 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1488 | __func__); | 1505 | __func__); |
1489 | 1506 | ||
1490 | break; | 1507 | break; |
1508 | case SAA7134_BOARD_ZOLID_HYBRID_PCI: | ||
1509 | fe0->dvb.frontend = dvb_attach(tda10048_attach, | ||
1510 | &zolid_tda10048_config, | ||
1511 | &dev->i2c_adap); | ||
1512 | if (fe0->dvb.frontend != NULL) { | ||
1513 | dvb_attach(tda829x_attach, fe0->dvb.frontend, | ||
1514 | &dev->i2c_adap, 0x4b, | ||
1515 | &tda829x_no_probe); | ||
1516 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
1517 | 0x60, &dev->i2c_adap, | ||
1518 | &zolid_tda18271_config); | ||
1519 | } | ||
1520 | break; | ||
1491 | default: | 1521 | default: |
1492 | wprintk("Huh? unknown DVB card?\n"); | 1522 | wprintk("Huh? unknown DVB card?\n"); |
1493 | break; | 1523 | break; |
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index e1e83c7b966e..a0e8c62e6ae1 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -251,6 +251,10 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | |||
251 | if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir) | 251 | if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir) |
252 | return 0; | 252 | return 0; |
253 | 253 | ||
254 | /* Wrong data decode fix */ | ||
255 | if (data[9] != (unsigned char)(~data[8])) | ||
256 | return 0; | ||
257 | |||
254 | *ir_key = data[9]; | 258 | *ir_key = data[9]; |
255 | *ir_raw = data[9]; | 259 | *ir_raw = data[9]; |
256 | 260 | ||
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index d18bb9643856..6ee3e9b7769e 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -296,6 +296,7 @@ struct saa7134_format { | |||
296 | #define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170 | 296 | #define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170 |
297 | #define SAA7134_BOARD_BEHOLD_X7 171 | 297 | #define SAA7134_BOARD_BEHOLD_X7 171 |
298 | #define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172 | 298 | #define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172 |
299 | #define SAA7134_BOARD_ZOLID_HYBRID_PCI 173 | ||
299 | 300 | ||
300 | #define SAA7134_MAXBOARDS 32 | 301 | #define SAA7134_MAXBOARDS 32 |
301 | #define SAA7134_INPUT_MAX 8 | 302 | #define SAA7134_INPUT_MAX 8 |
diff --git a/drivers/media/video/saa7164/Kconfig b/drivers/media/video/saa7164/Kconfig new file mode 100644 index 000000000000..353263725172 --- /dev/null +++ b/drivers/media/video/saa7164/Kconfig | |||
@@ -0,0 +1,18 @@ | |||
1 | config VIDEO_SAA7164 | ||
2 | tristate "NXP SAA7164 support" | ||
3 | depends on DVB_CORE && PCI && I2C | ||
4 | select I2C_ALGOBIT | ||
5 | select FW_LOADER | ||
6 | select VIDEO_TUNER | ||
7 | select VIDEO_TVEEPROM | ||
8 | select VIDEOBUF_DVB | ||
9 | select DVB_TDA10048 if !DVB_FE_CUSTOMISE | ||
10 | select DVB_S5H1411 if !DVB_FE_CUSTOMISE | ||
11 | select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE | ||
12 | ---help--- | ||
13 | This is a video4linux driver for NXP SAA7164 based | ||
14 | TV cards. | ||
15 | |||
16 | To compile this driver as a module, choose M here: the | ||
17 | module will be called saa7164 | ||
18 | |||
diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile new file mode 100644 index 000000000000..4b329fd42add --- /dev/null +++ b/drivers/media/video/saa7164/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ | ||
2 | saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \ | ||
3 | saa7164-buffer.o | ||
4 | |||
5 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o | ||
6 | |||
7 | EXTRA_CFLAGS += -Idrivers/media/video | ||
8 | EXTRA_CFLAGS += -Idrivers/media/common/tuners | ||
9 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core | ||
10 | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends | ||
11 | |||
12 | EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) | ||
diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c new file mode 100644 index 000000000000..bb6df1b276be --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-api.c | |||
@@ -0,0 +1,600 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/wait.h> | ||
23 | |||
24 | #include "saa7164.h" | ||
25 | |||
26 | int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode) | ||
27 | { | ||
28 | int ret; | ||
29 | |||
30 | ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR, | ||
31 | SAA_STATE_CONTROL, sizeof(mode), &mode); | ||
32 | if (ret != SAA_OK) | ||
33 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
34 | |||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version) | ||
39 | { | ||
40 | int ret; | ||
41 | |||
42 | ret = saa7164_cmd_send(dev, 0, GET_CUR, | ||
43 | GET_FW_VERSION_CONTROL, sizeof(u32), version); | ||
44 | if (ret != SAA_OK) | ||
45 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
46 | |||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen) | ||
51 | { | ||
52 | u8 reg[] = { 0x0f, 0x00 }; | ||
53 | |||
54 | if (buflen < 128) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */ | ||
58 | /* TODO: Pull the details from the boards struct */ | ||
59 | return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg), | ||
60 | ®[0], 128, buf); | ||
61 | } | ||
62 | |||
63 | |||
64 | int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, | ||
65 | struct saa7164_tsport *port, | ||
66 | tmComResTSFormatDescrHeader_t *tsfmt) | ||
67 | { | ||
68 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex); | ||
69 | dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset); | ||
70 | dprintk(DBGLVL_API, " bPacketLength= 0x%x\n", tsfmt->bPacketLength); | ||
71 | dprintk(DBGLVL_API, " bStrideLength= 0x%x\n", tsfmt->bStrideLength); | ||
72 | dprintk(DBGLVL_API, " bguid = (....)\n"); | ||
73 | |||
74 | /* Cache the hardware configuration in the port */ | ||
75 | |||
76 | port->bufcounter = port->hwcfg.BARLocation; | ||
77 | port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); | ||
78 | port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); | ||
79 | port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); | ||
80 | port->bufptr32l = port->hwcfg.BARLocation + | ||
81 | (4 * sizeof(u32)) + | ||
82 | (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); | ||
83 | port->bufptr32h = port->hwcfg.BARLocation + | ||
84 | (4 * sizeof(u32)) + | ||
85 | (sizeof(u32) * port->hwcfg.buffercount); | ||
86 | port->bufptr64 = port->hwcfg.BARLocation + | ||
87 | (4 * sizeof(u32)) + | ||
88 | (sizeof(u32) * port->hwcfg.buffercount); | ||
89 | dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n", | ||
90 | port->hwcfg.BARLocation); | ||
91 | |||
92 | dprintk(DBGLVL_API, " = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n", | ||
93 | port->nr); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | ||
99 | { | ||
100 | struct saa7164_tsport *port = 0; | ||
101 | u32 idx, next_offset; | ||
102 | int i; | ||
103 | tmComResDescrHeader_t *hdr, *t; | ||
104 | tmComResExtDevDescrHeader_t *exthdr; | ||
105 | tmComResPathDescrHeader_t *pathhdr; | ||
106 | tmComResAntTermDescrHeader_t *anttermhdr; | ||
107 | tmComResTunerDescrHeader_t *tunerunithdr; | ||
108 | tmComResDMATermDescrHeader_t *vcoutputtermhdr; | ||
109 | tmComResTSFormatDescrHeader_t *tsfmt; | ||
110 | u32 currpath = 0; | ||
111 | |||
112 | dprintk(DBGLVL_API, | ||
113 | "%s(?,?,%d) sizeof(tmComResDescrHeader_t) = %d bytes\n", | ||
114 | __func__, len, (u32)sizeof(tmComResDescrHeader_t)); | ||
115 | |||
116 | for (idx = 0; idx < (len - sizeof(tmComResDescrHeader_t)); ) { | ||
117 | |||
118 | hdr = (tmComResDescrHeader_t *)(buf + idx); | ||
119 | |||
120 | if (hdr->type != CS_INTERFACE) | ||
121 | return SAA_ERR_NOT_SUPPORTED; | ||
122 | |||
123 | dprintk(DBGLVL_API, "@ 0x%x = \n", idx); | ||
124 | switch (hdr->subtype) { | ||
125 | case GENERAL_REQUEST: | ||
126 | dprintk(DBGLVL_API, " GENERAL_REQUEST\n"); | ||
127 | break; | ||
128 | case VC_TUNER_PATH: | ||
129 | dprintk(DBGLVL_API, " VC_TUNER_PATH\n"); | ||
130 | pathhdr = (tmComResPathDescrHeader_t *)(buf + idx); | ||
131 | dprintk(DBGLVL_API, " pathid = 0x%x\n", | ||
132 | pathhdr->pathid); | ||
133 | currpath = pathhdr->pathid; | ||
134 | break; | ||
135 | case VC_INPUT_TERMINAL: | ||
136 | dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n"); | ||
137 | anttermhdr = | ||
138 | (tmComResAntTermDescrHeader_t *)(buf + idx); | ||
139 | dprintk(DBGLVL_API, " terminalid = 0x%x\n", | ||
140 | anttermhdr->terminalid); | ||
141 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n", | ||
142 | anttermhdr->terminaltype); | ||
143 | switch (anttermhdr->terminaltype) { | ||
144 | case ITT_ANTENNA: | ||
145 | dprintk(DBGLVL_API, " = ITT_ANTENNA\n"); | ||
146 | break; | ||
147 | case LINE_CONNECTOR: | ||
148 | dprintk(DBGLVL_API, " = LINE_CONNECTOR\n"); | ||
149 | break; | ||
150 | case SPDIF_CONNECTOR: | ||
151 | dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n"); | ||
152 | break; | ||
153 | case COMPOSITE_CONNECTOR: | ||
154 | dprintk(DBGLVL_API, | ||
155 | " = COMPOSITE_CONNECTOR\n"); | ||
156 | break; | ||
157 | case SVIDEO_CONNECTOR: | ||
158 | dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n"); | ||
159 | break; | ||
160 | case COMPONENT_CONNECTOR: | ||
161 | dprintk(DBGLVL_API, | ||
162 | " = COMPONENT_CONNECTOR\n"); | ||
163 | break; | ||
164 | case STANDARD_DMA: | ||
165 | dprintk(DBGLVL_API, " = STANDARD_DMA\n"); | ||
166 | break; | ||
167 | default: | ||
168 | dprintk(DBGLVL_API, " = undefined (0x%x)\n", | ||
169 | anttermhdr->terminaltype); | ||
170 | } | ||
171 | dprintk(DBGLVL_API, " assocterminal= 0x%x\n", | ||
172 | anttermhdr->assocterminal); | ||
173 | dprintk(DBGLVL_API, " iterminal = 0x%x\n", | ||
174 | anttermhdr->iterminal); | ||
175 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", | ||
176 | anttermhdr->controlsize); | ||
177 | break; | ||
178 | case VC_OUTPUT_TERMINAL: | ||
179 | dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n"); | ||
180 | vcoutputtermhdr = | ||
181 | (tmComResDMATermDescrHeader_t *)(buf + idx); | ||
182 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | ||
183 | vcoutputtermhdr->unitid); | ||
184 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n", | ||
185 | vcoutputtermhdr->terminaltype); | ||
186 | switch (vcoutputtermhdr->terminaltype) { | ||
187 | case ITT_ANTENNA: | ||
188 | dprintk(DBGLVL_API, " = ITT_ANTENNA\n"); | ||
189 | break; | ||
190 | case LINE_CONNECTOR: | ||
191 | dprintk(DBGLVL_API, " = LINE_CONNECTOR\n"); | ||
192 | break; | ||
193 | case SPDIF_CONNECTOR: | ||
194 | dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n"); | ||
195 | break; | ||
196 | case COMPOSITE_CONNECTOR: | ||
197 | dprintk(DBGLVL_API, | ||
198 | " = COMPOSITE_CONNECTOR\n"); | ||
199 | break; | ||
200 | case SVIDEO_CONNECTOR: | ||
201 | dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n"); | ||
202 | break; | ||
203 | case COMPONENT_CONNECTOR: | ||
204 | dprintk(DBGLVL_API, | ||
205 | " = COMPONENT_CONNECTOR\n"); | ||
206 | break; | ||
207 | case STANDARD_DMA: | ||
208 | dprintk(DBGLVL_API, " = STANDARD_DMA\n"); | ||
209 | break; | ||
210 | default: | ||
211 | dprintk(DBGLVL_API, " = undefined (0x%x)\n", | ||
212 | vcoutputtermhdr->terminaltype); | ||
213 | } | ||
214 | dprintk(DBGLVL_API, " assocterminal= 0x%x\n", | ||
215 | vcoutputtermhdr->assocterminal); | ||
216 | dprintk(DBGLVL_API, " sourceid = 0x%x\n", | ||
217 | vcoutputtermhdr->sourceid); | ||
218 | dprintk(DBGLVL_API, " iterminal = 0x%x\n", | ||
219 | vcoutputtermhdr->iterminal); | ||
220 | dprintk(DBGLVL_API, " BARLocation = 0x%x\n", | ||
221 | vcoutputtermhdr->BARLocation); | ||
222 | dprintk(DBGLVL_API, " flags = 0x%x\n", | ||
223 | vcoutputtermhdr->flags); | ||
224 | dprintk(DBGLVL_API, " interruptid = 0x%x\n", | ||
225 | vcoutputtermhdr->interruptid); | ||
226 | dprintk(DBGLVL_API, " buffercount = 0x%x\n", | ||
227 | vcoutputtermhdr->buffercount); | ||
228 | dprintk(DBGLVL_API, " metadatasize = 0x%x\n", | ||
229 | vcoutputtermhdr->metadatasize); | ||
230 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", | ||
231 | vcoutputtermhdr->controlsize); | ||
232 | dprintk(DBGLVL_API, " numformats = 0x%x\n", | ||
233 | vcoutputtermhdr->numformats); | ||
234 | |||
235 | t = (tmComResDescrHeader_t *) | ||
236 | ((tmComResDMATermDescrHeader_t *)(buf + idx)); | ||
237 | next_offset = idx + (vcoutputtermhdr->len); | ||
238 | for (i = 0; i < vcoutputtermhdr->numformats; i++) { | ||
239 | t = (tmComResDescrHeader_t *) | ||
240 | (buf + next_offset); | ||
241 | switch (t->subtype) { | ||
242 | case VS_FORMAT_MPEG2TS: | ||
243 | tsfmt = | ||
244 | (tmComResTSFormatDescrHeader_t *)t; | ||
245 | if (currpath == 1) | ||
246 | port = &dev->ts1; | ||
247 | else | ||
248 | port = &dev->ts2; | ||
249 | memcpy(&port->hwcfg, vcoutputtermhdr, | ||
250 | sizeof(*vcoutputtermhdr)); | ||
251 | saa7164_api_configure_port_mpeg2ts(dev, | ||
252 | port, tsfmt); | ||
253 | break; | ||
254 | case VS_FORMAT_MPEG2PS: | ||
255 | dprintk(DBGLVL_API, | ||
256 | " = VS_FORMAT_MPEG2PS\n"); | ||
257 | break; | ||
258 | case VS_FORMAT_VBI: | ||
259 | dprintk(DBGLVL_API, | ||
260 | " = VS_FORMAT_VBI\n"); | ||
261 | break; | ||
262 | case VS_FORMAT_RDS: | ||
263 | dprintk(DBGLVL_API, | ||
264 | " = VS_FORMAT_RDS\n"); | ||
265 | break; | ||
266 | case VS_FORMAT_UNCOMPRESSED: | ||
267 | dprintk(DBGLVL_API, | ||
268 | " = VS_FORMAT_UNCOMPRESSED\n"); | ||
269 | break; | ||
270 | case VS_FORMAT_TYPE: | ||
271 | dprintk(DBGLVL_API, | ||
272 | " = VS_FORMAT_TYPE\n"); | ||
273 | break; | ||
274 | default: | ||
275 | dprintk(DBGLVL_API, | ||
276 | " = undefined (0x%x)\n", | ||
277 | t->subtype); | ||
278 | } | ||
279 | next_offset += t->len; | ||
280 | } | ||
281 | |||
282 | break; | ||
283 | case TUNER_UNIT: | ||
284 | dprintk(DBGLVL_API, " TUNER_UNIT\n"); | ||
285 | tunerunithdr = | ||
286 | (tmComResTunerDescrHeader_t *)(buf + idx); | ||
287 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | ||
288 | tunerunithdr->unitid); | ||
289 | dprintk(DBGLVL_API, " sourceid = 0x%x\n", | ||
290 | tunerunithdr->sourceid); | ||
291 | dprintk(DBGLVL_API, " iunit = 0x%x\n", | ||
292 | tunerunithdr->iunit); | ||
293 | dprintk(DBGLVL_API, " tuningstandards = 0x%x\n", | ||
294 | tunerunithdr->tuningstandards); | ||
295 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", | ||
296 | tunerunithdr->controlsize); | ||
297 | dprintk(DBGLVL_API, " controls = 0x%x\n", | ||
298 | tunerunithdr->controls); | ||
299 | break; | ||
300 | case VC_SELECTOR_UNIT: | ||
301 | dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n"); | ||
302 | break; | ||
303 | case VC_PROCESSING_UNIT: | ||
304 | dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n"); | ||
305 | break; | ||
306 | case FEATURE_UNIT: | ||
307 | dprintk(DBGLVL_API, " FEATURE_UNIT\n"); | ||
308 | break; | ||
309 | case ENCODER_UNIT: | ||
310 | dprintk(DBGLVL_API, " ENCODER_UNIT\n"); | ||
311 | break; | ||
312 | case EXTENSION_UNIT: | ||
313 | dprintk(DBGLVL_API, " EXTENSION_UNIT\n"); | ||
314 | exthdr = (tmComResExtDevDescrHeader_t *)(buf + idx); | ||
315 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | ||
316 | exthdr->unitid); | ||
317 | dprintk(DBGLVL_API, " deviceid = 0x%x\n", | ||
318 | exthdr->deviceid); | ||
319 | dprintk(DBGLVL_API, " devicetype = 0x%x\n", | ||
320 | exthdr->devicetype); | ||
321 | if (exthdr->devicetype & 0x1) | ||
322 | dprintk(DBGLVL_API, " = Decoder Device\n"); | ||
323 | if (exthdr->devicetype & 0x2) | ||
324 | dprintk(DBGLVL_API, " = GPIO Source\n"); | ||
325 | if (exthdr->devicetype & 0x4) | ||
326 | dprintk(DBGLVL_API, " = Video Decoder\n"); | ||
327 | if (exthdr->devicetype & 0x8) | ||
328 | dprintk(DBGLVL_API, " = Audio Decoder\n"); | ||
329 | if (exthdr->devicetype & 0x20) | ||
330 | dprintk(DBGLVL_API, " = Crossbar\n"); | ||
331 | if (exthdr->devicetype & 0x40) | ||
332 | dprintk(DBGLVL_API, " = Tuner\n"); | ||
333 | if (exthdr->devicetype & 0x80) | ||
334 | dprintk(DBGLVL_API, " = IF PLL\n"); | ||
335 | if (exthdr->devicetype & 0x100) | ||
336 | dprintk(DBGLVL_API, " = Demodulator\n"); | ||
337 | if (exthdr->devicetype & 0x200) | ||
338 | dprintk(DBGLVL_API, " = RDS Decoder\n"); | ||
339 | if (exthdr->devicetype & 0x400) | ||
340 | dprintk(DBGLVL_API, " = Encoder\n"); | ||
341 | if (exthdr->devicetype & 0x800) | ||
342 | dprintk(DBGLVL_API, " = IR Decoder\n"); | ||
343 | if (exthdr->devicetype & 0x1000) | ||
344 | dprintk(DBGLVL_API, " = EEPROM\n"); | ||
345 | if (exthdr->devicetype & 0x2000) | ||
346 | dprintk(DBGLVL_API, | ||
347 | " = VBI Decoder\n"); | ||
348 | if (exthdr->devicetype & 0x10000) | ||
349 | dprintk(DBGLVL_API, | ||
350 | " = Streaming Device\n"); | ||
351 | if (exthdr->devicetype & 0x20000) | ||
352 | dprintk(DBGLVL_API, | ||
353 | " = DRM Device\n"); | ||
354 | if (exthdr->devicetype & 0x40000000) | ||
355 | dprintk(DBGLVL_API, | ||
356 | " = Generic Device\n"); | ||
357 | if (exthdr->devicetype & 0x80000000) | ||
358 | dprintk(DBGLVL_API, | ||
359 | " = Config Space Device\n"); | ||
360 | dprintk(DBGLVL_API, " numgpiopins = 0x%x\n", | ||
361 | exthdr->numgpiopins); | ||
362 | dprintk(DBGLVL_API, " numgpiogroups = 0x%x\n", | ||
363 | exthdr->numgpiogroups); | ||
364 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", | ||
365 | exthdr->controlsize); | ||
366 | break; | ||
367 | case PVC_INFRARED_UNIT: | ||
368 | dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n"); | ||
369 | break; | ||
370 | case DRM_UNIT: | ||
371 | dprintk(DBGLVL_API, " DRM_UNIT\n"); | ||
372 | break; | ||
373 | default: | ||
374 | dprintk(DBGLVL_API, "default %d\n", hdr->subtype); | ||
375 | } | ||
376 | |||
377 | dprintk(DBGLVL_API, " 1.%x\n", hdr->len); | ||
378 | dprintk(DBGLVL_API, " 2.%x\n", hdr->type); | ||
379 | dprintk(DBGLVL_API, " 3.%x\n", hdr->subtype); | ||
380 | dprintk(DBGLVL_API, " 4.%x\n", hdr->unitid); | ||
381 | |||
382 | idx += hdr->len; | ||
383 | } | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | int saa7164_api_enum_subdevs(struct saa7164_dev *dev) | ||
389 | { | ||
390 | int ret; | ||
391 | u32 buflen = 0; | ||
392 | u8 *buf; | ||
393 | |||
394 | dprintk(DBGLVL_API, "%s()\n", __func__); | ||
395 | |||
396 | /* Get the total descriptor length */ | ||
397 | ret = saa7164_cmd_send(dev, 0, GET_LEN, | ||
398 | GET_DESCRIPTORS_CONTROL, sizeof(buflen), &buflen); | ||
399 | if (ret != SAA_OK) | ||
400 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
401 | |||
402 | dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n", | ||
403 | __func__, buflen); | ||
404 | |||
405 | /* Allocate enough storage for all of the descs */ | ||
406 | buf = kzalloc(buflen, GFP_KERNEL); | ||
407 | if (buf == NULL) | ||
408 | return SAA_ERR_NO_RESOURCES; | ||
409 | |||
410 | /* Retrieve them */ | ||
411 | ret = saa7164_cmd_send(dev, 0, GET_CUR, | ||
412 | GET_DESCRIPTORS_CONTROL, buflen, buf); | ||
413 | if (ret != SAA_OK) { | ||
414 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
415 | goto out; | ||
416 | } | ||
417 | |||
418 | if (debug & DBGLVL_API) | ||
419 | saa7164_dumphex16(dev, buf, (buflen/16)*16); | ||
420 | |||
421 | saa7164_api_dump_subdevs(dev, buf, buflen); | ||
422 | |||
423 | out: | ||
424 | kfree(buf); | ||
425 | return ret; | ||
426 | } | ||
427 | |||
428 | int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, | ||
429 | u32 datalen, u8 *data) | ||
430 | { | ||
431 | struct saa7164_dev *dev = bus->dev; | ||
432 | u16 len = 0; | ||
433 | int unitid; | ||
434 | u32 regval; | ||
435 | u8 buf[256]; | ||
436 | int ret; | ||
437 | |||
438 | dprintk(DBGLVL_API, "%s()\n", __func__); | ||
439 | |||
440 | if (reglen > 4) | ||
441 | return -EIO; | ||
442 | |||
443 | if (reglen == 1) | ||
444 | regval = *(reg); | ||
445 | else | ||
446 | if (reglen == 2) | ||
447 | regval = ((*(reg) << 8) || *(reg+1)); | ||
448 | else | ||
449 | if (reglen == 3) | ||
450 | regval = ((*(reg) << 16) | (*(reg+1) << 8) | *(reg+2)); | ||
451 | else | ||
452 | if (reglen == 4) | ||
453 | regval = ((*(reg) << 24) | (*(reg+1) << 16) | | ||
454 | (*(reg+2) << 8) | *(reg+3)); | ||
455 | |||
456 | /* Prepare the send buffer */ | ||
457 | /* Bytes 00-03 source register length | ||
458 | * 04-07 source bytes to read | ||
459 | * 08... register address | ||
460 | */ | ||
461 | memset(buf, 0, sizeof(buf)); | ||
462 | memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen); | ||
463 | *((u32 *)(buf + 0 * sizeof(u32))) = reglen; | ||
464 | *((u32 *)(buf + 1 * sizeof(u32))) = datalen; | ||
465 | |||
466 | unitid = saa7164_i2caddr_to_unitid(bus, addr); | ||
467 | if (unitid < 0) { | ||
468 | printk(KERN_ERR | ||
469 | "%s() error, cannot translate regaddr 0x%x to unitid\n", | ||
470 | __func__, addr); | ||
471 | return -EIO; | ||
472 | } | ||
473 | |||
474 | ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN, | ||
475 | EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len); | ||
476 | if (ret != SAA_OK) { | ||
477 | printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret); | ||
478 | return -EIO; | ||
479 | } | ||
480 | |||
481 | dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len); | ||
482 | |||
483 | if (debug & DBGLVL_I2C) | ||
484 | saa7164_dumphex16(dev, buf, 2 * 16); | ||
485 | |||
486 | ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR, | ||
487 | EXU_REGISTER_ACCESS_CONTROL, len, &buf); | ||
488 | if (ret != SAA_OK) | ||
489 | printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret); | ||
490 | else { | ||
491 | if (debug & DBGLVL_I2C) | ||
492 | saa7164_dumphex16(dev, buf, sizeof(buf)); | ||
493 | memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen); | ||
494 | } | ||
495 | |||
496 | return ret == SAA_OK ? 0 : -EIO; | ||
497 | } | ||
498 | |||
499 | /* For a given 8 bit i2c address device, write the buffer */ | ||
500 | int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, | ||
501 | u8 *data) | ||
502 | { | ||
503 | struct saa7164_dev *dev = bus->dev; | ||
504 | u16 len = 0; | ||
505 | int unitid; | ||
506 | int reglen; | ||
507 | u8 buf[256]; | ||
508 | int ret; | ||
509 | |||
510 | dprintk(DBGLVL_API, "%s()\n", __func__); | ||
511 | |||
512 | if ((datalen == 0) || (datalen > 232)) | ||
513 | return -EIO; | ||
514 | |||
515 | memset(buf, 0, sizeof(buf)); | ||
516 | |||
517 | unitid = saa7164_i2caddr_to_unitid(bus, addr); | ||
518 | if (unitid < 0) { | ||
519 | printk(KERN_ERR | ||
520 | "%s() error, cannot translate regaddr 0x%x to unitid\n", | ||
521 | __func__, addr); | ||
522 | return -EIO; | ||
523 | } | ||
524 | |||
525 | reglen = saa7164_i2caddr_to_reglen(bus, addr); | ||
526 | if (unitid < 0) { | ||
527 | printk(KERN_ERR | ||
528 | "%s() error, cannot translate regaddr to reglen\n", | ||
529 | __func__); | ||
530 | return -EIO; | ||
531 | } | ||
532 | |||
533 | ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN, | ||
534 | EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len); | ||
535 | if (ret != SAA_OK) { | ||
536 | printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret); | ||
537 | return -EIO; | ||
538 | } | ||
539 | |||
540 | dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len); | ||
541 | |||
542 | /* Prepare the send buffer */ | ||
543 | /* Bytes 00-03 dest register length | ||
544 | * 04-07 dest bytes to write | ||
545 | * 08... register address | ||
546 | */ | ||
547 | *((u32 *)(buf + 0 * sizeof(u32))) = reglen; | ||
548 | *((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen; | ||
549 | memcpy((buf + 2 * sizeof(u32)), data, datalen); | ||
550 | |||
551 | if (debug & DBGLVL_I2C) | ||
552 | saa7164_dumphex16(dev, buf, sizeof(buf)); | ||
553 | |||
554 | ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR, | ||
555 | EXU_REGISTER_ACCESS_CONTROL, len, &buf); | ||
556 | if (ret != SAA_OK) | ||
557 | printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret); | ||
558 | |||
559 | return ret == SAA_OK ? 0 : -EIO; | ||
560 | } | ||
561 | |||
562 | |||
563 | int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid, | ||
564 | u8 pin, u8 state) | ||
565 | { | ||
566 | int ret; | ||
567 | tmComResGPIO_t t; | ||
568 | |||
569 | dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n", | ||
570 | __func__, unitid, pin, state); | ||
571 | |||
572 | if ((pin > 7) || (state > 2)) | ||
573 | return SAA_ERR_BAD_PARAMETER; | ||
574 | |||
575 | t.pin = pin; | ||
576 | t.state = state; | ||
577 | |||
578 | ret = saa7164_cmd_send(dev, unitid, SET_CUR, | ||
579 | EXU_GPIO_CONTROL, sizeof(t), &t); | ||
580 | if (ret != SAA_OK) | ||
581 | printk(KERN_ERR "%s() error, ret = 0x%x\n", | ||
582 | __func__, ret); | ||
583 | |||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, | ||
588 | u8 pin) | ||
589 | { | ||
590 | return saa7164_api_modify_gpio(dev, unitid, pin, 1); | ||
591 | } | ||
592 | |||
593 | int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, | ||
594 | u8 pin) | ||
595 | { | ||
596 | return saa7164_api_modify_gpio(dev, unitid, pin, 0); | ||
597 | } | ||
598 | |||
599 | |||
600 | |||
diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/video/saa7164/saa7164-buffer.c new file mode 100644 index 000000000000..9ca5c83d165b --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-buffer.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "saa7164.h" | ||
23 | |||
24 | /* The PCI address space for buffer handling looks like this: | ||
25 | |||
26 | +-u32 wide-------------+ | ||
27 | | + | ||
28 | +-u64 wide------------------------------------+ | ||
29 | + + | ||
30 | +----------------------+ | ||
31 | | CurrentBufferPtr + Pointer to current PCI buffer >-+ | ||
32 | +----------------------+ | | ||
33 | | Unused + | | ||
34 | +----------------------+ | | ||
35 | | Pitch + = 188 (bytes) | | ||
36 | +----------------------+ | | ||
37 | | PCI buffer size + = pitch * number of lines (312) | | ||
38 | +----------------------+ | | ||
39 | |0| Buf0 Write Offset + | | ||
40 | +----------------------+ v | ||
41 | |1| Buf1 Write Offset + | | ||
42 | +----------------------+ | | ||
43 | |2| Buf2 Write Offset + | | ||
44 | +----------------------+ | | ||
45 | |3| Buf3 Write Offset + | | ||
46 | +----------------------+ | | ||
47 | ... More write offsets | | ||
48 | +---------------------------------------------+ | | ||
49 | +0| set of ptrs to PCI pagetables + | | ||
50 | +---------------------------------------------+ | | ||
51 | +1| set of ptrs to PCI pagetables + <--------+ | ||
52 | +---------------------------------------------+ | ||
53 | +2| set of ptrs to PCI pagetables + | ||
54 | +---------------------------------------------+ | ||
55 | +3| set of ptrs to PCI pagetables + >--+ | ||
56 | +---------------------------------------------+ | | ||
57 | ... More buffer pointers | +----------------+ | ||
58 | +->| pt[0] TS data | | ||
59 | | +----------------+ | ||
60 | | | ||
61 | | +----------------+ | ||
62 | +->| pt[1] TS data | | ||
63 | | +----------------+ | ||
64 | | etc | ||
65 | */ | ||
66 | |||
67 | /* Allocate a new buffer structure and associated PCI space in bytes. | ||
68 | * len must be a multiple of sizeof(u64) | ||
69 | */ | ||
70 | struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port, | ||
71 | u32 len) | ||
72 | { | ||
73 | struct saa7164_buffer *buf = 0; | ||
74 | struct saa7164_dev *dev = port->dev; | ||
75 | int i; | ||
76 | |||
77 | if ((len == 0) || (len >= 65536) || (len % sizeof(u64))) { | ||
78 | log_warn("%s() SAA_ERR_BAD_PARAMETER\n", __func__); | ||
79 | goto ret; | ||
80 | } | ||
81 | |||
82 | buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL); | ||
83 | if (buf == NULL) { | ||
84 | log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__); | ||
85 | goto ret; | ||
86 | } | ||
87 | |||
88 | buf->port = port; | ||
89 | buf->flags = SAA7164_BUFFER_FREE; | ||
90 | /* TODO: arg len is being ignored */ | ||
91 | buf->pci_size = SAA7164_PT_ENTRIES * 0x1000; | ||
92 | buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000; | ||
93 | |||
94 | /* Allocate contiguous memory */ | ||
95 | buf->cpu = pci_alloc_consistent(port->dev->pci, buf->pci_size, | ||
96 | &buf->dma); | ||
97 | if (!buf->cpu) | ||
98 | goto fail1; | ||
99 | |||
100 | buf->pt_cpu = pci_alloc_consistent(port->dev->pci, buf->pt_size, | ||
101 | &buf->pt_dma); | ||
102 | if (!buf->pt_cpu) | ||
103 | goto fail2; | ||
104 | |||
105 | /* init the buffers to a known pattern, easier during debugging */ | ||
106 | memset(buf->cpu, 0xff, buf->pci_size); | ||
107 | memset(buf->pt_cpu, 0xff, buf->pt_size); | ||
108 | |||
109 | dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p\n", __func__, buf); | ||
110 | dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08lx len = 0x%x\n", | ||
111 | buf->cpu, (long)buf->dma, buf->pci_size); | ||
112 | dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n", | ||
113 | buf->pt_cpu, (long)buf->pt_dma, buf->pt_size); | ||
114 | |||
115 | /* Format the Page Table Entries to point into the data buffer */ | ||
116 | for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) { | ||
117 | |||
118 | *(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */ | ||
119 | |||
120 | } | ||
121 | |||
122 | goto ret; | ||
123 | |||
124 | fail2: | ||
125 | pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma); | ||
126 | fail1: | ||
127 | kfree(buf); | ||
128 | |||
129 | buf = 0; | ||
130 | ret: | ||
131 | return buf; | ||
132 | } | ||
133 | |||
134 | int saa7164_buffer_dealloc(struct saa7164_tsport *port, | ||
135 | struct saa7164_buffer *buf) | ||
136 | { | ||
137 | struct saa7164_dev *dev = port->dev; | ||
138 | |||
139 | if ((buf == 0) || (port == 0)) | ||
140 | return SAA_ERR_BAD_PARAMETER; | ||
141 | |||
142 | dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n", __func__, buf); | ||
143 | |||
144 | if (buf->flags != SAA7164_BUFFER_FREE) | ||
145 | log_warn(" freeing a non-free buffer\n"); | ||
146 | |||
147 | pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma); | ||
148 | pci_free_consistent(port->dev->pci, buf->pt_size, buf->pt_cpu, | ||
149 | buf->pt_dma); | ||
150 | |||
151 | kfree(buf); | ||
152 | |||
153 | return SAA_OK; | ||
154 | } | ||
155 | |||
diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c new file mode 100644 index 000000000000..83a04640a25a --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-bus.c | |||
@@ -0,0 +1,448 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "saa7164.h" | ||
23 | |||
24 | /* The message bus to/from the firmware is a ring buffer in PCI address | ||
25 | * space. Establish the defaults. | ||
26 | */ | ||
27 | int saa7164_bus_setup(struct saa7164_dev *dev) | ||
28 | { | ||
29 | tmComResBusInfo_t *b = &dev->bus; | ||
30 | |||
31 | mutex_init(&b->lock); | ||
32 | |||
33 | b->Type = TYPE_BUS_PCIe; | ||
34 | b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE; | ||
35 | |||
36 | b->m_pdwSetRing = (u8 *)(dev->bmmio + | ||
37 | ((u32)dev->busdesc.CommandRing)); | ||
38 | |||
39 | b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE; | ||
40 | |||
41 | b->m_pdwGetRing = (u8 *)(dev->bmmio + | ||
42 | ((u32)dev->busdesc.ResponseRing)); | ||
43 | |||
44 | b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE; | ||
45 | |||
46 | b->m_pdwSetWritePos = (u32 *)((u8 *)(dev->bmmio + | ||
47 | ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64)))); | ||
48 | |||
49 | b->m_pdwSetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos + | ||
50 | 1 * sizeof(u32)); | ||
51 | |||
52 | b->m_pdwGetWritePos = (u32 *)((u8 *)b->m_pdwSetWritePos + | ||
53 | 2 * sizeof(u32)); | ||
54 | |||
55 | b->m_pdwGetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos + | ||
56 | 3 * sizeof(u32)); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | void saa7164_bus_dump(struct saa7164_dev *dev) | ||
62 | { | ||
63 | tmComResBusInfo_t *b = &dev->bus; | ||
64 | |||
65 | dprintk(DBGLVL_BUS, "Dumping the bus structure:\n"); | ||
66 | dprintk(DBGLVL_BUS, " .type = %d\n", b->Type); | ||
67 | dprintk(DBGLVL_BUS, " .dev->bmmio = 0x%p\n", dev->bmmio); | ||
68 | dprintk(DBGLVL_BUS, " .m_wMaxReqSize = 0x%x\n", b->m_wMaxReqSize); | ||
69 | dprintk(DBGLVL_BUS, " .m_pdwSetRing = 0x%p\n", b->m_pdwSetRing); | ||
70 | dprintk(DBGLVL_BUS, " .m_dwSizeSetRing = 0x%x\n", b->m_dwSizeSetRing); | ||
71 | dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing); | ||
72 | dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing); | ||
73 | |||
74 | dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n", | ||
75 | b->m_pdwSetWritePos, *b->m_pdwSetWritePos); | ||
76 | |||
77 | dprintk(DBGLVL_BUS, " .m_pdwSetReadPos = 0x%p (0x%08x)\n", | ||
78 | b->m_pdwSetReadPos, *b->m_pdwSetReadPos); | ||
79 | |||
80 | dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n", | ||
81 | b->m_pdwGetWritePos, *b->m_pdwGetWritePos); | ||
82 | |||
83 | dprintk(DBGLVL_BUS, " .m_pdwGetReadPos = 0x%p (0x%08x)\n", | ||
84 | b->m_pdwGetReadPos, *b->m_pdwGetReadPos); | ||
85 | } | ||
86 | |||
87 | void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf) | ||
88 | { | ||
89 | dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); | ||
90 | dprintk(DBGLVL_BUS, " .id = %d\n", m->id); | ||
91 | dprintk(DBGLVL_BUS, " .flags = 0x%x\n", m->flags); | ||
92 | dprintk(DBGLVL_BUS, " .size = 0x%x\n", m->size); | ||
93 | dprintk(DBGLVL_BUS, " .command = 0x%x\n", m->command); | ||
94 | dprintk(DBGLVL_BUS, " .controlselector = 0x%x\n", m->controlselector); | ||
95 | dprintk(DBGLVL_BUS, " .seqno = %d\n", m->seqno); | ||
96 | if (buf) | ||
97 | dprintk(DBGLVL_BUS, " .buffer (ignored)\n"); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Places a command or a response on the bus. The implementation does not | ||
102 | * know if it is a command or a response it just places the data on the | ||
103 | * bus depending on the bus information given in the tmComResBusInfo_t | ||
104 | * structure. If the command or response does not fit into the bus ring | ||
105 | * buffer it will be refused. | ||
106 | * | ||
107 | * Return Value: | ||
108 | * SAA_OK The function executed successfully. | ||
109 | * < 0 One or more members are not initialized. | ||
110 | */ | ||
111 | int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | ||
112 | { | ||
113 | tmComResBusInfo_t *bus = &dev->bus; | ||
114 | u32 bytes_to_write, read_distance, timeout, curr_srp, curr_swp; | ||
115 | u32 new_swp, space_rem; | ||
116 | int ret = SAA_ERR_BAD_PARAMETER; | ||
117 | |||
118 | if (!msg) { | ||
119 | printk(KERN_ERR "%s() !msg\n", __func__); | ||
120 | return SAA_ERR_BAD_PARAMETER; | ||
121 | } | ||
122 | |||
123 | dprintk(DBGLVL_BUS, "%s()\n", __func__); | ||
124 | |||
125 | msg->size = cpu_to_le16(msg->size); | ||
126 | msg->command = cpu_to_le16(msg->command); | ||
127 | msg->controlselector = cpu_to_le16(msg->controlselector); | ||
128 | |||
129 | if (msg->size > dev->bus.m_wMaxReqSize) { | ||
130 | printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", | ||
131 | __func__); | ||
132 | return SAA_ERR_BAD_PARAMETER; | ||
133 | } | ||
134 | |||
135 | if ((msg->size > 0) && (buf == 0)) { | ||
136 | printk(KERN_ERR "%s() Missing message buffer\n", __func__); | ||
137 | return SAA_ERR_BAD_PARAMETER; | ||
138 | } | ||
139 | |||
140 | /* Lock the bus from any other access */ | ||
141 | mutex_lock(&bus->lock); | ||
142 | |||
143 | bytes_to_write = sizeof(*msg) + msg->size; | ||
144 | read_distance = 0; | ||
145 | timeout = SAA_BUS_TIMEOUT; | ||
146 | curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos); | ||
147 | curr_swp = le32_to_cpu(*bus->m_pdwSetWritePos); | ||
148 | |||
149 | /* Deal with ring wrapping issues */ | ||
150 | if (curr_srp > curr_swp) | ||
151 | /* The ring has not wrapped yet */ | ||
152 | read_distance = curr_srp - curr_swp; | ||
153 | else | ||
154 | /* Deal with the wrapped ring */ | ||
155 | read_distance = (curr_srp + bus->m_dwSizeSetRing) - curr_swp; | ||
156 | |||
157 | dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__, | ||
158 | bytes_to_write); | ||
159 | |||
160 | dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__, | ||
161 | read_distance); | ||
162 | |||
163 | dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp); | ||
164 | dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp); | ||
165 | |||
166 | /* Process the msg and write the content onto the bus */ | ||
167 | while (bytes_to_write >= read_distance) { | ||
168 | |||
169 | if (timeout-- == 0) { | ||
170 | printk(KERN_ERR "%s() bus timeout\n", __func__); | ||
171 | ret = SAA_ERR_NO_RESOURCES; | ||
172 | goto out; | ||
173 | } | ||
174 | |||
175 | /* TODO: Review this delay, efficient? */ | ||
176 | /* Wait, allowing the hardware fetch time */ | ||
177 | mdelay(1); | ||
178 | |||
179 | /* Check the space usage again */ | ||
180 | curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos); | ||
181 | |||
182 | /* Deal with ring wrapping issues */ | ||
183 | if (curr_srp > curr_swp) | ||
184 | /* Read didn't wrap around the buffer */ | ||
185 | read_distance = curr_srp - curr_swp; | ||
186 | else | ||
187 | /* Deal with the wrapped ring */ | ||
188 | read_distance = (curr_srp + bus->m_dwSizeSetRing) - | ||
189 | curr_swp; | ||
190 | |||
191 | } | ||
192 | |||
193 | /* Calculate the new write position */ | ||
194 | new_swp = curr_swp + bytes_to_write; | ||
195 | |||
196 | dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); | ||
197 | dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__, | ||
198 | bus->m_dwSizeSetRing); | ||
199 | |||
200 | /* Mental Note: line 462 tmmhComResBusPCIe.cpp */ | ||
201 | |||
202 | /* Check if we're going to wrap again */ | ||
203 | if (new_swp > bus->m_dwSizeSetRing) { | ||
204 | |||
205 | /* Ring wraps */ | ||
206 | new_swp -= bus->m_dwSizeSetRing; | ||
207 | |||
208 | space_rem = bus->m_dwSizeSetRing - curr_swp; | ||
209 | |||
210 | dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__, | ||
211 | space_rem); | ||
212 | |||
213 | dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__, | ||
214 | (u32)sizeof(*msg)); | ||
215 | |||
216 | if (space_rem < sizeof(*msg)) { | ||
217 | dprintk(DBGLVL_BUS, "%s() tr4\n", __func__); | ||
218 | |||
219 | /* Split the msg into pieces as the ring wraps */ | ||
220 | memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem); | ||
221 | memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem, | ||
222 | sizeof(*msg) - space_rem); | ||
223 | |||
224 | memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem, | ||
225 | buf, msg->size); | ||
226 | |||
227 | } else if (space_rem == sizeof(*msg)) { | ||
228 | dprintk(DBGLVL_BUS, "%s() tr5\n", __func__); | ||
229 | |||
230 | /* Additional data at the beginning of the ring */ | ||
231 | memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); | ||
232 | memcpy(bus->m_pdwSetRing, buf, msg->size); | ||
233 | |||
234 | } else { | ||
235 | /* Additional data wraps around the ring */ | ||
236 | memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); | ||
237 | if (msg->size > 0) { | ||
238 | memcpy(bus->m_pdwSetRing + curr_swp + | ||
239 | sizeof(*msg), buf, space_rem - | ||
240 | sizeof(*msg)); | ||
241 | memcpy(bus->m_pdwSetRing, (u8 *)buf + | ||
242 | space_rem - sizeof(*msg), | ||
243 | bytes_to_write - space_rem); | ||
244 | } | ||
245 | |||
246 | } | ||
247 | |||
248 | } /* (new_swp > bus->m_dwSizeSetRing) */ | ||
249 | else { | ||
250 | dprintk(DBGLVL_BUS, "%s() tr6\n", __func__); | ||
251 | |||
252 | /* The ring buffer doesn't wrap, two simple copies */ | ||
253 | memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); | ||
254 | memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, | ||
255 | msg->size); | ||
256 | } | ||
257 | |||
258 | dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); | ||
259 | |||
260 | /* TODO: Convert all of the direct PCI writes into | ||
261 | * saa7164_writel/b calls for consistency. | ||
262 | */ | ||
263 | |||
264 | /* Update the bus write position */ | ||
265 | *bus->m_pdwSetWritePos = cpu_to_le32(new_swp); | ||
266 | ret = SAA_OK; | ||
267 | |||
268 | out: | ||
269 | mutex_unlock(&bus->lock); | ||
270 | return ret; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Receive a command or a response from the bus. The implementation does not | ||
275 | * know if it is a command or a response it simply dequeues the data, | ||
276 | * depending on the bus information given in the tmComResBusInfo_t structure. | ||
277 | * | ||
278 | * Return Value: | ||
279 | * 0 The function executed successfully. | ||
280 | * < 0 One or more members are not initialized. | ||
281 | */ | ||
282 | int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, | ||
283 | int peekonly) | ||
284 | { | ||
285 | tmComResBusInfo_t *bus = &dev->bus; | ||
286 | u32 bytes_to_read, write_distance, curr_grp, curr_gwp, | ||
287 | new_grp, buf_size, space_rem; | ||
288 | tmComResInfo_t msg_tmp; | ||
289 | int ret = SAA_ERR_BAD_PARAMETER; | ||
290 | |||
291 | if (msg == 0) | ||
292 | return ret; | ||
293 | |||
294 | if (msg->size > dev->bus.m_wMaxReqSize) { | ||
295 | printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", | ||
296 | __func__); | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | if ((peekonly == 0) && (msg->size > 0) && (buf == 0)) { | ||
301 | printk(KERN_ERR | ||
302 | "%s() Missing msg buf, size should be %d bytes\n", | ||
303 | __func__, msg->size); | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | mutex_lock(&bus->lock); | ||
308 | |||
309 | /* Peek the bus to see if a msg exists, if it's not what we're expecting | ||
310 | * then return cleanly else read the message from the bus. | ||
311 | */ | ||
312 | curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos); | ||
313 | curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos); | ||
314 | |||
315 | if (curr_gwp == curr_grp) { | ||
316 | dprintk(DBGLVL_BUS, "%s() No message on the bus\n", __func__); | ||
317 | ret = SAA_ERR_EMPTY; | ||
318 | goto out; | ||
319 | } | ||
320 | |||
321 | bytes_to_read = sizeof(*msg); | ||
322 | |||
323 | /* Calculate write distance to current read position */ | ||
324 | write_distance = 0; | ||
325 | if (curr_gwp >= curr_grp) | ||
326 | /* Write doesn't wrap around the ring */ | ||
327 | write_distance = curr_gwp - curr_grp; | ||
328 | else | ||
329 | /* Write wraps around the ring */ | ||
330 | write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; | ||
331 | |||
332 | if (bytes_to_read > write_distance) { | ||
333 | printk(KERN_ERR "%s() No message/response found\n", __func__); | ||
334 | ret = SAA_ERR_INVALID_COMMAND; | ||
335 | goto out; | ||
336 | } | ||
337 | |||
338 | /* Calculate the new read position */ | ||
339 | new_grp = curr_grp + bytes_to_read; | ||
340 | if (new_grp > bus->m_dwSizeGetRing) { | ||
341 | |||
342 | /* Ring wraps */ | ||
343 | new_grp -= bus->m_dwSizeGetRing; | ||
344 | space_rem = bus->m_dwSizeGetRing - curr_grp; | ||
345 | |||
346 | memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem); | ||
347 | memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing, | ||
348 | bytes_to_read - space_rem); | ||
349 | |||
350 | } else { | ||
351 | /* No wrapping */ | ||
352 | memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read); | ||
353 | } | ||
354 | |||
355 | /* No need to update the read positions, because this was a peek */ | ||
356 | /* If the caller specifically want to peek, return */ | ||
357 | if (peekonly) { | ||
358 | memcpy(msg, &msg_tmp, sizeof(*msg)); | ||
359 | goto peekout; | ||
360 | } | ||
361 | |||
362 | /* Check if the command/response matches what is expected */ | ||
363 | if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) || | ||
364 | (msg_tmp.controlselector != msg->controlselector) || | ||
365 | (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) { | ||
366 | |||
367 | printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__); | ||
368 | saa7164_bus_dumpmsg(dev, msg, buf); | ||
369 | saa7164_bus_dumpmsg(dev, &msg_tmp, 0); | ||
370 | ret = SAA_ERR_INVALID_COMMAND; | ||
371 | goto out; | ||
372 | } | ||
373 | |||
374 | /* Get the actual command and response from the bus */ | ||
375 | buf_size = msg->size; | ||
376 | |||
377 | bytes_to_read = sizeof(*msg) + msg->size; | ||
378 | /* Calculate write distance to current read position */ | ||
379 | write_distance = 0; | ||
380 | if (curr_gwp >= curr_grp) | ||
381 | /* Write doesn't wrap around the ring */ | ||
382 | write_distance = curr_gwp - curr_grp; | ||
383 | else | ||
384 | /* Write wraps around the ring */ | ||
385 | write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; | ||
386 | |||
387 | if (bytes_to_read > write_distance) { | ||
388 | printk(KERN_ERR "%s() Invalid bus state, missing msg " | ||
389 | "or mangled ring, faulty H/W / bad code?\n", __func__); | ||
390 | ret = SAA_ERR_INVALID_COMMAND; | ||
391 | goto out; | ||
392 | } | ||
393 | |||
394 | /* Calculate the new read position */ | ||
395 | new_grp = curr_grp + bytes_to_read; | ||
396 | if (new_grp > bus->m_dwSizeGetRing) { | ||
397 | |||
398 | /* Ring wraps */ | ||
399 | new_grp -= bus->m_dwSizeGetRing; | ||
400 | space_rem = bus->m_dwSizeGetRing - curr_grp; | ||
401 | |||
402 | if (space_rem < sizeof(*msg)) { | ||
403 | /* msg wraps around the ring */ | ||
404 | memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem); | ||
405 | memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing, | ||
406 | sizeof(*msg) - space_rem); | ||
407 | if (buf) | ||
408 | memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) - | ||
409 | space_rem, buf_size); | ||
410 | |||
411 | } else if (space_rem == sizeof(*msg)) { | ||
412 | memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); | ||
413 | if (buf) | ||
414 | memcpy(buf, bus->m_pdwGetRing, buf_size); | ||
415 | } else { | ||
416 | /* Additional data wraps around the ring */ | ||
417 | memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); | ||
418 | if (buf) { | ||
419 | memcpy(buf, bus->m_pdwGetRing + curr_grp + | ||
420 | sizeof(*msg), space_rem - sizeof(*msg)); | ||
421 | memcpy(buf + space_rem - sizeof(*msg), | ||
422 | bus->m_pdwGetRing, bytes_to_read - | ||
423 | space_rem); | ||
424 | } | ||
425 | |||
426 | } | ||
427 | |||
428 | } else { | ||
429 | /* No wrapping */ | ||
430 | memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); | ||
431 | if (buf) | ||
432 | memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), | ||
433 | buf_size); | ||
434 | } | ||
435 | |||
436 | /* Update the read positions, adjusting the ring */ | ||
437 | *bus->m_pdwGetReadPos = cpu_to_le32(new_grp); | ||
438 | |||
439 | peekout: | ||
440 | msg->size = le16_to_cpu(msg->size); | ||
441 | msg->command = le16_to_cpu(msg->command); | ||
442 | msg->controlselector = le16_to_cpu(msg->controlselector); | ||
443 | ret = SAA_OK; | ||
444 | out: | ||
445 | mutex_unlock(&bus->lock); | ||
446 | return ret; | ||
447 | } | ||
448 | |||
diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c new file mode 100644 index 000000000000..a3c299405f46 --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-cards.c | |||
@@ -0,0 +1,624 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/delay.h> | ||
26 | |||
27 | #include "saa7164.h" | ||
28 | |||
29 | /* The Bridge API needs to understand register widths (in bytes) for the | ||
30 | * attached I2C devices, so we can simplify the virtual i2c mechansms | ||
31 | * and keep the -i2c.c implementation clean. | ||
32 | */ | ||
33 | #define REGLEN_8bit 1 | ||
34 | #define REGLEN_16bit 2 | ||
35 | |||
36 | struct saa7164_board saa7164_boards[] = { | ||
37 | [SAA7164_BOARD_UNKNOWN] = { | ||
38 | /* Bridge will not load any firmware, without knowing | ||
39 | * the rev this would be fatal. */ | ||
40 | .name = "Unknown", | ||
41 | }, | ||
42 | [SAA7164_BOARD_UNKNOWN_REV2] = { | ||
43 | /* Bridge will load the v2 f/w and dump descriptors */ | ||
44 | /* Required during new board bringup */ | ||
45 | .name = "Generic Rev2", | ||
46 | .chiprev = SAA7164_CHIP_REV2, | ||
47 | }, | ||
48 | [SAA7164_BOARD_UNKNOWN_REV3] = { | ||
49 | /* Bridge will load the v2 f/w and dump descriptors */ | ||
50 | /* Required during new board bringup */ | ||
51 | .name = "Generic Rev3", | ||
52 | .chiprev = SAA7164_CHIP_REV3, | ||
53 | }, | ||
54 | [SAA7164_BOARD_HAUPPAUGE_HVR2200] = { | ||
55 | .name = "Hauppauge WinTV-HVR2200", | ||
56 | .porta = SAA7164_MPEG_DVB, | ||
57 | .portb = SAA7164_MPEG_DVB, | ||
58 | .chiprev = SAA7164_CHIP_REV3, | ||
59 | .unit = {{ | ||
60 | .id = 0x1d, | ||
61 | .type = SAA7164_UNIT_EEPROM, | ||
62 | .name = "4K EEPROM", | ||
63 | .i2c_bus_nr = SAA7164_I2C_BUS_0, | ||
64 | .i2c_bus_addr = 0xa0 >> 1, | ||
65 | .i2c_reg_len = REGLEN_8bit, | ||
66 | }, { | ||
67 | .id = 0x04, | ||
68 | .type = SAA7164_UNIT_TUNER, | ||
69 | .name = "TDA18271-1", | ||
70 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
71 | .i2c_bus_addr = 0xc0 >> 1, | ||
72 | .i2c_reg_len = REGLEN_8bit, | ||
73 | }, { | ||
74 | .id = 0x1b, | ||
75 | .type = SAA7164_UNIT_TUNER, | ||
76 | .name = "TDA18271-2", | ||
77 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
78 | .i2c_bus_addr = 0xc0 >> 1, | ||
79 | .i2c_reg_len = REGLEN_8bit, | ||
80 | }, { | ||
81 | .id = 0x1e, | ||
82 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
83 | .name = "TDA10048-1", | ||
84 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
85 | .i2c_bus_addr = 0x10 >> 1, | ||
86 | .i2c_reg_len = REGLEN_8bit, | ||
87 | }, { | ||
88 | .id = 0x1f, | ||
89 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
90 | .name = "TDA10048-2", | ||
91 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
92 | .i2c_bus_addr = 0x12 >> 1, | ||
93 | .i2c_reg_len = REGLEN_8bit, | ||
94 | } }, | ||
95 | }, | ||
96 | [SAA7164_BOARD_HAUPPAUGE_HVR2200_2] = { | ||
97 | .name = "Hauppauge WinTV-HVR2200", | ||
98 | .porta = SAA7164_MPEG_DVB, | ||
99 | .portb = SAA7164_MPEG_DVB, | ||
100 | .chiprev = SAA7164_CHIP_REV2, | ||
101 | .unit = {{ | ||
102 | .id = 0x06, | ||
103 | .type = SAA7164_UNIT_EEPROM, | ||
104 | .name = "4K EEPROM", | ||
105 | .i2c_bus_nr = SAA7164_I2C_BUS_0, | ||
106 | .i2c_bus_addr = 0xa0 >> 1, | ||
107 | .i2c_reg_len = REGLEN_8bit, | ||
108 | }, { | ||
109 | .id = 0x04, | ||
110 | .type = SAA7164_UNIT_TUNER, | ||
111 | .name = "TDA18271-1", | ||
112 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
113 | .i2c_bus_addr = 0xc0 >> 1, | ||
114 | .i2c_reg_len = REGLEN_8bit, | ||
115 | }, { | ||
116 | .id = 0x05, | ||
117 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
118 | .name = "TDA10048-1", | ||
119 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
120 | .i2c_bus_addr = 0x10 >> 1, | ||
121 | .i2c_reg_len = REGLEN_8bit, | ||
122 | }, { | ||
123 | .id = 0x1e, | ||
124 | .type = SAA7164_UNIT_TUNER, | ||
125 | .name = "TDA18271-2", | ||
126 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
127 | .i2c_bus_addr = 0xc0 >> 1, | ||
128 | .i2c_reg_len = REGLEN_8bit, | ||
129 | }, { | ||
130 | .id = 0x1f, | ||
131 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
132 | .name = "TDA10048-2", | ||
133 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
134 | .i2c_bus_addr = 0x12 >> 1, | ||
135 | .i2c_reg_len = REGLEN_8bit, | ||
136 | } }, | ||
137 | }, | ||
138 | [SAA7164_BOARD_HAUPPAUGE_HVR2200_3] = { | ||
139 | .name = "Hauppauge WinTV-HVR2200", | ||
140 | .porta = SAA7164_MPEG_DVB, | ||
141 | .portb = SAA7164_MPEG_DVB, | ||
142 | .chiprev = SAA7164_CHIP_REV2, | ||
143 | .unit = {{ | ||
144 | .id = 0x1d, | ||
145 | .type = SAA7164_UNIT_EEPROM, | ||
146 | .name = "4K EEPROM", | ||
147 | .i2c_bus_nr = SAA7164_I2C_BUS_0, | ||
148 | .i2c_bus_addr = 0xa0 >> 1, | ||
149 | .i2c_reg_len = REGLEN_8bit, | ||
150 | }, { | ||
151 | .id = 0x04, | ||
152 | .type = SAA7164_UNIT_TUNER, | ||
153 | .name = "TDA18271-1", | ||
154 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
155 | .i2c_bus_addr = 0xc0 >> 1, | ||
156 | .i2c_reg_len = REGLEN_8bit, | ||
157 | }, { | ||
158 | .id = 0x05, | ||
159 | .type = SAA7164_UNIT_ANALOG_DEMODULATOR, | ||
160 | .name = "TDA8290-1", | ||
161 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
162 | .i2c_bus_addr = 0x84 >> 1, | ||
163 | .i2c_reg_len = REGLEN_8bit, | ||
164 | }, { | ||
165 | .id = 0x1b, | ||
166 | .type = SAA7164_UNIT_TUNER, | ||
167 | .name = "TDA18271-2", | ||
168 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
169 | .i2c_bus_addr = 0xc0 >> 1, | ||
170 | .i2c_reg_len = REGLEN_8bit, | ||
171 | }, { | ||
172 | .id = 0x1c, | ||
173 | .type = SAA7164_UNIT_ANALOG_DEMODULATOR, | ||
174 | .name = "TDA8290-2", | ||
175 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
176 | .i2c_bus_addr = 0x84 >> 1, | ||
177 | .i2c_reg_len = REGLEN_8bit, | ||
178 | }, { | ||
179 | .id = 0x1e, | ||
180 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
181 | .name = "TDA10048-1", | ||
182 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
183 | .i2c_bus_addr = 0x10 >> 1, | ||
184 | .i2c_reg_len = REGLEN_8bit, | ||
185 | }, { | ||
186 | .id = 0x1f, | ||
187 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
188 | .name = "TDA10048-2", | ||
189 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
190 | .i2c_bus_addr = 0x12 >> 1, | ||
191 | .i2c_reg_len = REGLEN_8bit, | ||
192 | } }, | ||
193 | }, | ||
194 | [SAA7164_BOARD_HAUPPAUGE_HVR2250] = { | ||
195 | .name = "Hauppauge WinTV-HVR2250", | ||
196 | .porta = SAA7164_MPEG_DVB, | ||
197 | .portb = SAA7164_MPEG_DVB, | ||
198 | .chiprev = SAA7164_CHIP_REV3, | ||
199 | .unit = {{ | ||
200 | .id = 0x22, | ||
201 | .type = SAA7164_UNIT_EEPROM, | ||
202 | .name = "4K EEPROM", | ||
203 | .i2c_bus_nr = SAA7164_I2C_BUS_0, | ||
204 | .i2c_bus_addr = 0xa0 >> 1, | ||
205 | .i2c_reg_len = REGLEN_8bit, | ||
206 | }, { | ||
207 | .id = 0x04, | ||
208 | .type = SAA7164_UNIT_TUNER, | ||
209 | .name = "TDA18271-1", | ||
210 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
211 | .i2c_bus_addr = 0xc0 >> 1, | ||
212 | .i2c_reg_len = REGLEN_8bit, | ||
213 | }, { | ||
214 | .id = 0x07, | ||
215 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
216 | .name = "CX24228/S5H1411-1 (TOP)", | ||
217 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
218 | .i2c_bus_addr = 0x32 >> 1, | ||
219 | .i2c_reg_len = REGLEN_8bit, | ||
220 | }, { | ||
221 | .id = 0x08, | ||
222 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
223 | .name = "CX24228/S5H1411-1 (QAM)", | ||
224 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
225 | .i2c_bus_addr = 0x34 >> 1, | ||
226 | .i2c_reg_len = REGLEN_8bit, | ||
227 | }, { | ||
228 | .id = 0x1e, | ||
229 | .type = SAA7164_UNIT_TUNER, | ||
230 | .name = "TDA18271-2", | ||
231 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
232 | .i2c_bus_addr = 0xc0 >> 1, | ||
233 | .i2c_reg_len = REGLEN_8bit, | ||
234 | }, { | ||
235 | .id = 0x20, | ||
236 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
237 | .name = "CX24228/S5H1411-2 (TOP)", | ||
238 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
239 | .i2c_bus_addr = 0x32 >> 1, | ||
240 | .i2c_reg_len = REGLEN_8bit, | ||
241 | }, { | ||
242 | .id = 0x23, | ||
243 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
244 | .name = "CX24228/S5H1411-2 (QAM)", | ||
245 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
246 | .i2c_bus_addr = 0x34 >> 1, | ||
247 | .i2c_reg_len = REGLEN_8bit, | ||
248 | } }, | ||
249 | }, | ||
250 | [SAA7164_BOARD_HAUPPAUGE_HVR2250_2] = { | ||
251 | .name = "Hauppauge WinTV-HVR2250", | ||
252 | .porta = SAA7164_MPEG_DVB, | ||
253 | .portb = SAA7164_MPEG_DVB, | ||
254 | .chiprev = SAA7164_CHIP_REV3, | ||
255 | .unit = {{ | ||
256 | .id = 0x28, | ||
257 | .type = SAA7164_UNIT_EEPROM, | ||
258 | .name = "4K EEPROM", | ||
259 | .i2c_bus_nr = SAA7164_I2C_BUS_0, | ||
260 | .i2c_bus_addr = 0xa0 >> 1, | ||
261 | .i2c_reg_len = REGLEN_8bit, | ||
262 | }, { | ||
263 | .id = 0x04, | ||
264 | .type = SAA7164_UNIT_TUNER, | ||
265 | .name = "TDA18271-1", | ||
266 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
267 | .i2c_bus_addr = 0xc0 >> 1, | ||
268 | .i2c_reg_len = REGLEN_8bit, | ||
269 | }, { | ||
270 | .id = 0x07, | ||
271 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
272 | .name = "CX24228/S5H1411-1 (TOP)", | ||
273 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
274 | .i2c_bus_addr = 0x32 >> 1, | ||
275 | .i2c_reg_len = REGLEN_8bit, | ||
276 | }, { | ||
277 | .id = 0x08, | ||
278 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
279 | .name = "CX24228/S5H1411-1 (QAM)", | ||
280 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
281 | .i2c_bus_addr = 0x34 >> 1, | ||
282 | .i2c_reg_len = REGLEN_8bit, | ||
283 | }, { | ||
284 | .id = 0x24, | ||
285 | .type = SAA7164_UNIT_TUNER, | ||
286 | .name = "TDA18271-2", | ||
287 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
288 | .i2c_bus_addr = 0xc0 >> 1, | ||
289 | .i2c_reg_len = REGLEN_8bit, | ||
290 | }, { | ||
291 | .id = 0x26, | ||
292 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
293 | .name = "CX24228/S5H1411-2 (TOP)", | ||
294 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
295 | .i2c_bus_addr = 0x32 >> 1, | ||
296 | .i2c_reg_len = REGLEN_8bit, | ||
297 | }, { | ||
298 | .id = 0x29, | ||
299 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
300 | .name = "CX24228/S5H1411-2 (QAM)", | ||
301 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
302 | .i2c_bus_addr = 0x34 >> 1, | ||
303 | .i2c_reg_len = REGLEN_8bit, | ||
304 | } }, | ||
305 | }, | ||
306 | [SAA7164_BOARD_HAUPPAUGE_HVR2250_3] = { | ||
307 | .name = "Hauppauge WinTV-HVR2250", | ||
308 | .porta = SAA7164_MPEG_DVB, | ||
309 | .portb = SAA7164_MPEG_DVB, | ||
310 | .chiprev = SAA7164_CHIP_REV3, | ||
311 | .unit = {{ | ||
312 | .id = 0x26, | ||
313 | .type = SAA7164_UNIT_EEPROM, | ||
314 | .name = "4K EEPROM", | ||
315 | .i2c_bus_nr = SAA7164_I2C_BUS_0, | ||
316 | .i2c_bus_addr = 0xa0 >> 1, | ||
317 | .i2c_reg_len = REGLEN_8bit, | ||
318 | }, { | ||
319 | .id = 0x04, | ||
320 | .type = SAA7164_UNIT_TUNER, | ||
321 | .name = "TDA18271-1", | ||
322 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
323 | .i2c_bus_addr = 0xc0 >> 1, | ||
324 | .i2c_reg_len = REGLEN_8bit, | ||
325 | }, { | ||
326 | .id = 0x07, | ||
327 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
328 | .name = "CX24228/S5H1411-1 (TOP)", | ||
329 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
330 | .i2c_bus_addr = 0x32 >> 1, | ||
331 | .i2c_reg_len = REGLEN_8bit, | ||
332 | }, { | ||
333 | .id = 0x08, | ||
334 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
335 | .name = "CX24228/S5H1411-1 (QAM)", | ||
336 | .i2c_bus_nr = SAA7164_I2C_BUS_1, | ||
337 | .i2c_bus_addr = 0x34 >> 1, | ||
338 | .i2c_reg_len = REGLEN_8bit, | ||
339 | }, { | ||
340 | .id = 0x22, | ||
341 | .type = SAA7164_UNIT_TUNER, | ||
342 | .name = "TDA18271-2", | ||
343 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
344 | .i2c_bus_addr = 0xc0 >> 1, | ||
345 | .i2c_reg_len = REGLEN_8bit, | ||
346 | }, { | ||
347 | .id = 0x24, | ||
348 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
349 | .name = "CX24228/S5H1411-2 (TOP)", | ||
350 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
351 | .i2c_bus_addr = 0x32 >> 1, | ||
352 | .i2c_reg_len = REGLEN_8bit, | ||
353 | }, { | ||
354 | .id = 0x27, | ||
355 | .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
356 | .name = "CX24228/S5H1411-2 (QAM)", | ||
357 | .i2c_bus_nr = SAA7164_I2C_BUS_2, | ||
358 | .i2c_bus_addr = 0x34 >> 1, | ||
359 | .i2c_reg_len = REGLEN_8bit, | ||
360 | } }, | ||
361 | }, | ||
362 | }; | ||
363 | const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards); | ||
364 | |||
365 | /* ------------------------------------------------------------------ */ | ||
366 | /* PCI subsystem IDs */ | ||
367 | |||
368 | struct saa7164_subid saa7164_subids[] = { | ||
369 | { | ||
370 | .subvendor = 0x0070, | ||
371 | .subdevice = 0x8880, | ||
372 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, | ||
373 | }, { | ||
374 | .subvendor = 0x0070, | ||
375 | .subdevice = 0x8810, | ||
376 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, | ||
377 | }, { | ||
378 | .subvendor = 0x0070, | ||
379 | .subdevice = 0x8980, | ||
380 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2200, | ||
381 | }, { | ||
382 | .subvendor = 0x0070, | ||
383 | .subdevice = 0x8900, | ||
384 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_2, | ||
385 | }, { | ||
386 | .subvendor = 0x0070, | ||
387 | .subdevice = 0x8901, | ||
388 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_3, | ||
389 | }, { | ||
390 | .subvendor = 0x0070, | ||
391 | .subdevice = 0x88A1, | ||
392 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_3, | ||
393 | }, { | ||
394 | .subvendor = 0x0070, | ||
395 | .subdevice = 0x8891, | ||
396 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, | ||
397 | }, { | ||
398 | .subvendor = 0x0070, | ||
399 | .subdevice = 0x8851, | ||
400 | .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, | ||
401 | }, | ||
402 | }; | ||
403 | const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); | ||
404 | |||
405 | void saa7164_card_list(struct saa7164_dev *dev) | ||
406 | { | ||
407 | int i; | ||
408 | |||
409 | if (0 == dev->pci->subsystem_vendor && | ||
410 | 0 == dev->pci->subsystem_device) { | ||
411 | printk(KERN_ERR | ||
412 | "%s: Board has no valid PCIe Subsystem ID and can't\n" | ||
413 | "%s: be autodetected. Pass card=<n> insmod option to\n" | ||
414 | "%s: workaround that. Send complaints to the vendor\n" | ||
415 | "%s: of the TV card. Best regards,\n" | ||
416 | "%s: -- tux\n", | ||
417 | dev->name, dev->name, dev->name, dev->name, dev->name); | ||
418 | } else { | ||
419 | printk(KERN_ERR | ||
420 | "%s: Your board isn't known (yet) to the driver.\n" | ||
421 | "%s: Try to pick one of the existing card configs via\n" | ||
422 | "%s: card=<n> insmod option. Updating to the latest\n" | ||
423 | "%s: version might help as well.\n", | ||
424 | dev->name, dev->name, dev->name, dev->name); | ||
425 | } | ||
426 | |||
427 | printk(KERN_ERR "%s: Here are valid choices for the card=<n> insmod " | ||
428 | "option:\n", dev->name); | ||
429 | |||
430 | for (i = 0; i < saa7164_bcount; i++) | ||
431 | printk(KERN_ERR "%s: card=%d -> %s\n", | ||
432 | dev->name, i, saa7164_boards[i].name); | ||
433 | } | ||
434 | |||
435 | /* TODO: clean this define up into the -cards.c structs */ | ||
436 | #define PCIEBRIDGE_UNITID 2 | ||
437 | |||
438 | void saa7164_gpio_setup(struct saa7164_dev *dev) | ||
439 | { | ||
440 | |||
441 | |||
442 | switch (dev->board) { | ||
443 | case SAA7164_BOARD_HAUPPAUGE_HVR2200: | ||
444 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: | ||
445 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: | ||
446 | case SAA7164_BOARD_HAUPPAUGE_HVR2250: | ||
447 | case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: | ||
448 | case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: | ||
449 | /* | ||
450 | GPIO 2: s5h1411 / tda10048-1 demod reset | ||
451 | GPIO 3: s5h1411 / tda10048-2 demod reset | ||
452 | GPIO 7: IRBlaster Zilog reset | ||
453 | */ | ||
454 | |||
455 | /* Reset parts by going in and out of reset */ | ||
456 | saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2); | ||
457 | saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3); | ||
458 | |||
459 | msleep(10); | ||
460 | |||
461 | saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 2); | ||
462 | saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3); | ||
463 | break; | ||
464 | } | ||
465 | |||
466 | } | ||
467 | |||
468 | static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) | ||
469 | { | ||
470 | struct tveeprom tv; | ||
471 | |||
472 | /* TODO: Assumption: eeprom on bus 0 */ | ||
473 | tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, | ||
474 | eeprom_data); | ||
475 | |||
476 | /* Make sure we support the board model */ | ||
477 | switch (tv.model) { | ||
478 | case 88001: | ||
479 | /* Development board - Limit circulation */ | ||
480 | /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) | ||
481 | * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */ | ||
482 | case 88021: | ||
483 | /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) | ||
484 | * ATSC/QAM (TDA18271/S5H1411) and basic analog, MCE CIR, FM */ | ||
485 | break; | ||
486 | case 88041: | ||
487 | /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) | ||
488 | * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */ | ||
489 | break; | ||
490 | case 88061: | ||
491 | /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) | ||
492 | * ATSC/QAM (TDA18271/S5H1411) and basic analog, FM */ | ||
493 | break; | ||
494 | case 89519: | ||
495 | case 89609: | ||
496 | /* WinTV-HVR2200 (PCIe, Retail, full-height) | ||
497 | * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ | ||
498 | break; | ||
499 | case 89619: | ||
500 | /* WinTV-HVR2200 (PCIe, Retail, half-height) | ||
501 | * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ | ||
502 | break; | ||
503 | default: | ||
504 | printk(KERN_ERR "%s: Warning: Unknown Hauppauge model #%d\n", | ||
505 | dev->name, tv.model); | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | printk(KERN_INFO "%s: Hauppauge eeprom: model=%d\n", dev->name, | ||
510 | tv.model); | ||
511 | } | ||
512 | |||
513 | void saa7164_card_setup(struct saa7164_dev *dev) | ||
514 | { | ||
515 | static u8 eeprom[256]; | ||
516 | |||
517 | if (dev->i2c_bus[0].i2c_rc == 0) { | ||
518 | if (saa7164_api_read_eeprom(dev, &eeprom[0], | ||
519 | sizeof(eeprom)) < 0) | ||
520 | return; | ||
521 | } | ||
522 | |||
523 | switch (dev->board) { | ||
524 | case SAA7164_BOARD_HAUPPAUGE_HVR2200: | ||
525 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: | ||
526 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: | ||
527 | case SAA7164_BOARD_HAUPPAUGE_HVR2250: | ||
528 | case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: | ||
529 | case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: | ||
530 | hauppauge_eeprom(dev, &eeprom[0]); | ||
531 | break; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | /* With most other drivers, the kernel expects to communicate with subdrivers | ||
536 | * through i2c. This bridge does not allow that, it does not expose any direct | ||
537 | * access to I2C. Instead we have to communicate through the device f/w for | ||
538 | * register access to 'processing units'. Each unit has a unique | ||
539 | * id, regardless of how the physical implementation occurs across | ||
540 | * the three physical i2c busses. The being said if we want leverge of | ||
541 | * the existing kernel drivers for tuners and demods we have to 'speak i2c', | ||
542 | * to this bridge implements 3 virtual i2c buses. This is a helper function | ||
543 | * for those. | ||
544 | * | ||
545 | * Description: Translate the kernels notion of an i2c address and bus into | ||
546 | * the appropriate unitid. | ||
547 | */ | ||
548 | int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr) | ||
549 | { | ||
550 | /* For a given bus and i2c device address, return the saa7164 unique | ||
551 | * unitid. < 0 on error */ | ||
552 | |||
553 | struct saa7164_dev *dev = bus->dev; | ||
554 | struct saa7164_unit *unit; | ||
555 | int i; | ||
556 | |||
557 | for (i = 0; i < SAA7164_MAX_UNITS; i++) { | ||
558 | unit = &saa7164_boards[dev->board].unit[i]; | ||
559 | |||
560 | if (unit->type == SAA7164_UNIT_UNDEFINED) | ||
561 | continue; | ||
562 | if ((bus->nr == unit->i2c_bus_nr) && | ||
563 | (addr == unit->i2c_bus_addr)) | ||
564 | return unit->id; | ||
565 | } | ||
566 | |||
567 | return -1; | ||
568 | } | ||
569 | |||
570 | /* The 7164 API needs to know the i2c register length in advance. | ||
571 | * this is a helper function. Based on a specific chip addr and bus return the | ||
572 | * reg length. | ||
573 | */ | ||
574 | int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr) | ||
575 | { | ||
576 | /* For a given bus and i2c device address, return the | ||
577 | * saa7164 registry address width. < 0 on error | ||
578 | */ | ||
579 | |||
580 | struct saa7164_dev *dev = bus->dev; | ||
581 | struct saa7164_unit *unit; | ||
582 | int i; | ||
583 | |||
584 | for (i = 0; i < SAA7164_MAX_UNITS; i++) { | ||
585 | unit = &saa7164_boards[dev->board].unit[i]; | ||
586 | |||
587 | if (unit->type == SAA7164_UNIT_UNDEFINED) | ||
588 | continue; | ||
589 | |||
590 | if ((bus->nr == unit->i2c_bus_nr) && | ||
591 | (addr == unit->i2c_bus_addr)) | ||
592 | return unit->i2c_reg_len; | ||
593 | } | ||
594 | |||
595 | return -1; | ||
596 | } | ||
597 | /* TODO: implement a 'findeeprom' functio like the above and fix any other | ||
598 | * eeprom related todo's in -api.c. | ||
599 | */ | ||
600 | |||
601 | /* Translate a unitid into a x readable device name, for display purposes. */ | ||
602 | char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid) | ||
603 | { | ||
604 | char *undefed = "UNDEFINED"; | ||
605 | char *bridge = "BRIDGE"; | ||
606 | struct saa7164_unit *unit; | ||
607 | int i; | ||
608 | |||
609 | if (unitid == 0) | ||
610 | return bridge; | ||
611 | |||
612 | for (i = 0; i < SAA7164_MAX_UNITS; i++) { | ||
613 | unit = &saa7164_boards[dev->board].unit[i]; | ||
614 | |||
615 | if (unit->type == SAA7164_UNIT_UNDEFINED) | ||
616 | continue; | ||
617 | |||
618 | if (unitid == unit->id) | ||
619 | return unit->name; | ||
620 | } | ||
621 | |||
622 | return undefed; | ||
623 | } | ||
624 | |||
diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/video/saa7164/saa7164-cmd.c new file mode 100644 index 000000000000..e097f1a0969a --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-cmd.c | |||
@@ -0,0 +1,572 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/wait.h> | ||
23 | |||
24 | #include "saa7164.h" | ||
25 | |||
26 | int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev) | ||
27 | { | ||
28 | int i, ret = -1; | ||
29 | |||
30 | mutex_lock(&dev->lock); | ||
31 | for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { | ||
32 | if (dev->cmds[i].inuse == 0) { | ||
33 | dev->cmds[i].inuse = 1; | ||
34 | dev->cmds[i].signalled = 0; | ||
35 | dev->cmds[i].timeout = 0; | ||
36 | ret = dev->cmds[i].seqno; | ||
37 | break; | ||
38 | } | ||
39 | } | ||
40 | mutex_unlock(&dev->lock); | ||
41 | |||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno) | ||
46 | { | ||
47 | mutex_lock(&dev->lock); | ||
48 | if ((dev->cmds[seqno].inuse == 1) && | ||
49 | (dev->cmds[seqno].seqno == seqno)) { | ||
50 | dev->cmds[seqno].inuse = 0; | ||
51 | dev->cmds[seqno].signalled = 0; | ||
52 | dev->cmds[seqno].timeout = 0; | ||
53 | } | ||
54 | mutex_unlock(&dev->lock); | ||
55 | } | ||
56 | |||
57 | void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno) | ||
58 | { | ||
59 | mutex_lock(&dev->lock); | ||
60 | if ((dev->cmds[seqno].inuse == 1) && | ||
61 | (dev->cmds[seqno].seqno == seqno)) { | ||
62 | dev->cmds[seqno].timeout = 1; | ||
63 | } | ||
64 | mutex_unlock(&dev->lock); | ||
65 | } | ||
66 | |||
67 | u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno) | ||
68 | { | ||
69 | int ret = 0; | ||
70 | |||
71 | mutex_lock(&dev->lock); | ||
72 | if ((dev->cmds[seqno].inuse == 1) && | ||
73 | (dev->cmds[seqno].seqno == seqno)) { | ||
74 | ret = dev->cmds[seqno].timeout; | ||
75 | } | ||
76 | mutex_unlock(&dev->lock); | ||
77 | |||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | /* Commands to the f/w get marshelled to/from this code then onto the PCI | ||
82 | * -bus/c running buffer. */ | ||
83 | int saa7164_irq_dequeue(struct saa7164_dev *dev) | ||
84 | { | ||
85 | int ret = SAA_OK; | ||
86 | u32 timeout; | ||
87 | wait_queue_head_t *q = 0; | ||
88 | dprintk(DBGLVL_CMD, "%s()\n", __func__); | ||
89 | |||
90 | /* While any outstand message on the bus exists... */ | ||
91 | do { | ||
92 | |||
93 | /* Peek the msg bus */ | ||
94 | tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 }; | ||
95 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); | ||
96 | if (ret != SAA_OK) | ||
97 | break; | ||
98 | |||
99 | q = &dev->cmds[tRsp.seqno].wait; | ||
100 | timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno); | ||
101 | dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout); | ||
102 | if (!timeout) { | ||
103 | dprintk(DBGLVL_CMD, | ||
104 | "%s() signalled seqno(%d) (for dequeue)\n", | ||
105 | __func__, tRsp.seqno); | ||
106 | dev->cmds[tRsp.seqno].signalled = 1; | ||
107 | wake_up(q); | ||
108 | } else { | ||
109 | printk(KERN_ERR | ||
110 | "%s() found timed out command on the bus\n", | ||
111 | __func__); | ||
112 | } | ||
113 | } while (0); | ||
114 | |||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | /* Commands to the f/w get marshelled to/from this code then onto the PCI | ||
119 | * -bus/c running buffer. */ | ||
120 | int saa7164_cmd_dequeue(struct saa7164_dev *dev) | ||
121 | { | ||
122 | int loop = 1; | ||
123 | int ret; | ||
124 | u32 timeout; | ||
125 | wait_queue_head_t *q = 0; | ||
126 | u8 tmp[512]; | ||
127 | dprintk(DBGLVL_CMD, "%s()\n", __func__); | ||
128 | |||
129 | while (loop) { | ||
130 | |||
131 | tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 }; | ||
132 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); | ||
133 | if (ret == SAA_ERR_EMPTY) | ||
134 | return SAA_OK; | ||
135 | |||
136 | if (ret != SAA_OK) | ||
137 | return ret; | ||
138 | |||
139 | q = &dev->cmds[tRsp.seqno].wait; | ||
140 | timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno); | ||
141 | dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout); | ||
142 | if (timeout) { | ||
143 | printk(KERN_ERR "found timed out command on the bus\n"); | ||
144 | |||
145 | /* Clean the bus */ | ||
146 | ret = saa7164_bus_get(dev, &tRsp, &tmp, 0); | ||
147 | printk(KERN_ERR "ret = %x\n", ret); | ||
148 | if (ret == SAA_ERR_EMPTY) | ||
149 | /* Someone else already fetched the response */ | ||
150 | return SAA_OK; | ||
151 | |||
152 | if (ret != SAA_OK) | ||
153 | return ret; | ||
154 | |||
155 | if (tRsp.flags & PVC_CMDFLAG_CONTINUE) | ||
156 | printk(KERN_ERR "split response\n"); | ||
157 | else | ||
158 | saa7164_cmd_free_seqno(dev, tRsp.seqno); | ||
159 | |||
160 | printk(KERN_ERR " timeout continue\n"); | ||
161 | continue; | ||
162 | } | ||
163 | |||
164 | dprintk(DBGLVL_CMD, "%s() signalled seqno(%d) (for dequeue)\n", | ||
165 | __func__, tRsp.seqno); | ||
166 | dev->cmds[tRsp.seqno].signalled = 1; | ||
167 | wake_up(q); | ||
168 | return SAA_OK; | ||
169 | } | ||
170 | |||
171 | return SAA_OK; | ||
172 | } | ||
173 | |||
174 | int saa7164_cmd_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | ||
175 | { | ||
176 | tmComResBusInfo_t *bus = &dev->bus; | ||
177 | u8 cmd_sent; | ||
178 | u16 size, idx; | ||
179 | u32 cmds; | ||
180 | void *tmp; | ||
181 | int ret = -1; | ||
182 | |||
183 | if (!msg) { | ||
184 | printk(KERN_ERR "%s() !msg\n", __func__); | ||
185 | return SAA_ERR_BAD_PARAMETER; | ||
186 | } | ||
187 | |||
188 | mutex_lock(&dev->cmds[msg->id].lock); | ||
189 | |||
190 | size = msg->size; | ||
191 | idx = 0; | ||
192 | cmds = size / bus->m_wMaxReqSize; | ||
193 | if (size % bus->m_wMaxReqSize == 0) | ||
194 | cmds -= 1; | ||
195 | |||
196 | cmd_sent = 0; | ||
197 | |||
198 | /* Split the request into smaller chunks */ | ||
199 | for (idx = 0; idx < cmds; idx++) { | ||
200 | |||
201 | msg->flags |= SAA_CMDFLAG_CONTINUE; | ||
202 | msg->size = bus->m_wMaxReqSize; | ||
203 | tmp = buf + idx * bus->m_wMaxReqSize; | ||
204 | |||
205 | ret = saa7164_bus_set(dev, msg, tmp); | ||
206 | if (ret != SAA_OK) { | ||
207 | printk(KERN_ERR "%s() set failed %d\n", __func__, ret); | ||
208 | |||
209 | if (cmd_sent) { | ||
210 | ret = SAA_ERR_BUSY; | ||
211 | goto out; | ||
212 | } | ||
213 | ret = SAA_ERR_OVERFLOW; | ||
214 | goto out; | ||
215 | } | ||
216 | cmd_sent = 1; | ||
217 | } | ||
218 | |||
219 | /* If not the last command... */ | ||
220 | if (idx != 0) | ||
221 | msg->flags &= ~SAA_CMDFLAG_CONTINUE; | ||
222 | |||
223 | msg->size = size - idx * bus->m_wMaxReqSize; | ||
224 | |||
225 | ret = saa7164_bus_set(dev, msg, buf + idx * bus->m_wMaxReqSize); | ||
226 | if (ret != SAA_OK) { | ||
227 | printk(KERN_ERR "%s() set last failed %d\n", __func__, ret); | ||
228 | |||
229 | if (cmd_sent) { | ||
230 | ret = SAA_ERR_BUSY; | ||
231 | goto out; | ||
232 | } | ||
233 | ret = SAA_ERR_OVERFLOW; | ||
234 | goto out; | ||
235 | } | ||
236 | ret = SAA_OK; | ||
237 | |||
238 | out: | ||
239 | mutex_unlock(&dev->cmds[msg->id].lock); | ||
240 | return ret; | ||
241 | } | ||
242 | |||
243 | /* Wait for a signal event, without holding a mutex. Either return TIMEOUT if | ||
244 | * the event never occured, or SAA_OK if it was signaled during the wait. | ||
245 | */ | ||
246 | int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) | ||
247 | { | ||
248 | wait_queue_head_t *q = 0; | ||
249 | int ret = SAA_BUS_TIMEOUT; | ||
250 | unsigned long stamp; | ||
251 | int r; | ||
252 | |||
253 | if (debug >= 4) | ||
254 | saa7164_bus_dump(dev); | ||
255 | |||
256 | dprintk(DBGLVL_CMD, "%s(seqno=%d)\n", __func__, seqno); | ||
257 | |||
258 | mutex_lock(&dev->lock); | ||
259 | if ((dev->cmds[seqno].inuse == 1) && | ||
260 | (dev->cmds[seqno].seqno == seqno)) { | ||
261 | q = &dev->cmds[seqno].wait; | ||
262 | } | ||
263 | mutex_unlock(&dev->lock); | ||
264 | |||
265 | if (q) { | ||
266 | /* If we haven't been signalled we need to wait */ | ||
267 | if (dev->cmds[seqno].signalled == 0) { | ||
268 | stamp = jiffies; | ||
269 | dprintk(DBGLVL_CMD, | ||
270 | "%s(seqno=%d) Waiting (signalled=%d)\n", | ||
271 | __func__, seqno, dev->cmds[seqno].signalled); | ||
272 | |||
273 | /* Wait for signalled to be flagged or timeout */ | ||
274 | /* In a highly stressed system this can easily extend | ||
275 | * into multiple seconds before the deferred worker | ||
276 | * is scheduled, and we're woken up via signal. | ||
277 | * We typically are signalled in < 50ms but it can | ||
278 | * take MUCH longer. | ||
279 | */ | ||
280 | wait_event_timeout(*q, dev->cmds[seqno].signalled, (HZ * waitsecs)); | ||
281 | r = time_before(jiffies, stamp + (HZ * waitsecs)); | ||
282 | if (r) | ||
283 | ret = SAA_OK; | ||
284 | else | ||
285 | saa7164_cmd_timeout_seqno(dev, seqno); | ||
286 | |||
287 | dprintk(DBGLVL_CMD, "%s(seqno=%d) Waiting res = %d " | ||
288 | "(signalled=%d)\n", __func__, seqno, r, | ||
289 | dev->cmds[seqno].signalled); | ||
290 | } else | ||
291 | ret = SAA_OK; | ||
292 | } else | ||
293 | printk(KERN_ERR "%s(seqno=%d) seqno is invalid\n", | ||
294 | __func__, seqno); | ||
295 | |||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno) | ||
300 | { | ||
301 | int i; | ||
302 | dprintk(DBGLVL_CMD, "%s()\n", __func__); | ||
303 | |||
304 | mutex_lock(&dev->lock); | ||
305 | for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { | ||
306 | if (dev->cmds[i].inuse == 1) { | ||
307 | dprintk(DBGLVL_CMD, | ||
308 | "seqno %d inuse, sig = %d, t/out = %d\n", | ||
309 | dev->cmds[i].seqno, | ||
310 | dev->cmds[i].signalled, | ||
311 | dev->cmds[i].timeout); | ||
312 | } | ||
313 | } | ||
314 | |||
315 | for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { | ||
316 | if ((dev->cmds[i].inuse == 1) && ((i == 0) || | ||
317 | (dev->cmds[i].signalled) || (dev->cmds[i].timeout))) { | ||
318 | dprintk(DBGLVL_CMD, "%s(seqno=%d) calling wake_up\n", | ||
319 | __func__, i); | ||
320 | dev->cmds[i].signalled = 1; | ||
321 | wake_up(&dev->cmds[i].wait); | ||
322 | } | ||
323 | } | ||
324 | mutex_unlock(&dev->lock); | ||
325 | } | ||
326 | |||
327 | int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, tmComResCmd_t command, | ||
328 | u16 controlselector, u16 size, void *buf) | ||
329 | { | ||
330 | tmComResInfo_t command_t, *pcommand_t; | ||
331 | tmComResInfo_t response_t, *presponse_t; | ||
332 | u8 errdata[256]; | ||
333 | u16 resp_dsize; | ||
334 | u16 data_recd; | ||
335 | u32 loop; | ||
336 | int ret; | ||
337 | int safety = 0; | ||
338 | |||
339 | dprintk(DBGLVL_CMD, "%s(unitid = %s (%d) , command = 0x%x, " | ||
340 | "sel = 0x%x)\n", __func__, saa7164_unitid_name(dev, id), id, | ||
341 | command, controlselector); | ||
342 | |||
343 | if ((size == 0) || (buf == 0)) { | ||
344 | printk(KERN_ERR "%s() Invalid param\n", __func__); | ||
345 | return SAA_ERR_BAD_PARAMETER; | ||
346 | } | ||
347 | |||
348 | /* Prepare some basic command/response structures */ | ||
349 | memset(&command_t, 0, sizeof(command_t)); | ||
350 | memset(&response_t, 0, sizeof(&response_t)); | ||
351 | pcommand_t = &command_t; | ||
352 | presponse_t = &response_t; | ||
353 | command_t.id = id; | ||
354 | command_t.command = command; | ||
355 | command_t.controlselector = controlselector; | ||
356 | command_t.size = size; | ||
357 | |||
358 | /* Allocate a unique sequence number */ | ||
359 | ret = saa7164_cmd_alloc_seqno(dev); | ||
360 | if (ret < 0) { | ||
361 | printk(KERN_ERR "%s() No free sequences\n", __func__); | ||
362 | ret = SAA_ERR_NO_RESOURCES; | ||
363 | goto out; | ||
364 | } | ||
365 | |||
366 | command_t.seqno = (u8)ret; | ||
367 | |||
368 | /* Send Command */ | ||
369 | resp_dsize = size; | ||
370 | pcommand_t->size = size; | ||
371 | |||
372 | dprintk(DBGLVL_CMD, "%s() pcommand_t.seqno = %d\n", | ||
373 | __func__, pcommand_t->seqno); | ||
374 | |||
375 | dprintk(DBGLVL_CMD, "%s() pcommand_t.size = %d\n", | ||
376 | __func__, pcommand_t->size); | ||
377 | |||
378 | ret = saa7164_cmd_set(dev, pcommand_t, buf); | ||
379 | if (ret != SAA_OK) { | ||
380 | printk(KERN_ERR "%s() set command failed %d\n", __func__, ret); | ||
381 | |||
382 | if (ret != SAA_ERR_BUSY) | ||
383 | saa7164_cmd_free_seqno(dev, pcommand_t->seqno); | ||
384 | else | ||
385 | /* Flag a timeout, because at least one | ||
386 | * command was sent */ | ||
387 | saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno); | ||
388 | |||
389 | goto out; | ||
390 | } | ||
391 | |||
392 | /* With split responses we have to collect the msgs piece by piece */ | ||
393 | data_recd = 0; | ||
394 | loop = 1; | ||
395 | while (loop) { | ||
396 | dprintk(DBGLVL_CMD, "%s() loop\n", __func__); | ||
397 | |||
398 | ret = saa7164_cmd_wait(dev, pcommand_t->seqno); | ||
399 | dprintk(DBGLVL_CMD, "%s() loop ret = %d\n", __func__, ret); | ||
400 | |||
401 | /* if power is down and this is not a power command ... */ | ||
402 | |||
403 | if (ret == SAA_BUS_TIMEOUT) { | ||
404 | printk(KERN_ERR "Event timed out\n"); | ||
405 | saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | if (ret != SAA_OK) { | ||
410 | printk(KERN_ERR "spurious error\n"); | ||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | /* Peek response */ | ||
415 | ret = saa7164_bus_get(dev, presponse_t, NULL, 1); | ||
416 | if (ret == SAA_ERR_EMPTY) { | ||
417 | dprintk(4, "%s() SAA_ERR_EMPTY\n", __func__); | ||
418 | continue; | ||
419 | } | ||
420 | if (ret != SAA_OK) { | ||
421 | printk(KERN_ERR "peek failed\n"); | ||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | dprintk(DBGLVL_CMD, "%s() presponse_t->seqno = %d\n", | ||
426 | __func__, presponse_t->seqno); | ||
427 | |||
428 | dprintk(DBGLVL_CMD, "%s() presponse_t->flags = 0x%x\n", | ||
429 | __func__, presponse_t->flags); | ||
430 | |||
431 | dprintk(DBGLVL_CMD, "%s() presponse_t->size = %d\n", | ||
432 | __func__, presponse_t->size); | ||
433 | |||
434 | /* Check if the response was for our command */ | ||
435 | if (presponse_t->seqno != pcommand_t->seqno) { | ||
436 | |||
437 | dprintk(DBGLVL_CMD, | ||
438 | "wrong event: seqno = %d, " | ||
439 | "expected seqno = %d, " | ||
440 | "will dequeue regardless\n", | ||
441 | presponse_t->seqno, pcommand_t->seqno); | ||
442 | |||
443 | ret = saa7164_cmd_dequeue(dev); | ||
444 | if (ret != SAA_OK) { | ||
445 | printk(KERN_ERR "dequeue failed, ret = %d\n", | ||
446 | ret); | ||
447 | if (safety++ > 16) { | ||
448 | printk(KERN_ERR | ||
449 | "dequeue exceeded, safety exit\n"); | ||
450 | return SAA_ERR_BUSY; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | continue; | ||
455 | } | ||
456 | |||
457 | if ((presponse_t->flags & PVC_RESPONSEFLAG_ERROR) != 0) { | ||
458 | |||
459 | memset(&errdata[0], 0, sizeof(errdata)); | ||
460 | |||
461 | ret = saa7164_bus_get(dev, presponse_t, &errdata[0], 0); | ||
462 | if (ret != SAA_OK) { | ||
463 | printk(KERN_ERR "get error(2)\n"); | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | saa7164_cmd_free_seqno(dev, pcommand_t->seqno); | ||
468 | |||
469 | dprintk(DBGLVL_CMD, "%s() errdata %02x%02x%02x%02x\n", | ||
470 | __func__, errdata[0], errdata[1], errdata[2], | ||
471 | errdata[3]); | ||
472 | |||
473 | /* Map error codes */ | ||
474 | dprintk(DBGLVL_CMD, "%s() cmd, error code = 0x%x\n", | ||
475 | __func__, errdata[0]); | ||
476 | |||
477 | switch (errdata[0]) { | ||
478 | case PVC_ERRORCODE_INVALID_COMMAND: | ||
479 | dprintk(DBGLVL_CMD, "%s() INVALID_COMMAND\n", | ||
480 | __func__); | ||
481 | ret = SAA_ERR_INVALID_COMMAND; | ||
482 | break; | ||
483 | case PVC_ERRORCODE_INVALID_DATA: | ||
484 | dprintk(DBGLVL_CMD, "%s() INVALID_DATA\n", | ||
485 | __func__); | ||
486 | ret = SAA_ERR_BAD_PARAMETER; | ||
487 | break; | ||
488 | case PVC_ERRORCODE_TIMEOUT: | ||
489 | dprintk(DBGLVL_CMD, "%s() TIMEOUT\n", __func__); | ||
490 | ret = SAA_ERR_TIMEOUT; | ||
491 | break; | ||
492 | case PVC_ERRORCODE_NAK: | ||
493 | dprintk(DBGLVL_CMD, "%s() NAK\n", __func__); | ||
494 | ret = SAA_ERR_NULL_PACKET; | ||
495 | break; | ||
496 | case PVC_ERRORCODE_UNKNOWN: | ||
497 | case PVC_ERRORCODE_INVALID_CONTROL: | ||
498 | dprintk(DBGLVL_CMD, | ||
499 | "%s() UNKNOWN OR INVALID CONTROL\n", | ||
500 | __func__); | ||
501 | default: | ||
502 | dprintk(DBGLVL_CMD, "%s() UNKNOWN\n", __func__); | ||
503 | ret = SAA_ERR_NOT_SUPPORTED; | ||
504 | } | ||
505 | |||
506 | /* See of other commands are on the bus */ | ||
507 | if (saa7164_cmd_dequeue(dev) != SAA_OK) | ||
508 | printk(KERN_ERR "dequeue(2) failed\n"); | ||
509 | |||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | /* If response is invalid */ | ||
514 | if ((presponse_t->id != pcommand_t->id) || | ||
515 | (presponse_t->command != pcommand_t->command) || | ||
516 | (presponse_t->controlselector != | ||
517 | pcommand_t->controlselector) || | ||
518 | (((resp_dsize - data_recd) != presponse_t->size) && | ||
519 | !(presponse_t->flags & PVC_CMDFLAG_CONTINUE)) || | ||
520 | ((resp_dsize - data_recd) < presponse_t->size)) { | ||
521 | |||
522 | /* Invalid */ | ||
523 | dprintk(DBGLVL_CMD, "%s() Invalid\n", __func__); | ||
524 | ret = saa7164_bus_get(dev, presponse_t, 0, 0); | ||
525 | if (ret != SAA_OK) { | ||
526 | printk(KERN_ERR "get failed\n"); | ||
527 | return ret; | ||
528 | } | ||
529 | |||
530 | /* See of other commands are on the bus */ | ||
531 | if (saa7164_cmd_dequeue(dev) != SAA_OK) | ||
532 | printk(KERN_ERR "dequeue(3) failed\n"); | ||
533 | continue; | ||
534 | } | ||
535 | |||
536 | /* OK, now we're actually getting out correct response */ | ||
537 | ret = saa7164_bus_get(dev, presponse_t, buf + data_recd, 0); | ||
538 | if (ret != SAA_OK) { | ||
539 | printk(KERN_ERR "get failed\n"); | ||
540 | return ret; | ||
541 | } | ||
542 | |||
543 | data_recd = presponse_t->size + data_recd; | ||
544 | if (resp_dsize == data_recd) { | ||
545 | dprintk(DBGLVL_CMD, "%s() Resp recd\n", __func__); | ||
546 | break; | ||
547 | } | ||
548 | |||
549 | /* See of other commands are on the bus */ | ||
550 | if (saa7164_cmd_dequeue(dev) != SAA_OK) | ||
551 | printk(KERN_ERR "dequeue(3) failed\n"); | ||
552 | |||
553 | continue; | ||
554 | |||
555 | } /* (loop) */ | ||
556 | |||
557 | /* Release the sequence number allocation */ | ||
558 | saa7164_cmd_free_seqno(dev, pcommand_t->seqno); | ||
559 | |||
560 | /* if powerdown signal all pending commands */ | ||
561 | |||
562 | dprintk(DBGLVL_CMD, "%s() Calling dequeue then exit\n", __func__); | ||
563 | |||
564 | /* See of other commands are on the bus */ | ||
565 | if (saa7164_cmd_dequeue(dev) != SAA_OK) | ||
566 | printk(KERN_ERR "dequeue(4) failed\n"); | ||
567 | |||
568 | ret = SAA_OK; | ||
569 | out: | ||
570 | return ret; | ||
571 | } | ||
572 | |||
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c new file mode 100644 index 000000000000..f0dbead188c8 --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-core.c | |||
@@ -0,0 +1,740 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/kmod.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <asm/div64.h> | ||
32 | |||
33 | #include "saa7164.h" | ||
34 | |||
35 | MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards"); | ||
36 | MODULE_AUTHOR("Steven Toth <stoth@kernellabs.com>"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | /* | ||
40 | 1 Basic | ||
41 | 2 | ||
42 | 4 i2c | ||
43 | 8 api | ||
44 | 16 cmd | ||
45 | 32 bus | ||
46 | */ | ||
47 | |||
48 | unsigned int debug; | ||
49 | module_param(debug, int, 0644); | ||
50 | MODULE_PARM_DESC(debug, "enable debug messages"); | ||
51 | |||
52 | unsigned int waitsecs = 10; | ||
53 | module_param(waitsecs, int, 0644); | ||
54 | MODULE_PARM_DESC(debug, "timeout on firmware messages"); | ||
55 | |||
56 | static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET }; | ||
57 | module_param_array(card, int, NULL, 0444); | ||
58 | MODULE_PARM_DESC(card, "card type"); | ||
59 | |||
60 | static unsigned int saa7164_devcount; | ||
61 | |||
62 | static DEFINE_MUTEX(devlist); | ||
63 | LIST_HEAD(saa7164_devlist); | ||
64 | |||
65 | #define INT_SIZE 16 | ||
66 | |||
67 | static void saa7164_work_cmdhandler(struct work_struct *w) | ||
68 | { | ||
69 | struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd); | ||
70 | |||
71 | /* Wake up any complete commands */ | ||
72 | saa7164_irq_dequeue(dev); | ||
73 | } | ||
74 | |||
75 | static void saa7164_buffer_deliver(struct saa7164_buffer *buf) | ||
76 | { | ||
77 | struct saa7164_tsport *port = buf->port; | ||
78 | |||
79 | /* Feed the transport payload into the kernel demux */ | ||
80 | dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu, | ||
81 | SAA7164_TS_NUMBER_OF_LINES); | ||
82 | |||
83 | } | ||
84 | |||
85 | static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port) | ||
86 | { | ||
87 | struct saa7164_dev *dev = port->dev; | ||
88 | struct saa7164_buffer *buf; | ||
89 | struct list_head *c, *n; | ||
90 | int wp, i = 0, rp; | ||
91 | |||
92 | /* Find the current write point from the hardware */ | ||
93 | wp = saa7164_readl(port->bufcounter); | ||
94 | if (wp > (port->hwcfg.buffercount - 1)) | ||
95 | BUG(); | ||
96 | |||
97 | /* Find the previous buffer to the current write point */ | ||
98 | if (wp == 0) | ||
99 | rp = 7; | ||
100 | else | ||
101 | rp = wp - 1; | ||
102 | |||
103 | /* Lookup the WP in the buffer list */ | ||
104 | /* TODO: turn this into a worker thread */ | ||
105 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
106 | buf = list_entry(c, struct saa7164_buffer, list); | ||
107 | if (i++ > port->hwcfg.buffercount) | ||
108 | BUG(); | ||
109 | |||
110 | if (buf->nr == rp) { | ||
111 | /* Found the buffer, deal with it */ | ||
112 | dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n", | ||
113 | __func__, wp, rp); | ||
114 | saa7164_buffer_deliver(buf); | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* Primary IRQ handler and dispatch mechanism */ | ||
123 | static irqreturn_t saa7164_irq(int irq, void *dev_id) | ||
124 | { | ||
125 | struct saa7164_dev *dev = dev_id; | ||
126 | u32 intid, intstat[INT_SIZE/4]; | ||
127 | int i, handled = 0, bit; | ||
128 | |||
129 | if (dev == 0) { | ||
130 | printk(KERN_ERR "%s() No device specified\n", __func__); | ||
131 | handled = 0; | ||
132 | goto out; | ||
133 | } | ||
134 | |||
135 | /* Check that the hardware is accessable. If the status bytes are | ||
136 | * 0xFF then the device is not accessable, the the IRQ belongs | ||
137 | * to another driver. | ||
138 | * 4 x u32 interrupt registers. | ||
139 | */ | ||
140 | for (i = 0; i < INT_SIZE/4; i++) { | ||
141 | |||
142 | /* TODO: Convert into saa7164_readl() */ | ||
143 | /* Read the 4 hardware interrupt registers */ | ||
144 | intstat[i] = saa7164_readl(dev->int_status + (i * 4)); | ||
145 | |||
146 | if (intstat[i]) | ||
147 | handled = 1; | ||
148 | } | ||
149 | if (handled == 0) | ||
150 | goto out; | ||
151 | |||
152 | /* For each of the HW interrupt registers */ | ||
153 | for (i = 0; i < INT_SIZE/4; i++) { | ||
154 | |||
155 | if (intstat[i]) { | ||
156 | /* Each function of the board has it's own interruptid. | ||
157 | * Find the function that triggered then call | ||
158 | * it's handler. | ||
159 | */ | ||
160 | for (bit = 0; bit < 32; bit++) { | ||
161 | |||
162 | if (((intstat[i] >> bit) & 0x00000001) == 0) | ||
163 | continue; | ||
164 | |||
165 | /* Calculate the interrupt id (0x00 to 0x7f) */ | ||
166 | |||
167 | intid = (i * 32) + bit; | ||
168 | if (intid == dev->intfdesc.bInterruptId) { | ||
169 | /* A response to an cmd/api call */ | ||
170 | schedule_work(&dev->workcmd); | ||
171 | } else if (intid == | ||
172 | dev->ts1.hwcfg.interruptid) { | ||
173 | |||
174 | /* Transport path 1 */ | ||
175 | saa7164_irq_ts(&dev->ts1); | ||
176 | |||
177 | } else if (intid == | ||
178 | dev->ts2.hwcfg.interruptid) { | ||
179 | |||
180 | /* Transport path 2 */ | ||
181 | saa7164_irq_ts(&dev->ts2); | ||
182 | |||
183 | } else { | ||
184 | /* Find the function */ | ||
185 | dprintk(DBGLVL_IRQ, | ||
186 | "%s() unhandled interrupt " | ||
187 | "reg 0x%x bit 0x%x " | ||
188 | "intid = 0x%x\n", | ||
189 | __func__, i, bit, intid); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | /* Ack it */ | ||
194 | saa7164_writel(dev->int_ack + (i * 4), intstat[i]); | ||
195 | |||
196 | } | ||
197 | } | ||
198 | out: | ||
199 | return IRQ_RETVAL(handled); | ||
200 | } | ||
201 | |||
202 | void saa7164_getfirmwarestatus(struct saa7164_dev *dev) | ||
203 | { | ||
204 | struct saa7164_fw_status *s = &dev->fw_status; | ||
205 | |||
206 | dev->fw_status.status = saa7164_readl(SAA_DEVICE_SYSINIT_STATUS); | ||
207 | dev->fw_status.mode = saa7164_readl(SAA_DEVICE_SYSINIT_MODE); | ||
208 | dev->fw_status.spec = saa7164_readl(SAA_DEVICE_SYSINIT_SPEC); | ||
209 | dev->fw_status.inst = saa7164_readl(SAA_DEVICE_SYSINIT_INST); | ||
210 | dev->fw_status.cpuload = saa7164_readl(SAA_DEVICE_SYSINIT_CPULOAD); | ||
211 | dev->fw_status.remainheap = | ||
212 | saa7164_readl(SAA_DEVICE_SYSINIT_REMAINHEAP); | ||
213 | |||
214 | dprintk(1, "Firmware status:\n"); | ||
215 | dprintk(1, " .status = 0x%08x\n", s->status); | ||
216 | dprintk(1, " .mode = 0x%08x\n", s->mode); | ||
217 | dprintk(1, " .spec = 0x%08x\n", s->spec); | ||
218 | dprintk(1, " .inst = 0x%08x\n", s->inst); | ||
219 | dprintk(1, " .cpuload = 0x%08x\n", s->cpuload); | ||
220 | dprintk(1, " .remainheap = 0x%08x\n", s->remainheap); | ||
221 | } | ||
222 | |||
223 | u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev) | ||
224 | { | ||
225 | u32 reg; | ||
226 | |||
227 | reg = saa7164_readl(SAA_DEVICE_VERSION); | ||
228 | dprintk(1, "Device running firmware version %d.%d.%d.%d (0x%x)\n", | ||
229 | (reg & 0x0000fc00) >> 10, | ||
230 | (reg & 0x000003e0) >> 5, | ||
231 | (reg & 0x0000001f), | ||
232 | (reg & 0xffff0000) >> 16, | ||
233 | reg); | ||
234 | |||
235 | return reg; | ||
236 | } | ||
237 | |||
238 | /* TODO: Debugging func, remove */ | ||
239 | void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len) | ||
240 | { | ||
241 | int i; | ||
242 | |||
243 | printk(KERN_INFO "--------------------> " | ||
244 | "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); | ||
245 | |||
246 | for (i = 0; i < len; i += 16) | ||
247 | printk(KERN_INFO " [0x%08x] " | ||
248 | "%02x %02x %02x %02x %02x %02x %02x %02x " | ||
249 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, | ||
250 | *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3), | ||
251 | *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7), | ||
252 | *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11), | ||
253 | *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15)); | ||
254 | } | ||
255 | |||
256 | /* TODO: Debugging func, remove */ | ||
257 | void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr) | ||
258 | { | ||
259 | int i; | ||
260 | |||
261 | dprintk(1, "--------------------> " | ||
262 | "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); | ||
263 | |||
264 | for (i = 0; i < 0x100; i += 16) | ||
265 | dprintk(1, "region0[0x%08x] = " | ||
266 | "%02x %02x %02x %02x %02x %02x %02x %02x" | ||
267 | " %02x %02x %02x %02x %02x %02x %02x %02x\n", i, | ||
268 | (u8)saa7164_readb(addr + i + 0), | ||
269 | (u8)saa7164_readb(addr + i + 1), | ||
270 | (u8)saa7164_readb(addr + i + 2), | ||
271 | (u8)saa7164_readb(addr + i + 3), | ||
272 | (u8)saa7164_readb(addr + i + 4), | ||
273 | (u8)saa7164_readb(addr + i + 5), | ||
274 | (u8)saa7164_readb(addr + i + 6), | ||
275 | (u8)saa7164_readb(addr + i + 7), | ||
276 | (u8)saa7164_readb(addr + i + 8), | ||
277 | (u8)saa7164_readb(addr + i + 9), | ||
278 | (u8)saa7164_readb(addr + i + 10), | ||
279 | (u8)saa7164_readb(addr + i + 11), | ||
280 | (u8)saa7164_readb(addr + i + 12), | ||
281 | (u8)saa7164_readb(addr + i + 13), | ||
282 | (u8)saa7164_readb(addr + i + 14), | ||
283 | (u8)saa7164_readb(addr + i + 15) | ||
284 | ); | ||
285 | } | ||
286 | |||
287 | static void saa7164_dump_hwdesc(struct saa7164_dev *dev) | ||
288 | { | ||
289 | dprintk(1, "@0x%p hwdesc sizeof(tmComResHWDescr_t) = %d bytes\n", | ||
290 | &dev->hwdesc, (u32)sizeof(tmComResHWDescr_t)); | ||
291 | |||
292 | dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength); | ||
293 | dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType); | ||
294 | dprintk(1, " .bDescriptorSubtype = 0x%x\n", | ||
295 | dev->hwdesc.bDescriptorSubtype); | ||
296 | |||
297 | dprintk(1, " .bcdSpecVersion = 0x%x\n", dev->hwdesc.bcdSpecVersion); | ||
298 | dprintk(1, " .dwClockFrequency = 0x%x\n", dev->hwdesc.dwClockFrequency); | ||
299 | dprintk(1, " .dwClockUpdateRes = 0x%x\n", dev->hwdesc.dwClockUpdateRes); | ||
300 | dprintk(1, " .bCapabilities = 0x%x\n", dev->hwdesc.bCapabilities); | ||
301 | dprintk(1, " .dwDeviceRegistersLocation = 0x%x\n", | ||
302 | dev->hwdesc.dwDeviceRegistersLocation); | ||
303 | |||
304 | dprintk(1, " .dwHostMemoryRegion = 0x%x\n", | ||
305 | dev->hwdesc.dwHostMemoryRegion); | ||
306 | |||
307 | dprintk(1, " .dwHostMemoryRegionSize = 0x%x\n", | ||
308 | dev->hwdesc.dwHostMemoryRegionSize); | ||
309 | |||
310 | dprintk(1, " .dwHostHibernatMemRegion = 0x%x\n", | ||
311 | dev->hwdesc.dwHostHibernatMemRegion); | ||
312 | |||
313 | dprintk(1, " .dwHostHibernatMemRegionSize = 0x%x\n", | ||
314 | dev->hwdesc.dwHostHibernatMemRegionSize); | ||
315 | } | ||
316 | |||
317 | static void saa7164_dump_intfdesc(struct saa7164_dev *dev) | ||
318 | { | ||
319 | dprintk(1, "@0x%p intfdesc " | ||
320 | "sizeof(tmComResInterfaceDescr_t) = %d bytes\n", | ||
321 | &dev->intfdesc, (u32)sizeof(tmComResInterfaceDescr_t)); | ||
322 | |||
323 | dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength); | ||
324 | dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType); | ||
325 | dprintk(1, " .bDescriptorSubtype = 0x%x\n", | ||
326 | dev->intfdesc.bDescriptorSubtype); | ||
327 | |||
328 | dprintk(1, " .bFlags = 0x%x\n", dev->intfdesc.bFlags); | ||
329 | dprintk(1, " .bInterfaceType = 0x%x\n", dev->intfdesc.bInterfaceType); | ||
330 | dprintk(1, " .bInterfaceId = 0x%x\n", dev->intfdesc.bInterfaceId); | ||
331 | dprintk(1, " .bBaseInterface = 0x%x\n", dev->intfdesc.bBaseInterface); | ||
332 | dprintk(1, " .bInterruptId = 0x%x\n", dev->intfdesc.bInterruptId); | ||
333 | dprintk(1, " .bDebugInterruptId = 0x%x\n", | ||
334 | dev->intfdesc.bDebugInterruptId); | ||
335 | |||
336 | dprintk(1, " .BARLocation = 0x%x\n", dev->intfdesc.BARLocation); | ||
337 | } | ||
338 | |||
339 | static void saa7164_dump_busdesc(struct saa7164_dev *dev) | ||
340 | { | ||
341 | dprintk(1, "@0x%p busdesc sizeof(tmComResBusDescr_t) = %d bytes\n", | ||
342 | &dev->busdesc, (u32)sizeof(tmComResBusDescr_t)); | ||
343 | |||
344 | dprintk(1, " .CommandRing = 0x%016Lx\n", dev->busdesc.CommandRing); | ||
345 | dprintk(1, " .ResponseRing = 0x%016Lx\n", dev->busdesc.ResponseRing); | ||
346 | dprintk(1, " .CommandWrite = 0x%x\n", dev->busdesc.CommandWrite); | ||
347 | dprintk(1, " .CommandRead = 0x%x\n", dev->busdesc.CommandRead); | ||
348 | dprintk(1, " .ResponseWrite = 0x%x\n", dev->busdesc.ResponseWrite); | ||
349 | dprintk(1, " .ResponseRead = 0x%x\n", dev->busdesc.ResponseRead); | ||
350 | } | ||
351 | |||
352 | /* Much of the hardware configuration and PCI registers are configured | ||
353 | * dynamically depending on firmware. We have to cache some initial | ||
354 | * structures then use these to locate other important structures | ||
355 | * from PCI space. | ||
356 | */ | ||
357 | static void saa7164_get_descriptors(struct saa7164_dev *dev) | ||
358 | { | ||
359 | memcpy(&dev->hwdesc, dev->bmmio, sizeof(tmComResHWDescr_t)); | ||
360 | memcpy(&dev->intfdesc, dev->bmmio + sizeof(tmComResHWDescr_t), | ||
361 | sizeof(tmComResInterfaceDescr_t)); | ||
362 | memcpy(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation, | ||
363 | sizeof(tmComResBusDescr_t)); | ||
364 | |||
365 | if (dev->hwdesc.bLength != sizeof(tmComResHWDescr_t)) { | ||
366 | printk(KERN_ERR "Structure tmComResHWDescr_t is mangled\n"); | ||
367 | printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength, | ||
368 | (u32)sizeof(tmComResHWDescr_t)); | ||
369 | } else | ||
370 | saa7164_dump_hwdesc(dev); | ||
371 | |||
372 | if (dev->intfdesc.bLength != sizeof(tmComResInterfaceDescr_t)) { | ||
373 | printk(KERN_ERR "struct tmComResInterfaceDescr_t is mangled\n"); | ||
374 | printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength, | ||
375 | (u32)sizeof(tmComResInterfaceDescr_t)); | ||
376 | } else | ||
377 | saa7164_dump_intfdesc(dev); | ||
378 | |||
379 | saa7164_dump_busdesc(dev); | ||
380 | } | ||
381 | |||
382 | static int saa7164_pci_quirks(struct saa7164_dev *dev) | ||
383 | { | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int get_resources(struct saa7164_dev *dev) | ||
388 | { | ||
389 | if (request_mem_region(pci_resource_start(dev->pci, 0), | ||
390 | pci_resource_len(dev->pci, 0), dev->name)) { | ||
391 | |||
392 | if (request_mem_region(pci_resource_start(dev->pci, 2), | ||
393 | pci_resource_len(dev->pci, 2), dev->name)) | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n", | ||
398 | dev->name, | ||
399 | (u64)pci_resource_start(dev->pci, 0), | ||
400 | (u64)pci_resource_start(dev->pci, 2)); | ||
401 | |||
402 | return -EBUSY; | ||
403 | } | ||
404 | |||
405 | static int saa7164_dev_setup(struct saa7164_dev *dev) | ||
406 | { | ||
407 | int i; | ||
408 | |||
409 | mutex_init(&dev->lock); | ||
410 | atomic_inc(&dev->refcount); | ||
411 | dev->nr = saa7164_devcount++; | ||
412 | |||
413 | sprintf(dev->name, "saa7164[%d]", dev->nr); | ||
414 | |||
415 | mutex_lock(&devlist); | ||
416 | list_add_tail(&dev->devlist, &saa7164_devlist); | ||
417 | mutex_unlock(&devlist); | ||
418 | |||
419 | /* board config */ | ||
420 | dev->board = UNSET; | ||
421 | if (card[dev->nr] < saa7164_bcount) | ||
422 | dev->board = card[dev->nr]; | ||
423 | |||
424 | for (i = 0; UNSET == dev->board && i < saa7164_idcount; i++) | ||
425 | if (dev->pci->subsystem_vendor == saa7164_subids[i].subvendor && | ||
426 | dev->pci->subsystem_device == | ||
427 | saa7164_subids[i].subdevice) | ||
428 | dev->board = saa7164_subids[i].card; | ||
429 | |||
430 | if (UNSET == dev->board) { | ||
431 | dev->board = SAA7164_BOARD_UNKNOWN; | ||
432 | saa7164_card_list(dev); | ||
433 | } | ||
434 | |||
435 | dev->pci_bus = dev->pci->bus->number; | ||
436 | dev->pci_slot = PCI_SLOT(dev->pci->devfn); | ||
437 | |||
438 | /* I2C Defaults / setup */ | ||
439 | dev->i2c_bus[0].dev = dev; | ||
440 | dev->i2c_bus[0].nr = 0; | ||
441 | dev->i2c_bus[1].dev = dev; | ||
442 | dev->i2c_bus[1].nr = 1; | ||
443 | dev->i2c_bus[2].dev = dev; | ||
444 | dev->i2c_bus[2].nr = 2; | ||
445 | |||
446 | /* Transport port A Defaults / setup */ | ||
447 | dev->ts1.dev = dev; | ||
448 | dev->ts1.nr = 0; | ||
449 | mutex_init(&dev->ts1.dvb.lock); | ||
450 | INIT_LIST_HEAD(&dev->ts1.dmaqueue.list); | ||
451 | INIT_LIST_HEAD(&dev->ts1.dummy_dmaqueue.list); | ||
452 | mutex_init(&dev->ts1.dmaqueue_lock); | ||
453 | mutex_init(&dev->ts1.dummy_dmaqueue_lock); | ||
454 | |||
455 | /* Transport port B Defaults / setup */ | ||
456 | dev->ts2.dev = dev; | ||
457 | dev->ts2.nr = 1; | ||
458 | mutex_init(&dev->ts2.dvb.lock); | ||
459 | INIT_LIST_HEAD(&dev->ts2.dmaqueue.list); | ||
460 | INIT_LIST_HEAD(&dev->ts2.dummy_dmaqueue.list); | ||
461 | mutex_init(&dev->ts2.dmaqueue_lock); | ||
462 | mutex_init(&dev->ts2.dummy_dmaqueue_lock); | ||
463 | |||
464 | if (get_resources(dev) < 0) { | ||
465 | printk(KERN_ERR "CORE %s No more PCIe resources for " | ||
466 | "subsystem: %04x:%04x\n", | ||
467 | dev->name, dev->pci->subsystem_vendor, | ||
468 | dev->pci->subsystem_device); | ||
469 | |||
470 | saa7164_devcount--; | ||
471 | return -ENODEV; | ||
472 | } | ||
473 | |||
474 | /* PCI/e allocations */ | ||
475 | dev->lmmio = ioremap(pci_resource_start(dev->pci, 0), | ||
476 | pci_resource_len(dev->pci, 0)); | ||
477 | |||
478 | dev->lmmio2 = ioremap(pci_resource_start(dev->pci, 2), | ||
479 | pci_resource_len(dev->pci, 2)); | ||
480 | |||
481 | dev->bmmio = (u8 __iomem *)dev->lmmio; | ||
482 | dev->bmmio2 = (u8 __iomem *)dev->lmmio2; | ||
483 | |||
484 | /* Inerrupt and ack register locations offset of bmmio */ | ||
485 | dev->int_status = 0x183000 + 0xf80; | ||
486 | dev->int_ack = 0x183000 + 0xf90; | ||
487 | |||
488 | printk(KERN_INFO | ||
489 | "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", | ||
490 | dev->name, dev->pci->subsystem_vendor, | ||
491 | dev->pci->subsystem_device, saa7164_boards[dev->board].name, | ||
492 | dev->board, card[dev->nr] == dev->board ? | ||
493 | "insmod option" : "autodetected"); | ||
494 | |||
495 | saa7164_pci_quirks(dev); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static void saa7164_dev_unregister(struct saa7164_dev *dev) | ||
501 | { | ||
502 | dprintk(1, "%s()\n", __func__); | ||
503 | |||
504 | release_mem_region(pci_resource_start(dev->pci, 0), | ||
505 | pci_resource_len(dev->pci, 0)); | ||
506 | |||
507 | release_mem_region(pci_resource_start(dev->pci, 2), | ||
508 | pci_resource_len(dev->pci, 2)); | ||
509 | |||
510 | if (!atomic_dec_and_test(&dev->refcount)) | ||
511 | return; | ||
512 | |||
513 | iounmap(dev->lmmio); | ||
514 | iounmap(dev->lmmio2); | ||
515 | |||
516 | return; | ||
517 | } | ||
518 | |||
519 | static int __devinit saa7164_initdev(struct pci_dev *pci_dev, | ||
520 | const struct pci_device_id *pci_id) | ||
521 | { | ||
522 | struct saa7164_dev *dev; | ||
523 | int err, i; | ||
524 | u32 version; | ||
525 | |||
526 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
527 | if (NULL == dev) | ||
528 | return -ENOMEM; | ||
529 | |||
530 | /* pci init */ | ||
531 | dev->pci = pci_dev; | ||
532 | if (pci_enable_device(pci_dev)) { | ||
533 | err = -EIO; | ||
534 | goto fail_free; | ||
535 | } | ||
536 | |||
537 | if (saa7164_dev_setup(dev) < 0) { | ||
538 | err = -EINVAL; | ||
539 | goto fail_free; | ||
540 | } | ||
541 | |||
542 | /* print pci info */ | ||
543 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | ||
544 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | ||
545 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | ||
546 | "latency: %d, mmio: 0x%llx\n", dev->name, | ||
547 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, | ||
548 | dev->pci_lat, | ||
549 | (unsigned long long)pci_resource_start(pci_dev, 0)); | ||
550 | |||
551 | pci_set_master(pci_dev); | ||
552 | /* TODO */ | ||
553 | if (!pci_dma_supported(pci_dev, 0xffffffff)) { | ||
554 | printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); | ||
555 | err = -EIO; | ||
556 | goto fail_irq; | ||
557 | } | ||
558 | |||
559 | err = request_irq(pci_dev->irq, saa7164_irq, | ||
560 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); | ||
561 | if (err < 0) { | ||
562 | printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, | ||
563 | pci_dev->irq); | ||
564 | err = -EIO; | ||
565 | goto fail_irq; | ||
566 | } | ||
567 | |||
568 | pci_set_drvdata(pci_dev, dev); | ||
569 | |||
570 | /* Init the internal command list */ | ||
571 | for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { | ||
572 | dev->cmds[i].seqno = i; | ||
573 | dev->cmds[i].inuse = 0; | ||
574 | mutex_init(&dev->cmds[i].lock); | ||
575 | init_waitqueue_head(&dev->cmds[i].wait); | ||
576 | } | ||
577 | |||
578 | /* We need a deferred interrupt handler for cmd handling */ | ||
579 | INIT_WORK(&dev->workcmd, saa7164_work_cmdhandler); | ||
580 | |||
581 | /* Only load the firmware if we know the board */ | ||
582 | if (dev->board != SAA7164_BOARD_UNKNOWN) { | ||
583 | |||
584 | err = saa7164_downloadfirmware(dev); | ||
585 | if (err < 0) { | ||
586 | printk(KERN_ERR | ||
587 | "Failed to boot firmware, no features " | ||
588 | "registered\n"); | ||
589 | goto fail_fw; | ||
590 | } | ||
591 | |||
592 | saa7164_get_descriptors(dev); | ||
593 | saa7164_dumpregs(dev, 0); | ||
594 | saa7164_getcurrentfirmwareversion(dev); | ||
595 | saa7164_getfirmwarestatus(dev); | ||
596 | err = saa7164_bus_setup(dev); | ||
597 | if (err < 0) | ||
598 | printk(KERN_ERR | ||
599 | "Failed to setup the bus, will continue\n"); | ||
600 | saa7164_bus_dump(dev); | ||
601 | |||
602 | /* Ping the running firmware via the command bus and get the | ||
603 | * firmware version, this checks the bus is running OK. | ||
604 | */ | ||
605 | version = 0; | ||
606 | if (saa7164_api_get_fw_version(dev, &version) == SAA_OK) | ||
607 | dprintk(1, "Bus is operating correctly using " | ||
608 | "version %d.%d.%d.%d (0x%x)\n", | ||
609 | (version & 0x0000fc00) >> 10, | ||
610 | (version & 0x000003e0) >> 5, | ||
611 | (version & 0x0000001f), | ||
612 | (version & 0xffff0000) >> 16, | ||
613 | version); | ||
614 | else | ||
615 | printk(KERN_ERR | ||
616 | "Failed to communicate with the firmware\n"); | ||
617 | |||
618 | /* Bring up the I2C buses */ | ||
619 | saa7164_i2c_register(&dev->i2c_bus[0]); | ||
620 | saa7164_i2c_register(&dev->i2c_bus[1]); | ||
621 | saa7164_i2c_register(&dev->i2c_bus[2]); | ||
622 | saa7164_gpio_setup(dev); | ||
623 | saa7164_card_setup(dev); | ||
624 | |||
625 | |||
626 | /* Parse the dynamic device configuration, find various | ||
627 | * media endpoints (MPEG, WMV, PS, TS) and cache their | ||
628 | * configuration details into the driver, so we can | ||
629 | * reference them later during simething_register() func, | ||
630 | * interrupt handlers, deferred work handlers etc. | ||
631 | */ | ||
632 | saa7164_api_enum_subdevs(dev); | ||
633 | |||
634 | /* Begin to create the video sub-systems and register funcs */ | ||
635 | if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) { | ||
636 | if (saa7164_dvb_register(&dev->ts1) < 0) { | ||
637 | printk(KERN_ERR "%s() Failed to register " | ||
638 | "dvb adapters on porta\n", | ||
639 | __func__); | ||
640 | } | ||
641 | } | ||
642 | |||
643 | if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) { | ||
644 | if (saa7164_dvb_register(&dev->ts2) < 0) { | ||
645 | printk(KERN_ERR"%s() Failed to register " | ||
646 | "dvb adapters on portb\n", | ||
647 | __func__); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | } /* != BOARD_UNKNOWN */ | ||
652 | else | ||
653 | printk(KERN_ERR "%s() Unsupported board detected, " | ||
654 | "registering without firmware\n", __func__); | ||
655 | |||
656 | dprintk(1, "%s() parameter debug = %d\n", __func__, debug); | ||
657 | dprintk(1, "%s() parameter waitsecs = %d\n", __func__, waitsecs); | ||
658 | |||
659 | fail_fw: | ||
660 | return 0; | ||
661 | |||
662 | fail_irq: | ||
663 | saa7164_dev_unregister(dev); | ||
664 | fail_free: | ||
665 | kfree(dev); | ||
666 | return err; | ||
667 | } | ||
668 | |||
669 | static void saa7164_shutdown(struct saa7164_dev *dev) | ||
670 | { | ||
671 | dprintk(1, "%s()\n", __func__); | ||
672 | } | ||
673 | |||
674 | static void __devexit saa7164_finidev(struct pci_dev *pci_dev) | ||
675 | { | ||
676 | struct saa7164_dev *dev = pci_get_drvdata(pci_dev); | ||
677 | |||
678 | saa7164_shutdown(dev); | ||
679 | |||
680 | if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) | ||
681 | saa7164_dvb_unregister(&dev->ts1); | ||
682 | |||
683 | if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) | ||
684 | saa7164_dvb_unregister(&dev->ts2); | ||
685 | |||
686 | saa7164_i2c_unregister(&dev->i2c_bus[0]); | ||
687 | saa7164_i2c_unregister(&dev->i2c_bus[1]); | ||
688 | saa7164_i2c_unregister(&dev->i2c_bus[2]); | ||
689 | |||
690 | pci_disable_device(pci_dev); | ||
691 | |||
692 | /* unregister stuff */ | ||
693 | free_irq(pci_dev->irq, dev); | ||
694 | pci_set_drvdata(pci_dev, NULL); | ||
695 | |||
696 | mutex_lock(&devlist); | ||
697 | list_del(&dev->devlist); | ||
698 | mutex_unlock(&devlist); | ||
699 | |||
700 | saa7164_dev_unregister(dev); | ||
701 | kfree(dev); | ||
702 | } | ||
703 | |||
704 | static struct pci_device_id saa7164_pci_tbl[] = { | ||
705 | { | ||
706 | /* SAA7164 */ | ||
707 | .vendor = 0x1131, | ||
708 | .device = 0x7164, | ||
709 | .subvendor = PCI_ANY_ID, | ||
710 | .subdevice = PCI_ANY_ID, | ||
711 | }, { | ||
712 | /* --- end of list --- */ | ||
713 | } | ||
714 | }; | ||
715 | MODULE_DEVICE_TABLE(pci, saa7164_pci_tbl); | ||
716 | |||
717 | static struct pci_driver saa7164_pci_driver = { | ||
718 | .name = "saa7164", | ||
719 | .id_table = saa7164_pci_tbl, | ||
720 | .probe = saa7164_initdev, | ||
721 | .remove = __devexit_p(saa7164_finidev), | ||
722 | /* TODO */ | ||
723 | .suspend = NULL, | ||
724 | .resume = NULL, | ||
725 | }; | ||
726 | |||
727 | static int saa7164_init(void) | ||
728 | { | ||
729 | printk(KERN_INFO "saa7164 driver loaded\n"); | ||
730 | return pci_register_driver(&saa7164_pci_driver); | ||
731 | } | ||
732 | |||
733 | static void saa7164_fini(void) | ||
734 | { | ||
735 | pci_unregister_driver(&saa7164_pci_driver); | ||
736 | } | ||
737 | |||
738 | module_init(saa7164_init); | ||
739 | module_exit(saa7164_fini); | ||
740 | |||
diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c new file mode 100644 index 000000000000..6a2d847d6a88 --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-dvb.c | |||
@@ -0,0 +1,602 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "saa7164.h" | ||
23 | |||
24 | #include "tda10048.h" | ||
25 | #include "tda18271.h" | ||
26 | #include "s5h1411.h" | ||
27 | |||
28 | #define DRIVER_NAME "saa7164" | ||
29 | |||
30 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
31 | |||
32 | /* addr is in the card struct, get it from there */ | ||
33 | static struct tda10048_config hauppauge_hvr2200_1_config = { | ||
34 | .demod_address = 0x10 >> 1, | ||
35 | .output_mode = TDA10048_SERIAL_OUTPUT, | ||
36 | .fwbulkwritelen = TDA10048_BULKWRITE_200, | ||
37 | .inversion = TDA10048_INVERSION_ON, | ||
38 | .dtv6_if_freq_khz = TDA10048_IF_3300, | ||
39 | .dtv7_if_freq_khz = TDA10048_IF_3500, | ||
40 | .dtv8_if_freq_khz = TDA10048_IF_4000, | ||
41 | .clk_freq_khz = TDA10048_CLK_16000, | ||
42 | }; | ||
43 | static struct tda10048_config hauppauge_hvr2200_2_config = { | ||
44 | .demod_address = 0x12 >> 1, | ||
45 | .output_mode = TDA10048_SERIAL_OUTPUT, | ||
46 | .fwbulkwritelen = TDA10048_BULKWRITE_200, | ||
47 | .inversion = TDA10048_INVERSION_ON, | ||
48 | .dtv6_if_freq_khz = TDA10048_IF_3300, | ||
49 | .dtv7_if_freq_khz = TDA10048_IF_3500, | ||
50 | .dtv8_if_freq_khz = TDA10048_IF_4000, | ||
51 | .clk_freq_khz = TDA10048_CLK_16000, | ||
52 | }; | ||
53 | |||
54 | static struct tda18271_std_map hauppauge_tda18271_std_map = { | ||
55 | .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3, | ||
56 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
57 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, | ||
58 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
59 | }; | ||
60 | |||
61 | static struct tda18271_config hauppauge_hvr22x0_tuner_config = { | ||
62 | .std_map = &hauppauge_tda18271_std_map, | ||
63 | .gate = TDA18271_GATE_ANALOG, | ||
64 | .role = TDA18271_MASTER, | ||
65 | }; | ||
66 | |||
67 | static struct tda18271_config hauppauge_hvr22x0s_tuner_config = { | ||
68 | .std_map = &hauppauge_tda18271_std_map, | ||
69 | .gate = TDA18271_GATE_ANALOG, | ||
70 | .role = TDA18271_SLAVE, | ||
71 | .rf_cal_on_startup = 1 | ||
72 | }; | ||
73 | |||
74 | static struct s5h1411_config hauppauge_s5h1411_config = { | ||
75 | .output_mode = S5H1411_SERIAL_OUTPUT, | ||
76 | .gpio = S5H1411_GPIO_ON, | ||
77 | .qam_if = S5H1411_IF_4000, | ||
78 | .vsb_if = S5H1411_IF_3250, | ||
79 | .inversion = S5H1411_INVERSION_ON, | ||
80 | .status_mode = S5H1411_DEMODLOCKING, | ||
81 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
82 | }; | ||
83 | |||
84 | static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port) | ||
85 | { | ||
86 | struct saa7164_dev *dev = port->dev; | ||
87 | int ret; | ||
88 | |||
89 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
90 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
91 | printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", | ||
92 | __func__, ret); | ||
93 | ret = -EIO; | ||
94 | } else { | ||
95 | dprintk(DBGLVL_DVB, "%s() Stopped\n", __func__); | ||
96 | ret = 0; | ||
97 | } | ||
98 | |||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port) | ||
103 | { | ||
104 | struct saa7164_dev *dev = port->dev; | ||
105 | int ret; | ||
106 | |||
107 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); | ||
108 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
109 | printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", | ||
110 | __func__, ret); | ||
111 | ret = -EIO; | ||
112 | } else { | ||
113 | dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); | ||
114 | ret = 0; | ||
115 | } | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port) | ||
121 | { | ||
122 | struct saa7164_dev *dev = port->dev; | ||
123 | int ret; | ||
124 | |||
125 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); | ||
126 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
127 | printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", | ||
128 | __func__, ret); | ||
129 | ret = -EIO; | ||
130 | } else { | ||
131 | dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); | ||
132 | ret = 0; | ||
133 | } | ||
134 | |||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | /* Firmware is very windows centric, meaning you have to transition | ||
139 | * the part through AVStream / KS Windows stages, forwards or backwards. | ||
140 | * States are: stopped, acquired (h/w), paused, started. | ||
141 | */ | ||
142 | static int saa7164_dvb_stop_streaming(struct saa7164_tsport *port) | ||
143 | { | ||
144 | struct saa7164_dev *dev = port->dev; | ||
145 | int ret; | ||
146 | |||
147 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | ||
148 | |||
149 | ret = saa7164_dvb_pause_tsport(port); | ||
150 | ret = saa7164_dvb_acquire_tsport(port); | ||
151 | ret = saa7164_dvb_stop_tsport(port); | ||
152 | |||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | static int saa7164_dvb_cfg_tsport(struct saa7164_tsport *port) | ||
157 | { | ||
158 | tmHWStreamParameters_t *params = &port->hw_streamingparams; | ||
159 | struct saa7164_dev *dev = port->dev; | ||
160 | struct saa7164_buffer *buf; | ||
161 | struct list_head *c, *n; | ||
162 | int i = 0; | ||
163 | |||
164 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | ||
165 | |||
166 | saa7164_writel(port->pitch, params->pitch); | ||
167 | saa7164_writel(port->bufsize, params->pitch * params->numberoflines); | ||
168 | |||
169 | dprintk(DBGLVL_DVB, " configured:\n"); | ||
170 | dprintk(DBGLVL_DVB, " lmmio 0x%p\n", dev->lmmio); | ||
171 | dprintk(DBGLVL_DVB, " bufcounter 0x%x = 0x%x\n", port->bufcounter, | ||
172 | saa7164_readl(port->bufcounter)); | ||
173 | |||
174 | dprintk(DBGLVL_DVB, " pitch 0x%x = %d\n", port->pitch, | ||
175 | saa7164_readl(port->pitch)); | ||
176 | |||
177 | dprintk(DBGLVL_DVB, " bufsize 0x%x = %d\n", port->bufsize, | ||
178 | saa7164_readl(port->bufsize)); | ||
179 | |||
180 | dprintk(DBGLVL_DVB, " buffercount = %d\n", port->hwcfg.buffercount); | ||
181 | dprintk(DBGLVL_DVB, " bufoffset = 0x%x\n", port->bufoffset); | ||
182 | dprintk(DBGLVL_DVB, " bufptr32h = 0x%x\n", port->bufptr32h); | ||
183 | dprintk(DBGLVL_DVB, " bufptr32l = 0x%x\n", port->bufptr32l); | ||
184 | |||
185 | /* Poke the buffers and offsets into PCI space */ | ||
186 | mutex_lock(&port->dmaqueue_lock); | ||
187 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
188 | buf = list_entry(c, struct saa7164_buffer, list); | ||
189 | |||
190 | /* TODO: Review this in light of 32v64 assignments */ | ||
191 | saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0); | ||
192 | saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), | ||
193 | buf->pt_dma); | ||
194 | saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0); | ||
195 | |||
196 | dprintk(DBGLVL_DVB, | ||
197 | " buf[%d] offset 0x%llx (0x%x) " | ||
198 | "buf 0x%llx/%llx (0x%x/%x)\n", | ||
199 | i, | ||
200 | (u64)port->bufoffset + (i * sizeof(u32)), | ||
201 | saa7164_readl(port->bufoffset + (sizeof(u32) * i)), | ||
202 | (u64)port->bufptr32h + ((sizeof(u32) * 2) * i), | ||
203 | (u64)port->bufptr32l + ((sizeof(u32) * 2) * i), | ||
204 | saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) | ||
205 | * 2)), | ||
206 | saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) | ||
207 | * 2))); | ||
208 | |||
209 | if (i++ > port->hwcfg.buffercount) | ||
210 | BUG(); | ||
211 | |||
212 | } | ||
213 | mutex_unlock(&port->dmaqueue_lock); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int saa7164_dvb_start_tsport(struct saa7164_tsport *port) | ||
219 | { | ||
220 | struct saa7164_dev *dev = port->dev; | ||
221 | int ret = 0, result; | ||
222 | |||
223 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | ||
224 | |||
225 | saa7164_dvb_cfg_tsport(port); | ||
226 | |||
227 | /* Acquire the hardware */ | ||
228 | result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); | ||
229 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
230 | printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", | ||
231 | __func__, result); | ||
232 | |||
233 | /* Stop the hardware, regardless */ | ||
234 | result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
235 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
236 | printk(KERN_ERR "%s() acquire/forced stop transition " | ||
237 | "failed, res = 0x%x\n", __func__, result); | ||
238 | } | ||
239 | ret = -EIO; | ||
240 | goto out; | ||
241 | } else | ||
242 | dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); | ||
243 | |||
244 | /* Pause the hardware */ | ||
245 | result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); | ||
246 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
247 | printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", | ||
248 | __func__, result); | ||
249 | |||
250 | /* Stop the hardware, regardless */ | ||
251 | result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
252 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
253 | printk(KERN_ERR "%s() pause/forced stop transition " | ||
254 | "failed, res = 0x%x\n", __func__, result); | ||
255 | } | ||
256 | |||
257 | ret = -EIO; | ||
258 | goto out; | ||
259 | } else | ||
260 | dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); | ||
261 | |||
262 | /* Start the hardware */ | ||
263 | result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); | ||
264 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
265 | printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", | ||
266 | __func__, result); | ||
267 | |||
268 | /* Stop the hardware, regardless */ | ||
269 | result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
270 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
271 | printk(KERN_ERR "%s() run/forced stop transition " | ||
272 | "failed, res = 0x%x\n", __func__, result); | ||
273 | } | ||
274 | |||
275 | ret = -EIO; | ||
276 | } else | ||
277 | dprintk(DBGLVL_DVB, "%s() Running\n", __func__); | ||
278 | |||
279 | out: | ||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) | ||
284 | { | ||
285 | struct dvb_demux *demux = feed->demux; | ||
286 | struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv; | ||
287 | struct saa7164_dvb *dvb = &port->dvb; | ||
288 | struct saa7164_dev *dev = port->dev; | ||
289 | int ret = 0; | ||
290 | |||
291 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | ||
292 | |||
293 | if (!demux->dmx.frontend) | ||
294 | return -EINVAL; | ||
295 | |||
296 | if (dvb) { | ||
297 | mutex_lock(&dvb->lock); | ||
298 | if (dvb->feeding++ == 0) { | ||
299 | /* Start transport */ | ||
300 | ret = saa7164_dvb_start_tsport(port); | ||
301 | } | ||
302 | mutex_unlock(&dvb->lock); | ||
303 | dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", | ||
304 | __func__, port->nr, dvb->feeding); | ||
305 | } | ||
306 | |||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) | ||
311 | { | ||
312 | struct dvb_demux *demux = feed->demux; | ||
313 | struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv; | ||
314 | struct saa7164_dvb *dvb = &port->dvb; | ||
315 | struct saa7164_dev *dev = port->dev; | ||
316 | int ret = 0; | ||
317 | |||
318 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | ||
319 | |||
320 | if (dvb) { | ||
321 | mutex_lock(&dvb->lock); | ||
322 | if (--dvb->feeding == 0) { | ||
323 | /* Stop transport */ | ||
324 | ret = saa7164_dvb_stop_streaming(port); | ||
325 | } | ||
326 | mutex_unlock(&dvb->lock); | ||
327 | dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", | ||
328 | __func__, port->nr, dvb->feeding); | ||
329 | } | ||
330 | |||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static int dvb_register(struct saa7164_tsport *port) | ||
335 | { | ||
336 | struct saa7164_dvb *dvb = &port->dvb; | ||
337 | struct saa7164_dev *dev = port->dev; | ||
338 | struct saa7164_buffer *buf; | ||
339 | int result, i; | ||
340 | |||
341 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | ||
342 | |||
343 | /* Sanity check that the PCI configuration space is active */ | ||
344 | if (port->hwcfg.BARLocation == 0) { | ||
345 | result = -ENOMEM; | ||
346 | printk(KERN_ERR "%s: dvb_register_adapter failed " | ||
347 | "(errno = %d), NO PCI configuration\n", | ||
348 | DRIVER_NAME, result); | ||
349 | goto fail_adapter; | ||
350 | } | ||
351 | |||
352 | /* Init and establish defaults */ | ||
353 | port->hw_streamingparams.bitspersample = 8; | ||
354 | port->hw_streamingparams.samplesperline = 188; | ||
355 | port->hw_streamingparams.numberoflines = | ||
356 | (SAA7164_TS_NUMBER_OF_LINES * 188) / 188; | ||
357 | |||
358 | port->hw_streamingparams.pitch = 188; | ||
359 | port->hw_streamingparams.linethreshold = 0; | ||
360 | port->hw_streamingparams.pagetablelistvirt = 0; | ||
361 | port->hw_streamingparams.pagetablelistphys = 0; | ||
362 | port->hw_streamingparams.numpagetables = 2 + | ||
363 | ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE); | ||
364 | |||
365 | port->hw_streamingparams.numpagetableentries = port->hwcfg.buffercount; | ||
366 | |||
367 | /* Allocate the PCI resources */ | ||
368 | for (i = 0; i < port->hwcfg.buffercount; i++) { | ||
369 | buf = saa7164_buffer_alloc(port, | ||
370 | port->hw_streamingparams.numberoflines * | ||
371 | port->hw_streamingparams.pitch); | ||
372 | |||
373 | if (!buf) { | ||
374 | result = -ENOMEM; | ||
375 | printk(KERN_ERR "%s: dvb_register_adapter failed " | ||
376 | "(errno = %d), unable to allocate buffers\n", | ||
377 | DRIVER_NAME, result); | ||
378 | goto fail_adapter; | ||
379 | } | ||
380 | buf->nr = i; | ||
381 | |||
382 | mutex_lock(&port->dmaqueue_lock); | ||
383 | list_add_tail(&buf->list, &port->dmaqueue.list); | ||
384 | mutex_unlock(&port->dmaqueue_lock); | ||
385 | } | ||
386 | |||
387 | /* register adapter */ | ||
388 | result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, | ||
389 | &dev->pci->dev, adapter_nr); | ||
390 | if (result < 0) { | ||
391 | printk(KERN_ERR "%s: dvb_register_adapter failed " | ||
392 | "(errno = %d)\n", DRIVER_NAME, result); | ||
393 | goto fail_adapter; | ||
394 | } | ||
395 | dvb->adapter.priv = port; | ||
396 | |||
397 | /* register frontend */ | ||
398 | result = dvb_register_frontend(&dvb->adapter, dvb->frontend); | ||
399 | if (result < 0) { | ||
400 | printk(KERN_ERR "%s: dvb_register_frontend failed " | ||
401 | "(errno = %d)\n", DRIVER_NAME, result); | ||
402 | goto fail_frontend; | ||
403 | } | ||
404 | |||
405 | /* register demux stuff */ | ||
406 | dvb->demux.dmx.capabilities = | ||
407 | DMX_TS_FILTERING | DMX_SECTION_FILTERING | | ||
408 | DMX_MEMORY_BASED_FILTERING; | ||
409 | dvb->demux.priv = port; | ||
410 | dvb->demux.filternum = 256; | ||
411 | dvb->demux.feednum = 256; | ||
412 | dvb->demux.start_feed = saa7164_dvb_start_feed; | ||
413 | dvb->demux.stop_feed = saa7164_dvb_stop_feed; | ||
414 | result = dvb_dmx_init(&dvb->demux); | ||
415 | if (result < 0) { | ||
416 | printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", | ||
417 | DRIVER_NAME, result); | ||
418 | goto fail_dmx; | ||
419 | } | ||
420 | |||
421 | dvb->dmxdev.filternum = 256; | ||
422 | dvb->dmxdev.demux = &dvb->demux.dmx; | ||
423 | dvb->dmxdev.capabilities = 0; | ||
424 | result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); | ||
425 | if (result < 0) { | ||
426 | printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", | ||
427 | DRIVER_NAME, result); | ||
428 | goto fail_dmxdev; | ||
429 | } | ||
430 | |||
431 | dvb->fe_hw.source = DMX_FRONTEND_0; | ||
432 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
433 | if (result < 0) { | ||
434 | printk(KERN_ERR "%s: add_frontend failed " | ||
435 | "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result); | ||
436 | goto fail_fe_hw; | ||
437 | } | ||
438 | |||
439 | dvb->fe_mem.source = DMX_MEMORY_FE; | ||
440 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
441 | if (result < 0) { | ||
442 | printk(KERN_ERR "%s: add_frontend failed " | ||
443 | "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result); | ||
444 | goto fail_fe_mem; | ||
445 | } | ||
446 | |||
447 | result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
448 | if (result < 0) { | ||
449 | printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", | ||
450 | DRIVER_NAME, result); | ||
451 | goto fail_fe_conn; | ||
452 | } | ||
453 | |||
454 | /* register network adapter */ | ||
455 | dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); | ||
456 | return 0; | ||
457 | |||
458 | fail_fe_conn: | ||
459 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
460 | fail_fe_mem: | ||
461 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
462 | fail_fe_hw: | ||
463 | dvb_dmxdev_release(&dvb->dmxdev); | ||
464 | fail_dmxdev: | ||
465 | dvb_dmx_release(&dvb->demux); | ||
466 | fail_dmx: | ||
467 | dvb_unregister_frontend(dvb->frontend); | ||
468 | fail_frontend: | ||
469 | dvb_frontend_detach(dvb->frontend); | ||
470 | dvb_unregister_adapter(&dvb->adapter); | ||
471 | fail_adapter: | ||
472 | return result; | ||
473 | } | ||
474 | |||
475 | int saa7164_dvb_unregister(struct saa7164_tsport *port) | ||
476 | { | ||
477 | struct saa7164_dvb *dvb = &port->dvb; | ||
478 | struct saa7164_dev *dev = port->dev; | ||
479 | struct saa7164_buffer *b; | ||
480 | struct list_head *c, *n; | ||
481 | |||
482 | dprintk(DBGLVL_DVB, "%s()\n", __func__); | ||
483 | |||
484 | /* Remove any allocated buffers */ | ||
485 | mutex_lock(&port->dmaqueue_lock); | ||
486 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
487 | b = list_entry(c, struct saa7164_buffer, list); | ||
488 | list_del(c); | ||
489 | saa7164_buffer_dealloc(port, b); | ||
490 | } | ||
491 | mutex_unlock(&port->dmaqueue_lock); | ||
492 | |||
493 | if (dvb->frontend == NULL) | ||
494 | return 0; | ||
495 | |||
496 | dvb_net_release(&dvb->net); | ||
497 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
498 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
499 | dvb_dmxdev_release(&dvb->dmxdev); | ||
500 | dvb_dmx_release(&dvb->demux); | ||
501 | dvb_unregister_frontend(dvb->frontend); | ||
502 | dvb_frontend_detach(dvb->frontend); | ||
503 | dvb_unregister_adapter(&dvb->adapter); | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | /* All the DVB attach calls go here, this function get's modified | ||
508 | * for each new card. | ||
509 | */ | ||
510 | int saa7164_dvb_register(struct saa7164_tsport *port) | ||
511 | { | ||
512 | struct saa7164_dev *dev = port->dev; | ||
513 | struct saa7164_dvb *dvb = &port->dvb; | ||
514 | struct saa7164_i2c *i2c_bus = NULL; | ||
515 | int ret; | ||
516 | |||
517 | dprintk(DBGLVL_DVB, "%s()\n", __func__); | ||
518 | |||
519 | /* init frontend */ | ||
520 | switch (dev->board) { | ||
521 | case SAA7164_BOARD_HAUPPAUGE_HVR2200: | ||
522 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: | ||
523 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: | ||
524 | i2c_bus = &dev->i2c_bus[port->nr + 1]; | ||
525 | switch (port->nr) { | ||
526 | case 0: | ||
527 | port->dvb.frontend = dvb_attach(tda10048_attach, | ||
528 | &hauppauge_hvr2200_1_config, | ||
529 | &i2c_bus->i2c_adap); | ||
530 | |||
531 | if (port->dvb.frontend != NULL) { | ||
532 | /* TODO: addr is in the card struct */ | ||
533 | dvb_attach(tda18271_attach, port->dvb.frontend, | ||
534 | 0xc0 >> 1, &i2c_bus->i2c_adap, | ||
535 | &hauppauge_hvr22x0_tuner_config); | ||
536 | } | ||
537 | |||
538 | break; | ||
539 | case 1: | ||
540 | port->dvb.frontend = dvb_attach(tda10048_attach, | ||
541 | &hauppauge_hvr2200_2_config, | ||
542 | &i2c_bus->i2c_adap); | ||
543 | |||
544 | if (port->dvb.frontend != NULL) { | ||
545 | /* TODO: addr is in the card struct */ | ||
546 | dvb_attach(tda18271_attach, port->dvb.frontend, | ||
547 | 0xc0 >> 1, &i2c_bus->i2c_adap, | ||
548 | &hauppauge_hvr22x0s_tuner_config); | ||
549 | } | ||
550 | |||
551 | break; | ||
552 | } | ||
553 | break; | ||
554 | case SAA7164_BOARD_HAUPPAUGE_HVR2250: | ||
555 | case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: | ||
556 | case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: | ||
557 | i2c_bus = &dev->i2c_bus[port->nr + 1]; | ||
558 | |||
559 | port->dvb.frontend = dvb_attach(s5h1411_attach, | ||
560 | &hauppauge_s5h1411_config, | ||
561 | &i2c_bus->i2c_adap); | ||
562 | |||
563 | if (port->dvb.frontend != NULL) { | ||
564 | if (port->nr == 0) { | ||
565 | /* Master TDA18271 */ | ||
566 | /* TODO: addr is in the card struct */ | ||
567 | dvb_attach(tda18271_attach, port->dvb.frontend, | ||
568 | 0xc0 >> 1, &i2c_bus->i2c_adap, | ||
569 | &hauppauge_hvr22x0_tuner_config); | ||
570 | } else { | ||
571 | /* Slave TDA18271 */ | ||
572 | dvb_attach(tda18271_attach, port->dvb.frontend, | ||
573 | 0xc0 >> 1, &i2c_bus->i2c_adap, | ||
574 | &hauppauge_hvr22x0s_tuner_config); | ||
575 | } | ||
576 | } | ||
577 | |||
578 | break; | ||
579 | default: | ||
580 | printk(KERN_ERR "%s: The frontend isn't supported\n", | ||
581 | dev->name); | ||
582 | break; | ||
583 | } | ||
584 | if (NULL == dvb->frontend) { | ||
585 | printk(KERN_ERR "%s() Frontend initialization failed\n", | ||
586 | __func__); | ||
587 | return -1; | ||
588 | } | ||
589 | |||
590 | /* Put the analog decoder in standby to keep it quiet */ | ||
591 | |||
592 | /* register everything */ | ||
593 | ret = dvb_register(port); | ||
594 | if (ret < 0) { | ||
595 | if (dvb->frontend->ops.release) | ||
596 | dvb->frontend->ops.release(dvb->frontend); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | return 0; | ||
601 | } | ||
602 | |||
diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/video/saa7164/saa7164-fw.c new file mode 100644 index 000000000000..ee0af3534ede --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-fw.c | |||
@@ -0,0 +1,613 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/firmware.h> | ||
23 | |||
24 | #include "saa7164.h" | ||
25 | |||
26 | #define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2.fw" | ||
27 | #define SAA7164_REV2_FIRMWARE_SIZE 3978608 | ||
28 | |||
29 | #define SAA7164_REV3_FIRMWARE "v4l-saa7164-1.0.3.fw" | ||
30 | #define SAA7164_REV3_FIRMWARE_SIZE 3978608 | ||
31 | |||
32 | struct fw_header { | ||
33 | u32 firmwaresize; | ||
34 | u32 bslsize; | ||
35 | u32 reserved; | ||
36 | u32 version; | ||
37 | }; | ||
38 | |||
39 | int saa7164_dl_wait_ack(struct saa7164_dev *dev, u32 reg) | ||
40 | { | ||
41 | u32 timeout = SAA_DEVICE_TIMEOUT; | ||
42 | while ((saa7164_readl(reg) & 0x01) == 0) { | ||
43 | timeout -= 10; | ||
44 | if (timeout == 0) { | ||
45 | printk(KERN_ERR "%s() timeout (no d/l ack)\n", | ||
46 | __func__); | ||
47 | return -EBUSY; | ||
48 | } | ||
49 | msleep(100); | ||
50 | } | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg) | ||
56 | { | ||
57 | u32 timeout = SAA_DEVICE_TIMEOUT; | ||
58 | while (saa7164_readl(reg) & 0x01) { | ||
59 | timeout -= 10; | ||
60 | if (timeout == 0) { | ||
61 | printk(KERN_ERR "%s() timeout (no d/l clr)\n", | ||
62 | __func__); | ||
63 | return -EBUSY; | ||
64 | } | ||
65 | msleep(100); | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /* TODO: move dlflags into dev-> and change to write/readl/b */ | ||
72 | /* TODO: Excessive levels of debug */ | ||
73 | int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize, | ||
74 | u32 dlflags, u8 *dst, u32 dstsize) | ||
75 | { | ||
76 | u32 reg, timeout, offset; | ||
77 | u8 *srcbuf = NULL; | ||
78 | int ret; | ||
79 | |||
80 | u32 dlflag = dlflags; | ||
81 | u32 dlflag_ack = dlflag + 4; | ||
82 | u32 drflag = dlflag_ack + 4; | ||
83 | u32 drflag_ack = drflag + 4; | ||
84 | u32 bleflag = drflag_ack + 4; | ||
85 | |||
86 | dprintk(DBGLVL_FW, | ||
87 | "%s(image=%p, size=%d, flags=0x%x, dst=%p, dstsize=0x%x)\n", | ||
88 | __func__, src, srcsize, dlflags, dst, dstsize); | ||
89 | |||
90 | if ((src == 0) || (dst == 0)) { | ||
91 | ret = -EIO; | ||
92 | goto out; | ||
93 | } | ||
94 | |||
95 | srcbuf = kzalloc(4 * 1048576, GFP_KERNEL); | ||
96 | if (NULL == srcbuf) { | ||
97 | ret = -ENOMEM; | ||
98 | goto out; | ||
99 | } | ||
100 | |||
101 | if (srcsize > (4*1048576)) { | ||
102 | ret = -ENOMEM; | ||
103 | goto out; | ||
104 | } | ||
105 | |||
106 | memcpy(srcbuf, src, srcsize); | ||
107 | |||
108 | dprintk(DBGLVL_FW, "%s() dlflag = 0x%x\n", __func__, dlflag); | ||
109 | dprintk(DBGLVL_FW, "%s() dlflag_ack = 0x%x\n", __func__, dlflag_ack); | ||
110 | dprintk(DBGLVL_FW, "%s() drflag = 0x%x\n", __func__, drflag); | ||
111 | dprintk(DBGLVL_FW, "%s() drflag_ack = 0x%x\n", __func__, drflag_ack); | ||
112 | dprintk(DBGLVL_FW, "%s() bleflag = 0x%x\n", __func__, bleflag); | ||
113 | |||
114 | reg = saa7164_readl(dlflag); | ||
115 | dprintk(DBGLVL_FW, "%s() dlflag (0x%x)= 0x%x\n", __func__, dlflag, reg); | ||
116 | if (reg == 1) | ||
117 | dprintk(DBGLVL_FW, | ||
118 | "%s() Download flag already set, please reboot\n", | ||
119 | __func__); | ||
120 | |||
121 | /* Indicate download start */ | ||
122 | saa7164_writel(dlflag, 1); | ||
123 | ret = saa7164_dl_wait_ack(dev, dlflag_ack); | ||
124 | if (ret < 0) | ||
125 | goto out; | ||
126 | |||
127 | /* Ack download start, then wait for wait */ | ||
128 | saa7164_writel(dlflag, 0); | ||
129 | ret = saa7164_dl_wait_clr(dev, dlflag_ack); | ||
130 | if (ret < 0) | ||
131 | goto out; | ||
132 | |||
133 | /* Deal with the raw firmware, in the appropriate chunk size */ | ||
134 | for (offset = 0; srcsize > dstsize; | ||
135 | srcsize -= dstsize, offset += dstsize) { | ||
136 | |||
137 | dprintk(DBGLVL_FW, "%s() memcpy %d\n", __func__, dstsize); | ||
138 | memcpy(dst, srcbuf + offset, dstsize); | ||
139 | |||
140 | /* Flag the data as ready */ | ||
141 | saa7164_writel(drflag, 1); | ||
142 | ret = saa7164_dl_wait_ack(dev, drflag_ack); | ||
143 | if (ret < 0) | ||
144 | goto out; | ||
145 | |||
146 | /* Wait for indication data was received */ | ||
147 | saa7164_writel(drflag, 0); | ||
148 | ret = saa7164_dl_wait_clr(dev, drflag_ack); | ||
149 | if (ret < 0) | ||
150 | goto out; | ||
151 | |||
152 | } | ||
153 | |||
154 | dprintk(DBGLVL_FW, "%s() memcpy(l) %d\n", __func__, dstsize); | ||
155 | /* Write last block to the device */ | ||
156 | memcpy(dst, srcbuf+offset, srcsize); | ||
157 | |||
158 | /* Flag the data as ready */ | ||
159 | saa7164_writel(drflag, 1); | ||
160 | ret = saa7164_dl_wait_ack(dev, drflag_ack); | ||
161 | if (ret < 0) | ||
162 | goto out; | ||
163 | |||
164 | saa7164_writel(drflag, 0); | ||
165 | timeout = 0; | ||
166 | while (saa7164_readl(bleflag) != SAA_DEVICE_IMAGE_BOOTING) { | ||
167 | if (saa7164_readl(bleflag) & SAA_DEVICE_IMAGE_CORRUPT) { | ||
168 | printk(KERN_ERR "%s() image corrupt\n", __func__); | ||
169 | ret = -EBUSY; | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | if (saa7164_readl(bleflag) & SAA_DEVICE_MEMORY_CORRUPT) { | ||
174 | printk(KERN_ERR "%s() device memory corrupt\n", | ||
175 | __func__); | ||
176 | ret = -EBUSY; | ||
177 | goto out; | ||
178 | } | ||
179 | |||
180 | msleep(10); | ||
181 | if (timeout++ > 60) | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | printk(KERN_INFO "%s() Image downloaded, booting...\n", __func__); | ||
186 | |||
187 | ret = saa7164_dl_wait_clr(dev, drflag_ack); | ||
188 | if (ret < 0) | ||
189 | goto out; | ||
190 | |||
191 | printk(KERN_INFO "%s() Image booted successfully.\n", __func__); | ||
192 | ret = 0; | ||
193 | |||
194 | out: | ||
195 | kfree(srcbuf); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /* TODO: Excessive debug */ | ||
200 | /* Load the firmware. Optionally it can be in ROM or newer versions | ||
201 | * can be on disk, saving the expense of the ROM hardware. */ | ||
202 | int saa7164_downloadfirmware(struct saa7164_dev *dev) | ||
203 | { | ||
204 | /* u32 second_timeout = 60 * SAA_DEVICE_TIMEOUT; */ | ||
205 | u32 tmp, filesize, version, err_flags, first_timeout, fwlength; | ||
206 | u32 second_timeout, updatebootloader = 1, bootloadersize = 0; | ||
207 | const struct firmware *fw = NULL; | ||
208 | struct fw_header *hdr, *boothdr = NULL, *fwhdr; | ||
209 | u32 bootloaderversion = 0, fwloadersize; | ||
210 | u8 *bootloaderoffset = NULL, *fwloaderoffset; | ||
211 | char *fwname; | ||
212 | int ret; | ||
213 | |||
214 | dprintk(DBGLVL_FW, "%s()\n", __func__); | ||
215 | |||
216 | if (saa7164_boards[dev->board].chiprev == SAA7164_CHIP_REV2) { | ||
217 | fwname = SAA7164_REV2_FIRMWARE; | ||
218 | fwlength = SAA7164_REV2_FIRMWARE_SIZE; | ||
219 | } else { | ||
220 | fwname = SAA7164_REV3_FIRMWARE; | ||
221 | fwlength = SAA7164_REV3_FIRMWARE_SIZE; | ||
222 | } | ||
223 | |||
224 | version = saa7164_getcurrentfirmwareversion(dev); | ||
225 | |||
226 | if (version == 0x00) { | ||
227 | |||
228 | second_timeout = 100; | ||
229 | first_timeout = 100; | ||
230 | err_flags = saa7164_readl(SAA_BOOTLOADERERROR_FLAGS); | ||
231 | dprintk(DBGLVL_FW, "%s() err_flags = %x\n", | ||
232 | __func__, err_flags); | ||
233 | |||
234 | while (err_flags != SAA_DEVICE_IMAGE_BOOTING) { | ||
235 | dprintk(DBGLVL_FW, "%s() err_flags = %x\n", | ||
236 | __func__, err_flags); | ||
237 | msleep(10); | ||
238 | |||
239 | if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) { | ||
240 | printk(KERN_ERR "%s() firmware corrupt\n", | ||
241 | __func__); | ||
242 | break; | ||
243 | } | ||
244 | if (err_flags & SAA_DEVICE_MEMORY_CORRUPT) { | ||
245 | printk(KERN_ERR "%s() device memory corrupt\n", | ||
246 | __func__); | ||
247 | break; | ||
248 | } | ||
249 | if (err_flags & SAA_DEVICE_NO_IMAGE) { | ||
250 | printk(KERN_ERR "%s() no first image\n", | ||
251 | __func__); | ||
252 | break; | ||
253 | } | ||
254 | if (err_flags & SAA_DEVICE_IMAGE_SEARCHING) { | ||
255 | first_timeout -= 10; | ||
256 | if (first_timeout == 0) { | ||
257 | printk(KERN_ERR | ||
258 | "%s() no first image\n", | ||
259 | __func__); | ||
260 | break; | ||
261 | } | ||
262 | } else if (err_flags & SAA_DEVICE_IMAGE_LOADING) { | ||
263 | second_timeout -= 10; | ||
264 | if (second_timeout == 0) { | ||
265 | printk(KERN_ERR | ||
266 | "%s() FW load time exceeded\n", | ||
267 | __func__); | ||
268 | break; | ||
269 | } | ||
270 | } else { | ||
271 | second_timeout -= 10; | ||
272 | if (second_timeout == 0) { | ||
273 | printk(KERN_ERR | ||
274 | "%s() Unknown bootloader flags 0x%x\n", | ||
275 | __func__, err_flags); | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | err_flags = saa7164_readl(SAA_BOOTLOADERERROR_FLAGS); | ||
281 | } /* While != Booting */ | ||
282 | |||
283 | if (err_flags == SAA_DEVICE_IMAGE_BOOTING) { | ||
284 | dprintk(DBGLVL_FW, "%s() Loader 1 has loaded.\n", | ||
285 | __func__); | ||
286 | first_timeout = SAA_DEVICE_TIMEOUT; | ||
287 | second_timeout = 60 * SAA_DEVICE_TIMEOUT; | ||
288 | second_timeout = 100; | ||
289 | |||
290 | err_flags = saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS); | ||
291 | dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n", | ||
292 | __func__, err_flags); | ||
293 | while (err_flags != SAA_DEVICE_IMAGE_BOOTING) { | ||
294 | dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n", | ||
295 | __func__, err_flags); | ||
296 | msleep(10); | ||
297 | |||
298 | if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) { | ||
299 | printk(KERN_ERR | ||
300 | "%s() firmware corrupt\n", | ||
301 | __func__); | ||
302 | break; | ||
303 | } | ||
304 | if (err_flags & SAA_DEVICE_MEMORY_CORRUPT) { | ||
305 | printk(KERN_ERR | ||
306 | "%s() device memory corrupt\n", | ||
307 | __func__); | ||
308 | break; | ||
309 | } | ||
310 | if (err_flags & SAA_DEVICE_NO_IMAGE) { | ||
311 | printk(KERN_ERR "%s() no first image\n", | ||
312 | __func__); | ||
313 | break; | ||
314 | } | ||
315 | if (err_flags & SAA_DEVICE_IMAGE_SEARCHING) { | ||
316 | first_timeout -= 10; | ||
317 | if (first_timeout == 0) { | ||
318 | printk(KERN_ERR | ||
319 | "%s() no second image\n", | ||
320 | __func__); | ||
321 | break; | ||
322 | } | ||
323 | } else if (err_flags & | ||
324 | SAA_DEVICE_IMAGE_LOADING) { | ||
325 | second_timeout -= 10; | ||
326 | if (second_timeout == 0) { | ||
327 | printk(KERN_ERR | ||
328 | "%s() FW load time exceeded\n", | ||
329 | __func__); | ||
330 | break; | ||
331 | } | ||
332 | } else { | ||
333 | second_timeout -= 10; | ||
334 | if (second_timeout == 0) { | ||
335 | printk(KERN_ERR | ||
336 | "%s() Unknown bootloader flags 0x%x\n", | ||
337 | __func__, err_flags); | ||
338 | break; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | err_flags = | ||
343 | saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS); | ||
344 | } /* err_flags != SAA_DEVICE_IMAGE_BOOTING */ | ||
345 | |||
346 | dprintk(DBGLVL_FW, "%s() Loader flags 1:0x%x 2:0x%x.\n", | ||
347 | __func__, | ||
348 | saa7164_readl(SAA_BOOTLOADERERROR_FLAGS), | ||
349 | saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS)); | ||
350 | |||
351 | } /* err_flags == SAA_DEVICE_IMAGE_BOOTING */ | ||
352 | |||
353 | /* It's possible for both firmwares to have booted, | ||
354 | * but that doesn't mean they've finished booting yet. | ||
355 | */ | ||
356 | if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) == | ||
357 | SAA_DEVICE_IMAGE_BOOTING) && | ||
358 | (saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS) == | ||
359 | SAA_DEVICE_IMAGE_BOOTING)) { | ||
360 | |||
361 | |||
362 | dprintk(DBGLVL_FW, "%s() Loader 2 has loaded.\n", | ||
363 | __func__); | ||
364 | |||
365 | first_timeout = SAA_DEVICE_TIMEOUT; | ||
366 | while (first_timeout) { | ||
367 | msleep(10); | ||
368 | |||
369 | version = | ||
370 | saa7164_getcurrentfirmwareversion(dev); | ||
371 | if (version) { | ||
372 | dprintk(DBGLVL_FW, | ||
373 | "%s() All f/w loaded successfully\n", | ||
374 | __func__); | ||
375 | break; | ||
376 | } else { | ||
377 | first_timeout -= 10; | ||
378 | if (first_timeout == 0) { | ||
379 | printk(KERN_ERR | ||
380 | "%s() FW did not boot\n", | ||
381 | __func__); | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | version = saa7164_getcurrentfirmwareversion(dev); | ||
388 | } /* version == 0 */ | ||
389 | |||
390 | /* Has the firmware really booted? */ | ||
391 | if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) == | ||
392 | SAA_DEVICE_IMAGE_BOOTING) && | ||
393 | (saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS) == | ||
394 | SAA_DEVICE_IMAGE_BOOTING) && (version == 0)) { | ||
395 | |||
396 | printk(KERN_ERR | ||
397 | "%s() The firmware hung, probably bad firmware\n", | ||
398 | __func__); | ||
399 | |||
400 | /* Tell the second stage loader we have a deadlock */ | ||
401 | saa7164_writel(SAA_DEVICE_DEADLOCK_DETECTED_OFFSET, | ||
402 | SAA_DEVICE_DEADLOCK_DETECTED); | ||
403 | |||
404 | saa7164_getfirmwarestatus(dev); | ||
405 | |||
406 | return -ENOMEM; | ||
407 | } | ||
408 | |||
409 | dprintk(DBGLVL_FW, "Device has Firmware Version %d.%d.%d.%d\n", | ||
410 | (version & 0x0000fc00) >> 10, | ||
411 | (version & 0x000003e0) >> 5, | ||
412 | (version & 0x0000001f), | ||
413 | (version & 0xffff0000) >> 16); | ||
414 | |||
415 | /* Load the firmwware from the disk if required */ | ||
416 | if (version == 0) { | ||
417 | |||
418 | printk(KERN_INFO "%s() Waiting for firmware upload (%s)\n", | ||
419 | __func__, fwname); | ||
420 | |||
421 | ret = request_firmware(&fw, fwname, &dev->pci->dev); | ||
422 | if (ret) { | ||
423 | printk(KERN_ERR "%s() Upload failed. " | ||
424 | "(file not found?)\n", __func__); | ||
425 | return -ENOMEM; | ||
426 | } | ||
427 | |||
428 | printk(KERN_INFO "%s() firmware read %Zu bytes.\n", | ||
429 | __func__, fw->size); | ||
430 | |||
431 | if (fw->size != fwlength) { | ||
432 | printk(KERN_ERR "xc5000: firmware incorrect size\n"); | ||
433 | ret = -ENOMEM; | ||
434 | goto out; | ||
435 | } | ||
436 | |||
437 | printk(KERN_INFO "%s() firmware loaded.\n", __func__); | ||
438 | |||
439 | hdr = (struct fw_header *)fw->data; | ||
440 | printk(KERN_INFO "Firmware file header part 1:\n"); | ||
441 | printk(KERN_INFO " .FirmwareSize = 0x%x\n", hdr->firmwaresize); | ||
442 | printk(KERN_INFO " .BSLSize = 0x%x\n", hdr->bslsize); | ||
443 | printk(KERN_INFO " .Reserved = 0x%x\n", hdr->reserved); | ||
444 | printk(KERN_INFO " .Version = 0x%x\n", hdr->version); | ||
445 | |||
446 | /* Retreive bootloader if reqd */ | ||
447 | if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) | ||
448 | /* Second bootloader in the firmware file */ | ||
449 | filesize = hdr->reserved * 16; | ||
450 | else | ||
451 | filesize = (hdr->firmwaresize + hdr->bslsize) * | ||
452 | 16 + sizeof(struct fw_header); | ||
453 | |||
454 | printk(KERN_INFO "%s() SecBootLoader.FileSize = %d\n", | ||
455 | __func__, filesize); | ||
456 | |||
457 | /* Get bootloader (if reqd) and firmware header */ | ||
458 | if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) { | ||
459 | /* Second boot loader is required */ | ||
460 | |||
461 | /* Get the loader header */ | ||
462 | boothdr = (struct fw_header *)(fw->data + | ||
463 | sizeof(struct fw_header)); | ||
464 | |||
465 | bootloaderversion = | ||
466 | saa7164_readl(SAA_DEVICE_2ND_VERSION); | ||
467 | dprintk(DBGLVL_FW, "Onboard BootLoader:\n"); | ||
468 | dprintk(DBGLVL_FW, "->Flag 0x%x\n", | ||
469 | saa7164_readl(SAA_BOOTLOADERERROR_FLAGS)); | ||
470 | dprintk(DBGLVL_FW, "->Ack 0x%x\n", | ||
471 | saa7164_readl(SAA_DATAREADY_FLAG_ACK)); | ||
472 | dprintk(DBGLVL_FW, "->FW Version 0x%x\n", version); | ||
473 | dprintk(DBGLVL_FW, "->Loader Version 0x%x\n", | ||
474 | bootloaderversion); | ||
475 | |||
476 | if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) == | ||
477 | 0x03) && (saa7164_readl(SAA_DATAREADY_FLAG_ACK) | ||
478 | == 0x00) && (version == 0x00)) { | ||
479 | |||
480 | dprintk(DBGLVL_FW, "BootLoader version in " | ||
481 | "rom %d.%d.%d.%d\n", | ||
482 | (bootloaderversion & 0x0000fc00) >> 10, | ||
483 | (bootloaderversion & 0x000003e0) >> 5, | ||
484 | (bootloaderversion & 0x0000001f), | ||
485 | (bootloaderversion & 0xffff0000) >> 16 | ||
486 | ); | ||
487 | dprintk(DBGLVL_FW, "BootLoader version " | ||
488 | "in file %d.%d.%d.%d\n", | ||
489 | (boothdr->version & 0x0000fc00) >> 10, | ||
490 | (boothdr->version & 0x000003e0) >> 5, | ||
491 | (boothdr->version & 0x0000001f), | ||
492 | (boothdr->version & 0xffff0000) >> 16 | ||
493 | ); | ||
494 | |||
495 | if (bootloaderversion == boothdr->version) | ||
496 | updatebootloader = 0; | ||
497 | } | ||
498 | |||
499 | /* Calculate offset to firmware header */ | ||
500 | tmp = (boothdr->firmwaresize + boothdr->bslsize) * 16 + | ||
501 | (sizeof(struct fw_header) + | ||
502 | sizeof(struct fw_header)); | ||
503 | |||
504 | fwhdr = (struct fw_header *)(fw->data+tmp); | ||
505 | } else { | ||
506 | /* No second boot loader */ | ||
507 | fwhdr = hdr; | ||
508 | } | ||
509 | |||
510 | dprintk(DBGLVL_FW, "Firmware version in file %d.%d.%d.%d\n", | ||
511 | (fwhdr->version & 0x0000fc00) >> 10, | ||
512 | (fwhdr->version & 0x000003e0) >> 5, | ||
513 | (fwhdr->version & 0x0000001f), | ||
514 | (fwhdr->version & 0xffff0000) >> 16 | ||
515 | ); | ||
516 | |||
517 | if (version == fwhdr->version) { | ||
518 | /* No download, firmware already on board */ | ||
519 | ret = 0; | ||
520 | goto out; | ||
521 | } | ||
522 | |||
523 | if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) { | ||
524 | if (updatebootloader) { | ||
525 | /* Get ready to upload the bootloader */ | ||
526 | bootloadersize = (boothdr->firmwaresize + | ||
527 | boothdr->bslsize) * 16 + | ||
528 | sizeof(struct fw_header); | ||
529 | |||
530 | bootloaderoffset = (u8 *)(fw->data + | ||
531 | sizeof(struct fw_header)); | ||
532 | |||
533 | dprintk(DBGLVL_FW, "bootloader d/l starts.\n"); | ||
534 | printk(KERN_INFO "%s() FirmwareSize = 0x%x\n", | ||
535 | __func__, boothdr->firmwaresize); | ||
536 | printk(KERN_INFO "%s() BSLSize = 0x%x\n", | ||
537 | __func__, boothdr->bslsize); | ||
538 | printk(KERN_INFO "%s() Reserved = 0x%x\n", | ||
539 | __func__, boothdr->reserved); | ||
540 | printk(KERN_INFO "%s() Version = 0x%x\n", | ||
541 | __func__, boothdr->version); | ||
542 | ret = saa7164_downloadimage( | ||
543 | dev, | ||
544 | bootloaderoffset, | ||
545 | bootloadersize, | ||
546 | SAA_DOWNLOAD_FLAGS, | ||
547 | dev->bmmio + SAA_DEVICE_DOWNLOAD_OFFSET, | ||
548 | SAA_DEVICE_BUFFERBLOCKSIZE); | ||
549 | if (ret < 0) { | ||
550 | printk(KERN_ERR | ||
551 | "bootloader d/l has failed\n"); | ||
552 | goto out; | ||
553 | } | ||
554 | dprintk(DBGLVL_FW, | ||
555 | "bootloader download complete.\n"); | ||
556 | |||
557 | } | ||
558 | |||
559 | printk(KERN_ERR "starting firmware download(2)\n"); | ||
560 | bootloadersize = (boothdr->firmwaresize + | ||
561 | boothdr->bslsize) * 16 + | ||
562 | sizeof(struct fw_header); | ||
563 | |||
564 | bootloaderoffset = | ||
565 | (u8 *)(fw->data + sizeof(struct fw_header)); | ||
566 | |||
567 | fwloaderoffset = bootloaderoffset + bootloadersize; | ||
568 | |||
569 | /* TODO: fix this bounds overrun here with old f/ws */ | ||
570 | fwloadersize = (fwhdr->firmwaresize + fwhdr->bslsize) * | ||
571 | 16 + sizeof(struct fw_header); | ||
572 | |||
573 | ret = saa7164_downloadimage( | ||
574 | dev, | ||
575 | fwloaderoffset, | ||
576 | fwloadersize, | ||
577 | SAA_DEVICE_2ND_DOWNLOADFLAG_OFFSET, | ||
578 | dev->bmmio + SAA_DEVICE_2ND_DOWNLOAD_OFFSET, | ||
579 | SAA_DEVICE_2ND_BUFFERBLOCKSIZE); | ||
580 | if (ret < 0) { | ||
581 | printk(KERN_ERR "firmware download failed\n"); | ||
582 | goto out; | ||
583 | } | ||
584 | printk(KERN_ERR "firmware download complete.\n"); | ||
585 | |||
586 | } else { | ||
587 | |||
588 | /* No bootloader update reqd, download firmware only */ | ||
589 | printk(KERN_ERR "starting firmware download(3)\n"); | ||
590 | |||
591 | ret = saa7164_downloadimage( | ||
592 | dev, | ||
593 | (u8 *)fw->data, | ||
594 | fw->size, | ||
595 | SAA_DOWNLOAD_FLAGS, | ||
596 | dev->bmmio + SAA_DEVICE_DOWNLOAD_OFFSET, | ||
597 | SAA_DEVICE_BUFFERBLOCKSIZE); | ||
598 | if (ret < 0) { | ||
599 | printk(KERN_ERR "firmware download failed\n"); | ||
600 | goto out; | ||
601 | } | ||
602 | printk(KERN_ERR "firmware download complete.\n"); | ||
603 | } | ||
604 | } | ||
605 | |||
606 | ret = 0; | ||
607 | |||
608 | out: | ||
609 | if (fw) | ||
610 | release_firmware(fw); | ||
611 | |||
612 | return ret; | ||
613 | } | ||
diff --git a/drivers/media/video/saa7164/saa7164-i2c.c b/drivers/media/video/saa7164/saa7164-i2c.c new file mode 100644 index 000000000000..e1ae9b01bf0f --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-i2c.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include "saa7164.h" | ||
29 | |||
30 | static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | ||
31 | { | ||
32 | struct saa7164_i2c *bus = i2c_adap->algo_data; | ||
33 | struct saa7164_dev *dev = bus->dev; | ||
34 | int i, retval = 0; | ||
35 | |||
36 | dprintk(DBGLVL_I2C, "%s(num = %d)\n", __func__, num); | ||
37 | |||
38 | for (i = 0 ; i < num; i++) { | ||
39 | dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x len = 0x%x\n", | ||
40 | __func__, num, msgs[i].addr, msgs[i].len); | ||
41 | if (msgs[i].flags & I2C_M_RD) { | ||
42 | /* Unsupported - Yet*/ | ||
43 | printk(KERN_ERR "%s() Unsupported - Yet\n", __func__); | ||
44 | continue; | ||
45 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && | ||
46 | msgs[i].addr == msgs[i + 1].addr) { | ||
47 | /* write then read from same address */ | ||
48 | |||
49 | retval = saa7164_api_i2c_read(bus, msgs[i].addr, | ||
50 | msgs[i].len, msgs[i].buf, | ||
51 | msgs[i+1].len, msgs[i+1].buf | ||
52 | ); | ||
53 | |||
54 | i++; | ||
55 | |||
56 | if (retval < 0) | ||
57 | goto err; | ||
58 | } else { | ||
59 | /* write */ | ||
60 | retval = saa7164_api_i2c_write(bus, msgs[i].addr, | ||
61 | msgs[i].len, msgs[i].buf); | ||
62 | } | ||
63 | if (retval < 0) | ||
64 | goto err; | ||
65 | } | ||
66 | return num; | ||
67 | |||
68 | err: | ||
69 | return retval; | ||
70 | } | ||
71 | |||
72 | void saa7164_call_i2c_clients(struct saa7164_i2c *bus, unsigned int cmd, | ||
73 | void *arg) | ||
74 | { | ||
75 | if (bus->i2c_rc != 0) | ||
76 | return; | ||
77 | |||
78 | i2c_clients_command(&bus->i2c_adap, cmd, arg); | ||
79 | } | ||
80 | |||
81 | static u32 saa7164_functionality(struct i2c_adapter *adap) | ||
82 | { | ||
83 | return I2C_FUNC_I2C; | ||
84 | } | ||
85 | |||
86 | static struct i2c_algorithm saa7164_i2c_algo_template = { | ||
87 | .master_xfer = i2c_xfer, | ||
88 | .functionality = saa7164_functionality, | ||
89 | }; | ||
90 | |||
91 | /* ----------------------------------------------------------------------- */ | ||
92 | |||
93 | static struct i2c_adapter saa7164_i2c_adap_template = { | ||
94 | .name = "saa7164", | ||
95 | .owner = THIS_MODULE, | ||
96 | .algo = &saa7164_i2c_algo_template, | ||
97 | }; | ||
98 | |||
99 | static struct i2c_client saa7164_i2c_client_template = { | ||
100 | .name = "saa7164 internal", | ||
101 | }; | ||
102 | |||
103 | int saa7164_i2c_register(struct saa7164_i2c *bus) | ||
104 | { | ||
105 | struct saa7164_dev *dev = bus->dev; | ||
106 | |||
107 | dprintk(DBGLVL_I2C, "%s(bus = %d)\n", __func__, bus->nr); | ||
108 | |||
109 | memcpy(&bus->i2c_adap, &saa7164_i2c_adap_template, | ||
110 | sizeof(bus->i2c_adap)); | ||
111 | |||
112 | memcpy(&bus->i2c_algo, &saa7164_i2c_algo_template, | ||
113 | sizeof(bus->i2c_algo)); | ||
114 | |||
115 | memcpy(&bus->i2c_client, &saa7164_i2c_client_template, | ||
116 | sizeof(bus->i2c_client)); | ||
117 | |||
118 | bus->i2c_adap.dev.parent = &dev->pci->dev; | ||
119 | |||
120 | strlcpy(bus->i2c_adap.name, bus->dev->name, | ||
121 | sizeof(bus->i2c_adap.name)); | ||
122 | |||
123 | bus->i2c_algo.data = bus; | ||
124 | bus->i2c_adap.algo_data = bus; | ||
125 | i2c_set_adapdata(&bus->i2c_adap, bus); | ||
126 | i2c_add_adapter(&bus->i2c_adap); | ||
127 | |||
128 | bus->i2c_client.adapter = &bus->i2c_adap; | ||
129 | |||
130 | if (0 != bus->i2c_rc) | ||
131 | printk(KERN_ERR "%s: i2c bus %d register FAILED\n", | ||
132 | dev->name, bus->nr); | ||
133 | |||
134 | return bus->i2c_rc; | ||
135 | } | ||
136 | |||
137 | int saa7164_i2c_unregister(struct saa7164_i2c *bus) | ||
138 | { | ||
139 | i2c_del_adapter(&bus->i2c_adap); | ||
140 | return 0; | ||
141 | } | ||
diff --git a/drivers/media/video/saa7164/saa7164-reg.h b/drivers/media/video/saa7164/saa7164-reg.h new file mode 100644 index 000000000000..06be4c13d5b1 --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-reg.h | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | /* TODO: Retest the driver with errors expressed as negatives */ | ||
23 | |||
24 | /* Result codes */ | ||
25 | #define SAA_OK 0 | ||
26 | #define SAA_ERR_BAD_PARAMETER 0x09 | ||
27 | #define SAA_ERR_NO_RESOURCES 0x0c | ||
28 | #define SAA_ERR_NOT_SUPPORTED 0x13 | ||
29 | #define SAA_ERR_BUSY 0x15 | ||
30 | #define SAA_ERR_READ 0x17 | ||
31 | #define SAA_ERR_TIMEOUT 0x1f | ||
32 | #define SAA_ERR_OVERFLOW 0x20 | ||
33 | #define SAA_ERR_EMPTY 0x22 | ||
34 | #define SAA_ERR_NOT_STARTED 0x23 | ||
35 | #define SAA_ERR_ALREADY_STARTED 0x24 | ||
36 | #define SAA_ERR_NOT_STOPPED 0x25 | ||
37 | #define SAA_ERR_ALREADY_STOPPED 0x26 | ||
38 | #define SAA_ERR_INVALID_COMMAND 0x3e | ||
39 | #define SAA_ERR_NULL_PACKET 0x59 | ||
40 | |||
41 | /* Errors and flags from the silicon */ | ||
42 | #define PVC_ERRORCODE_UNKNOWN 0x00 | ||
43 | #define PVC_ERRORCODE_INVALID_COMMAND 0x01 | ||
44 | #define PVC_ERRORCODE_INVALID_CONTROL 0x02 | ||
45 | #define PVC_ERRORCODE_INVALID_DATA 0x03 | ||
46 | #define PVC_ERRORCODE_TIMEOUT 0x04 | ||
47 | #define PVC_ERRORCODE_NAK 0x05 | ||
48 | #define PVC_RESPONSEFLAG_ERROR 0x01 | ||
49 | #define PVC_RESPONSEFLAG_OVERFLOW 0x02 | ||
50 | #define PVC_RESPONSEFLAG_RESET 0x04 | ||
51 | #define PVC_RESPONSEFLAG_INTERFACE 0x08 | ||
52 | #define PVC_RESPONSEFLAG_CONTINUED 0x10 | ||
53 | #define PVC_CMDFLAG_INTERRUPT 0x02 | ||
54 | #define PVC_CMDFLAG_INTERFACE 0x04 | ||
55 | #define PVC_CMDFLAG_SERIALIZE 0x08 | ||
56 | #define PVC_CMDFLAG_CONTINUE 0x10 | ||
57 | |||
58 | /* Silicon Commands */ | ||
59 | #define GET_DESCRIPTORS_CONTROL 0x01 | ||
60 | #define GET_STRING_CONTROL 0x03 | ||
61 | #define GET_LANGUAGE_CONTROL 0x05 | ||
62 | #define SET_POWER_CONTROL 0x07 | ||
63 | #define GET_FW_VERSION_CONTROL 0x09 | ||
64 | #define SET_DEBUG_LEVEL_CONTROL 0x0B | ||
65 | #define GET_DEBUG_DATA_CONTROL 0x0C | ||
66 | #define GET_PRODUCTION_INFO_CONTROL 0x0D | ||
67 | |||
68 | /* cmd defines */ | ||
69 | #define SAA_CMDFLAG_CONTINUE 0x10 | ||
70 | #define SAA_CMD_MAX_MSG_UNITS 256 | ||
71 | |||
72 | /* Some defines */ | ||
73 | #define SAA_BUS_TIMEOUT 50 | ||
74 | #define SAA_DEVICE_TIMEOUT 5000 | ||
75 | #define SAA_DEVICE_MAXREQUESTSIZE 256 | ||
76 | |||
77 | /* Register addresses */ | ||
78 | #define SAA_DEVICE_VERSION 0x30 | ||
79 | #define SAA_DOWNLOAD_FLAGS 0x34 | ||
80 | #define SAA_DOWNLOAD_FLAG 0x34 | ||
81 | #define SAA_DOWNLOAD_FLAG_ACK 0x38 | ||
82 | #define SAA_DATAREADY_FLAG 0x3C | ||
83 | #define SAA_DATAREADY_FLAG_ACK 0x40 | ||
84 | |||
85 | /* Boot loader register and bit definitions */ | ||
86 | #define SAA_BOOTLOADERERROR_FLAGS 0x44 | ||
87 | #define SAA_DEVICE_IMAGE_SEARCHING 0x01 | ||
88 | #define SAA_DEVICE_IMAGE_LOADING 0x02 | ||
89 | #define SAA_DEVICE_IMAGE_BOOTING 0x03 | ||
90 | #define SAA_DEVICE_IMAGE_CORRUPT 0x04 | ||
91 | #define SAA_DEVICE_MEMORY_CORRUPT 0x08 | ||
92 | #define SAA_DEVICE_NO_IMAGE 0x10 | ||
93 | |||
94 | /* Register addresses */ | ||
95 | #define SAA_DEVICE_2ND_VERSION 0x50 | ||
96 | #define SAA_DEVICE_2ND_DOWNLOADFLAG_OFFSET 0x54 | ||
97 | |||
98 | /* Register addresses */ | ||
99 | #define SAA_SECONDSTAGEERROR_FLAGS 0x64 | ||
100 | |||
101 | /* Bootloader regs and flags */ | ||
102 | #define SAA_DEVICE_DEADLOCK_DETECTED_OFFSET 0x6C | ||
103 | #define SAA_DEVICE_DEADLOCK_DETECTED 0xDEADDEAD | ||
104 | |||
105 | /* Basic firmware status registers */ | ||
106 | #define SAA_DEVICE_SYSINIT_STATUS_OFFSET 0x70 | ||
107 | #define SAA_DEVICE_SYSINIT_STATUS 0x70 | ||
108 | #define SAA_DEVICE_SYSINIT_MODE 0x74 | ||
109 | #define SAA_DEVICE_SYSINIT_SPEC 0x78 | ||
110 | #define SAA_DEVICE_SYSINIT_INST 0x7C | ||
111 | #define SAA_DEVICE_SYSINIT_CPULOAD 0x80 | ||
112 | #define SAA_DEVICE_SYSINIT_REMAINHEAP 0x84 | ||
113 | |||
114 | #define SAA_DEVICE_DOWNLOAD_OFFSET 0x1000 | ||
115 | #define SAA_DEVICE_BUFFERBLOCKSIZE 0x1000 | ||
116 | |||
117 | #define SAA_DEVICE_2ND_BUFFERBLOCKSIZE 0x100000 | ||
118 | #define SAA_DEVICE_2ND_DOWNLOAD_OFFSET 0x200000 | ||
119 | |||
120 | /* Descriptors */ | ||
121 | #define CS_INTERFACE 0x24 | ||
122 | |||
123 | /* Descriptor subtypes */ | ||
124 | #define VC_INPUT_TERMINAL 0x02 | ||
125 | #define VC_OUTPUT_TERMINAL 0x03 | ||
126 | #define VC_SELECTOR_UNIT 0x04 | ||
127 | #define VC_PROCESSING_UNIT 0x05 | ||
128 | #define FEATURE_UNIT 0x06 | ||
129 | #define TUNER_UNIT 0x09 | ||
130 | #define ENCODER_UNIT 0x0A | ||
131 | #define EXTENSION_UNIT 0x0B | ||
132 | #define VC_TUNER_PATH 0xF0 | ||
133 | #define PVC_HARDWARE_DESCRIPTOR 0xF1 | ||
134 | #define PVC_INTERFACE_DESCRIPTOR 0xF2 | ||
135 | #define PVC_INFRARED_UNIT 0xF3 | ||
136 | #define DRM_UNIT 0xF4 | ||
137 | #define GENERAL_REQUEST 0xF5 | ||
138 | |||
139 | /* Format Types */ | ||
140 | #define VS_FORMAT_TYPE 0x02 | ||
141 | #define VS_FORMAT_TYPE_I 0x01 | ||
142 | #define VS_FORMAT_UNCOMPRESSED 0x04 | ||
143 | #define VS_FRAME_UNCOMPRESSED 0x05 | ||
144 | #define VS_FORMAT_MPEG2PS 0x09 | ||
145 | #define VS_FORMAT_MPEG2TS 0x0A | ||
146 | #define VS_FORMAT_MPEG4SL 0x0B | ||
147 | #define VS_FORMAT_WM9 0x0C | ||
148 | #define VS_FORMAT_DIVX 0x0D | ||
149 | #define VS_FORMAT_VBI 0x0E | ||
150 | #define VS_FORMAT_RDS 0x0F | ||
151 | |||
152 | /* Device extension commands */ | ||
153 | #define EXU_REGISTER_ACCESS_CONTROL 0x00 | ||
154 | #define EXU_GPIO_CONTROL 0x01 | ||
155 | #define EXU_GPIO_GROUP_CONTROL 0x02 | ||
156 | #define EXU_INTERRUPT_CONTROL 0x03 | ||
157 | |||
158 | /* State Transition and args */ | ||
159 | #define SAA_STATE_CONTROL 0x03 | ||
160 | #define SAA_DMASTATE_STOP 0x00 | ||
161 | #define SAA_DMASTATE_ACQUIRE 0x01 | ||
162 | #define SAA_DMASTATE_PAUSE 0x02 | ||
163 | #define SAA_DMASTATE_RUN 0x03 | ||
164 | |||
165 | /* Hardware registers */ | ||
166 | |||
diff --git a/drivers/media/video/saa7164/saa7164-types.h b/drivers/media/video/saa7164/saa7164-types.h new file mode 100644 index 000000000000..99093f23aae5 --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-types.h | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | /* TODO: Cleanup and shorten the namespace */ | ||
23 | |||
24 | /* Some structues are passed directly to/from the firmware and | ||
25 | * have strict alignment requirements. This is one of them. | ||
26 | */ | ||
27 | typedef struct { | ||
28 | u8 bLength; | ||
29 | u8 bDescriptorType; | ||
30 | u8 bDescriptorSubtype; | ||
31 | u16 bcdSpecVersion; | ||
32 | u32 dwClockFrequency; | ||
33 | u32 dwClockUpdateRes; | ||
34 | u8 bCapabilities; | ||
35 | u32 dwDeviceRegistersLocation; | ||
36 | u32 dwHostMemoryRegion; | ||
37 | u32 dwHostMemoryRegionSize; | ||
38 | u32 dwHostHibernatMemRegion; | ||
39 | u32 dwHostHibernatMemRegionSize; | ||
40 | } __attribute__((packed)) tmComResHWDescr_t; | ||
41 | |||
42 | /* This is DWORD aligned on windows but I can't find the right | ||
43 | * gcc syntax to match the binary data from the device. | ||
44 | * I've manually padded with Reserved[3] bytes to match the hardware, | ||
45 | * but this could break if GCC decies to pack in a different way. | ||
46 | */ | ||
47 | typedef struct { | ||
48 | u8 bLength; | ||
49 | u8 bDescriptorType; | ||
50 | u8 bDescriptorSubtype; | ||
51 | u8 bFlags; | ||
52 | u8 bInterfaceType; | ||
53 | u8 bInterfaceId; | ||
54 | u8 bBaseInterface; | ||
55 | u8 bInterruptId; | ||
56 | u8 bDebugInterruptId; | ||
57 | u8 BARLocation; | ||
58 | u8 Reserved[3]; | ||
59 | } tmComResInterfaceDescr_t; | ||
60 | |||
61 | typedef struct { | ||
62 | u64 CommandRing; | ||
63 | u64 ResponseRing; | ||
64 | u32 CommandWrite; | ||
65 | u32 CommandRead; | ||
66 | u32 ResponseWrite; | ||
67 | u32 ResponseRead; | ||
68 | } tmComResBusDescr_t; | ||
69 | |||
70 | typedef enum { | ||
71 | NONE = 0, | ||
72 | TYPE_BUS_PCI = 1, | ||
73 | TYPE_BUS_PCIe = 2, | ||
74 | TYPE_BUS_USB = 3, | ||
75 | TYPE_BUS_I2C = 4 | ||
76 | } tmBusType_t; | ||
77 | |||
78 | typedef struct { | ||
79 | tmBusType_t Type; | ||
80 | u16 m_wMaxReqSize; | ||
81 | u8 *m_pdwSetRing; | ||
82 | u32 m_dwSizeSetRing; | ||
83 | u8 *m_pdwGetRing; | ||
84 | u32 m_dwSizeGetRing; | ||
85 | u32 *m_pdwSetWritePos; | ||
86 | u32 *m_pdwSetReadPos; | ||
87 | u32 *m_pdwGetWritePos; | ||
88 | u32 *m_pdwGetReadPos; | ||
89 | |||
90 | /* All access is protected */ | ||
91 | struct mutex lock; | ||
92 | |||
93 | } tmComResBusInfo_t; | ||
94 | |||
95 | typedef struct { | ||
96 | u8 id; | ||
97 | u8 flags; | ||
98 | u16 size; | ||
99 | u32 command; | ||
100 | u16 controlselector; | ||
101 | u8 seqno; | ||
102 | } __attribute__((packed)) tmComResInfo_t; | ||
103 | |||
104 | typedef enum { | ||
105 | SET_CUR = 0x01, | ||
106 | GET_CUR = 0x81, | ||
107 | GET_MIN = 0x82, | ||
108 | GET_MAX = 0x83, | ||
109 | GET_RES = 0x84, | ||
110 | GET_LEN = 0x85, | ||
111 | GET_INFO = 0x86, | ||
112 | GET_DEF = 0x87 | ||
113 | } tmComResCmd_t; | ||
114 | |||
115 | struct cmd { | ||
116 | u8 seqno; | ||
117 | u32 inuse; | ||
118 | u32 timeout; | ||
119 | u32 signalled; | ||
120 | struct mutex lock; | ||
121 | wait_queue_head_t wait; | ||
122 | }; | ||
123 | |||
124 | typedef struct { | ||
125 | u32 pathid; | ||
126 | u32 size; | ||
127 | void *descriptor; | ||
128 | } tmDescriptor_t; | ||
129 | |||
130 | typedef struct { | ||
131 | u8 len; | ||
132 | u8 type; | ||
133 | u8 subtype; | ||
134 | u8 unitid; | ||
135 | } __attribute__((packed)) tmComResDescrHeader_t; | ||
136 | |||
137 | typedef struct { | ||
138 | u8 len; | ||
139 | u8 type; | ||
140 | u8 subtype; | ||
141 | u8 unitid; | ||
142 | u32 devicetype; | ||
143 | u16 deviceid; | ||
144 | u32 numgpiopins; | ||
145 | u8 numgpiogroups; | ||
146 | u8 controlsize; | ||
147 | } __attribute__((packed)) tmComResExtDevDescrHeader_t; | ||
148 | |||
149 | typedef struct { | ||
150 | u32 pin; | ||
151 | u8 state; | ||
152 | } __attribute__((packed)) tmComResGPIO_t; | ||
153 | |||
154 | typedef struct { | ||
155 | u8 len; | ||
156 | u8 type; | ||
157 | u8 subtype; | ||
158 | u8 pathid; | ||
159 | } __attribute__((packed)) tmComResPathDescrHeader_t; | ||
160 | |||
161 | /* terminaltype */ | ||
162 | typedef enum { | ||
163 | ITT_ANTENNA = 0x0203, | ||
164 | LINE_CONNECTOR = 0x0603, | ||
165 | SPDIF_CONNECTOR = 0x0605, | ||
166 | COMPOSITE_CONNECTOR = 0x0401, | ||
167 | SVIDEO_CONNECTOR = 0x0402, | ||
168 | COMPONENT_CONNECTOR = 0x0403, | ||
169 | STANDARD_DMA = 0xF101 | ||
170 | } tmComResTermType_t; | ||
171 | |||
172 | typedef struct { | ||
173 | u8 len; | ||
174 | u8 type; | ||
175 | u8 subtype; | ||
176 | u8 terminalid; | ||
177 | u16 terminaltype; | ||
178 | u8 assocterminal; | ||
179 | u8 iterminal; | ||
180 | u8 controlsize; | ||
181 | } __attribute__((packed)) tmComResAntTermDescrHeader_t; | ||
182 | |||
183 | typedef struct { | ||
184 | u8 len; | ||
185 | u8 type; | ||
186 | u8 subtype; | ||
187 | u8 unitid; | ||
188 | u8 sourceid; | ||
189 | u8 iunit; | ||
190 | u32 tuningstandards; | ||
191 | u8 controlsize; | ||
192 | u32 controls; | ||
193 | } __attribute__((packed)) tmComResTunerDescrHeader_t; | ||
194 | |||
195 | typedef enum { | ||
196 | /* the buffer does not contain any valid data */ | ||
197 | TM_BUFFER_FLAG_EMPTY, | ||
198 | |||
199 | /* the buffer is filled with valid data */ | ||
200 | TM_BUFFER_FLAG_DONE, | ||
201 | |||
202 | /* the buffer is the dummy buffer - TODO??? */ | ||
203 | TM_BUFFER_FLAG_DUMMY_BUFFER | ||
204 | } tmBufferFlag_t; | ||
205 | |||
206 | typedef struct { | ||
207 | u64 *pagetablevirt; | ||
208 | u64 pagetablephys; | ||
209 | u16 offset; | ||
210 | u8 *context; | ||
211 | u64 timestamp; | ||
212 | tmBufferFlag_t BufferFlag_t; | ||
213 | u32 lostbuffers; | ||
214 | u32 validbuffers; | ||
215 | u64 *dummypagevirt; | ||
216 | u64 dummypagephys; | ||
217 | u64 *addressvirt; | ||
218 | } tmBuffer_t; | ||
219 | |||
220 | typedef struct { | ||
221 | u32 bitspersample; | ||
222 | u32 samplesperline; | ||
223 | u32 numberoflines; | ||
224 | u32 pitch; | ||
225 | u32 linethreshold; | ||
226 | u64 **pagetablelistvirt; | ||
227 | u64 *pagetablelistphys; | ||
228 | u32 numpagetables; | ||
229 | u32 numpagetableentries; | ||
230 | } tmHWStreamParameters_t; | ||
231 | |||
232 | typedef struct { | ||
233 | tmHWStreamParameters_t HWStreamParameters_t; | ||
234 | u64 qwDummyPageTablePhys; | ||
235 | u64 *pDummyPageTableVirt; | ||
236 | } tmStreamParameters_t; | ||
237 | |||
238 | typedef struct { | ||
239 | u8 len; | ||
240 | u8 type; | ||
241 | u8 subtyle; | ||
242 | u8 unitid; | ||
243 | u16 terminaltype; | ||
244 | u8 assocterminal; | ||
245 | u8 sourceid; | ||
246 | u8 iterminal; | ||
247 | u32 BARLocation; | ||
248 | u8 flags; | ||
249 | u8 interruptid; | ||
250 | u8 buffercount; | ||
251 | u8 metadatasize; | ||
252 | u8 numformats; | ||
253 | u8 controlsize; | ||
254 | } __attribute__((packed)) tmComResDMATermDescrHeader_t; | ||
255 | |||
256 | /* | ||
257 | * | ||
258 | * Description: | ||
259 | * This is the transport stream format header. | ||
260 | * | ||
261 | * Settings: | ||
262 | * bLength - The size of this descriptor in bytes. | ||
263 | * bDescriptorType - CS_INTERFACE. | ||
264 | * bDescriptorSubtype - VS_FORMAT_MPEG2TS descriptor subtype. | ||
265 | * bFormatIndex - A non-zero constant that uniquely identifies the | ||
266 | * format. | ||
267 | * bDataOffset - Offset to TSP packet within MPEG-2 TS transport | ||
268 | * stride, in bytes. | ||
269 | * bPacketLength - Length of TSP packet, in bytes (typically 188). | ||
270 | * bStrideLength - Length of MPEG-2 TS transport stride. | ||
271 | * guidStrideFormat - A Globally Unique Identifier indicating the | ||
272 | * format of the stride data (if any). Set to zeros | ||
273 | * if there is no Stride Data, or if the Stride | ||
274 | * Data is to be ignored by the application. | ||
275 | * | ||
276 | */ | ||
277 | typedef struct { | ||
278 | u8 len; | ||
279 | u8 type; | ||
280 | u8 subtype; | ||
281 | u8 bFormatIndex; | ||
282 | u8 bDataOffset; | ||
283 | u8 bPacketLength; | ||
284 | u8 bStrideLength; | ||
285 | u8 guidStrideFormat[16]; | ||
286 | } __attribute__((packed)) tmComResTSFormatDescrHeader_t; | ||
287 | |||
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h new file mode 100644 index 000000000000..6753008a9c9b --- /dev/null +++ b/drivers/media/video/saa7164/saa7164.h | |||
@@ -0,0 +1,400 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * | ||
15 | * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | Driver architecture | ||
24 | ******************* | ||
25 | |||
26 | saa7164_core.c/buffer.c/cards.c/i2c.c/dvb.c | ||
27 | | : Standard Linux driver framework for creating | ||
28 | | : exposing and managing interfaces to the rest | ||
29 | | : of the kernel or userland. Also uses _fw.c to load | ||
30 | | : firmware direct into the PCIe bus, bypassing layers. | ||
31 | V | ||
32 | saa7164_api..() : Translate kernel specific functions/features | ||
33 | | : into command buffers. | ||
34 | V | ||
35 | saa7164_cmd..() : Manages the flow of command packets on/off, | ||
36 | | : the bus. Deal with bus errors, timeouts etc. | ||
37 | V | ||
38 | saa7164_bus..() : Manage a read/write memory ring buffer in the | ||
39 | | : PCIe Address space. | ||
40 | | | ||
41 | | saa7164_fw...() : Load any frimware | ||
42 | | | : direct into the device | ||
43 | V V | ||
44 | <- ----------------- PCIe address space -------------------- -> | ||
45 | */ | ||
46 | |||
47 | #include <linux/pci.h> | ||
48 | #include <linux/i2c.h> | ||
49 | #include <linux/i2c-algo-bit.h> | ||
50 | #include <linux/kdev_t.h> | ||
51 | |||
52 | #include <media/tuner.h> | ||
53 | #include <media/tveeprom.h> | ||
54 | #include <media/videobuf-dma-sg.h> | ||
55 | #include <media/videobuf-dvb.h> | ||
56 | |||
57 | #include "saa7164-reg.h" | ||
58 | #include "saa7164-types.h" | ||
59 | |||
60 | #include <linux/version.h> | ||
61 | #include <linux/mutex.h> | ||
62 | |||
63 | #define SAA7164_MAXBOARDS 8 | ||
64 | |||
65 | #define UNSET (-1U) | ||
66 | #define SAA7164_BOARD_NOAUTO UNSET | ||
67 | #define SAA7164_BOARD_UNKNOWN 0 | ||
68 | #define SAA7164_BOARD_UNKNOWN_REV2 1 | ||
69 | #define SAA7164_BOARD_UNKNOWN_REV3 2 | ||
70 | #define SAA7164_BOARD_HAUPPAUGE_HVR2250 3 | ||
71 | #define SAA7164_BOARD_HAUPPAUGE_HVR2200 4 | ||
72 | #define SAA7164_BOARD_HAUPPAUGE_HVR2200_2 5 | ||
73 | #define SAA7164_BOARD_HAUPPAUGE_HVR2200_3 6 | ||
74 | #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7 | ||
75 | #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 | ||
76 | |||
77 | #define SAA7164_MAX_UNITS 8 | ||
78 | #define SAA7164_TS_NUMBER_OF_LINES 312 | ||
79 | #define SAA7164_PT_ENTRIES 16 /* (312 * 188) / 4096 */ | ||
80 | |||
81 | #define DBGLVL_FW 4 | ||
82 | #define DBGLVL_DVB 8 | ||
83 | #define DBGLVL_I2C 16 | ||
84 | #define DBGLVL_API 32 | ||
85 | #define DBGLVL_CMD 64 | ||
86 | #define DBGLVL_BUS 128 | ||
87 | #define DBGLVL_IRQ 256 | ||
88 | #define DBGLVL_BUF 512 | ||
89 | |||
90 | enum port_t { | ||
91 | SAA7164_MPEG_UNDEFINED = 0, | ||
92 | SAA7164_MPEG_DVB, | ||
93 | }; | ||
94 | |||
95 | enum saa7164_i2c_bus_nr { | ||
96 | SAA7164_I2C_BUS_0 = 0, | ||
97 | SAA7164_I2C_BUS_1, | ||
98 | SAA7164_I2C_BUS_2, | ||
99 | }; | ||
100 | |||
101 | enum saa7164_buffer_flags { | ||
102 | SAA7164_BUFFER_UNDEFINED = 0, | ||
103 | SAA7164_BUFFER_FREE, | ||
104 | SAA7164_BUFFER_BUSY, | ||
105 | SAA7164_BUFFER_FULL | ||
106 | }; | ||
107 | |||
108 | enum saa7164_unit_type { | ||
109 | SAA7164_UNIT_UNDEFINED = 0, | ||
110 | SAA7164_UNIT_DIGITAL_DEMODULATOR, | ||
111 | SAA7164_UNIT_ANALOG_DEMODULATOR, | ||
112 | SAA7164_UNIT_TUNER, | ||
113 | SAA7164_UNIT_EEPROM, | ||
114 | SAA7164_UNIT_ZILOG_IRBLASTER, | ||
115 | SAA7164_UNIT_ENCODER, | ||
116 | }; | ||
117 | |||
118 | /* The PCIe bridge doesn't grant direct access to i2c. | ||
119 | * Instead, you address i2c devices using a uniqely | ||
120 | * allocated 'unitid' value via a messaging API. This | ||
121 | * is a problem. The kernel and existing demod/tuner | ||
122 | * drivers expect to talk 'i2c', so we have to maintain | ||
123 | * a translation layer, and a series of functions to | ||
124 | * convert i2c bus + device address into a unit id. | ||
125 | */ | ||
126 | struct saa7164_unit { | ||
127 | enum saa7164_unit_type type; | ||
128 | u8 id; | ||
129 | char *name; | ||
130 | enum saa7164_i2c_bus_nr i2c_bus_nr; | ||
131 | u8 i2c_bus_addr; | ||
132 | u8 i2c_reg_len; | ||
133 | }; | ||
134 | |||
135 | struct saa7164_board { | ||
136 | char *name; | ||
137 | enum port_t porta, portb; | ||
138 | enum { | ||
139 | SAA7164_CHIP_UNDEFINED = 0, | ||
140 | SAA7164_CHIP_REV2, | ||
141 | SAA7164_CHIP_REV3, | ||
142 | } chiprev; | ||
143 | struct saa7164_unit unit[SAA7164_MAX_UNITS]; | ||
144 | }; | ||
145 | |||
146 | struct saa7164_subid { | ||
147 | u16 subvendor; | ||
148 | u16 subdevice; | ||
149 | u32 card; | ||
150 | }; | ||
151 | |||
152 | struct saa7164_fw_status { | ||
153 | |||
154 | /* RISC Core details */ | ||
155 | u32 status; | ||
156 | u32 mode; | ||
157 | u32 spec; | ||
158 | u32 inst; | ||
159 | u32 cpuload; | ||
160 | u32 remainheap; | ||
161 | |||
162 | /* Firmware version */ | ||
163 | u32 version; | ||
164 | u32 major; | ||
165 | u32 sub; | ||
166 | u32 rel; | ||
167 | u32 buildnr; | ||
168 | }; | ||
169 | |||
170 | struct saa7164_dvb { | ||
171 | struct mutex lock; | ||
172 | struct dvb_adapter adapter; | ||
173 | struct dvb_frontend *frontend; | ||
174 | struct dvb_demux demux; | ||
175 | struct dmxdev dmxdev; | ||
176 | struct dmx_frontend fe_hw; | ||
177 | struct dmx_frontend fe_mem; | ||
178 | struct dvb_net net; | ||
179 | int feeding; | ||
180 | }; | ||
181 | |||
182 | struct saa7164_i2c { | ||
183 | struct saa7164_dev *dev; | ||
184 | |||
185 | enum saa7164_i2c_bus_nr nr; | ||
186 | |||
187 | /* I2C I/O */ | ||
188 | struct i2c_adapter i2c_adap; | ||
189 | struct i2c_algo_bit_data i2c_algo; | ||
190 | struct i2c_client i2c_client; | ||
191 | u32 i2c_rc; | ||
192 | }; | ||
193 | |||
194 | struct saa7164_tsport; | ||
195 | |||
196 | struct saa7164_buffer { | ||
197 | struct list_head list; | ||
198 | |||
199 | u32 nr; | ||
200 | |||
201 | struct saa7164_tsport *port; | ||
202 | |||
203 | /* Hardware Specific */ | ||
204 | /* PCI Memory allocations */ | ||
205 | enum saa7164_buffer_flags flags; /* Free, Busy, Full */ | ||
206 | |||
207 | /* A block of page align PCI memory */ | ||
208 | u32 pci_size; /* PCI allocation size in bytes */ | ||
209 | u64 *cpu; /* Virtual address */ | ||
210 | dma_addr_t dma; /* Physical address */ | ||
211 | |||
212 | /* A page table that splits the block into a number of entries */ | ||
213 | u32 pt_size; /* PCI allocation size in bytes */ | ||
214 | u64 *pt_cpu; /* Virtual address */ | ||
215 | dma_addr_t pt_dma; /* Physical address */ | ||
216 | }; | ||
217 | |||
218 | struct saa7164_tsport { | ||
219 | |||
220 | struct saa7164_dev *dev; | ||
221 | int nr; | ||
222 | enum port_t type; | ||
223 | |||
224 | struct saa7164_dvb dvb; | ||
225 | |||
226 | /* HW related stream parameters */ | ||
227 | tmHWStreamParameters_t hw_streamingparams; | ||
228 | |||
229 | /* DMA configuration values, is seeded during initialization */ | ||
230 | tmComResDMATermDescrHeader_t hwcfg; | ||
231 | |||
232 | /* hardware specific registers */ | ||
233 | u32 bufcounter; | ||
234 | u32 pitch; | ||
235 | u32 bufsize; | ||
236 | u32 bufoffset; | ||
237 | u32 bufptr32l; | ||
238 | u32 bufptr32h; | ||
239 | u64 bufptr64; | ||
240 | |||
241 | u32 numpte; /* Number of entries in array, only valid in head */ | ||
242 | struct mutex dmaqueue_lock; | ||
243 | struct mutex dummy_dmaqueue_lock; | ||
244 | struct saa7164_buffer dmaqueue; | ||
245 | struct saa7164_buffer dummy_dmaqueue; | ||
246 | |||
247 | }; | ||
248 | |||
249 | struct saa7164_dev { | ||
250 | struct list_head devlist; | ||
251 | atomic_t refcount; | ||
252 | |||
253 | /* pci stuff */ | ||
254 | struct pci_dev *pci; | ||
255 | unsigned char pci_rev, pci_lat; | ||
256 | int pci_bus, pci_slot; | ||
257 | u32 __iomem *lmmio; | ||
258 | u8 __iomem *bmmio; | ||
259 | u32 __iomem *lmmio2; | ||
260 | u8 __iomem *bmmio2; | ||
261 | int pci_irqmask; | ||
262 | |||
263 | /* board details */ | ||
264 | int nr; | ||
265 | int hwrevision; | ||
266 | u32 board; | ||
267 | char name[32]; | ||
268 | |||
269 | /* firmware status */ | ||
270 | struct saa7164_fw_status fw_status; | ||
271 | |||
272 | tmComResHWDescr_t hwdesc; | ||
273 | tmComResInterfaceDescr_t intfdesc; | ||
274 | tmComResBusDescr_t busdesc; | ||
275 | |||
276 | tmComResBusInfo_t bus; | ||
277 | |||
278 | /* Interrupt status and ack registers */ | ||
279 | u32 int_status; | ||
280 | u32 int_ack; | ||
281 | |||
282 | struct cmd cmds[SAA_CMD_MAX_MSG_UNITS]; | ||
283 | struct mutex lock; | ||
284 | |||
285 | /* I2c related */ | ||
286 | struct saa7164_i2c i2c_bus[3]; | ||
287 | |||
288 | /* Transport related */ | ||
289 | struct saa7164_tsport ts1, ts2; | ||
290 | |||
291 | /* Deferred command/api interrupts handling */ | ||
292 | struct work_struct workcmd; | ||
293 | |||
294 | }; | ||
295 | |||
296 | extern struct list_head saa7164_devlist; | ||
297 | extern unsigned int waitsecs; | ||
298 | |||
299 | /* ----------------------------------------------------------- */ | ||
300 | /* saa7164-core.c */ | ||
301 | void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr); | ||
302 | void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len); | ||
303 | void saa7164_getfirmwarestatus(struct saa7164_dev *dev); | ||
304 | u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev); | ||
305 | |||
306 | /* ----------------------------------------------------------- */ | ||
307 | /* saa7164-fw.c */ | ||
308 | int saa7164_downloadfirmware(struct saa7164_dev *dev); | ||
309 | |||
310 | /* ----------------------------------------------------------- */ | ||
311 | /* saa7164-i2c.c */ | ||
312 | extern int saa7164_i2c_register(struct saa7164_i2c *bus); | ||
313 | extern int saa7164_i2c_unregister(struct saa7164_i2c *bus); | ||
314 | extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus, | ||
315 | unsigned int cmd, void *arg); | ||
316 | |||
317 | /* ----------------------------------------------------------- */ | ||
318 | /* saa7164-bus.c */ | ||
319 | int saa7164_bus_setup(struct saa7164_dev *dev); | ||
320 | void saa7164_bus_dump(struct saa7164_dev *dev); | ||
321 | int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf); | ||
322 | int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, | ||
323 | void *buf, int peekonly); | ||
324 | |||
325 | /* ----------------------------------------------------------- */ | ||
326 | /* saa7164-cmd.c */ | ||
327 | int saa7164_cmd_send(struct saa7164_dev *dev, | ||
328 | u8 id, tmComResCmd_t command, u16 controlselector, | ||
329 | u16 size, void *buf); | ||
330 | void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno); | ||
331 | int saa7164_irq_dequeue(struct saa7164_dev *dev); | ||
332 | |||
333 | /* ----------------------------------------------------------- */ | ||
334 | /* saa7164-api.c */ | ||
335 | int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version); | ||
336 | int saa7164_api_enum_subdevs(struct saa7164_dev *dev); | ||
337 | int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, | ||
338 | u32 datalen, u8 *data); | ||
339 | int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, | ||
340 | u32 datalen, u8 *data); | ||
341 | int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr, | ||
342 | u32 datalen, u8 *data); | ||
343 | int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen); | ||
344 | int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); | ||
345 | int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); | ||
346 | int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode); | ||
347 | |||
348 | /* ----------------------------------------------------------- */ | ||
349 | /* saa7164-cards.c */ | ||
350 | extern struct saa7164_board saa7164_boards[]; | ||
351 | extern const unsigned int saa7164_bcount; | ||
352 | |||
353 | extern struct saa7164_subid saa7164_subids[]; | ||
354 | extern const unsigned int saa7164_idcount; | ||
355 | |||
356 | extern void saa7164_card_list(struct saa7164_dev *dev); | ||
357 | extern void saa7164_gpio_setup(struct saa7164_dev *dev); | ||
358 | extern void saa7164_card_setup(struct saa7164_dev *dev); | ||
359 | |||
360 | extern int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr); | ||
361 | extern int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr); | ||
362 | extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid); | ||
363 | |||
364 | /* ----------------------------------------------------------- */ | ||
365 | /* saa7164-dvb.c */ | ||
366 | extern int saa7164_dvb_register(struct saa7164_tsport *port); | ||
367 | extern int saa7164_dvb_unregister(struct saa7164_tsport *port); | ||
368 | |||
369 | /* ----------------------------------------------------------- */ | ||
370 | /* saa7164-buffer.c */ | ||
371 | extern struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port, | ||
372 | u32 len); | ||
373 | extern int saa7164_buffer_dealloc(struct saa7164_tsport *port, | ||
374 | struct saa7164_buffer *buf); | ||
375 | |||
376 | /* ----------------------------------------------------------- */ | ||
377 | |||
378 | extern unsigned int debug; | ||
379 | #define dprintk(level, fmt, arg...)\ | ||
380 | do { if (debug & level)\ | ||
381 | printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ | ||
382 | } while (0) | ||
383 | |||
384 | #define log_warn(fmt, arg...)\ | ||
385 | do { \ | ||
386 | printk(KERN_WARNING "%s: " fmt, dev->name, ## arg);\ | ||
387 | } while (0) | ||
388 | |||
389 | #define log_err(fmt, arg...)\ | ||
390 | do { \ | ||
391 | printk(KERN_ERROR "%s: " fmt, dev->name, ## arg);\ | ||
392 | } while (0) | ||
393 | |||
394 | #define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2)) | ||
395 | #define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2)) | ||
396 | |||
397 | |||
398 | #define saa7164_readb(reg) readl(dev->bmmio + (reg)) | ||
399 | #define saa7164_writeb(reg, value) writel((value), dev->bmmio + (reg)) | ||
400 | |||
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 61c47b824083..5ab7c5aefd62 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -74,6 +74,13 @@ | |||
74 | #define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ | 74 | #define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ |
75 | #define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ | 75 | #define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ |
76 | 76 | ||
77 | #undef DEBUG_GEOMETRY | ||
78 | #ifdef DEBUG_GEOMETRY | ||
79 | #define dev_geo dev_info | ||
80 | #else | ||
81 | #define dev_geo dev_dbg | ||
82 | #endif | ||
83 | |||
77 | /* per video frame buffer */ | 84 | /* per video frame buffer */ |
78 | struct sh_mobile_ceu_buffer { | 85 | struct sh_mobile_ceu_buffer { |
79 | struct videobuf_buffer vb; /* v4l buffer must be first */ | 86 | struct videobuf_buffer vb; /* v4l buffer must be first */ |
@@ -92,10 +99,21 @@ struct sh_mobile_ceu_dev { | |||
92 | spinlock_t lock; | 99 | spinlock_t lock; |
93 | struct list_head capture; | 100 | struct list_head capture; |
94 | struct videobuf_buffer *active; | 101 | struct videobuf_buffer *active; |
95 | int is_interlaced; | ||
96 | 102 | ||
97 | struct sh_mobile_ceu_info *pdata; | 103 | struct sh_mobile_ceu_info *pdata; |
98 | 104 | ||
105 | u32 cflcr; | ||
106 | |||
107 | unsigned int is_interlaced:1; | ||
108 | unsigned int image_mode:1; | ||
109 | unsigned int is_16bit:1; | ||
110 | }; | ||
111 | |||
112 | struct sh_mobile_ceu_cam { | ||
113 | struct v4l2_rect ceu_rect; | ||
114 | unsigned int cam_width; | ||
115 | unsigned int cam_height; | ||
116 | const struct soc_camera_data_format *extra_fmt; | ||
99 | const struct soc_camera_data_format *camera_fmt; | 117 | const struct soc_camera_data_format *camera_fmt; |
100 | }; | 118 | }; |
101 | 119 | ||
@@ -146,7 +164,8 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, | |||
146 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 164 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
147 | int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3; | 165 | int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3; |
148 | 166 | ||
149 | *size = PAGE_ALIGN(icd->width * icd->height * bytes_per_pixel); | 167 | *size = PAGE_ALIGN(icd->user_width * icd->user_height * |
168 | bytes_per_pixel); | ||
150 | 169 | ||
151 | if (0 == *count) | 170 | if (0 == *count) |
152 | *count = 2; | 171 | *count = 2; |
@@ -156,7 +175,7 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, | |||
156 | (*count)--; | 175 | (*count)--; |
157 | } | 176 | } |
158 | 177 | ||
159 | dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); | 178 | dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); |
160 | 179 | ||
161 | return 0; | 180 | return 0; |
162 | } | 181 | } |
@@ -165,8 +184,9 @@ static void free_buffer(struct videobuf_queue *vq, | |||
165 | struct sh_mobile_ceu_buffer *buf) | 184 | struct sh_mobile_ceu_buffer *buf) |
166 | { | 185 | { |
167 | struct soc_camera_device *icd = vq->priv_data; | 186 | struct soc_camera_device *icd = vq->priv_data; |
187 | struct device *dev = icd->dev.parent; | ||
168 | 188 | ||
169 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, | 189 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, |
170 | &buf->vb, buf->vb.baddr, buf->vb.bsize); | 190 | &buf->vb, buf->vb.baddr, buf->vb.bsize); |
171 | 191 | ||
172 | if (in_interrupt()) | 192 | if (in_interrupt()) |
@@ -174,7 +194,7 @@ static void free_buffer(struct videobuf_queue *vq, | |||
174 | 194 | ||
175 | videobuf_waiton(&buf->vb, 0, 0); | 195 | videobuf_waiton(&buf->vb, 0, 0); |
176 | videobuf_dma_contig_free(vq, &buf->vb); | 196 | videobuf_dma_contig_free(vq, &buf->vb); |
177 | dev_dbg(&icd->dev, "%s freed\n", __func__); | 197 | dev_dbg(dev, "%s freed\n", __func__); |
178 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | 198 | buf->vb.state = VIDEOBUF_NEEDS_INIT; |
179 | } | 199 | } |
180 | 200 | ||
@@ -205,7 +225,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
205 | phys_addr_top = videobuf_to_dma_contig(pcdev->active); | 225 | phys_addr_top = videobuf_to_dma_contig(pcdev->active); |
206 | ceu_write(pcdev, CDAYR, phys_addr_top); | 226 | ceu_write(pcdev, CDAYR, phys_addr_top); |
207 | if (pcdev->is_interlaced) { | 227 | if (pcdev->is_interlaced) { |
208 | phys_addr_bottom = phys_addr_top + icd->width; | 228 | phys_addr_bottom = phys_addr_top + icd->user_width; |
209 | ceu_write(pcdev, CDBYR, phys_addr_bottom); | 229 | ceu_write(pcdev, CDBYR, phys_addr_bottom); |
210 | } | 230 | } |
211 | 231 | ||
@@ -214,10 +234,12 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
214 | case V4L2_PIX_FMT_NV21: | 234 | case V4L2_PIX_FMT_NV21: |
215 | case V4L2_PIX_FMT_NV16: | 235 | case V4L2_PIX_FMT_NV16: |
216 | case V4L2_PIX_FMT_NV61: | 236 | case V4L2_PIX_FMT_NV61: |
217 | phys_addr_top += icd->width * icd->height; | 237 | phys_addr_top += icd->user_width * |
238 | icd->user_height; | ||
218 | ceu_write(pcdev, CDACR, phys_addr_top); | 239 | ceu_write(pcdev, CDACR, phys_addr_top); |
219 | if (pcdev->is_interlaced) { | 240 | if (pcdev->is_interlaced) { |
220 | phys_addr_bottom = phys_addr_top + icd->width; | 241 | phys_addr_bottom = phys_addr_top + |
242 | icd->user_width; | ||
221 | ceu_write(pcdev, CDBCR, phys_addr_bottom); | 243 | ceu_write(pcdev, CDBCR, phys_addr_bottom); |
222 | } | 244 | } |
223 | } | 245 | } |
@@ -236,7 +258,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, | |||
236 | 258 | ||
237 | buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); | 259 | buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); |
238 | 260 | ||
239 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, | 261 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, |
240 | vb, vb->baddr, vb->bsize); | 262 | vb, vb->baddr, vb->bsize); |
241 | 263 | ||
242 | /* Added list head initialization on alloc */ | 264 | /* Added list head initialization on alloc */ |
@@ -251,12 +273,12 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, | |||
251 | BUG_ON(NULL == icd->current_fmt); | 273 | BUG_ON(NULL == icd->current_fmt); |
252 | 274 | ||
253 | if (buf->fmt != icd->current_fmt || | 275 | if (buf->fmt != icd->current_fmt || |
254 | vb->width != icd->width || | 276 | vb->width != icd->user_width || |
255 | vb->height != icd->height || | 277 | vb->height != icd->user_height || |
256 | vb->field != field) { | 278 | vb->field != field) { |
257 | buf->fmt = icd->current_fmt; | 279 | buf->fmt = icd->current_fmt; |
258 | vb->width = icd->width; | 280 | vb->width = icd->user_width; |
259 | vb->height = icd->height; | 281 | vb->height = icd->user_height; |
260 | vb->field = field; | 282 | vb->field = field; |
261 | vb->state = VIDEOBUF_NEEDS_INIT; | 283 | vb->state = VIDEOBUF_NEEDS_INIT; |
262 | } | 284 | } |
@@ -289,7 +311,7 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, | |||
289 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 311 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
290 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 312 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
291 | 313 | ||
292 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, | 314 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, |
293 | vb, vb->baddr, vb->bsize); | 315 | vb, vb->baddr, vb->bsize); |
294 | 316 | ||
295 | vb->state = VIDEOBUF_QUEUED; | 317 | vb->state = VIDEOBUF_QUEUED; |
@@ -304,6 +326,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, | |||
304 | static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, | 326 | static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, |
305 | struct videobuf_buffer *vb) | 327 | struct videobuf_buffer *vb) |
306 | { | 328 | { |
329 | struct soc_camera_device *icd = vq->priv_data; | ||
330 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
331 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
332 | unsigned long flags; | ||
333 | |||
334 | spin_lock_irqsave(&pcdev->lock, flags); | ||
335 | |||
336 | if (pcdev->active == vb) { | ||
337 | /* disable capture (release DMA buffer), reset */ | ||
338 | ceu_write(pcdev, CAPSR, 1 << 16); | ||
339 | pcdev->active = NULL; | ||
340 | } | ||
341 | |||
342 | if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && | ||
343 | !list_empty(&vb->queue)) { | ||
344 | vb->state = VIDEOBUF_ERROR; | ||
345 | list_del_init(&vb->queue); | ||
346 | } | ||
347 | |||
348 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
349 | |||
307 | free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb)); | 350 | free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb)); |
308 | } | 351 | } |
309 | 352 | ||
@@ -323,6 +366,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) | |||
323 | spin_lock_irqsave(&pcdev->lock, flags); | 366 | spin_lock_irqsave(&pcdev->lock, flags); |
324 | 367 | ||
325 | vb = pcdev->active; | 368 | vb = pcdev->active; |
369 | if (!vb) | ||
370 | /* Stale interrupt from a released buffer */ | ||
371 | goto out; | ||
372 | |||
326 | list_del_init(&vb->queue); | 373 | list_del_init(&vb->queue); |
327 | 374 | ||
328 | if (!list_empty(&pcdev->capture)) | 375 | if (!list_empty(&pcdev->capture)) |
@@ -337,6 +384,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) | |||
337 | do_gettimeofday(&vb->ts); | 384 | do_gettimeofday(&vb->ts); |
338 | vb->field_count++; | 385 | vb->field_count++; |
339 | wake_up(&vb->done); | 386 | wake_up(&vb->done); |
387 | |||
388 | out: | ||
340 | spin_unlock_irqrestore(&pcdev->lock, flags); | 389 | spin_unlock_irqrestore(&pcdev->lock, flags); |
341 | 390 | ||
342 | return IRQ_HANDLED; | 391 | return IRQ_HANDLED; |
@@ -347,28 +396,23 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
347 | { | 396 | { |
348 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 397 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
349 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 398 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
350 | int ret = -EBUSY; | ||
351 | 399 | ||
352 | if (pcdev->icd) | 400 | if (pcdev->icd) |
353 | goto err; | 401 | return -EBUSY; |
354 | 402 | ||
355 | dev_info(&icd->dev, | 403 | dev_info(icd->dev.parent, |
356 | "SuperH Mobile CEU driver attached to camera %d\n", | 404 | "SuperH Mobile CEU driver attached to camera %d\n", |
357 | icd->devnum); | 405 | icd->devnum); |
358 | 406 | ||
359 | ret = icd->ops->init(icd); | 407 | clk_enable(pcdev->clk); |
360 | if (ret) | ||
361 | goto err; | ||
362 | |||
363 | pm_runtime_get_sync(ici->dev); | ||
364 | 408 | ||
365 | ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ | 409 | ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ |
366 | while (ceu_read(pcdev, CSTSR) & 1) | 410 | while (ceu_read(pcdev, CSTSR) & 1) |
367 | msleep(1); | 411 | msleep(1); |
368 | 412 | ||
369 | pcdev->icd = icd; | 413 | pcdev->icd = icd; |
370 | err: | 414 | |
371 | return ret; | 415 | return 0; |
372 | } | 416 | } |
373 | 417 | ||
374 | /* Called with .video_lock held */ | 418 | /* Called with .video_lock held */ |
@@ -394,25 +438,151 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | |||
394 | } | 438 | } |
395 | spin_unlock_irqrestore(&pcdev->lock, flags); | 439 | spin_unlock_irqrestore(&pcdev->lock, flags); |
396 | 440 | ||
397 | pm_runtime_put_sync(ici->dev); | 441 | clk_disable(pcdev->clk); |
398 | 442 | ||
399 | icd->ops->release(icd); | 443 | dev_info(icd->dev.parent, |
400 | |||
401 | dev_info(&icd->dev, | ||
402 | "SuperH Mobile CEU driver detached from camera %d\n", | 444 | "SuperH Mobile CEU driver detached from camera %d\n", |
403 | icd->devnum); | 445 | icd->devnum); |
404 | 446 | ||
405 | pcdev->icd = NULL; | 447 | pcdev->icd = NULL; |
406 | } | 448 | } |
407 | 449 | ||
450 | /* | ||
451 | * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)" | ||
452 | * in SH7722 Hardware Manual | ||
453 | */ | ||
454 | static unsigned int size_dst(unsigned int src, unsigned int scale) | ||
455 | { | ||
456 | unsigned int mant_pre = scale >> 12; | ||
457 | if (!src || !scale) | ||
458 | return src; | ||
459 | return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) * | ||
460 | mant_pre * 4096 / scale + 1; | ||
461 | } | ||
462 | |||
463 | static u16 calc_scale(unsigned int src, unsigned int *dst) | ||
464 | { | ||
465 | u16 scale; | ||
466 | |||
467 | if (src == *dst) | ||
468 | return 0; | ||
469 | |||
470 | scale = (src * 4096 / *dst) & ~7; | ||
471 | |||
472 | while (scale > 4096 && size_dst(src, scale) < *dst) | ||
473 | scale -= 8; | ||
474 | |||
475 | *dst = size_dst(src, scale); | ||
476 | |||
477 | return scale; | ||
478 | } | ||
479 | |||
480 | /* rect is guaranteed to not exceed the scaled camera rectangle */ | ||
481 | static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd, | ||
482 | unsigned int out_width, | ||
483 | unsigned int out_height) | ||
484 | { | ||
485 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
486 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
487 | struct v4l2_rect *rect = &cam->ceu_rect; | ||
488 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
489 | unsigned int height, width, cdwdr_width, in_width, in_height; | ||
490 | unsigned int left_offset, top_offset; | ||
491 | u32 camor; | ||
492 | |||
493 | dev_dbg(icd->dev.parent, "Crop %ux%u@%u:%u\n", | ||
494 | rect->width, rect->height, rect->left, rect->top); | ||
495 | |||
496 | left_offset = rect->left; | ||
497 | top_offset = rect->top; | ||
498 | |||
499 | if (pcdev->image_mode) { | ||
500 | in_width = rect->width; | ||
501 | if (!pcdev->is_16bit) { | ||
502 | in_width *= 2; | ||
503 | left_offset *= 2; | ||
504 | } | ||
505 | width = cdwdr_width = out_width; | ||
506 | } else { | ||
507 | unsigned int w_factor = (icd->current_fmt->depth + 7) >> 3; | ||
508 | |||
509 | width = out_width * w_factor / 2; | ||
510 | |||
511 | if (!pcdev->is_16bit) | ||
512 | w_factor *= 2; | ||
513 | |||
514 | in_width = rect->width * w_factor / 2; | ||
515 | left_offset = left_offset * w_factor / 2; | ||
516 | |||
517 | cdwdr_width = width * 2; | ||
518 | } | ||
519 | |||
520 | height = out_height; | ||
521 | in_height = rect->height; | ||
522 | if (pcdev->is_interlaced) { | ||
523 | height /= 2; | ||
524 | in_height /= 2; | ||
525 | top_offset /= 2; | ||
526 | cdwdr_width *= 2; | ||
527 | } | ||
528 | |||
529 | /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ | ||
530 | camor = left_offset | (top_offset << 16); | ||
531 | |||
532 | dev_geo(icd->dev.parent, | ||
533 | "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor, | ||
534 | (in_height << 16) | in_width, (height << 16) | width, | ||
535 | cdwdr_width); | ||
536 | |||
537 | ceu_write(pcdev, CAMOR, camor); | ||
538 | ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); | ||
539 | ceu_write(pcdev, CFSZR, (height << 16) | width); | ||
540 | ceu_write(pcdev, CDWDR, cdwdr_width); | ||
541 | } | ||
542 | |||
543 | static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev) | ||
544 | { | ||
545 | u32 capsr = ceu_read(pcdev, CAPSR); | ||
546 | ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */ | ||
547 | return capsr; | ||
548 | } | ||
549 | |||
550 | static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) | ||
551 | { | ||
552 | unsigned long timeout = jiffies + 10 * HZ; | ||
553 | |||
554 | /* | ||
555 | * Wait until the end of the current frame. It can take a long time, | ||
556 | * but if it has been aborted by a CAPSR reset, it shoule exit sooner. | ||
557 | */ | ||
558 | while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout)) | ||
559 | msleep(1); | ||
560 | |||
561 | if (time_after(jiffies, timeout)) { | ||
562 | dev_err(pcdev->ici.v4l2_dev.dev, | ||
563 | "Timeout waiting for frame end! Interface problem?\n"); | ||
564 | return; | ||
565 | } | ||
566 | |||
567 | /* Wait until reset clears, this shall not hang... */ | ||
568 | while (ceu_read(pcdev, CAPSR) & (1 << 16)) | ||
569 | udelay(10); | ||
570 | |||
571 | /* Anything to restore? */ | ||
572 | if (capsr & ~(1 << 16)) | ||
573 | ceu_write(pcdev, CAPSR, capsr); | ||
574 | } | ||
575 | |||
408 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | 576 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, |
409 | __u32 pixfmt) | 577 | __u32 pixfmt) |
410 | { | 578 | { |
411 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 579 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
412 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 580 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
413 | int ret, buswidth, width, height, cfszr_width, cdwdr_width; | 581 | int ret; |
414 | unsigned long camera_flags, common_flags, value; | 582 | unsigned long camera_flags, common_flags, value; |
415 | int yuv_mode, yuv_lineskip; | 583 | int yuv_lineskip; |
584 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
585 | u32 capsr = capture_save_reset(pcdev); | ||
416 | 586 | ||
417 | camera_flags = icd->ops->query_bus_param(icd); | 587 | camera_flags = icd->ops->query_bus_param(icd); |
418 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 588 | common_flags = soc_camera_bus_param_compatible(camera_flags, |
@@ -426,10 +596,10 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
426 | 596 | ||
427 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { | 597 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { |
428 | case SOCAM_DATAWIDTH_8: | 598 | case SOCAM_DATAWIDTH_8: |
429 | buswidth = 8; | 599 | pcdev->is_16bit = 0; |
430 | break; | 600 | break; |
431 | case SOCAM_DATAWIDTH_16: | 601 | case SOCAM_DATAWIDTH_16: |
432 | buswidth = 16; | 602 | pcdev->is_16bit = 1; |
433 | break; | 603 | break; |
434 | default: | 604 | default: |
435 | return -EINVAL; | 605 | return -EINVAL; |
@@ -439,7 +609,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
439 | ceu_write(pcdev, CRCMPR, 0); | 609 | ceu_write(pcdev, CRCMPR, 0); |
440 | 610 | ||
441 | value = 0x00000010; /* data fetch by default */ | 611 | value = 0x00000010; /* data fetch by default */ |
442 | yuv_mode = yuv_lineskip = 0; | 612 | yuv_lineskip = 0; |
443 | 613 | ||
444 | switch (icd->current_fmt->fourcc) { | 614 | switch (icd->current_fmt->fourcc) { |
445 | case V4L2_PIX_FMT_NV12: | 615 | case V4L2_PIX_FMT_NV12: |
@@ -448,8 +618,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
448 | /* fall-through */ | 618 | /* fall-through */ |
449 | case V4L2_PIX_FMT_NV16: | 619 | case V4L2_PIX_FMT_NV16: |
450 | case V4L2_PIX_FMT_NV61: | 620 | case V4L2_PIX_FMT_NV61: |
451 | yuv_mode = 1; | 621 | switch (cam->camera_fmt->fourcc) { |
452 | switch (pcdev->camera_fmt->fourcc) { | ||
453 | case V4L2_PIX_FMT_UYVY: | 622 | case V4L2_PIX_FMT_UYVY: |
454 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ | 623 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ |
455 | break; | 624 | break; |
@@ -473,36 +642,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
473 | 642 | ||
474 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | 643 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
475 | value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; | 644 | value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; |
476 | value |= buswidth == 16 ? 1 << 12 : 0; | 645 | value |= pcdev->is_16bit ? 1 << 12 : 0; |
477 | ceu_write(pcdev, CAMCR, value); | 646 | ceu_write(pcdev, CAMCR, value); |
478 | 647 | ||
479 | ceu_write(pcdev, CAPCR, 0x00300000); | 648 | ceu_write(pcdev, CAPCR, 0x00300000); |
480 | ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); | 649 | ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); |
481 | 650 | ||
651 | sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height); | ||
482 | mdelay(1); | 652 | mdelay(1); |
483 | 653 | ||
484 | if (yuv_mode) { | 654 | ceu_write(pcdev, CFLCR, pcdev->cflcr); |
485 | width = icd->width * 2; | ||
486 | width = buswidth == 16 ? width / 2 : width; | ||
487 | cfszr_width = cdwdr_width = icd->width; | ||
488 | } else { | ||
489 | width = icd->width * ((icd->current_fmt->depth + 7) >> 3); | ||
490 | width = buswidth == 16 ? width / 2 : width; | ||
491 | cfszr_width = buswidth == 8 ? width / 2 : width; | ||
492 | cdwdr_width = buswidth == 16 ? width * 2 : width; | ||
493 | } | ||
494 | |||
495 | height = icd->height; | ||
496 | if (pcdev->is_interlaced) { | ||
497 | height /= 2; | ||
498 | cdwdr_width *= 2; | ||
499 | } | ||
500 | |||
501 | ceu_write(pcdev, CAMOR, 0); | ||
502 | ceu_write(pcdev, CAPWR, (height << 16) | width); | ||
503 | ceu_write(pcdev, CFLCR, 0); /* no scaling */ | ||
504 | ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width); | ||
505 | ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */ | ||
506 | 655 | ||
507 | /* A few words about byte order (observed in Big Endian mode) | 656 | /* A few words about byte order (observed in Big Endian mode) |
508 | * | 657 | * |
@@ -521,10 +670,15 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
521 | value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ | 670 | value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ |
522 | 671 | ||
523 | ceu_write(pcdev, CDOCR, value); | 672 | ceu_write(pcdev, CDOCR, value); |
524 | |||
525 | ceu_write(pcdev, CDWDR, cdwdr_width); | ||
526 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ | 673 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ |
527 | 674 | ||
675 | dev_dbg(icd->dev.parent, "S_FMT successful for %c%c%c%c %ux%u\n", | ||
676 | pixfmt & 0xff, (pixfmt >> 8) & 0xff, | ||
677 | (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff, | ||
678 | icd->user_width, icd->user_height); | ||
679 | |||
680 | capture_restore(pcdev, capsr); | ||
681 | |||
528 | /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ | 682 | /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ |
529 | return 0; | 683 | return 0; |
530 | } | 684 | } |
@@ -574,24 +728,35 @@ static const struct soc_camera_data_format sh_mobile_ceu_formats[] = { | |||
574 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | 728 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, |
575 | struct soc_camera_format_xlate *xlate) | 729 | struct soc_camera_format_xlate *xlate) |
576 | { | 730 | { |
577 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 731 | struct device *dev = icd->dev.parent; |
578 | int ret, k, n; | 732 | int ret, k, n; |
579 | int formats = 0; | 733 | int formats = 0; |
734 | struct sh_mobile_ceu_cam *cam; | ||
580 | 735 | ||
581 | ret = sh_mobile_ceu_try_bus_param(icd); | 736 | ret = sh_mobile_ceu_try_bus_param(icd); |
582 | if (ret < 0) | 737 | if (ret < 0) |
583 | return 0; | 738 | return 0; |
584 | 739 | ||
740 | if (!icd->host_priv) { | ||
741 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
742 | if (!cam) | ||
743 | return -ENOMEM; | ||
744 | |||
745 | icd->host_priv = cam; | ||
746 | } else { | ||
747 | cam = icd->host_priv; | ||
748 | } | ||
749 | |||
585 | /* Beginning of a pass */ | 750 | /* Beginning of a pass */ |
586 | if (!idx) | 751 | if (!idx) |
587 | icd->host_priv = NULL; | 752 | cam->extra_fmt = NULL; |
588 | 753 | ||
589 | switch (icd->formats[idx].fourcc) { | 754 | switch (icd->formats[idx].fourcc) { |
590 | case V4L2_PIX_FMT_UYVY: | 755 | case V4L2_PIX_FMT_UYVY: |
591 | case V4L2_PIX_FMT_VYUY: | 756 | case V4L2_PIX_FMT_VYUY: |
592 | case V4L2_PIX_FMT_YUYV: | 757 | case V4L2_PIX_FMT_YUYV: |
593 | case V4L2_PIX_FMT_YVYU: | 758 | case V4L2_PIX_FMT_YVYU: |
594 | if (icd->host_priv) | 759 | if (cam->extra_fmt) |
595 | goto add_single_format; | 760 | goto add_single_format; |
596 | 761 | ||
597 | /* | 762 | /* |
@@ -603,7 +768,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
603 | * the host_priv pointer and check whether the format you're | 768 | * the host_priv pointer and check whether the format you're |
604 | * going to add now is already there. | 769 | * going to add now is already there. |
605 | */ | 770 | */ |
606 | icd->host_priv = (void *)sh_mobile_ceu_formats; | 771 | cam->extra_fmt = (void *)sh_mobile_ceu_formats; |
607 | 772 | ||
608 | n = ARRAY_SIZE(sh_mobile_ceu_formats); | 773 | n = ARRAY_SIZE(sh_mobile_ceu_formats); |
609 | formats += n; | 774 | formats += n; |
@@ -612,7 +777,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
612 | xlate->cam_fmt = icd->formats + idx; | 777 | xlate->cam_fmt = icd->formats + idx; |
613 | xlate->buswidth = icd->formats[idx].depth; | 778 | xlate->buswidth = icd->formats[idx].depth; |
614 | xlate++; | 779 | xlate++; |
615 | dev_dbg(ici->dev, "Providing format %s using %s\n", | 780 | dev_dbg(dev, "Providing format %s using %s\n", |
616 | sh_mobile_ceu_formats[k].name, | 781 | sh_mobile_ceu_formats[k].name, |
617 | icd->formats[idx].name); | 782 | icd->formats[idx].name); |
618 | } | 783 | } |
@@ -625,7 +790,7 @@ add_single_format: | |||
625 | xlate->cam_fmt = icd->formats + idx; | 790 | xlate->cam_fmt = icd->formats + idx; |
626 | xlate->buswidth = icd->formats[idx].depth; | 791 | xlate->buswidth = icd->formats[idx].depth; |
627 | xlate++; | 792 | xlate++; |
628 | dev_dbg(ici->dev, | 793 | dev_dbg(dev, |
629 | "Providing format %s in pass-through mode\n", | 794 | "Providing format %s in pass-through mode\n", |
630 | icd->formats[idx].name); | 795 | icd->formats[idx].name); |
631 | } | 796 | } |
@@ -634,82 +799,714 @@ add_single_format: | |||
634 | return formats; | 799 | return formats; |
635 | } | 800 | } |
636 | 801 | ||
802 | static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) | ||
803 | { | ||
804 | kfree(icd->host_priv); | ||
805 | icd->host_priv = NULL; | ||
806 | } | ||
807 | |||
808 | /* Check if any dimension of r1 is smaller than respective one of r2 */ | ||
809 | static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2) | ||
810 | { | ||
811 | return r1->width < r2->width || r1->height < r2->height; | ||
812 | } | ||
813 | |||
814 | /* Check if r1 fails to cover r2 */ | ||
815 | static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2) | ||
816 | { | ||
817 | return r1->left > r2->left || r1->top > r2->top || | ||
818 | r1->left + r1->width < r2->left + r2->width || | ||
819 | r1->top + r1->height < r2->top + r2->height; | ||
820 | } | ||
821 | |||
822 | static unsigned int scale_down(unsigned int size, unsigned int scale) | ||
823 | { | ||
824 | return (size * 4096 + scale / 2) / scale; | ||
825 | } | ||
826 | |||
827 | static unsigned int scale_up(unsigned int size, unsigned int scale) | ||
828 | { | ||
829 | return (size * scale + 2048) / 4096; | ||
830 | } | ||
831 | |||
832 | static unsigned int calc_generic_scale(unsigned int input, unsigned int output) | ||
833 | { | ||
834 | return (input * 4096 + output / 2) / output; | ||
835 | } | ||
836 | |||
837 | static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) | ||
838 | { | ||
839 | struct v4l2_crop crop; | ||
840 | struct v4l2_cropcap cap; | ||
841 | int ret; | ||
842 | |||
843 | crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
844 | |||
845 | ret = v4l2_subdev_call(sd, video, g_crop, &crop); | ||
846 | if (!ret) { | ||
847 | *rect = crop.c; | ||
848 | return ret; | ||
849 | } | ||
850 | |||
851 | /* Camera driver doesn't support .g_crop(), assume default rectangle */ | ||
852 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
853 | |||
854 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
855 | if (ret < 0) | ||
856 | return ret; | ||
857 | |||
858 | *rect = cap.defrect; | ||
859 | |||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | /* | ||
864 | * The common for both scaling and cropping iterative approach is: | ||
865 | * 1. try if the client can produce exactly what requested by the user | ||
866 | * 2. if (1) failed, try to double the client image until we get one big enough | ||
867 | * 3. if (2) failed, try to request the maximum image | ||
868 | */ | ||
869 | static int client_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop, | ||
870 | struct v4l2_crop *cam_crop) | ||
871 | { | ||
872 | struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; | ||
873 | struct device *dev = sd->v4l2_dev->dev; | ||
874 | struct v4l2_cropcap cap; | ||
875 | int ret; | ||
876 | unsigned int width, height; | ||
877 | |||
878 | v4l2_subdev_call(sd, video, s_crop, crop); | ||
879 | ret = client_g_rect(sd, cam_rect); | ||
880 | if (ret < 0) | ||
881 | return ret; | ||
882 | |||
883 | /* | ||
884 | * Now cam_crop contains the current camera input rectangle, and it must | ||
885 | * be within camera cropcap bounds | ||
886 | */ | ||
887 | if (!memcmp(rect, cam_rect, sizeof(*rect))) { | ||
888 | /* Even if camera S_CROP failed, but camera rectangle matches */ | ||
889 | dev_dbg(dev, "Camera S_CROP successful for %ux%u@%u:%u\n", | ||
890 | rect->width, rect->height, rect->left, rect->top); | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | /* Try to fix cropping, that camera hasn't managed to set */ | ||
895 | dev_geo(dev, "Fix camera S_CROP for %ux%u@%u:%u to %ux%u@%u:%u\n", | ||
896 | cam_rect->width, cam_rect->height, | ||
897 | cam_rect->left, cam_rect->top, | ||
898 | rect->width, rect->height, rect->left, rect->top); | ||
899 | |||
900 | /* We need sensor maximum rectangle */ | ||
901 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
902 | if (ret < 0) | ||
903 | return ret; | ||
904 | |||
905 | soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2, | ||
906 | cap.bounds.width); | ||
907 | soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4, | ||
908 | cap.bounds.height); | ||
909 | |||
910 | /* | ||
911 | * Popular special case - some cameras can only handle fixed sizes like | ||
912 | * QVGA, VGA,... Take care to avoid infinite loop. | ||
913 | */ | ||
914 | width = max(cam_rect->width, 2); | ||
915 | height = max(cam_rect->height, 2); | ||
916 | |||
917 | while (!ret && (is_smaller(cam_rect, rect) || | ||
918 | is_inside(cam_rect, rect)) && | ||
919 | (cap.bounds.width > width || cap.bounds.height > height)) { | ||
920 | |||
921 | width *= 2; | ||
922 | height *= 2; | ||
923 | |||
924 | cam_rect->width = width; | ||
925 | cam_rect->height = height; | ||
926 | |||
927 | /* | ||
928 | * We do not know what capabilities the camera has to set up | ||
929 | * left and top borders. We could try to be smarter in iterating | ||
930 | * them, e.g., if camera current left is to the right of the | ||
931 | * target left, set it to the middle point between the current | ||
932 | * left and minimum left. But that would add too much | ||
933 | * complexity: we would have to iterate each border separately. | ||
934 | */ | ||
935 | if (cam_rect->left > rect->left) | ||
936 | cam_rect->left = cap.bounds.left; | ||
937 | |||
938 | if (cam_rect->left + cam_rect->width < rect->left + rect->width) | ||
939 | cam_rect->width = rect->left + rect->width - | ||
940 | cam_rect->left; | ||
941 | |||
942 | if (cam_rect->top > rect->top) | ||
943 | cam_rect->top = cap.bounds.top; | ||
944 | |||
945 | if (cam_rect->top + cam_rect->height < rect->top + rect->height) | ||
946 | cam_rect->height = rect->top + rect->height - | ||
947 | cam_rect->top; | ||
948 | |||
949 | v4l2_subdev_call(sd, video, s_crop, cam_crop); | ||
950 | ret = client_g_rect(sd, cam_rect); | ||
951 | dev_geo(dev, "Camera S_CROP %d for %ux%u@%u:%u\n", ret, | ||
952 | cam_rect->width, cam_rect->height, | ||
953 | cam_rect->left, cam_rect->top); | ||
954 | } | ||
955 | |||
956 | /* S_CROP must not modify the rectangle */ | ||
957 | if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) { | ||
958 | /* | ||
959 | * The camera failed to configure a suitable cropping, | ||
960 | * we cannot use the current rectangle, set to max | ||
961 | */ | ||
962 | *cam_rect = cap.bounds; | ||
963 | v4l2_subdev_call(sd, video, s_crop, cam_crop); | ||
964 | ret = client_g_rect(sd, cam_rect); | ||
965 | dev_geo(dev, "Camera S_CROP %d for max %ux%u@%u:%u\n", ret, | ||
966 | cam_rect->width, cam_rect->height, | ||
967 | cam_rect->left, cam_rect->top); | ||
968 | } | ||
969 | |||
970 | return ret; | ||
971 | } | ||
972 | |||
973 | static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect, | ||
974 | unsigned int *scale_h, unsigned int *scale_v) | ||
975 | { | ||
976 | struct v4l2_format f; | ||
977 | int ret; | ||
978 | |||
979 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
980 | |||
981 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
982 | if (ret < 0) | ||
983 | return ret; | ||
984 | |||
985 | *scale_h = calc_generic_scale(rect->width, f.fmt.pix.width); | ||
986 | *scale_v = calc_generic_scale(rect->height, f.fmt.pix.height); | ||
987 | |||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static int get_camera_subwin(struct soc_camera_device *icd, | ||
992 | struct v4l2_rect *cam_subrect, | ||
993 | unsigned int cam_hscale, unsigned int cam_vscale) | ||
994 | { | ||
995 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
996 | struct v4l2_rect *ceu_rect = &cam->ceu_rect; | ||
997 | |||
998 | if (!ceu_rect->width) { | ||
999 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1000 | struct device *dev = icd->dev.parent; | ||
1001 | struct v4l2_format f; | ||
1002 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
1003 | int ret; | ||
1004 | /* First time */ | ||
1005 | |||
1006 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1007 | |||
1008 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
1009 | if (ret < 0) | ||
1010 | return ret; | ||
1011 | |||
1012 | dev_geo(dev, "camera fmt %ux%u\n", pix->width, pix->height); | ||
1013 | |||
1014 | if (pix->width > 2560) { | ||
1015 | ceu_rect->width = 2560; | ||
1016 | ceu_rect->left = (pix->width - 2560) / 2; | ||
1017 | } else { | ||
1018 | ceu_rect->width = pix->width; | ||
1019 | ceu_rect->left = 0; | ||
1020 | } | ||
1021 | |||
1022 | if (pix->height > 1920) { | ||
1023 | ceu_rect->height = 1920; | ||
1024 | ceu_rect->top = (pix->height - 1920) / 2; | ||
1025 | } else { | ||
1026 | ceu_rect->height = pix->height; | ||
1027 | ceu_rect->top = 0; | ||
1028 | } | ||
1029 | |||
1030 | dev_geo(dev, "initialised CEU rect %ux%u@%u:%u\n", | ||
1031 | ceu_rect->width, ceu_rect->height, | ||
1032 | ceu_rect->left, ceu_rect->top); | ||
1033 | } | ||
1034 | |||
1035 | cam_subrect->width = scale_up(ceu_rect->width, cam_hscale); | ||
1036 | cam_subrect->left = scale_up(ceu_rect->left, cam_hscale); | ||
1037 | cam_subrect->height = scale_up(ceu_rect->height, cam_vscale); | ||
1038 | cam_subrect->top = scale_up(ceu_rect->top, cam_vscale); | ||
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, | ||
1044 | bool ceu_can_scale) | ||
1045 | { | ||
1046 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1047 | struct device *dev = icd->dev.parent; | ||
1048 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1049 | unsigned int width = pix->width, height = pix->height, tmp_w, tmp_h; | ||
1050 | unsigned int max_width, max_height; | ||
1051 | struct v4l2_cropcap cap; | ||
1052 | int ret; | ||
1053 | |||
1054 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1055 | |||
1056 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
1057 | if (ret < 0) | ||
1058 | return ret; | ||
1059 | |||
1060 | max_width = min(cap.bounds.width, 2560); | ||
1061 | max_height = min(cap.bounds.height, 1920); | ||
1062 | |||
1063 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | ||
1064 | if (ret < 0) | ||
1065 | return ret; | ||
1066 | |||
1067 | dev_geo(dev, "camera scaled to %ux%u\n", pix->width, pix->height); | ||
1068 | |||
1069 | if ((width == pix->width && height == pix->height) || !ceu_can_scale) | ||
1070 | return 0; | ||
1071 | |||
1072 | /* Camera set a format, but geometry is not precise, try to improve */ | ||
1073 | tmp_w = pix->width; | ||
1074 | tmp_h = pix->height; | ||
1075 | |||
1076 | /* width <= max_width && height <= max_height - guaranteed by try_fmt */ | ||
1077 | while ((width > tmp_w || height > tmp_h) && | ||
1078 | tmp_w < max_width && tmp_h < max_height) { | ||
1079 | tmp_w = min(2 * tmp_w, max_width); | ||
1080 | tmp_h = min(2 * tmp_h, max_height); | ||
1081 | pix->width = tmp_w; | ||
1082 | pix->height = tmp_h; | ||
1083 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | ||
1084 | dev_geo(dev, "Camera scaled to %ux%u\n", | ||
1085 | pix->width, pix->height); | ||
1086 | if (ret < 0) { | ||
1087 | /* This shouldn't happen */ | ||
1088 | dev_err(dev, "Client failed to set format: %d\n", ret); | ||
1089 | return ret; | ||
1090 | } | ||
1091 | } | ||
1092 | |||
1093 | return 0; | ||
1094 | } | ||
1095 | |||
1096 | /** | ||
1097 | * @rect - camera cropped rectangle | ||
1098 | * @sub_rect - CEU cropped rectangle, mapped back to camera input area | ||
1099 | * @ceu_rect - on output calculated CEU crop rectangle | ||
1100 | */ | ||
1101 | static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, | ||
1102 | struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect, | ||
1103 | struct v4l2_format *f, bool ceu_can_scale) | ||
1104 | { | ||
1105 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1106 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1107 | struct device *dev = icd->dev.parent; | ||
1108 | struct v4l2_format f_tmp = *f; | ||
1109 | struct v4l2_pix_format *pix_tmp = &f_tmp.fmt.pix; | ||
1110 | unsigned int scale_h, scale_v; | ||
1111 | int ret; | ||
1112 | |||
1113 | /* 5. Apply iterative camera S_FMT for camera user window. */ | ||
1114 | ret = client_s_fmt(icd, &f_tmp, ceu_can_scale); | ||
1115 | if (ret < 0) | ||
1116 | return ret; | ||
1117 | |||
1118 | dev_geo(dev, "5: camera scaled to %ux%u\n", | ||
1119 | pix_tmp->width, pix_tmp->height); | ||
1120 | |||
1121 | /* 6. Retrieve camera output window (g_fmt) */ | ||
1122 | |||
1123 | /* unneeded - it is already in "f_tmp" */ | ||
1124 | |||
1125 | /* 7. Calculate new camera scales. */ | ||
1126 | ret = get_camera_scales(sd, rect, &scale_h, &scale_v); | ||
1127 | if (ret < 0) | ||
1128 | return ret; | ||
1129 | |||
1130 | dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v); | ||
1131 | |||
1132 | cam->cam_width = pix_tmp->width; | ||
1133 | cam->cam_height = pix_tmp->height; | ||
1134 | f->fmt.pix.width = pix_tmp->width; | ||
1135 | f->fmt.pix.height = pix_tmp->height; | ||
1136 | |||
1137 | /* | ||
1138 | * 8. Calculate new CEU crop - apply camera scales to previously | ||
1139 | * calculated "effective" crop. | ||
1140 | */ | ||
1141 | ceu_rect->left = scale_down(sub_rect->left, scale_h); | ||
1142 | ceu_rect->width = scale_down(sub_rect->width, scale_h); | ||
1143 | ceu_rect->top = scale_down(sub_rect->top, scale_v); | ||
1144 | ceu_rect->height = scale_down(sub_rect->height, scale_v); | ||
1145 | |||
1146 | dev_geo(dev, "8: new CEU rect %ux%u@%u:%u\n", | ||
1147 | ceu_rect->width, ceu_rect->height, | ||
1148 | ceu_rect->left, ceu_rect->top); | ||
1149 | |||
1150 | return 0; | ||
1151 | } | ||
1152 | |||
1153 | /* Get combined scales */ | ||
1154 | static int get_scales(struct soc_camera_device *icd, | ||
1155 | unsigned int *scale_h, unsigned int *scale_v) | ||
1156 | { | ||
1157 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1158 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1159 | struct v4l2_crop cam_crop; | ||
1160 | unsigned int width_in, height_in; | ||
1161 | int ret; | ||
1162 | |||
1163 | cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1164 | |||
1165 | ret = client_g_rect(sd, &cam_crop.c); | ||
1166 | if (ret < 0) | ||
1167 | return ret; | ||
1168 | |||
1169 | ret = get_camera_scales(sd, &cam_crop.c, scale_h, scale_v); | ||
1170 | if (ret < 0) | ||
1171 | return ret; | ||
1172 | |||
1173 | width_in = scale_up(cam->ceu_rect.width, *scale_h); | ||
1174 | height_in = scale_up(cam->ceu_rect.height, *scale_v); | ||
1175 | |||
1176 | *scale_h = calc_generic_scale(cam->ceu_rect.width, icd->user_width); | ||
1177 | *scale_v = calc_generic_scale(cam->ceu_rect.height, icd->user_height); | ||
1178 | |||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1182 | /* | ||
1183 | * CEU can scale and crop, but we don't want to waste bandwidth and kill the | ||
1184 | * framerate by always requesting the maximum image from the client. See | ||
1185 | * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of | ||
1186 | * scaling and cropping algorithms and for the meaning of referenced here steps. | ||
1187 | */ | ||
637 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | 1188 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, |
638 | struct v4l2_rect *rect) | 1189 | struct v4l2_crop *a) |
639 | { | 1190 | { |
640 | return icd->ops->set_crop(icd, rect); | 1191 | struct v4l2_rect *rect = &a->c; |
1192 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1193 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1194 | struct v4l2_crop cam_crop; | ||
1195 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1196 | struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect; | ||
1197 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1198 | struct device *dev = icd->dev.parent; | ||
1199 | struct v4l2_format f; | ||
1200 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
1201 | unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v, | ||
1202 | out_width, out_height; | ||
1203 | u32 capsr, cflcr; | ||
1204 | int ret; | ||
1205 | |||
1206 | /* 1. Calculate current combined scales. */ | ||
1207 | ret = get_scales(icd, &scale_comb_h, &scale_comb_v); | ||
1208 | if (ret < 0) | ||
1209 | return ret; | ||
1210 | |||
1211 | dev_geo(dev, "1: combined scales %u:%u\n", scale_comb_h, scale_comb_v); | ||
1212 | |||
1213 | /* 2. Apply iterative camera S_CROP for new input window. */ | ||
1214 | ret = client_s_crop(sd, a, &cam_crop); | ||
1215 | if (ret < 0) | ||
1216 | return ret; | ||
1217 | |||
1218 | dev_geo(dev, "2: camera cropped to %ux%u@%u:%u\n", | ||
1219 | cam_rect->width, cam_rect->height, | ||
1220 | cam_rect->left, cam_rect->top); | ||
1221 | |||
1222 | /* On success cam_crop contains current camera crop */ | ||
1223 | |||
1224 | /* | ||
1225 | * 3. If old combined scales applied to new crop produce an impossible | ||
1226 | * user window, adjust scales to produce nearest possible window. | ||
1227 | */ | ||
1228 | out_width = scale_down(rect->width, scale_comb_h); | ||
1229 | out_height = scale_down(rect->height, scale_comb_v); | ||
1230 | |||
1231 | if (out_width > 2560) | ||
1232 | out_width = 2560; | ||
1233 | else if (out_width < 2) | ||
1234 | out_width = 2; | ||
1235 | |||
1236 | if (out_height > 1920) | ||
1237 | out_height = 1920; | ||
1238 | else if (out_height < 4) | ||
1239 | out_height = 4; | ||
1240 | |||
1241 | dev_geo(dev, "3: Adjusted output %ux%u\n", out_width, out_height); | ||
1242 | |||
1243 | /* 4. Use G_CROP to retrieve actual input window: already in cam_crop */ | ||
1244 | |||
1245 | /* | ||
1246 | * 5. Using actual input window and calculated combined scales calculate | ||
1247 | * camera target output window. | ||
1248 | */ | ||
1249 | pix->width = scale_down(cam_rect->width, scale_comb_h); | ||
1250 | pix->height = scale_down(cam_rect->height, scale_comb_v); | ||
1251 | |||
1252 | dev_geo(dev, "5: camera target %ux%u\n", pix->width, pix->height); | ||
1253 | |||
1254 | /* 6. - 9. */ | ||
1255 | pix->pixelformat = cam->camera_fmt->fourcc; | ||
1256 | pix->colorspace = cam->camera_fmt->colorspace; | ||
1257 | |||
1258 | capsr = capture_save_reset(pcdev); | ||
1259 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); | ||
1260 | |||
1261 | /* Make relative to camera rectangle */ | ||
1262 | rect->left -= cam_rect->left; | ||
1263 | rect->top -= cam_rect->top; | ||
1264 | |||
1265 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1266 | |||
1267 | ret = client_scale(icd, cam_rect, rect, ceu_rect, &f, | ||
1268 | pcdev->image_mode && !pcdev->is_interlaced); | ||
1269 | |||
1270 | dev_geo(dev, "6-9: %d\n", ret); | ||
1271 | |||
1272 | /* 10. Use CEU cropping to crop to the new window. */ | ||
1273 | sh_mobile_ceu_set_rect(icd, out_width, out_height); | ||
1274 | |||
1275 | dev_geo(dev, "10: CEU cropped to %ux%u@%u:%u\n", | ||
1276 | ceu_rect->width, ceu_rect->height, | ||
1277 | ceu_rect->left, ceu_rect->top); | ||
1278 | |||
1279 | /* | ||
1280 | * 11. Calculate CEU scales from camera scales from results of (10) and | ||
1281 | * user window from (3) | ||
1282 | */ | ||
1283 | scale_ceu_h = calc_scale(ceu_rect->width, &out_width); | ||
1284 | scale_ceu_v = calc_scale(ceu_rect->height, &out_height); | ||
1285 | |||
1286 | dev_geo(dev, "11: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v); | ||
1287 | |||
1288 | /* 12. Apply CEU scales. */ | ||
1289 | cflcr = scale_ceu_h | (scale_ceu_v << 16); | ||
1290 | if (cflcr != pcdev->cflcr) { | ||
1291 | pcdev->cflcr = cflcr; | ||
1292 | ceu_write(pcdev, CFLCR, cflcr); | ||
1293 | } | ||
1294 | |||
1295 | /* Restore capture */ | ||
1296 | if (pcdev->active) | ||
1297 | capsr |= 1; | ||
1298 | capture_restore(pcdev, capsr); | ||
1299 | |||
1300 | icd->user_width = out_width; | ||
1301 | icd->user_height = out_height; | ||
1302 | |||
1303 | /* Even if only camera cropping succeeded */ | ||
1304 | return ret; | ||
641 | } | 1305 | } |
642 | 1306 | ||
1307 | /* Similar to set_crop multistage iterative algorithm */ | ||
643 | static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | 1308 | static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, |
644 | struct v4l2_format *f) | 1309 | struct v4l2_format *f) |
645 | { | 1310 | { |
646 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1311 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
647 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 1312 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
648 | __u32 pixfmt = f->fmt.pix.pixelformat; | 1313 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
649 | const struct soc_camera_format_xlate *xlate; | 1314 | struct v4l2_pix_format *pix = &f->fmt.pix; |
650 | struct v4l2_format cam_f = *f; | 1315 | struct v4l2_format cam_f = *f; |
1316 | struct v4l2_pix_format *cam_pix = &cam_f.fmt.pix; | ||
1317 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1318 | struct device *dev = icd->dev.parent; | ||
1319 | __u32 pixfmt = pix->pixelformat; | ||
1320 | const struct soc_camera_format_xlate *xlate; | ||
1321 | struct v4l2_crop cam_crop; | ||
1322 | struct v4l2_rect *cam_rect = &cam_crop.c, cam_subrect, ceu_rect; | ||
1323 | unsigned int scale_cam_h, scale_cam_v; | ||
1324 | u16 scale_v, scale_h; | ||
651 | int ret; | 1325 | int ret; |
1326 | bool is_interlaced, image_mode; | ||
1327 | |||
1328 | switch (pix->field) { | ||
1329 | case V4L2_FIELD_INTERLACED: | ||
1330 | is_interlaced = true; | ||
1331 | break; | ||
1332 | case V4L2_FIELD_ANY: | ||
1333 | default: | ||
1334 | pix->field = V4L2_FIELD_NONE; | ||
1335 | /* fall-through */ | ||
1336 | case V4L2_FIELD_NONE: | ||
1337 | is_interlaced = false; | ||
1338 | break; | ||
1339 | } | ||
652 | 1340 | ||
653 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1341 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
654 | if (!xlate) { | 1342 | if (!xlate) { |
655 | dev_warn(ici->dev, "Format %x not found\n", pixfmt); | 1343 | dev_warn(dev, "Format %x not found\n", pixfmt); |
656 | return -EINVAL; | 1344 | return -EINVAL; |
657 | } | 1345 | } |
658 | 1346 | ||
659 | cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc; | 1347 | /* 1. Calculate current camera scales. */ |
660 | ret = icd->ops->set_fmt(icd, &cam_f); | 1348 | cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
661 | 1349 | ||
662 | if (!ret) { | 1350 | ret = client_g_rect(sd, cam_rect); |
663 | icd->buswidth = xlate->buswidth; | 1351 | if (ret < 0) |
664 | icd->current_fmt = xlate->host_fmt; | 1352 | return ret; |
665 | pcdev->camera_fmt = xlate->cam_fmt; | 1353 | |
1354 | ret = get_camera_scales(sd, cam_rect, &scale_cam_h, &scale_cam_v); | ||
1355 | if (ret < 0) | ||
1356 | return ret; | ||
1357 | |||
1358 | dev_geo(dev, "1: camera scales %u:%u\n", scale_cam_h, scale_cam_v); | ||
1359 | |||
1360 | /* | ||
1361 | * 2. Calculate "effective" input crop (sensor subwindow) - CEU crop | ||
1362 | * scaled back at current camera scales onto input window. | ||
1363 | */ | ||
1364 | ret = get_camera_subwin(icd, &cam_subrect, scale_cam_h, scale_cam_v); | ||
1365 | if (ret < 0) | ||
1366 | return ret; | ||
1367 | |||
1368 | dev_geo(dev, "2: subwin %ux%u@%u:%u\n", | ||
1369 | cam_subrect.width, cam_subrect.height, | ||
1370 | cam_subrect.left, cam_subrect.top); | ||
1371 | |||
1372 | /* | ||
1373 | * 3. Calculate new combined scales from "effective" input window to | ||
1374 | * requested user window. | ||
1375 | */ | ||
1376 | scale_h = calc_generic_scale(cam_subrect.width, pix->width); | ||
1377 | scale_v = calc_generic_scale(cam_subrect.height, pix->height); | ||
1378 | |||
1379 | dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); | ||
1380 | |||
1381 | /* | ||
1382 | * 4. Calculate camera output window by applying combined scales to real | ||
1383 | * input window. | ||
1384 | */ | ||
1385 | cam_pix->width = scale_down(cam_rect->width, scale_h); | ||
1386 | cam_pix->height = scale_down(cam_rect->height, scale_v); | ||
1387 | cam_pix->pixelformat = xlate->cam_fmt->fourcc; | ||
1388 | |||
1389 | switch (pixfmt) { | ||
1390 | case V4L2_PIX_FMT_NV12: | ||
1391 | case V4L2_PIX_FMT_NV21: | ||
1392 | case V4L2_PIX_FMT_NV16: | ||
1393 | case V4L2_PIX_FMT_NV61: | ||
1394 | image_mode = true; | ||
1395 | break; | ||
1396 | default: | ||
1397 | image_mode = false; | ||
666 | } | 1398 | } |
667 | 1399 | ||
668 | return ret; | 1400 | dev_geo(dev, "4: camera output %ux%u\n", |
1401 | cam_pix->width, cam_pix->height); | ||
1402 | |||
1403 | /* 5. - 9. */ | ||
1404 | ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &cam_f, | ||
1405 | image_mode && !is_interlaced); | ||
1406 | |||
1407 | dev_geo(dev, "5-9: client scale %d\n", ret); | ||
1408 | |||
1409 | /* Done with the camera. Now see if we can improve the result */ | ||
1410 | |||
1411 | dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n", | ||
1412 | ret, cam_pix->width, cam_pix->height, pix->width, pix->height); | ||
1413 | if (ret < 0) | ||
1414 | return ret; | ||
1415 | |||
1416 | /* 10. Use CEU scaling to scale to the requested user window. */ | ||
1417 | |||
1418 | /* We cannot scale up */ | ||
1419 | if (pix->width > cam_pix->width) | ||
1420 | pix->width = cam_pix->width; | ||
1421 | if (pix->width > ceu_rect.width) | ||
1422 | pix->width = ceu_rect.width; | ||
1423 | |||
1424 | if (pix->height > cam_pix->height) | ||
1425 | pix->height = cam_pix->height; | ||
1426 | if (pix->height > ceu_rect.height) | ||
1427 | pix->height = ceu_rect.height; | ||
1428 | |||
1429 | /* Let's rock: scale pix->{width x height} down to width x height */ | ||
1430 | scale_h = calc_scale(ceu_rect.width, &pix->width); | ||
1431 | scale_v = calc_scale(ceu_rect.height, &pix->height); | ||
1432 | |||
1433 | dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", | ||
1434 | ceu_rect.width, scale_h, pix->width, | ||
1435 | ceu_rect.height, scale_v, pix->height); | ||
1436 | |||
1437 | pcdev->cflcr = scale_h | (scale_v << 16); | ||
1438 | |||
1439 | icd->buswidth = xlate->buswidth; | ||
1440 | icd->current_fmt = xlate->host_fmt; | ||
1441 | cam->camera_fmt = xlate->cam_fmt; | ||
1442 | cam->ceu_rect = ceu_rect; | ||
1443 | |||
1444 | pcdev->is_interlaced = is_interlaced; | ||
1445 | pcdev->image_mode = image_mode; | ||
1446 | |||
1447 | return 0; | ||
669 | } | 1448 | } |
670 | 1449 | ||
671 | static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | 1450 | static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, |
672 | struct v4l2_format *f) | 1451 | struct v4l2_format *f) |
673 | { | 1452 | { |
674 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
675 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
676 | const struct soc_camera_format_xlate *xlate; | 1453 | const struct soc_camera_format_xlate *xlate; |
677 | __u32 pixfmt = f->fmt.pix.pixelformat; | 1454 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1455 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1456 | __u32 pixfmt = pix->pixelformat; | ||
1457 | int width, height; | ||
678 | int ret; | 1458 | int ret; |
679 | 1459 | ||
680 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1460 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
681 | if (!xlate) { | 1461 | if (!xlate) { |
682 | dev_warn(ici->dev, "Format %x not found\n", pixfmt); | 1462 | dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); |
683 | return -EINVAL; | 1463 | return -EINVAL; |
684 | } | 1464 | } |
685 | 1465 | ||
686 | /* FIXME: calculate using depth and bus width */ | 1466 | /* FIXME: calculate using depth and bus width */ |
687 | 1467 | ||
688 | v4l_bound_align_image(&f->fmt.pix.width, 2, 2560, 1, | 1468 | v4l_bound_align_image(&pix->width, 2, 2560, 1, |
689 | &f->fmt.pix.height, 4, 1920, 2, 0); | 1469 | &pix->height, 4, 1920, 2, 0); |
1470 | |||
1471 | width = pix->width; | ||
1472 | height = pix->height; | ||
690 | 1473 | ||
691 | f->fmt.pix.bytesperline = f->fmt.pix.width * | 1474 | pix->bytesperline = pix->width * |
692 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); | 1475 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); |
693 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | 1476 | pix->sizeimage = pix->height * pix->bytesperline; |
1477 | |||
1478 | pix->pixelformat = xlate->cam_fmt->fourcc; | ||
694 | 1479 | ||
695 | /* limit to sensor capabilities */ | 1480 | /* limit to sensor capabilities */ |
696 | ret = icd->ops->try_fmt(icd, f); | 1481 | ret = v4l2_subdev_call(sd, video, try_fmt, f); |
1482 | pix->pixelformat = pixfmt; | ||
697 | if (ret < 0) | 1483 | if (ret < 0) |
698 | return ret; | 1484 | return ret; |
699 | 1485 | ||
700 | switch (f->fmt.pix.field) { | 1486 | switch (pixfmt) { |
701 | case V4L2_FIELD_INTERLACED: | 1487 | case V4L2_PIX_FMT_NV12: |
702 | pcdev->is_interlaced = 1; | 1488 | case V4L2_PIX_FMT_NV21: |
703 | break; | 1489 | case V4L2_PIX_FMT_NV16: |
704 | case V4L2_FIELD_ANY: | 1490 | case V4L2_PIX_FMT_NV61: |
705 | f->fmt.pix.field = V4L2_FIELD_NONE; | 1491 | /* FIXME: check against rect_max after converting soc-camera */ |
706 | /* fall-through */ | 1492 | /* We can scale precisely, need a bigger image from camera */ |
707 | case V4L2_FIELD_NONE: | 1493 | if (pix->width < width || pix->height < height) { |
708 | pcdev->is_interlaced = 0; | 1494 | int tmp_w = pix->width, tmp_h = pix->height; |
709 | break; | 1495 | pix->width = 2560; |
710 | default: | 1496 | pix->height = 1920; |
711 | ret = -EINVAL; | 1497 | ret = v4l2_subdev_call(sd, video, try_fmt, f); |
712 | break; | 1498 | if (ret < 0) { |
1499 | /* Shouldn't actually happen... */ | ||
1500 | dev_err(icd->dev.parent, | ||
1501 | "FIXME: try_fmt() returned %d\n", ret); | ||
1502 | pix->width = tmp_w; | ||
1503 | pix->height = tmp_h; | ||
1504 | } | ||
1505 | } | ||
1506 | if (pix->width > width) | ||
1507 | pix->width = width; | ||
1508 | if (pix->height > height) | ||
1509 | pix->height = height; | ||
713 | } | 1510 | } |
714 | 1511 | ||
715 | return ret; | 1512 | return ret; |
@@ -769,7 +1566,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, | |||
769 | 1566 | ||
770 | videobuf_queue_dma_contig_init(q, | 1567 | videobuf_queue_dma_contig_init(q, |
771 | &sh_mobile_ceu_videobuf_ops, | 1568 | &sh_mobile_ceu_videobuf_ops, |
772 | ici->dev, &pcdev->lock, | 1569 | icd->dev.parent, &pcdev->lock, |
773 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 1570 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
774 | pcdev->is_interlaced ? | 1571 | pcdev->is_interlaced ? |
775 | V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, | 1572 | V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, |
@@ -777,22 +1574,76 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, | |||
777 | icd); | 1574 | icd); |
778 | } | 1575 | } |
779 | 1576 | ||
1577 | static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd, | ||
1578 | struct v4l2_control *ctrl) | ||
1579 | { | ||
1580 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1581 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1582 | u32 val; | ||
1583 | |||
1584 | switch (ctrl->id) { | ||
1585 | case V4L2_CID_SHARPNESS: | ||
1586 | val = ceu_read(pcdev, CLFCR); | ||
1587 | ctrl->value = val ^ 1; | ||
1588 | return 0; | ||
1589 | } | ||
1590 | return -ENOIOCTLCMD; | ||
1591 | } | ||
1592 | |||
1593 | static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, | ||
1594 | struct v4l2_control *ctrl) | ||
1595 | { | ||
1596 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1597 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1598 | |||
1599 | switch (ctrl->id) { | ||
1600 | case V4L2_CID_SHARPNESS: | ||
1601 | switch (icd->current_fmt->fourcc) { | ||
1602 | case V4L2_PIX_FMT_NV12: | ||
1603 | case V4L2_PIX_FMT_NV21: | ||
1604 | case V4L2_PIX_FMT_NV16: | ||
1605 | case V4L2_PIX_FMT_NV61: | ||
1606 | ceu_write(pcdev, CLFCR, !ctrl->value); | ||
1607 | return 0; | ||
1608 | } | ||
1609 | return -EINVAL; | ||
1610 | } | ||
1611 | return -ENOIOCTLCMD; | ||
1612 | } | ||
1613 | |||
1614 | static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = { | ||
1615 | { | ||
1616 | .id = V4L2_CID_SHARPNESS, | ||
1617 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1618 | .name = "Low-pass filter", | ||
1619 | .minimum = 0, | ||
1620 | .maximum = 1, | ||
1621 | .step = 1, | ||
1622 | .default_value = 0, | ||
1623 | }, | ||
1624 | }; | ||
1625 | |||
780 | static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | 1626 | static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { |
781 | .owner = THIS_MODULE, | 1627 | .owner = THIS_MODULE, |
782 | .add = sh_mobile_ceu_add_device, | 1628 | .add = sh_mobile_ceu_add_device, |
783 | .remove = sh_mobile_ceu_remove_device, | 1629 | .remove = sh_mobile_ceu_remove_device, |
784 | .get_formats = sh_mobile_ceu_get_formats, | 1630 | .get_formats = sh_mobile_ceu_get_formats, |
1631 | .put_formats = sh_mobile_ceu_put_formats, | ||
785 | .set_crop = sh_mobile_ceu_set_crop, | 1632 | .set_crop = sh_mobile_ceu_set_crop, |
786 | .set_fmt = sh_mobile_ceu_set_fmt, | 1633 | .set_fmt = sh_mobile_ceu_set_fmt, |
787 | .try_fmt = sh_mobile_ceu_try_fmt, | 1634 | .try_fmt = sh_mobile_ceu_try_fmt, |
1635 | .set_ctrl = sh_mobile_ceu_set_ctrl, | ||
1636 | .get_ctrl = sh_mobile_ceu_get_ctrl, | ||
788 | .reqbufs = sh_mobile_ceu_reqbufs, | 1637 | .reqbufs = sh_mobile_ceu_reqbufs, |
789 | .poll = sh_mobile_ceu_poll, | 1638 | .poll = sh_mobile_ceu_poll, |
790 | .querycap = sh_mobile_ceu_querycap, | 1639 | .querycap = sh_mobile_ceu_querycap, |
791 | .set_bus_param = sh_mobile_ceu_set_bus_param, | 1640 | .set_bus_param = sh_mobile_ceu_set_bus_param, |
792 | .init_videobuf = sh_mobile_ceu_init_videobuf, | 1641 | .init_videobuf = sh_mobile_ceu_init_videobuf, |
1642 | .controls = sh_mobile_ceu_controls, | ||
1643 | .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), | ||
793 | }; | 1644 | }; |
794 | 1645 | ||
795 | static int sh_mobile_ceu_probe(struct platform_device *pdev) | 1646 | static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) |
796 | { | 1647 | { |
797 | struct sh_mobile_ceu_dev *pcdev; | 1648 | struct sh_mobile_ceu_dev *pcdev; |
798 | struct resource *res; | 1649 | struct resource *res; |
@@ -865,7 +1716,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) | |||
865 | pm_runtime_resume(&pdev->dev); | 1716 | pm_runtime_resume(&pdev->dev); |
866 | 1717 | ||
867 | pcdev->ici.priv = pcdev; | 1718 | pcdev->ici.priv = pcdev; |
868 | pcdev->ici.dev = &pdev->dev; | 1719 | pcdev->ici.v4l2_dev.dev = &pdev->dev; |
869 | pcdev->ici.nr = pdev->id; | 1720 | pcdev->ici.nr = pdev->id; |
870 | pcdev->ici.drv_name = dev_name(&pdev->dev); | 1721 | pcdev->ici.drv_name = dev_name(&pdev->dev); |
871 | pcdev->ici.ops = &sh_mobile_ceu_host_ops; | 1722 | pcdev->ici.ops = &sh_mobile_ceu_host_ops; |
@@ -889,7 +1740,7 @@ exit: | |||
889 | return err; | 1740 | return err; |
890 | } | 1741 | } |
891 | 1742 | ||
892 | static int sh_mobile_ceu_remove(struct platform_device *pdev) | 1743 | static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev) |
893 | { | 1744 | { |
894 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | 1745 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); |
895 | struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, | 1746 | struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, |
@@ -927,7 +1778,7 @@ static struct platform_driver sh_mobile_ceu_driver = { | |||
927 | .pm = &sh_mobile_ceu_dev_pm_ops, | 1778 | .pm = &sh_mobile_ceu_dev_pm_ops, |
928 | }, | 1779 | }, |
929 | .probe = sh_mobile_ceu_probe, | 1780 | .probe = sh_mobile_ceu_probe, |
930 | .remove = sh_mobile_ceu_remove, | 1781 | .remove = __exit_p(sh_mobile_ceu_remove), |
931 | }; | 1782 | }; |
932 | 1783 | ||
933 | static int __init sh_mobile_ceu_init(void) | 1784 | static int __init sh_mobile_ceu_init(void) |
@@ -946,3 +1797,4 @@ module_exit(sh_mobile_ceu_exit); | |||
946 | MODULE_DESCRIPTION("SuperH Mobile CEU driver"); | 1797 | MODULE_DESCRIPTION("SuperH Mobile CEU driver"); |
947 | MODULE_AUTHOR("Magnus Damm"); | 1798 | MODULE_AUTHOR("Magnus Damm"); |
948 | MODULE_LICENSE("GPL"); | 1799 | MODULE_LICENSE("GPL"); |
1800 | MODULE_ALIAS("platform:sh_mobile_ceu"); | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 23edfdc4d4bc..9d84c94e8a40 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c | |||
@@ -1954,8 +1954,10 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
1954 | (!list_empty(&cam->outqueue)) || | 1954 | (!list_empty(&cam->outqueue)) || |
1955 | (cam->state & DEV_DISCONNECTED) || | 1955 | (cam->state & DEV_DISCONNECTED) || |
1956 | (cam->state & DEV_MISCONFIGURED), | 1956 | (cam->state & DEV_MISCONFIGURED), |
1957 | cam->module_param.frame_timeout * | 1957 | msecs_to_jiffies( |
1958 | 1000 * msecs_to_jiffies(1) ); | 1958 | cam->module_param.frame_timeout * 1000 |
1959 | ) | ||
1960 | ); | ||
1959 | if (timeout < 0) { | 1961 | if (timeout < 0) { |
1960 | mutex_unlock(&cam->fileop_mutex); | 1962 | mutex_unlock(&cam->fileop_mutex); |
1961 | return timeout; | 1963 | return timeout; |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 9f5ae8167855..59aa7a3694c2 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -21,15 +21,15 @@ | |||
21 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/module.h> | ||
25 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/module.h> | ||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | 28 | ||
29 | #include <media/soc_camera.h> | 29 | #include <media/soc_camera.h> |
30 | #include <media/v4l2-common.h> | 30 | #include <media/v4l2-common.h> |
31 | #include <media/v4l2-dev.h> | ||
32 | #include <media/v4l2-ioctl.h> | 31 | #include <media/v4l2-ioctl.h> |
32 | #include <media/v4l2-dev.h> | ||
33 | #include <media/videobuf-core.h> | 33 | #include <media/videobuf-core.h> |
34 | 34 | ||
35 | /* Default to VGA resolution */ | 35 | /* Default to VGA resolution */ |
@@ -38,7 +38,7 @@ | |||
38 | 38 | ||
39 | static LIST_HEAD(hosts); | 39 | static LIST_HEAD(hosts); |
40 | static LIST_HEAD(devices); | 40 | static LIST_HEAD(devices); |
41 | static DEFINE_MUTEX(list_lock); | 41 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
42 | 42 | ||
43 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( | 43 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( |
44 | struct soc_camera_device *icd, unsigned int fourcc) | 44 | struct soc_camera_device *icd, unsigned int fourcc) |
@@ -152,12 +152,9 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) | |||
152 | { | 152 | { |
153 | struct soc_camera_file *icf = file->private_data; | 153 | struct soc_camera_file *icf = file->private_data; |
154 | struct soc_camera_device *icd = icf->icd; | 154 | struct soc_camera_device *icd = icf->icd; |
155 | int ret = 0; | 155 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
156 | |||
157 | if (icd->ops->set_std) | ||
158 | ret = icd->ops->set_std(icd, a); | ||
159 | 156 | ||
160 | return ret; | 157 | return v4l2_subdev_call(sd, core, s_std, *a); |
161 | } | 158 | } |
162 | 159 | ||
163 | static int soc_camera_reqbufs(struct file *file, void *priv, | 160 | static int soc_camera_reqbufs(struct file *file, void *priv, |
@@ -170,8 +167,6 @@ static int soc_camera_reqbufs(struct file *file, void *priv, | |||
170 | 167 | ||
171 | WARN_ON(priv != file->private_data); | 168 | WARN_ON(priv != file->private_data); |
172 | 169 | ||
173 | dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory); | ||
174 | |||
175 | ret = videobuf_reqbufs(&icf->vb_vidq, p); | 170 | ret = videobuf_reqbufs(&icf->vb_vidq, p); |
176 | if (ret < 0) | 171 | if (ret < 0) |
177 | return ret; | 172 | return ret; |
@@ -209,10 +204,11 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
209 | return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); | 204 | return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); |
210 | } | 205 | } |
211 | 206 | ||
207 | /* Always entered with .video_lock held */ | ||
212 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | 208 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
213 | { | 209 | { |
214 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 210 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
215 | int i, fmts = 0; | 211 | int i, fmts = 0, ret; |
216 | 212 | ||
217 | if (!ici->ops->get_formats) | 213 | if (!ici->ops->get_formats) |
218 | /* | 214 | /* |
@@ -225,8 +221,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
225 | * First pass - only count formats this host-sensor | 221 | * First pass - only count formats this host-sensor |
226 | * configuration can provide | 222 | * configuration can provide |
227 | */ | 223 | */ |
228 | for (i = 0; i < icd->num_formats; i++) | 224 | for (i = 0; i < icd->num_formats; i++) { |
229 | fmts += ici->ops->get_formats(icd, i, NULL); | 225 | ret = ici->ops->get_formats(icd, i, NULL); |
226 | if (ret < 0) | ||
227 | return ret; | ||
228 | fmts += ret; | ||
229 | } | ||
230 | 230 | ||
231 | if (!fmts) | 231 | if (!fmts) |
232 | return -ENXIO; | 232 | return -ENXIO; |
@@ -248,20 +248,39 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
248 | icd->user_formats[i].cam_fmt = icd->formats + i; | 248 | icd->user_formats[i].cam_fmt = icd->formats + i; |
249 | icd->user_formats[i].buswidth = icd->formats[i].depth; | 249 | icd->user_formats[i].buswidth = icd->formats[i].depth; |
250 | } else { | 250 | } else { |
251 | fmts += ici->ops->get_formats(icd, i, | 251 | ret = ici->ops->get_formats(icd, i, |
252 | &icd->user_formats[fmts]); | 252 | &icd->user_formats[fmts]); |
253 | if (ret < 0) | ||
254 | goto egfmt; | ||
255 | fmts += ret; | ||
253 | } | 256 | } |
254 | 257 | ||
255 | icd->current_fmt = icd->user_formats[0].host_fmt; | 258 | icd->current_fmt = icd->user_formats[0].host_fmt; |
256 | 259 | ||
257 | return 0; | 260 | return 0; |
261 | |||
262 | egfmt: | ||
263 | icd->num_user_formats = 0; | ||
264 | vfree(icd->user_formats); | ||
265 | return ret; | ||
258 | } | 266 | } |
259 | 267 | ||
268 | /* Always entered with .video_lock held */ | ||
260 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) | 269 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) |
261 | { | 270 | { |
271 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
272 | |||
273 | if (ici->ops->put_formats) | ||
274 | ici->ops->put_formats(icd); | ||
275 | icd->current_fmt = NULL; | ||
276 | icd->num_user_formats = 0; | ||
262 | vfree(icd->user_formats); | 277 | vfree(icd->user_formats); |
278 | icd->user_formats = NULL; | ||
263 | } | 279 | } |
264 | 280 | ||
281 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ | ||
282 | ((x) >> 24) & 0xff | ||
283 | |||
265 | /* Called with .vb_lock held */ | 284 | /* Called with .vb_lock held */ |
266 | static int soc_camera_set_fmt(struct soc_camera_file *icf, | 285 | static int soc_camera_set_fmt(struct soc_camera_file *icf, |
267 | struct v4l2_format *f) | 286 | struct v4l2_format *f) |
@@ -271,6 +290,9 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
271 | struct v4l2_pix_format *pix = &f->fmt.pix; | 290 | struct v4l2_pix_format *pix = &f->fmt.pix; |
272 | int ret; | 291 | int ret; |
273 | 292 | ||
293 | dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n", | ||
294 | pixfmtstr(pix->pixelformat), pix->width, pix->height); | ||
295 | |||
274 | /* We always call try_fmt() before set_fmt() or set_crop() */ | 296 | /* We always call try_fmt() before set_fmt() or set_crop() */ |
275 | ret = ici->ops->try_fmt(icd, f); | 297 | ret = ici->ops->try_fmt(icd, f); |
276 | if (ret < 0) | 298 | if (ret < 0) |
@@ -281,13 +303,13 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
281 | return ret; | 303 | return ret; |
282 | } else if (!icd->current_fmt || | 304 | } else if (!icd->current_fmt || |
283 | icd->current_fmt->fourcc != pix->pixelformat) { | 305 | icd->current_fmt->fourcc != pix->pixelformat) { |
284 | dev_err(ici->dev, | 306 | dev_err(&icd->dev, |
285 | "Host driver hasn't set up current format correctly!\n"); | 307 | "Host driver hasn't set up current format correctly!\n"); |
286 | return -EINVAL; | 308 | return -EINVAL; |
287 | } | 309 | } |
288 | 310 | ||
289 | icd->width = pix->width; | 311 | icd->user_width = pix->width; |
290 | icd->height = pix->height; | 312 | icd->user_height = pix->height; |
291 | icf->vb_vidq.field = | 313 | icf->vb_vidq.field = |
292 | icd->field = pix->field; | 314 | icd->field = pix->field; |
293 | 315 | ||
@@ -296,7 +318,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
296 | f->type); | 318 | f->type); |
297 | 319 | ||
298 | dev_dbg(&icd->dev, "set width: %d height: %d\n", | 320 | dev_dbg(&icd->dev, "set width: %d height: %d\n", |
299 | icd->width, icd->height); | 321 | icd->user_width, icd->user_height); |
300 | 322 | ||
301 | /* set physical bus parameters */ | 323 | /* set physical bus parameters */ |
302 | return ici->ops->set_bus_param(icd, pix->pixelformat); | 324 | return ici->ops->set_bus_param(icd, pix->pixelformat); |
@@ -304,30 +326,24 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
304 | 326 | ||
305 | static int soc_camera_open(struct file *file) | 327 | static int soc_camera_open(struct file *file) |
306 | { | 328 | { |
307 | struct video_device *vdev; | 329 | struct video_device *vdev = video_devdata(file); |
308 | struct soc_camera_device *icd; | 330 | struct soc_camera_device *icd = container_of(vdev->parent, |
331 | struct soc_camera_device, | ||
332 | dev); | ||
333 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
309 | struct soc_camera_host *ici; | 334 | struct soc_camera_host *ici; |
310 | struct soc_camera_file *icf; | 335 | struct soc_camera_file *icf; |
311 | int ret; | 336 | int ret; |
312 | 337 | ||
313 | icf = vmalloc(sizeof(*icf)); | 338 | if (!icd->ops) |
314 | if (!icf) | 339 | /* No device driver attached */ |
315 | return -ENOMEM; | 340 | return -ENODEV; |
316 | |||
317 | /* | ||
318 | * It is safe to dereference these pointers now as long as a user has | ||
319 | * the video device open - we are protected by the held cdev reference. | ||
320 | */ | ||
321 | 341 | ||
322 | vdev = video_devdata(file); | ||
323 | icd = container_of(vdev->parent, struct soc_camera_device, dev); | ||
324 | ici = to_soc_camera_host(icd->dev.parent); | 342 | ici = to_soc_camera_host(icd->dev.parent); |
325 | 343 | ||
326 | if (!try_module_get(icd->ops->owner)) { | 344 | icf = vmalloc(sizeof(*icf)); |
327 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); | 345 | if (!icf) |
328 | ret = -EINVAL; | 346 | return -ENOMEM; |
329 | goto emgd; | ||
330 | } | ||
331 | 347 | ||
332 | if (!try_module_get(ici->ops->owner)) { | 348 | if (!try_module_get(ici->ops->owner)) { |
333 | dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); | 349 | dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); |
@@ -335,7 +351,10 @@ static int soc_camera_open(struct file *file) | |||
335 | goto emgi; | 351 | goto emgi; |
336 | } | 352 | } |
337 | 353 | ||
338 | /* Protect against icd->remove() until we module_get() both drivers. */ | 354 | /* |
355 | * Protect against icd->ops->remove() until we module_get() both | ||
356 | * drivers. | ||
357 | */ | ||
339 | mutex_lock(&icd->video_lock); | 358 | mutex_lock(&icd->video_lock); |
340 | 359 | ||
341 | icf->icd = icd; | 360 | icf->icd = icd; |
@@ -347,14 +366,24 @@ static int soc_camera_open(struct file *file) | |||
347 | struct v4l2_format f = { | 366 | struct v4l2_format f = { |
348 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | 367 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, |
349 | .fmt.pix = { | 368 | .fmt.pix = { |
350 | .width = icd->width, | 369 | .width = icd->user_width, |
351 | .height = icd->height, | 370 | .height = icd->user_height, |
352 | .field = icd->field, | 371 | .field = icd->field, |
353 | .pixelformat = icd->current_fmt->fourcc, | 372 | .pixelformat = icd->current_fmt->fourcc, |
354 | .colorspace = icd->current_fmt->colorspace, | 373 | .colorspace = icd->current_fmt->colorspace, |
355 | }, | 374 | }, |
356 | }; | 375 | }; |
357 | 376 | ||
377 | if (icl->power) { | ||
378 | ret = icl->power(icd->pdev, 1); | ||
379 | if (ret < 0) | ||
380 | goto epower; | ||
381 | } | ||
382 | |||
383 | /* The camera could have been already on, try to reset */ | ||
384 | if (icl->reset) | ||
385 | icl->reset(icd->pdev); | ||
386 | |||
358 | ret = ici->ops->add(icd); | 387 | ret = ici->ops->add(icd); |
359 | if (ret < 0) { | 388 | if (ret < 0) { |
360 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); | 389 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); |
@@ -367,28 +396,29 @@ static int soc_camera_open(struct file *file) | |||
367 | goto esfmt; | 396 | goto esfmt; |
368 | } | 397 | } |
369 | 398 | ||
370 | mutex_unlock(&icd->video_lock); | ||
371 | |||
372 | file->private_data = icf; | 399 | file->private_data = icf; |
373 | dev_dbg(&icd->dev, "camera device open\n"); | 400 | dev_dbg(&icd->dev, "camera device open\n"); |
374 | 401 | ||
375 | ici->ops->init_videobuf(&icf->vb_vidq, icd); | 402 | ici->ops->init_videobuf(&icf->vb_vidq, icd); |
376 | 403 | ||
404 | mutex_unlock(&icd->video_lock); | ||
405 | |||
377 | return 0; | 406 | return 0; |
378 | 407 | ||
379 | /* | 408 | /* |
380 | * First three errors are entered with the .video_lock held | 409 | * First five errors are entered with the .video_lock held |
381 | * and use_count == 1 | 410 | * and use_count == 1 |
382 | */ | 411 | */ |
383 | esfmt: | 412 | esfmt: |
384 | ici->ops->remove(icd); | 413 | ici->ops->remove(icd); |
385 | eiciadd: | 414 | eiciadd: |
415 | if (icl->power) | ||
416 | icl->power(icd->pdev, 0); | ||
417 | epower: | ||
386 | icd->use_count--; | 418 | icd->use_count--; |
387 | mutex_unlock(&icd->video_lock); | 419 | mutex_unlock(&icd->video_lock); |
388 | module_put(ici->ops->owner); | 420 | module_put(ici->ops->owner); |
389 | emgi: | 421 | emgi: |
390 | module_put(icd->ops->owner); | ||
391 | emgd: | ||
392 | vfree(icf); | 422 | vfree(icf); |
393 | return ret; | 423 | return ret; |
394 | } | 424 | } |
@@ -398,21 +428,24 @@ static int soc_camera_close(struct file *file) | |||
398 | struct soc_camera_file *icf = file->private_data; | 428 | struct soc_camera_file *icf = file->private_data; |
399 | struct soc_camera_device *icd = icf->icd; | 429 | struct soc_camera_device *icd = icf->icd; |
400 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 430 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
401 | struct video_device *vdev = icd->vdev; | ||
402 | 431 | ||
403 | mutex_lock(&icd->video_lock); | 432 | mutex_lock(&icd->video_lock); |
404 | icd->use_count--; | 433 | icd->use_count--; |
405 | if (!icd->use_count) | 434 | if (!icd->use_count) { |
435 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
436 | |||
406 | ici->ops->remove(icd); | 437 | ici->ops->remove(icd); |
438 | if (icl->power) | ||
439 | icl->power(icd->pdev, 0); | ||
440 | } | ||
407 | 441 | ||
408 | mutex_unlock(&icd->video_lock); | 442 | mutex_unlock(&icd->video_lock); |
409 | 443 | ||
410 | module_put(icd->ops->owner); | ||
411 | module_put(ici->ops->owner); | 444 | module_put(ici->ops->owner); |
412 | 445 | ||
413 | vfree(icf); | 446 | vfree(icf); |
414 | 447 | ||
415 | dev_dbg(vdev->parent, "camera device close\n"); | 448 | dev_dbg(&icd->dev, "camera device close\n"); |
416 | 449 | ||
417 | return 0; | 450 | return 0; |
418 | } | 451 | } |
@@ -422,10 +455,9 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf, | |||
422 | { | 455 | { |
423 | struct soc_camera_file *icf = file->private_data; | 456 | struct soc_camera_file *icf = file->private_data; |
424 | struct soc_camera_device *icd = icf->icd; | 457 | struct soc_camera_device *icd = icf->icd; |
425 | struct video_device *vdev = icd->vdev; | ||
426 | int err = -EINVAL; | 458 | int err = -EINVAL; |
427 | 459 | ||
428 | dev_err(vdev->parent, "camera device read not implemented\n"); | 460 | dev_err(&icd->dev, "camera device read not implemented\n"); |
429 | 461 | ||
430 | return err; | 462 | return err; |
431 | } | 463 | } |
@@ -483,8 +515,8 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
483 | 515 | ||
484 | mutex_lock(&icf->vb_vidq.vb_lock); | 516 | mutex_lock(&icf->vb_vidq.vb_lock); |
485 | 517 | ||
486 | if (videobuf_queue_is_busy(&icf->vb_vidq)) { | 518 | if (icf->vb_vidq.bufs[0]) { |
487 | dev_err(&icd->dev, "S_FMT denied: queue busy\n"); | 519 | dev_err(&icd->dev, "S_FMT denied: queue initialised\n"); |
488 | ret = -EBUSY; | 520 | ret = -EBUSY; |
489 | goto unlock; | 521 | goto unlock; |
490 | } | 522 | } |
@@ -525,8 +557,8 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, | |||
525 | 557 | ||
526 | WARN_ON(priv != file->private_data); | 558 | WARN_ON(priv != file->private_data); |
527 | 559 | ||
528 | pix->width = icd->width; | 560 | pix->width = icd->user_width; |
529 | pix->height = icd->height; | 561 | pix->height = icd->user_height; |
530 | pix->field = icf->vb_vidq.field; | 562 | pix->field = icf->vb_vidq.field; |
531 | pix->pixelformat = icd->current_fmt->fourcc; | 563 | pix->pixelformat = icd->current_fmt->fourcc; |
532 | pix->bytesperline = pix->width * | 564 | pix->bytesperline = pix->width * |
@@ -555,18 +587,17 @@ static int soc_camera_streamon(struct file *file, void *priv, | |||
555 | { | 587 | { |
556 | struct soc_camera_file *icf = file->private_data; | 588 | struct soc_camera_file *icf = file->private_data; |
557 | struct soc_camera_device *icd = icf->icd; | 589 | struct soc_camera_device *icd = icf->icd; |
590 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
558 | int ret; | 591 | int ret; |
559 | 592 | ||
560 | WARN_ON(priv != file->private_data); | 593 | WARN_ON(priv != file->private_data); |
561 | 594 | ||
562 | dev_dbg(&icd->dev, "%s\n", __func__); | ||
563 | |||
564 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 595 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
565 | return -EINVAL; | 596 | return -EINVAL; |
566 | 597 | ||
567 | mutex_lock(&icd->video_lock); | 598 | mutex_lock(&icd->video_lock); |
568 | 599 | ||
569 | icd->ops->start_capture(icd); | 600 | v4l2_subdev_call(sd, video, s_stream, 1); |
570 | 601 | ||
571 | /* This calls buf_queue from host driver's videobuf_queue_ops */ | 602 | /* This calls buf_queue from host driver's videobuf_queue_ops */ |
572 | ret = videobuf_streamon(&icf->vb_vidq); | 603 | ret = videobuf_streamon(&icf->vb_vidq); |
@@ -581,11 +612,10 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
581 | { | 612 | { |
582 | struct soc_camera_file *icf = file->private_data; | 613 | struct soc_camera_file *icf = file->private_data; |
583 | struct soc_camera_device *icd = icf->icd; | 614 | struct soc_camera_device *icd = icf->icd; |
615 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
584 | 616 | ||
585 | WARN_ON(priv != file->private_data); | 617 | WARN_ON(priv != file->private_data); |
586 | 618 | ||
587 | dev_dbg(&icd->dev, "%s\n", __func__); | ||
588 | |||
589 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 619 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
590 | return -EINVAL; | 620 | return -EINVAL; |
591 | 621 | ||
@@ -595,7 +625,7 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
595 | * remaining buffers. When the last buffer is freed, stop capture */ | 625 | * remaining buffers. When the last buffer is freed, stop capture */ |
596 | videobuf_streamoff(&icf->vb_vidq); | 626 | videobuf_streamoff(&icf->vb_vidq); |
597 | 627 | ||
598 | icd->ops->stop_capture(icd); | 628 | v4l2_subdev_call(sd, video, s_stream, 0); |
599 | 629 | ||
600 | mutex_unlock(&icd->video_lock); | 630 | mutex_unlock(&icd->video_lock); |
601 | 631 | ||
@@ -607,6 +637,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv, | |||
607 | { | 637 | { |
608 | struct soc_camera_file *icf = file->private_data; | 638 | struct soc_camera_file *icf = file->private_data; |
609 | struct soc_camera_device *icd = icf->icd; | 639 | struct soc_camera_device *icd = icf->icd; |
640 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
610 | int i; | 641 | int i; |
611 | 642 | ||
612 | WARN_ON(priv != file->private_data); | 643 | WARN_ON(priv != file->private_data); |
@@ -614,6 +645,15 @@ static int soc_camera_queryctrl(struct file *file, void *priv, | |||
614 | if (!qc->id) | 645 | if (!qc->id) |
615 | return -EINVAL; | 646 | return -EINVAL; |
616 | 647 | ||
648 | /* First check host controls */ | ||
649 | for (i = 0; i < ici->ops->num_controls; i++) | ||
650 | if (qc->id == ici->ops->controls[i].id) { | ||
651 | memcpy(qc, &(ici->ops->controls[i]), | ||
652 | sizeof(*qc)); | ||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | /* Then device controls */ | ||
617 | for (i = 0; i < icd->ops->num_controls; i++) | 657 | for (i = 0; i < icd->ops->num_controls; i++) |
618 | if (qc->id == icd->ops->controls[i].id) { | 658 | if (qc->id == icd->ops->controls[i].id) { |
619 | memcpy(qc, &(icd->ops->controls[i]), | 659 | memcpy(qc, &(icd->ops->controls[i]), |
@@ -629,25 +669,19 @@ static int soc_camera_g_ctrl(struct file *file, void *priv, | |||
629 | { | 669 | { |
630 | struct soc_camera_file *icf = file->private_data; | 670 | struct soc_camera_file *icf = file->private_data; |
631 | struct soc_camera_device *icd = icf->icd; | 671 | struct soc_camera_device *icd = icf->icd; |
672 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
673 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
674 | int ret; | ||
632 | 675 | ||
633 | WARN_ON(priv != file->private_data); | 676 | WARN_ON(priv != file->private_data); |
634 | 677 | ||
635 | switch (ctrl->id) { | 678 | if (ici->ops->get_ctrl) { |
636 | case V4L2_CID_GAIN: | 679 | ret = ici->ops->get_ctrl(icd, ctrl); |
637 | if (icd->gain == (unsigned short)~0) | 680 | if (ret != -ENOIOCTLCMD) |
638 | return -EINVAL; | 681 | return ret; |
639 | ctrl->value = icd->gain; | ||
640 | return 0; | ||
641 | case V4L2_CID_EXPOSURE: | ||
642 | if (icd->exposure == (unsigned short)~0) | ||
643 | return -EINVAL; | ||
644 | ctrl->value = icd->exposure; | ||
645 | return 0; | ||
646 | } | 682 | } |
647 | 683 | ||
648 | if (icd->ops->get_control) | 684 | return v4l2_subdev_call(sd, core, g_ctrl, ctrl); |
649 | return icd->ops->get_control(icd, ctrl); | ||
650 | return -EINVAL; | ||
651 | } | 685 | } |
652 | 686 | ||
653 | static int soc_camera_s_ctrl(struct file *file, void *priv, | 687 | static int soc_camera_s_ctrl(struct file *file, void *priv, |
@@ -655,12 +689,19 @@ static int soc_camera_s_ctrl(struct file *file, void *priv, | |||
655 | { | 689 | { |
656 | struct soc_camera_file *icf = file->private_data; | 690 | struct soc_camera_file *icf = file->private_data; |
657 | struct soc_camera_device *icd = icf->icd; | 691 | struct soc_camera_device *icd = icf->icd; |
692 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
693 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
694 | int ret; | ||
658 | 695 | ||
659 | WARN_ON(priv != file->private_data); | 696 | WARN_ON(priv != file->private_data); |
660 | 697 | ||
661 | if (icd->ops->set_control) | 698 | if (ici->ops->set_ctrl) { |
662 | return icd->ops->set_control(icd, ctrl); | 699 | ret = ici->ops->set_ctrl(icd, ctrl); |
663 | return -EINVAL; | 700 | if (ret != -ENOIOCTLCMD) |
701 | return ret; | ||
702 | } | ||
703 | |||
704 | return v4l2_subdev_call(sd, core, s_ctrl, ctrl); | ||
664 | } | 705 | } |
665 | 706 | ||
666 | static int soc_camera_cropcap(struct file *file, void *fh, | 707 | static int soc_camera_cropcap(struct file *file, void *fh, |
@@ -668,20 +709,9 @@ static int soc_camera_cropcap(struct file *file, void *fh, | |||
668 | { | 709 | { |
669 | struct soc_camera_file *icf = file->private_data; | 710 | struct soc_camera_file *icf = file->private_data; |
670 | struct soc_camera_device *icd = icf->icd; | 711 | struct soc_camera_device *icd = icf->icd; |
712 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
671 | 713 | ||
672 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 714 | return ici->ops->cropcap(icd, a); |
673 | a->bounds.left = icd->x_min; | ||
674 | a->bounds.top = icd->y_min; | ||
675 | a->bounds.width = icd->width_max; | ||
676 | a->bounds.height = icd->height_max; | ||
677 | a->defrect.left = icd->x_min; | ||
678 | a->defrect.top = icd->y_min; | ||
679 | a->defrect.width = DEFAULT_WIDTH; | ||
680 | a->defrect.height = DEFAULT_HEIGHT; | ||
681 | a->pixelaspect.numerator = 1; | ||
682 | a->pixelaspect.denominator = 1; | ||
683 | |||
684 | return 0; | ||
685 | } | 715 | } |
686 | 716 | ||
687 | static int soc_camera_g_crop(struct file *file, void *fh, | 717 | static int soc_camera_g_crop(struct file *file, void *fh, |
@@ -689,36 +719,53 @@ static int soc_camera_g_crop(struct file *file, void *fh, | |||
689 | { | 719 | { |
690 | struct soc_camera_file *icf = file->private_data; | 720 | struct soc_camera_file *icf = file->private_data; |
691 | struct soc_camera_device *icd = icf->icd; | 721 | struct soc_camera_device *icd = icf->icd; |
722 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
723 | int ret; | ||
692 | 724 | ||
693 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 725 | mutex_lock(&icf->vb_vidq.vb_lock); |
694 | a->c.left = icd->x_current; | 726 | ret = ici->ops->get_crop(icd, a); |
695 | a->c.top = icd->y_current; | 727 | mutex_unlock(&icf->vb_vidq.vb_lock); |
696 | a->c.width = icd->width; | ||
697 | a->c.height = icd->height; | ||
698 | 728 | ||
699 | return 0; | 729 | return ret; |
700 | } | 730 | } |
701 | 731 | ||
732 | /* | ||
733 | * According to the V4L2 API, drivers shall not update the struct v4l2_crop | ||
734 | * argument with the actual geometry, instead, the user shall use G_CROP to | ||
735 | * retrieve it. However, we expect camera host and client drivers to update | ||
736 | * the argument, which we then use internally, but do not return to the user. | ||
737 | */ | ||
702 | static int soc_camera_s_crop(struct file *file, void *fh, | 738 | static int soc_camera_s_crop(struct file *file, void *fh, |
703 | struct v4l2_crop *a) | 739 | struct v4l2_crop *a) |
704 | { | 740 | { |
705 | struct soc_camera_file *icf = file->private_data; | 741 | struct soc_camera_file *icf = file->private_data; |
706 | struct soc_camera_device *icd = icf->icd; | 742 | struct soc_camera_device *icd = icf->icd; |
707 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 743 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
744 | struct v4l2_rect *rect = &a->c; | ||
745 | struct v4l2_crop current_crop; | ||
708 | int ret; | 746 | int ret; |
709 | 747 | ||
710 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 748 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
711 | return -EINVAL; | 749 | return -EINVAL; |
712 | 750 | ||
751 | dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n", | ||
752 | rect->width, rect->height, rect->left, rect->top); | ||
753 | |||
713 | /* Cropping is allowed during a running capture, guard consistency */ | 754 | /* Cropping is allowed during a running capture, guard consistency */ |
714 | mutex_lock(&icf->vb_vidq.vb_lock); | 755 | mutex_lock(&icf->vb_vidq.vb_lock); |
715 | 756 | ||
716 | ret = ici->ops->set_crop(icd, &a->c); | 757 | /* If get_crop fails, we'll let host and / or client drivers decide */ |
717 | if (!ret) { | 758 | ret = ici->ops->get_crop(icd, ¤t_crop); |
718 | icd->width = a->c.width; | 759 | |
719 | icd->height = a->c.height; | 760 | /* Prohibit window size change with initialised buffers */ |
720 | icd->x_current = a->c.left; | 761 | if (icf->vb_vidq.bufs[0] && !ret && |
721 | icd->y_current = a->c.top; | 762 | (a->c.width != current_crop.c.width || |
763 | a->c.height != current_crop.c.height)) { | ||
764 | dev_err(&icd->dev, | ||
765 | "S_CROP denied: queue initialised and sizes differ\n"); | ||
766 | ret = -EBUSY; | ||
767 | } else { | ||
768 | ret = ici->ops->set_crop(icd, a); | ||
722 | } | 769 | } |
723 | 770 | ||
724 | mutex_unlock(&icf->vb_vidq.vb_lock); | 771 | mutex_unlock(&icf->vb_vidq.vb_lock); |
@@ -731,11 +778,9 @@ static int soc_camera_g_chip_ident(struct file *file, void *fh, | |||
731 | { | 778 | { |
732 | struct soc_camera_file *icf = file->private_data; | 779 | struct soc_camera_file *icf = file->private_data; |
733 | struct soc_camera_device *icd = icf->icd; | 780 | struct soc_camera_device *icd = icf->icd; |
781 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
734 | 782 | ||
735 | if (!icd->ops->get_chip_id) | 783 | return v4l2_subdev_call(sd, core, g_chip_ident, id); |
736 | return -EINVAL; | ||
737 | |||
738 | return icd->ops->get_chip_id(icd, id); | ||
739 | } | 784 | } |
740 | 785 | ||
741 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 786 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -744,11 +789,9 @@ static int soc_camera_g_register(struct file *file, void *fh, | |||
744 | { | 789 | { |
745 | struct soc_camera_file *icf = file->private_data; | 790 | struct soc_camera_file *icf = file->private_data; |
746 | struct soc_camera_device *icd = icf->icd; | 791 | struct soc_camera_device *icd = icf->icd; |
792 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
747 | 793 | ||
748 | if (!icd->ops->get_register) | 794 | return v4l2_subdev_call(sd, core, g_register, reg); |
749 | return -EINVAL; | ||
750 | |||
751 | return icd->ops->get_register(icd, reg); | ||
752 | } | 795 | } |
753 | 796 | ||
754 | static int soc_camera_s_register(struct file *file, void *fh, | 797 | static int soc_camera_s_register(struct file *file, void *fh, |
@@ -756,37 +799,12 @@ static int soc_camera_s_register(struct file *file, void *fh, | |||
756 | { | 799 | { |
757 | struct soc_camera_file *icf = file->private_data; | 800 | struct soc_camera_file *icf = file->private_data; |
758 | struct soc_camera_device *icd = icf->icd; | 801 | struct soc_camera_device *icd = icf->icd; |
802 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
759 | 803 | ||
760 | if (!icd->ops->set_register) | 804 | return v4l2_subdev_call(sd, core, s_register, reg); |
761 | return -EINVAL; | ||
762 | |||
763 | return icd->ops->set_register(icd, reg); | ||
764 | } | 805 | } |
765 | #endif | 806 | #endif |
766 | 807 | ||
767 | static int device_register_link(struct soc_camera_device *icd) | ||
768 | { | ||
769 | int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); | ||
770 | |||
771 | if (!ret) | ||
772 | ret = device_register(&icd->dev); | ||
773 | |||
774 | if (ret < 0) { | ||
775 | /* Prevent calling device_unregister() */ | ||
776 | icd->dev.parent = NULL; | ||
777 | dev_err(&icd->dev, "Cannot register device: %d\n", ret); | ||
778 | /* Even if probe() was unsuccessful for all registered drivers, | ||
779 | * device_register() returns 0, and we add the link, just to | ||
780 | * document this camera's control device */ | ||
781 | } else if (icd->control) | ||
782 | /* Have to sysfs_remove_link() before device_unregister()? */ | ||
783 | if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj, | ||
784 | "control")) | ||
785 | dev_warn(&icd->dev, | ||
786 | "Failed creating the control symlink\n"); | ||
787 | return ret; | ||
788 | } | ||
789 | |||
790 | /* So far this function cannot fail */ | 808 | /* So far this function cannot fail */ |
791 | static void scan_add_host(struct soc_camera_host *ici) | 809 | static void scan_add_host(struct soc_camera_host *ici) |
792 | { | 810 | { |
@@ -796,106 +814,193 @@ static void scan_add_host(struct soc_camera_host *ici) | |||
796 | 814 | ||
797 | list_for_each_entry(icd, &devices, list) { | 815 | list_for_each_entry(icd, &devices, list) { |
798 | if (icd->iface == ici->nr) { | 816 | if (icd->iface == ici->nr) { |
799 | icd->dev.parent = ici->dev; | 817 | int ret; |
800 | device_register_link(icd); | 818 | icd->dev.parent = ici->v4l2_dev.dev; |
819 | dev_set_name(&icd->dev, "%u-%u", icd->iface, | ||
820 | icd->devnum); | ||
821 | ret = device_register(&icd->dev); | ||
822 | if (ret < 0) { | ||
823 | icd->dev.parent = NULL; | ||
824 | dev_err(&icd->dev, | ||
825 | "Cannot register device: %d\n", ret); | ||
826 | } | ||
801 | } | 827 | } |
802 | } | 828 | } |
803 | 829 | ||
804 | mutex_unlock(&list_lock); | 830 | mutex_unlock(&list_lock); |
805 | } | 831 | } |
806 | 832 | ||
807 | /* return: 0 if no match found or a match found and | 833 | #ifdef CONFIG_I2C_BOARDINFO |
808 | * device_register() successful, error code otherwise */ | 834 | static int soc_camera_init_i2c(struct soc_camera_device *icd, |
809 | static int scan_add_device(struct soc_camera_device *icd) | 835 | struct soc_camera_link *icl) |
810 | { | 836 | { |
811 | struct soc_camera_host *ici; | 837 | struct i2c_client *client; |
812 | int ret = 0; | 838 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
839 | struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id); | ||
840 | struct v4l2_subdev *subdev; | ||
841 | int ret; | ||
813 | 842 | ||
814 | mutex_lock(&list_lock); | 843 | if (!adap) { |
844 | ret = -ENODEV; | ||
845 | dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n", | ||
846 | icl->i2c_adapter_id); | ||
847 | goto ei2cga; | ||
848 | } | ||
815 | 849 | ||
816 | list_add_tail(&icd->list, &devices); | 850 | icl->board_info->platform_data = icd; |
817 | 851 | ||
818 | /* Watch out for class_for_each_device / class_find_device API by | 852 | subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, |
819 | * Dave Young <hidave.darkstar@gmail.com> */ | 853 | icl->module_name, icl->board_info, NULL); |
820 | list_for_each_entry(ici, &hosts, list) { | 854 | if (!subdev) { |
821 | if (icd->iface == ici->nr) { | 855 | ret = -ENOMEM; |
822 | ret = 1; | 856 | goto ei2cnd; |
823 | icd->dev.parent = ici->dev; | ||
824 | break; | ||
825 | } | ||
826 | } | 857 | } |
827 | 858 | ||
828 | mutex_unlock(&list_lock); | 859 | client = subdev->priv; |
829 | 860 | ||
830 | if (ret) | 861 | /* Use to_i2c_client(dev) to recover the i2c client */ |
831 | ret = device_register_link(icd); | 862 | dev_set_drvdata(&icd->dev, &client->dev); |
832 | 863 | ||
864 | return 0; | ||
865 | ei2cnd: | ||
866 | i2c_put_adapter(adap); | ||
867 | ei2cga: | ||
833 | return ret; | 868 | return ret; |
834 | } | 869 | } |
835 | 870 | ||
871 | static void soc_camera_free_i2c(struct soc_camera_device *icd) | ||
872 | { | ||
873 | struct i2c_client *client = | ||
874 | to_i2c_client(to_soc_camera_control(icd)); | ||
875 | dev_set_drvdata(&icd->dev, NULL); | ||
876 | v4l2_device_unregister_subdev(i2c_get_clientdata(client)); | ||
877 | i2c_unregister_device(client); | ||
878 | i2c_put_adapter(client->adapter); | ||
879 | } | ||
880 | #else | ||
881 | #define soc_camera_init_i2c(icd, icl) (-ENODEV) | ||
882 | #define soc_camera_free_i2c(icd) do {} while (0) | ||
883 | #endif | ||
884 | |||
885 | static int soc_camera_video_start(struct soc_camera_device *icd); | ||
886 | static int video_dev_create(struct soc_camera_device *icd); | ||
887 | /* Called during host-driver probe */ | ||
836 | static int soc_camera_probe(struct device *dev) | 888 | static int soc_camera_probe(struct device *dev) |
837 | { | 889 | { |
838 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | 890 | struct soc_camera_device *icd = to_soc_camera_dev(dev); |
839 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 891 | struct soc_camera_host *ici = to_soc_camera_host(dev->parent); |
892 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
893 | struct device *control = NULL; | ||
894 | struct v4l2_subdev *sd; | ||
895 | struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; | ||
840 | int ret; | 896 | int ret; |
841 | 897 | ||
842 | /* | 898 | dev_info(dev, "Probing %s\n", dev_name(dev)); |
843 | * Possible race scenario: | ||
844 | * modprobe <camera-host-driver> triggers __func__ | ||
845 | * at this moment respective <camera-sensor-driver> gets rmmod'ed | ||
846 | * to protect take module references. | ||
847 | */ | ||
848 | 899 | ||
849 | if (!try_module_get(icd->ops->owner)) { | 900 | if (icl->power) { |
850 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); | 901 | ret = icl->power(icd->pdev, 1); |
851 | ret = -EINVAL; | 902 | if (ret < 0) { |
852 | goto emgd; | 903 | dev_err(dev, |
904 | "Platform failed to power-on the camera.\n"); | ||
905 | goto epower; | ||
906 | } | ||
853 | } | 907 | } |
854 | 908 | ||
855 | if (!try_module_get(ici->ops->owner)) { | 909 | /* The camera could have been already on, try to reset */ |
856 | dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); | 910 | if (icl->reset) |
911 | icl->reset(icd->pdev); | ||
912 | |||
913 | ret = ici->ops->add(icd); | ||
914 | if (ret < 0) | ||
915 | goto eadd; | ||
916 | |||
917 | /* Must have icd->vdev before registering the device */ | ||
918 | ret = video_dev_create(icd); | ||
919 | if (ret < 0) | ||
920 | goto evdc; | ||
921 | |||
922 | /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ | ||
923 | if (icl->board_info) { | ||
924 | ret = soc_camera_init_i2c(icd, icl); | ||
925 | if (ret < 0) | ||
926 | goto eadddev; | ||
927 | } else if (!icl->add_device || !icl->del_device) { | ||
857 | ret = -EINVAL; | 928 | ret = -EINVAL; |
858 | goto emgi; | 929 | goto eadddev; |
930 | } else { | ||
931 | if (icl->module_name) | ||
932 | ret = request_module(icl->module_name); | ||
933 | |||
934 | ret = icl->add_device(icl, &icd->dev); | ||
935 | if (ret < 0) | ||
936 | goto eadddev; | ||
937 | |||
938 | /* | ||
939 | * FIXME: this is racy, have to use driver-binding notification, | ||
940 | * when it is available | ||
941 | */ | ||
942 | control = to_soc_camera_control(icd); | ||
943 | if (!control || !control->driver || !dev_get_drvdata(control) || | ||
944 | !try_module_get(control->driver->owner)) { | ||
945 | icl->del_device(icl); | ||
946 | goto enodrv; | ||
947 | } | ||
859 | } | 948 | } |
860 | 949 | ||
950 | /* At this point client .probe() should have run already */ | ||
951 | ret = soc_camera_init_user_formats(icd); | ||
952 | if (ret < 0) | ||
953 | goto eiufmt; | ||
954 | |||
955 | icd->field = V4L2_FIELD_ANY; | ||
956 | |||
957 | /* ..._video_start() will create a device node, so we have to protect */ | ||
861 | mutex_lock(&icd->video_lock); | 958 | mutex_lock(&icd->video_lock); |
862 | 959 | ||
863 | /* We only call ->add() here to activate and probe the camera. | 960 | ret = soc_camera_video_start(icd); |
864 | * We shall ->remove() and deactivate it immediately afterwards. */ | ||
865 | ret = ici->ops->add(icd); | ||
866 | if (ret < 0) | 961 | if (ret < 0) |
867 | goto eiadd; | 962 | goto evidstart; |
963 | |||
964 | /* Try to improve our guess of a reasonable window format */ | ||
965 | sd = soc_camera_to_subdev(icd); | ||
966 | if (!v4l2_subdev_call(sd, video, g_fmt, &f)) { | ||
967 | icd->user_width = f.fmt.pix.width; | ||
968 | icd->user_height = f.fmt.pix.height; | ||
969 | } | ||
868 | 970 | ||
869 | ret = icd->ops->probe(icd); | 971 | /* Do we have to sysfs_remove_link() before device_unregister()? */ |
870 | if (ret >= 0) { | 972 | if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj, |
871 | const struct v4l2_queryctrl *qctrl; | 973 | "control")) |
974 | dev_warn(&icd->dev, "Failed creating the control symlink\n"); | ||
872 | 975 | ||
873 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN); | 976 | ici->ops->remove(icd); |
874 | icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0; | ||
875 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | ||
876 | icd->exposure = qctrl ? qctrl->default_value : | ||
877 | (unsigned short)~0; | ||
878 | 977 | ||
879 | ret = soc_camera_init_user_formats(icd); | 978 | if (icl->power) |
880 | if (ret < 0) { | 979 | icl->power(icd->pdev, 0); |
881 | if (icd->ops->remove) | ||
882 | icd->ops->remove(icd); | ||
883 | goto eiufmt; | ||
884 | } | ||
885 | 980 | ||
886 | icd->height = DEFAULT_HEIGHT; | 981 | mutex_unlock(&icd->video_lock); |
887 | icd->width = DEFAULT_WIDTH; | ||
888 | icd->field = V4L2_FIELD_ANY; | ||
889 | } | ||
890 | 982 | ||
983 | return 0; | ||
984 | |||
985 | evidstart: | ||
986 | mutex_unlock(&icd->video_lock); | ||
987 | soc_camera_free_user_formats(icd); | ||
891 | eiufmt: | 988 | eiufmt: |
989 | if (icl->board_info) { | ||
990 | soc_camera_free_i2c(icd); | ||
991 | } else { | ||
992 | icl->del_device(icl); | ||
993 | module_put(control->driver->owner); | ||
994 | } | ||
995 | enodrv: | ||
996 | eadddev: | ||
997 | video_device_release(icd->vdev); | ||
998 | evdc: | ||
892 | ici->ops->remove(icd); | 999 | ici->ops->remove(icd); |
893 | eiadd: | 1000 | eadd: |
894 | mutex_unlock(&icd->video_lock); | 1001 | if (icl->power) |
895 | module_put(ici->ops->owner); | 1002 | icl->power(icd->pdev, 0); |
896 | emgi: | 1003 | epower: |
897 | module_put(icd->ops->owner); | ||
898 | emgd: | ||
899 | return ret; | 1004 | return ret; |
900 | } | 1005 | } |
901 | 1006 | ||
@@ -904,12 +1009,28 @@ emgd: | |||
904 | static int soc_camera_remove(struct device *dev) | 1009 | static int soc_camera_remove(struct device *dev) |
905 | { | 1010 | { |
906 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | 1011 | struct soc_camera_device *icd = to_soc_camera_dev(dev); |
1012 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
1013 | struct video_device *vdev = icd->vdev; | ||
907 | 1014 | ||
908 | mutex_lock(&icd->video_lock); | 1015 | BUG_ON(!dev->parent); |
909 | if (icd->ops->remove) | ||
910 | icd->ops->remove(icd); | ||
911 | mutex_unlock(&icd->video_lock); | ||
912 | 1016 | ||
1017 | if (vdev) { | ||
1018 | mutex_lock(&icd->video_lock); | ||
1019 | video_unregister_device(vdev); | ||
1020 | icd->vdev = NULL; | ||
1021 | mutex_unlock(&icd->video_lock); | ||
1022 | } | ||
1023 | |||
1024 | if (icl->board_info) { | ||
1025 | soc_camera_free_i2c(icd); | ||
1026 | } else { | ||
1027 | struct device_driver *drv = to_soc_camera_control(icd) ? | ||
1028 | to_soc_camera_control(icd)->driver : NULL; | ||
1029 | if (drv) { | ||
1030 | icl->del_device(icl); | ||
1031 | module_put(drv->owner); | ||
1032 | } | ||
1033 | } | ||
913 | soc_camera_free_user_formats(icd); | 1034 | soc_camera_free_user_formats(icd); |
914 | 1035 | ||
915 | return 0; | 1036 | return 0; |
@@ -957,14 +1078,33 @@ static void dummy_release(struct device *dev) | |||
957 | { | 1078 | { |
958 | } | 1079 | } |
959 | 1080 | ||
1081 | static int default_cropcap(struct soc_camera_device *icd, | ||
1082 | struct v4l2_cropcap *a) | ||
1083 | { | ||
1084 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1085 | return v4l2_subdev_call(sd, video, cropcap, a); | ||
1086 | } | ||
1087 | |||
1088 | static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a) | ||
1089 | { | ||
1090 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1091 | return v4l2_subdev_call(sd, video, g_crop, a); | ||
1092 | } | ||
1093 | |||
1094 | static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a) | ||
1095 | { | ||
1096 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1097 | return v4l2_subdev_call(sd, video, s_crop, a); | ||
1098 | } | ||
1099 | |||
960 | int soc_camera_host_register(struct soc_camera_host *ici) | 1100 | int soc_camera_host_register(struct soc_camera_host *ici) |
961 | { | 1101 | { |
962 | struct soc_camera_host *ix; | 1102 | struct soc_camera_host *ix; |
1103 | int ret; | ||
963 | 1104 | ||
964 | if (!ici || !ici->ops || | 1105 | if (!ici || !ici->ops || |
965 | !ici->ops->try_fmt || | 1106 | !ici->ops->try_fmt || |
966 | !ici->ops->set_fmt || | 1107 | !ici->ops->set_fmt || |
967 | !ici->ops->set_crop || | ||
968 | !ici->ops->set_bus_param || | 1108 | !ici->ops->set_bus_param || |
969 | !ici->ops->querycap || | 1109 | !ici->ops->querycap || |
970 | !ici->ops->init_videobuf || | 1110 | !ici->ops->init_videobuf || |
@@ -972,18 +1112,27 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
972 | !ici->ops->add || | 1112 | !ici->ops->add || |
973 | !ici->ops->remove || | 1113 | !ici->ops->remove || |
974 | !ici->ops->poll || | 1114 | !ici->ops->poll || |
975 | !ici->dev) | 1115 | !ici->v4l2_dev.dev) |
976 | return -EINVAL; | 1116 | return -EINVAL; |
977 | 1117 | ||
1118 | if (!ici->ops->set_crop) | ||
1119 | ici->ops->set_crop = default_s_crop; | ||
1120 | if (!ici->ops->get_crop) | ||
1121 | ici->ops->get_crop = default_g_crop; | ||
1122 | if (!ici->ops->cropcap) | ||
1123 | ici->ops->cropcap = default_cropcap; | ||
1124 | |||
978 | mutex_lock(&list_lock); | 1125 | mutex_lock(&list_lock); |
979 | list_for_each_entry(ix, &hosts, list) { | 1126 | list_for_each_entry(ix, &hosts, list) { |
980 | if (ix->nr == ici->nr) { | 1127 | if (ix->nr == ici->nr) { |
981 | mutex_unlock(&list_lock); | 1128 | ret = -EBUSY; |
982 | return -EBUSY; | 1129 | goto edevreg; |
983 | } | 1130 | } |
984 | } | 1131 | } |
985 | 1132 | ||
986 | dev_set_drvdata(ici->dev, ici); | 1133 | ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev); |
1134 | if (ret < 0) | ||
1135 | goto edevreg; | ||
987 | 1136 | ||
988 | list_add_tail(&ici->list, &hosts); | 1137 | list_add_tail(&ici->list, &hosts); |
989 | mutex_unlock(&list_lock); | 1138 | mutex_unlock(&list_lock); |
@@ -991,6 +1140,10 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
991 | scan_add_host(ici); | 1140 | scan_add_host(ici); |
992 | 1141 | ||
993 | return 0; | 1142 | return 0; |
1143 | |||
1144 | edevreg: | ||
1145 | mutex_unlock(&list_lock); | ||
1146 | return ret; | ||
994 | } | 1147 | } |
995 | EXPORT_SYMBOL(soc_camera_host_register); | 1148 | EXPORT_SYMBOL(soc_camera_host_register); |
996 | 1149 | ||
@@ -1004,42 +1157,34 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) | |||
1004 | list_del(&ici->list); | 1157 | list_del(&ici->list); |
1005 | 1158 | ||
1006 | list_for_each_entry(icd, &devices, list) { | 1159 | list_for_each_entry(icd, &devices, list) { |
1007 | if (icd->dev.parent == ici->dev) { | 1160 | if (icd->iface == ici->nr) { |
1161 | /* The bus->remove will be called */ | ||
1008 | device_unregister(&icd->dev); | 1162 | device_unregister(&icd->dev); |
1009 | /* Not before device_unregister(), .remove | 1163 | /* Not before device_unregister(), .remove |
1010 | * needs parent to call ici->ops->remove() */ | 1164 | * needs parent to call ici->ops->remove() */ |
1011 | icd->dev.parent = NULL; | 1165 | icd->dev.parent = NULL; |
1166 | |||
1167 | /* If the host module is loaded again, device_register() | ||
1168 | * would complain "already initialised" */ | ||
1012 | memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj)); | 1169 | memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj)); |
1013 | } | 1170 | } |
1014 | } | 1171 | } |
1015 | 1172 | ||
1016 | mutex_unlock(&list_lock); | 1173 | mutex_unlock(&list_lock); |
1017 | 1174 | ||
1018 | dev_set_drvdata(ici->dev, NULL); | 1175 | v4l2_device_unregister(&ici->v4l2_dev); |
1019 | } | 1176 | } |
1020 | EXPORT_SYMBOL(soc_camera_host_unregister); | 1177 | EXPORT_SYMBOL(soc_camera_host_unregister); |
1021 | 1178 | ||
1022 | /* Image capture device */ | 1179 | /* Image capture device */ |
1023 | int soc_camera_device_register(struct soc_camera_device *icd) | 1180 | static int soc_camera_device_register(struct soc_camera_device *icd) |
1024 | { | 1181 | { |
1025 | struct soc_camera_device *ix; | 1182 | struct soc_camera_device *ix; |
1026 | int num = -1, i; | 1183 | int num = -1, i; |
1027 | 1184 | ||
1028 | if (!icd || !icd->ops || | ||
1029 | !icd->ops->probe || | ||
1030 | !icd->ops->init || | ||
1031 | !icd->ops->release || | ||
1032 | !icd->ops->start_capture || | ||
1033 | !icd->ops->stop_capture || | ||
1034 | !icd->ops->set_crop || | ||
1035 | !icd->ops->set_fmt || | ||
1036 | !icd->ops->try_fmt || | ||
1037 | !icd->ops->query_bus_param || | ||
1038 | !icd->ops->set_bus_param) | ||
1039 | return -EINVAL; | ||
1040 | |||
1041 | for (i = 0; i < 256 && num < 0; i++) { | 1185 | for (i = 0; i < 256 && num < 0; i++) { |
1042 | num = i; | 1186 | num = i; |
1187 | /* Check if this index is available on this interface */ | ||
1043 | list_for_each_entry(ix, &devices, list) { | 1188 | list_for_each_entry(ix, &devices, list) { |
1044 | if (ix->iface == icd->iface && ix->devnum == i) { | 1189 | if (ix->iface == icd->iface && ix->devnum == i) { |
1045 | num = -1; | 1190 | num = -1; |
@@ -1061,21 +1206,15 @@ int soc_camera_device_register(struct soc_camera_device *icd) | |||
1061 | icd->host_priv = NULL; | 1206 | icd->host_priv = NULL; |
1062 | mutex_init(&icd->video_lock); | 1207 | mutex_init(&icd->video_lock); |
1063 | 1208 | ||
1064 | return scan_add_device(icd); | 1209 | list_add_tail(&icd->list, &devices); |
1210 | |||
1211 | return 0; | ||
1065 | } | 1212 | } |
1066 | EXPORT_SYMBOL(soc_camera_device_register); | ||
1067 | 1213 | ||
1068 | void soc_camera_device_unregister(struct soc_camera_device *icd) | 1214 | static void soc_camera_device_unregister(struct soc_camera_device *icd) |
1069 | { | 1215 | { |
1070 | mutex_lock(&list_lock); | ||
1071 | list_del(&icd->list); | 1216 | list_del(&icd->list); |
1072 | |||
1073 | /* The bus->remove will be eventually called */ | ||
1074 | if (icd->dev.parent) | ||
1075 | device_unregister(&icd->dev); | ||
1076 | mutex_unlock(&list_lock); | ||
1077 | } | 1217 | } |
1078 | EXPORT_SYMBOL(soc_camera_device_unregister); | ||
1079 | 1218 | ||
1080 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | 1219 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { |
1081 | .vidioc_querycap = soc_camera_querycap, | 1220 | .vidioc_querycap = soc_camera_querycap, |
@@ -1106,23 +1245,13 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | |||
1106 | #endif | 1245 | #endif |
1107 | }; | 1246 | }; |
1108 | 1247 | ||
1109 | /* | 1248 | static int video_dev_create(struct soc_camera_device *icd) |
1110 | * Usually called from the struct soc_camera_ops .probe() method, i.e., from | ||
1111 | * soc_camera_probe() above with .video_lock held | ||
1112 | */ | ||
1113 | int soc_camera_video_start(struct soc_camera_device *icd) | ||
1114 | { | 1249 | { |
1115 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1250 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1116 | int err = -ENOMEM; | 1251 | struct video_device *vdev = video_device_alloc(); |
1117 | struct video_device *vdev; | ||
1118 | 1252 | ||
1119 | if (!icd->dev.parent) | ||
1120 | return -ENODEV; | ||
1121 | |||
1122 | vdev = video_device_alloc(); | ||
1123 | if (!vdev) | 1253 | if (!vdev) |
1124 | goto evidallocd; | 1254 | return -ENOMEM; |
1125 | dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); | ||
1126 | 1255 | ||
1127 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); | 1256 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); |
1128 | 1257 | ||
@@ -1132,87 +1261,93 @@ int soc_camera_video_start(struct soc_camera_device *icd) | |||
1132 | vdev->ioctl_ops = &soc_camera_ioctl_ops; | 1261 | vdev->ioctl_ops = &soc_camera_ioctl_ops; |
1133 | vdev->release = video_device_release; | 1262 | vdev->release = video_device_release; |
1134 | vdev->minor = -1; | 1263 | vdev->minor = -1; |
1135 | vdev->tvnorms = V4L2_STD_UNKNOWN, | 1264 | vdev->tvnorms = V4L2_STD_UNKNOWN; |
1136 | 1265 | ||
1137 | err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); | ||
1138 | if (err < 0) { | ||
1139 | dev_err(vdev->parent, "video_register_device failed\n"); | ||
1140 | goto evidregd; | ||
1141 | } | ||
1142 | icd->vdev = vdev; | 1266 | icd->vdev = vdev; |
1143 | 1267 | ||
1144 | return 0; | 1268 | return 0; |
1145 | |||
1146 | evidregd: | ||
1147 | video_device_release(vdev); | ||
1148 | evidallocd: | ||
1149 | return err; | ||
1150 | } | 1269 | } |
1151 | EXPORT_SYMBOL(soc_camera_video_start); | ||
1152 | 1270 | ||
1153 | /* Called from client .remove() methods with .video_lock held */ | 1271 | /* |
1154 | void soc_camera_video_stop(struct soc_camera_device *icd) | 1272 | * Called from soc_camera_probe() above (with .video_lock held???) |
1273 | */ | ||
1274 | static int soc_camera_video_start(struct soc_camera_device *icd) | ||
1155 | { | 1275 | { |
1156 | struct video_device *vdev = icd->vdev; | 1276 | int ret; |
1157 | 1277 | ||
1158 | dev_dbg(&icd->dev, "%s\n", __func__); | 1278 | if (!icd->dev.parent) |
1279 | return -ENODEV; | ||
1159 | 1280 | ||
1160 | if (!icd->dev.parent || !vdev) | 1281 | if (!icd->ops || |
1161 | return; | 1282 | !icd->ops->query_bus_param || |
1283 | !icd->ops->set_bus_param) | ||
1284 | return -EINVAL; | ||
1285 | |||
1286 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, | ||
1287 | icd->vdev->minor); | ||
1288 | if (ret < 0) { | ||
1289 | dev_err(&icd->dev, "video_register_device failed: %d\n", ret); | ||
1290 | return ret; | ||
1291 | } | ||
1162 | 1292 | ||
1163 | video_unregister_device(vdev); | 1293 | return 0; |
1164 | icd->vdev = NULL; | ||
1165 | } | 1294 | } |
1166 | EXPORT_SYMBOL(soc_camera_video_stop); | ||
1167 | 1295 | ||
1168 | static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) | 1296 | static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) |
1169 | { | 1297 | { |
1170 | struct soc_camera_link *icl = pdev->dev.platform_data; | 1298 | struct soc_camera_link *icl = pdev->dev.platform_data; |
1171 | struct i2c_adapter *adap; | 1299 | struct soc_camera_device *icd; |
1172 | struct i2c_client *client; | 1300 | int ret; |
1173 | 1301 | ||
1174 | if (!icl) | 1302 | if (!icl) |
1175 | return -EINVAL; | 1303 | return -EINVAL; |
1176 | 1304 | ||
1177 | adap = i2c_get_adapter(icl->i2c_adapter_id); | 1305 | icd = kzalloc(sizeof(*icd), GFP_KERNEL); |
1178 | if (!adap) { | 1306 | if (!icd) |
1179 | dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n", | ||
1180 | icl->i2c_adapter_id); | ||
1181 | /* -ENODEV and -ENXIO do not produce an error on probe()... */ | ||
1182 | return -ENOENT; | ||
1183 | } | ||
1184 | |||
1185 | icl->board_info->platform_data = icl; | ||
1186 | client = i2c_new_device(adap, icl->board_info); | ||
1187 | if (!client) { | ||
1188 | i2c_put_adapter(adap); | ||
1189 | return -ENOMEM; | 1307 | return -ENOMEM; |
1190 | } | ||
1191 | 1308 | ||
1192 | platform_set_drvdata(pdev, client); | 1309 | icd->iface = icl->bus_id; |
1310 | icd->pdev = &pdev->dev; | ||
1311 | platform_set_drvdata(pdev, icd); | ||
1312 | icd->dev.platform_data = icl; | ||
1313 | |||
1314 | ret = soc_camera_device_register(icd); | ||
1315 | if (ret < 0) | ||
1316 | goto escdevreg; | ||
1317 | |||
1318 | icd->user_width = DEFAULT_WIDTH; | ||
1319 | icd->user_height = DEFAULT_HEIGHT; | ||
1193 | 1320 | ||
1194 | return 0; | 1321 | return 0; |
1322 | |||
1323 | escdevreg: | ||
1324 | kfree(icd); | ||
1325 | |||
1326 | return ret; | ||
1195 | } | 1327 | } |
1196 | 1328 | ||
1329 | /* Only called on rmmod for each platform device, since they are not | ||
1330 | * hot-pluggable. Now we know, that all our users - hosts and devices have | ||
1331 | * been unloaded already */ | ||
1197 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) | 1332 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) |
1198 | { | 1333 | { |
1199 | struct i2c_client *client = platform_get_drvdata(pdev); | 1334 | struct soc_camera_device *icd = platform_get_drvdata(pdev); |
1200 | 1335 | ||
1201 | if (!client) | 1336 | if (!icd) |
1202 | return -ENODEV; | 1337 | return -EINVAL; |
1203 | 1338 | ||
1204 | i2c_unregister_device(client); | 1339 | soc_camera_device_unregister(icd); |
1205 | i2c_put_adapter(client->adapter); | 1340 | |
1341 | kfree(icd); | ||
1206 | 1342 | ||
1207 | return 0; | 1343 | return 0; |
1208 | } | 1344 | } |
1209 | 1345 | ||
1210 | static struct platform_driver __refdata soc_camera_pdrv = { | 1346 | static struct platform_driver __refdata soc_camera_pdrv = { |
1211 | .probe = soc_camera_pdrv_probe, | 1347 | .remove = __devexit_p(soc_camera_pdrv_remove), |
1212 | .remove = __devexit_p(soc_camera_pdrv_remove), | 1348 | .driver = { |
1213 | .driver = { | 1349 | .name = "soc-camera-pdrv", |
1214 | .name = "soc-camera-pdrv", | 1350 | .owner = THIS_MODULE, |
1215 | .owner = THIS_MODULE, | ||
1216 | }, | 1351 | }, |
1217 | }; | 1352 | }; |
1218 | 1353 | ||
@@ -1225,7 +1360,7 @@ static int __init soc_camera_init(void) | |||
1225 | if (ret) | 1360 | if (ret) |
1226 | goto edrvr; | 1361 | goto edrvr; |
1227 | 1362 | ||
1228 | ret = platform_driver_register(&soc_camera_pdrv); | 1363 | ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe); |
1229 | if (ret) | 1364 | if (ret) |
1230 | goto epdr; | 1365 | goto epdr; |
1231 | 1366 | ||
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index c48676356ab7..b6a575ce5da2 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c | |||
@@ -16,54 +16,32 @@ | |||
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/videodev2.h> | 18 | #include <linux/videodev2.h> |
19 | #include <media/v4l2-common.h> | 19 | #include <media/v4l2-subdev.h> |
20 | #include <media/soc_camera.h> | 20 | #include <media/soc_camera.h> |
21 | #include <media/soc_camera_platform.h> | 21 | #include <media/soc_camera_platform.h> |
22 | 22 | ||
23 | struct soc_camera_platform_priv { | 23 | struct soc_camera_platform_priv { |
24 | struct soc_camera_platform_info *info; | 24 | struct v4l2_subdev subdev; |
25 | struct soc_camera_device icd; | ||
26 | struct soc_camera_data_format format; | 25 | struct soc_camera_data_format format; |
27 | }; | 26 | }; |
28 | 27 | ||
29 | static struct soc_camera_platform_info * | 28 | static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) |
30 | soc_camera_platform_get_info(struct soc_camera_device *icd) | ||
31 | { | 29 | { |
32 | struct soc_camera_platform_priv *priv; | 30 | struct v4l2_subdev *subdev = platform_get_drvdata(pdev); |
33 | priv = container_of(icd, struct soc_camera_platform_priv, icd); | 31 | return container_of(subdev, struct soc_camera_platform_priv, subdev); |
34 | return priv->info; | ||
35 | } | ||
36 | |||
37 | static int soc_camera_platform_init(struct soc_camera_device *icd) | ||
38 | { | ||
39 | struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); | ||
40 | |||
41 | if (p->power) | ||
42 | p->power(1); | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int soc_camera_platform_release(struct soc_camera_device *icd) | ||
48 | { | ||
49 | struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); | ||
50 | |||
51 | if (p->power) | ||
52 | p->power(0); | ||
53 | |||
54 | return 0; | ||
55 | } | 32 | } |
56 | 33 | ||
57 | static int soc_camera_platform_start_capture(struct soc_camera_device *icd) | 34 | static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd) |
58 | { | 35 | { |
59 | struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); | 36 | struct platform_device *pdev = |
60 | return p->set_capture(p, 1); | 37 | to_platform_device(to_soc_camera_control(icd)); |
38 | return pdev->dev.platform_data; | ||
61 | } | 39 | } |
62 | 40 | ||
63 | static int soc_camera_platform_stop_capture(struct soc_camera_device *icd) | 41 | static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) |
64 | { | 42 | { |
65 | struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); | 43 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); |
66 | return p->set_capture(p, 0); | 44 | return p->set_capture(p, enable); |
67 | } | 45 | } |
68 | 46 | ||
69 | static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, | 47 | static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, |
@@ -75,26 +53,14 @@ static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, | |||
75 | static unsigned long | 53 | static unsigned long |
76 | soc_camera_platform_query_bus_param(struct soc_camera_device *icd) | 54 | soc_camera_platform_query_bus_param(struct soc_camera_device *icd) |
77 | { | 55 | { |
78 | struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); | 56 | struct soc_camera_platform_info *p = get_info(icd); |
79 | return p->bus_param; | 57 | return p->bus_param; |
80 | } | 58 | } |
81 | 59 | ||
82 | static int soc_camera_platform_set_crop(struct soc_camera_device *icd, | 60 | static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd, |
83 | struct v4l2_rect *rect) | ||
84 | { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int soc_camera_platform_set_fmt(struct soc_camera_device *icd, | ||
89 | struct v4l2_format *f) | 61 | struct v4l2_format *f) |
90 | { | 62 | { |
91 | return 0; | 63 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); |
92 | } | ||
93 | |||
94 | static int soc_camera_platform_try_fmt(struct soc_camera_device *icd, | ||
95 | struct v4l2_format *f) | ||
96 | { | ||
97 | struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); | ||
98 | struct v4l2_pix_format *pix = &f->fmt.pix; | 64 | struct v4l2_pix_format *pix = &f->fmt.pix; |
99 | 65 | ||
100 | pix->width = p->format.width; | 66 | pix->width = p->format.width; |
@@ -102,82 +68,99 @@ static int soc_camera_platform_try_fmt(struct soc_camera_device *icd, | |||
102 | return 0; | 68 | return 0; |
103 | } | 69 | } |
104 | 70 | ||
105 | static int soc_camera_platform_video_probe(struct soc_camera_device *icd) | 71 | static void soc_camera_platform_video_probe(struct soc_camera_device *icd, |
72 | struct platform_device *pdev) | ||
106 | { | 73 | { |
107 | struct soc_camera_platform_priv *priv; | 74 | struct soc_camera_platform_priv *priv = get_priv(pdev); |
108 | priv = container_of(icd, struct soc_camera_platform_priv, icd); | 75 | struct soc_camera_platform_info *p = pdev->dev.platform_data; |
109 | 76 | ||
110 | priv->format.name = priv->info->format_name; | 77 | priv->format.name = p->format_name; |
111 | priv->format.depth = priv->info->format_depth; | 78 | priv->format.depth = p->format_depth; |
112 | priv->format.fourcc = priv->info->format.pixelformat; | 79 | priv->format.fourcc = p->format.pixelformat; |
113 | priv->format.colorspace = priv->info->format.colorspace; | 80 | priv->format.colorspace = p->format.colorspace; |
114 | 81 | ||
115 | icd->formats = &priv->format; | 82 | icd->formats = &priv->format; |
116 | icd->num_formats = 1; | 83 | icd->num_formats = 1; |
117 | |||
118 | return soc_camera_video_start(icd); | ||
119 | } | 84 | } |
120 | 85 | ||
121 | static void soc_camera_platform_video_remove(struct soc_camera_device *icd) | 86 | static struct v4l2_subdev_core_ops platform_subdev_core_ops; |
122 | { | 87 | |
123 | soc_camera_video_stop(icd); | 88 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { |
124 | } | 89 | .s_stream = soc_camera_platform_s_stream, |
90 | .try_fmt = soc_camera_platform_try_fmt, | ||
91 | }; | ||
92 | |||
93 | static struct v4l2_subdev_ops platform_subdev_ops = { | ||
94 | .core = &platform_subdev_core_ops, | ||
95 | .video = &platform_subdev_video_ops, | ||
96 | }; | ||
125 | 97 | ||
126 | static struct soc_camera_ops soc_camera_platform_ops = { | 98 | static struct soc_camera_ops soc_camera_platform_ops = { |
127 | .owner = THIS_MODULE, | ||
128 | .probe = soc_camera_platform_video_probe, | ||
129 | .remove = soc_camera_platform_video_remove, | ||
130 | .init = soc_camera_platform_init, | ||
131 | .release = soc_camera_platform_release, | ||
132 | .start_capture = soc_camera_platform_start_capture, | ||
133 | .stop_capture = soc_camera_platform_stop_capture, | ||
134 | .set_crop = soc_camera_platform_set_crop, | ||
135 | .set_fmt = soc_camera_platform_set_fmt, | ||
136 | .try_fmt = soc_camera_platform_try_fmt, | ||
137 | .set_bus_param = soc_camera_platform_set_bus_param, | 99 | .set_bus_param = soc_camera_platform_set_bus_param, |
138 | .query_bus_param = soc_camera_platform_query_bus_param, | 100 | .query_bus_param = soc_camera_platform_query_bus_param, |
139 | }; | 101 | }; |
140 | 102 | ||
141 | static int soc_camera_platform_probe(struct platform_device *pdev) | 103 | static int soc_camera_platform_probe(struct platform_device *pdev) |
142 | { | 104 | { |
105 | struct soc_camera_host *ici; | ||
143 | struct soc_camera_platform_priv *priv; | 106 | struct soc_camera_platform_priv *priv; |
144 | struct soc_camera_platform_info *p; | 107 | struct soc_camera_platform_info *p = pdev->dev.platform_data; |
145 | struct soc_camera_device *icd; | 108 | struct soc_camera_device *icd; |
146 | int ret; | 109 | int ret; |
147 | 110 | ||
148 | p = pdev->dev.platform_data; | ||
149 | if (!p) | 111 | if (!p) |
150 | return -EINVAL; | 112 | return -EINVAL; |
151 | 113 | ||
114 | if (!p->dev) { | ||
115 | dev_err(&pdev->dev, | ||
116 | "Platform has not set soc_camera_device pointer!\n"); | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
152 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 120 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
153 | if (!priv) | 121 | if (!priv) |
154 | return -ENOMEM; | 122 | return -ENOMEM; |
155 | 123 | ||
156 | priv->info = p; | 124 | icd = to_soc_camera_dev(p->dev); |
157 | platform_set_drvdata(pdev, priv); | 125 | |
126 | /* soc-camera convention: control's drvdata points to the subdev */ | ||
127 | platform_set_drvdata(pdev, &priv->subdev); | ||
128 | /* Set the control device reference */ | ||
129 | dev_set_drvdata(&icd->dev, &pdev->dev); | ||
130 | |||
131 | icd->y_skip_top = 0; | ||
132 | icd->ops = &soc_camera_platform_ops; | ||
133 | |||
134 | ici = to_soc_camera_host(icd->dev.parent); | ||
158 | 135 | ||
159 | icd = &priv->icd; | 136 | soc_camera_platform_video_probe(icd, pdev); |
160 | icd->ops = &soc_camera_platform_ops; | ||
161 | icd->control = &pdev->dev; | ||
162 | icd->width_min = 0; | ||
163 | icd->width_max = priv->info->format.width; | ||
164 | icd->height_min = 0; | ||
165 | icd->height_max = priv->info->format.height; | ||
166 | icd->y_skip_top = 0; | ||
167 | icd->iface = priv->info->iface; | ||
168 | 137 | ||
169 | ret = soc_camera_device_register(icd); | 138 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); |
139 | v4l2_set_subdevdata(&priv->subdev, p); | ||
140 | strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE); | ||
141 | |||
142 | ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev); | ||
170 | if (ret) | 143 | if (ret) |
171 | kfree(priv); | 144 | goto evdrs; |
145 | |||
146 | return ret; | ||
172 | 147 | ||
148 | evdrs: | ||
149 | icd->ops = NULL; | ||
150 | platform_set_drvdata(pdev, NULL); | ||
151 | kfree(priv); | ||
173 | return ret; | 152 | return ret; |
174 | } | 153 | } |
175 | 154 | ||
176 | static int soc_camera_platform_remove(struct platform_device *pdev) | 155 | static int soc_camera_platform_remove(struct platform_device *pdev) |
177 | { | 156 | { |
178 | struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev); | 157 | struct soc_camera_platform_priv *priv = get_priv(pdev); |
158 | struct soc_camera_platform_info *p = pdev->dev.platform_data; | ||
159 | struct soc_camera_device *icd = to_soc_camera_dev(p->dev); | ||
179 | 160 | ||
180 | soc_camera_device_unregister(&priv->icd); | 161 | v4l2_device_unregister_subdev(&priv->subdev); |
162 | icd->ops = NULL; | ||
163 | platform_set_drvdata(pdev, NULL); | ||
181 | kfree(priv); | 164 | kfree(priv); |
182 | return 0; | 165 | return 0; |
183 | } | 166 | } |
@@ -185,6 +168,7 @@ static int soc_camera_platform_remove(struct platform_device *pdev) | |||
185 | static struct platform_driver soc_camera_platform_driver = { | 168 | static struct platform_driver soc_camera_platform_driver = { |
186 | .driver = { | 169 | .driver = { |
187 | .name = "soc_camera_platform", | 170 | .name = "soc_camera_platform", |
171 | .owner = THIS_MODULE, | ||
188 | }, | 172 | }, |
189 | .probe = soc_camera_platform_probe, | 173 | .probe = soc_camera_platform_probe, |
190 | .remove = soc_camera_platform_remove, | 174 | .remove = soc_camera_platform_remove, |
@@ -206,3 +190,4 @@ module_exit(soc_camera_platform_module_exit); | |||
206 | MODULE_DESCRIPTION("SoC Camera Platform driver"); | 190 | MODULE_DESCRIPTION("SoC Camera Platform driver"); |
207 | MODULE_AUTHOR("Magnus Damm"); | 191 | MODULE_AUTHOR("Magnus Damm"); |
208 | MODULE_LICENSE("GPL v2"); | 192 | MODULE_LICENSE("GPL v2"); |
193 | MODULE_ALIAS("platform:soc_camera_platform"); | ||
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2816f1839230..aba92e2313d8 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "tuner-simple.h" | 29 | #include "tuner-simple.h" |
30 | #include "tda9887.h" | 30 | #include "tda9887.h" |
31 | #include "xc5000.h" | 31 | #include "xc5000.h" |
32 | #include "tda18271.h" | ||
32 | 33 | ||
33 | #define UNSET (-1U) | 34 | #define UNSET (-1U) |
34 | 35 | ||
@@ -420,6 +421,17 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
420 | goto attach_failed; | 421 | goto attach_failed; |
421 | break; | 422 | break; |
422 | } | 423 | } |
424 | case TUNER_NXP_TDA18271: | ||
425 | { | ||
426 | struct tda18271_config cfg = { | ||
427 | .config = t->config, | ||
428 | }; | ||
429 | |||
430 | if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr, | ||
431 | t->i2c->adapter, &cfg)) | ||
432 | goto attach_failed; | ||
433 | break; | ||
434 | } | ||
423 | default: | 435 | default: |
424 | if (!dvb_attach(simple_tuner_attach, &t->fe, | 436 | if (!dvb_attach(simple_tuner_attach, &t->fe, |
425 | t->i2c->adapter, t->i2c->addr, t->type)) | 437 | t->i2c->adapter, t->i2c->addr, t->type)) |
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 3750f7fadb12..244372627df2 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c | |||
@@ -31,7 +31,10 @@ | |||
31 | #include <linux/i2c.h> | 31 | #include <linux/i2c.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/videodev2.h> | 33 | #include <linux/videodev2.h> |
34 | #include <media/v4l2-int-device.h> | 34 | |
35 | #include <media/v4l2-device.h> | ||
36 | #include <media/v4l2-common.h> | ||
37 | #include <media/v4l2-chip-ident.h> | ||
35 | #include <media/tvp514x.h> | 38 | #include <media/tvp514x.h> |
36 | 39 | ||
37 | #include "tvp514x_regs.h" | 40 | #include "tvp514x_regs.h" |
@@ -49,15 +52,11 @@ static int debug; | |||
49 | module_param(debug, bool, 0644); | 52 | module_param(debug, bool, 0644); |
50 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | 53 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); |
51 | 54 | ||
52 | #define dump_reg(client, reg, val) \ | 55 | MODULE_AUTHOR("Texas Instruments"); |
53 | do { \ | 56 | MODULE_DESCRIPTION("TVP514X linux decoder driver"); |
54 | val = tvp514x_read_reg(client, reg); \ | 57 | MODULE_LICENSE("GPL"); |
55 | v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \ | ||
56 | } while (0) | ||
57 | 58 | ||
58 | /** | 59 | /* enum tvp514x_std - enum for supported standards */ |
59 | * enum tvp514x_std - enum for supported standards | ||
60 | */ | ||
61 | enum tvp514x_std { | 60 | enum tvp514x_std { |
62 | STD_NTSC_MJ = 0, | 61 | STD_NTSC_MJ = 0, |
63 | STD_PAL_BDGHIN, | 62 | STD_PAL_BDGHIN, |
@@ -65,14 +64,6 @@ enum tvp514x_std { | |||
65 | }; | 64 | }; |
66 | 65 | ||
67 | /** | 66 | /** |
68 | * enum tvp514x_state - enum for different decoder states | ||
69 | */ | ||
70 | enum tvp514x_state { | ||
71 | STATE_NOT_DETECTED, | ||
72 | STATE_DETECTED | ||
73 | }; | ||
74 | |||
75 | /** | ||
76 | * struct tvp514x_std_info - Structure to store standard informations | 67 | * struct tvp514x_std_info - Structure to store standard informations |
77 | * @width: Line width in pixels | 68 | * @width: Line width in pixels |
78 | * @height:Number of active lines | 69 | * @height:Number of active lines |
@@ -89,33 +80,27 @@ struct tvp514x_std_info { | |||
89 | static struct tvp514x_reg tvp514x_reg_list_default[0x40]; | 80 | static struct tvp514x_reg tvp514x_reg_list_default[0x40]; |
90 | /** | 81 | /** |
91 | * struct tvp514x_decoder - TVP5146/47 decoder object | 82 | * struct tvp514x_decoder - TVP5146/47 decoder object |
92 | * @v4l2_int_device: Slave handle | 83 | * @sd: Subdevice Slave handle |
93 | * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device | ||
94 | * @tvp514x_regs: copy of hw's regs with preset values. | 84 | * @tvp514x_regs: copy of hw's regs with preset values. |
95 | * @pdata: Board specific | 85 | * @pdata: Board specific |
96 | * @client: I2C client data | ||
97 | * @id: Entry from I2C table | ||
98 | * @ver: Chip version | 86 | * @ver: Chip version |
99 | * @state: TVP5146/47 decoder state - detected or not-detected | 87 | * @streaming: TVP5146/47 decoder streaming - enabled or disabled. |
100 | * @pix: Current pixel format | 88 | * @pix: Current pixel format |
101 | * @num_fmts: Number of formats | 89 | * @num_fmts: Number of formats |
102 | * @fmt_list: Format list | 90 | * @fmt_list: Format list |
103 | * @current_std: Current standard | 91 | * @current_std: Current standard |
104 | * @num_stds: Number of standards | 92 | * @num_stds: Number of standards |
105 | * @std_list: Standards list | 93 | * @std_list: Standards list |
106 | * @route: input and output routing at chip level | 94 | * @input: Input routing at chip level |
95 | * @output: Output routing at chip level | ||
107 | */ | 96 | */ |
108 | struct tvp514x_decoder { | 97 | struct tvp514x_decoder { |
109 | struct v4l2_int_device v4l2_int_device; | 98 | struct v4l2_subdev sd; |
110 | struct v4l2_int_slave tvp514x_slave; | ||
111 | struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)]; | 99 | struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)]; |
112 | const struct tvp514x_platform_data *pdata; | 100 | const struct tvp514x_platform_data *pdata; |
113 | struct i2c_client *client; | ||
114 | |||
115 | struct i2c_device_id *id; | ||
116 | 101 | ||
117 | int ver; | 102 | int ver; |
118 | enum tvp514x_state state; | 103 | int streaming; |
119 | 104 | ||
120 | struct v4l2_pix_format pix; | 105 | struct v4l2_pix_format pix; |
121 | int num_fmts; | 106 | int num_fmts; |
@@ -124,15 +109,18 @@ struct tvp514x_decoder { | |||
124 | enum tvp514x_std current_std; | 109 | enum tvp514x_std current_std; |
125 | int num_stds; | 110 | int num_stds; |
126 | struct tvp514x_std_info *std_list; | 111 | struct tvp514x_std_info *std_list; |
127 | 112 | /* Input and Output Routing parameters */ | |
128 | struct v4l2_routing route; | 113 | u32 input; |
114 | u32 output; | ||
129 | }; | 115 | }; |
130 | 116 | ||
131 | /* TVP514x default register values */ | 117 | /* TVP514x default register values */ |
132 | static struct tvp514x_reg tvp514x_reg_list_default[] = { | 118 | static struct tvp514x_reg tvp514x_reg_list_default[] = { |
133 | {TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */ | 119 | /* Composite selected */ |
120 | {TOK_WRITE, REG_INPUT_SEL, 0x05}, | ||
134 | {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F}, | 121 | {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F}, |
135 | {TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */ | 122 | /* Auto mode */ |
123 | {TOK_WRITE, REG_VIDEO_STD, 0x00}, | ||
136 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, | 124 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, |
137 | {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F}, | 125 | {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F}, |
138 | {TOK_WRITE, REG_COLOR_KILLER, 0x10}, | 126 | {TOK_WRITE, REG_COLOR_KILLER, 0x10}, |
@@ -145,53 +133,74 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = { | |||
145 | {TOK_WRITE, REG_HUE, 0x00}, | 133 | {TOK_WRITE, REG_HUE, 0x00}, |
146 | {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00}, | 134 | {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00}, |
147 | {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E}, | 135 | {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E}, |
148 | {TOK_SKIP, 0x0F, 0x00}, /* Reserved */ | 136 | /* Reserved */ |
137 | {TOK_SKIP, 0x0F, 0x00}, | ||
149 | {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80}, | 138 | {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80}, |
150 | {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80}, | 139 | {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80}, |
151 | {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80}, | 140 | {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80}, |
152 | {TOK_SKIP, 0x13, 0x00}, /* Reserved */ | 141 | /* Reserved */ |
142 | {TOK_SKIP, 0x13, 0x00}, | ||
153 | {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80}, | 143 | {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80}, |
154 | {TOK_SKIP, 0x15, 0x00}, /* Reserved */ | 144 | /* Reserved */ |
155 | {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, /* NTSC timing */ | 145 | {TOK_SKIP, 0x15, 0x00}, |
146 | /* NTSC timing */ | ||
147 | {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, | ||
156 | {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00}, | 148 | {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00}, |
157 | {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25}, | 149 | {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25}, |
158 | {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03}, | 150 | {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03}, |
159 | {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, /* NTSC timing */ | 151 | /* NTSC timing */ |
152 | {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, | ||
160 | {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00}, | 153 | {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00}, |
161 | {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40}, | 154 | {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40}, |
162 | {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00}, | 155 | {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00}, |
163 | {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, /* NTSC timing */ | 156 | /* NTSC timing */ |
157 | {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, | ||
164 | {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00}, | 158 | {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00}, |
165 | {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07}, | 159 | {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07}, |
166 | {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00}, | 160 | {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00}, |
167 | {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, /* NTSC timing */ | 161 | /* NTSC timing */ |
162 | {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, | ||
168 | {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00}, | 163 | {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00}, |
169 | {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15}, | 164 | {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15}, |
170 | {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00}, | 165 | {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00}, |
171 | {TOK_SKIP, 0x26, 0x00}, /* Reserved */ | 166 | /* Reserved */ |
172 | {TOK_SKIP, 0x27, 0x00}, /* Reserved */ | 167 | {TOK_SKIP, 0x26, 0x00}, |
168 | /* Reserved */ | ||
169 | {TOK_SKIP, 0x27, 0x00}, | ||
173 | {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC}, | 170 | {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC}, |
174 | {TOK_SKIP, 0x29, 0x00}, /* Reserved */ | 171 | /* Reserved */ |
172 | {TOK_SKIP, 0x29, 0x00}, | ||
175 | {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00}, | 173 | {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00}, |
176 | {TOK_SKIP, 0x2B, 0x00}, /* Reserved */ | 174 | /* Reserved */ |
175 | {TOK_SKIP, 0x2B, 0x00}, | ||
177 | {TOK_SKIP, REG_SCART_DELAY, 0x00}, | 176 | {TOK_SKIP, REG_SCART_DELAY, 0x00}, |
178 | {TOK_SKIP, REG_CTI_DELAY, 0x00}, | 177 | {TOK_SKIP, REG_CTI_DELAY, 0x00}, |
179 | {TOK_SKIP, REG_CTI_CONTROL, 0x00}, | 178 | {TOK_SKIP, REG_CTI_CONTROL, 0x00}, |
180 | {TOK_SKIP, 0x2F, 0x00}, /* Reserved */ | 179 | /* Reserved */ |
181 | {TOK_SKIP, 0x30, 0x00}, /* Reserved */ | 180 | {TOK_SKIP, 0x2F, 0x00}, |
182 | {TOK_SKIP, 0x31, 0x00}, /* Reserved */ | 181 | /* Reserved */ |
183 | {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, /* HS, VS active high */ | 182 | {TOK_SKIP, 0x30, 0x00}, |
184 | {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, /* 10-bit BT.656 */ | 183 | /* Reserved */ |
185 | {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, /* Enable clk & data */ | 184 | {TOK_SKIP, 0x31, 0x00}, |
186 | {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, /* Enable AVID & FLD */ | 185 | /* HS, VS active high */ |
187 | {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, /* Enable VS & HS */ | 186 | {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, |
187 | /* 10-bit BT.656 */ | ||
188 | {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, | ||
189 | /* Enable clk & data */ | ||
190 | {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, | ||
191 | /* Enable AVID & FLD */ | ||
192 | {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, | ||
193 | /* Enable VS & HS */ | ||
194 | {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, | ||
188 | {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF}, | 195 | {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF}, |
189 | {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF}, | 196 | {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF}, |
190 | {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, /* Clear status */ | 197 | /* Clear status */ |
198 | {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, | ||
191 | {TOK_TERM, 0, 0}, | 199 | {TOK_TERM, 0, 0}, |
192 | }; | 200 | }; |
193 | 201 | ||
194 | /* List of image formats supported by TVP5146/47 decoder | 202 | /** |
203 | * List of image formats supported by TVP5146/47 decoder | ||
195 | * Currently we are using 8 bit mode only, but can be | 204 | * Currently we are using 8 bit mode only, but can be |
196 | * extended to 10/20 bit mode. | 205 | * extended to 10/20 bit mode. |
197 | */ | 206 | */ |
@@ -205,7 +214,7 @@ static const struct v4l2_fmtdesc tvp514x_fmt_list[] = { | |||
205 | }, | 214 | }, |
206 | }; | 215 | }; |
207 | 216 | ||
208 | /* | 217 | /** |
209 | * Supported standards - | 218 | * Supported standards - |
210 | * | 219 | * |
211 | * Currently supports two standards only, need to add support for rest of the | 220 | * Currently supports two standards only, need to add support for rest of the |
@@ -240,35 +249,32 @@ static struct tvp514x_std_info tvp514x_std_list[] = { | |||
240 | }, | 249 | }, |
241 | /* Standard: need to add for additional standard */ | 250 | /* Standard: need to add for additional standard */ |
242 | }; | 251 | }; |
243 | /* | ||
244 | * Control structure for Auto Gain | ||
245 | * This is temporary data, will get replaced once | ||
246 | * v4l2_ctrl_query_fill supports it. | ||
247 | */ | ||
248 | static const struct v4l2_queryctrl tvp514x_autogain_ctrl = { | ||
249 | .id = V4L2_CID_AUTOGAIN, | ||
250 | .name = "Gain, Automatic", | ||
251 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
252 | .minimum = 0, | ||
253 | .maximum = 1, | ||
254 | .step = 1, | ||
255 | .default_value = 1, | ||
256 | }; | ||
257 | 252 | ||
258 | /* | 253 | |
259 | * Read a value from a register in an TVP5146/47 decoder device. | 254 | static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd) |
255 | { | ||
256 | return container_of(sd, struct tvp514x_decoder, sd); | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
261 | * tvp514x_read_reg() - Read a value from a register in an TVP5146/47. | ||
262 | * @sd: ptr to v4l2_subdev struct | ||
263 | * @reg: TVP5146/47 register address | ||
264 | * | ||
260 | * Returns value read if successful, or non-zero (-1) otherwise. | 265 | * Returns value read if successful, or non-zero (-1) otherwise. |
261 | */ | 266 | */ |
262 | static int tvp514x_read_reg(struct i2c_client *client, u8 reg) | 267 | static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg) |
263 | { | 268 | { |
264 | int err; | 269 | int err, retry = 0; |
265 | int retry = 0; | 270 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
271 | |||
266 | read_again: | 272 | read_again: |
267 | 273 | ||
268 | err = i2c_smbus_read_byte_data(client, reg); | 274 | err = i2c_smbus_read_byte_data(client, reg); |
269 | if (err == -1) { | 275 | if (err == -1) { |
270 | if (retry <= I2C_RETRY_COUNT) { | 276 | if (retry <= I2C_RETRY_COUNT) { |
271 | v4l_warn(client, "Read: retry ... %d\n", retry); | 277 | v4l2_warn(sd, "Read: retry ... %d\n", retry); |
272 | retry++; | 278 | retry++; |
273 | msleep_interruptible(10); | 279 | msleep_interruptible(10); |
274 | goto read_again; | 280 | goto read_again; |
@@ -278,20 +284,39 @@ read_again: | |||
278 | return err; | 284 | return err; |
279 | } | 285 | } |
280 | 286 | ||
281 | /* | 287 | /** |
288 | * dump_reg() - dump the register content of TVP5146/47. | ||
289 | * @sd: ptr to v4l2_subdev struct | ||
290 | * @reg: TVP5146/47 register address | ||
291 | */ | ||
292 | static void dump_reg(struct v4l2_subdev *sd, u8 reg) | ||
293 | { | ||
294 | u32 val; | ||
295 | |||
296 | val = tvp514x_read_reg(sd, reg); | ||
297 | v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val); | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * tvp514x_write_reg() - Write a value to a register in TVP5146/47 | ||
302 | * @sd: ptr to v4l2_subdev struct | ||
303 | * @reg: TVP5146/47 register address | ||
304 | * @val: value to be written to the register | ||
305 | * | ||
282 | * Write a value to a register in an TVP5146/47 decoder device. | 306 | * Write a value to a register in an TVP5146/47 decoder device. |
283 | * Returns zero if successful, or non-zero otherwise. | 307 | * Returns zero if successful, or non-zero otherwise. |
284 | */ | 308 | */ |
285 | static int tvp514x_write_reg(struct i2c_client *client, u8 reg, u8 val) | 309 | static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val) |
286 | { | 310 | { |
287 | int err; | 311 | int err, retry = 0; |
288 | int retry = 0; | 312 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
313 | |||
289 | write_again: | 314 | write_again: |
290 | 315 | ||
291 | err = i2c_smbus_write_byte_data(client, reg, val); | 316 | err = i2c_smbus_write_byte_data(client, reg, val); |
292 | if (err) { | 317 | if (err) { |
293 | if (retry <= I2C_RETRY_COUNT) { | 318 | if (retry <= I2C_RETRY_COUNT) { |
294 | v4l_warn(client, "Write: retry ... %d\n", retry); | 319 | v4l2_warn(sd, "Write: retry ... %d\n", retry); |
295 | retry++; | 320 | retry++; |
296 | msleep_interruptible(10); | 321 | msleep_interruptible(10); |
297 | goto write_again; | 322 | goto write_again; |
@@ -301,17 +326,19 @@ write_again: | |||
301 | return err; | 326 | return err; |
302 | } | 327 | } |
303 | 328 | ||
304 | /* | 329 | /** |
305 | * tvp514x_write_regs : Initializes a list of TVP5146/47 registers | 330 | * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers |
331 | * @sd: ptr to v4l2_subdev struct | ||
332 | * @reglist: list of TVP5146/47 registers and values | ||
333 | * | ||
334 | * Initializes a list of TVP5146/47 registers:- | ||
306 | * if token is TOK_TERM, then entire write operation terminates | 335 | * if token is TOK_TERM, then entire write operation terminates |
307 | * if token is TOK_DELAY, then a delay of 'val' msec is introduced | 336 | * if token is TOK_DELAY, then a delay of 'val' msec is introduced |
308 | * if token is TOK_SKIP, then the register write is skipped | 337 | * if token is TOK_SKIP, then the register write is skipped |
309 | * if token is TOK_WRITE, then the register write is performed | 338 | * if token is TOK_WRITE, then the register write is performed |
310 | * | ||
311 | * reglist - list of registers to be written | ||
312 | * Returns zero if successful, or non-zero otherwise. | 339 | * Returns zero if successful, or non-zero otherwise. |
313 | */ | 340 | */ |
314 | static int tvp514x_write_regs(struct i2c_client *client, | 341 | static int tvp514x_write_regs(struct v4l2_subdev *sd, |
315 | const struct tvp514x_reg reglist[]) | 342 | const struct tvp514x_reg reglist[]) |
316 | { | 343 | { |
317 | int err; | 344 | int err; |
@@ -326,31 +353,33 @@ static int tvp514x_write_regs(struct i2c_client *client, | |||
326 | if (next->token == TOK_SKIP) | 353 | if (next->token == TOK_SKIP) |
327 | continue; | 354 | continue; |
328 | 355 | ||
329 | err = tvp514x_write_reg(client, next->reg, (u8) next->val); | 356 | err = tvp514x_write_reg(sd, next->reg, (u8) next->val); |
330 | if (err) { | 357 | if (err) { |
331 | v4l_err(client, "Write failed. Err[%d]\n", err); | 358 | v4l2_err(sd, "Write failed. Err[%d]\n", err); |
332 | return err; | 359 | return err; |
333 | } | 360 | } |
334 | } | 361 | } |
335 | return 0; | 362 | return 0; |
336 | } | 363 | } |
337 | 364 | ||
338 | /* | 365 | /** |
339 | * tvp514x_get_current_std: | 366 | * tvp514x_get_current_std() : Get the current standard detected by TVP5146/47 |
340 | * Returns the current standard detected by TVP5146/47 | 367 | * @sd: ptr to v4l2_subdev struct |
368 | * | ||
369 | * Get current standard detected by TVP5146/47, STD_INVALID if there is no | ||
370 | * standard detected. | ||
341 | */ | 371 | */ |
342 | static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder | 372 | static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd) |
343 | *decoder) | ||
344 | { | 373 | { |
345 | u8 std, std_status; | 374 | u8 std, std_status; |
346 | 375 | ||
347 | std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD); | 376 | std = tvp514x_read_reg(sd, REG_VIDEO_STD); |
348 | if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) { | 377 | if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) |
349 | /* use the standard status register */ | 378 | /* use the standard status register */ |
350 | std_status = tvp514x_read_reg(decoder->client, | 379 | std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS); |
351 | REG_VIDEO_STD_STATUS); | 380 | else |
352 | } else | 381 | /* use the standard register itself */ |
353 | std_status = std; /* use the standard register itself */ | 382 | std_status = std; |
354 | 383 | ||
355 | switch (std_status & VIDEO_STD_MASK) { | 384 | switch (std_status & VIDEO_STD_MASK) { |
356 | case VIDEO_STD_NTSC_MJ_BIT: | 385 | case VIDEO_STD_NTSC_MJ_BIT: |
@@ -366,94 +395,99 @@ static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder | |||
366 | return STD_INVALID; | 395 | return STD_INVALID; |
367 | } | 396 | } |
368 | 397 | ||
369 | /* | 398 | /* TVP5146/47 register dump function */ |
370 | * TVP5146/47 register dump function | 399 | static void tvp514x_reg_dump(struct v4l2_subdev *sd) |
371 | */ | ||
372 | static void tvp514x_reg_dump(struct tvp514x_decoder *decoder) | ||
373 | { | 400 | { |
374 | u8 value; | 401 | dump_reg(sd, REG_INPUT_SEL); |
375 | 402 | dump_reg(sd, REG_AFE_GAIN_CTRL); | |
376 | dump_reg(decoder->client, REG_INPUT_SEL, value); | 403 | dump_reg(sd, REG_VIDEO_STD); |
377 | dump_reg(decoder->client, REG_AFE_GAIN_CTRL, value); | 404 | dump_reg(sd, REG_OPERATION_MODE); |
378 | dump_reg(decoder->client, REG_VIDEO_STD, value); | 405 | dump_reg(sd, REG_COLOR_KILLER); |
379 | dump_reg(decoder->client, REG_OPERATION_MODE, value); | 406 | dump_reg(sd, REG_LUMA_CONTROL1); |
380 | dump_reg(decoder->client, REG_COLOR_KILLER, value); | 407 | dump_reg(sd, REG_LUMA_CONTROL2); |
381 | dump_reg(decoder->client, REG_LUMA_CONTROL1, value); | 408 | dump_reg(sd, REG_LUMA_CONTROL3); |
382 | dump_reg(decoder->client, REG_LUMA_CONTROL2, value); | 409 | dump_reg(sd, REG_BRIGHTNESS); |
383 | dump_reg(decoder->client, REG_LUMA_CONTROL3, value); | 410 | dump_reg(sd, REG_CONTRAST); |
384 | dump_reg(decoder->client, REG_BRIGHTNESS, value); | 411 | dump_reg(sd, REG_SATURATION); |
385 | dump_reg(decoder->client, REG_CONTRAST, value); | 412 | dump_reg(sd, REG_HUE); |
386 | dump_reg(decoder->client, REG_SATURATION, value); | 413 | dump_reg(sd, REG_CHROMA_CONTROL1); |
387 | dump_reg(decoder->client, REG_HUE, value); | 414 | dump_reg(sd, REG_CHROMA_CONTROL2); |
388 | dump_reg(decoder->client, REG_CHROMA_CONTROL1, value); | 415 | dump_reg(sd, REG_COMP_PR_SATURATION); |
389 | dump_reg(decoder->client, REG_CHROMA_CONTROL2, value); | 416 | dump_reg(sd, REG_COMP_Y_CONTRAST); |
390 | dump_reg(decoder->client, REG_COMP_PR_SATURATION, value); | 417 | dump_reg(sd, REG_COMP_PB_SATURATION); |
391 | dump_reg(decoder->client, REG_COMP_Y_CONTRAST, value); | 418 | dump_reg(sd, REG_COMP_Y_BRIGHTNESS); |
392 | dump_reg(decoder->client, REG_COMP_PB_SATURATION, value); | 419 | dump_reg(sd, REG_AVID_START_PIXEL_LSB); |
393 | dump_reg(decoder->client, REG_COMP_Y_BRIGHTNESS, value); | 420 | dump_reg(sd, REG_AVID_START_PIXEL_MSB); |
394 | dump_reg(decoder->client, REG_AVID_START_PIXEL_LSB, value); | 421 | dump_reg(sd, REG_AVID_STOP_PIXEL_LSB); |
395 | dump_reg(decoder->client, REG_AVID_START_PIXEL_MSB, value); | 422 | dump_reg(sd, REG_AVID_STOP_PIXEL_MSB); |
396 | dump_reg(decoder->client, REG_AVID_STOP_PIXEL_LSB, value); | 423 | dump_reg(sd, REG_HSYNC_START_PIXEL_LSB); |
397 | dump_reg(decoder->client, REG_AVID_STOP_PIXEL_MSB, value); | 424 | dump_reg(sd, REG_HSYNC_START_PIXEL_MSB); |
398 | dump_reg(decoder->client, REG_HSYNC_START_PIXEL_LSB, value); | 425 | dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB); |
399 | dump_reg(decoder->client, REG_HSYNC_START_PIXEL_MSB, value); | 426 | dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB); |
400 | dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_LSB, value); | 427 | dump_reg(sd, REG_VSYNC_START_LINE_LSB); |
401 | dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_MSB, value); | 428 | dump_reg(sd, REG_VSYNC_START_LINE_MSB); |
402 | dump_reg(decoder->client, REG_VSYNC_START_LINE_LSB, value); | 429 | dump_reg(sd, REG_VSYNC_STOP_LINE_LSB); |
403 | dump_reg(decoder->client, REG_VSYNC_START_LINE_MSB, value); | 430 | dump_reg(sd, REG_VSYNC_STOP_LINE_MSB); |
404 | dump_reg(decoder->client, REG_VSYNC_STOP_LINE_LSB, value); | 431 | dump_reg(sd, REG_VBLK_START_LINE_LSB); |
405 | dump_reg(decoder->client, REG_VSYNC_STOP_LINE_MSB, value); | 432 | dump_reg(sd, REG_VBLK_START_LINE_MSB); |
406 | dump_reg(decoder->client, REG_VBLK_START_LINE_LSB, value); | 433 | dump_reg(sd, REG_VBLK_STOP_LINE_LSB); |
407 | dump_reg(decoder->client, REG_VBLK_START_LINE_MSB, value); | 434 | dump_reg(sd, REG_VBLK_STOP_LINE_MSB); |
408 | dump_reg(decoder->client, REG_VBLK_STOP_LINE_LSB, value); | 435 | dump_reg(sd, REG_SYNC_CONTROL); |
409 | dump_reg(decoder->client, REG_VBLK_STOP_LINE_MSB, value); | 436 | dump_reg(sd, REG_OUTPUT_FORMATTER1); |
410 | dump_reg(decoder->client, REG_SYNC_CONTROL, value); | 437 | dump_reg(sd, REG_OUTPUT_FORMATTER2); |
411 | dump_reg(decoder->client, REG_OUTPUT_FORMATTER1, value); | 438 | dump_reg(sd, REG_OUTPUT_FORMATTER3); |
412 | dump_reg(decoder->client, REG_OUTPUT_FORMATTER2, value); | 439 | dump_reg(sd, REG_OUTPUT_FORMATTER4); |
413 | dump_reg(decoder->client, REG_OUTPUT_FORMATTER3, value); | 440 | dump_reg(sd, REG_OUTPUT_FORMATTER5); |
414 | dump_reg(decoder->client, REG_OUTPUT_FORMATTER4, value); | 441 | dump_reg(sd, REG_OUTPUT_FORMATTER6); |
415 | dump_reg(decoder->client, REG_OUTPUT_FORMATTER5, value); | 442 | dump_reg(sd, REG_CLEAR_LOST_LOCK); |
416 | dump_reg(decoder->client, REG_OUTPUT_FORMATTER6, value); | ||
417 | dump_reg(decoder->client, REG_CLEAR_LOST_LOCK, value); | ||
418 | } | 443 | } |
419 | 444 | ||
420 | /* | 445 | /** |
421 | * Configure the TVP5146/47 with the current register settings | 446 | * tvp514x_configure() - Configure the TVP5146/47 registers |
447 | * @sd: ptr to v4l2_subdev struct | ||
448 | * @decoder: ptr to tvp514x_decoder structure | ||
449 | * | ||
422 | * Returns zero if successful, or non-zero otherwise. | 450 | * Returns zero if successful, or non-zero otherwise. |
423 | */ | 451 | */ |
424 | static int tvp514x_configure(struct tvp514x_decoder *decoder) | 452 | static int tvp514x_configure(struct v4l2_subdev *sd, |
453 | struct tvp514x_decoder *decoder) | ||
425 | { | 454 | { |
426 | int err; | 455 | int err; |
427 | 456 | ||
428 | /* common register initialization */ | 457 | /* common register initialization */ |
429 | err = | 458 | err = |
430 | tvp514x_write_regs(decoder->client, decoder->tvp514x_regs); | 459 | tvp514x_write_regs(sd, decoder->tvp514x_regs); |
431 | if (err) | 460 | if (err) |
432 | return err; | 461 | return err; |
433 | 462 | ||
434 | if (debug) | 463 | if (debug) |
435 | tvp514x_reg_dump(decoder); | 464 | tvp514x_reg_dump(sd); |
436 | 465 | ||
437 | return 0; | 466 | return 0; |
438 | } | 467 | } |
439 | 468 | ||
440 | /* | 469 | /** |
441 | * Detect if an tvp514x is present, and if so which revision. | 470 | * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision. |
471 | * @sd: pointer to standard V4L2 sub-device structure | ||
472 | * @decoder: pointer to tvp514x_decoder structure | ||
473 | * | ||
442 | * A device is considered to be detected if the chip ID (LSB and MSB) | 474 | * A device is considered to be detected if the chip ID (LSB and MSB) |
443 | * registers match the expected values. | 475 | * registers match the expected values. |
444 | * Any value of the rom version register is accepted. | 476 | * Any value of the rom version register is accepted. |
445 | * Returns ENODEV error number if no device is detected, or zero | 477 | * Returns ENODEV error number if no device is detected, or zero |
446 | * if a device is detected. | 478 | * if a device is detected. |
447 | */ | 479 | */ |
448 | static int tvp514x_detect(struct tvp514x_decoder *decoder) | 480 | static int tvp514x_detect(struct v4l2_subdev *sd, |
481 | struct tvp514x_decoder *decoder) | ||
449 | { | 482 | { |
450 | u8 chip_id_msb, chip_id_lsb, rom_ver; | 483 | u8 chip_id_msb, chip_id_lsb, rom_ver; |
484 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
451 | 485 | ||
452 | chip_id_msb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_MSB); | 486 | chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB); |
453 | chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB); | 487 | chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB); |
454 | rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION); | 488 | rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION); |
455 | 489 | ||
456 | v4l_dbg(1, debug, decoder->client, | 490 | v4l2_dbg(1, debug, sd, |
457 | "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n", | 491 | "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n", |
458 | chip_id_msb, chip_id_lsb, rom_ver); | 492 | chip_id_msb, chip_id_lsb, rom_ver); |
459 | if ((chip_id_msb != TVP514X_CHIP_ID_MSB) | 493 | if ((chip_id_msb != TVP514X_CHIP_ID_MSB) |
@@ -462,38 +496,30 @@ static int tvp514x_detect(struct tvp514x_decoder *decoder) | |||
462 | /* We didn't read the values we expected, so this must not be | 496 | /* We didn't read the values we expected, so this must not be |
463 | * an TVP5146/47. | 497 | * an TVP5146/47. |
464 | */ | 498 | */ |
465 | v4l_err(decoder->client, | 499 | v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n", |
466 | "chip id mismatch msb:0x%x lsb:0x%x\n", | 500 | chip_id_msb, chip_id_lsb); |
467 | chip_id_msb, chip_id_lsb); | ||
468 | return -ENODEV; | 501 | return -ENODEV; |
469 | } | 502 | } |
470 | 503 | ||
471 | decoder->ver = rom_ver; | 504 | decoder->ver = rom_ver; |
472 | decoder->state = STATE_DETECTED; | ||
473 | 505 | ||
474 | v4l_info(decoder->client, | 506 | v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n", |
475 | "%s found at 0x%x (%s)\n", decoder->client->name, | 507 | client->name, decoder->ver, |
476 | decoder->client->addr << 1, | 508 | client->addr << 1, client->adapter->name); |
477 | decoder->client->adapter->name); | ||
478 | return 0; | 509 | return 0; |
479 | } | 510 | } |
480 | 511 | ||
481 | /* | ||
482 | * Following are decoder interface functions implemented by | ||
483 | * TVP5146/47 decoder driver. | ||
484 | */ | ||
485 | |||
486 | /** | 512 | /** |
487 | * ioctl_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl | 513 | * tvp514x_querystd() - V4L2 decoder interface handler for querystd |
488 | * @s: pointer to standard V4L2 device structure | 514 | * @sd: pointer to standard V4L2 sub-device structure |
489 | * @std_id: standard V4L2 std_id ioctl enum | 515 | * @std_id: standard V4L2 std_id ioctl enum |
490 | * | 516 | * |
491 | * Returns the current standard detected by TVP5146/47. If no active input is | 517 | * Returns the current standard detected by TVP5146/47. If no active input is |
492 | * detected, returns -EINVAL | 518 | * detected, returns -EINVAL |
493 | */ | 519 | */ |
494 | static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id) | 520 | static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) |
495 | { | 521 | { |
496 | struct tvp514x_decoder *decoder = s->priv; | 522 | struct tvp514x_decoder *decoder = to_decoder(sd); |
497 | enum tvp514x_std current_std; | 523 | enum tvp514x_std current_std; |
498 | enum tvp514x_input input_sel; | 524 | enum tvp514x_input input_sel; |
499 | u8 sync_lock_status, lock_mask; | 525 | u8 sync_lock_status, lock_mask; |
@@ -502,11 +528,11 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id) | |||
502 | return -EINVAL; | 528 | return -EINVAL; |
503 | 529 | ||
504 | /* get the current standard */ | 530 | /* get the current standard */ |
505 | current_std = tvp514x_get_current_std(decoder); | 531 | current_std = tvp514x_get_current_std(sd); |
506 | if (current_std == STD_INVALID) | 532 | if (current_std == STD_INVALID) |
507 | return -EINVAL; | 533 | return -EINVAL; |
508 | 534 | ||
509 | input_sel = decoder->route.input; | 535 | input_sel = decoder->input; |
510 | 536 | ||
511 | switch (input_sel) { | 537 | switch (input_sel) { |
512 | case INPUT_CVBS_VI1A: | 538 | case INPUT_CVBS_VI1A: |
@@ -544,42 +570,39 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id) | |||
544 | return -EINVAL; | 570 | return -EINVAL; |
545 | } | 571 | } |
546 | /* check whether signal is locked */ | 572 | /* check whether signal is locked */ |
547 | sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1); | 573 | sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); |
548 | if (lock_mask != (sync_lock_status & lock_mask)) | 574 | if (lock_mask != (sync_lock_status & lock_mask)) |
549 | return -EINVAL; /* No input detected */ | 575 | return -EINVAL; /* No input detected */ |
550 | 576 | ||
551 | decoder->current_std = current_std; | 577 | decoder->current_std = current_std; |
552 | *std_id = decoder->std_list[current_std].standard.id; | 578 | *std_id = decoder->std_list[current_std].standard.id; |
553 | 579 | ||
554 | v4l_dbg(1, debug, decoder->client, "Current STD: %s", | 580 | v4l2_dbg(1, debug, sd, "Current STD: %s", |
555 | decoder->std_list[current_std].standard.name); | 581 | decoder->std_list[current_std].standard.name); |
556 | return 0; | 582 | return 0; |
557 | } | 583 | } |
558 | 584 | ||
559 | /** | 585 | /** |
560 | * ioctl_s_std - V4L2 decoder interface handler for VIDIOC_S_STD ioctl | 586 | * tvp514x_s_std() - V4L2 decoder interface handler for s_std |
561 | * @s: pointer to standard V4L2 device structure | 587 | * @sd: pointer to standard V4L2 sub-device structure |
562 | * @std_id: standard V4L2 v4l2_std_id ioctl enum | 588 | * @std_id: standard V4L2 v4l2_std_id ioctl enum |
563 | * | 589 | * |
564 | * If std_id is supported, sets the requested standard. Otherwise, returns | 590 | * If std_id is supported, sets the requested standard. Otherwise, returns |
565 | * -EINVAL | 591 | * -EINVAL |
566 | */ | 592 | */ |
567 | static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id) | 593 | static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id) |
568 | { | 594 | { |
569 | struct tvp514x_decoder *decoder = s->priv; | 595 | struct tvp514x_decoder *decoder = to_decoder(sd); |
570 | int err, i; | 596 | int err, i; |
571 | 597 | ||
572 | if (std_id == NULL) | ||
573 | return -EINVAL; | ||
574 | |||
575 | for (i = 0; i < decoder->num_stds; i++) | 598 | for (i = 0; i < decoder->num_stds; i++) |
576 | if (*std_id & decoder->std_list[i].standard.id) | 599 | if (std_id & decoder->std_list[i].standard.id) |
577 | break; | 600 | break; |
578 | 601 | ||
579 | if ((i == decoder->num_stds) || (i == STD_INVALID)) | 602 | if ((i == decoder->num_stds) || (i == STD_INVALID)) |
580 | return -EINVAL; | 603 | return -EINVAL; |
581 | 604 | ||
582 | err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD, | 605 | err = tvp514x_write_reg(sd, REG_VIDEO_STD, |
583 | decoder->std_list[i].video_std); | 606 | decoder->std_list[i].video_std); |
584 | if (err) | 607 | if (err) |
585 | return err; | 608 | return err; |
@@ -588,24 +611,26 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id) | |||
588 | decoder->tvp514x_regs[REG_VIDEO_STD].val = | 611 | decoder->tvp514x_regs[REG_VIDEO_STD].val = |
589 | decoder->std_list[i].video_std; | 612 | decoder->std_list[i].video_std; |
590 | 613 | ||
591 | v4l_dbg(1, debug, decoder->client, "Standard set to: %s", | 614 | v4l2_dbg(1, debug, sd, "Standard set to: %s", |
592 | decoder->std_list[i].standard.name); | 615 | decoder->std_list[i].standard.name); |
593 | return 0; | 616 | return 0; |
594 | } | 617 | } |
595 | 618 | ||
596 | /** | 619 | /** |
597 | * ioctl_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl | 620 | * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing |
598 | * @s: pointer to standard V4L2 device structure | 621 | * @sd: pointer to standard V4L2 sub-device structure |
599 | * @index: number of the input | 622 | * @input: input selector for routing the signal |
623 | * @output: output selector for routing the signal | ||
624 | * @config: config value. Not used | ||
600 | * | 625 | * |
601 | * If index is valid, selects the requested input. Otherwise, returns -EINVAL if | 626 | * If index is valid, selects the requested input. Otherwise, returns -EINVAL if |
602 | * the input is not supported or there is no active signal present in the | 627 | * the input is not supported or there is no active signal present in the |
603 | * selected input. | 628 | * selected input. |
604 | */ | 629 | */ |
605 | static int ioctl_s_routing(struct v4l2_int_device *s, | 630 | static int tvp514x_s_routing(struct v4l2_subdev *sd, |
606 | struct v4l2_routing *route) | 631 | u32 input, u32 output, u32 config) |
607 | { | 632 | { |
608 | struct tvp514x_decoder *decoder = s->priv; | 633 | struct tvp514x_decoder *decoder = to_decoder(sd); |
609 | int err; | 634 | int err; |
610 | enum tvp514x_input input_sel; | 635 | enum tvp514x_input input_sel; |
611 | enum tvp514x_output output_sel; | 636 | enum tvp514x_output output_sel; |
@@ -613,20 +638,21 @@ static int ioctl_s_routing(struct v4l2_int_device *s, | |||
613 | u8 sync_lock_status, lock_mask; | 638 | u8 sync_lock_status, lock_mask; |
614 | int try_count = LOCK_RETRY_COUNT; | 639 | int try_count = LOCK_RETRY_COUNT; |
615 | 640 | ||
616 | if ((!route) || (route->input >= INPUT_INVALID) || | 641 | if ((input >= INPUT_INVALID) || |
617 | (route->output >= OUTPUT_INVALID)) | 642 | (output >= OUTPUT_INVALID)) |
618 | return -EINVAL; /* Index out of bound */ | 643 | /* Index out of bound */ |
644 | return -EINVAL; | ||
619 | 645 | ||
620 | input_sel = route->input; | 646 | input_sel = input; |
621 | output_sel = route->output; | 647 | output_sel = output; |
622 | 648 | ||
623 | err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel); | 649 | err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel); |
624 | if (err) | 650 | if (err) |
625 | return err; | 651 | return err; |
626 | 652 | ||
627 | output_sel |= tvp514x_read_reg(decoder->client, | 653 | output_sel |= tvp514x_read_reg(sd, |
628 | REG_OUTPUT_FORMATTER1) & 0x7; | 654 | REG_OUTPUT_FORMATTER1) & 0x7; |
629 | err = tvp514x_write_reg(decoder->client, REG_OUTPUT_FORMATTER1, | 655 | err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1, |
630 | output_sel); | 656 | output_sel); |
631 | if (err) | 657 | if (err) |
632 | return err; | 658 | return err; |
@@ -637,7 +663,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s, | |||
637 | /* Clear status */ | 663 | /* Clear status */ |
638 | msleep(LOCK_RETRY_DELAY); | 664 | msleep(LOCK_RETRY_DELAY); |
639 | err = | 665 | err = |
640 | tvp514x_write_reg(decoder->client, REG_CLEAR_LOST_LOCK, 0x01); | 666 | tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01); |
641 | if (err) | 667 | if (err) |
642 | return err; | 668 | return err; |
643 | 669 | ||
@@ -672,7 +698,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s, | |||
672 | lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | | 698 | lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | |
673 | STATUS_VIRT_SYNC_LOCK_BIT; | 699 | STATUS_VIRT_SYNC_LOCK_BIT; |
674 | break; | 700 | break; |
675 | /*Need to add other interfaces*/ | 701 | /* Need to add other interfaces*/ |
676 | default: | 702 | default: |
677 | return -EINVAL; | 703 | return -EINVAL; |
678 | } | 704 | } |
@@ -682,42 +708,41 @@ static int ioctl_s_routing(struct v4l2_int_device *s, | |||
682 | msleep(LOCK_RETRY_DELAY); | 708 | msleep(LOCK_RETRY_DELAY); |
683 | 709 | ||
684 | /* get the current standard for future reference */ | 710 | /* get the current standard for future reference */ |
685 | current_std = tvp514x_get_current_std(decoder); | 711 | current_std = tvp514x_get_current_std(sd); |
686 | if (current_std == STD_INVALID) | 712 | if (current_std == STD_INVALID) |
687 | continue; | 713 | continue; |
688 | 714 | ||
689 | sync_lock_status = tvp514x_read_reg(decoder->client, | 715 | sync_lock_status = tvp514x_read_reg(sd, |
690 | REG_STATUS1); | 716 | REG_STATUS1); |
691 | if (lock_mask == (sync_lock_status & lock_mask)) | 717 | if (lock_mask == (sync_lock_status & lock_mask)) |
692 | break; /* Input detected */ | 718 | /* Input detected */ |
719 | break; | ||
693 | } | 720 | } |
694 | 721 | ||
695 | if ((current_std == STD_INVALID) || (try_count < 0)) | 722 | if ((current_std == STD_INVALID) || (try_count < 0)) |
696 | return -EINVAL; | 723 | return -EINVAL; |
697 | 724 | ||
698 | decoder->current_std = current_std; | 725 | decoder->current_std = current_std; |
699 | decoder->route.input = route->input; | 726 | decoder->input = input; |
700 | decoder->route.output = route->output; | 727 | decoder->output = output; |
701 | 728 | ||
702 | v4l_dbg(1, debug, decoder->client, | 729 | v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d", |
703 | "Input set to: %d, std : %d", | ||
704 | input_sel, current_std); | 730 | input_sel, current_std); |
705 | 731 | ||
706 | return 0; | 732 | return 0; |
707 | } | 733 | } |
708 | 734 | ||
709 | /** | 735 | /** |
710 | * ioctl_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl | 736 | * tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl |
711 | * @s: pointer to standard V4L2 device structure | 737 | * @sd: pointer to standard V4L2 sub-device structure |
712 | * @qctrl: standard V4L2 v4l2_queryctrl structure | 738 | * @qctrl: standard V4L2 v4l2_queryctrl structure |
713 | * | 739 | * |
714 | * If the requested control is supported, returns the control information. | 740 | * If the requested control is supported, returns the control information. |
715 | * Otherwise, returns -EINVAL if the control is not supported. | 741 | * Otherwise, returns -EINVAL if the control is not supported. |
716 | */ | 742 | */ |
717 | static int | 743 | static int |
718 | ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl) | 744 | tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) |
719 | { | 745 | { |
720 | struct tvp514x_decoder *decoder = s->priv; | ||
721 | int err = -EINVAL; | 746 | int err = -EINVAL; |
722 | 747 | ||
723 | if (qctrl == NULL) | 748 | if (qctrl == NULL) |
@@ -725,13 +750,13 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl) | |||
725 | 750 | ||
726 | switch (qctrl->id) { | 751 | switch (qctrl->id) { |
727 | case V4L2_CID_BRIGHTNESS: | 752 | case V4L2_CID_BRIGHTNESS: |
728 | /* Brightness supported is (0-255), | 753 | /* Brightness supported is (0-255), */ |
729 | */ | ||
730 | err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); | 754 | err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); |
731 | break; | 755 | break; |
732 | case V4L2_CID_CONTRAST: | 756 | case V4L2_CID_CONTRAST: |
733 | case V4L2_CID_SATURATION: | 757 | case V4L2_CID_SATURATION: |
734 | /* Saturation and Contrast supported is - | 758 | /** |
759 | * Saturation and Contrast supported is - | ||
735 | * Contrast: 0 - 255 (Default - 128) | 760 | * Contrast: 0 - 255 (Default - 128) |
736 | * Saturation: 0 - 255 (Default - 128) | 761 | * Saturation: 0 - 255 (Default - 128) |
737 | */ | 762 | */ |
@@ -744,30 +769,27 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl) | |||
744 | err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0); | 769 | err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0); |
745 | break; | 770 | break; |
746 | case V4L2_CID_AUTOGAIN: | 771 | case V4L2_CID_AUTOGAIN: |
747 | /* Autogain is either 0 or 1*/ | 772 | /** |
748 | memcpy(qctrl, &tvp514x_autogain_ctrl, | 773 | * Auto Gain supported is - |
749 | sizeof(struct v4l2_queryctrl)); | 774 | * 0 - 1 (Default - 1) |
750 | err = 0; | 775 | */ |
776 | err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); | ||
751 | break; | 777 | break; |
752 | default: | 778 | default: |
753 | v4l_err(decoder->client, | 779 | v4l2_err(sd, "invalid control id %d\n", qctrl->id); |
754 | "invalid control id %d\n", qctrl->id); | ||
755 | return err; | 780 | return err; |
756 | } | 781 | } |
757 | 782 | ||
758 | v4l_dbg(1, debug, decoder->client, | 783 | v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d", |
759 | "Query Control: %s : Min - %d, Max - %d, Def - %d", | 784 | qctrl->name, qctrl->minimum, qctrl->maximum, |
760 | qctrl->name, | ||
761 | qctrl->minimum, | ||
762 | qctrl->maximum, | ||
763 | qctrl->default_value); | 785 | qctrl->default_value); |
764 | 786 | ||
765 | return err; | 787 | return err; |
766 | } | 788 | } |
767 | 789 | ||
768 | /** | 790 | /** |
769 | * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl | 791 | * tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl |
770 | * @s: pointer to standard V4L2 device structure | 792 | * @sd: pointer to standard V4L2 sub-device structure |
771 | * @ctrl: pointer to v4l2_control structure | 793 | * @ctrl: pointer to v4l2_control structure |
772 | * | 794 | * |
773 | * If the requested control is supported, returns the control's current | 795 | * If the requested control is supported, returns the control's current |
@@ -775,9 +797,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl) | |||
775 | * supported. | 797 | * supported. |
776 | */ | 798 | */ |
777 | static int | 799 | static int |
778 | ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) | 800 | tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
779 | { | 801 | { |
780 | struct tvp514x_decoder *decoder = s->priv; | 802 | struct tvp514x_decoder *decoder = to_decoder(sd); |
781 | 803 | ||
782 | if (ctrl == NULL) | 804 | if (ctrl == NULL) |
783 | return -EINVAL; | 805 | return -EINVAL; |
@@ -811,74 +833,70 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) | |||
811 | 833 | ||
812 | break; | 834 | break; |
813 | default: | 835 | default: |
814 | v4l_err(decoder->client, | 836 | v4l2_err(sd, "invalid control id %d\n", ctrl->id); |
815 | "invalid control id %d\n", ctrl->id); | ||
816 | return -EINVAL; | 837 | return -EINVAL; |
817 | } | 838 | } |
818 | 839 | ||
819 | v4l_dbg(1, debug, decoder->client, | 840 | v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d", |
820 | "Get Control: ID - %d - %d", | ||
821 | ctrl->id, ctrl->value); | 841 | ctrl->id, ctrl->value); |
822 | return 0; | 842 | return 0; |
823 | } | 843 | } |
824 | 844 | ||
825 | /** | 845 | /** |
826 | * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl | 846 | * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl |
827 | * @s: pointer to standard V4L2 device structure | 847 | * @sd: pointer to standard V4L2 sub-device structure |
828 | * @ctrl: pointer to v4l2_control structure | 848 | * @ctrl: pointer to v4l2_control structure |
829 | * | 849 | * |
830 | * If the requested control is supported, sets the control's current | 850 | * If the requested control is supported, sets the control's current |
831 | * value in HW. Otherwise, returns -EINVAL if the control is not supported. | 851 | * value in HW. Otherwise, returns -EINVAL if the control is not supported. |
832 | */ | 852 | */ |
833 | static int | 853 | static int |
834 | ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) | 854 | tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
835 | { | 855 | { |
836 | struct tvp514x_decoder *decoder = s->priv; | 856 | struct tvp514x_decoder *decoder = to_decoder(sd); |
837 | int err = -EINVAL, value; | 857 | int err = -EINVAL, value; |
838 | 858 | ||
839 | if (ctrl == NULL) | 859 | if (ctrl == NULL) |
840 | return err; | 860 | return err; |
841 | 861 | ||
842 | value = (__s32) ctrl->value; | 862 | value = ctrl->value; |
843 | 863 | ||
844 | switch (ctrl->id) { | 864 | switch (ctrl->id) { |
845 | case V4L2_CID_BRIGHTNESS: | 865 | case V4L2_CID_BRIGHTNESS: |
846 | if (ctrl->value < 0 || ctrl->value > 255) { | 866 | if (ctrl->value < 0 || ctrl->value > 255) { |
847 | v4l_err(decoder->client, | 867 | v4l2_err(sd, "invalid brightness setting %d\n", |
848 | "invalid brightness setting %d\n", | ||
849 | ctrl->value); | 868 | ctrl->value); |
850 | return -ERANGE; | 869 | return -ERANGE; |
851 | } | 870 | } |
852 | err = tvp514x_write_reg(decoder->client, REG_BRIGHTNESS, | 871 | err = tvp514x_write_reg(sd, REG_BRIGHTNESS, |
853 | value); | 872 | value); |
854 | if (err) | 873 | if (err) |
855 | return err; | 874 | return err; |
875 | |||
856 | decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; | 876 | decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; |
857 | break; | 877 | break; |
858 | case V4L2_CID_CONTRAST: | 878 | case V4L2_CID_CONTRAST: |
859 | if (ctrl->value < 0 || ctrl->value > 255) { | 879 | if (ctrl->value < 0 || ctrl->value > 255) { |
860 | v4l_err(decoder->client, | 880 | v4l2_err(sd, "invalid contrast setting %d\n", |
861 | "invalid contrast setting %d\n", | ||
862 | ctrl->value); | 881 | ctrl->value); |
863 | return -ERANGE; | 882 | return -ERANGE; |
864 | } | 883 | } |
865 | err = tvp514x_write_reg(decoder->client, REG_CONTRAST, | 884 | err = tvp514x_write_reg(sd, REG_CONTRAST, value); |
866 | value); | ||
867 | if (err) | 885 | if (err) |
868 | return err; | 886 | return err; |
887 | |||
869 | decoder->tvp514x_regs[REG_CONTRAST].val = value; | 888 | decoder->tvp514x_regs[REG_CONTRAST].val = value; |
870 | break; | 889 | break; |
871 | case V4L2_CID_SATURATION: | 890 | case V4L2_CID_SATURATION: |
872 | if (ctrl->value < 0 || ctrl->value > 255) { | 891 | if (ctrl->value < 0 || ctrl->value > 255) { |
873 | v4l_err(decoder->client, | 892 | v4l2_err(sd, "invalid saturation setting %d\n", |
874 | "invalid saturation setting %d\n", | ||
875 | ctrl->value); | 893 | ctrl->value); |
876 | return -ERANGE; | 894 | return -ERANGE; |
877 | } | 895 | } |
878 | err = tvp514x_write_reg(decoder->client, REG_SATURATION, | 896 | err = tvp514x_write_reg(sd, REG_SATURATION, value); |
879 | value); | ||
880 | if (err) | 897 | if (err) |
881 | return err; | 898 | return err; |
899 | |||
882 | decoder->tvp514x_regs[REG_SATURATION].val = value; | 900 | decoder->tvp514x_regs[REG_SATURATION].val = value; |
883 | break; | 901 | break; |
884 | case V4L2_CID_HUE: | 902 | case V4L2_CID_HUE: |
@@ -889,15 +907,13 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) | |||
889 | else if (value == 0) | 907 | else if (value == 0) |
890 | value = 0; | 908 | value = 0; |
891 | else { | 909 | else { |
892 | v4l_err(decoder->client, | 910 | v4l2_err(sd, "invalid hue setting %d\n", ctrl->value); |
893 | "invalid hue setting %d\n", | ||
894 | ctrl->value); | ||
895 | return -ERANGE; | 911 | return -ERANGE; |
896 | } | 912 | } |
897 | err = tvp514x_write_reg(decoder->client, REG_HUE, | 913 | err = tvp514x_write_reg(sd, REG_HUE, value); |
898 | value); | ||
899 | if (err) | 914 | if (err) |
900 | return err; | 915 | return err; |
916 | |||
901 | decoder->tvp514x_regs[REG_HUE].val = value; | 917 | decoder->tvp514x_regs[REG_HUE].val = value; |
902 | break; | 918 | break; |
903 | case V4L2_CID_AUTOGAIN: | 919 | case V4L2_CID_AUTOGAIN: |
@@ -906,41 +922,38 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) | |||
906 | else if (value == 0) | 922 | else if (value == 0) |
907 | value = 0x0C; | 923 | value = 0x0C; |
908 | else { | 924 | else { |
909 | v4l_err(decoder->client, | 925 | v4l2_err(sd, "invalid auto gain setting %d\n", |
910 | "invalid auto gain setting %d\n", | ||
911 | ctrl->value); | 926 | ctrl->value); |
912 | return -ERANGE; | 927 | return -ERANGE; |
913 | } | 928 | } |
914 | err = tvp514x_write_reg(decoder->client, REG_AFE_GAIN_CTRL, | 929 | err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value); |
915 | value); | ||
916 | if (err) | 930 | if (err) |
917 | return err; | 931 | return err; |
932 | |||
918 | decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; | 933 | decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; |
919 | break; | 934 | break; |
920 | default: | 935 | default: |
921 | v4l_err(decoder->client, | 936 | v4l2_err(sd, "invalid control id %d\n", ctrl->id); |
922 | "invalid control id %d\n", ctrl->id); | ||
923 | return err; | 937 | return err; |
924 | } | 938 | } |
925 | 939 | ||
926 | v4l_dbg(1, debug, decoder->client, | 940 | v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d", |
927 | "Set Control: ID - %d - %d", | ||
928 | ctrl->id, ctrl->value); | 941 | ctrl->id, ctrl->value); |
929 | 942 | ||
930 | return err; | 943 | return err; |
931 | } | 944 | } |
932 | 945 | ||
933 | /** | 946 | /** |
934 | * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl | 947 | * tvp514x_enum_fmt_cap() - V4L2 decoder interface handler for enum_fmt |
935 | * @s: pointer to standard V4L2 device structure | 948 | * @sd: pointer to standard V4L2 sub-device structure |
936 | * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure | 949 | * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure |
937 | * | 950 | * |
938 | * Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats | 951 | * Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats |
939 | */ | 952 | */ |
940 | static int | 953 | static int |
941 | ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt) | 954 | tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) |
942 | { | 955 | { |
943 | struct tvp514x_decoder *decoder = s->priv; | 956 | struct tvp514x_decoder *decoder = to_decoder(sd); |
944 | int index; | 957 | int index; |
945 | 958 | ||
946 | if (fmt == NULL) | 959 | if (fmt == NULL) |
@@ -948,24 +961,25 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt) | |||
948 | 961 | ||
949 | index = fmt->index; | 962 | index = fmt->index; |
950 | if ((index >= decoder->num_fmts) || (index < 0)) | 963 | if ((index >= decoder->num_fmts) || (index < 0)) |
951 | return -EINVAL; /* Index out of bound */ | 964 | /* Index out of bound */ |
965 | return -EINVAL; | ||
952 | 966 | ||
953 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 967 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
954 | return -EINVAL; /* only capture is supported */ | 968 | /* only capture is supported */ |
969 | return -EINVAL; | ||
955 | 970 | ||
956 | memcpy(fmt, &decoder->fmt_list[index], | 971 | memcpy(fmt, &decoder->fmt_list[index], |
957 | sizeof(struct v4l2_fmtdesc)); | 972 | sizeof(struct v4l2_fmtdesc)); |
958 | 973 | ||
959 | v4l_dbg(1, debug, decoder->client, | 974 | v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)", |
960 | "Current FMT: index - %d (%s)", | ||
961 | decoder->fmt_list[index].index, | 975 | decoder->fmt_list[index].index, |
962 | decoder->fmt_list[index].description); | 976 | decoder->fmt_list[index].description); |
963 | return 0; | 977 | return 0; |
964 | } | 978 | } |
965 | 979 | ||
966 | /** | 980 | /** |
967 | * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl | 981 | * tvp514x_try_fmt_cap() - V4L2 decoder interface handler for try_fmt |
968 | * @s: pointer to standard V4L2 device structure | 982 | * @sd: pointer to standard V4L2 sub-device structure |
969 | * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure | 983 | * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure |
970 | * | 984 | * |
971 | * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This | 985 | * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This |
@@ -973,9 +987,9 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt) | |||
973 | * without actually making it take effect. | 987 | * without actually making it take effect. |
974 | */ | 988 | */ |
975 | static int | 989 | static int |
976 | ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | 990 | tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) |
977 | { | 991 | { |
978 | struct tvp514x_decoder *decoder = s->priv; | 992 | struct tvp514x_decoder *decoder = to_decoder(sd); |
979 | int ifmt; | 993 | int ifmt; |
980 | struct v4l2_pix_format *pix; | 994 | struct v4l2_pix_format *pix; |
981 | enum tvp514x_std current_std; | 995 | enum tvp514x_std current_std; |
@@ -984,12 +998,13 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
984 | return -EINVAL; | 998 | return -EINVAL; |
985 | 999 | ||
986 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1000 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1001 | /* only capture is supported */ | ||
987 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1002 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
988 | 1003 | ||
989 | pix = &f->fmt.pix; | 1004 | pix = &f->fmt.pix; |
990 | 1005 | ||
991 | /* Calculate height and width based on current standard */ | 1006 | /* Calculate height and width based on current standard */ |
992 | current_std = tvp514x_get_current_std(decoder); | 1007 | current_std = tvp514x_get_current_std(sd); |
993 | if (current_std == STD_INVALID) | 1008 | if (current_std == STD_INVALID) |
994 | return -EINVAL; | 1009 | return -EINVAL; |
995 | 1010 | ||
@@ -1003,7 +1018,8 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
1003 | break; | 1018 | break; |
1004 | } | 1019 | } |
1005 | if (ifmt == decoder->num_fmts) | 1020 | if (ifmt == decoder->num_fmts) |
1006 | ifmt = 0; /* None of the format matched, select default */ | 1021 | /* None of the format matched, select default */ |
1022 | ifmt = 0; | ||
1007 | pix->pixelformat = decoder->fmt_list[ifmt].pixelformat; | 1023 | pix->pixelformat = decoder->fmt_list[ifmt].pixelformat; |
1008 | 1024 | ||
1009 | pix->field = V4L2_FIELD_INTERLACED; | 1025 | pix->field = V4L2_FIELD_INTERLACED; |
@@ -1012,8 +1028,7 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
1012 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | 1028 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; |
1013 | pix->priv = 0; | 1029 | pix->priv = 0; |
1014 | 1030 | ||
1015 | v4l_dbg(1, debug, decoder->client, | 1031 | v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d" |
1016 | "Try FMT: pixelformat - %s, bytesperline - %d" | ||
1017 | "Width - %d, Height - %d", | 1032 | "Width - %d, Height - %d", |
1018 | decoder->fmt_list[ifmt].description, pix->bytesperline, | 1033 | decoder->fmt_list[ifmt].description, pix->bytesperline, |
1019 | pix->width, pix->height); | 1034 | pix->width, pix->height); |
@@ -1021,8 +1036,8 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
1021 | } | 1036 | } |
1022 | 1037 | ||
1023 | /** | 1038 | /** |
1024 | * ioctl_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT ioctl | 1039 | * tvp514x_s_fmt_cap() - V4L2 decoder interface handler for s_fmt |
1025 | * @s: pointer to standard V4L2 device structure | 1040 | * @sd: pointer to standard V4L2 sub-device structure |
1026 | * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure | 1041 | * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure |
1027 | * | 1042 | * |
1028 | * If the requested format is supported, configures the HW to use that | 1043 | * If the requested format is supported, configures the HW to use that |
@@ -1030,9 +1045,9 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
1030 | * correctly configured. | 1045 | * correctly configured. |
1031 | */ | 1046 | */ |
1032 | static int | 1047 | static int |
1033 | ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | 1048 | tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) |
1034 | { | 1049 | { |
1035 | struct tvp514x_decoder *decoder = s->priv; | 1050 | struct tvp514x_decoder *decoder = to_decoder(sd); |
1036 | struct v4l2_pix_format *pix; | 1051 | struct v4l2_pix_format *pix; |
1037 | int rval; | 1052 | int rval; |
1038 | 1053 | ||
@@ -1040,10 +1055,11 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
1040 | return -EINVAL; | 1055 | return -EINVAL; |
1041 | 1056 | ||
1042 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1057 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1043 | return -EINVAL; /* only capture is supported */ | 1058 | /* only capture is supported */ |
1059 | return -EINVAL; | ||
1044 | 1060 | ||
1045 | pix = &f->fmt.pix; | 1061 | pix = &f->fmt.pix; |
1046 | rval = ioctl_try_fmt_cap(s, f); | 1062 | rval = tvp514x_try_fmt_cap(sd, f); |
1047 | if (rval) | 1063 | if (rval) |
1048 | return rval; | 1064 | return rval; |
1049 | 1065 | ||
@@ -1053,28 +1069,28 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
1053 | } | 1069 | } |
1054 | 1070 | ||
1055 | /** | 1071 | /** |
1056 | * ioctl_g_fmt_cap - V4L2 decoder interface handler for ioctl_g_fmt_cap | 1072 | * tvp514x_g_fmt_cap() - V4L2 decoder interface handler for tvp514x_g_fmt_cap |
1057 | * @s: pointer to standard V4L2 device structure | 1073 | * @sd: pointer to standard V4L2 sub-device structure |
1058 | * @f: pointer to standard V4L2 v4l2_format structure | 1074 | * @f: pointer to standard V4L2 v4l2_format structure |
1059 | * | 1075 | * |
1060 | * Returns the decoder's current pixel format in the v4l2_format | 1076 | * Returns the decoder's current pixel format in the v4l2_format |
1061 | * parameter. | 1077 | * parameter. |
1062 | */ | 1078 | */ |
1063 | static int | 1079 | static int |
1064 | ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | 1080 | tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) |
1065 | { | 1081 | { |
1066 | struct tvp514x_decoder *decoder = s->priv; | 1082 | struct tvp514x_decoder *decoder = to_decoder(sd); |
1067 | 1083 | ||
1068 | if (f == NULL) | 1084 | if (f == NULL) |
1069 | return -EINVAL; | 1085 | return -EINVAL; |
1070 | 1086 | ||
1071 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1087 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1072 | return -EINVAL; /* only capture is supported */ | 1088 | /* only capture is supported */ |
1089 | return -EINVAL; | ||
1073 | 1090 | ||
1074 | f->fmt.pix = decoder->pix; | 1091 | f->fmt.pix = decoder->pix; |
1075 | 1092 | ||
1076 | v4l_dbg(1, debug, decoder->client, | 1093 | v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d" |
1077 | "Current FMT: bytesperline - %d" | ||
1078 | "Width - %d, Height - %d", | 1094 | "Width - %d, Height - %d", |
1079 | decoder->pix.bytesperline, | 1095 | decoder->pix.bytesperline, |
1080 | decoder->pix.width, decoder->pix.height); | 1096 | decoder->pix.width, decoder->pix.height); |
@@ -1082,16 +1098,16 @@ ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) | |||
1082 | } | 1098 | } |
1083 | 1099 | ||
1084 | /** | 1100 | /** |
1085 | * ioctl_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM ioctl | 1101 | * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm |
1086 | * @s: pointer to standard V4L2 device structure | 1102 | * @sd: pointer to standard V4L2 sub-device structure |
1087 | * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure | 1103 | * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure |
1088 | * | 1104 | * |
1089 | * Returns the decoder's video CAPTURE parameters. | 1105 | * Returns the decoder's video CAPTURE parameters. |
1090 | */ | 1106 | */ |
1091 | static int | 1107 | static int |
1092 | ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) | 1108 | tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) |
1093 | { | 1109 | { |
1094 | struct tvp514x_decoder *decoder = s->priv; | 1110 | struct tvp514x_decoder *decoder = to_decoder(sd); |
1095 | struct v4l2_captureparm *cparm; | 1111 | struct v4l2_captureparm *cparm; |
1096 | enum tvp514x_std current_std; | 1112 | enum tvp514x_std current_std; |
1097 | 1113 | ||
@@ -1099,13 +1115,14 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) | |||
1099 | return -EINVAL; | 1115 | return -EINVAL; |
1100 | 1116 | ||
1101 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1117 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1102 | return -EINVAL; /* only capture is supported */ | 1118 | /* only capture is supported */ |
1119 | return -EINVAL; | ||
1103 | 1120 | ||
1104 | memset(a, 0, sizeof(*a)); | 1121 | memset(a, 0, sizeof(*a)); |
1105 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1122 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1106 | 1123 | ||
1107 | /* get the current standard */ | 1124 | /* get the current standard */ |
1108 | current_std = tvp514x_get_current_std(decoder); | 1125 | current_std = tvp514x_get_current_std(sd); |
1109 | if (current_std == STD_INVALID) | 1126 | if (current_std == STD_INVALID) |
1110 | return -EINVAL; | 1127 | return -EINVAL; |
1111 | 1128 | ||
@@ -1120,17 +1137,17 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) | |||
1120 | } | 1137 | } |
1121 | 1138 | ||
1122 | /** | 1139 | /** |
1123 | * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl | 1140 | * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm |
1124 | * @s: pointer to standard V4L2 device structure | 1141 | * @sd: pointer to standard V4L2 sub-device structure |
1125 | * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure | 1142 | * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure |
1126 | * | 1143 | * |
1127 | * Configures the decoder to use the input parameters, if possible. If | 1144 | * Configures the decoder to use the input parameters, if possible. If |
1128 | * not possible, returns the appropriate error code. | 1145 | * not possible, returns the appropriate error code. |
1129 | */ | 1146 | */ |
1130 | static int | 1147 | static int |
1131 | ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) | 1148 | tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) |
1132 | { | 1149 | { |
1133 | struct tvp514x_decoder *decoder = s->priv; | 1150 | struct tvp514x_decoder *decoder = to_decoder(sd); |
1134 | struct v4l2_fract *timeperframe; | 1151 | struct v4l2_fract *timeperframe; |
1135 | enum tvp514x_std current_std; | 1152 | enum tvp514x_std current_std; |
1136 | 1153 | ||
@@ -1138,12 +1155,13 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) | |||
1138 | return -EINVAL; | 1155 | return -EINVAL; |
1139 | 1156 | ||
1140 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1157 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1141 | return -EINVAL; /* only capture is supported */ | 1158 | /* only capture is supported */ |
1159 | return -EINVAL; | ||
1142 | 1160 | ||
1143 | timeperframe = &a->parm.capture.timeperframe; | 1161 | timeperframe = &a->parm.capture.timeperframe; |
1144 | 1162 | ||
1145 | /* get the current standard */ | 1163 | /* get the current standard */ |
1146 | current_std = tvp514x_get_current_std(decoder); | 1164 | current_std = tvp514x_get_current_std(sd); |
1147 | if (current_std == STD_INVALID) | 1165 | if (current_std == STD_INVALID) |
1148 | return -EINVAL; | 1166 | return -EINVAL; |
1149 | 1167 | ||
@@ -1156,111 +1174,58 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) | |||
1156 | } | 1174 | } |
1157 | 1175 | ||
1158 | /** | 1176 | /** |
1159 | * ioctl_g_ifparm - V4L2 decoder interface handler for vidioc_int_g_ifparm_num | 1177 | * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream |
1160 | * @s: pointer to standard V4L2 device structure | 1178 | * @sd: pointer to standard V4L2 sub-device structure |
1161 | * @p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure | 1179 | * @enable: streaming enable or disable |
1162 | * | ||
1163 | * Gets slave interface parameters. | ||
1164 | * Calculates the required xclk value to support the requested | ||
1165 | * clock parameters in p. This value is returned in the p | ||
1166 | * parameter. | ||
1167 | */ | ||
1168 | static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) | ||
1169 | { | ||
1170 | struct tvp514x_decoder *decoder = s->priv; | ||
1171 | int rval; | ||
1172 | |||
1173 | if (p == NULL) | ||
1174 | return -EINVAL; | ||
1175 | |||
1176 | if (NULL == decoder->pdata->ifparm) | ||
1177 | return -EINVAL; | ||
1178 | |||
1179 | rval = decoder->pdata->ifparm(p); | ||
1180 | if (rval) { | ||
1181 | v4l_err(decoder->client, "g_ifparm.Err[%d]\n", rval); | ||
1182 | return rval; | ||
1183 | } | ||
1184 | |||
1185 | p->u.bt656.clock_curr = TVP514X_XCLK_BT656; | ||
1186 | |||
1187 | return 0; | ||
1188 | } | ||
1189 | |||
1190 | /** | ||
1191 | * ioctl_g_priv - V4L2 decoder interface handler for vidioc_int_g_priv_num | ||
1192 | * @s: pointer to standard V4L2 device structure | ||
1193 | * @p: void pointer to hold decoder's private data address | ||
1194 | * | ||
1195 | * Returns device's (decoder's) private data area address in p parameter | ||
1196 | */ | ||
1197 | static int ioctl_g_priv(struct v4l2_int_device *s, void *p) | ||
1198 | { | ||
1199 | struct tvp514x_decoder *decoder = s->priv; | ||
1200 | |||
1201 | if (NULL == decoder->pdata->priv_data_set) | ||
1202 | return -EINVAL; | ||
1203 | |||
1204 | return decoder->pdata->priv_data_set(p); | ||
1205 | } | ||
1206 | |||
1207 | /** | ||
1208 | * ioctl_s_power - V4L2 decoder interface handler for vidioc_int_s_power_num | ||
1209 | * @s: pointer to standard V4L2 device structure | ||
1210 | * @on: power state to which device is to be set | ||
1211 | * | 1180 | * |
1212 | * Sets devices power state to requrested state, if possible. | 1181 | * Sets streaming to enable or disable, if possible. |
1213 | */ | 1182 | */ |
1214 | static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on) | 1183 | static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable) |
1215 | { | 1184 | { |
1216 | struct tvp514x_decoder *decoder = s->priv; | ||
1217 | int err = 0; | 1185 | int err = 0; |
1186 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1187 | struct tvp514x_decoder *decoder = to_decoder(sd); | ||
1218 | 1188 | ||
1219 | switch (on) { | 1189 | if (decoder->streaming == enable) |
1220 | case V4L2_POWER_OFF: | 1190 | return 0; |
1221 | /* Power Down Sequence */ | ||
1222 | err = | ||
1223 | tvp514x_write_reg(decoder->client, REG_OPERATION_MODE, | ||
1224 | 0x01); | ||
1225 | /* Disable mux for TVP5146/47 decoder data path */ | ||
1226 | if (decoder->pdata->power_set) | ||
1227 | err |= decoder->pdata->power_set(on); | ||
1228 | decoder->state = STATE_NOT_DETECTED; | ||
1229 | break; | ||
1230 | 1191 | ||
1231 | case V4L2_POWER_STANDBY: | 1192 | switch (enable) { |
1232 | if (decoder->pdata->power_set) | 1193 | case 0: |
1233 | err = decoder->pdata->power_set(on); | 1194 | { |
1195 | /* Power Down Sequence */ | ||
1196 | err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01); | ||
1197 | if (err) { | ||
1198 | v4l2_err(sd, "Unable to turn off decoder\n"); | ||
1199 | return err; | ||
1200 | } | ||
1201 | decoder->streaming = enable; | ||
1234 | break; | 1202 | break; |
1203 | } | ||
1204 | case 1: | ||
1205 | { | ||
1206 | struct tvp514x_reg *int_seq = (struct tvp514x_reg *) | ||
1207 | client->driver->id_table->driver_data; | ||
1235 | 1208 | ||
1236 | case V4L2_POWER_ON: | 1209 | /* Power Up Sequence */ |
1237 | /* Enable mux for TVP5146/47 decoder data path */ | 1210 | err = tvp514x_write_regs(sd, int_seq); |
1238 | if ((decoder->pdata->power_set) && | 1211 | if (err) { |
1239 | (decoder->state == STATE_NOT_DETECTED)) { | 1212 | v4l2_err(sd, "Unable to turn on decoder\n"); |
1240 | int i; | 1213 | return err; |
1241 | struct tvp514x_init_seq *int_seq = | ||
1242 | (struct tvp514x_init_seq *) | ||
1243 | decoder->id->driver_data; | ||
1244 | |||
1245 | err = decoder->pdata->power_set(on); | ||
1246 | |||
1247 | /* Power Up Sequence */ | ||
1248 | for (i = 0; i < int_seq->no_regs; i++) { | ||
1249 | err |= tvp514x_write_reg(decoder->client, | ||
1250 | int_seq->init_reg_seq[i].reg, | ||
1251 | int_seq->init_reg_seq[i].val); | ||
1252 | } | ||
1253 | /* Detect the sensor is not already detected */ | ||
1254 | err |= tvp514x_detect(decoder); | ||
1255 | if (err) { | ||
1256 | v4l_err(decoder->client, | ||
1257 | "Unable to detect decoder\n"); | ||
1258 | return err; | ||
1259 | } | ||
1260 | } | 1214 | } |
1261 | err |= tvp514x_configure(decoder); | 1215 | /* Detect if not already detected */ |
1216 | err = tvp514x_detect(sd, decoder); | ||
1217 | if (err) { | ||
1218 | v4l2_err(sd, "Unable to detect decoder\n"); | ||
1219 | return err; | ||
1220 | } | ||
1221 | err = tvp514x_configure(sd, decoder); | ||
1222 | if (err) { | ||
1223 | v4l2_err(sd, "Unable to configure decoder\n"); | ||
1224 | return err; | ||
1225 | } | ||
1226 | decoder->streaming = enable; | ||
1262 | break; | 1227 | break; |
1263 | 1228 | } | |
1264 | default: | 1229 | default: |
1265 | err = -ENODEV; | 1230 | err = -ENODEV; |
1266 | break; | 1231 | break; |
@@ -1269,93 +1234,38 @@ static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on) | |||
1269 | return err; | 1234 | return err; |
1270 | } | 1235 | } |
1271 | 1236 | ||
1272 | /** | 1237 | static const struct v4l2_subdev_core_ops tvp514x_core_ops = { |
1273 | * ioctl_init - V4L2 decoder interface handler for VIDIOC_INT_INIT | 1238 | .queryctrl = tvp514x_queryctrl, |
1274 | * @s: pointer to standard V4L2 device structure | 1239 | .g_ctrl = tvp514x_g_ctrl, |
1275 | * | 1240 | .s_ctrl = tvp514x_s_ctrl, |
1276 | * Initialize the decoder device (calls tvp514x_configure()) | 1241 | .s_std = tvp514x_s_std, |
1277 | */ | 1242 | }; |
1278 | static int ioctl_init(struct v4l2_int_device *s) | ||
1279 | { | ||
1280 | struct tvp514x_decoder *decoder = s->priv; | ||
1281 | |||
1282 | /* Set default standard to auto */ | ||
1283 | decoder->tvp514x_regs[REG_VIDEO_STD].val = | ||
1284 | VIDEO_STD_AUTO_SWITCH_BIT; | ||
1285 | |||
1286 | return tvp514x_configure(decoder); | ||
1287 | } | ||
1288 | |||
1289 | /** | ||
1290 | * ioctl_dev_exit - V4L2 decoder interface handler for vidioc_int_dev_exit_num | ||
1291 | * @s: pointer to standard V4L2 device structure | ||
1292 | * | ||
1293 | * Delinitialise the dev. at slave detach. The complement of ioctl_dev_init. | ||
1294 | */ | ||
1295 | static int ioctl_dev_exit(struct v4l2_int_device *s) | ||
1296 | { | ||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | /** | ||
1301 | * ioctl_dev_init - V4L2 decoder interface handler for vidioc_int_dev_init_num | ||
1302 | * @s: pointer to standard V4L2 device structure | ||
1303 | * | ||
1304 | * Initialise the device when slave attaches to the master. Returns 0 if | ||
1305 | * TVP5146/47 device could be found, otherwise returns appropriate error. | ||
1306 | */ | ||
1307 | static int ioctl_dev_init(struct v4l2_int_device *s) | ||
1308 | { | ||
1309 | struct tvp514x_decoder *decoder = s->priv; | ||
1310 | int err; | ||
1311 | |||
1312 | err = tvp514x_detect(decoder); | ||
1313 | if (err < 0) { | ||
1314 | v4l_err(decoder->client, | ||
1315 | "Unable to detect decoder\n"); | ||
1316 | return err; | ||
1317 | } | ||
1318 | |||
1319 | v4l_info(decoder->client, | ||
1320 | "chip version 0x%.2x detected\n", decoder->ver); | ||
1321 | 1243 | ||
1322 | return 0; | 1244 | static const struct v4l2_subdev_video_ops tvp514x_video_ops = { |
1323 | } | 1245 | .s_routing = tvp514x_s_routing, |
1246 | .querystd = tvp514x_querystd, | ||
1247 | .enum_fmt = tvp514x_enum_fmt_cap, | ||
1248 | .g_fmt = tvp514x_g_fmt_cap, | ||
1249 | .try_fmt = tvp514x_try_fmt_cap, | ||
1250 | .s_fmt = tvp514x_s_fmt_cap, | ||
1251 | .g_parm = tvp514x_g_parm, | ||
1252 | .s_parm = tvp514x_s_parm, | ||
1253 | .s_stream = tvp514x_s_stream, | ||
1254 | }; | ||
1324 | 1255 | ||
1325 | static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = { | 1256 | static const struct v4l2_subdev_ops tvp514x_ops = { |
1326 | {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*) ioctl_dev_init}, | 1257 | .core = &tvp514x_core_ops, |
1327 | {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func*) ioctl_dev_exit}, | 1258 | .video = &tvp514x_video_ops, |
1328 | {vidioc_int_s_power_num, (v4l2_int_ioctl_func*) ioctl_s_power}, | ||
1329 | {vidioc_int_g_priv_num, (v4l2_int_ioctl_func*) ioctl_g_priv}, | ||
1330 | {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*) ioctl_g_ifparm}, | ||
1331 | {vidioc_int_init_num, (v4l2_int_ioctl_func*) ioctl_init}, | ||
1332 | {vidioc_int_enum_fmt_cap_num, | ||
1333 | (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, | ||
1334 | {vidioc_int_try_fmt_cap_num, | ||
1335 | (v4l2_int_ioctl_func *) ioctl_try_fmt_cap}, | ||
1336 | {vidioc_int_g_fmt_cap_num, | ||
1337 | (v4l2_int_ioctl_func *) ioctl_g_fmt_cap}, | ||
1338 | {vidioc_int_s_fmt_cap_num, | ||
1339 | (v4l2_int_ioctl_func *) ioctl_s_fmt_cap}, | ||
1340 | {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm}, | ||
1341 | {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm}, | ||
1342 | {vidioc_int_queryctrl_num, | ||
1343 | (v4l2_int_ioctl_func *) ioctl_queryctrl}, | ||
1344 | {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl}, | ||
1345 | {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl}, | ||
1346 | {vidioc_int_querystd_num, (v4l2_int_ioctl_func *) ioctl_querystd}, | ||
1347 | {vidioc_int_s_std_num, (v4l2_int_ioctl_func *) ioctl_s_std}, | ||
1348 | {vidioc_int_s_video_routing_num, | ||
1349 | (v4l2_int_ioctl_func *) ioctl_s_routing}, | ||
1350 | }; | 1259 | }; |
1351 | 1260 | ||
1352 | static struct tvp514x_decoder tvp514x_dev = { | 1261 | static struct tvp514x_decoder tvp514x_dev = { |
1353 | .state = STATE_NOT_DETECTED, | 1262 | .streaming = 0, |
1354 | 1263 | ||
1355 | .fmt_list = tvp514x_fmt_list, | 1264 | .fmt_list = tvp514x_fmt_list, |
1356 | .num_fmts = ARRAY_SIZE(tvp514x_fmt_list), | 1265 | .num_fmts = ARRAY_SIZE(tvp514x_fmt_list), |
1357 | 1266 | ||
1358 | .pix = { /* Default to NTSC 8-bit YUV 422 */ | 1267 | .pix = { |
1268 | /* Default to NTSC 8-bit YUV 422 */ | ||
1359 | .width = NTSC_NUM_ACTIVE_PIXELS, | 1269 | .width = NTSC_NUM_ACTIVE_PIXELS, |
1360 | .height = NTSC_NUM_ACTIVE_LINES, | 1270 | .height = NTSC_NUM_ACTIVE_LINES, |
1361 | .pixelformat = V4L2_PIX_FMT_UYVY, | 1271 | .pixelformat = V4L2_PIX_FMT_UYVY, |
@@ -1369,20 +1279,13 @@ static struct tvp514x_decoder tvp514x_dev = { | |||
1369 | .current_std = STD_NTSC_MJ, | 1279 | .current_std = STD_NTSC_MJ, |
1370 | .std_list = tvp514x_std_list, | 1280 | .std_list = tvp514x_std_list, |
1371 | .num_stds = ARRAY_SIZE(tvp514x_std_list), | 1281 | .num_stds = ARRAY_SIZE(tvp514x_std_list), |
1372 | .v4l2_int_device = { | 1282 | |
1373 | .module = THIS_MODULE, | ||
1374 | .name = TVP514X_MODULE_NAME, | ||
1375 | .type = v4l2_int_type_slave, | ||
1376 | }, | ||
1377 | .tvp514x_slave = { | ||
1378 | .ioctls = tvp514x_ioctl_desc, | ||
1379 | .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc), | ||
1380 | }, | ||
1381 | }; | 1283 | }; |
1382 | 1284 | ||
1383 | /** | 1285 | /** |
1384 | * tvp514x_probe - decoder driver i2c probe handler | 1286 | * tvp514x_probe() - decoder driver i2c probe handler |
1385 | * @client: i2c driver client device structure | 1287 | * @client: i2c driver client device structure |
1288 | * @id: i2c driver id table | ||
1386 | * | 1289 | * |
1387 | * Register decoder as an i2c client device and V4L2 | 1290 | * Register decoder as an i2c client device and V4L2 |
1388 | * device. | 1291 | * device. |
@@ -1391,88 +1294,71 @@ static int | |||
1391 | tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) | 1294 | tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) |
1392 | { | 1295 | { |
1393 | struct tvp514x_decoder *decoder; | 1296 | struct tvp514x_decoder *decoder; |
1394 | int err; | 1297 | struct v4l2_subdev *sd; |
1395 | 1298 | ||
1396 | /* Check if the adapter supports the needed features */ | 1299 | /* Check if the adapter supports the needed features */ |
1397 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 1300 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
1398 | return -EIO; | 1301 | return -EIO; |
1399 | 1302 | ||
1303 | if (!client->dev.platform_data) { | ||
1304 | v4l2_err(client, "No platform data!!\n"); | ||
1305 | return -ENODEV; | ||
1306 | } | ||
1307 | |||
1400 | decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); | 1308 | decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); |
1401 | if (!decoder) | 1309 | if (!decoder) |
1402 | return -ENOMEM; | 1310 | return -ENOMEM; |
1403 | 1311 | ||
1404 | if (!client->dev.platform_data) { | 1312 | /* Initialize the tvp514x_decoder with default configuration */ |
1405 | v4l_err(client, "No platform data!!\n"); | ||
1406 | err = -ENODEV; | ||
1407 | goto out_free; | ||
1408 | } | ||
1409 | |||
1410 | *decoder = tvp514x_dev; | 1313 | *decoder = tvp514x_dev; |
1411 | decoder->v4l2_int_device.priv = decoder; | 1314 | /* Copy default register configuration */ |
1412 | decoder->pdata = client->dev.platform_data; | ||
1413 | decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave; | ||
1414 | memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, | 1315 | memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, |
1415 | sizeof(tvp514x_reg_list_default)); | 1316 | sizeof(tvp514x_reg_list_default)); |
1416 | /* | 1317 | |
1318 | /* Copy board specific information here */ | ||
1319 | decoder->pdata = client->dev.platform_data; | ||
1320 | |||
1321 | /** | ||
1417 | * Fetch platform specific data, and configure the | 1322 | * Fetch platform specific data, and configure the |
1418 | * tvp514x_reg_list[] accordingly. Since this is one | 1323 | * tvp514x_reg_list[] accordingly. Since this is one |
1419 | * time configuration, no need to preserve. | 1324 | * time configuration, no need to preserve. |
1420 | */ | 1325 | */ |
1421 | decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |= | 1326 | decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |= |
1422 | (decoder->pdata->clk_polarity << 1); | 1327 | (decoder->pdata->clk_polarity << 1); |
1423 | decoder->tvp514x_regs[REG_SYNC_CONTROL].val |= | 1328 | decoder->tvp514x_regs[REG_SYNC_CONTROL].val |= |
1424 | ((decoder->pdata->hs_polarity << 2) | | 1329 | ((decoder->pdata->hs_polarity << 2) | |
1425 | (decoder->pdata->vs_polarity << 3)); | 1330 | (decoder->pdata->vs_polarity << 3)); |
1426 | /* | 1331 | /* Set default standard to auto */ |
1427 | * Save the id data, required for power up sequence | 1332 | decoder->tvp514x_regs[REG_VIDEO_STD].val = |
1428 | */ | 1333 | VIDEO_STD_AUTO_SWITCH_BIT; |
1429 | decoder->id = (struct i2c_device_id *)id; | ||
1430 | /* Attach to Master */ | ||
1431 | strcpy(decoder->v4l2_int_device.u.slave->attach_to, | ||
1432 | decoder->pdata->master); | ||
1433 | decoder->client = client; | ||
1434 | i2c_set_clientdata(client, decoder); | ||
1435 | 1334 | ||
1436 | /* Register with V4L2 layer as slave device */ | 1335 | /* Register with V4L2 layer as slave device */ |
1437 | err = v4l2_int_device_register(&decoder->v4l2_int_device); | 1336 | sd = &decoder->sd; |
1438 | if (err) { | 1337 | v4l2_i2c_subdev_init(sd, client, &tvp514x_ops); |
1439 | i2c_set_clientdata(client, NULL); | 1338 | |
1440 | v4l_err(client, | 1339 | v4l2_info(sd, "%s decoder driver registered !!\n", sd->name); |
1441 | "Unable to register to v4l2. Err[%d]\n", err); | 1340 | |
1442 | goto out_free; | ||
1443 | |||
1444 | } else | ||
1445 | v4l_info(client, "Registered to v4l2 master %s!!\n", | ||
1446 | decoder->pdata->master); | ||
1447 | return 0; | 1341 | return 0; |
1448 | 1342 | ||
1449 | out_free: | ||
1450 | kfree(decoder); | ||
1451 | return err; | ||
1452 | } | 1343 | } |
1453 | 1344 | ||
1454 | /** | 1345 | /** |
1455 | * tvp514x_remove - decoder driver i2c remove handler | 1346 | * tvp514x_remove() - decoder driver i2c remove handler |
1456 | * @client: i2c driver client device structure | 1347 | * @client: i2c driver client device structure |
1457 | * | 1348 | * |
1458 | * Unregister decoder as an i2c client device and V4L2 | 1349 | * Unregister decoder as an i2c client device and V4L2 |
1459 | * device. Complement of tvp514x_probe(). | 1350 | * device. Complement of tvp514x_probe(). |
1460 | */ | 1351 | */ |
1461 | static int __exit tvp514x_remove(struct i2c_client *client) | 1352 | static int tvp514x_remove(struct i2c_client *client) |
1462 | { | 1353 | { |
1463 | struct tvp514x_decoder *decoder = i2c_get_clientdata(client); | 1354 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1464 | 1355 | struct tvp514x_decoder *decoder = to_decoder(sd); | |
1465 | if (!client->adapter) | ||
1466 | return -ENODEV; /* our client isn't attached */ | ||
1467 | 1356 | ||
1468 | v4l2_int_device_unregister(&decoder->v4l2_int_device); | 1357 | v4l2_device_unregister_subdev(sd); |
1469 | i2c_set_clientdata(client, NULL); | ||
1470 | kfree(decoder); | 1358 | kfree(decoder); |
1471 | return 0; | 1359 | return 0; |
1472 | } | 1360 | } |
1473 | /* | 1361 | /* TVP5146 Init/Power on Sequence */ |
1474 | * TVP5146 Init/Power on Sequence | ||
1475 | */ | ||
1476 | static const struct tvp514x_reg tvp5146_init_reg_seq[] = { | 1362 | static const struct tvp514x_reg tvp5146_init_reg_seq[] = { |
1477 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, | 1363 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, |
1478 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | 1364 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, |
@@ -1485,14 +1371,10 @@ static const struct tvp514x_reg tvp5146_init_reg_seq[] = { | |||
1485 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, | 1371 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, |
1486 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, | 1372 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, |
1487 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, | 1373 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, |
1374 | {TOK_TERM, 0, 0}, | ||
1488 | }; | 1375 | }; |
1489 | static const struct tvp514x_init_seq tvp5146_init = { | 1376 | |
1490 | .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq), | 1377 | /* TVP5147 Init/Power on Sequence */ |
1491 | .init_reg_seq = tvp5146_init_reg_seq, | ||
1492 | }; | ||
1493 | /* | ||
1494 | * TVP5147 Init/Power on Sequence | ||
1495 | */ | ||
1496 | static const struct tvp514x_reg tvp5147_init_reg_seq[] = { | 1378 | static const struct tvp514x_reg tvp5147_init_reg_seq[] = { |
1497 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, | 1379 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, |
1498 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | 1380 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, |
@@ -1512,71 +1394,51 @@ static const struct tvp514x_reg tvp5147_init_reg_seq[] = { | |||
1512 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, | 1394 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, |
1513 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, | 1395 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, |
1514 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, | 1396 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, |
1397 | {TOK_TERM, 0, 0}, | ||
1515 | }; | 1398 | }; |
1516 | static const struct tvp514x_init_seq tvp5147_init = { | 1399 | |
1517 | .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq), | 1400 | /* TVP5146M2/TVP5147M1 Init/Power on Sequence */ |
1518 | .init_reg_seq = tvp5147_init_reg_seq, | ||
1519 | }; | ||
1520 | /* | ||
1521 | * TVP5146M2/TVP5147M1 Init/Power on Sequence | ||
1522 | */ | ||
1523 | static const struct tvp514x_reg tvp514xm_init_reg_seq[] = { | 1401 | static const struct tvp514x_reg tvp514xm_init_reg_seq[] = { |
1524 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, | 1402 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, |
1525 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, | 1403 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, |
1404 | {TOK_TERM, 0, 0}, | ||
1526 | }; | 1405 | }; |
1527 | static const struct tvp514x_init_seq tvp514xm_init = { | 1406 | |
1528 | .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq), | 1407 | /** |
1529 | .init_reg_seq = tvp514xm_init_reg_seq, | ||
1530 | }; | ||
1531 | /* | ||
1532 | * I2C Device Table - | 1408 | * I2C Device Table - |
1533 | * | 1409 | * |
1534 | * name - Name of the actual device/chip. | 1410 | * name - Name of the actual device/chip. |
1535 | * driver_data - Driver data | 1411 | * driver_data - Driver data |
1536 | */ | 1412 | */ |
1537 | static const struct i2c_device_id tvp514x_id[] = { | 1413 | static const struct i2c_device_id tvp514x_id[] = { |
1538 | {"tvp5146", (unsigned long)&tvp5146_init}, | 1414 | {"tvp5146", (unsigned long)tvp5146_init_reg_seq}, |
1539 | {"tvp5146m2", (unsigned long)&tvp514xm_init}, | 1415 | {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq}, |
1540 | {"tvp5147", (unsigned long)&tvp5147_init}, | 1416 | {"tvp5147", (unsigned long)tvp5147_init_reg_seq}, |
1541 | {"tvp5147m1", (unsigned long)&tvp514xm_init}, | 1417 | {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq}, |
1542 | {}, | 1418 | {}, |
1543 | }; | 1419 | }; |
1544 | 1420 | ||
1545 | MODULE_DEVICE_TABLE(i2c, tvp514x_id); | 1421 | MODULE_DEVICE_TABLE(i2c, tvp514x_id); |
1546 | 1422 | ||
1547 | static struct i2c_driver tvp514x_i2c_driver = { | 1423 | static struct i2c_driver tvp514x_driver = { |
1548 | .driver = { | 1424 | .driver = { |
1549 | .name = TVP514X_MODULE_NAME, | 1425 | .owner = THIS_MODULE, |
1550 | .owner = THIS_MODULE, | 1426 | .name = TVP514X_MODULE_NAME, |
1551 | }, | 1427 | }, |
1552 | .probe = tvp514x_probe, | 1428 | .probe = tvp514x_probe, |
1553 | .remove = __exit_p(tvp514x_remove), | 1429 | .remove = tvp514x_remove, |
1554 | .id_table = tvp514x_id, | 1430 | .id_table = tvp514x_id, |
1555 | }; | 1431 | }; |
1556 | 1432 | ||
1557 | /** | ||
1558 | * tvp514x_init | ||
1559 | * | ||
1560 | * Module init function | ||
1561 | */ | ||
1562 | static int __init tvp514x_init(void) | 1433 | static int __init tvp514x_init(void) |
1563 | { | 1434 | { |
1564 | return i2c_add_driver(&tvp514x_i2c_driver); | 1435 | return i2c_add_driver(&tvp514x_driver); |
1565 | } | 1436 | } |
1566 | 1437 | ||
1567 | /** | 1438 | static void __exit tvp514x_exit(void) |
1568 | * tvp514x_cleanup | ||
1569 | * | ||
1570 | * Module exit function | ||
1571 | */ | ||
1572 | static void __exit tvp514x_cleanup(void) | ||
1573 | { | 1439 | { |
1574 | i2c_del_driver(&tvp514x_i2c_driver); | 1440 | i2c_del_driver(&tvp514x_driver); |
1575 | } | 1441 | } |
1576 | 1442 | ||
1577 | module_init(tvp514x_init); | 1443 | module_init(tvp514x_init); |
1578 | module_exit(tvp514x_cleanup); | 1444 | module_exit(tvp514x_exit); |
1579 | |||
1580 | MODULE_AUTHOR("Texas Instruments"); | ||
1581 | MODULE_DESCRIPTION("TVP514X linux decoder driver"); | ||
1582 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h index 351620aeecc2..18f29ad0dfe2 100644 --- a/drivers/media/video/tvp514x_regs.h +++ b/drivers/media/video/tvp514x_regs.h | |||
@@ -284,14 +284,4 @@ struct tvp514x_reg { | |||
284 | u32 val; | 284 | u32 val; |
285 | }; | 285 | }; |
286 | 286 | ||
287 | /** | ||
288 | * struct tvp514x_init_seq - Structure for TVP5146/47/46M2/47M1 power up | ||
289 | * Sequence. | ||
290 | * @ no_regs - Number of registers to write for power up sequence. | ||
291 | * @ init_reg_seq - Array of registers and respective value to write. | ||
292 | */ | ||
293 | struct tvp514x_init_seq { | ||
294 | unsigned int no_regs; | ||
295 | const struct tvp514x_reg *init_reg_seq; | ||
296 | }; | ||
297 | #endif /* ifndef _TVP514X_REGS_H */ | 287 | #endif /* ifndef _TVP514X_REGS_H */ |
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index aa5065ea09ed..269ab044072a 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/videodev2.h> | 25 | #include <linux/videodev2.h> |
26 | #include <media/v4l2-chip-ident.h> | 26 | #include <media/v4l2-chip-ident.h> |
27 | #include <media/v4l2-common.h> | 27 | #include <media/v4l2-subdev.h> |
28 | #include <media/soc_camera.h> | 28 | #include <media/soc_camera.h> |
29 | #include <media/tw9910.h> | 29 | #include <media/tw9910.h> |
30 | 30 | ||
@@ -223,9 +223,8 @@ struct tw9910_hsync_ctrl { | |||
223 | }; | 223 | }; |
224 | 224 | ||
225 | struct tw9910_priv { | 225 | struct tw9910_priv { |
226 | struct v4l2_subdev subdev; | ||
226 | struct tw9910_video_info *info; | 227 | struct tw9910_video_info *info; |
227 | struct i2c_client *client; | ||
228 | struct soc_camera_device icd; | ||
229 | const struct tw9910_scale_ctrl *scale; | 228 | const struct tw9910_scale_ctrl *scale; |
230 | }; | 229 | }; |
231 | 230 | ||
@@ -356,6 +355,12 @@ static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { | |||
356 | /* | 355 | /* |
357 | * general function | 356 | * general function |
358 | */ | 357 | */ |
358 | static struct tw9910_priv *to_tw9910(const struct i2c_client *client) | ||
359 | { | ||
360 | return container_of(i2c_get_clientdata(client), struct tw9910_priv, | ||
361 | subdev); | ||
362 | } | ||
363 | |||
359 | static int tw9910_set_scale(struct i2c_client *client, | 364 | static int tw9910_set_scale(struct i2c_client *client, |
360 | const struct tw9910_scale_ctrl *scale) | 365 | const struct tw9910_scale_ctrl *scale) |
361 | { | 366 | { |
@@ -509,44 +514,20 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height) | |||
509 | /* | 514 | /* |
510 | * soc_camera_ops function | 515 | * soc_camera_ops function |
511 | */ | 516 | */ |
512 | static int tw9910_init(struct soc_camera_device *icd) | 517 | static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) |
513 | { | ||
514 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | ||
515 | int ret = 0; | ||
516 | |||
517 | if (priv->info->link.power) { | ||
518 | ret = priv->info->link.power(&priv->client->dev, 1); | ||
519 | if (ret < 0) | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | if (priv->info->link.reset) | ||
524 | ret = priv->info->link.reset(&priv->client->dev); | ||
525 | |||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | static int tw9910_release(struct soc_camera_device *icd) | ||
530 | { | 518 | { |
531 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | 519 | struct i2c_client *client = sd->priv; |
532 | int ret = 0; | 520 | struct tw9910_priv *priv = to_tw9910(client); |
533 | |||
534 | if (priv->info->link.power) | ||
535 | ret = priv->info->link.power(&priv->client->dev, 0); | ||
536 | |||
537 | return ret; | ||
538 | } | ||
539 | 521 | ||
540 | static int tw9910_start_capture(struct soc_camera_device *icd) | 522 | if (!enable) |
541 | { | 523 | return 0; |
542 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | ||
543 | 524 | ||
544 | if (!priv->scale) { | 525 | if (!priv->scale) { |
545 | dev_err(&icd->dev, "norm select error\n"); | 526 | dev_err(&client->dev, "norm select error\n"); |
546 | return -EPERM; | 527 | return -EPERM; |
547 | } | 528 | } |
548 | 529 | ||
549 | dev_dbg(&icd->dev, "%s %dx%d\n", | 530 | dev_dbg(&client->dev, "%s %dx%d\n", |
550 | priv->scale->name, | 531 | priv->scale->name, |
551 | priv->scale->width, | 532 | priv->scale->width, |
552 | priv->scale->height); | 533 | priv->scale->height); |
@@ -554,11 +535,6 @@ static int tw9910_start_capture(struct soc_camera_device *icd) | |||
554 | return 0; | 535 | return 0; |
555 | } | 536 | } |
556 | 537 | ||
557 | static int tw9910_stop_capture(struct soc_camera_device *icd) | ||
558 | { | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int tw9910_set_bus_param(struct soc_camera_device *icd, | 538 | static int tw9910_set_bus_param(struct soc_camera_device *icd, |
563 | unsigned long flags) | 539 | unsigned long flags) |
564 | { | 540 | { |
@@ -567,8 +543,9 @@ static int tw9910_set_bus_param(struct soc_camera_device *icd, | |||
567 | 543 | ||
568 | static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) | 544 | static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) |
569 | { | 545 | { |
570 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | 546 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
571 | struct soc_camera_link *icl = priv->client->dev.platform_data; | 547 | struct tw9910_priv *priv = to_tw9910(client); |
548 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
572 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | 549 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | |
573 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | 550 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | |
574 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; | 551 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; |
@@ -576,21 +553,11 @@ static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) | |||
576 | return soc_camera_apply_sensor_flags(icl, flags); | 553 | return soc_camera_apply_sensor_flags(icl, flags); |
577 | } | 554 | } |
578 | 555 | ||
579 | static int tw9910_get_chip_id(struct soc_camera_device *icd, | 556 | static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) |
580 | struct v4l2_dbg_chip_ident *id) | ||
581 | { | ||
582 | id->ident = V4L2_IDENT_TW9910; | ||
583 | id->revision = 0; | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int tw9910_set_std(struct soc_camera_device *icd, | ||
589 | v4l2_std_id *a) | ||
590 | { | 557 | { |
591 | int ret = -EINVAL; | 558 | int ret = -EINVAL; |
592 | 559 | ||
593 | if (*a & (V4L2_STD_NTSC | V4L2_STD_PAL)) | 560 | if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL)) |
594 | ret = 0; | 561 | ret = 0; |
595 | 562 | ||
596 | return ret; | 563 | return ret; |
@@ -606,17 +573,26 @@ static int tw9910_enum_input(struct soc_camera_device *icd, | |||
606 | return 0; | 573 | return 0; |
607 | } | 574 | } |
608 | 575 | ||
576 | static int tw9910_g_chip_ident(struct v4l2_subdev *sd, | ||
577 | struct v4l2_dbg_chip_ident *id) | ||
578 | { | ||
579 | id->ident = V4L2_IDENT_TW9910; | ||
580 | id->revision = 0; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
609 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 585 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
610 | static int tw9910_get_register(struct soc_camera_device *icd, | 586 | static int tw9910_g_register(struct v4l2_subdev *sd, |
611 | struct v4l2_dbg_register *reg) | 587 | struct v4l2_dbg_register *reg) |
612 | { | 588 | { |
613 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | 589 | struct i2c_client *client = sd->priv; |
614 | int ret; | 590 | int ret; |
615 | 591 | ||
616 | if (reg->reg > 0xff) | 592 | if (reg->reg > 0xff) |
617 | return -EINVAL; | 593 | return -EINVAL; |
618 | 594 | ||
619 | ret = i2c_smbus_read_byte_data(priv->client, reg->reg); | 595 | ret = i2c_smbus_read_byte_data(client, reg->reg); |
620 | if (ret < 0) | 596 | if (ret < 0) |
621 | return ret; | 597 | return ret; |
622 | 598 | ||
@@ -628,23 +604,25 @@ static int tw9910_get_register(struct soc_camera_device *icd, | |||
628 | return 0; | 604 | return 0; |
629 | } | 605 | } |
630 | 606 | ||
631 | static int tw9910_set_register(struct soc_camera_device *icd, | 607 | static int tw9910_s_register(struct v4l2_subdev *sd, |
632 | struct v4l2_dbg_register *reg) | 608 | struct v4l2_dbg_register *reg) |
633 | { | 609 | { |
634 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | 610 | struct i2c_client *client = sd->priv; |
635 | 611 | ||
636 | if (reg->reg > 0xff || | 612 | if (reg->reg > 0xff || |
637 | reg->val > 0xff) | 613 | reg->val > 0xff) |
638 | return -EINVAL; | 614 | return -EINVAL; |
639 | 615 | ||
640 | return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val); | 616 | return i2c_smbus_write_byte_data(client, reg->reg, reg->val); |
641 | } | 617 | } |
642 | #endif | 618 | #endif |
643 | 619 | ||
644 | static int tw9910_set_crop(struct soc_camera_device *icd, | 620 | static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
645 | struct v4l2_rect *rect) | ||
646 | { | 621 | { |
647 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | 622 | struct v4l2_rect *rect = &a->c; |
623 | struct i2c_client *client = sd->priv; | ||
624 | struct tw9910_priv *priv = to_tw9910(client); | ||
625 | struct soc_camera_device *icd = client->dev.platform_data; | ||
648 | int ret = -EINVAL; | 626 | int ret = -EINVAL; |
649 | u8 val; | 627 | u8 val; |
650 | 628 | ||
@@ -658,8 +636,8 @@ static int tw9910_set_crop(struct soc_camera_device *icd, | |||
658 | /* | 636 | /* |
659 | * reset hardware | 637 | * reset hardware |
660 | */ | 638 | */ |
661 | tw9910_reset(priv->client); | 639 | tw9910_reset(client); |
662 | ret = tw9910_write_array(priv->client, tw9910_default_regs); | 640 | ret = tw9910_write_array(client, tw9910_default_regs); |
663 | if (ret < 0) | 641 | if (ret < 0) |
664 | goto tw9910_set_fmt_error; | 642 | goto tw9910_set_fmt_error; |
665 | 643 | ||
@@ -670,7 +648,7 @@ static int tw9910_set_crop(struct soc_camera_device *icd, | |||
670 | if (SOCAM_DATAWIDTH_16 == priv->info->buswidth) | 648 | if (SOCAM_DATAWIDTH_16 == priv->info->buswidth) |
671 | val = LEN; | 649 | val = LEN; |
672 | 650 | ||
673 | ret = tw9910_mask_set(priv->client, OPFORM, LEN, val); | 651 | ret = tw9910_mask_set(client, OPFORM, LEN, val); |
674 | if (ret < 0) | 652 | if (ret < 0) |
675 | goto tw9910_set_fmt_error; | 653 | goto tw9910_set_fmt_error; |
676 | 654 | ||
@@ -698,52 +676,139 @@ static int tw9910_set_crop(struct soc_camera_device *icd, | |||
698 | val = 0; | 676 | val = 0; |
699 | } | 677 | } |
700 | 678 | ||
701 | ret = tw9910_mask_set(priv->client, VBICNTL, RTSEL_MASK, val); | 679 | ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val); |
702 | if (ret < 0) | 680 | if (ret < 0) |
703 | goto tw9910_set_fmt_error; | 681 | goto tw9910_set_fmt_error; |
704 | 682 | ||
705 | /* | 683 | /* |
706 | * set scale | 684 | * set scale |
707 | */ | 685 | */ |
708 | ret = tw9910_set_scale(priv->client, priv->scale); | 686 | ret = tw9910_set_scale(client, priv->scale); |
709 | if (ret < 0) | 687 | if (ret < 0) |
710 | goto tw9910_set_fmt_error; | 688 | goto tw9910_set_fmt_error; |
711 | 689 | ||
712 | /* | 690 | /* |
713 | * set cropping | 691 | * set cropping |
714 | */ | 692 | */ |
715 | ret = tw9910_set_cropping(priv->client, &tw9910_cropping_ctrl); | 693 | ret = tw9910_set_cropping(client, &tw9910_cropping_ctrl); |
716 | if (ret < 0) | 694 | if (ret < 0) |
717 | goto tw9910_set_fmt_error; | 695 | goto tw9910_set_fmt_error; |
718 | 696 | ||
719 | /* | 697 | /* |
720 | * set hsync | 698 | * set hsync |
721 | */ | 699 | */ |
722 | ret = tw9910_set_hsync(priv->client, &tw9910_hsync_ctrl); | 700 | ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); |
723 | if (ret < 0) | 701 | if (ret < 0) |
724 | goto tw9910_set_fmt_error; | 702 | goto tw9910_set_fmt_error; |
725 | 703 | ||
704 | rect->width = priv->scale->width; | ||
705 | rect->height = priv->scale->height; | ||
706 | rect->left = 0; | ||
707 | rect->top = 0; | ||
708 | |||
726 | return ret; | 709 | return ret; |
727 | 710 | ||
728 | tw9910_set_fmt_error: | 711 | tw9910_set_fmt_error: |
729 | 712 | ||
730 | tw9910_reset(priv->client); | 713 | tw9910_reset(client); |
731 | priv->scale = NULL; | 714 | priv->scale = NULL; |
732 | 715 | ||
733 | return ret; | 716 | return ret; |
734 | } | 717 | } |
735 | 718 | ||
736 | static int tw9910_set_fmt(struct soc_camera_device *icd, | 719 | static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
737 | struct v4l2_format *f) | 720 | { |
721 | struct i2c_client *client = sd->priv; | ||
722 | struct tw9910_priv *priv = to_tw9910(client); | ||
723 | |||
724 | if (!priv->scale) { | ||
725 | int ret; | ||
726 | struct v4l2_crop crop = { | ||
727 | .c = { | ||
728 | .left = 0, | ||
729 | .top = 0, | ||
730 | .width = 640, | ||
731 | .height = 480, | ||
732 | }, | ||
733 | }; | ||
734 | ret = tw9910_s_crop(sd, &crop); | ||
735 | if (ret < 0) | ||
736 | return ret; | ||
737 | } | ||
738 | |||
739 | a->c.left = 0; | ||
740 | a->c.top = 0; | ||
741 | a->c.width = priv->scale->width; | ||
742 | a->c.height = priv->scale->height; | ||
743 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
738 | { | 749 | { |
750 | a->bounds.left = 0; | ||
751 | a->bounds.top = 0; | ||
752 | a->bounds.width = 768; | ||
753 | a->bounds.height = 576; | ||
754 | a->defrect.left = 0; | ||
755 | a->defrect.top = 0; | ||
756 | a->defrect.width = 640; | ||
757 | a->defrect.height = 480; | ||
758 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
759 | a->pixelaspect.numerator = 1; | ||
760 | a->pixelaspect.denominator = 1; | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
766 | { | ||
767 | struct i2c_client *client = sd->priv; | ||
768 | struct tw9910_priv *priv = to_tw9910(client); | ||
769 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
770 | |||
771 | if (!priv->scale) { | ||
772 | int ret; | ||
773 | struct v4l2_crop crop = { | ||
774 | .c = { | ||
775 | .left = 0, | ||
776 | .top = 0, | ||
777 | .width = 640, | ||
778 | .height = 480, | ||
779 | }, | ||
780 | }; | ||
781 | ret = tw9910_s_crop(sd, &crop); | ||
782 | if (ret < 0) | ||
783 | return ret; | ||
784 | } | ||
785 | |||
786 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
787 | |||
788 | pix->width = priv->scale->width; | ||
789 | pix->height = priv->scale->height; | ||
790 | pix->pixelformat = V4L2_PIX_FMT_VYUY; | ||
791 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
792 | pix->field = V4L2_FIELD_INTERLACED; | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
798 | { | ||
799 | struct i2c_client *client = sd->priv; | ||
800 | struct tw9910_priv *priv = to_tw9910(client); | ||
739 | struct v4l2_pix_format *pix = &f->fmt.pix; | 801 | struct v4l2_pix_format *pix = &f->fmt.pix; |
740 | struct v4l2_rect rect = { | 802 | /* See tw9910_s_crop() - no proper cropping support */ |
741 | .left = icd->x_current, | 803 | struct v4l2_crop a = { |
742 | .top = icd->y_current, | 804 | .c = { |
743 | .width = pix->width, | 805 | .left = 0, |
744 | .height = pix->height, | 806 | .top = 0, |
807 | .width = pix->width, | ||
808 | .height = pix->height, | ||
809 | }, | ||
745 | }; | 810 | }; |
746 | int i; | 811 | int i, ret; |
747 | 812 | ||
748 | /* | 813 | /* |
749 | * check color format | 814 | * check color format |
@@ -755,19 +820,25 @@ static int tw9910_set_fmt(struct soc_camera_device *icd, | |||
755 | if (i == ARRAY_SIZE(tw9910_color_fmt)) | 820 | if (i == ARRAY_SIZE(tw9910_color_fmt)) |
756 | return -EINVAL; | 821 | return -EINVAL; |
757 | 822 | ||
758 | return tw9910_set_crop(icd, &rect); | 823 | ret = tw9910_s_crop(sd, &a); |
824 | if (!ret) { | ||
825 | pix->width = priv->scale->width; | ||
826 | pix->height = priv->scale->height; | ||
827 | } | ||
828 | return ret; | ||
759 | } | 829 | } |
760 | 830 | ||
761 | static int tw9910_try_fmt(struct soc_camera_device *icd, | 831 | static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
762 | struct v4l2_format *f) | ||
763 | { | 832 | { |
833 | struct i2c_client *client = sd->priv; | ||
834 | struct soc_camera_device *icd = client->dev.platform_data; | ||
764 | struct v4l2_pix_format *pix = &f->fmt.pix; | 835 | struct v4l2_pix_format *pix = &f->fmt.pix; |
765 | const struct tw9910_scale_ctrl *scale; | 836 | const struct tw9910_scale_ctrl *scale; |
766 | 837 | ||
767 | if (V4L2_FIELD_ANY == pix->field) { | 838 | if (V4L2_FIELD_ANY == pix->field) { |
768 | pix->field = V4L2_FIELD_INTERLACED; | 839 | pix->field = V4L2_FIELD_INTERLACED; |
769 | } else if (V4L2_FIELD_INTERLACED != pix->field) { | 840 | } else if (V4L2_FIELD_INTERLACED != pix->field) { |
770 | dev_err(&icd->dev, "Field type invalid.\n"); | 841 | dev_err(&client->dev, "Field type invalid.\n"); |
771 | return -EINVAL; | 842 | return -EINVAL; |
772 | } | 843 | } |
773 | 844 | ||
@@ -784,11 +855,11 @@ static int tw9910_try_fmt(struct soc_camera_device *icd, | |||
784 | return 0; | 855 | return 0; |
785 | } | 856 | } |
786 | 857 | ||
787 | static int tw9910_video_probe(struct soc_camera_device *icd) | 858 | static int tw9910_video_probe(struct soc_camera_device *icd, |
859 | struct i2c_client *client) | ||
788 | { | 860 | { |
789 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | 861 | struct tw9910_priv *priv = to_tw9910(client); |
790 | s32 val; | 862 | s32 val; |
791 | int ret; | ||
792 | 863 | ||
793 | /* | 864 | /* |
794 | * We must have a parent by now. And it cannot be a wrong one. | 865 | * We must have a parent by now. And it cannot be a wrong one. |
@@ -803,7 +874,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd) | |||
803 | */ | 874 | */ |
804 | if (SOCAM_DATAWIDTH_16 != priv->info->buswidth && | 875 | if (SOCAM_DATAWIDTH_16 != priv->info->buswidth && |
805 | SOCAM_DATAWIDTH_8 != priv->info->buswidth) { | 876 | SOCAM_DATAWIDTH_8 != priv->info->buswidth) { |
806 | dev_err(&icd->dev, "bus width error\n"); | 877 | dev_err(&client->dev, "bus width error\n"); |
807 | return -ENODEV; | 878 | return -ENODEV; |
808 | } | 879 | } |
809 | 880 | ||
@@ -813,54 +884,54 @@ static int tw9910_video_probe(struct soc_camera_device *icd) | |||
813 | /* | 884 | /* |
814 | * check and show Product ID | 885 | * check and show Product ID |
815 | */ | 886 | */ |
816 | val = i2c_smbus_read_byte_data(priv->client, ID); | 887 | val = i2c_smbus_read_byte_data(client, ID); |
888 | |||
817 | if (0x0B != GET_ID(val) || | 889 | if (0x0B != GET_ID(val) || |
818 | 0x00 != GET_ReV(val)) { | 890 | 0x00 != GET_ReV(val)) { |
819 | dev_err(&icd->dev, | 891 | dev_err(&client->dev, |
820 | "Product ID error %x:%x\n", GET_ID(val), GET_ReV(val)); | 892 | "Product ID error %x:%x\n", GET_ID(val), GET_ReV(val)); |
821 | return -ENODEV; | 893 | return -ENODEV; |
822 | } | 894 | } |
823 | 895 | ||
824 | dev_info(&icd->dev, | 896 | dev_info(&client->dev, |
825 | "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val)); | 897 | "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val)); |
826 | 898 | ||
827 | ret = soc_camera_video_start(icd); | ||
828 | if (ret < 0) | ||
829 | return ret; | ||
830 | |||
831 | icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; | 899 | icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; |
832 | icd->vdev->current_norm = V4L2_STD_NTSC; | 900 | icd->vdev->current_norm = V4L2_STD_NTSC; |
833 | 901 | ||
834 | return ret; | 902 | return 0; |
835 | } | ||
836 | |||
837 | static void tw9910_video_remove(struct soc_camera_device *icd) | ||
838 | { | ||
839 | soc_camera_video_stop(icd); | ||
840 | } | 903 | } |
841 | 904 | ||
842 | static struct soc_camera_ops tw9910_ops = { | 905 | static struct soc_camera_ops tw9910_ops = { |
843 | .owner = THIS_MODULE, | ||
844 | .probe = tw9910_video_probe, | ||
845 | .remove = tw9910_video_remove, | ||
846 | .init = tw9910_init, | ||
847 | .release = tw9910_release, | ||
848 | .start_capture = tw9910_start_capture, | ||
849 | .stop_capture = tw9910_stop_capture, | ||
850 | .set_crop = tw9910_set_crop, | ||
851 | .set_fmt = tw9910_set_fmt, | ||
852 | .try_fmt = tw9910_try_fmt, | ||
853 | .set_bus_param = tw9910_set_bus_param, | 906 | .set_bus_param = tw9910_set_bus_param, |
854 | .query_bus_param = tw9910_query_bus_param, | 907 | .query_bus_param = tw9910_query_bus_param, |
855 | .get_chip_id = tw9910_get_chip_id, | ||
856 | .set_std = tw9910_set_std, | ||
857 | .enum_input = tw9910_enum_input, | 908 | .enum_input = tw9910_enum_input, |
909 | }; | ||
910 | |||
911 | static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { | ||
912 | .g_chip_ident = tw9910_g_chip_ident, | ||
913 | .s_std = tw9910_s_std, | ||
858 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 914 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
859 | .get_register = tw9910_get_register, | 915 | .g_register = tw9910_g_register, |
860 | .set_register = tw9910_set_register, | 916 | .s_register = tw9910_s_register, |
861 | #endif | 917 | #endif |
862 | }; | 918 | }; |
863 | 919 | ||
920 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | ||
921 | .s_stream = tw9910_s_stream, | ||
922 | .g_fmt = tw9910_g_fmt, | ||
923 | .s_fmt = tw9910_s_fmt, | ||
924 | .try_fmt = tw9910_try_fmt, | ||
925 | .cropcap = tw9910_cropcap, | ||
926 | .g_crop = tw9910_g_crop, | ||
927 | .s_crop = tw9910_s_crop, | ||
928 | }; | ||
929 | |||
930 | static struct v4l2_subdev_ops tw9910_subdev_ops = { | ||
931 | .core = &tw9910_subdev_core_ops, | ||
932 | .video = &tw9910_subdev_video_ops, | ||
933 | }; | ||
934 | |||
864 | /* | 935 | /* |
865 | * i2c_driver function | 936 | * i2c_driver function |
866 | */ | 937 | */ |
@@ -871,18 +942,24 @@ static int tw9910_probe(struct i2c_client *client, | |||
871 | { | 942 | { |
872 | struct tw9910_priv *priv; | 943 | struct tw9910_priv *priv; |
873 | struct tw9910_video_info *info; | 944 | struct tw9910_video_info *info; |
874 | struct soc_camera_device *icd; | 945 | struct soc_camera_device *icd = client->dev.platform_data; |
875 | const struct tw9910_scale_ctrl *scale; | 946 | struct i2c_adapter *adapter = |
876 | int i, ret; | 947 | to_i2c_adapter(client->dev.parent); |
948 | struct soc_camera_link *icl; | ||
949 | int ret; | ||
950 | |||
951 | if (!icd) { | ||
952 | dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); | ||
953 | return -EINVAL; | ||
954 | } | ||
877 | 955 | ||
878 | if (!client->dev.platform_data) | 956 | icl = to_soc_camera_link(icd); |
957 | if (!icl) | ||
879 | return -EINVAL; | 958 | return -EINVAL; |
880 | 959 | ||
881 | info = container_of(client->dev.platform_data, | 960 | info = container_of(icl, struct tw9910_video_info, link); |
882 | struct tw9910_video_info, link); | ||
883 | 961 | ||
884 | if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent), | 962 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
885 | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
886 | dev_err(&client->dev, | 963 | dev_err(&client->dev, |
887 | "I2C-Adapter doesn't support " | 964 | "I2C-Adapter doesn't support " |
888 | "I2C_FUNC_SMBUS_BYTE_DATA\n"); | 965 | "I2C_FUNC_SMBUS_BYTE_DATA\n"); |
@@ -894,40 +971,15 @@ static int tw9910_probe(struct i2c_client *client, | |||
894 | return -ENOMEM; | 971 | return -ENOMEM; |
895 | 972 | ||
896 | priv->info = info; | 973 | priv->info = info; |
897 | priv->client = client; | ||
898 | i2c_set_clientdata(client, priv); | ||
899 | 974 | ||
900 | icd = &priv->icd; | 975 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); |
976 | |||
901 | icd->ops = &tw9910_ops; | 977 | icd->ops = &tw9910_ops; |
902 | icd->control = &client->dev; | ||
903 | icd->iface = info->link.bus_id; | 978 | icd->iface = info->link.bus_id; |
904 | 979 | ||
905 | /* | 980 | ret = tw9910_video_probe(icd, client); |
906 | * set width and height | ||
907 | */ | ||
908 | icd->width_max = tw9910_ntsc_scales[0].width; /* set default */ | ||
909 | icd->width_min = tw9910_ntsc_scales[0].width; | ||
910 | icd->height_max = tw9910_ntsc_scales[0].height; | ||
911 | icd->height_min = tw9910_ntsc_scales[0].height; | ||
912 | |||
913 | scale = tw9910_ntsc_scales; | ||
914 | for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) { | ||
915 | icd->width_max = max(scale[i].width, icd->width_max); | ||
916 | icd->width_min = min(scale[i].width, icd->width_min); | ||
917 | icd->height_max = max(scale[i].height, icd->height_max); | ||
918 | icd->height_min = min(scale[i].height, icd->height_min); | ||
919 | } | ||
920 | scale = tw9910_pal_scales; | ||
921 | for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) { | ||
922 | icd->width_max = max(scale[i].width, icd->width_max); | ||
923 | icd->width_min = min(scale[i].width, icd->width_min); | ||
924 | icd->height_max = max(scale[i].height, icd->height_max); | ||
925 | icd->height_min = min(scale[i].height, icd->height_min); | ||
926 | } | ||
927 | |||
928 | ret = soc_camera_device_register(icd); | ||
929 | |||
930 | if (ret) { | 981 | if (ret) { |
982 | icd->ops = NULL; | ||
931 | i2c_set_clientdata(client, NULL); | 983 | i2c_set_clientdata(client, NULL); |
932 | kfree(priv); | 984 | kfree(priv); |
933 | } | 985 | } |
@@ -937,9 +989,10 @@ static int tw9910_probe(struct i2c_client *client, | |||
937 | 989 | ||
938 | static int tw9910_remove(struct i2c_client *client) | 990 | static int tw9910_remove(struct i2c_client *client) |
939 | { | 991 | { |
940 | struct tw9910_priv *priv = i2c_get_clientdata(client); | 992 | struct tw9910_priv *priv = to_tw9910(client); |
993 | struct soc_camera_device *icd = client->dev.platform_data; | ||
941 | 994 | ||
942 | soc_camera_device_unregister(&priv->icd); | 995 | icd->ops = NULL; |
943 | i2c_set_clientdata(client, NULL); | 996 | i2c_set_clientdata(client, NULL); |
944 | kfree(priv); | 997 | kfree(priv); |
945 | return 0; | 998 | return 0; |
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 1fe5befbbf85..f97fd06d5948 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c | |||
@@ -246,9 +246,9 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) | |||
246 | switch (usbvision_device_data[usbvision->DevModel].Codec) { | 246 | switch (usbvision_device_data[usbvision->DevModel].Codec) { |
247 | case CODEC_SAA7113: | 247 | case CODEC_SAA7113: |
248 | case CODEC_SAA7111: | 248 | case CODEC_SAA7111: |
249 | v4l2_i2c_new_probed_subdev(&usbvision->v4l2_dev, | 249 | v4l2_i2c_new_subdev(&usbvision->v4l2_dev, |
250 | &usbvision->i2c_adap, "saa7115", | 250 | &usbvision->i2c_adap, "saa7115", |
251 | "saa7115_auto", saa711x_addrs); | 251 | "saa7115_auto", 0, saa711x_addrs); |
252 | break; | 252 | break; |
253 | } | 253 | } |
254 | if (usbvision_device_data[usbvision->DevModel].Tuner == 1) { | 254 | if (usbvision_device_data[usbvision->DevModel].Tuner == 1) { |
@@ -256,16 +256,16 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) | |||
256 | enum v4l2_i2c_tuner_type type; | 256 | enum v4l2_i2c_tuner_type type; |
257 | struct tuner_setup tun_setup; | 257 | struct tuner_setup tun_setup; |
258 | 258 | ||
259 | sd = v4l2_i2c_new_probed_subdev(&usbvision->v4l2_dev, | 259 | sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev, |
260 | &usbvision->i2c_adap, "tuner", | 260 | &usbvision->i2c_adap, "tuner", |
261 | "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | 261 | "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); |
262 | /* depending on whether we found a demod or not, select | 262 | /* depending on whether we found a demod or not, select |
263 | the tuner type. */ | 263 | the tuner type. */ |
264 | type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; | 264 | type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; |
265 | 265 | ||
266 | sd = v4l2_i2c_new_probed_subdev(&usbvision->v4l2_dev, | 266 | sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev, |
267 | &usbvision->i2c_adap, "tuner", | 267 | &usbvision->i2c_adap, "tuner", |
268 | "tuner", v4l2_i2c_tuner_addrs(type)); | 268 | "tuner", 0, v4l2_i2c_tuner_addrs(type)); |
269 | 269 | ||
270 | if (usbvision->tuner_type != -1) { | 270 | if (usbvision->tuner_type != -1) { |
271 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | 271 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; |
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 5b757f32d997..f960e8ea4f17 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c | |||
@@ -124,13 +124,14 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, | |||
124 | int ret; | 124 | int ret; |
125 | 125 | ||
126 | size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; | 126 | size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; |
127 | if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && | ||
128 | query == UVC_GET_DEF) | ||
129 | return -EIO; | ||
130 | |||
127 | data = kmalloc(size, GFP_KERNEL); | 131 | data = kmalloc(size, GFP_KERNEL); |
128 | if (data == NULL) | 132 | if (data == NULL) |
129 | return -ENOMEM; | 133 | return -ENOMEM; |
130 | 134 | ||
131 | if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) | ||
132 | return -EIO; | ||
133 | |||
134 | ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum, | 135 | ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum, |
135 | probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, | 136 | probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, |
136 | size, UVC_CTRL_STREAMING_TIMEOUT); | 137 | size, UVC_CTRL_STREAMING_TIMEOUT); |
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 761fbd64db58..0c2105ca611e 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c | |||
@@ -564,10 +564,9 @@ static noinline long v4l1_compat_get_input_info( | |||
564 | break; | 564 | break; |
565 | } | 565 | } |
566 | chan->norm = 0; | 566 | chan->norm = 0; |
567 | err = drv(file, VIDIOC_G_STD, &sid); | 567 | /* Note: G_STD might not be present for radio receivers, |
568 | if (err < 0) | 568 | * so we should ignore any errors. */ |
569 | dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %ld\n", err); | 569 | if (drv(file, VIDIOC_G_STD, &sid) == 0) { |
570 | if (err == 0) { | ||
571 | if (sid & V4L2_STD_PAL) | 570 | if (sid & V4L2_STD_PAL) |
572 | chan->norm = VIDEO_MODE_PAL; | 571 | chan->norm = VIDEO_MODE_PAL; |
573 | if (sid & V4L2_STD_NTSC) | 572 | if (sid & V4L2_STD_NTSC) |
@@ -776,10 +775,9 @@ static noinline long v4l1_compat_get_tuner( | |||
776 | tun->flags |= VIDEO_TUNER_SECAM; | 775 | tun->flags |= VIDEO_TUNER_SECAM; |
777 | } | 776 | } |
778 | 777 | ||
779 | err = drv(file, VIDIOC_G_STD, &sid); | 778 | /* Note: G_STD might not be present for radio receivers, |
780 | if (err < 0) | 779 | * so we should ignore any errors. */ |
781 | dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %ld\n", err); | 780 | if (drv(file, VIDIOC_G_STD, &sid) == 0) { |
782 | if (err == 0) { | ||
783 | if (sid & V4L2_STD_PAL) | 781 | if (sid & V4L2_STD_PAL) |
784 | tun->mode = VIDEO_MODE_PAL; | 782 | tun->mode = VIDEO_MODE_PAL; |
785 | if (sid & V4L2_STD_NTSC) | 783 | if (sid & V4L2_STD_NTSC) |
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 3a0c64935b0e..f5a93ae3cdf9 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -814,139 +814,6 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); | |||
814 | 814 | ||
815 | 815 | ||
816 | /* Load an i2c sub-device. */ | 816 | /* Load an i2c sub-device. */ |
817 | struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, | ||
818 | struct i2c_adapter *adapter, | ||
819 | const char *module_name, const char *client_type, u8 addr) | ||
820 | { | ||
821 | struct v4l2_subdev *sd = NULL; | ||
822 | struct i2c_client *client; | ||
823 | struct i2c_board_info info; | ||
824 | |||
825 | BUG_ON(!v4l2_dev); | ||
826 | |||
827 | if (module_name) | ||
828 | request_module(module_name); | ||
829 | |||
830 | /* Setup the i2c board info with the device type and | ||
831 | the device address. */ | ||
832 | memset(&info, 0, sizeof(info)); | ||
833 | strlcpy(info.type, client_type, sizeof(info.type)); | ||
834 | info.addr = addr; | ||
835 | |||
836 | /* Create the i2c client */ | ||
837 | client = i2c_new_device(adapter, &info); | ||
838 | /* Note: it is possible in the future that | ||
839 | c->driver is NULL if the driver is still being loaded. | ||
840 | We need better support from the kernel so that we | ||
841 | can easily wait for the load to finish. */ | ||
842 | if (client == NULL || client->driver == NULL) | ||
843 | goto error; | ||
844 | |||
845 | /* Lock the module so we can safely get the v4l2_subdev pointer */ | ||
846 | if (!try_module_get(client->driver->driver.owner)) | ||
847 | goto error; | ||
848 | sd = i2c_get_clientdata(client); | ||
849 | |||
850 | /* Register with the v4l2_device which increases the module's | ||
851 | use count as well. */ | ||
852 | if (v4l2_device_register_subdev(v4l2_dev, sd)) | ||
853 | sd = NULL; | ||
854 | /* Decrease the module use count to match the first try_module_get. */ | ||
855 | module_put(client->driver->driver.owner); | ||
856 | |||
857 | if (sd) { | ||
858 | /* We return errors from v4l2_subdev_call only if we have the | ||
859 | callback as the .s_config is not mandatory */ | ||
860 | int err = v4l2_subdev_call(sd, core, s_config, 0, NULL); | ||
861 | |||
862 | if (err && err != -ENOIOCTLCMD) { | ||
863 | v4l2_device_unregister_subdev(sd); | ||
864 | sd = NULL; | ||
865 | } | ||
866 | } | ||
867 | |||
868 | error: | ||
869 | /* If we have a client but no subdev, then something went wrong and | ||
870 | we must unregister the client. */ | ||
871 | if (client && sd == NULL) | ||
872 | i2c_unregister_device(client); | ||
873 | return sd; | ||
874 | } | ||
875 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); | ||
876 | |||
877 | /* Probe and load an i2c sub-device. */ | ||
878 | struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev, | ||
879 | struct i2c_adapter *adapter, | ||
880 | const char *module_name, const char *client_type, | ||
881 | const unsigned short *addrs) | ||
882 | { | ||
883 | struct v4l2_subdev *sd = NULL; | ||
884 | struct i2c_client *client = NULL; | ||
885 | struct i2c_board_info info; | ||
886 | |||
887 | BUG_ON(!v4l2_dev); | ||
888 | |||
889 | if (module_name) | ||
890 | request_module(module_name); | ||
891 | |||
892 | /* Setup the i2c board info with the device type and | ||
893 | the device address. */ | ||
894 | memset(&info, 0, sizeof(info)); | ||
895 | strlcpy(info.type, client_type, sizeof(info.type)); | ||
896 | |||
897 | /* Probe and create the i2c client */ | ||
898 | client = i2c_new_probed_device(adapter, &info, addrs); | ||
899 | /* Note: it is possible in the future that | ||
900 | c->driver is NULL if the driver is still being loaded. | ||
901 | We need better support from the kernel so that we | ||
902 | can easily wait for the load to finish. */ | ||
903 | if (client == NULL || client->driver == NULL) | ||
904 | goto error; | ||
905 | |||
906 | /* Lock the module so we can safely get the v4l2_subdev pointer */ | ||
907 | if (!try_module_get(client->driver->driver.owner)) | ||
908 | goto error; | ||
909 | sd = i2c_get_clientdata(client); | ||
910 | |||
911 | /* Register with the v4l2_device which increases the module's | ||
912 | use count as well. */ | ||
913 | if (v4l2_device_register_subdev(v4l2_dev, sd)) | ||
914 | sd = NULL; | ||
915 | /* Decrease the module use count to match the first try_module_get. */ | ||
916 | module_put(client->driver->driver.owner); | ||
917 | |||
918 | if (sd) { | ||
919 | /* We return errors from v4l2_subdev_call only if we have the | ||
920 | callback as the .s_config is not mandatory */ | ||
921 | int err = v4l2_subdev_call(sd, core, s_config, 0, NULL); | ||
922 | |||
923 | if (err && err != -ENOIOCTLCMD) { | ||
924 | v4l2_device_unregister_subdev(sd); | ||
925 | sd = NULL; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | error: | ||
930 | /* If we have a client but no subdev, then something went wrong and | ||
931 | we must unregister the client. */ | ||
932 | if (client && sd == NULL) | ||
933 | i2c_unregister_device(client); | ||
934 | return sd; | ||
935 | } | ||
936 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev); | ||
937 | |||
938 | struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev, | ||
939 | struct i2c_adapter *adapter, | ||
940 | const char *module_name, const char *client_type, u8 addr) | ||
941 | { | ||
942 | unsigned short addrs[2] = { addr, I2C_CLIENT_END }; | ||
943 | |||
944 | return v4l2_i2c_new_probed_subdev(v4l2_dev, adapter, | ||
945 | module_name, client_type, addrs); | ||
946 | } | ||
947 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr); | ||
948 | |||
949 | /* Load an i2c sub-device. */ | ||
950 | struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, | 817 | struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, |
951 | struct i2c_adapter *adapter, const char *module_name, | 818 | struct i2c_adapter *adapter, const char *module_name, |
952 | struct i2c_board_info *info, const unsigned short *probe_addrs) | 819 | struct i2c_board_info *info, const unsigned short *probe_addrs) |
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index a7f1b69a7dab..500cbe9891ac 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -66,7 +66,49 @@ static struct device_attribute video_device_attrs[] = { | |||
66 | */ | 66 | */ |
67 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; | 67 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; |
68 | static DEFINE_MUTEX(videodev_lock); | 68 | static DEFINE_MUTEX(videodev_lock); |
69 | static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); | 69 | static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); |
70 | |||
71 | /* Device node utility functions */ | ||
72 | |||
73 | /* Note: these utility functions all assume that vfl_type is in the range | ||
74 | [0, VFL_TYPE_MAX-1]. */ | ||
75 | |||
76 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | ||
77 | /* Return the bitmap corresponding to vfl_type. */ | ||
78 | static inline unsigned long *devnode_bits(int vfl_type) | ||
79 | { | ||
80 | /* Any types not assigned to fixed minor ranges must be mapped to | ||
81 | one single bitmap for the purposes of finding a free node number | ||
82 | since all those unassigned types use the same minor range. */ | ||
83 | int idx = (vfl_type > VFL_TYPE_VTX) ? VFL_TYPE_MAX - 1 : vfl_type; | ||
84 | |||
85 | return devnode_nums[idx]; | ||
86 | } | ||
87 | #else | ||
88 | /* Return the bitmap corresponding to vfl_type. */ | ||
89 | static inline unsigned long *devnode_bits(int vfl_type) | ||
90 | { | ||
91 | return devnode_nums[vfl_type]; | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | /* Mark device node number vdev->num as used */ | ||
96 | static inline void devnode_set(struct video_device *vdev) | ||
97 | { | ||
98 | set_bit(vdev->num, devnode_bits(vdev->vfl_type)); | ||
99 | } | ||
100 | |||
101 | /* Mark device node number vdev->num as unused */ | ||
102 | static inline void devnode_clear(struct video_device *vdev) | ||
103 | { | ||
104 | clear_bit(vdev->num, devnode_bits(vdev->vfl_type)); | ||
105 | } | ||
106 | |||
107 | /* Try to find a free device node number in the range [from, to> */ | ||
108 | static inline int devnode_find(struct video_device *vdev, int from, int to) | ||
109 | { | ||
110 | return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from); | ||
111 | } | ||
70 | 112 | ||
71 | struct video_device *video_device_alloc(void) | 113 | struct video_device *video_device_alloc(void) |
72 | { | 114 | { |
@@ -119,8 +161,8 @@ static void v4l2_device_release(struct device *cd) | |||
119 | the release() callback. */ | 161 | the release() callback. */ |
120 | vdev->cdev = NULL; | 162 | vdev->cdev = NULL; |
121 | 163 | ||
122 | /* Mark minor as free */ | 164 | /* Mark device node number as free */ |
123 | clear_bit(vdev->num, video_nums[vdev->vfl_type]); | 165 | devnode_clear(vdev); |
124 | 166 | ||
125 | mutex_unlock(&videodev_lock); | 167 | mutex_unlock(&videodev_lock); |
126 | 168 | ||
@@ -299,32 +341,28 @@ static const struct file_operations v4l2_fops = { | |||
299 | }; | 341 | }; |
300 | 342 | ||
301 | /** | 343 | /** |
302 | * get_index - assign stream number based on parent device | 344 | * get_index - assign stream index number based on parent device |
303 | * @vdev: video_device to assign index number to, vdev->parent should be assigned | 345 | * @vdev: video_device to assign index number to, vdev->parent should be assigned |
304 | * @num: -1 if auto assign, requested number otherwise | ||
305 | * | 346 | * |
306 | * Note that when this is called the new device has not yet been registered | 347 | * Note that when this is called the new device has not yet been registered |
307 | * in the video_device array. | 348 | * in the video_device array, but it was able to obtain a minor number. |
349 | * | ||
350 | * This means that we can always obtain a free stream index number since | ||
351 | * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in | ||
352 | * use of the video_device array. | ||
308 | * | 353 | * |
309 | * Returns -ENFILE if num is already in use, a free index number if | 354 | * Returns a free index number. |
310 | * successful. | ||
311 | */ | 355 | */ |
312 | static int get_index(struct video_device *vdev, int num) | 356 | static int get_index(struct video_device *vdev) |
313 | { | 357 | { |
314 | /* This can be static since this function is called with the global | 358 | /* This can be static since this function is called with the global |
315 | videodev_lock held. */ | 359 | videodev_lock held. */ |
316 | static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES); | 360 | static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES); |
317 | int i; | 361 | int i; |
318 | 362 | ||
319 | if (num >= VIDEO_NUM_DEVICES) { | 363 | /* Some drivers do not set the parent. In that case always return 0. */ |
320 | printk(KERN_ERR "videodev: %s num is too large\n", __func__); | ||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | /* Some drivers do not set the parent. In that case always return | ||
325 | num or 0. */ | ||
326 | if (vdev->parent == NULL) | 364 | if (vdev->parent == NULL) |
327 | return num >= 0 ? num : 0; | 365 | return 0; |
328 | 366 | ||
329 | bitmap_zero(used, VIDEO_NUM_DEVICES); | 367 | bitmap_zero(used, VIDEO_NUM_DEVICES); |
330 | 368 | ||
@@ -335,35 +373,23 @@ static int get_index(struct video_device *vdev, int num) | |||
335 | } | 373 | } |
336 | } | 374 | } |
337 | 375 | ||
338 | if (num >= 0) { | 376 | return find_first_zero_bit(used, VIDEO_NUM_DEVICES); |
339 | if (test_bit(num, used)) | ||
340 | return -ENFILE; | ||
341 | return num; | ||
342 | } | ||
343 | |||
344 | i = find_first_zero_bit(used, VIDEO_NUM_DEVICES); | ||
345 | return i == VIDEO_NUM_DEVICES ? -ENFILE : i; | ||
346 | } | 377 | } |
347 | 378 | ||
348 | int video_register_device(struct video_device *vdev, int type, int nr) | ||
349 | { | ||
350 | return video_register_device_index(vdev, type, nr, -1); | ||
351 | } | ||
352 | EXPORT_SYMBOL(video_register_device); | ||
353 | |||
354 | /** | 379 | /** |
355 | * video_register_device_index - register video4linux devices | 380 | * video_register_device - register video4linux devices |
356 | * @vdev: video device structure we want to register | 381 | * @vdev: video device structure we want to register |
357 | * @type: type of device to register | 382 | * @type: type of device to register |
358 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... | 383 | * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... |
359 | * -1 == first free) | 384 | * -1 == first free) |
360 | * @index: stream number based on parent device; | 385 | * @warn_if_nr_in_use: warn if the desired device node number |
361 | * -1 if auto assign, requested number otherwise | 386 | * was already in use and another number was chosen instead. |
362 | * | 387 | * |
363 | * The registration code assigns minor numbers based on the type | 388 | * The registration code assigns minor numbers and device node numbers |
364 | * requested. -ENFILE is returned in all the device slots for this | 389 | * based on the requested type and registers the new device node with |
365 | * category are full. If not then the minor field is set and the | 390 | * the kernel. |
366 | * driver initialize function is called (if non %NULL). | 391 | * An error is returned if no free minor or device node number could be |
392 | * found, or if the registration of the device node failed. | ||
367 | * | 393 | * |
368 | * Zero is returned on success. | 394 | * Zero is returned on success. |
369 | * | 395 | * |
@@ -377,8 +403,8 @@ EXPORT_SYMBOL(video_register_device); | |||
377 | * | 403 | * |
378 | * %VFL_TYPE_RADIO - A radio card | 404 | * %VFL_TYPE_RADIO - A radio card |
379 | */ | 405 | */ |
380 | int video_register_device_index(struct video_device *vdev, int type, int nr, | 406 | static int __video_register_device(struct video_device *vdev, int type, int nr, |
381 | int index) | 407 | int warn_if_nr_in_use) |
382 | { | 408 | { |
383 | int i = 0; | 409 | int i = 0; |
384 | int ret; | 410 | int ret; |
@@ -421,7 +447,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
421 | if (vdev->v4l2_dev && vdev->v4l2_dev->dev) | 447 | if (vdev->v4l2_dev && vdev->v4l2_dev->dev) |
422 | vdev->parent = vdev->v4l2_dev->dev; | 448 | vdev->parent = vdev->v4l2_dev->dev; |
423 | 449 | ||
424 | /* Part 2: find a free minor, kernel number and device index. */ | 450 | /* Part 2: find a free minor, device node number and device index. */ |
425 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | 451 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
426 | /* Keep the ranges for the first four types for historical | 452 | /* Keep the ranges for the first four types for historical |
427 | * reasons. | 453 | * reasons. |
@@ -452,21 +478,22 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
452 | } | 478 | } |
453 | #endif | 479 | #endif |
454 | 480 | ||
455 | /* Pick a minor number */ | 481 | /* Pick a device node number */ |
456 | mutex_lock(&videodev_lock); | 482 | mutex_lock(&videodev_lock); |
457 | nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr); | 483 | nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt); |
458 | if (nr == minor_cnt) | 484 | if (nr == minor_cnt) |
459 | nr = find_first_zero_bit(video_nums[type], minor_cnt); | 485 | nr = devnode_find(vdev, 0, minor_cnt); |
460 | if (nr == minor_cnt) { | 486 | if (nr == minor_cnt) { |
461 | printk(KERN_ERR "could not get a free kernel number\n"); | 487 | printk(KERN_ERR "could not get a free device node number\n"); |
462 | mutex_unlock(&videodev_lock); | 488 | mutex_unlock(&videodev_lock); |
463 | return -ENFILE; | 489 | return -ENFILE; |
464 | } | 490 | } |
465 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | 491 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
466 | /* 1-on-1 mapping of kernel number to minor number */ | 492 | /* 1-on-1 mapping of device node number to minor number */ |
467 | i = nr; | 493 | i = nr; |
468 | #else | 494 | #else |
469 | /* The kernel number and minor numbers are independent */ | 495 | /* The device node number and minor numbers are independent, so |
496 | we just find the first free minor number. */ | ||
470 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) | 497 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) |
471 | if (video_device[i] == NULL) | 498 | if (video_device[i] == NULL) |
472 | break; | 499 | break; |
@@ -478,17 +505,13 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
478 | #endif | 505 | #endif |
479 | vdev->minor = i + minor_offset; | 506 | vdev->minor = i + minor_offset; |
480 | vdev->num = nr; | 507 | vdev->num = nr; |
481 | set_bit(nr, video_nums[type]); | 508 | devnode_set(vdev); |
509 | |||
482 | /* Should not happen since we thought this minor was free */ | 510 | /* Should not happen since we thought this minor was free */ |
483 | WARN_ON(video_device[vdev->minor] != NULL); | 511 | WARN_ON(video_device[vdev->minor] != NULL); |
484 | ret = vdev->index = get_index(vdev, index); | 512 | vdev->index = get_index(vdev); |
485 | mutex_unlock(&videodev_lock); | 513 | mutex_unlock(&videodev_lock); |
486 | 514 | ||
487 | if (ret < 0) { | ||
488 | printk(KERN_ERR "%s: get_index failed\n", __func__); | ||
489 | goto cleanup; | ||
490 | } | ||
491 | |||
492 | /* Part 3: Initialize the character device */ | 515 | /* Part 3: Initialize the character device */ |
493 | vdev->cdev = cdev_alloc(); | 516 | vdev->cdev = cdev_alloc(); |
494 | if (vdev->cdev == NULL) { | 517 | if (vdev->cdev == NULL) { |
@@ -517,7 +540,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
517 | vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); | 540 | vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); |
518 | if (vdev->parent) | 541 | if (vdev->parent) |
519 | vdev->dev.parent = vdev->parent; | 542 | vdev->dev.parent = vdev->parent; |
520 | dev_set_name(&vdev->dev, "%s%d", name_base, nr); | 543 | dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); |
521 | ret = device_register(&vdev->dev); | 544 | ret = device_register(&vdev->dev); |
522 | if (ret < 0) { | 545 | if (ret < 0) { |
523 | printk(KERN_ERR "%s: device_register failed\n", __func__); | 546 | printk(KERN_ERR "%s: device_register failed\n", __func__); |
@@ -527,6 +550,10 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
527 | reference to the device goes away. */ | 550 | reference to the device goes away. */ |
528 | vdev->dev.release = v4l2_device_release; | 551 | vdev->dev.release = v4l2_device_release; |
529 | 552 | ||
553 | if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) | ||
554 | printk(KERN_WARNING "%s: requested %s%d, got %s%d\n", | ||
555 | __func__, name_base, nr, name_base, vdev->num); | ||
556 | |||
530 | /* Part 5: Activate this minor. The char device can now be used. */ | 557 | /* Part 5: Activate this minor. The char device can now be used. */ |
531 | mutex_lock(&videodev_lock); | 558 | mutex_lock(&videodev_lock); |
532 | video_device[vdev->minor] = vdev; | 559 | video_device[vdev->minor] = vdev; |
@@ -537,13 +564,24 @@ cleanup: | |||
537 | mutex_lock(&videodev_lock); | 564 | mutex_lock(&videodev_lock); |
538 | if (vdev->cdev) | 565 | if (vdev->cdev) |
539 | cdev_del(vdev->cdev); | 566 | cdev_del(vdev->cdev); |
540 | clear_bit(vdev->num, video_nums[type]); | 567 | devnode_clear(vdev); |
541 | mutex_unlock(&videodev_lock); | 568 | mutex_unlock(&videodev_lock); |
542 | /* Mark this video device as never having been registered. */ | 569 | /* Mark this video device as never having been registered. */ |
543 | vdev->minor = -1; | 570 | vdev->minor = -1; |
544 | return ret; | 571 | return ret; |
545 | } | 572 | } |
546 | EXPORT_SYMBOL(video_register_device_index); | 573 | |
574 | int video_register_device(struct video_device *vdev, int type, int nr) | ||
575 | { | ||
576 | return __video_register_device(vdev, type, nr, 1); | ||
577 | } | ||
578 | EXPORT_SYMBOL(video_register_device); | ||
579 | |||
580 | int video_register_device_no_warn(struct video_device *vdev, int type, int nr) | ||
581 | { | ||
582 | return __video_register_device(vdev, type, nr, 0); | ||
583 | } | ||
584 | EXPORT_SYMBOL(video_register_device_no_warn); | ||
547 | 585 | ||
548 | /** | 586 | /** |
549 | * video_unregister_device - unregister a video4linux device | 587 | * video_unregister_device - unregister a video4linux device |
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index f3b6e15d91f2..cd6a3446ab7e 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c | |||
@@ -4333,11 +4333,11 @@ static int __init vino_module_init(void) | |||
4333 | vino_init_stage++; | 4333 | vino_init_stage++; |
4334 | 4334 | ||
4335 | vino_drvdata->decoder = | 4335 | vino_drvdata->decoder = |
4336 | v4l2_i2c_new_probed_subdev_addr(&vino_drvdata->v4l2_dev, | 4336 | v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, |
4337 | &vino_i2c_adapter, "saa7191", "saa7191", 0x45); | 4337 | "saa7191", "saa7191", 0, I2C_ADDRS(0x45)); |
4338 | vino_drvdata->camera = | 4338 | vino_drvdata->camera = |
4339 | v4l2_i2c_new_probed_subdev_addr(&vino_drvdata->v4l2_dev, | 4339 | v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, |
4340 | &vino_i2c_adapter, "indycam", "indycam", 0x2b); | 4340 | "indycam", "indycam", 0, I2C_ADDRS(0x2b)); |
4341 | 4341 | ||
4342 | dprintk("init complete!\n"); | 4342 | dprintk("init complete!\n"); |
4343 | 4343 | ||
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 602484dd3da9..37fcdc447db5 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c | |||
@@ -3515,9 +3515,9 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3515 | w9968cf_turn_on_led(cam); | 3515 | w9968cf_turn_on_led(cam); |
3516 | 3516 | ||
3517 | w9968cf_i2c_init(cam); | 3517 | w9968cf_i2c_init(cam); |
3518 | cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->v4l2_dev, | 3518 | cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev, |
3519 | &cam->i2c_adapter, | 3519 | &cam->i2c_adapter, |
3520 | "ovcamchip", "ovcamchip", addrs); | 3520 | "ovcamchip", "ovcamchip", 0, addrs); |
3521 | 3521 | ||
3522 | usb_set_intfdata(intf, cam); | 3522 | usb_set_intfdata(intf, cam); |
3523 | mutex_unlock(&cam->dev_mutex); | 3523 | mutex_unlock(&cam->dev_mutex); |
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 96971044fc78..b3c6436b33ba 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c | |||
@@ -819,8 +819,10 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
819 | (!list_empty(&cam->outqueue)) || | 819 | (!list_empty(&cam->outqueue)) || |
820 | (cam->state & DEV_DISCONNECTED) || | 820 | (cam->state & DEV_DISCONNECTED) || |
821 | (cam->state & DEV_MISCONFIGURED), | 821 | (cam->state & DEV_MISCONFIGURED), |
822 | cam->module_param.frame_timeout * | 822 | msecs_to_jiffies( |
823 | 1000 * msecs_to_jiffies(1) ); | 823 | cam->module_param.frame_timeout * 1000 |
824 | ) | ||
825 | ); | ||
824 | if (timeout < 0) { | 826 | if (timeout < 0) { |
825 | mutex_unlock(&cam->fileop_mutex); | 827 | mutex_unlock(&cam->fileop_mutex); |
826 | return timeout; | 828 | return timeout; |
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 0c4d9b1f8e6f..be70574870de 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c | |||
@@ -1357,15 +1357,15 @@ static int __devinit zoran_probe(struct pci_dev *pdev, | |||
1357 | goto zr_free_irq; | 1357 | goto zr_free_irq; |
1358 | } | 1358 | } |
1359 | 1359 | ||
1360 | zr->decoder = v4l2_i2c_new_probed_subdev(&zr->v4l2_dev, | 1360 | zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, |
1361 | &zr->i2c_adapter, zr->card.mod_decoder, zr->card.i2c_decoder, | 1361 | &zr->i2c_adapter, zr->card.mod_decoder, zr->card.i2c_decoder, |
1362 | zr->card.addrs_decoder); | 1362 | 0, zr->card.addrs_decoder); |
1363 | 1363 | ||
1364 | if (zr->card.mod_encoder) | 1364 | if (zr->card.mod_encoder) |
1365 | zr->encoder = v4l2_i2c_new_probed_subdev(&zr->v4l2_dev, | 1365 | zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, |
1366 | &zr->i2c_adapter, | 1366 | &zr->i2c_adapter, |
1367 | zr->card.mod_encoder, zr->card.i2c_encoder, | 1367 | zr->card.mod_encoder, zr->card.i2c_encoder, |
1368 | zr->card.addrs_encoder); | 1368 | 0, zr->card.addrs_encoder); |
1369 | 1369 | ||
1370 | dprintk(2, | 1370 | dprintk(2, |
1371 | KERN_INFO "%s: Initializing videocodec bus...\n", | 1371 | KERN_INFO "%s: Initializing videocodec bus...\n", |