diff options
Diffstat (limited to 'drivers/media')
215 files changed, 16869 insertions, 17396 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 8270388e2a0d..1d0758aeb8e4 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig | |||
@@ -172,6 +172,9 @@ comment "Media ancillary drivers (tuners, sensors, i2c, frontends)" | |||
172 | config MEDIA_SUBDRV_AUTOSELECT | 172 | config MEDIA_SUBDRV_AUTOSELECT |
173 | bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)" | 173 | bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)" |
174 | depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT | 174 | depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT |
175 | depends on HAS_IOMEM | ||
176 | select I2C | ||
177 | select I2C_MUX | ||
175 | default y | 178 | default y |
176 | help | 179 | help |
177 | By default, a media driver auto-selects all possible ancillary | 180 | By default, a media driver auto-selects all possible ancillary |
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 419a2d6b4349..f19a2ccd1e4b 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h | |||
@@ -239,6 +239,7 @@ | |||
239 | #define USB_PID_AVERMEDIA_A835B_4835 0x4835 | 239 | #define USB_PID_AVERMEDIA_A835B_4835 0x4835 |
240 | #define USB_PID_AVERMEDIA_1867 0x1867 | 240 | #define USB_PID_AVERMEDIA_1867 0x1867 |
241 | #define USB_PID_AVERMEDIA_A867 0xa867 | 241 | #define USB_PID_AVERMEDIA_A867 0xa867 |
242 | #define USB_PID_AVERMEDIA_H335 0x0335 | ||
242 | #define USB_PID_AVERMEDIA_TWINSTAR 0x0825 | 243 | #define USB_PID_AVERMEDIA_TWINSTAR 0x0825 |
243 | #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 | 244 | #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 |
244 | #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 | 245 | #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 |
@@ -317,6 +318,7 @@ | |||
317 | #define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6 | 318 | #define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6 |
318 | #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 | 319 | #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 |
319 | #define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 | 320 | #define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 |
321 | #define USB_PID_WINFAST_DTV_DONGLE_MINID 0x6f0f | ||
320 | #define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 | 322 | #define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 |
321 | #define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 | 323 | #define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 |
322 | #define USB_PID_GENPIX_8PSK_REV_2 0x0202 | 324 | #define USB_PID_GENPIX_8PSK_REV_2 0x0202 |
@@ -365,6 +367,7 @@ | |||
365 | #define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac | 367 | #define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac |
366 | #define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001 | 368 | #define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001 |
367 | #define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002 | 369 | #define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002 |
370 | #define USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI 0x0003 | ||
368 | #define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004 | 371 | #define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004 |
369 | #define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500 | 372 | #define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500 |
370 | #define USB_PID_CPYTO_REDI_PC50A 0xa803 | 373 | #define USB_PID_CPYTO_REDI_PC50A 0xa803 |
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index bddbab43a2df..dd12a1ebda82 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig | |||
@@ -35,6 +35,13 @@ config DVB_STV6110x | |||
35 | help | 35 | help |
36 | A Silicon tuner that supports DVB-S and DVB-S2 modes | 36 | A Silicon tuner that supports DVB-S and DVB-S2 modes |
37 | 37 | ||
38 | config DVB_M88DS3103 | ||
39 | tristate "Montage M88DS3103" | ||
40 | depends on DVB_CORE && I2C && I2C_MUX | ||
41 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
42 | help | ||
43 | Say Y when you want to support this frontend. | ||
44 | |||
38 | comment "Multistandard (cable + terrestrial) frontends" | 45 | comment "Multistandard (cable + terrestrial) frontends" |
39 | depends on DVB_CORE | 46 | depends on DVB_CORE |
40 | 47 | ||
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index f9cb43d9aed9..0c75a6aafb9d 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile | |||
@@ -85,6 +85,7 @@ obj-$(CONFIG_DVB_STV6110) += stv6110.o | |||
85 | obj-$(CONFIG_DVB_STV0900) += stv0900.o | 85 | obj-$(CONFIG_DVB_STV0900) += stv0900.o |
86 | obj-$(CONFIG_DVB_STV090x) += stv090x.o | 86 | obj-$(CONFIG_DVB_STV090x) += stv090x.o |
87 | obj-$(CONFIG_DVB_STV6110x) += stv6110x.o | 87 | obj-$(CONFIG_DVB_STV6110x) += stv6110x.o |
88 | obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o | ||
88 | obj-$(CONFIG_DVB_ISL6423) += isl6423.o | 89 | obj-$(CONFIG_DVB_ISL6423) += isl6423.o |
89 | obj-$(CONFIG_DVB_EC100) += ec100.o | 90 | obj-$(CONFIG_DVB_EC100) += ec100.o |
90 | obj-$(CONFIG_DVB_HD29L2) += hd29l2.o | 91 | obj-$(CONFIG_DVB_HD29L2) += hd29l2.o |
diff --git a/drivers/media/dvb-frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c index 74fbb5d58bed..780da58132f1 100644 --- a/drivers/media/dvb-frontends/a8293.c +++ b/drivers/media/dvb-frontends/a8293.c | |||
@@ -96,6 +96,8 @@ static int a8293_set_voltage(struct dvb_frontend *fe, | |||
96 | if (ret) | 96 | if (ret) |
97 | goto err; | 97 | goto err; |
98 | 98 | ||
99 | usleep_range(1500, 50000); | ||
100 | |||
99 | return ret; | 101 | return ret; |
100 | err: | 102 | err: |
101 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 103 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index 476b422ccf19..68f768a5422d 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c | |||
@@ -135,15 +135,33 @@ | |||
135 | 135 | ||
136 | 136 | ||
137 | enum cmds { | 137 | enum cmds { |
138 | CMD_SET_VCO = 0x10, | 138 | CMD_SET_VCOFREQ = 0x10, |
139 | CMD_TUNEREQUEST = 0x11, | 139 | CMD_TUNEREQUEST = 0x11, |
140 | CMD_MPEGCONFIG = 0x13, | 140 | CMD_GLOBAL_MPEGCFG = 0x13, |
141 | CMD_TUNERINIT = 0x14, | 141 | CMD_MPEGCFG = 0x14, |
142 | CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ | 142 | CMD_TUNERINIT = 0x15, |
143 | CMD_LNBDCLEVEL = 0x22, | 143 | CMD_GET_SRATE = 0x18, |
144 | CMD_SET_TONE = 0x23, | 144 | CMD_SET_GOLDCODE = 0x19, |
145 | CMD_UPDFWVERS = 0x35, | 145 | CMD_GET_AGCACC = 0x1a, |
146 | CMD_TUNERSLEEP = 0x36, | 146 | CMD_DEMODINIT = 0x1b, |
147 | CMD_GETCTLACC = 0x1c, | ||
148 | |||
149 | CMD_LNBCONFIG = 0x20, | ||
150 | CMD_LNBSEND = 0x21, | ||
151 | CMD_LNBDCLEVEL = 0x22, | ||
152 | CMD_LNBPCBCONFIG = 0x23, | ||
153 | CMD_LNBSENDTONEBST = 0x24, | ||
154 | CMD_LNBUPDREPLY = 0x25, | ||
155 | |||
156 | CMD_SET_GPIOMODE = 0x30, | ||
157 | CMD_SET_GPIOEN = 0x31, | ||
158 | CMD_SET_GPIODIR = 0x32, | ||
159 | CMD_SET_GPIOOUT = 0x33, | ||
160 | CMD_ENABLERSCORR = 0x34, | ||
161 | CMD_FWVERSION = 0x35, | ||
162 | CMD_SET_SLEEPMODE = 0x36, | ||
163 | CMD_BERCTRL = 0x3c, | ||
164 | CMD_EVENTCTRL = 0x3d, | ||
147 | }; | 165 | }; |
148 | 166 | ||
149 | static LIST_HEAD(hybrid_tuner_instance_list); | 167 | static LIST_HEAD(hybrid_tuner_instance_list); |
@@ -619,8 +637,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, | |||
619 | cx24117_writereg(state, 0xf7, 0x0c); | 637 | cx24117_writereg(state, 0xf7, 0x0c); |
620 | cx24117_writereg(state, 0xe0, 0x00); | 638 | cx24117_writereg(state, 0xe0, 0x00); |
621 | 639 | ||
622 | /* CMD 1B */ | 640 | /* Init demodulator */ |
623 | cmd.args[0] = 0x1b; | 641 | cmd.args[0] = CMD_DEMODINIT; |
624 | cmd.args[1] = 0x00; | 642 | cmd.args[1] = 0x00; |
625 | cmd.args[2] = 0x01; | 643 | cmd.args[2] = 0x01; |
626 | cmd.args[3] = 0x00; | 644 | cmd.args[3] = 0x00; |
@@ -629,8 +647,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, | |||
629 | if (ret != 0) | 647 | if (ret != 0) |
630 | goto error; | 648 | goto error; |
631 | 649 | ||
632 | /* CMD 10 */ | 650 | /* Set VCO frequency */ |
633 | cmd.args[0] = CMD_SET_VCO; | 651 | cmd.args[0] = CMD_SET_VCOFREQ; |
634 | cmd.args[1] = 0x06; | 652 | cmd.args[1] = 0x06; |
635 | cmd.args[2] = 0x2b; | 653 | cmd.args[2] = 0x2b; |
636 | cmd.args[3] = 0xd8; | 654 | cmd.args[3] = 0xd8; |
@@ -648,8 +666,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, | |||
648 | if (ret != 0) | 666 | if (ret != 0) |
649 | goto error; | 667 | goto error; |
650 | 668 | ||
651 | /* CMD 15 */ | 669 | /* Tuner init */ |
652 | cmd.args[0] = 0x15; | 670 | cmd.args[0] = CMD_TUNERINIT; |
653 | cmd.args[1] = 0x00; | 671 | cmd.args[1] = 0x00; |
654 | cmd.args[2] = 0x01; | 672 | cmd.args[2] = 0x01; |
655 | cmd.args[3] = 0x00; | 673 | cmd.args[3] = 0x00; |
@@ -667,8 +685,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, | |||
667 | if (ret != 0) | 685 | if (ret != 0) |
668 | goto error; | 686 | goto error; |
669 | 687 | ||
670 | /* CMD 13 */ | 688 | /* Global MPEG config */ |
671 | cmd.args[0] = CMD_MPEGCONFIG; | 689 | cmd.args[0] = CMD_GLOBAL_MPEGCFG; |
672 | cmd.args[1] = 0x00; | 690 | cmd.args[1] = 0x00; |
673 | cmd.args[2] = 0x00; | 691 | cmd.args[2] = 0x00; |
674 | cmd.args[3] = 0x00; | 692 | cmd.args[3] = 0x00; |
@@ -679,9 +697,9 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, | |||
679 | if (ret != 0) | 697 | if (ret != 0) |
680 | goto error; | 698 | goto error; |
681 | 699 | ||
682 | /* CMD 14 */ | 700 | /* MPEG config for each demod */ |
683 | for (i = 0; i < 2; i++) { | 701 | for (i = 0; i < 2; i++) { |
684 | cmd.args[0] = CMD_TUNERINIT; | 702 | cmd.args[0] = CMD_MPEGCFG; |
685 | cmd.args[1] = (u8) i; | 703 | cmd.args[1] = (u8) i; |
686 | cmd.args[2] = 0x00; | 704 | cmd.args[2] = 0x00; |
687 | cmd.args[3] = 0x05; | 705 | cmd.args[3] = 0x05; |
@@ -699,8 +717,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, | |||
699 | cx24117_writereg(state, 0xcf, 0x00); | 717 | cx24117_writereg(state, 0xcf, 0x00); |
700 | cx24117_writereg(state, 0xe5, 0x04); | 718 | cx24117_writereg(state, 0xe5, 0x04); |
701 | 719 | ||
702 | /* Firmware CMD 35: Get firmware version */ | 720 | /* Get firmware version */ |
703 | cmd.args[0] = CMD_UPDFWVERS; | 721 | cmd.args[0] = CMD_FWVERSION; |
704 | cmd.len = 2; | 722 | cmd.len = 2; |
705 | for (i = 0; i < 4; i++) { | 723 | for (i = 0; i < 4; i++) { |
706 | cmd.args[1] = i; | 724 | cmd.args[1] = i; |
@@ -779,8 +797,8 @@ static int cx24117_read_signal_strength(struct dvb_frontend *fe, | |||
779 | u8 reg = (state->demod == 0) ? | 797 | u8 reg = (state->demod == 0) ? |
780 | CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1; | 798 | CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1; |
781 | 799 | ||
782 | /* Firmware CMD 1A */ | 800 | /* Read AGC accumulator register */ |
783 | cmd.args[0] = 0x1a; | 801 | cmd.args[0] = CMD_GET_AGCACC; |
784 | cmd.args[1] = (u8) state->demod; | 802 | cmd.args[1] = (u8) state->demod; |
785 | cmd.len = 2; | 803 | cmd.len = 2; |
786 | ret = cx24117_cmd_execute(fe, &cmd); | 804 | ret = cx24117_cmd_execute(fe, &cmd); |
@@ -899,22 +917,15 @@ static int cx24117_set_voltage(struct dvb_frontend *fe, | |||
899 | voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : | 917 | voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : |
900 | "SEC_VOLTAGE_OFF"); | 918 | "SEC_VOLTAGE_OFF"); |
901 | 919 | ||
902 | /* CMD 32 */ | 920 | /* Prepare a set GPIO logic level CMD */ |
903 | cmd.args[0] = 0x32; | 921 | cmd.args[0] = CMD_SET_GPIOOUT; |
904 | cmd.args[1] = reg; | 922 | cmd.args[2] = reg; /* mask */ |
905 | cmd.args[2] = reg; | ||
906 | cmd.len = 3; | 923 | cmd.len = 3; |
907 | ret = cx24117_cmd_execute(fe, &cmd); | ||
908 | if (ret) | ||
909 | return ret; | ||
910 | 924 | ||
911 | if ((voltage == SEC_VOLTAGE_13) || | 925 | if ((voltage == SEC_VOLTAGE_13) || |
912 | (voltage == SEC_VOLTAGE_18)) { | 926 | (voltage == SEC_VOLTAGE_18)) { |
913 | /* CMD 33 */ | 927 | /* power on LNB */ |
914 | cmd.args[0] = 0x33; | ||
915 | cmd.args[1] = reg; | 928 | cmd.args[1] = reg; |
916 | cmd.args[2] = reg; | ||
917 | cmd.len = 3; | ||
918 | ret = cx24117_cmd_execute(fe, &cmd); | 929 | ret = cx24117_cmd_execute(fe, &cmd); |
919 | if (ret != 0) | 930 | if (ret != 0) |
920 | return ret; | 931 | return ret; |
@@ -926,22 +937,22 @@ static int cx24117_set_voltage(struct dvb_frontend *fe, | |||
926 | /* Wait for voltage/min repeat delay */ | 937 | /* Wait for voltage/min repeat delay */ |
927 | msleep(100); | 938 | msleep(100); |
928 | 939 | ||
929 | /* CMD 22 - CMD_LNBDCLEVEL */ | 940 | /* Set 13V/18V select pin */ |
930 | cmd.args[0] = CMD_LNBDCLEVEL; | 941 | cmd.args[0] = CMD_LNBDCLEVEL; |
931 | cmd.args[1] = state->demod ? 0 : 1; | 942 | cmd.args[1] = state->demod ? 0 : 1; |
932 | cmd.args[2] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00); | 943 | cmd.args[2] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00); |
933 | cmd.len = 3; | 944 | cmd.len = 3; |
945 | ret = cx24117_cmd_execute(fe, &cmd); | ||
934 | 946 | ||
935 | /* Min delay time before DiSEqC send */ | 947 | /* Min delay time before DiSEqC send */ |
936 | msleep(20); | 948 | msleep(20); |
937 | } else { | 949 | } else { |
938 | cmd.args[0] = 0x33; | 950 | /* power off LNB */ |
939 | cmd.args[1] = 0x00; | 951 | cmd.args[1] = 0x00; |
940 | cmd.args[2] = reg; | 952 | ret = cx24117_cmd_execute(fe, &cmd); |
941 | cmd.len = 3; | ||
942 | } | 953 | } |
943 | 954 | ||
944 | return cx24117_cmd_execute(fe, &cmd); | 955 | return ret; |
945 | } | 956 | } |
946 | 957 | ||
947 | static int cx24117_set_tone(struct dvb_frontend *fe, | 958 | static int cx24117_set_tone(struct dvb_frontend *fe, |
@@ -968,8 +979,7 @@ static int cx24117_set_tone(struct dvb_frontend *fe, | |||
968 | msleep(20); | 979 | msleep(20); |
969 | 980 | ||
970 | /* Set the tone */ | 981 | /* Set the tone */ |
971 | /* CMD 23 - CMD_SET_TONE */ | 982 | cmd.args[0] = CMD_LNBPCBCONFIG; |
972 | cmd.args[0] = CMD_SET_TONE; | ||
973 | cmd.args[1] = (state->demod ? 0 : 1); | 983 | cmd.args[1] = (state->demod ? 0 : 1); |
974 | cmd.args[2] = 0x00; | 984 | cmd.args[2] = 0x00; |
975 | cmd.args[3] = 0x00; | 985 | cmd.args[3] = 0x00; |
@@ -1231,8 +1241,8 @@ static int cx24117_initfe(struct dvb_frontend *fe) | |||
1231 | 1241 | ||
1232 | mutex_lock(&state->priv->fe_lock); | 1242 | mutex_lock(&state->priv->fe_lock); |
1233 | 1243 | ||
1234 | /* Firmware CMD 36: Power config */ | 1244 | /* Set sleep mode off */ |
1235 | cmd.args[0] = CMD_TUNERSLEEP; | 1245 | cmd.args[0] = CMD_SET_SLEEPMODE; |
1236 | cmd.args[1] = (state->demod ? 1 : 0); | 1246 | cmd.args[1] = (state->demod ? 1 : 0); |
1237 | cmd.args[2] = 0; | 1247 | cmd.args[2] = 0; |
1238 | cmd.len = 3; | 1248 | cmd.len = 3; |
@@ -1244,8 +1254,8 @@ static int cx24117_initfe(struct dvb_frontend *fe) | |||
1244 | if (ret != 0) | 1254 | if (ret != 0) |
1245 | goto exit; | 1255 | goto exit; |
1246 | 1256 | ||
1247 | /* CMD 3C */ | 1257 | /* Set BER control */ |
1248 | cmd.args[0] = 0x3c; | 1258 | cmd.args[0] = CMD_BERCTRL; |
1249 | cmd.args[1] = (state->demod ? 1 : 0); | 1259 | cmd.args[1] = (state->demod ? 1 : 0); |
1250 | cmd.args[2] = 0x10; | 1260 | cmd.args[2] = 0x10; |
1251 | cmd.args[3] = 0x10; | 1261 | cmd.args[3] = 0x10; |
@@ -1254,12 +1264,22 @@ static int cx24117_initfe(struct dvb_frontend *fe) | |||
1254 | if (ret != 0) | 1264 | if (ret != 0) |
1255 | goto exit; | 1265 | goto exit; |
1256 | 1266 | ||
1257 | /* CMD 34 */ | 1267 | /* Set RS correction (enable/disable) */ |
1258 | cmd.args[0] = 0x34; | 1268 | cmd.args[0] = CMD_ENABLERSCORR; |
1259 | cmd.args[1] = (state->demod ? 1 : 0); | 1269 | cmd.args[1] = (state->demod ? 1 : 0); |
1260 | cmd.args[2] = CX24117_OCC; | 1270 | cmd.args[2] = CX24117_OCC; |
1261 | cmd.len = 3; | 1271 | cmd.len = 3; |
1262 | ret = cx24117_cmd_execute_nolock(fe, &cmd); | 1272 | ret = cx24117_cmd_execute_nolock(fe, &cmd); |
1273 | if (ret != 0) | ||
1274 | goto exit; | ||
1275 | |||
1276 | /* Set GPIO direction */ | ||
1277 | /* Set as output - controls LNB power on/off */ | ||
1278 | cmd.args[0] = CMD_SET_GPIODIR; | ||
1279 | cmd.args[1] = 0x30; | ||
1280 | cmd.args[2] = 0x30; | ||
1281 | cmd.len = 3; | ||
1282 | ret = cx24117_cmd_execute_nolock(fe, &cmd); | ||
1263 | 1283 | ||
1264 | exit: | 1284 | exit: |
1265 | mutex_unlock(&state->priv->fe_lock); | 1285 | mutex_unlock(&state->priv->fe_lock); |
@@ -1278,8 +1298,8 @@ static int cx24117_sleep(struct dvb_frontend *fe) | |||
1278 | dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n", | 1298 | dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n", |
1279 | __func__, state->demod); | 1299 | __func__, state->demod); |
1280 | 1300 | ||
1281 | /* Firmware CMD 36: Power config */ | 1301 | /* Set sleep mode on */ |
1282 | cmd.args[0] = CMD_TUNERSLEEP; | 1302 | cmd.args[0] = CMD_SET_SLEEPMODE; |
1283 | cmd.args[1] = (state->demod ? 1 : 0); | 1303 | cmd.args[1] = (state->demod ? 1 : 0); |
1284 | cmd.args[2] = 1; | 1304 | cmd.args[2] = 1; |
1285 | cmd.len = 3; | 1305 | cmd.len = 3; |
@@ -1558,7 +1578,8 @@ static int cx24117_get_frontend(struct dvb_frontend *fe) | |||
1558 | 1578 | ||
1559 | u8 buf[0x1f-4]; | 1579 | u8 buf[0x1f-4]; |
1560 | 1580 | ||
1561 | cmd.args[0] = 0x1c; | 1581 | /* Read current tune parameters */ |
1582 | cmd.args[0] = CMD_GETCTLACC; | ||
1562 | cmd.args[1] = (u8) state->demod; | 1583 | cmd.args[1] = (u8) state->demod; |
1563 | cmd.len = 2; | 1584 | cmd.len = 2; |
1564 | ret = cx24117_cmd_execute(fe, &cmd); | 1585 | ret = cx24117_cmd_execute(fe, &cmd); |
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 6dbbee453ee1..1632d78a5479 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
12 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
13 | #include <linux/mutex.h> | 13 | #include <linux/mutex.h> |
14 | #include <asm/div64.h> | ||
14 | 15 | ||
15 | #include "dvb_math.h" | 16 | #include "dvb_math.h" |
16 | 17 | ||
@@ -118,6 +119,12 @@ struct dib8000_state { | |||
118 | u8 longest_intlv_layer; | 119 | u8 longest_intlv_layer; |
119 | u16 output_mode; | 120 | u16 output_mode; |
120 | 121 | ||
122 | /* for DVBv5 stats */ | ||
123 | s64 init_ucb; | ||
124 | unsigned long per_jiffies_stats; | ||
125 | unsigned long ber_jiffies_stats; | ||
126 | unsigned long ber_jiffies_stats_layer[3]; | ||
127 | |||
121 | #ifdef DIB8000_AGC_FREEZE | 128 | #ifdef DIB8000_AGC_FREEZE |
122 | u16 agc1_max; | 129 | u16 agc1_max; |
123 | u16 agc1_min; | 130 | u16 agc1_min; |
@@ -157,15 +164,10 @@ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) | |||
157 | return ret; | 164 | return ret; |
158 | } | 165 | } |
159 | 166 | ||
160 | static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) | 167 | static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg) |
161 | { | 168 | { |
162 | u16 ret; | 169 | u16 ret; |
163 | 170 | ||
164 | if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { | ||
165 | dprintk("could not acquire lock"); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | state->i2c_write_buffer[0] = reg >> 8; | 171 | state->i2c_write_buffer[0] = reg >> 8; |
170 | state->i2c_write_buffer[1] = reg & 0xff; | 172 | state->i2c_write_buffer[1] = reg & 0xff; |
171 | 173 | ||
@@ -183,6 +185,21 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) | |||
183 | dprintk("i2c read error on %d", reg); | 185 | dprintk("i2c read error on %d", reg); |
184 | 186 | ||
185 | ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; | 187 | ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; |
188 | |||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) | ||
193 | { | ||
194 | u16 ret; | ||
195 | |||
196 | if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { | ||
197 | dprintk("could not acquire lock"); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | ret = __dib8000_read_word(state, reg); | ||
202 | |||
186 | mutex_unlock(&state->i2c_buffer_lock); | 203 | mutex_unlock(&state->i2c_buffer_lock); |
187 | 204 | ||
188 | return ret; | 205 | return ret; |
@@ -192,8 +209,15 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg) | |||
192 | { | 209 | { |
193 | u16 rw[2]; | 210 | u16 rw[2]; |
194 | 211 | ||
195 | rw[0] = dib8000_read_word(state, reg + 0); | 212 | if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { |
196 | rw[1] = dib8000_read_word(state, reg + 1); | 213 | dprintk("could not acquire lock"); |
214 | return 0; | ||
215 | } | ||
216 | |||
217 | rw[0] = __dib8000_read_word(state, reg + 0); | ||
218 | rw[1] = __dib8000_read_word(state, reg + 1); | ||
219 | |||
220 | mutex_unlock(&state->i2c_buffer_lock); | ||
197 | 221 | ||
198 | return ((rw[0] << 16) | (rw[1])); | 222 | return ((rw[0] << 16) | (rw[1])); |
199 | } | 223 | } |
@@ -787,7 +811,7 @@ int dib8000_update_pll(struct dvb_frontend *fe, | |||
787 | dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio); | 811 | dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio); |
788 | dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ | 812 | dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ |
789 | } | 813 | } |
790 | } | 814 | } |
791 | 815 | ||
792 | return 0; | 816 | return 0; |
793 | } | 817 | } |
@@ -966,6 +990,45 @@ static u16 dib8000_identify(struct i2c_device *client) | |||
966 | return value; | 990 | return value; |
967 | } | 991 | } |
968 | 992 | ||
993 | static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc); | ||
994 | |||
995 | static void dib8000_reset_stats(struct dvb_frontend *fe) | ||
996 | { | ||
997 | struct dib8000_state *state = fe->demodulator_priv; | ||
998 | struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; | ||
999 | u32 ucb; | ||
1000 | |||
1001 | memset(&c->strength, 0, sizeof(c->strength)); | ||
1002 | memset(&c->cnr, 0, sizeof(c->cnr)); | ||
1003 | memset(&c->post_bit_error, 0, sizeof(c->post_bit_error)); | ||
1004 | memset(&c->post_bit_count, 0, sizeof(c->post_bit_count)); | ||
1005 | memset(&c->block_error, 0, sizeof(c->block_error)); | ||
1006 | |||
1007 | c->strength.len = 1; | ||
1008 | c->cnr.len = 1; | ||
1009 | c->block_error.len = 1; | ||
1010 | c->block_count.len = 1; | ||
1011 | c->post_bit_error.len = 1; | ||
1012 | c->post_bit_count.len = 1; | ||
1013 | |||
1014 | c->strength.stat[0].scale = FE_SCALE_DECIBEL; | ||
1015 | c->strength.stat[0].uvalue = 0; | ||
1016 | |||
1017 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
1018 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
1019 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
1020 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
1021 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
1022 | |||
1023 | dib8000_read_unc_blocks(fe, &ucb); | ||
1024 | |||
1025 | state->init_ucb = -ucb; | ||
1026 | state->ber_jiffies_stats = 0; | ||
1027 | state->per_jiffies_stats = 0; | ||
1028 | memset(&state->ber_jiffies_stats_layer, 0, | ||
1029 | sizeof(state->ber_jiffies_stats_layer)); | ||
1030 | } | ||
1031 | |||
969 | static int dib8000_reset(struct dvb_frontend *fe) | 1032 | static int dib8000_reset(struct dvb_frontend *fe) |
970 | { | 1033 | { |
971 | struct dib8000_state *state = fe->demodulator_priv; | 1034 | struct dib8000_state *state = fe->demodulator_priv; |
@@ -1071,6 +1134,8 @@ static int dib8000_reset(struct dvb_frontend *fe) | |||
1071 | 1134 | ||
1072 | dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); | 1135 | dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); |
1073 | 1136 | ||
1137 | dib8000_reset_stats(fe); | ||
1138 | |||
1074 | return 0; | 1139 | return 0; |
1075 | } | 1140 | } |
1076 | 1141 | ||
@@ -2445,7 +2510,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) | |||
2445 | if (state->revision == 0x8090) | 2510 | if (state->revision == 0x8090) |
2446 | internal = dib8000_read32(state, 23) / 1000; | 2511 | internal = dib8000_read32(state, 23) / 1000; |
2447 | 2512 | ||
2448 | if (state->autosearch_state == AS_SEARCHING_FFT) { | 2513 | if ((state->revision >= 0x8002) && |
2514 | (state->autosearch_state == AS_SEARCHING_FFT)) { | ||
2449 | dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ | 2515 | dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ |
2450 | dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ | 2516 | dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ |
2451 | 2517 | ||
@@ -2481,7 +2547,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) | |||
2481 | dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ | 2547 | dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ |
2482 | dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ | 2548 | dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ |
2483 | dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ | 2549 | dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ |
2484 | } else if (state->autosearch_state == AS_SEARCHING_GUARD) { | 2550 | } else if ((state->revision >= 0x8002) && |
2551 | (state->autosearch_state == AS_SEARCHING_GUARD)) { | ||
2485 | c->transmission_mode = TRANSMISSION_MODE_8K; | 2552 | c->transmission_mode = TRANSMISSION_MODE_8K; |
2486 | c->guard_interval = GUARD_INTERVAL_1_8; | 2553 | c->guard_interval = GUARD_INTERVAL_1_8; |
2487 | c->inversion = 0; | 2554 | c->inversion = 0; |
@@ -2583,7 +2650,8 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe) | |||
2583 | struct dib8000_state *state = fe->demodulator_priv; | 2650 | struct dib8000_state *state = fe->demodulator_priv; |
2584 | u16 irq_pending = dib8000_read_word(state, 1284); | 2651 | u16 irq_pending = dib8000_read_word(state, 1284); |
2585 | 2652 | ||
2586 | if (state->autosearch_state == AS_SEARCHING_FFT) { | 2653 | if ((state->revision >= 0x8002) && |
2654 | (state->autosearch_state == AS_SEARCHING_FFT)) { | ||
2587 | if (irq_pending & 0x1) { | 2655 | if (irq_pending & 0x1) { |
2588 | dprintk("dib8000_autosearch_irq: max correlation result available"); | 2656 | dprintk("dib8000_autosearch_irq: max correlation result available"); |
2589 | return 3; | 2657 | return 3; |
@@ -2853,6 +2921,91 @@ static int dib8090p_init_sdram(struct dib8000_state *state) | |||
2853 | return 0; | 2921 | return 0; |
2854 | } | 2922 | } |
2855 | 2923 | ||
2924 | /** | ||
2925 | * is_manual_mode - Check if TMCC should be used for parameters settings | ||
2926 | * @c: struct dvb_frontend_properties | ||
2927 | * | ||
2928 | * By default, TMCC table should be used for parameter settings on most | ||
2929 | * usercases. However, sometimes it is desirable to lock the demod to | ||
2930 | * use the manual parameters. | ||
2931 | * | ||
2932 | * On manual mode, the current dib8000_tune state machine is very restrict: | ||
2933 | * It requires that both per-layer and per-transponder parameters to be | ||
2934 | * properly specified, otherwise the device won't lock. | ||
2935 | * | ||
2936 | * Check if all those conditions are properly satisfied before allowing | ||
2937 | * the device to use the manual frequency lock mode. | ||
2938 | */ | ||
2939 | static int is_manual_mode(struct dtv_frontend_properties *c) | ||
2940 | { | ||
2941 | int i, n_segs = 0; | ||
2942 | |||
2943 | /* Use auto mode on DVB-T compat mode */ | ||
2944 | if (c->delivery_system != SYS_ISDBT) | ||
2945 | return 0; | ||
2946 | |||
2947 | /* | ||
2948 | * Transmission mode is only detected on auto mode, currently | ||
2949 | */ | ||
2950 | if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { | ||
2951 | dprintk("transmission mode auto"); | ||
2952 | return 0; | ||
2953 | } | ||
2954 | |||
2955 | /* | ||
2956 | * Guard interval is only detected on auto mode, currently | ||
2957 | */ | ||
2958 | if (c->guard_interval == GUARD_INTERVAL_AUTO) { | ||
2959 | dprintk("guard interval auto"); | ||
2960 | return 0; | ||
2961 | } | ||
2962 | |||
2963 | /* | ||
2964 | * If no layer is enabled, assume auto mode, as at least one | ||
2965 | * layer should be enabled | ||
2966 | */ | ||
2967 | if (!c->isdbt_layer_enabled) { | ||
2968 | dprintk("no layer modulation specified"); | ||
2969 | return 0; | ||
2970 | } | ||
2971 | |||
2972 | /* | ||
2973 | * Check if the per-layer parameters aren't auto and | ||
2974 | * disable a layer if segment count is 0 or invalid. | ||
2975 | */ | ||
2976 | for (i = 0; i < 3; i++) { | ||
2977 | if (!(c->isdbt_layer_enabled & 1 << i)) | ||
2978 | continue; | ||
2979 | |||
2980 | if ((c->layer[i].segment_count > 13) || | ||
2981 | (c->layer[i].segment_count == 0)) { | ||
2982 | c->isdbt_layer_enabled &= ~(1 << i); | ||
2983 | continue; | ||
2984 | } | ||
2985 | |||
2986 | n_segs += c->layer[i].segment_count; | ||
2987 | |||
2988 | if ((c->layer[i].modulation == QAM_AUTO) || | ||
2989 | (c->layer[i].fec == FEC_AUTO)) { | ||
2990 | dprintk("layer %c has either modulation or FEC auto", | ||
2991 | 'A' + i); | ||
2992 | return 0; | ||
2993 | } | ||
2994 | } | ||
2995 | |||
2996 | /* | ||
2997 | * Userspace specified a wrong number of segments. | ||
2998 | * fallback to auto mode. | ||
2999 | */ | ||
3000 | if (n_segs == 0 || n_segs > 13) { | ||
3001 | dprintk("number of segments is invalid"); | ||
3002 | return 0; | ||
3003 | } | ||
3004 | |||
3005 | /* Everything looks ok for manual mode */ | ||
3006 | return 1; | ||
3007 | } | ||
3008 | |||
2856 | static int dib8000_tune(struct dvb_frontend *fe) | 3009 | static int dib8000_tune(struct dvb_frontend *fe) |
2857 | { | 3010 | { |
2858 | struct dib8000_state *state = fe->demodulator_priv; | 3011 | struct dib8000_state *state = fe->demodulator_priv; |
@@ -2878,40 +3031,19 @@ static int dib8000_tune(struct dvb_frontend *fe) | |||
2878 | 3031 | ||
2879 | switch (*tune_state) { | 3032 | switch (*tune_state) { |
2880 | case CT_DEMOD_START: /* 30 */ | 3033 | case CT_DEMOD_START: /* 30 */ |
3034 | dib8000_reset_stats(fe); | ||
3035 | |||
2881 | if (state->revision == 0x8090) | 3036 | if (state->revision == 0x8090) |
2882 | dib8090p_init_sdram(state); | 3037 | dib8090p_init_sdram(state); |
2883 | state->status = FE_STATUS_TUNE_PENDING; | 3038 | state->status = FE_STATUS_TUNE_PENDING; |
2884 | if ((c->delivery_system != SYS_ISDBT) || | 3039 | state->channel_parameters_set = is_manual_mode(c); |
2885 | (c->inversion == INVERSION_AUTO) || | 3040 | |
2886 | (c->transmission_mode == TRANSMISSION_MODE_AUTO) || | 3041 | dprintk("Tuning channel on %s search mode", |
2887 | (c->guard_interval == GUARD_INTERVAL_AUTO) || | 3042 | state->channel_parameters_set ? "manual" : "auto"); |
2888 | (((c->isdbt_layer_enabled & (1 << 0)) != 0) && | ||
2889 | (c->layer[0].segment_count != 0xff) && | ||
2890 | (c->layer[0].segment_count != 0) && | ||
2891 | ((c->layer[0].modulation == QAM_AUTO) || | ||
2892 | (c->layer[0].fec == FEC_AUTO))) || | ||
2893 | (((c->isdbt_layer_enabled & (1 << 1)) != 0) && | ||
2894 | (c->layer[1].segment_count != 0xff) && | ||
2895 | (c->layer[1].segment_count != 0) && | ||
2896 | ((c->layer[1].modulation == QAM_AUTO) || | ||
2897 | (c->layer[1].fec == FEC_AUTO))) || | ||
2898 | (((c->isdbt_layer_enabled & (1 << 2)) != 0) && | ||
2899 | (c->layer[2].segment_count != 0xff) && | ||
2900 | (c->layer[2].segment_count != 0) && | ||
2901 | ((c->layer[2].modulation == QAM_AUTO) || | ||
2902 | (c->layer[2].fec == FEC_AUTO))) || | ||
2903 | (((c->layer[0].segment_count == 0) || | ||
2904 | ((c->isdbt_layer_enabled & (1 << 0)) == 0)) && | ||
2905 | ((c->layer[1].segment_count == 0) || | ||
2906 | ((c->isdbt_layer_enabled & (2 << 0)) == 0)) && | ||
2907 | ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0)))) | ||
2908 | state->channel_parameters_set = 0; /* auto search */ | ||
2909 | else | ||
2910 | state->channel_parameters_set = 1; /* channel parameters are known */ | ||
2911 | 3043 | ||
2912 | dib8000_viterbi_state(state, 0); /* force chan dec in restart */ | 3044 | dib8000_viterbi_state(state, 0); /* force chan dec in restart */ |
2913 | 3045 | ||
2914 | /* Layer monit */ | 3046 | /* Layer monitor */ |
2915 | dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); | 3047 | dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); |
2916 | 3048 | ||
2917 | dib8000_set_frequency_offset(state); | 3049 | dib8000_set_frequency_offset(state); |
@@ -3256,15 +3388,27 @@ static int dib8000_sleep(struct dvb_frontend *fe) | |||
3256 | return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); | 3388 | return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); |
3257 | } | 3389 | } |
3258 | 3390 | ||
3391 | static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat); | ||
3392 | |||
3259 | static int dib8000_get_frontend(struct dvb_frontend *fe) | 3393 | static int dib8000_get_frontend(struct dvb_frontend *fe) |
3260 | { | 3394 | { |
3261 | struct dib8000_state *state = fe->demodulator_priv; | 3395 | struct dib8000_state *state = fe->demodulator_priv; |
3262 | u16 i, val = 0; | 3396 | u16 i, val = 0; |
3263 | fe_status_t stat; | 3397 | fe_status_t stat = 0; |
3264 | u8 index_frontend, sub_index_frontend; | 3398 | u8 index_frontend, sub_index_frontend; |
3265 | 3399 | ||
3266 | fe->dtv_property_cache.bandwidth_hz = 6000000; | 3400 | fe->dtv_property_cache.bandwidth_hz = 6000000; |
3267 | 3401 | ||
3402 | /* | ||
3403 | * If called to early, get_frontend makes dib8000_tune to either | ||
3404 | * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail. | ||
3405 | * So, let's just return if frontend 0 has not locked. | ||
3406 | */ | ||
3407 | dib8000_read_status(fe, &stat); | ||
3408 | if (!(stat & FE_HAS_SYNC)) | ||
3409 | return 0; | ||
3410 | |||
3411 | dprintk("TMCC lock"); | ||
3268 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { | 3412 | for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { |
3269 | state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); | 3413 | state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); |
3270 | if (stat&FE_HAS_SYNC) { | 3414 | if (stat&FE_HAS_SYNC) { |
@@ -3335,9 +3479,13 @@ static int dib8000_get_frontend(struct dvb_frontend *fe) | |||
3335 | fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; | 3479 | fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; |
3336 | dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); | 3480 | dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); |
3337 | 3481 | ||
3338 | val = dib8000_read_word(state, 499 + i); | 3482 | val = dib8000_read_word(state, 499 + i) & 0x3; |
3339 | fe->dtv_property_cache.layer[i].interleaving = val & 0x3; | 3483 | /* Interleaving can be 0, 1, 2 or 4 */ |
3340 | dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving); | 3484 | if (val == 3) |
3485 | val = 4; | ||
3486 | fe->dtv_property_cache.layer[i].interleaving = val; | ||
3487 | dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", | ||
3488 | i, fe->dtv_property_cache.layer[i].interleaving); | ||
3341 | 3489 | ||
3342 | val = dib8000_read_word(state, 481 + i); | 3490 | val = dib8000_read_word(state, 481 + i); |
3343 | switch (val & 0x7) { | 3491 | switch (val & 0x7) { |
@@ -3556,6 +3704,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe) | |||
3556 | return 0; | 3704 | return 0; |
3557 | } | 3705 | } |
3558 | 3706 | ||
3707 | static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat); | ||
3708 | |||
3559 | static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) | 3709 | static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) |
3560 | { | 3710 | { |
3561 | struct dib8000_state *state = fe->demodulator_priv; | 3711 | struct dib8000_state *state = fe->demodulator_priv; |
@@ -3593,6 +3743,7 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) | |||
3593 | if (lock & 0x01) | 3743 | if (lock & 0x01) |
3594 | *stat |= FE_HAS_VITERBI; | 3744 | *stat |= FE_HAS_VITERBI; |
3595 | } | 3745 | } |
3746 | dib8000_get_stats(fe, *stat); | ||
3596 | 3747 | ||
3597 | return 0; | 3748 | return 0; |
3598 | } | 3749 | } |
@@ -3699,6 +3850,357 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) | |||
3699 | return 0; | 3850 | return 0; |
3700 | } | 3851 | } |
3701 | 3852 | ||
3853 | struct per_layer_regs { | ||
3854 | u16 lock, ber, per; | ||
3855 | }; | ||
3856 | |||
3857 | static const struct per_layer_regs per_layer_regs[] = { | ||
3858 | { 554, 560, 562 }, | ||
3859 | { 555, 576, 578 }, | ||
3860 | { 556, 581, 583 }, | ||
3861 | }; | ||
3862 | |||
3863 | struct linear_segments { | ||
3864 | unsigned x; | ||
3865 | signed y; | ||
3866 | }; | ||
3867 | |||
3868 | /* | ||
3869 | * Table to estimate signal strength in dBm. | ||
3870 | * This table was empirically determinated by measuring the signal | ||
3871 | * strength generated by a DTA-2111 RF generator directly connected into | ||
3872 | * a dib8076 device (a PixelView PV-D231U stick), using a good quality | ||
3873 | * 3 meters RC6 cable and good RC6 connectors. | ||
3874 | * The real value can actually be different on other devices, depending | ||
3875 | * on several factors, like if LNA is enabled or not, if diversity is | ||
3876 | * enabled, type of connectors, etc. | ||
3877 | * Yet, it is better to use this measure in dB than a random non-linear | ||
3878 | * percentage value, especially for antenna adjustments. | ||
3879 | * On my tests, the precision of the measure using this table is about | ||
3880 | * 0.5 dB, with sounds reasonable enough. | ||
3881 | */ | ||
3882 | static struct linear_segments strength_to_db_table[] = { | ||
3883 | { 55953, 108500 }, /* -22.5 dBm */ | ||
3884 | { 55394, 108000 }, | ||
3885 | { 53834, 107000 }, | ||
3886 | { 52863, 106000 }, | ||
3887 | { 52239, 105000 }, | ||
3888 | { 52012, 104000 }, | ||
3889 | { 51803, 103000 }, | ||
3890 | { 51566, 102000 }, | ||
3891 | { 51356, 101000 }, | ||
3892 | { 51112, 100000 }, | ||
3893 | { 50869, 99000 }, | ||
3894 | { 50600, 98000 }, | ||
3895 | { 50363, 97000 }, | ||
3896 | { 50117, 96000 }, /* -35 dBm */ | ||
3897 | { 49889, 95000 }, | ||
3898 | { 49680, 94000 }, | ||
3899 | { 49493, 93000 }, | ||
3900 | { 49302, 92000 }, | ||
3901 | { 48929, 91000 }, | ||
3902 | { 48416, 90000 }, | ||
3903 | { 48035, 89000 }, | ||
3904 | { 47593, 88000 }, | ||
3905 | { 47282, 87000 }, | ||
3906 | { 46953, 86000 }, | ||
3907 | { 46698, 85000 }, | ||
3908 | { 45617, 84000 }, | ||
3909 | { 44773, 83000 }, | ||
3910 | { 43845, 82000 }, | ||
3911 | { 43020, 81000 }, | ||
3912 | { 42010, 80000 }, /* -51 dBm */ | ||
3913 | { 0, 0 }, | ||
3914 | }; | ||
3915 | |||
3916 | static u32 interpolate_value(u32 value, struct linear_segments *segments, | ||
3917 | unsigned len) | ||
3918 | { | ||
3919 | u64 tmp64; | ||
3920 | u32 dx; | ||
3921 | s32 dy; | ||
3922 | int i, ret; | ||
3923 | |||
3924 | if (value >= segments[0].x) | ||
3925 | return segments[0].y; | ||
3926 | if (value < segments[len-1].x) | ||
3927 | return segments[len-1].y; | ||
3928 | |||
3929 | for (i = 1; i < len - 1; i++) { | ||
3930 | /* If value is identical, no need to interpolate */ | ||
3931 | if (value == segments[i].x) | ||
3932 | return segments[i].y; | ||
3933 | if (value > segments[i].x) | ||
3934 | break; | ||
3935 | } | ||
3936 | |||
3937 | /* Linear interpolation between the two (x,y) points */ | ||
3938 | dy = segments[i - 1].y - segments[i].y; | ||
3939 | dx = segments[i - 1].x - segments[i].x; | ||
3940 | |||
3941 | tmp64 = value - segments[i].x; | ||
3942 | tmp64 *= dy; | ||
3943 | do_div(tmp64, dx); | ||
3944 | ret = segments[i].y + tmp64; | ||
3945 | |||
3946 | return ret; | ||
3947 | } | ||
3948 | |||
3949 | static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer) | ||
3950 | { | ||
3951 | struct dib8000_state *state = fe->demodulator_priv; | ||
3952 | struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; | ||
3953 | int ini_layer, end_layer, i; | ||
3954 | u64 time_us, tmp64; | ||
3955 | u32 tmp, denom; | ||
3956 | int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs; | ||
3957 | int interleaving = 0, fft_div; | ||
3958 | |||
3959 | if (layer >= 0) { | ||
3960 | ini_layer = layer; | ||
3961 | end_layer = layer + 1; | ||
3962 | } else { | ||
3963 | ini_layer = 0; | ||
3964 | end_layer = 3; | ||
3965 | } | ||
3966 | |||
3967 | switch (c->guard_interval) { | ||
3968 | case GUARD_INTERVAL_1_4: | ||
3969 | guard = 4; | ||
3970 | break; | ||
3971 | case GUARD_INTERVAL_1_8: | ||
3972 | guard = 8; | ||
3973 | break; | ||
3974 | case GUARD_INTERVAL_1_16: | ||
3975 | guard = 16; | ||
3976 | break; | ||
3977 | default: | ||
3978 | case GUARD_INTERVAL_1_32: | ||
3979 | guard = 32; | ||
3980 | break; | ||
3981 | } | ||
3982 | |||
3983 | switch (c->transmission_mode) { | ||
3984 | case TRANSMISSION_MODE_2K: | ||
3985 | fft_div = 4; | ||
3986 | break; | ||
3987 | case TRANSMISSION_MODE_4K: | ||
3988 | fft_div = 2; | ||
3989 | break; | ||
3990 | default: | ||
3991 | case TRANSMISSION_MODE_8K: | ||
3992 | fft_div = 1; | ||
3993 | break; | ||
3994 | } | ||
3995 | |||
3996 | denom = 0; | ||
3997 | for (i = ini_layer; i < end_layer; i++) { | ||
3998 | nsegs = c->layer[i].segment_count; | ||
3999 | if (nsegs == 0 || nsegs > 13) | ||
4000 | continue; | ||
4001 | |||
4002 | switch (c->layer[i].modulation) { | ||
4003 | case DQPSK: | ||
4004 | case QPSK: | ||
4005 | bits_per_symbol = 2; | ||
4006 | break; | ||
4007 | case QAM_16: | ||
4008 | bits_per_symbol = 4; | ||
4009 | break; | ||
4010 | default: | ||
4011 | case QAM_64: | ||
4012 | bits_per_symbol = 6; | ||
4013 | break; | ||
4014 | } | ||
4015 | |||
4016 | switch (c->layer[i].fec) { | ||
4017 | case FEC_1_2: | ||
4018 | rate_num = 1; | ||
4019 | rate_denum = 2; | ||
4020 | break; | ||
4021 | case FEC_2_3: | ||
4022 | rate_num = 2; | ||
4023 | rate_denum = 3; | ||
4024 | break; | ||
4025 | case FEC_3_4: | ||
4026 | rate_num = 3; | ||
4027 | rate_denum = 4; | ||
4028 | break; | ||
4029 | case FEC_5_6: | ||
4030 | rate_num = 5; | ||
4031 | rate_denum = 6; | ||
4032 | break; | ||
4033 | default: | ||
4034 | case FEC_7_8: | ||
4035 | rate_num = 7; | ||
4036 | rate_denum = 8; | ||
4037 | break; | ||
4038 | } | ||
4039 | |||
4040 | interleaving = c->layer[i].interleaving; | ||
4041 | |||
4042 | denom += bits_per_symbol * rate_num * fft_div * nsegs * 384; | ||
4043 | } | ||
4044 | |||
4045 | /* If all goes wrong, wait for 1s for the next stats */ | ||
4046 | if (!denom) | ||
4047 | return 0; | ||
4048 | |||
4049 | /* Estimate the period for the total bit rate */ | ||
4050 | time_us = rate_denum * (1008 * 1562500L); | ||
4051 | tmp64 = time_us; | ||
4052 | do_div(tmp64, guard); | ||
4053 | time_us = time_us + tmp64; | ||
4054 | time_us += denom / 2; | ||
4055 | do_div(time_us, denom); | ||
4056 | |||
4057 | tmp = 1008 * 96 * interleaving; | ||
4058 | time_us += tmp + tmp / guard; | ||
4059 | |||
4060 | return time_us; | ||
4061 | } | ||
4062 | |||
4063 | static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat) | ||
4064 | { | ||
4065 | struct dib8000_state *state = fe->demodulator_priv; | ||
4066 | struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; | ||
4067 | int i; | ||
4068 | int show_per_stats = 0; | ||
4069 | u32 time_us = 0, snr, val; | ||
4070 | u64 blocks; | ||
4071 | s32 db; | ||
4072 | u16 strength; | ||
4073 | |||
4074 | /* Get Signal strength */ | ||
4075 | dib8000_read_signal_strength(fe, &strength); | ||
4076 | val = strength; | ||
4077 | db = interpolate_value(val, | ||
4078 | strength_to_db_table, | ||
4079 | ARRAY_SIZE(strength_to_db_table)) - 131000; | ||
4080 | c->strength.stat[0].svalue = db; | ||
4081 | |||
4082 | /* UCB/BER/CNR measures require lock */ | ||
4083 | if (!(stat & FE_HAS_LOCK)) { | ||
4084 | c->cnr.len = 1; | ||
4085 | c->block_count.len = 1; | ||
4086 | c->block_error.len = 1; | ||
4087 | c->post_bit_error.len = 1; | ||
4088 | c->post_bit_count.len = 1; | ||
4089 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
4090 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
4091 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
4092 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
4093 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
4094 | return 0; | ||
4095 | } | ||
4096 | |||
4097 | /* Check if time for stats was elapsed */ | ||
4098 | if (time_after(jiffies, state->per_jiffies_stats)) { | ||
4099 | state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000); | ||
4100 | |||
4101 | /* Get SNR */ | ||
4102 | snr = dib8000_get_snr(fe); | ||
4103 | for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) { | ||
4104 | if (state->fe[i]) | ||
4105 | snr += dib8000_get_snr(state->fe[i]); | ||
4106 | } | ||
4107 | snr = snr >> 16; | ||
4108 | |||
4109 | if (snr) { | ||
4110 | snr = 10 * intlog10(snr); | ||
4111 | snr = (1000L * snr) >> 24; | ||
4112 | } else { | ||
4113 | snr = 0; | ||
4114 | } | ||
4115 | c->cnr.stat[0].svalue = snr; | ||
4116 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | ||
4117 | |||
4118 | /* Get UCB measures */ | ||
4119 | dib8000_read_unc_blocks(fe, &val); | ||
4120 | if (val < state->init_ucb) | ||
4121 | state->init_ucb += 0x100000000LL; | ||
4122 | |||
4123 | c->block_error.stat[0].scale = FE_SCALE_COUNTER; | ||
4124 | c->block_error.stat[0].uvalue = val + state->init_ucb; | ||
4125 | |||
4126 | /* Estimate the number of packets based on bitrate */ | ||
4127 | if (!time_us) | ||
4128 | time_us = dib8000_get_time_us(fe, -1); | ||
4129 | |||
4130 | if (time_us) { | ||
4131 | blocks = 1250000ULL * 1000000ULL; | ||
4132 | do_div(blocks, time_us * 8 * 204); | ||
4133 | c->block_count.stat[0].scale = FE_SCALE_COUNTER; | ||
4134 | c->block_count.stat[0].uvalue += blocks; | ||
4135 | } | ||
4136 | |||
4137 | show_per_stats = 1; | ||
4138 | } | ||
4139 | |||
4140 | /* Get post-BER measures */ | ||
4141 | if (time_after(jiffies, state->ber_jiffies_stats)) { | ||
4142 | time_us = dib8000_get_time_us(fe, -1); | ||
4143 | state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000); | ||
4144 | |||
4145 | dprintk("Next all layers stats available in %u us.", time_us); | ||
4146 | |||
4147 | dib8000_read_ber(fe, &val); | ||
4148 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | ||
4149 | c->post_bit_error.stat[0].uvalue += val; | ||
4150 | |||
4151 | c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; | ||
4152 | c->post_bit_count.stat[0].uvalue += 100000000; | ||
4153 | } | ||
4154 | |||
4155 | if (state->revision < 0x8002) | ||
4156 | return 0; | ||
4157 | |||
4158 | c->block_error.len = 4; | ||
4159 | c->post_bit_error.len = 4; | ||
4160 | c->post_bit_count.len = 4; | ||
4161 | |||
4162 | for (i = 0; i < 3; i++) { | ||
4163 | unsigned nsegs = c->layer[i].segment_count; | ||
4164 | |||
4165 | if (nsegs == 0 || nsegs > 13) | ||
4166 | continue; | ||
4167 | |||
4168 | time_us = 0; | ||
4169 | |||
4170 | if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) { | ||
4171 | time_us = dib8000_get_time_us(fe, i); | ||
4172 | |||
4173 | state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000); | ||
4174 | dprintk("Next layer %c stats will be available in %u us\n", | ||
4175 | 'A' + i, time_us); | ||
4176 | |||
4177 | val = dib8000_read_word(state, per_layer_regs[i].ber); | ||
4178 | c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER; | ||
4179 | c->post_bit_error.stat[1 + i].uvalue += val; | ||
4180 | |||
4181 | c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER; | ||
4182 | c->post_bit_count.stat[1 + i].uvalue += 100000000; | ||
4183 | } | ||
4184 | |||
4185 | if (show_per_stats) { | ||
4186 | val = dib8000_read_word(state, per_layer_regs[i].per); | ||
4187 | |||
4188 | c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER; | ||
4189 | c->block_error.stat[1 + i].uvalue += val; | ||
4190 | |||
4191 | if (!time_us) | ||
4192 | time_us = dib8000_get_time_us(fe, i); | ||
4193 | if (time_us) { | ||
4194 | blocks = 1250000ULL * 1000000ULL; | ||
4195 | do_div(blocks, time_us * 8 * 204); | ||
4196 | c->block_count.stat[0].scale = FE_SCALE_COUNTER; | ||
4197 | c->block_count.stat[0].uvalue += blocks; | ||
4198 | } | ||
4199 | } | ||
4200 | } | ||
4201 | return 0; | ||
4202 | } | ||
4203 | |||
3702 | int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) | 4204 | int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) |
3703 | { | 4205 | { |
3704 | struct dib8000_state *state = fe->demodulator_priv; | 4206 | struct dib8000_state *state = fe->demodulator_priv; |
diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h index f22eb9f13ad5..f6cb34660327 100644 --- a/drivers/media/dvb-frontends/drxk.h +++ b/drivers/media/dvb-frontends/drxk.h | |||
@@ -29,7 +29,6 @@ | |||
29 | * A value of 0 (default) or lower indicates that | 29 | * A value of 0 (default) or lower indicates that |
30 | * the correct number of parameters will be | 30 | * the correct number of parameters will be |
31 | * automatically detected. | 31 | * automatically detected. |
32 | * @load_firmware_sync: Force the firmware load to be synchronous. | ||
33 | * | 32 | * |
34 | * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is | 33 | * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is |
35 | * UIO-3. | 34 | * UIO-3. |
@@ -41,7 +40,6 @@ struct drxk_config { | |||
41 | bool parallel_ts; | 40 | bool parallel_ts; |
42 | bool dynamic_clk; | 41 | bool dynamic_clk; |
43 | bool enable_merr_cfg; | 42 | bool enable_merr_cfg; |
44 | bool load_firmware_sync; | ||
45 | 43 | ||
46 | bool antenna_dvbt; | 44 | bool antenna_dvbt; |
47 | u16 antenna_gpio; | 45 | u16 antenna_gpio; |
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index bf29a3f0e6f0..cce94a75b2e1 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c | |||
@@ -6830,25 +6830,13 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, | |||
6830 | 6830 | ||
6831 | /* Load firmware and initialize DRX-K */ | 6831 | /* Load firmware and initialize DRX-K */ |
6832 | if (state->microcode_name) { | 6832 | if (state->microcode_name) { |
6833 | if (config->load_firmware_sync) { | 6833 | const struct firmware *fw = NULL; |
6834 | const struct firmware *fw = NULL; | ||
6835 | 6834 | ||
6836 | status = request_firmware(&fw, state->microcode_name, | 6835 | status = request_firmware(&fw, state->microcode_name, |
6837 | state->i2c->dev.parent); | 6836 | state->i2c->dev.parent); |
6838 | if (status < 0) | 6837 | if (status < 0) |
6839 | fw = NULL; | 6838 | fw = NULL; |
6840 | load_firmware_cb(fw, state); | 6839 | load_firmware_cb(fw, state); |
6841 | } else { | ||
6842 | status = request_firmware_nowait(THIS_MODULE, 1, | ||
6843 | state->microcode_name, | ||
6844 | state->i2c->dev.parent, | ||
6845 | GFP_KERNEL, | ||
6846 | state, load_firmware_cb); | ||
6847 | if (status < 0) { | ||
6848 | pr_err("failed to request a firmware\n"); | ||
6849 | return NULL; | ||
6850 | } | ||
6851 | } | ||
6852 | } else if (init_drxk(state) < 0) | 6840 | } else if (init_drxk(state) < 0) |
6853 | goto error; | 6841 | goto error; |
6854 | 6842 | ||
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c new file mode 100644 index 000000000000..b8a7897e7bd8 --- /dev/null +++ b/drivers/media/dvb-frontends/m88ds3103.c | |||
@@ -0,0 +1,1311 @@ | |||
1 | /* | ||
2 | * Montage M88DS3103 demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include "m88ds3103_priv.h" | ||
18 | |||
19 | static struct dvb_frontend_ops m88ds3103_ops; | ||
20 | |||
21 | /* write multiple registers */ | ||
22 | static int m88ds3103_wr_regs(struct m88ds3103_priv *priv, | ||
23 | u8 reg, const u8 *val, int len) | ||
24 | { | ||
25 | #define MAX_WR_LEN 32 | ||
26 | #define MAX_WR_XFER_LEN (MAX_WR_LEN + 1) | ||
27 | int ret; | ||
28 | u8 buf[MAX_WR_XFER_LEN]; | ||
29 | struct i2c_msg msg[1] = { | ||
30 | { | ||
31 | .addr = priv->cfg->i2c_addr, | ||
32 | .flags = 0, | ||
33 | .len = 1 + len, | ||
34 | .buf = buf, | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | if (WARN_ON(len > MAX_WR_LEN)) | ||
39 | return -EINVAL; | ||
40 | |||
41 | buf[0] = reg; | ||
42 | memcpy(&buf[1], val, len); | ||
43 | |||
44 | mutex_lock(&priv->i2c_mutex); | ||
45 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
46 | mutex_unlock(&priv->i2c_mutex); | ||
47 | if (ret == 1) { | ||
48 | ret = 0; | ||
49 | } else { | ||
50 | dev_warn(&priv->i2c->dev, | ||
51 | "%s: i2c wr failed=%d reg=%02x len=%d\n", | ||
52 | KBUILD_MODNAME, ret, reg, len); | ||
53 | ret = -EREMOTEIO; | ||
54 | } | ||
55 | |||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | /* read multiple registers */ | ||
60 | static int m88ds3103_rd_regs(struct m88ds3103_priv *priv, | ||
61 | u8 reg, u8 *val, int len) | ||
62 | { | ||
63 | #define MAX_RD_LEN 3 | ||
64 | #define MAX_RD_XFER_LEN (MAX_RD_LEN) | ||
65 | int ret; | ||
66 | u8 buf[MAX_RD_XFER_LEN]; | ||
67 | struct i2c_msg msg[2] = { | ||
68 | { | ||
69 | .addr = priv->cfg->i2c_addr, | ||
70 | .flags = 0, | ||
71 | .len = 1, | ||
72 | .buf = ®, | ||
73 | }, { | ||
74 | .addr = priv->cfg->i2c_addr, | ||
75 | .flags = I2C_M_RD, | ||
76 | .len = len, | ||
77 | .buf = buf, | ||
78 | } | ||
79 | }; | ||
80 | |||
81 | if (WARN_ON(len > MAX_RD_LEN)) | ||
82 | return -EINVAL; | ||
83 | |||
84 | mutex_lock(&priv->i2c_mutex); | ||
85 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
86 | mutex_unlock(&priv->i2c_mutex); | ||
87 | if (ret == 2) { | ||
88 | memcpy(val, buf, len); | ||
89 | ret = 0; | ||
90 | } else { | ||
91 | dev_warn(&priv->i2c->dev, | ||
92 | "%s: i2c rd failed=%d reg=%02x len=%d\n", | ||
93 | KBUILD_MODNAME, ret, reg, len); | ||
94 | ret = -EREMOTEIO; | ||
95 | } | ||
96 | |||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | /* write single register */ | ||
101 | static int m88ds3103_wr_reg(struct m88ds3103_priv *priv, u8 reg, u8 val) | ||
102 | { | ||
103 | return m88ds3103_wr_regs(priv, reg, &val, 1); | ||
104 | } | ||
105 | |||
106 | /* read single register */ | ||
107 | static int m88ds3103_rd_reg(struct m88ds3103_priv *priv, u8 reg, u8 *val) | ||
108 | { | ||
109 | return m88ds3103_rd_regs(priv, reg, val, 1); | ||
110 | } | ||
111 | |||
112 | /* write single register with mask */ | ||
113 | static int m88ds3103_wr_reg_mask(struct m88ds3103_priv *priv, | ||
114 | u8 reg, u8 val, u8 mask) | ||
115 | { | ||
116 | int ret; | ||
117 | u8 u8tmp; | ||
118 | |||
119 | /* no need for read if whole reg is written */ | ||
120 | if (mask != 0xff) { | ||
121 | ret = m88ds3103_rd_regs(priv, reg, &u8tmp, 1); | ||
122 | if (ret) | ||
123 | return ret; | ||
124 | |||
125 | val &= mask; | ||
126 | u8tmp &= ~mask; | ||
127 | val |= u8tmp; | ||
128 | } | ||
129 | |||
130 | return m88ds3103_wr_regs(priv, reg, &val, 1); | ||
131 | } | ||
132 | |||
133 | /* read single register with mask */ | ||
134 | static int m88ds3103_rd_reg_mask(struct m88ds3103_priv *priv, | ||
135 | u8 reg, u8 *val, u8 mask) | ||
136 | { | ||
137 | int ret, i; | ||
138 | u8 u8tmp; | ||
139 | |||
140 | ret = m88ds3103_rd_regs(priv, reg, &u8tmp, 1); | ||
141 | if (ret) | ||
142 | return ret; | ||
143 | |||
144 | u8tmp &= mask; | ||
145 | |||
146 | /* find position of the first bit */ | ||
147 | for (i = 0; i < 8; i++) { | ||
148 | if ((mask >> i) & 0x01) | ||
149 | break; | ||
150 | } | ||
151 | *val = u8tmp >> i; | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* write reg val table using reg addr auto increment */ | ||
157 | static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv, | ||
158 | const struct m88ds3103_reg_val *tab, int tab_len) | ||
159 | { | ||
160 | int ret, i, j; | ||
161 | u8 buf[83]; | ||
162 | dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); | ||
163 | |||
164 | if (tab_len > 83) { | ||
165 | ret = -EINVAL; | ||
166 | goto err; | ||
167 | } | ||
168 | |||
169 | for (i = 0, j = 0; i < tab_len; i++, j++) { | ||
170 | buf[j] = tab[i].val; | ||
171 | |||
172 | if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1 || | ||
173 | !((j + 1) % (priv->cfg->i2c_wr_max - 1))) { | ||
174 | ret = m88ds3103_wr_regs(priv, tab[i].reg - j, buf, j + 1); | ||
175 | if (ret) | ||
176 | goto err; | ||
177 | |||
178 | j = -1; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | return 0; | ||
183 | err: | ||
184 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
189 | { | ||
190 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
191 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
192 | int ret; | ||
193 | u8 u8tmp; | ||
194 | |||
195 | *status = 0; | ||
196 | |||
197 | if (!priv->warm) { | ||
198 | ret = -EAGAIN; | ||
199 | goto err; | ||
200 | } | ||
201 | |||
202 | switch (c->delivery_system) { | ||
203 | case SYS_DVBS: | ||
204 | ret = m88ds3103_rd_reg_mask(priv, 0xd1, &u8tmp, 0x07); | ||
205 | if (ret) | ||
206 | goto err; | ||
207 | |||
208 | if (u8tmp == 0x07) | ||
209 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
210 | FE_HAS_VITERBI | FE_HAS_SYNC | | ||
211 | FE_HAS_LOCK; | ||
212 | break; | ||
213 | case SYS_DVBS2: | ||
214 | ret = m88ds3103_rd_reg_mask(priv, 0x0d, &u8tmp, 0x8f); | ||
215 | if (ret) | ||
216 | goto err; | ||
217 | |||
218 | if (u8tmp == 0x8f) | ||
219 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
220 | FE_HAS_VITERBI | FE_HAS_SYNC | | ||
221 | FE_HAS_LOCK; | ||
222 | break; | ||
223 | default: | ||
224 | dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", | ||
225 | __func__); | ||
226 | ret = -EINVAL; | ||
227 | goto err; | ||
228 | } | ||
229 | |||
230 | priv->fe_status = *status; | ||
231 | |||
232 | dev_dbg(&priv->i2c->dev, "%s: lock=%02x status=%02x\n", | ||
233 | __func__, u8tmp, *status); | ||
234 | |||
235 | return 0; | ||
236 | err: | ||
237 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | static int m88ds3103_set_frontend(struct dvb_frontend *fe) | ||
242 | { | ||
243 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
244 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
245 | int ret, len; | ||
246 | const struct m88ds3103_reg_val *init; | ||
247 | u8 u8tmp, u8tmp1, u8tmp2; | ||
248 | u8 buf[2]; | ||
249 | u16 u16tmp, divide_ratio; | ||
250 | u32 tuner_frequency, target_mclk, ts_clk; | ||
251 | s32 s32tmp; | ||
252 | dev_dbg(&priv->i2c->dev, | ||
253 | "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", | ||
254 | __func__, c->delivery_system, | ||
255 | c->modulation, c->frequency, c->symbol_rate, | ||
256 | c->inversion, c->pilot, c->rolloff); | ||
257 | |||
258 | if (!priv->warm) { | ||
259 | ret = -EAGAIN; | ||
260 | goto err; | ||
261 | } | ||
262 | |||
263 | /* program tuner */ | ||
264 | if (fe->ops.tuner_ops.set_params) { | ||
265 | ret = fe->ops.tuner_ops.set_params(fe); | ||
266 | if (ret) | ||
267 | goto err; | ||
268 | } | ||
269 | |||
270 | if (fe->ops.tuner_ops.get_frequency) { | ||
271 | ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency); | ||
272 | if (ret) | ||
273 | goto err; | ||
274 | } | ||
275 | |||
276 | /* reset */ | ||
277 | ret = m88ds3103_wr_reg(priv, 0x07, 0x80); | ||
278 | if (ret) | ||
279 | goto err; | ||
280 | |||
281 | ret = m88ds3103_wr_reg(priv, 0x07, 0x00); | ||
282 | if (ret) | ||
283 | goto err; | ||
284 | |||
285 | ret = m88ds3103_wr_reg(priv, 0xb2, 0x01); | ||
286 | if (ret) | ||
287 | goto err; | ||
288 | |||
289 | ret = m88ds3103_wr_reg(priv, 0x00, 0x01); | ||
290 | if (ret) | ||
291 | goto err; | ||
292 | |||
293 | switch (c->delivery_system) { | ||
294 | case SYS_DVBS: | ||
295 | len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals); | ||
296 | init = m88ds3103_dvbs_init_reg_vals; | ||
297 | target_mclk = 96000; | ||
298 | break; | ||
299 | case SYS_DVBS2: | ||
300 | len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals); | ||
301 | init = m88ds3103_dvbs2_init_reg_vals; | ||
302 | |||
303 | switch (priv->cfg->ts_mode) { | ||
304 | case M88DS3103_TS_SERIAL: | ||
305 | case M88DS3103_TS_SERIAL_D7: | ||
306 | if (c->symbol_rate < 18000000) | ||
307 | target_mclk = 96000; | ||
308 | else | ||
309 | target_mclk = 144000; | ||
310 | break; | ||
311 | case M88DS3103_TS_PARALLEL: | ||
312 | case M88DS3103_TS_PARALLEL_12: | ||
313 | case M88DS3103_TS_PARALLEL_16: | ||
314 | case M88DS3103_TS_PARALLEL_19_2: | ||
315 | case M88DS3103_TS_CI: | ||
316 | if (c->symbol_rate < 18000000) | ||
317 | target_mclk = 96000; | ||
318 | else if (c->symbol_rate < 28000000) | ||
319 | target_mclk = 144000; | ||
320 | else | ||
321 | target_mclk = 192000; | ||
322 | break; | ||
323 | default: | ||
324 | dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", | ||
325 | __func__); | ||
326 | ret = -EINVAL; | ||
327 | goto err; | ||
328 | } | ||
329 | break; | ||
330 | default: | ||
331 | dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", | ||
332 | __func__); | ||
333 | ret = -EINVAL; | ||
334 | goto err; | ||
335 | } | ||
336 | |||
337 | /* program init table */ | ||
338 | if (c->delivery_system != priv->delivery_system) { | ||
339 | ret = m88ds3103_wr_reg_val_tab(priv, init, len); | ||
340 | if (ret) | ||
341 | goto err; | ||
342 | } | ||
343 | |||
344 | u8tmp1 = 0; /* silence compiler warning */ | ||
345 | switch (priv->cfg->ts_mode) { | ||
346 | case M88DS3103_TS_SERIAL: | ||
347 | u8tmp1 = 0x00; | ||
348 | ts_clk = 0; | ||
349 | u8tmp = 0x46; | ||
350 | break; | ||
351 | case M88DS3103_TS_SERIAL_D7: | ||
352 | u8tmp1 = 0x20; | ||
353 | ts_clk = 0; | ||
354 | u8tmp = 0x46; | ||
355 | break; | ||
356 | case M88DS3103_TS_PARALLEL: | ||
357 | ts_clk = 24000; | ||
358 | u8tmp = 0x42; | ||
359 | break; | ||
360 | case M88DS3103_TS_PARALLEL_12: | ||
361 | ts_clk = 12000; | ||
362 | u8tmp = 0x42; | ||
363 | break; | ||
364 | case M88DS3103_TS_PARALLEL_16: | ||
365 | ts_clk = 16000; | ||
366 | u8tmp = 0x42; | ||
367 | break; | ||
368 | case M88DS3103_TS_PARALLEL_19_2: | ||
369 | ts_clk = 19200; | ||
370 | u8tmp = 0x42; | ||
371 | break; | ||
372 | case M88DS3103_TS_CI: | ||
373 | ts_clk = 6000; | ||
374 | u8tmp = 0x43; | ||
375 | break; | ||
376 | default: | ||
377 | dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__); | ||
378 | ret = -EINVAL; | ||
379 | goto err; | ||
380 | } | ||
381 | |||
382 | /* TS mode */ | ||
383 | ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp); | ||
384 | if (ret) | ||
385 | goto err; | ||
386 | |||
387 | switch (priv->cfg->ts_mode) { | ||
388 | case M88DS3103_TS_SERIAL: | ||
389 | case M88DS3103_TS_SERIAL_D7: | ||
390 | ret = m88ds3103_wr_reg_mask(priv, 0x29, u8tmp1, 0x20); | ||
391 | if (ret) | ||
392 | goto err; | ||
393 | } | ||
394 | |||
395 | if (ts_clk) { | ||
396 | divide_ratio = DIV_ROUND_UP(target_mclk, ts_clk); | ||
397 | u8tmp1 = divide_ratio / 2; | ||
398 | u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); | ||
399 | } else { | ||
400 | divide_ratio = 0; | ||
401 | u8tmp1 = 0; | ||
402 | u8tmp2 = 0; | ||
403 | } | ||
404 | |||
405 | dev_dbg(&priv->i2c->dev, | ||
406 | "%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n", | ||
407 | __func__, target_mclk, ts_clk, divide_ratio); | ||
408 | |||
409 | u8tmp1--; | ||
410 | u8tmp2--; | ||
411 | /* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */ | ||
412 | u8tmp1 &= 0x3f; | ||
413 | /* u8tmp2[5:0] => ea[5:0] */ | ||
414 | u8tmp2 &= 0x3f; | ||
415 | |||
416 | ret = m88ds3103_rd_reg(priv, 0xfe, &u8tmp); | ||
417 | if (ret) | ||
418 | goto err; | ||
419 | |||
420 | u8tmp = ((u8tmp & 0xf0) << 0) | u8tmp1 >> 2; | ||
421 | ret = m88ds3103_wr_reg(priv, 0xfe, u8tmp); | ||
422 | if (ret) | ||
423 | goto err; | ||
424 | |||
425 | u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0; | ||
426 | ret = m88ds3103_wr_reg(priv, 0xea, u8tmp); | ||
427 | if (ret) | ||
428 | goto err; | ||
429 | |||
430 | switch (target_mclk) { | ||
431 | case 72000: | ||
432 | u8tmp1 = 0x00; /* 0b00 */ | ||
433 | u8tmp2 = 0x03; /* 0b11 */ | ||
434 | break; | ||
435 | case 96000: | ||
436 | u8tmp1 = 0x02; /* 0b10 */ | ||
437 | u8tmp2 = 0x01; /* 0b01 */ | ||
438 | break; | ||
439 | case 115200: | ||
440 | u8tmp1 = 0x01; /* 0b01 */ | ||
441 | u8tmp2 = 0x01; /* 0b01 */ | ||
442 | break; | ||
443 | case 144000: | ||
444 | u8tmp1 = 0x00; /* 0b00 */ | ||
445 | u8tmp2 = 0x01; /* 0b01 */ | ||
446 | break; | ||
447 | case 192000: | ||
448 | u8tmp1 = 0x03; /* 0b11 */ | ||
449 | u8tmp2 = 0x00; /* 0b00 */ | ||
450 | break; | ||
451 | default: | ||
452 | dev_dbg(&priv->i2c->dev, "%s: invalid target_mclk\n", __func__); | ||
453 | ret = -EINVAL; | ||
454 | goto err; | ||
455 | } | ||
456 | |||
457 | ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0); | ||
458 | if (ret) | ||
459 | goto err; | ||
460 | |||
461 | ret = m88ds3103_wr_reg_mask(priv, 0x24, u8tmp2 << 6, 0xc0); | ||
462 | if (ret) | ||
463 | goto err; | ||
464 | |||
465 | if (c->symbol_rate <= 3000000) | ||
466 | u8tmp = 0x20; | ||
467 | else if (c->symbol_rate <= 10000000) | ||
468 | u8tmp = 0x10; | ||
469 | else | ||
470 | u8tmp = 0x06; | ||
471 | |||
472 | ret = m88ds3103_wr_reg(priv, 0xc3, 0x08); | ||
473 | if (ret) | ||
474 | goto err; | ||
475 | |||
476 | ret = m88ds3103_wr_reg(priv, 0xc8, u8tmp); | ||
477 | if (ret) | ||
478 | goto err; | ||
479 | |||
480 | ret = m88ds3103_wr_reg(priv, 0xc4, 0x08); | ||
481 | if (ret) | ||
482 | goto err; | ||
483 | |||
484 | ret = m88ds3103_wr_reg(priv, 0xc7, 0x00); | ||
485 | if (ret) | ||
486 | goto err; | ||
487 | |||
488 | u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, M88DS3103_MCLK_KHZ / 2); | ||
489 | buf[0] = (u16tmp >> 0) & 0xff; | ||
490 | buf[1] = (u16tmp >> 8) & 0xff; | ||
491 | ret = m88ds3103_wr_regs(priv, 0x61, buf, 2); | ||
492 | if (ret) | ||
493 | goto err; | ||
494 | |||
495 | ret = m88ds3103_wr_reg_mask(priv, 0x4d, priv->cfg->spec_inv << 1, 0x02); | ||
496 | if (ret) | ||
497 | goto err; | ||
498 | |||
499 | ret = m88ds3103_wr_reg_mask(priv, 0x30, priv->cfg->agc_inv << 4, 0x10); | ||
500 | if (ret) | ||
501 | goto err; | ||
502 | |||
503 | ret = m88ds3103_wr_reg(priv, 0x33, priv->cfg->agc); | ||
504 | if (ret) | ||
505 | goto err; | ||
506 | |||
507 | dev_dbg(&priv->i2c->dev, "%s: carrier offset=%d\n", __func__, | ||
508 | (tuner_frequency - c->frequency)); | ||
509 | |||
510 | s32tmp = 0x10000 * (tuner_frequency - c->frequency); | ||
511 | s32tmp = DIV_ROUND_CLOSEST(s32tmp, M88DS3103_MCLK_KHZ); | ||
512 | if (s32tmp < 0) | ||
513 | s32tmp += 0x10000; | ||
514 | |||
515 | buf[0] = (s32tmp >> 0) & 0xff; | ||
516 | buf[1] = (s32tmp >> 8) & 0xff; | ||
517 | ret = m88ds3103_wr_regs(priv, 0x5e, buf, 2); | ||
518 | if (ret) | ||
519 | goto err; | ||
520 | |||
521 | ret = m88ds3103_wr_reg(priv, 0x00, 0x00); | ||
522 | if (ret) | ||
523 | goto err; | ||
524 | |||
525 | ret = m88ds3103_wr_reg(priv, 0xb2, 0x00); | ||
526 | if (ret) | ||
527 | goto err; | ||
528 | |||
529 | priv->delivery_system = c->delivery_system; | ||
530 | |||
531 | return 0; | ||
532 | err: | ||
533 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | static int m88ds3103_init(struct dvb_frontend *fe) | ||
538 | { | ||
539 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
540 | int ret, len, remaining; | ||
541 | const struct firmware *fw = NULL; | ||
542 | u8 *fw_file = M88DS3103_FIRMWARE; | ||
543 | u8 u8tmp; | ||
544 | dev_dbg(&priv->i2c->dev, "%s:\n", __func__); | ||
545 | |||
546 | /* set cold state by default */ | ||
547 | priv->warm = false; | ||
548 | |||
549 | /* wake up device from sleep */ | ||
550 | ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x01, 0x01); | ||
551 | if (ret) | ||
552 | goto err; | ||
553 | |||
554 | ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x00, 0x01); | ||
555 | if (ret) | ||
556 | goto err; | ||
557 | |||
558 | ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x00, 0x10); | ||
559 | if (ret) | ||
560 | goto err; | ||
561 | |||
562 | /* reset */ | ||
563 | ret = m88ds3103_wr_reg(priv, 0x07, 0x60); | ||
564 | if (ret) | ||
565 | goto err; | ||
566 | |||
567 | ret = m88ds3103_wr_reg(priv, 0x07, 0x00); | ||
568 | if (ret) | ||
569 | goto err; | ||
570 | |||
571 | /* firmware status */ | ||
572 | ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp); | ||
573 | if (ret) | ||
574 | goto err; | ||
575 | |||
576 | dev_dbg(&priv->i2c->dev, "%s: firmware=%02x\n", __func__, u8tmp); | ||
577 | |||
578 | if (u8tmp) | ||
579 | goto skip_fw_download; | ||
580 | |||
581 | /* cold state - try to download firmware */ | ||
582 | dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state\n", | ||
583 | KBUILD_MODNAME, m88ds3103_ops.info.name); | ||
584 | |||
585 | /* request the firmware, this will block and timeout */ | ||
586 | ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); | ||
587 | if (ret) { | ||
588 | dev_err(&priv->i2c->dev, "%s: firmare file '%s' not found\n", | ||
589 | KBUILD_MODNAME, fw_file); | ||
590 | goto err; | ||
591 | } | ||
592 | |||
593 | dev_info(&priv->i2c->dev, "%s: downloading firmware from file '%s'\n", | ||
594 | KBUILD_MODNAME, fw_file); | ||
595 | |||
596 | ret = m88ds3103_wr_reg(priv, 0xb2, 0x01); | ||
597 | if (ret) | ||
598 | goto err; | ||
599 | |||
600 | for (remaining = fw->size; remaining > 0; | ||
601 | remaining -= (priv->cfg->i2c_wr_max - 1)) { | ||
602 | len = remaining; | ||
603 | if (len > (priv->cfg->i2c_wr_max - 1)) | ||
604 | len = (priv->cfg->i2c_wr_max - 1); | ||
605 | |||
606 | ret = m88ds3103_wr_regs(priv, 0xb0, | ||
607 | &fw->data[fw->size - remaining], len); | ||
608 | if (ret) { | ||
609 | dev_err(&priv->i2c->dev, | ||
610 | "%s: firmware download failed=%d\n", | ||
611 | KBUILD_MODNAME, ret); | ||
612 | goto err; | ||
613 | } | ||
614 | } | ||
615 | |||
616 | ret = m88ds3103_wr_reg(priv, 0xb2, 0x00); | ||
617 | if (ret) | ||
618 | goto err; | ||
619 | |||
620 | release_firmware(fw); | ||
621 | fw = NULL; | ||
622 | |||
623 | ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp); | ||
624 | if (ret) | ||
625 | goto err; | ||
626 | |||
627 | if (!u8tmp) { | ||
628 | dev_info(&priv->i2c->dev, "%s: firmware did not run\n", | ||
629 | KBUILD_MODNAME); | ||
630 | ret = -EFAULT; | ||
631 | goto err; | ||
632 | } | ||
633 | |||
634 | dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n", | ||
635 | KBUILD_MODNAME, m88ds3103_ops.info.name); | ||
636 | dev_info(&priv->i2c->dev, "%s: firmware version %X.%X\n", | ||
637 | KBUILD_MODNAME, (u8tmp >> 4) & 0xf, (u8tmp >> 0 & 0xf)); | ||
638 | |||
639 | skip_fw_download: | ||
640 | /* warm state */ | ||
641 | priv->warm = true; | ||
642 | |||
643 | return 0; | ||
644 | err: | ||
645 | if (fw) | ||
646 | release_firmware(fw); | ||
647 | |||
648 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
649 | return ret; | ||
650 | } | ||
651 | |||
652 | static int m88ds3103_sleep(struct dvb_frontend *fe) | ||
653 | { | ||
654 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
655 | int ret; | ||
656 | dev_dbg(&priv->i2c->dev, "%s:\n", __func__); | ||
657 | |||
658 | priv->delivery_system = SYS_UNDEFINED; | ||
659 | |||
660 | /* TS Hi-Z */ | ||
661 | ret = m88ds3103_wr_reg_mask(priv, 0x27, 0x00, 0x01); | ||
662 | if (ret) | ||
663 | goto err; | ||
664 | |||
665 | /* sleep */ | ||
666 | ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x00, 0x01); | ||
667 | if (ret) | ||
668 | goto err; | ||
669 | |||
670 | ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x01, 0x01); | ||
671 | if (ret) | ||
672 | goto err; | ||
673 | |||
674 | ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x10, 0x10); | ||
675 | if (ret) | ||
676 | goto err; | ||
677 | |||
678 | return 0; | ||
679 | err: | ||
680 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | static int m88ds3103_get_frontend(struct dvb_frontend *fe) | ||
685 | { | ||
686 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
687 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
688 | int ret; | ||
689 | u8 buf[3]; | ||
690 | dev_dbg(&priv->i2c->dev, "%s:\n", __func__); | ||
691 | |||
692 | if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { | ||
693 | ret = -EAGAIN; | ||
694 | goto err; | ||
695 | } | ||
696 | |||
697 | switch (c->delivery_system) { | ||
698 | case SYS_DVBS: | ||
699 | ret = m88ds3103_rd_reg(priv, 0xe0, &buf[0]); | ||
700 | if (ret) | ||
701 | goto err; | ||
702 | |||
703 | ret = m88ds3103_rd_reg(priv, 0xe6, &buf[1]); | ||
704 | if (ret) | ||
705 | goto err; | ||
706 | |||
707 | switch ((buf[0] >> 2) & 0x01) { | ||
708 | case 0: | ||
709 | c->inversion = INVERSION_OFF; | ||
710 | break; | ||
711 | case 1: | ||
712 | c->inversion = INVERSION_ON; | ||
713 | break; | ||
714 | default: | ||
715 | dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", | ||
716 | __func__); | ||
717 | } | ||
718 | |||
719 | switch ((buf[1] >> 5) & 0x07) { | ||
720 | case 0: | ||
721 | c->fec_inner = FEC_7_8; | ||
722 | break; | ||
723 | case 1: | ||
724 | c->fec_inner = FEC_5_6; | ||
725 | break; | ||
726 | case 2: | ||
727 | c->fec_inner = FEC_3_4; | ||
728 | break; | ||
729 | case 3: | ||
730 | c->fec_inner = FEC_2_3; | ||
731 | break; | ||
732 | case 4: | ||
733 | c->fec_inner = FEC_1_2; | ||
734 | break; | ||
735 | default: | ||
736 | dev_dbg(&priv->i2c->dev, "%s: invalid fec_inner\n", | ||
737 | __func__); | ||
738 | } | ||
739 | |||
740 | c->modulation = QPSK; | ||
741 | |||
742 | break; | ||
743 | case SYS_DVBS2: | ||
744 | ret = m88ds3103_rd_reg(priv, 0x7e, &buf[0]); | ||
745 | if (ret) | ||
746 | goto err; | ||
747 | |||
748 | ret = m88ds3103_rd_reg(priv, 0x89, &buf[1]); | ||
749 | if (ret) | ||
750 | goto err; | ||
751 | |||
752 | ret = m88ds3103_rd_reg(priv, 0xf2, &buf[2]); | ||
753 | if (ret) | ||
754 | goto err; | ||
755 | |||
756 | switch ((buf[0] >> 0) & 0x0f) { | ||
757 | case 2: | ||
758 | c->fec_inner = FEC_2_5; | ||
759 | break; | ||
760 | case 3: | ||
761 | c->fec_inner = FEC_1_2; | ||
762 | break; | ||
763 | case 4: | ||
764 | c->fec_inner = FEC_3_5; | ||
765 | break; | ||
766 | case 5: | ||
767 | c->fec_inner = FEC_2_3; | ||
768 | break; | ||
769 | case 6: | ||
770 | c->fec_inner = FEC_3_4; | ||
771 | break; | ||
772 | case 7: | ||
773 | c->fec_inner = FEC_4_5; | ||
774 | break; | ||
775 | case 8: | ||
776 | c->fec_inner = FEC_5_6; | ||
777 | break; | ||
778 | case 9: | ||
779 | c->fec_inner = FEC_8_9; | ||
780 | break; | ||
781 | case 10: | ||
782 | c->fec_inner = FEC_9_10; | ||
783 | break; | ||
784 | default: | ||
785 | dev_dbg(&priv->i2c->dev, "%s: invalid fec_inner\n", | ||
786 | __func__); | ||
787 | } | ||
788 | |||
789 | switch ((buf[0] >> 5) & 0x01) { | ||
790 | case 0: | ||
791 | c->pilot = PILOT_OFF; | ||
792 | break; | ||
793 | case 1: | ||
794 | c->pilot = PILOT_ON; | ||
795 | break; | ||
796 | default: | ||
797 | dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n", | ||
798 | __func__); | ||
799 | } | ||
800 | |||
801 | switch ((buf[0] >> 6) & 0x07) { | ||
802 | case 0: | ||
803 | c->modulation = QPSK; | ||
804 | break; | ||
805 | case 1: | ||
806 | c->modulation = PSK_8; | ||
807 | break; | ||
808 | case 2: | ||
809 | c->modulation = APSK_16; | ||
810 | break; | ||
811 | case 3: | ||
812 | c->modulation = APSK_32; | ||
813 | break; | ||
814 | default: | ||
815 | dev_dbg(&priv->i2c->dev, "%s: invalid modulation\n", | ||
816 | __func__); | ||
817 | } | ||
818 | |||
819 | switch ((buf[1] >> 7) & 0x01) { | ||
820 | case 0: | ||
821 | c->inversion = INVERSION_OFF; | ||
822 | break; | ||
823 | case 1: | ||
824 | c->inversion = INVERSION_ON; | ||
825 | break; | ||
826 | default: | ||
827 | dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", | ||
828 | __func__); | ||
829 | } | ||
830 | |||
831 | switch ((buf[2] >> 0) & 0x03) { | ||
832 | case 0: | ||
833 | c->rolloff = ROLLOFF_35; | ||
834 | break; | ||
835 | case 1: | ||
836 | c->rolloff = ROLLOFF_25; | ||
837 | break; | ||
838 | case 2: | ||
839 | c->rolloff = ROLLOFF_20; | ||
840 | break; | ||
841 | default: | ||
842 | dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n", | ||
843 | __func__); | ||
844 | } | ||
845 | break; | ||
846 | default: | ||
847 | dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", | ||
848 | __func__); | ||
849 | ret = -EINVAL; | ||
850 | goto err; | ||
851 | } | ||
852 | |||
853 | ret = m88ds3103_rd_regs(priv, 0x6d, buf, 2); | ||
854 | if (ret) | ||
855 | goto err; | ||
856 | |||
857 | c->symbol_rate = 1ull * ((buf[1] << 8) | (buf[0] << 0)) * | ||
858 | M88DS3103_MCLK_KHZ * 1000 / 0x10000; | ||
859 | |||
860 | return 0; | ||
861 | err: | ||
862 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
863 | return ret; | ||
864 | } | ||
865 | |||
866 | static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
867 | { | ||
868 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
869 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
870 | int ret, i, tmp; | ||
871 | u8 buf[3]; | ||
872 | u16 noise, signal; | ||
873 | u32 noise_tot, signal_tot; | ||
874 | dev_dbg(&priv->i2c->dev, "%s:\n", __func__); | ||
875 | /* reports SNR in resolution of 0.1 dB */ | ||
876 | |||
877 | /* more iterations for more accurate estimation */ | ||
878 | #define M88DS3103_SNR_ITERATIONS 3 | ||
879 | |||
880 | switch (c->delivery_system) { | ||
881 | case SYS_DVBS: | ||
882 | tmp = 0; | ||
883 | |||
884 | for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { | ||
885 | ret = m88ds3103_rd_reg(priv, 0xff, &buf[0]); | ||
886 | if (ret) | ||
887 | goto err; | ||
888 | |||
889 | tmp += buf[0]; | ||
890 | } | ||
891 | |||
892 | /* use of one register limits max value to 15 dB */ | ||
893 | /* SNR(X) dB = 10 * ln(X) / ln(10) dB */ | ||
894 | tmp = DIV_ROUND_CLOSEST(tmp, 8 * M88DS3103_SNR_ITERATIONS); | ||
895 | if (tmp) | ||
896 | *snr = 100ul * intlog2(tmp) / intlog2(10); | ||
897 | else | ||
898 | *snr = 0; | ||
899 | break; | ||
900 | case SYS_DVBS2: | ||
901 | noise_tot = 0; | ||
902 | signal_tot = 0; | ||
903 | |||
904 | for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { | ||
905 | ret = m88ds3103_rd_regs(priv, 0x8c, buf, 3); | ||
906 | if (ret) | ||
907 | goto err; | ||
908 | |||
909 | noise = buf[1] << 6; /* [13:6] */ | ||
910 | noise |= buf[0] & 0x3f; /* [5:0] */ | ||
911 | noise >>= 2; | ||
912 | signal = buf[2] * buf[2]; | ||
913 | signal >>= 1; | ||
914 | |||
915 | noise_tot += noise; | ||
916 | signal_tot += signal; | ||
917 | } | ||
918 | |||
919 | noise = noise_tot / M88DS3103_SNR_ITERATIONS; | ||
920 | signal = signal_tot / M88DS3103_SNR_ITERATIONS; | ||
921 | |||
922 | /* SNR(X) dB = 10 * log10(X) dB */ | ||
923 | if (signal > noise) { | ||
924 | tmp = signal / noise; | ||
925 | *snr = 100ul * intlog10(tmp) / (1 << 24); | ||
926 | } else { | ||
927 | *snr = 0; | ||
928 | } | ||
929 | break; | ||
930 | default: | ||
931 | dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", | ||
932 | __func__); | ||
933 | ret = -EINVAL; | ||
934 | goto err; | ||
935 | } | ||
936 | |||
937 | return 0; | ||
938 | err: | ||
939 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
940 | return ret; | ||
941 | } | ||
942 | |||
943 | |||
944 | static int m88ds3103_set_tone(struct dvb_frontend *fe, | ||
945 | fe_sec_tone_mode_t fe_sec_tone_mode) | ||
946 | { | ||
947 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
948 | int ret; | ||
949 | u8 u8tmp, tone, reg_a1_mask; | ||
950 | dev_dbg(&priv->i2c->dev, "%s: fe_sec_tone_mode=%d\n", __func__, | ||
951 | fe_sec_tone_mode); | ||
952 | |||
953 | if (!priv->warm) { | ||
954 | ret = -EAGAIN; | ||
955 | goto err; | ||
956 | } | ||
957 | |||
958 | switch (fe_sec_tone_mode) { | ||
959 | case SEC_TONE_ON: | ||
960 | tone = 0; | ||
961 | reg_a1_mask = 0x87; | ||
962 | break; | ||
963 | case SEC_TONE_OFF: | ||
964 | tone = 1; | ||
965 | reg_a1_mask = 0x00; | ||
966 | break; | ||
967 | default: | ||
968 | dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n", | ||
969 | __func__); | ||
970 | ret = -EINVAL; | ||
971 | goto err; | ||
972 | } | ||
973 | |||
974 | u8tmp = tone << 7 | priv->cfg->envelope_mode << 5; | ||
975 | ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0); | ||
976 | if (ret) | ||
977 | goto err; | ||
978 | |||
979 | u8tmp = 1 << 2; | ||
980 | ret = m88ds3103_wr_reg_mask(priv, 0xa1, u8tmp, reg_a1_mask); | ||
981 | if (ret) | ||
982 | goto err; | ||
983 | |||
984 | return 0; | ||
985 | err: | ||
986 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
987 | return ret; | ||
988 | } | ||
989 | |||
990 | static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, | ||
991 | struct dvb_diseqc_master_cmd *diseqc_cmd) | ||
992 | { | ||
993 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
994 | int ret, i; | ||
995 | u8 u8tmp; | ||
996 | dev_dbg(&priv->i2c->dev, "%s: msg=%*ph\n", __func__, | ||
997 | diseqc_cmd->msg_len, diseqc_cmd->msg); | ||
998 | |||
999 | if (!priv->warm) { | ||
1000 | ret = -EAGAIN; | ||
1001 | goto err; | ||
1002 | } | ||
1003 | |||
1004 | if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) { | ||
1005 | ret = -EINVAL; | ||
1006 | goto err; | ||
1007 | } | ||
1008 | |||
1009 | u8tmp = priv->cfg->envelope_mode << 5; | ||
1010 | ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0); | ||
1011 | if (ret) | ||
1012 | goto err; | ||
1013 | |||
1014 | ret = m88ds3103_wr_regs(priv, 0xa3, diseqc_cmd->msg, | ||
1015 | diseqc_cmd->msg_len); | ||
1016 | if (ret) | ||
1017 | goto err; | ||
1018 | |||
1019 | ret = m88ds3103_wr_reg(priv, 0xa1, | ||
1020 | (diseqc_cmd->msg_len - 1) << 3 | 0x07); | ||
1021 | if (ret) | ||
1022 | goto err; | ||
1023 | |||
1024 | /* DiSEqC message typical period is 54 ms */ | ||
1025 | usleep_range(40000, 60000); | ||
1026 | |||
1027 | /* wait DiSEqC TX ready */ | ||
1028 | for (i = 20, u8tmp = 1; i && u8tmp; i--) { | ||
1029 | usleep_range(5000, 10000); | ||
1030 | |||
1031 | ret = m88ds3103_rd_reg_mask(priv, 0xa1, &u8tmp, 0x40); | ||
1032 | if (ret) | ||
1033 | goto err; | ||
1034 | } | ||
1035 | |||
1036 | dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); | ||
1037 | |||
1038 | if (i == 0) { | ||
1039 | dev_dbg(&priv->i2c->dev, "%s: diseqc tx timeout\n", __func__); | ||
1040 | |||
1041 | ret = m88ds3103_wr_reg_mask(priv, 0xa1, 0x40, 0xc0); | ||
1042 | if (ret) | ||
1043 | goto err; | ||
1044 | } | ||
1045 | |||
1046 | ret = m88ds3103_wr_reg_mask(priv, 0xa2, 0x80, 0xc0); | ||
1047 | if (ret) | ||
1048 | goto err; | ||
1049 | |||
1050 | if (i == 0) { | ||
1051 | ret = -ETIMEDOUT; | ||
1052 | goto err; | ||
1053 | } | ||
1054 | |||
1055 | return 0; | ||
1056 | err: | ||
1057 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
1058 | return ret; | ||
1059 | } | ||
1060 | |||
1061 | static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, | ||
1062 | fe_sec_mini_cmd_t fe_sec_mini_cmd) | ||
1063 | { | ||
1064 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
1065 | int ret, i; | ||
1066 | u8 u8tmp, burst; | ||
1067 | dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__, | ||
1068 | fe_sec_mini_cmd); | ||
1069 | |||
1070 | if (!priv->warm) { | ||
1071 | ret = -EAGAIN; | ||
1072 | goto err; | ||
1073 | } | ||
1074 | |||
1075 | u8tmp = priv->cfg->envelope_mode << 5; | ||
1076 | ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0); | ||
1077 | if (ret) | ||
1078 | goto err; | ||
1079 | |||
1080 | switch (fe_sec_mini_cmd) { | ||
1081 | case SEC_MINI_A: | ||
1082 | burst = 0x02; | ||
1083 | break; | ||
1084 | case SEC_MINI_B: | ||
1085 | burst = 0x01; | ||
1086 | break; | ||
1087 | default: | ||
1088 | dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n", | ||
1089 | __func__); | ||
1090 | ret = -EINVAL; | ||
1091 | goto err; | ||
1092 | } | ||
1093 | |||
1094 | ret = m88ds3103_wr_reg(priv, 0xa1, burst); | ||
1095 | if (ret) | ||
1096 | goto err; | ||
1097 | |||
1098 | /* DiSEqC ToneBurst period is 12.5 ms */ | ||
1099 | usleep_range(11000, 20000); | ||
1100 | |||
1101 | /* wait DiSEqC TX ready */ | ||
1102 | for (i = 5, u8tmp = 1; i && u8tmp; i--) { | ||
1103 | usleep_range(800, 2000); | ||
1104 | |||
1105 | ret = m88ds3103_rd_reg_mask(priv, 0xa1, &u8tmp, 0x40); | ||
1106 | if (ret) | ||
1107 | goto err; | ||
1108 | } | ||
1109 | |||
1110 | dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); | ||
1111 | |||
1112 | ret = m88ds3103_wr_reg_mask(priv, 0xa2, 0x80, 0xc0); | ||
1113 | if (ret) | ||
1114 | goto err; | ||
1115 | |||
1116 | if (i == 0) { | ||
1117 | dev_dbg(&priv->i2c->dev, "%s: diseqc tx timeout\n", __func__); | ||
1118 | ret = -ETIMEDOUT; | ||
1119 | goto err; | ||
1120 | } | ||
1121 | |||
1122 | return 0; | ||
1123 | err: | ||
1124 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
1125 | return ret; | ||
1126 | } | ||
1127 | |||
1128 | static int m88ds3103_get_tune_settings(struct dvb_frontend *fe, | ||
1129 | struct dvb_frontend_tune_settings *s) | ||
1130 | { | ||
1131 | s->min_delay_ms = 3000; | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static void m88ds3103_release(struct dvb_frontend *fe) | ||
1137 | { | ||
1138 | struct m88ds3103_priv *priv = fe->demodulator_priv; | ||
1139 | i2c_del_mux_adapter(priv->i2c_adapter); | ||
1140 | kfree(priv); | ||
1141 | } | ||
1142 | |||
1143 | static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) | ||
1144 | { | ||
1145 | struct m88ds3103_priv *priv = mux_priv; | ||
1146 | int ret; | ||
1147 | struct i2c_msg gate_open_msg[1] = { | ||
1148 | { | ||
1149 | .addr = priv->cfg->i2c_addr, | ||
1150 | .flags = 0, | ||
1151 | .len = 2, | ||
1152 | .buf = "\x03\x11", | ||
1153 | } | ||
1154 | }; | ||
1155 | |||
1156 | mutex_lock(&priv->i2c_mutex); | ||
1157 | |||
1158 | /* open tuner I2C repeater for 1 xfer, closes automatically */ | ||
1159 | ret = __i2c_transfer(priv->i2c, gate_open_msg, 1); | ||
1160 | if (ret != 1) { | ||
1161 | dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d\n", | ||
1162 | KBUILD_MODNAME, ret); | ||
1163 | if (ret >= 0) | ||
1164 | ret = -EREMOTEIO; | ||
1165 | |||
1166 | return ret; | ||
1167 | } | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | static int m88ds3103_deselect(struct i2c_adapter *adap, void *mux_priv, | ||
1173 | u32 chan) | ||
1174 | { | ||
1175 | struct m88ds3103_priv *priv = mux_priv; | ||
1176 | |||
1177 | mutex_unlock(&priv->i2c_mutex); | ||
1178 | |||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1182 | struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, | ||
1183 | struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter) | ||
1184 | { | ||
1185 | int ret; | ||
1186 | struct m88ds3103_priv *priv; | ||
1187 | u8 chip_id, u8tmp; | ||
1188 | |||
1189 | /* allocate memory for the internal priv */ | ||
1190 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
1191 | if (!priv) { | ||
1192 | ret = -ENOMEM; | ||
1193 | dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); | ||
1194 | goto err; | ||
1195 | } | ||
1196 | |||
1197 | priv->cfg = cfg; | ||
1198 | priv->i2c = i2c; | ||
1199 | mutex_init(&priv->i2c_mutex); | ||
1200 | |||
1201 | ret = m88ds3103_rd_reg(priv, 0x01, &chip_id); | ||
1202 | if (ret) | ||
1203 | goto err; | ||
1204 | |||
1205 | dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); | ||
1206 | |||
1207 | switch (chip_id) { | ||
1208 | case 0xd0: | ||
1209 | break; | ||
1210 | default: | ||
1211 | goto err; | ||
1212 | } | ||
1213 | |||
1214 | switch (priv->cfg->clock_out) { | ||
1215 | case M88DS3103_CLOCK_OUT_DISABLED: | ||
1216 | u8tmp = 0x80; | ||
1217 | break; | ||
1218 | case M88DS3103_CLOCK_OUT_ENABLED: | ||
1219 | u8tmp = 0x00; | ||
1220 | break; | ||
1221 | case M88DS3103_CLOCK_OUT_ENABLED_DIV2: | ||
1222 | u8tmp = 0x10; | ||
1223 | break; | ||
1224 | default: | ||
1225 | goto err; | ||
1226 | } | ||
1227 | |||
1228 | ret = m88ds3103_wr_reg(priv, 0x29, u8tmp); | ||
1229 | if (ret) | ||
1230 | goto err; | ||
1231 | |||
1232 | /* sleep */ | ||
1233 | ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x00, 0x01); | ||
1234 | if (ret) | ||
1235 | goto err; | ||
1236 | |||
1237 | ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x01, 0x01); | ||
1238 | if (ret) | ||
1239 | goto err; | ||
1240 | |||
1241 | ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x10, 0x10); | ||
1242 | if (ret) | ||
1243 | goto err; | ||
1244 | |||
1245 | /* create mux i2c adapter for tuner */ | ||
1246 | priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, | ||
1247 | m88ds3103_select, m88ds3103_deselect); | ||
1248 | if (priv->i2c_adapter == NULL) | ||
1249 | goto err; | ||
1250 | |||
1251 | *tuner_i2c_adapter = priv->i2c_adapter; | ||
1252 | |||
1253 | /* create dvb_frontend */ | ||
1254 | memcpy(&priv->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); | ||
1255 | priv->fe.demodulator_priv = priv; | ||
1256 | |||
1257 | return &priv->fe; | ||
1258 | err: | ||
1259 | dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
1260 | kfree(priv); | ||
1261 | return NULL; | ||
1262 | } | ||
1263 | EXPORT_SYMBOL(m88ds3103_attach); | ||
1264 | |||
1265 | static struct dvb_frontend_ops m88ds3103_ops = { | ||
1266 | .delsys = { SYS_DVBS, SYS_DVBS2 }, | ||
1267 | .info = { | ||
1268 | .name = "Montage M88DS3103", | ||
1269 | .frequency_min = 950000, | ||
1270 | .frequency_max = 2150000, | ||
1271 | .frequency_tolerance = 5000, | ||
1272 | .symbol_rate_min = 1000000, | ||
1273 | .symbol_rate_max = 45000000, | ||
1274 | .caps = FE_CAN_INVERSION_AUTO | | ||
1275 | FE_CAN_FEC_1_2 | | ||
1276 | FE_CAN_FEC_2_3 | | ||
1277 | FE_CAN_FEC_3_4 | | ||
1278 | FE_CAN_FEC_4_5 | | ||
1279 | FE_CAN_FEC_5_6 | | ||
1280 | FE_CAN_FEC_6_7 | | ||
1281 | FE_CAN_FEC_7_8 | | ||
1282 | FE_CAN_FEC_8_9 | | ||
1283 | FE_CAN_FEC_AUTO | | ||
1284 | FE_CAN_QPSK | | ||
1285 | FE_CAN_RECOVER | | ||
1286 | FE_CAN_2G_MODULATION | ||
1287 | }, | ||
1288 | |||
1289 | .release = m88ds3103_release, | ||
1290 | |||
1291 | .get_tune_settings = m88ds3103_get_tune_settings, | ||
1292 | |||
1293 | .init = m88ds3103_init, | ||
1294 | .sleep = m88ds3103_sleep, | ||
1295 | |||
1296 | .set_frontend = m88ds3103_set_frontend, | ||
1297 | .get_frontend = m88ds3103_get_frontend, | ||
1298 | |||
1299 | .read_status = m88ds3103_read_status, | ||
1300 | .read_snr = m88ds3103_read_snr, | ||
1301 | |||
1302 | .diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd, | ||
1303 | .diseqc_send_burst = m88ds3103_diseqc_send_burst, | ||
1304 | |||
1305 | .set_tone = m88ds3103_set_tone, | ||
1306 | }; | ||
1307 | |||
1308 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
1309 | MODULE_DESCRIPTION("Montage M88DS3103 DVB-S/S2 demodulator driver"); | ||
1310 | MODULE_LICENSE("GPL"); | ||
1311 | MODULE_FIRMWARE(M88DS3103_FIRMWARE); | ||
diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h new file mode 100644 index 000000000000..bbb7e3aa5675 --- /dev/null +++ b/drivers/media/dvb-frontends/m88ds3103.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Montage M88DS3103 demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef M88DS3103_H | ||
18 | #define M88DS3103_H | ||
19 | |||
20 | #include <linux/dvb/frontend.h> | ||
21 | |||
22 | struct m88ds3103_config { | ||
23 | /* | ||
24 | * I2C address | ||
25 | * Default: none, must set | ||
26 | * 0x68, ... | ||
27 | */ | ||
28 | u8 i2c_addr; | ||
29 | |||
30 | /* | ||
31 | * clock | ||
32 | * Default: none, must set | ||
33 | * 27000000 | ||
34 | */ | ||
35 | u32 clock; | ||
36 | |||
37 | /* | ||
38 | * max bytes I2C provider is asked to write at once | ||
39 | * Default: none, must set | ||
40 | * 33, 65, ... | ||
41 | */ | ||
42 | u16 i2c_wr_max; | ||
43 | |||
44 | /* | ||
45 | * TS output mode | ||
46 | * Default: M88DS3103_TS_SERIAL | ||
47 | */ | ||
48 | #define M88DS3103_TS_SERIAL 0 /* TS output pin D0, normal */ | ||
49 | #define M88DS3103_TS_SERIAL_D7 1 /* TS output pin D7 */ | ||
50 | #define M88DS3103_TS_PARALLEL 2 /* 24 MHz, normal */ | ||
51 | #define M88DS3103_TS_PARALLEL_12 3 /* 12 MHz */ | ||
52 | #define M88DS3103_TS_PARALLEL_16 4 /* 16 MHz */ | ||
53 | #define M88DS3103_TS_PARALLEL_19_2 5 /* 19.2 MHz */ | ||
54 | #define M88DS3103_TS_CI 6 /* 6 MHz */ | ||
55 | u8 ts_mode; | ||
56 | |||
57 | /* | ||
58 | * spectrum inversion | ||
59 | * Default: 0 | ||
60 | */ | ||
61 | u8 spec_inv:1; | ||
62 | |||
63 | /* | ||
64 | * AGC polarity | ||
65 | * Default: 0 | ||
66 | */ | ||
67 | u8 agc_inv:1; | ||
68 | |||
69 | /* | ||
70 | * clock output | ||
71 | * Default: M88DS3103_CLOCK_OUT_DISABLED | ||
72 | */ | ||
73 | #define M88DS3103_CLOCK_OUT_DISABLED 0 | ||
74 | #define M88DS3103_CLOCK_OUT_ENABLED 1 | ||
75 | #define M88DS3103_CLOCK_OUT_ENABLED_DIV2 2 | ||
76 | u8 clock_out; | ||
77 | |||
78 | /* | ||
79 | * DiSEqC envelope mode | ||
80 | * Default: 0 | ||
81 | */ | ||
82 | u8 envelope_mode:1; | ||
83 | |||
84 | /* | ||
85 | * AGC configuration | ||
86 | * Default: none, must set | ||
87 | */ | ||
88 | u8 agc; | ||
89 | }; | ||
90 | |||
91 | /* | ||
92 | * Driver implements own I2C-adapter for tuner I2C access. That's since chip | ||
93 | * has I2C-gate control which closes gate automatically after I2C transfer. | ||
94 | * Using own I2C adapter we can workaround that. | ||
95 | */ | ||
96 | |||
97 | #if defined(CONFIG_DVB_M88DS3103) || \ | ||
98 | (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE)) | ||
99 | extern struct dvb_frontend *m88ds3103_attach( | ||
100 | const struct m88ds3103_config *config, | ||
101 | struct i2c_adapter *i2c, | ||
102 | struct i2c_adapter **tuner_i2c); | ||
103 | #else | ||
104 | static inline struct dvb_frontend *m88ds3103_attach( | ||
105 | const struct m88ds3103_config *config, | ||
106 | struct i2c_adapter *i2c, | ||
107 | struct i2c_adapter **tuner_i2c) | ||
108 | { | ||
109 | pr_warn("%s: driver disabled by Kconfig\n", __func__); | ||
110 | return NULL; | ||
111 | } | ||
112 | #endif | ||
113 | |||
114 | #endif | ||
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h new file mode 100644 index 000000000000..84c3c06df622 --- /dev/null +++ b/drivers/media/dvb-frontends/m88ds3103_priv.h | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Montage M88DS3103 demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef M88DS3103_PRIV_H | ||
18 | #define M88DS3103_PRIV_H | ||
19 | |||
20 | #include "dvb_frontend.h" | ||
21 | #include "m88ds3103.h" | ||
22 | #include "dvb_math.h" | ||
23 | #include <linux/firmware.h> | ||
24 | #include <linux/i2c-mux.h> | ||
25 | |||
26 | #define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" | ||
27 | #define M88DS3103_MCLK_KHZ 96000 | ||
28 | |||
29 | struct m88ds3103_priv { | ||
30 | struct i2c_adapter *i2c; | ||
31 | /* mutex needed due to own tuner I2C adapter */ | ||
32 | struct mutex i2c_mutex; | ||
33 | const struct m88ds3103_config *cfg; | ||
34 | struct dvb_frontend fe; | ||
35 | fe_delivery_system_t delivery_system; | ||
36 | fe_status_t fe_status; | ||
37 | bool warm; /* FW running */ | ||
38 | struct i2c_adapter *i2c_adapter; | ||
39 | }; | ||
40 | |||
41 | struct m88ds3103_reg_val { | ||
42 | u8 reg; | ||
43 | u8 val; | ||
44 | }; | ||
45 | |||
46 | static const struct m88ds3103_reg_val m88ds3103_dvbs_init_reg_vals[] = { | ||
47 | {0x23, 0x07}, | ||
48 | {0x08, 0x03}, | ||
49 | {0x0c, 0x02}, | ||
50 | {0x21, 0x54}, | ||
51 | {0x25, 0x8a}, | ||
52 | {0x27, 0x31}, | ||
53 | {0x30, 0x08}, | ||
54 | {0x31, 0x40}, | ||
55 | {0x32, 0x32}, | ||
56 | {0x35, 0xff}, | ||
57 | {0x3a, 0x00}, | ||
58 | {0x37, 0x10}, | ||
59 | {0x38, 0x10}, | ||
60 | {0x39, 0x02}, | ||
61 | {0x42, 0x60}, | ||
62 | {0x4a, 0x80}, | ||
63 | {0x4b, 0x04}, | ||
64 | {0x4d, 0x91}, | ||
65 | {0x5d, 0xc8}, | ||
66 | {0x50, 0x36}, | ||
67 | {0x51, 0x36}, | ||
68 | {0x52, 0x36}, | ||
69 | {0x53, 0x36}, | ||
70 | {0x56, 0x01}, | ||
71 | {0x63, 0x0f}, | ||
72 | {0x64, 0x30}, | ||
73 | {0x65, 0x40}, | ||
74 | {0x68, 0x26}, | ||
75 | {0x69, 0x4c}, | ||
76 | {0x70, 0x20}, | ||
77 | {0x71, 0x70}, | ||
78 | {0x72, 0x04}, | ||
79 | {0x73, 0x00}, | ||
80 | {0x70, 0x40}, | ||
81 | {0x71, 0x70}, | ||
82 | {0x72, 0x04}, | ||
83 | {0x73, 0x00}, | ||
84 | {0x70, 0x60}, | ||
85 | {0x71, 0x70}, | ||
86 | {0x72, 0x04}, | ||
87 | {0x73, 0x00}, | ||
88 | {0x70, 0x80}, | ||
89 | {0x71, 0x70}, | ||
90 | {0x72, 0x04}, | ||
91 | {0x73, 0x00}, | ||
92 | {0x70, 0xa0}, | ||
93 | {0x71, 0x70}, | ||
94 | {0x72, 0x04}, | ||
95 | {0x73, 0x00}, | ||
96 | {0x70, 0x1f}, | ||
97 | {0x76, 0x38}, | ||
98 | {0x77, 0xa6}, | ||
99 | {0x78, 0x0c}, | ||
100 | {0x79, 0x80}, | ||
101 | {0x7f, 0x14}, | ||
102 | {0x7c, 0x00}, | ||
103 | {0xae, 0x82}, | ||
104 | {0x80, 0x64}, | ||
105 | {0x81, 0x66}, | ||
106 | {0x82, 0x44}, | ||
107 | {0x85, 0x04}, | ||
108 | {0xcd, 0xf4}, | ||
109 | {0x90, 0x33}, | ||
110 | {0xa0, 0x44}, | ||
111 | {0xc0, 0x08}, | ||
112 | {0xc3, 0x10}, | ||
113 | {0xc4, 0x08}, | ||
114 | {0xc5, 0xf0}, | ||
115 | {0xc6, 0xff}, | ||
116 | {0xc7, 0x00}, | ||
117 | {0xc8, 0x1a}, | ||
118 | {0xc9, 0x80}, | ||
119 | {0xe0, 0xf8}, | ||
120 | {0xe6, 0x8b}, | ||
121 | {0xd0, 0x40}, | ||
122 | {0xf8, 0x20}, | ||
123 | {0xfa, 0x0f}, | ||
124 | {0x00, 0x00}, | ||
125 | {0xbd, 0x01}, | ||
126 | {0xb8, 0x00}, | ||
127 | }; | ||
128 | |||
129 | static const struct m88ds3103_reg_val m88ds3103_dvbs2_init_reg_vals[] = { | ||
130 | {0x23, 0x07}, | ||
131 | {0x08, 0x07}, | ||
132 | {0x0c, 0x02}, | ||
133 | {0x21, 0x54}, | ||
134 | {0x25, 0x8a}, | ||
135 | {0x27, 0x31}, | ||
136 | {0x30, 0x08}, | ||
137 | {0x32, 0x32}, | ||
138 | {0x35, 0xff}, | ||
139 | {0x3a, 0x00}, | ||
140 | {0x37, 0x10}, | ||
141 | {0x38, 0x10}, | ||
142 | {0x39, 0x02}, | ||
143 | {0x42, 0x60}, | ||
144 | {0x4a, 0x80}, | ||
145 | {0x4b, 0x04}, | ||
146 | {0x4d, 0x91}, | ||
147 | {0x5d, 0xc8}, | ||
148 | {0x50, 0x36}, | ||
149 | {0x51, 0x36}, | ||
150 | {0x52, 0x36}, | ||
151 | {0x53, 0x36}, | ||
152 | {0x56, 0x01}, | ||
153 | {0x63, 0x0f}, | ||
154 | {0x64, 0x10}, | ||
155 | {0x65, 0x20}, | ||
156 | {0x68, 0x46}, | ||
157 | {0x69, 0xcd}, | ||
158 | {0x70, 0x20}, | ||
159 | {0x71, 0x70}, | ||
160 | {0x72, 0x04}, | ||
161 | {0x73, 0x00}, | ||
162 | {0x70, 0x40}, | ||
163 | {0x71, 0x70}, | ||
164 | {0x72, 0x04}, | ||
165 | {0x73, 0x00}, | ||
166 | {0x70, 0x60}, | ||
167 | {0x71, 0x70}, | ||
168 | {0x72, 0x04}, | ||
169 | {0x73, 0x00}, | ||
170 | {0x70, 0x80}, | ||
171 | {0x71, 0x70}, | ||
172 | {0x72, 0x04}, | ||
173 | {0x73, 0x00}, | ||
174 | {0x70, 0xa0}, | ||
175 | {0x71, 0x70}, | ||
176 | {0x72, 0x04}, | ||
177 | {0x73, 0x00}, | ||
178 | {0x70, 0x1f}, | ||
179 | {0x76, 0x38}, | ||
180 | {0x77, 0xa6}, | ||
181 | {0x78, 0x0c}, | ||
182 | {0x79, 0x80}, | ||
183 | {0x7f, 0x14}, | ||
184 | {0x85, 0x08}, | ||
185 | {0xcd, 0xf4}, | ||
186 | {0x90, 0x33}, | ||
187 | {0x86, 0x00}, | ||
188 | {0x87, 0x0f}, | ||
189 | {0x89, 0x00}, | ||
190 | {0x8b, 0x44}, | ||
191 | {0x8c, 0x66}, | ||
192 | {0x9d, 0xc1}, | ||
193 | {0x8a, 0x10}, | ||
194 | {0xad, 0x40}, | ||
195 | {0xa0, 0x44}, | ||
196 | {0xc0, 0x08}, | ||
197 | {0xc1, 0x10}, | ||
198 | {0xc2, 0x08}, | ||
199 | {0xc3, 0x10}, | ||
200 | {0xc4, 0x08}, | ||
201 | {0xc5, 0xf0}, | ||
202 | {0xc6, 0xff}, | ||
203 | {0xc7, 0x00}, | ||
204 | {0xc8, 0x1a}, | ||
205 | {0xc9, 0x80}, | ||
206 | {0xca, 0x23}, | ||
207 | {0xcb, 0x24}, | ||
208 | {0xcc, 0xf4}, | ||
209 | {0xce, 0x74}, | ||
210 | {0x00, 0x00}, | ||
211 | {0xbd, 0x01}, | ||
212 | {0xb8, 0x00}, | ||
213 | }; | ||
214 | |||
215 | #endif | ||
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c index 4da5272075cb..b2351466b0da 100644 --- a/drivers/media/dvb-frontends/m88rs2000.c +++ b/drivers/media/dvb-frontends/m88rs2000.c | |||
@@ -110,28 +110,94 @@ static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 reg) | |||
110 | return b1[0]; | 110 | return b1[0]; |
111 | } | 111 | } |
112 | 112 | ||
113 | static u32 m88rs2000_get_mclk(struct dvb_frontend *fe) | ||
114 | { | ||
115 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
116 | u32 mclk; | ||
117 | u8 reg; | ||
118 | /* Must not be 0x00 or 0xff */ | ||
119 | reg = m88rs2000_readreg(state, 0x86); | ||
120 | if (!reg || reg == 0xff) | ||
121 | return 0; | ||
122 | |||
123 | reg /= 2; | ||
124 | reg += 1; | ||
125 | |||
126 | mclk = (u32)(reg * RS2000_FE_CRYSTAL_KHZ + 28 / 2) / 28; | ||
127 | |||
128 | return mclk; | ||
129 | } | ||
130 | |||
131 | static int m88rs2000_set_carrieroffset(struct dvb_frontend *fe, s16 offset) | ||
132 | { | ||
133 | struct m88rs2000_state *state = fe->demodulator_priv; | ||
134 | u32 mclk; | ||
135 | s32 tmp; | ||
136 | u8 reg; | ||
137 | int ret; | ||
138 | |||
139 | mclk = m88rs2000_get_mclk(fe); | ||
140 | if (!mclk) | ||
141 | return -EINVAL; | ||
142 | |||
143 | tmp = (offset * 4096 + (s32)mclk / 2) / (s32)mclk; | ||
144 | if (tmp < 0) | ||
145 | tmp += 4096; | ||
146 | |||
147 | /* Carrier Offset */ | ||
148 | ret = m88rs2000_writereg(state, 0x9c, (u8)(tmp >> 4)); | ||
149 | |||
150 | reg = m88rs2000_readreg(state, 0x9d); | ||
151 | reg &= 0xf; | ||
152 | reg |= (u8)(tmp & 0xf) << 4; | ||
153 | |||
154 | ret |= m88rs2000_writereg(state, 0x9d, reg); | ||
155 | |||
156 | return ret; | ||
157 | } | ||
158 | |||
113 | static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate) | 159 | static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate) |
114 | { | 160 | { |
115 | struct m88rs2000_state *state = fe->demodulator_priv; | 161 | struct m88rs2000_state *state = fe->demodulator_priv; |
116 | int ret; | 162 | int ret; |
117 | u32 temp; | 163 | u64 temp; |
164 | u32 mclk; | ||
118 | u8 b[3]; | 165 | u8 b[3]; |
119 | 166 | ||
120 | if ((srate < 1000000) || (srate > 45000000)) | 167 | if ((srate < 1000000) || (srate > 45000000)) |
121 | return -EINVAL; | 168 | return -EINVAL; |
122 | 169 | ||
170 | mclk = m88rs2000_get_mclk(fe); | ||
171 | if (!mclk) | ||
172 | return -EINVAL; | ||
173 | |||
123 | temp = srate / 1000; | 174 | temp = srate / 1000; |
124 | temp *= 11831; | 175 | temp *= 1 << 24; |
125 | temp /= 68; | 176 | |
126 | temp -= 3; | 177 | do_div(temp, mclk); |
127 | 178 | ||
128 | b[0] = (u8) (temp >> 16) & 0xff; | 179 | b[0] = (u8) (temp >> 16) & 0xff; |
129 | b[1] = (u8) (temp >> 8) & 0xff; | 180 | b[1] = (u8) (temp >> 8) & 0xff; |
130 | b[2] = (u8) temp & 0xff; | 181 | b[2] = (u8) temp & 0xff; |
182 | |||
131 | ret = m88rs2000_writereg(state, 0x93, b[2]); | 183 | ret = m88rs2000_writereg(state, 0x93, b[2]); |
132 | ret |= m88rs2000_writereg(state, 0x94, b[1]); | 184 | ret |= m88rs2000_writereg(state, 0x94, b[1]); |
133 | ret |= m88rs2000_writereg(state, 0x95, b[0]); | 185 | ret |= m88rs2000_writereg(state, 0x95, b[0]); |
134 | 186 | ||
187 | if (srate > 10000000) | ||
188 | ret |= m88rs2000_writereg(state, 0xa0, 0x20); | ||
189 | else | ||
190 | ret |= m88rs2000_writereg(state, 0xa0, 0x60); | ||
191 | |||
192 | ret |= m88rs2000_writereg(state, 0xa1, 0xe0); | ||
193 | |||
194 | if (srate > 12000000) | ||
195 | ret |= m88rs2000_writereg(state, 0xa3, 0x20); | ||
196 | else if (srate > 2800000) | ||
197 | ret |= m88rs2000_writereg(state, 0xa3, 0x98); | ||
198 | else | ||
199 | ret |= m88rs2000_writereg(state, 0xa3, 0x90); | ||
200 | |||
135 | deb_info("m88rs2000: m88rs2000_set_symbolrate\n"); | 201 | deb_info("m88rs2000: m88rs2000_set_symbolrate\n"); |
136 | return ret; | 202 | return ret; |
137 | } | 203 | } |
@@ -261,8 +327,6 @@ struct inittab m88rs2000_shutdown[] = { | |||
261 | 327 | ||
262 | struct inittab fe_reset[] = { | 328 | struct inittab fe_reset[] = { |
263 | {DEMOD_WRITE, 0x00, 0x01}, | 329 | {DEMOD_WRITE, 0x00, 0x01}, |
264 | {DEMOD_WRITE, 0xf1, 0xbf}, | ||
265 | {DEMOD_WRITE, 0x00, 0x01}, | ||
266 | {DEMOD_WRITE, 0x20, 0x81}, | 330 | {DEMOD_WRITE, 0x20, 0x81}, |
267 | {DEMOD_WRITE, 0x21, 0x80}, | 331 | {DEMOD_WRITE, 0x21, 0x80}, |
268 | {DEMOD_WRITE, 0x10, 0x33}, | 332 | {DEMOD_WRITE, 0x10, 0x33}, |
@@ -305,9 +369,6 @@ struct inittab fe_trigger[] = { | |||
305 | {DEMOD_WRITE, 0x9b, 0x64}, | 369 | {DEMOD_WRITE, 0x9b, 0x64}, |
306 | {DEMOD_WRITE, 0x9e, 0x00}, | 370 | {DEMOD_WRITE, 0x9e, 0x00}, |
307 | {DEMOD_WRITE, 0x9f, 0xf8}, | 371 | {DEMOD_WRITE, 0x9f, 0xf8}, |
308 | {DEMOD_WRITE, 0xa0, 0x20}, | ||
309 | {DEMOD_WRITE, 0xa1, 0xe0}, | ||
310 | {DEMOD_WRITE, 0xa3, 0x38}, | ||
311 | {DEMOD_WRITE, 0x98, 0xff}, | 372 | {DEMOD_WRITE, 0x98, 0xff}, |
312 | {DEMOD_WRITE, 0xc0, 0x0f}, | 373 | {DEMOD_WRITE, 0xc0, 0x0f}, |
313 | {DEMOD_WRITE, 0x89, 0x01}, | 374 | {DEMOD_WRITE, 0x89, 0x01}, |
@@ -408,7 +469,7 @@ static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status) | |||
408 | 469 | ||
409 | *status = 0; | 470 | *status = 0; |
410 | 471 | ||
411 | if ((reg & 0x7) == 0x7) { | 472 | if ((reg & 0xee) == 0xee) { |
412 | *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI | 473 | *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI |
413 | | FE_HAS_SYNC | FE_HAS_LOCK; | 474 | | FE_HAS_SYNC | FE_HAS_LOCK; |
414 | if (state->config->set_ts_params) | 475 | if (state->config->set_ts_params) |
@@ -480,33 +541,38 @@ static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |||
480 | static int m88rs2000_set_fec(struct m88rs2000_state *state, | 541 | static int m88rs2000_set_fec(struct m88rs2000_state *state, |
481 | fe_code_rate_t fec) | 542 | fe_code_rate_t fec) |
482 | { | 543 | { |
483 | u16 fec_set; | 544 | u8 fec_set, reg; |
545 | int ret; | ||
546 | |||
484 | switch (fec) { | 547 | switch (fec) { |
485 | /* This is not confirmed kept for reference */ | 548 | case FEC_1_2: |
486 | /* case FEC_1_2: | 549 | fec_set = 0x8; |
487 | fec_set = 0x88; | ||
488 | break; | 550 | break; |
489 | case FEC_2_3: | 551 | case FEC_2_3: |
490 | fec_set = 0x68; | 552 | fec_set = 0x10; |
491 | break; | 553 | break; |
492 | case FEC_3_4: | 554 | case FEC_3_4: |
493 | fec_set = 0x48; | 555 | fec_set = 0x20; |
494 | break; | 556 | break; |
495 | case FEC_5_6: | 557 | case FEC_5_6: |
496 | fec_set = 0x28; | 558 | fec_set = 0x40; |
497 | break; | 559 | break; |
498 | case FEC_7_8: | 560 | case FEC_7_8: |
499 | fec_set = 0x18; | 561 | fec_set = 0x80; |
500 | break; */ | 562 | break; |
501 | case FEC_AUTO: | 563 | case FEC_AUTO: |
502 | default: | 564 | default: |
503 | fec_set = 0x08; | 565 | fec_set = 0x0; |
504 | } | 566 | } |
505 | m88rs2000_writereg(state, 0x76, fec_set); | ||
506 | 567 | ||
507 | return 0; | 568 | reg = m88rs2000_readreg(state, 0x70); |
508 | } | 569 | reg &= 0x7; |
570 | ret = m88rs2000_writereg(state, 0x70, reg | fec_set); | ||
509 | 571 | ||
572 | ret |= m88rs2000_writereg(state, 0x76, 0x8); | ||
573 | |||
574 | return ret; | ||
575 | } | ||
510 | 576 | ||
511 | static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state) | 577 | static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state) |
512 | { | 578 | { |
@@ -515,18 +581,20 @@ static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state) | |||
515 | reg = m88rs2000_readreg(state, 0x76); | 581 | reg = m88rs2000_readreg(state, 0x76); |
516 | m88rs2000_writereg(state, 0x9a, 0xb0); | 582 | m88rs2000_writereg(state, 0x9a, 0xb0); |
517 | 583 | ||
584 | reg &= 0xf0; | ||
585 | reg >>= 5; | ||
586 | |||
518 | switch (reg) { | 587 | switch (reg) { |
519 | case 0x88: | 588 | case 0x4: |
520 | return FEC_1_2; | 589 | return FEC_1_2; |
521 | case 0x68: | 590 | case 0x3: |
522 | return FEC_2_3; | 591 | return FEC_2_3; |
523 | case 0x48: | 592 | case 0x2: |
524 | return FEC_3_4; | 593 | return FEC_3_4; |
525 | case 0x28: | 594 | case 0x1: |
526 | return FEC_5_6; | 595 | return FEC_5_6; |
527 | case 0x18: | 596 | case 0x0: |
528 | return FEC_7_8; | 597 | return FEC_7_8; |
529 | case 0x08: | ||
530 | default: | 598 | default: |
531 | break; | 599 | break; |
532 | } | 600 | } |
@@ -540,9 +608,8 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) | |||
540 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 608 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
541 | fe_status_t status; | 609 | fe_status_t status; |
542 | int i, ret = 0; | 610 | int i, ret = 0; |
543 | s32 tmp; | ||
544 | u32 tuner_freq; | 611 | u32 tuner_freq; |
545 | u16 offset = 0; | 612 | s16 offset = 0; |
546 | u8 reg; | 613 | u8 reg; |
547 | 614 | ||
548 | state->no_lock_count = 0; | 615 | state->no_lock_count = 0; |
@@ -567,38 +634,31 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) | |||
567 | if (ret < 0) | 634 | if (ret < 0) |
568 | return -ENODEV; | 635 | return -ENODEV; |
569 | 636 | ||
570 | offset = tuner_freq - c->frequency; | 637 | offset = (s16)((s32)tuner_freq - c->frequency); |
571 | |||
572 | /* calculate offset assuming 96000kHz*/ | ||
573 | tmp = offset; | ||
574 | tmp *= 65536; | ||
575 | |||
576 | tmp = (2 * tmp + 96000) / (2 * 96000); | ||
577 | if (tmp < 0) | ||
578 | tmp += 65536; | ||
579 | 638 | ||
580 | offset = tmp & 0xffff; | 639 | /* default mclk value 96.4285 * 2 * 1000 = 192857 */ |
640 | if (((c->frequency % 192857) >= (192857 - 3000)) || | ||
641 | (c->frequency % 192857) <= 3000) | ||
642 | ret = m88rs2000_writereg(state, 0x86, 0xc2); | ||
643 | else | ||
644 | ret = m88rs2000_writereg(state, 0x86, 0xc6); | ||
581 | 645 | ||
582 | ret = m88rs2000_writereg(state, 0x9a, 0x30); | 646 | ret |= m88rs2000_set_carrieroffset(fe, offset); |
583 | /* Unknown usually 0xc6 sometimes 0xc1 */ | 647 | if (ret < 0) |
584 | reg = m88rs2000_readreg(state, 0x86); | 648 | return -ENODEV; |
585 | ret |= m88rs2000_writereg(state, 0x86, reg); | ||
586 | /* Offset lower nibble always 0 */ | ||
587 | ret |= m88rs2000_writereg(state, 0x9c, (offset >> 8)); | ||
588 | ret |= m88rs2000_writereg(state, 0x9d, offset & 0xf0); | ||
589 | 649 | ||
650 | /* Reset demod by symbol rate */ | ||
651 | if (c->symbol_rate > 27500000) | ||
652 | ret = m88rs2000_writereg(state, 0xf1, 0xa4); | ||
653 | else | ||
654 | ret = m88rs2000_writereg(state, 0xf1, 0xbf); | ||
590 | 655 | ||
591 | /* Reset Demod */ | 656 | ret |= m88rs2000_tab_set(state, fe_reset); |
592 | ret = m88rs2000_tab_set(state, fe_reset); | ||
593 | if (ret < 0) | 657 | if (ret < 0) |
594 | return -ENODEV; | 658 | return -ENODEV; |
595 | 659 | ||
596 | /* Unknown */ | ||
597 | reg = m88rs2000_readreg(state, 0x70); | ||
598 | ret = m88rs2000_writereg(state, 0x70, reg); | ||
599 | |||
600 | /* Set FEC */ | 660 | /* Set FEC */ |
601 | ret |= m88rs2000_set_fec(state, c->fec_inner); | 661 | ret = m88rs2000_set_fec(state, c->fec_inner); |
602 | ret |= m88rs2000_writereg(state, 0x85, 0x1); | 662 | ret |= m88rs2000_writereg(state, 0x85, 0x1); |
603 | ret |= m88rs2000_writereg(state, 0x8a, 0xbf); | 663 | ret |= m88rs2000_writereg(state, 0x8a, 0xbf); |
604 | ret |= m88rs2000_writereg(state, 0x8d, 0x1e); | 664 | ret |= m88rs2000_writereg(state, 0x8d, 0x1e); |
@@ -620,7 +680,7 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) | |||
620 | 680 | ||
621 | for (i = 0; i < 25; i++) { | 681 | for (i = 0; i < 25; i++) { |
622 | reg = m88rs2000_readreg(state, 0x8c); | 682 | reg = m88rs2000_readreg(state, 0x8c); |
623 | if ((reg & 0x7) == 0x7) { | 683 | if ((reg & 0xee) == 0xee) { |
624 | status = FE_HAS_LOCK; | 684 | status = FE_HAS_LOCK; |
625 | break; | 685 | break; |
626 | } | 686 | } |
diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h index 14ce31e76ae6..0a50ea90736b 100644 --- a/drivers/media/dvb-frontends/m88rs2000.h +++ b/drivers/media/dvb-frontends/m88rs2000.h | |||
@@ -53,6 +53,8 @@ static inline struct dvb_frontend *m88rs2000_attach( | |||
53 | } | 53 | } |
54 | #endif /* CONFIG_DVB_M88RS2000 */ | 54 | #endif /* CONFIG_DVB_M88RS2000 */ |
55 | 55 | ||
56 | #define RS2000_FE_CRYSTAL_KHZ 27000 | ||
57 | |||
56 | enum { | 58 | enum { |
57 | DEMOD_WRITE = 0x1, | 59 | DEMOD_WRITE = 0x1, |
58 | WRITE_DELAY = 0x10, | 60 | WRITE_DELAY = 0x10, |
diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c index fbca9856313a..4bf057544607 100644 --- a/drivers/media/dvb-frontends/nxt200x.c +++ b/drivers/media/dvb-frontends/nxt200x.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 40 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
41 | 41 | ||
42 | /* Max transfer size done by I2C transfer functions */ | 42 | /* Max transfer size done by I2C transfer functions */ |
43 | #define MAX_XFER_SIZE 64 | 43 | #define MAX_XFER_SIZE 256 |
44 | 44 | ||
45 | #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" | 45 | #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" |
46 | #define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" | 46 | #define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" |
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 842654d33317..4aa9c5311cc5 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig | |||
@@ -555,14 +555,6 @@ config VIDEO_MT9V032 | |||
555 | This is a Video4Linux2 sensor-level driver for the Micron | 555 | This is a Video4Linux2 sensor-level driver for the Micron |
556 | MT9V032 752x480 CMOS sensor. | 556 | MT9V032 752x480 CMOS sensor. |
557 | 557 | ||
558 | config VIDEO_TCM825X | ||
559 | tristate "TCM825x camera sensor support" | ||
560 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_INT_DEVICE | ||
561 | depends on MEDIA_CAMERA_SUPPORT | ||
562 | ---help--- | ||
563 | This is a driver for the Toshiba TCM825x VGA camera sensor. | ||
564 | It is used for example in Nokia N800. | ||
565 | |||
566 | config VIDEO_SR030PC30 | 558 | config VIDEO_SR030PC30 |
567 | tristate "Siliconfile SR030PC30 sensor support" | 559 | tristate "Siliconfile SR030PC30 sensor support" |
568 | depends on I2C && VIDEO_V4L2 | 560 | depends on I2C && VIDEO_V4L2 |
@@ -594,6 +586,13 @@ config VIDEO_S5K4ECGX | |||
594 | This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M | 586 | This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M |
595 | camera sensor with an embedded SoC image signal processor. | 587 | camera sensor with an embedded SoC image signal processor. |
596 | 588 | ||
589 | config VIDEO_S5K5BAF | ||
590 | tristate "Samsung S5K5BAF sensor support" | ||
591 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
592 | ---help--- | ||
593 | This is a V4L2 sensor-level driver for Samsung S5K5BAF 2M | ||
594 | camera sensor with an embedded SoC image signal processor. | ||
595 | |||
597 | source "drivers/media/i2c/smiapp/Kconfig" | 596 | source "drivers/media/i2c/smiapp/Kconfig" |
598 | 597 | ||
599 | config VIDEO_S5C73M3 | 598 | config VIDEO_S5C73M3 |
@@ -655,6 +654,18 @@ config VIDEO_UPD64083 | |||
655 | To compile this driver as a module, choose M here: the | 654 | To compile this driver as a module, choose M here: the |
656 | module will be called upd64083. | 655 | module will be called upd64083. |
657 | 656 | ||
657 | comment "Audio/Video compression chips" | ||
658 | |||
659 | config VIDEO_SAA6752HS | ||
660 | tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder" | ||
661 | depends on VIDEO_V4L2 && I2C | ||
662 | ---help--- | ||
663 | Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3 | ||
664 | audio encoder with multiplexer. | ||
665 | |||
666 | To compile this driver as a module, choose M here: the | ||
667 | module will be called saa6752hs. | ||
668 | |||
658 | comment "Miscellaneous helper chips" | 669 | comment "Miscellaneous helper chips" |
659 | 670 | ||
660 | config VIDEO_THS7303 | 671 | config VIDEO_THS7303 |
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index e03f1776f4f4..48888ae876fb 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o | |||
19 | obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o | 19 | obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o |
20 | obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o | 20 | obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o |
21 | obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o | 21 | obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o |
22 | obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o | ||
22 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o | 23 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o |
23 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o | 24 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o |
24 | obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o | 25 | obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o |
@@ -57,7 +58,6 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | |||
57 | obj-$(CONFIG_VIDEO_OV7640) += ov7640.o | 58 | obj-$(CONFIG_VIDEO_OV7640) += ov7640.o |
58 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | 59 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o |
59 | obj-$(CONFIG_VIDEO_OV9650) += ov9650.o | 60 | obj-$(CONFIG_VIDEO_OV9650) += ov9650.o |
60 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o | ||
61 | obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o | 61 | obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o |
62 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o | 62 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o |
63 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o | 63 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o |
@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | |||
67 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 67 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
68 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o | 68 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o |
69 | obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o | 69 | obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o |
70 | obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o | ||
70 | obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ | 71 | obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ |
71 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o | 72 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o |
72 | obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o | 73 | obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o |
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index b06a7e54ee0d..83225d6a0dd9 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c | |||
@@ -66,11 +66,6 @@ MODULE_LICENSE("GPL"); | |||
66 | ********************************************************************** | 66 | ********************************************************************** |
67 | */ | 67 | */ |
68 | 68 | ||
69 | struct i2c_reg_value { | ||
70 | u8 reg; | ||
71 | u8 value; | ||
72 | }; | ||
73 | |||
74 | struct ad9389b_state_edid { | 69 | struct ad9389b_state_edid { |
75 | /* total number of blocks */ | 70 | /* total number of blocks */ |
76 | u32 blocks; | 71 | u32 blocks; |
@@ -143,14 +138,14 @@ static int ad9389b_wr(struct v4l2_subdev *sd, u8 reg, u8 val) | |||
143 | if (ret == 0) | 138 | if (ret == 0) |
144 | return 0; | 139 | return 0; |
145 | } | 140 | } |
146 | v4l2_err(sd, "I2C Write Problem\n"); | 141 | v4l2_err(sd, "%s: failed reg 0x%x, val 0x%x\n", __func__, reg, val); |
147 | return ret; | 142 | return ret; |
148 | } | 143 | } |
149 | 144 | ||
150 | /* To set specific bits in the register, a clear-mask is given (to be AND-ed), | 145 | /* To set specific bits in the register, a clear-mask is given (to be AND-ed), |
151 | and then the value-mask (to be OR-ed). */ | 146 | and then the value-mask (to be OR-ed). */ |
152 | static inline void ad9389b_wr_and_or(struct v4l2_subdev *sd, u8 reg, | 147 | static inline void ad9389b_wr_and_or(struct v4l2_subdev *sd, u8 reg, |
153 | u8 clr_mask, u8 val_mask) | 148 | u8 clr_mask, u8 val_mask) |
154 | { | 149 | { |
155 | ad9389b_wr(sd, reg, (ad9389b_rd(sd, reg) & clr_mask) | val_mask); | 150 | ad9389b_wr(sd, reg, (ad9389b_rd(sd, reg) & clr_mask) | val_mask); |
156 | } | 151 | } |
@@ -321,12 +316,12 @@ static int ad9389b_s_ctrl(struct v4l2_ctrl *ctrl) | |||
321 | struct ad9389b_state *state = get_ad9389b_state(sd); | 316 | struct ad9389b_state *state = get_ad9389b_state(sd); |
322 | 317 | ||
323 | v4l2_dbg(1, debug, sd, | 318 | v4l2_dbg(1, debug, sd, |
324 | "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val); | 319 | "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val); |
325 | 320 | ||
326 | if (state->hdmi_mode_ctrl == ctrl) { | 321 | if (state->hdmi_mode_ctrl == ctrl) { |
327 | /* Set HDMI or DVI-D */ | 322 | /* Set HDMI or DVI-D */ |
328 | ad9389b_wr_and_or(sd, 0xaf, 0xfd, | 323 | ad9389b_wr_and_or(sd, 0xaf, 0xfd, |
329 | ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); | 324 | ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); |
330 | return 0; | 325 | return 0; |
331 | } | 326 | } |
332 | if (state->rgb_quantization_range_ctrl == ctrl) | 327 | if (state->rgb_quantization_range_ctrl == ctrl) |
@@ -387,61 +382,57 @@ static int ad9389b_log_status(struct v4l2_subdev *sd) | |||
387 | v4l2_info(sd, "chip revision %d\n", state->chip_revision); | 382 | v4l2_info(sd, "chip revision %d\n", state->chip_revision); |
388 | v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off"); | 383 | v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off"); |
389 | v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n", | 384 | v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n", |
390 | (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ? | 385 | (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ? |
391 | "detected" : "no", | 386 | "detected" : "no", |
392 | (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ? | 387 | (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ? |
393 | "detected" : "no", | 388 | "detected" : "no", |
394 | edid->segments ? "found" : "no", edid->blocks); | 389 | edid->segments ? "found" : "no", edid->blocks); |
395 | if (state->have_monitor) { | 390 | v4l2_info(sd, "%s output %s\n", |
396 | v4l2_info(sd, "%s output %s\n", | 391 | (ad9389b_rd(sd, 0xaf) & 0x02) ? |
397 | (ad9389b_rd(sd, 0xaf) & 0x02) ? | 392 | "HDMI" : "DVI-D", |
398 | "HDMI" : "DVI-D", | 393 | (ad9389b_rd(sd, 0xa1) & 0x3c) ? |
399 | (ad9389b_rd(sd, 0xa1) & 0x3c) ? | 394 | "disabled" : "enabled"); |
400 | "disabled" : "enabled"); | ||
401 | } | ||
402 | v4l2_info(sd, "ad9389b: %s\n", (ad9389b_rd(sd, 0xb8) & 0x40) ? | 395 | v4l2_info(sd, "ad9389b: %s\n", (ad9389b_rd(sd, 0xb8) & 0x40) ? |
403 | "encrypted" : "no encryption"); | 396 | "encrypted" : "no encryption"); |
404 | v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n", | 397 | v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n", |
405 | states[ad9389b_rd(sd, 0xc8) & 0xf], | 398 | states[ad9389b_rd(sd, 0xc8) & 0xf], |
406 | errors[ad9389b_rd(sd, 0xc8) >> 4], | 399 | errors[ad9389b_rd(sd, 0xc8) >> 4], |
407 | state->edid_detect_counter, | 400 | state->edid_detect_counter, |
408 | ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96)); | 401 | ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96)); |
409 | manual_gear = ad9389b_rd(sd, 0x98) & 0x80; | 402 | manual_gear = ad9389b_rd(sd, 0x98) & 0x80; |
410 | v4l2_info(sd, "ad9389b: RGB quantization: %s range\n", | 403 | v4l2_info(sd, "ad9389b: RGB quantization: %s range\n", |
411 | ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full"); | 404 | ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full"); |
412 | v4l2_info(sd, "ad9389b: %s gear %d\n", | 405 | v4l2_info(sd, "ad9389b: %s gear %d\n", |
413 | manual_gear ? "manual" : "automatic", | 406 | manual_gear ? "manual" : "automatic", |
414 | manual_gear ? ((ad9389b_rd(sd, 0x98) & 0x70) >> 4) : | 407 | manual_gear ? ((ad9389b_rd(sd, 0x98) & 0x70) >> 4) : |
415 | ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1)); | 408 | ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1)); |
416 | if (state->have_monitor) { | 409 | if (ad9389b_rd(sd, 0xaf) & 0x02) { |
417 | if (ad9389b_rd(sd, 0xaf) & 0x02) { | 410 | /* HDMI only */ |
418 | /* HDMI only */ | 411 | u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80; |
419 | u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80; | 412 | u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 | |
420 | u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 | | 413 | ad9389b_rd(sd, 0x02) << 8 | |
421 | ad9389b_rd(sd, 0x02) << 8 | | 414 | ad9389b_rd(sd, 0x03); |
422 | ad9389b_rd(sd, 0x03); | 415 | u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2; |
423 | u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2; | 416 | u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f; |
424 | u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f; | 417 | u32 CTS; |
425 | u32 CTS; | 418 | |
426 | 419 | if (manual_cts) | |
427 | if (manual_cts) | 420 | CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 | |
428 | CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 | | 421 | ad9389b_rd(sd, 0x08) << 8 | |
429 | ad9389b_rd(sd, 0x08) << 8 | | 422 | ad9389b_rd(sd, 0x09); |
430 | ad9389b_rd(sd, 0x09); | 423 | else |
431 | else | 424 | CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 | |
432 | CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 | | 425 | ad9389b_rd(sd, 0x05) << 8 | |
433 | ad9389b_rd(sd, 0x05) << 8 | | 426 | ad9389b_rd(sd, 0x06); |
434 | ad9389b_rd(sd, 0x06); | 427 | N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 | |
435 | N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 | | 428 | ad9389b_rd(sd, 0x02) << 8 | |
436 | ad9389b_rd(sd, 0x02) << 8 | | 429 | ad9389b_rd(sd, 0x03); |
437 | ad9389b_rd(sd, 0x03); | 430 | |
438 | 431 | v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n", | |
439 | v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n", | 432 | manual_cts ? "manual" : "automatic", N, CTS); |
440 | manual_cts ? "manual" : "automatic", N, CTS); | 433 | |
441 | 434 | v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n", | |
442 | v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n", | 435 | vic_detect, vic_sent); |
443 | vic_detect, vic_sent); | ||
444 | } | ||
445 | } | 436 | } |
446 | if (state->dv_timings.type == V4L2_DV_BT_656_1120) | 437 | if (state->dv_timings.type == V4L2_DV_BT_656_1120) |
447 | v4l2_print_dv_timings(sd->name, "timings: ", | 438 | v4l2_print_dv_timings(sd->name, "timings: ", |
@@ -486,7 +477,7 @@ static int ad9389b_s_power(struct v4l2_subdev *sd, int on) | |||
486 | } | 477 | } |
487 | if (i > 1) | 478 | if (i > 1) |
488 | v4l2_dbg(1, debug, sd, | 479 | v4l2_dbg(1, debug, sd, |
489 | "needed %d retries to powerup the ad9389b\n", i); | 480 | "needed %d retries to powerup the ad9389b\n", i); |
490 | 481 | ||
491 | /* Select chip: AD9389B */ | 482 | /* Select chip: AD9389B */ |
492 | ad9389b_wr_and_or(sd, 0xba, 0xef, 0x10); | 483 | ad9389b_wr_and_or(sd, 0xba, 0xef, 0x10); |
@@ -556,14 +547,16 @@ static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
556 | irq_status = ad9389b_rd(sd, 0x96); | 547 | irq_status = ad9389b_rd(sd, 0x96); |
557 | /* clear detected interrupts */ | 548 | /* clear detected interrupts */ |
558 | ad9389b_wr(sd, 0x96, irq_status); | 549 | ad9389b_wr(sd, 0x96, irq_status); |
550 | /* enable interrupts */ | ||
551 | ad9389b_set_isr(sd, true); | ||
552 | |||
553 | v4l2_dbg(1, debug, sd, "%s: irq_status 0x%x\n", __func__, irq_status); | ||
559 | 554 | ||
560 | if (irq_status & (MASK_AD9389B_HPD_INT | MASK_AD9389B_MSEN_INT)) | 555 | if (irq_status & (MASK_AD9389B_HPD_INT)) |
561 | ad9389b_check_monitor_present_status(sd); | 556 | ad9389b_check_monitor_present_status(sd); |
562 | if (irq_status & MASK_AD9389B_EDID_RDY_INT) | 557 | if (irq_status & MASK_AD9389B_EDID_RDY_INT) |
563 | ad9389b_check_edid_status(sd); | 558 | ad9389b_check_edid_status(sd); |
564 | 559 | ||
565 | /* enable interrupts */ | ||
566 | ad9389b_set_isr(sd, true); | ||
567 | *handled = true; | 560 | *handled = true; |
568 | return 0; | 561 | return 0; |
569 | } | 562 | } |
@@ -599,7 +592,7 @@ static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi | |||
599 | if (edid->blocks + edid->start_block >= state->edid.segments * 2) | 592 | if (edid->blocks + edid->start_block >= state->edid.segments * 2) |
600 | edid->blocks = state->edid.segments * 2 - edid->start_block; | 593 | edid->blocks = state->edid.segments * 2 - edid->start_block; |
601 | memcpy(edid->edid, &state->edid.data[edid->start_block * 128], | 594 | memcpy(edid->edid, &state->edid.data[edid->start_block * 128], |
602 | 128 * edid->blocks); | 595 | 128 * edid->blocks); |
603 | return 0; | 596 | return 0; |
604 | } | 597 | } |
605 | 598 | ||
@@ -612,8 +605,6 @@ static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = { | |||
612 | /* Enable/disable ad9389b output */ | 605 | /* Enable/disable ad9389b output */ |
613 | static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable) | 606 | static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable) |
614 | { | 607 | { |
615 | struct ad9389b_state *state = get_ad9389b_state(sd); | ||
616 | |||
617 | v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); | 608 | v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); |
618 | 609 | ||
619 | ad9389b_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c)); | 610 | ad9389b_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c)); |
@@ -621,7 +612,6 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable) | |||
621 | ad9389b_check_monitor_present_status(sd); | 612 | ad9389b_check_monitor_present_status(sd); |
622 | } else { | 613 | } else { |
623 | ad9389b_s_power(sd, 0); | 614 | ad9389b_s_power(sd, 0); |
624 | state->have_monitor = false; | ||
625 | } | 615 | } |
626 | return 0; | 616 | return 0; |
627 | } | 617 | } |
@@ -686,14 +676,14 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd, | |||
686 | } | 676 | } |
687 | 677 | ||
688 | static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd, | 678 | static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd, |
689 | struct v4l2_enum_dv_timings *timings) | 679 | struct v4l2_enum_dv_timings *timings) |
690 | { | 680 | { |
691 | return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap, | 681 | return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap, |
692 | NULL, NULL); | 682 | NULL, NULL); |
693 | } | 683 | } |
694 | 684 | ||
695 | static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd, | 685 | static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd, |
696 | struct v4l2_dv_timings_cap *cap) | 686 | struct v4l2_dv_timings_cap *cap) |
697 | { | 687 | { |
698 | *cap = ad9389b_timings_cap; | 688 | *cap = ad9389b_timings_cap; |
699 | return 0; | 689 | return 0; |
@@ -724,15 +714,15 @@ static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |||
724 | u32 N; | 714 | u32 N; |
725 | 715 | ||
726 | switch (freq) { | 716 | switch (freq) { |
727 | case 32000: N = 4096; break; | 717 | case 32000: N = 4096; break; |
728 | case 44100: N = 6272; break; | 718 | case 44100: N = 6272; break; |
729 | case 48000: N = 6144; break; | 719 | case 48000: N = 6144; break; |
730 | case 88200: N = 12544; break; | 720 | case 88200: N = 12544; break; |
731 | case 96000: N = 12288; break; | 721 | case 96000: N = 12288; break; |
732 | case 176400: N = 25088; break; | 722 | case 176400: N = 25088; break; |
733 | case 192000: N = 24576; break; | 723 | case 192000: N = 24576; break; |
734 | default: | 724 | default: |
735 | return -EINVAL; | 725 | return -EINVAL; |
736 | } | 726 | } |
737 | 727 | ||
738 | /* Set N (used with CTS to regenerate the audio clock) */ | 728 | /* Set N (used with CTS to regenerate the audio clock) */ |
@@ -748,15 +738,15 @@ static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |||
748 | u32 i2s_sf; | 738 | u32 i2s_sf; |
749 | 739 | ||
750 | switch (freq) { | 740 | switch (freq) { |
751 | case 32000: i2s_sf = 0x30; break; | 741 | case 32000: i2s_sf = 0x30; break; |
752 | case 44100: i2s_sf = 0x00; break; | 742 | case 44100: i2s_sf = 0x00; break; |
753 | case 48000: i2s_sf = 0x20; break; | 743 | case 48000: i2s_sf = 0x20; break; |
754 | case 88200: i2s_sf = 0x80; break; | 744 | case 88200: i2s_sf = 0x80; break; |
755 | case 96000: i2s_sf = 0xa0; break; | 745 | case 96000: i2s_sf = 0xa0; break; |
756 | case 176400: i2s_sf = 0xc0; break; | 746 | case 176400: i2s_sf = 0xc0; break; |
757 | case 192000: i2s_sf = 0xe0; break; | 747 | case 192000: i2s_sf = 0xe0; break; |
758 | default: | 748 | default: |
759 | return -EINVAL; | 749 | return -EINVAL; |
760 | } | 750 | } |
761 | 751 | ||
762 | /* Set sampling frequency for I2S audio to 48 kHz */ | 752 | /* Set sampling frequency for I2S audio to 48 kHz */ |
@@ -800,7 +790,7 @@ static const struct v4l2_subdev_ops ad9389b_ops = { | |||
800 | 790 | ||
801 | /* ----------------------------------------------------------------------- */ | 791 | /* ----------------------------------------------------------------------- */ |
802 | static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, | 792 | static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, |
803 | int segment, u8 *buf) | 793 | int segment, u8 *buf) |
804 | { | 794 | { |
805 | int i, j; | 795 | int i, j; |
806 | 796 | ||
@@ -826,8 +816,8 @@ static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, | |||
826 | static void ad9389b_edid_handler(struct work_struct *work) | 816 | static void ad9389b_edid_handler(struct work_struct *work) |
827 | { | 817 | { |
828 | struct delayed_work *dwork = to_delayed_work(work); | 818 | struct delayed_work *dwork = to_delayed_work(work); |
829 | struct ad9389b_state *state = container_of(dwork, | 819 | struct ad9389b_state *state = |
830 | struct ad9389b_state, edid_handler); | 820 | container_of(dwork, struct ad9389b_state, edid_handler); |
831 | struct v4l2_subdev *sd = &state->sd; | 821 | struct v4l2_subdev *sd = &state->sd; |
832 | struct ad9389b_edid_detect ed; | 822 | struct ad9389b_edid_detect ed; |
833 | 823 | ||
@@ -845,11 +835,10 @@ static void ad9389b_edid_handler(struct work_struct *work) | |||
845 | if (state->edid.read_retries) { | 835 | if (state->edid.read_retries) { |
846 | state->edid.read_retries--; | 836 | state->edid.read_retries--; |
847 | v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__); | 837 | v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__); |
848 | state->have_monitor = false; | ||
849 | ad9389b_s_power(sd, false); | 838 | ad9389b_s_power(sd, false); |
850 | ad9389b_s_power(sd, true); | 839 | ad9389b_s_power(sd, true); |
851 | queue_delayed_work(state->work_queue, | 840 | queue_delayed_work(state->work_queue, |
852 | &state->edid_handler, EDID_DELAY); | 841 | &state->edid_handler, EDID_DELAY); |
853 | return; | 842 | return; |
854 | } | 843 | } |
855 | } | 844 | } |
@@ -915,49 +904,35 @@ static void ad9389b_notify_monitor_detect(struct v4l2_subdev *sd) | |||
915 | v4l2_subdev_notify(sd, AD9389B_MONITOR_DETECT, (void *)&mdt); | 904 | v4l2_subdev_notify(sd, AD9389B_MONITOR_DETECT, (void *)&mdt); |
916 | } | 905 | } |
917 | 906 | ||
918 | static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd) | 907 | static void ad9389b_update_monitor_present_status(struct v4l2_subdev *sd) |
919 | { | 908 | { |
920 | struct ad9389b_state *state = get_ad9389b_state(sd); | 909 | struct ad9389b_state *state = get_ad9389b_state(sd); |
921 | /* read hotplug and rx-sense state */ | 910 | /* read hotplug and rx-sense state */ |
922 | u8 status = ad9389b_rd(sd, 0x42); | 911 | u8 status = ad9389b_rd(sd, 0x42); |
923 | 912 | ||
924 | v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n", | 913 | v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n", |
925 | __func__, | 914 | __func__, |
926 | status, | 915 | status, |
927 | status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "", | 916 | status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "", |
928 | status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : ""); | 917 | status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : ""); |
929 | 918 | ||
930 | if ((status & MASK_AD9389B_HPD_DETECT) && | 919 | if (status & MASK_AD9389B_HPD_DETECT) { |
931 | ((status & MASK_AD9389B_MSEN_DETECT) || state->edid.segments)) { | ||
932 | v4l2_dbg(1, debug, sd, | ||
933 | "%s: hotplug and (rx-sense or edid)\n", __func__); | ||
934 | if (!state->have_monitor) { | ||
935 | v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__); | ||
936 | state->have_monitor = true; | ||
937 | ad9389b_set_isr(sd, true); | ||
938 | if (!ad9389b_s_power(sd, true)) { | ||
939 | v4l2_dbg(1, debug, sd, | ||
940 | "%s: monitor detected, powerup failed\n", __func__); | ||
941 | return; | ||
942 | } | ||
943 | ad9389b_setup(sd); | ||
944 | ad9389b_notify_monitor_detect(sd); | ||
945 | state->edid.read_retries = EDID_MAX_RETRIES; | ||
946 | queue_delayed_work(state->work_queue, | ||
947 | &state->edid_handler, EDID_DELAY); | ||
948 | } | ||
949 | } else if (status & MASK_AD9389B_HPD_DETECT) { | ||
950 | v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__); | 920 | v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__); |
921 | state->have_monitor = true; | ||
922 | if (!ad9389b_s_power(sd, true)) { | ||
923 | v4l2_dbg(1, debug, sd, | ||
924 | "%s: monitor detected, powerup failed\n", __func__); | ||
925 | return; | ||
926 | } | ||
927 | ad9389b_setup(sd); | ||
928 | ad9389b_notify_monitor_detect(sd); | ||
951 | state->edid.read_retries = EDID_MAX_RETRIES; | 929 | state->edid.read_retries = EDID_MAX_RETRIES; |
952 | queue_delayed_work(state->work_queue, | 930 | queue_delayed_work(state->work_queue, |
953 | &state->edid_handler, EDID_DELAY); | 931 | &state->edid_handler, EDID_DELAY); |
954 | } else if (!(status & MASK_AD9389B_HPD_DETECT)) { | 932 | } else if (!(status & MASK_AD9389B_HPD_DETECT)) { |
955 | v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__); | 933 | v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__); |
956 | if (state->have_monitor) { | 934 | state->have_monitor = false; |
957 | v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__); | 935 | ad9389b_notify_monitor_detect(sd); |
958 | state->have_monitor = false; | ||
959 | ad9389b_notify_monitor_detect(sd); | ||
960 | } | ||
961 | ad9389b_s_power(sd, false); | 936 | ad9389b_s_power(sd, false); |
962 | memset(&state->edid, 0, sizeof(struct ad9389b_state_edid)); | 937 | memset(&state->edid, 0, sizeof(struct ad9389b_state_edid)); |
963 | } | 938 | } |
@@ -966,6 +941,35 @@ static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd) | |||
966 | v4l2_ctrl_s_ctrl(state->hotplug_ctrl, ad9389b_have_hotplug(sd) ? 0x1 : 0x0); | 941 | v4l2_ctrl_s_ctrl(state->hotplug_ctrl, ad9389b_have_hotplug(sd) ? 0x1 : 0x0); |
967 | v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, ad9389b_have_rx_sense(sd) ? 0x1 : 0x0); | 942 | v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, ad9389b_have_rx_sense(sd) ? 0x1 : 0x0); |
968 | v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0); | 943 | v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0); |
944 | |||
945 | /* update with setting from ctrls */ | ||
946 | ad9389b_s_ctrl(state->rgb_quantization_range_ctrl); | ||
947 | ad9389b_s_ctrl(state->hdmi_mode_ctrl); | ||
948 | } | ||
949 | |||
950 | static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd) | ||
951 | { | ||
952 | struct ad9389b_state *state = get_ad9389b_state(sd); | ||
953 | int retry = 0; | ||
954 | |||
955 | ad9389b_update_monitor_present_status(sd); | ||
956 | |||
957 | /* | ||
958 | * Rapid toggling of the hotplug may leave the chip powered off, | ||
959 | * even if we think it is on. In that case reset and power up again. | ||
960 | */ | ||
961 | while (state->power_on && (ad9389b_rd(sd, 0x41) & 0x40)) { | ||
962 | if (++retry > 5) { | ||
963 | v4l2_err(sd, "retried %d times, give up\n", retry); | ||
964 | return; | ||
965 | } | ||
966 | v4l2_dbg(1, debug, sd, "%s: reset and re-check status (%d)\n", __func__, retry); | ||
967 | ad9389b_notify_monitor_detect(sd); | ||
968 | cancel_delayed_work_sync(&state->edid_handler); | ||
969 | memset(&state->edid, 0, sizeof(struct ad9389b_state_edid)); | ||
970 | ad9389b_s_power(sd, false); | ||
971 | ad9389b_update_monitor_present_status(sd); | ||
972 | } | ||
969 | } | 973 | } |
970 | 974 | ||
971 | static bool edid_block_verify_crc(u8 *edid_block) | 975 | static bool edid_block_verify_crc(u8 *edid_block) |
@@ -978,7 +982,7 @@ static bool edid_block_verify_crc(u8 *edid_block) | |||
978 | return sum == 0; | 982 | return sum == 0; |
979 | } | 983 | } |
980 | 984 | ||
981 | static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment) | 985 | static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment) |
982 | { | 986 | { |
983 | struct ad9389b_state *state = get_ad9389b_state(sd); | 987 | struct ad9389b_state *state = get_ad9389b_state(sd); |
984 | u32 blocks = state->edid.blocks; | 988 | u32 blocks = state->edid.blocks; |
@@ -992,6 +996,25 @@ static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment) | |||
992 | return false; | 996 | return false; |
993 | } | 997 | } |
994 | 998 | ||
999 | static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment) | ||
1000 | { | ||
1001 | static const u8 hdmi_header[] = { | ||
1002 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 | ||
1003 | }; | ||
1004 | struct ad9389b_state *state = get_ad9389b_state(sd); | ||
1005 | u8 *data = state->edid.data; | ||
1006 | int i; | ||
1007 | |||
1008 | if (segment) | ||
1009 | return true; | ||
1010 | |||
1011 | for (i = 0; i < ARRAY_SIZE(hdmi_header); i++) | ||
1012 | if (data[i] != hdmi_header[i]) | ||
1013 | return false; | ||
1014 | |||
1015 | return true; | ||
1016 | } | ||
1017 | |||
995 | static bool ad9389b_check_edid_status(struct v4l2_subdev *sd) | 1018 | static bool ad9389b_check_edid_status(struct v4l2_subdev *sd) |
996 | { | 1019 | { |
997 | struct ad9389b_state *state = get_ad9389b_state(sd); | 1020 | struct ad9389b_state *state = get_ad9389b_state(sd); |
@@ -1000,7 +1023,7 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd) | |||
1000 | u8 edidRdy = ad9389b_rd(sd, 0xc5); | 1023 | u8 edidRdy = ad9389b_rd(sd, 0xc5); |
1001 | 1024 | ||
1002 | v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n", | 1025 | v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n", |
1003 | __func__, EDID_MAX_RETRIES - state->edid.read_retries); | 1026 | __func__, EDID_MAX_RETRIES - state->edid.read_retries); |
1004 | 1027 | ||
1005 | if (!(edidRdy & MASK_AD9389B_EDID_RDY)) | 1028 | if (!(edidRdy & MASK_AD9389B_EDID_RDY)) |
1006 | return false; | 1029 | return false; |
@@ -1013,16 +1036,16 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd) | |||
1013 | v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment); | 1036 | v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment); |
1014 | ad9389b_edid_rd(sd, 256, &state->edid.data[segment * 256]); | 1037 | ad9389b_edid_rd(sd, 256, &state->edid.data[segment * 256]); |
1015 | ad9389b_dbg_dump_edid(2, debug, sd, segment, | 1038 | ad9389b_dbg_dump_edid(2, debug, sd, segment, |
1016 | &state->edid.data[segment * 256]); | 1039 | &state->edid.data[segment * 256]); |
1017 | if (segment == 0) { | 1040 | if (segment == 0) { |
1018 | state->edid.blocks = state->edid.data[0x7e] + 1; | 1041 | state->edid.blocks = state->edid.data[0x7e] + 1; |
1019 | v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", | 1042 | v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", |
1020 | __func__, state->edid.blocks); | 1043 | __func__, state->edid.blocks); |
1021 | } | 1044 | } |
1022 | if (!edid_segment_verify_crc(sd, segment)) { | 1045 | if (!edid_verify_crc(sd, segment) || |
1046 | !edid_verify_header(sd, segment)) { | ||
1023 | /* edid crc error, force reread of edid segment */ | 1047 | /* edid crc error, force reread of edid segment */ |
1024 | v4l2_err(sd, "%s: edid crc error\n", __func__); | 1048 | v4l2_err(sd, "%s: edid crc or header error\n", __func__); |
1025 | state->have_monitor = false; | ||
1026 | ad9389b_s_power(sd, false); | 1049 | ad9389b_s_power(sd, false); |
1027 | ad9389b_s_power(sd, true); | 1050 | ad9389b_s_power(sd, true); |
1028 | return false; | 1051 | return false; |
@@ -1032,12 +1055,12 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd) | |||
1032 | if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) { | 1055 | if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) { |
1033 | /* Request next EDID segment */ | 1056 | /* Request next EDID segment */ |
1034 | v4l2_dbg(1, debug, sd, "%s: request segment %d\n", | 1057 | v4l2_dbg(1, debug, sd, "%s: request segment %d\n", |
1035 | __func__, state->edid.segments); | 1058 | __func__, state->edid.segments); |
1036 | ad9389b_wr(sd, 0xc9, 0xf); | 1059 | ad9389b_wr(sd, 0xc9, 0xf); |
1037 | ad9389b_wr(sd, 0xc4, state->edid.segments); | 1060 | ad9389b_wr(sd, 0xc4, state->edid.segments); |
1038 | state->edid.read_retries = EDID_MAX_RETRIES; | 1061 | state->edid.read_retries = EDID_MAX_RETRIES; |
1039 | queue_delayed_work(state->work_queue, | 1062 | queue_delayed_work(state->work_queue, |
1040 | &state->edid_handler, EDID_DELAY); | 1063 | &state->edid_handler, EDID_DELAY); |
1041 | return false; | 1064 | return false; |
1042 | } | 1065 | } |
1043 | 1066 | ||
@@ -1081,7 +1104,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1081 | return -EIO; | 1104 | return -EIO; |
1082 | 1105 | ||
1083 | v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n", | 1106 | v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n", |
1084 | client->addr << 1); | 1107 | client->addr << 1); |
1085 | 1108 | ||
1086 | state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); | 1109 | state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); |
1087 | if (!state) | 1110 | if (!state) |
@@ -1140,7 +1163,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1140 | goto err_entity; | 1163 | goto err_entity; |
1141 | } | 1164 | } |
1142 | v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n", | 1165 | v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n", |
1143 | ad9389b_rd(sd, 0x41), state->chip_revision); | 1166 | ad9389b_rd(sd, 0x41), state->chip_revision); |
1144 | 1167 | ||
1145 | state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1)); | 1168 | state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1)); |
1146 | if (state->edid_i2c_client == NULL) { | 1169 | if (state->edid_i2c_client == NULL) { |
@@ -1163,7 +1186,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1163 | ad9389b_set_isr(sd, true); | 1186 | ad9389b_set_isr(sd, true); |
1164 | 1187 | ||
1165 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, | 1188 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, |
1166 | client->addr << 1, client->adapter->name); | 1189 | client->addr << 1, client->adapter->name); |
1167 | return 0; | 1190 | return 0; |
1168 | 1191 | ||
1169 | err_unreg: | 1192 | err_unreg: |
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 7c8d971f1f61..ee618942cb8e 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c | |||
@@ -452,6 +452,29 @@ static int adv7511_log_status(struct v4l2_subdev *sd) | |||
452 | errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter, | 452 | errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter, |
453 | adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96)); | 453 | adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96)); |
454 | v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full"); | 454 | v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full"); |
455 | if (adv7511_rd(sd, 0xaf) & 0x02) { | ||
456 | /* HDMI only */ | ||
457 | u8 manual_cts = adv7511_rd(sd, 0x0a) & 0x80; | ||
458 | u32 N = (adv7511_rd(sd, 0x01) & 0xf) << 16 | | ||
459 | adv7511_rd(sd, 0x02) << 8 | | ||
460 | adv7511_rd(sd, 0x03); | ||
461 | u8 vic_detect = adv7511_rd(sd, 0x3e) >> 2; | ||
462 | u8 vic_sent = adv7511_rd(sd, 0x3d) & 0x3f; | ||
463 | u32 CTS; | ||
464 | |||
465 | if (manual_cts) | ||
466 | CTS = (adv7511_rd(sd, 0x07) & 0xf) << 16 | | ||
467 | adv7511_rd(sd, 0x08) << 8 | | ||
468 | adv7511_rd(sd, 0x09); | ||
469 | else | ||
470 | CTS = (adv7511_rd(sd, 0x04) & 0xf) << 16 | | ||
471 | adv7511_rd(sd, 0x05) << 8 | | ||
472 | adv7511_rd(sd, 0x06); | ||
473 | v4l2_info(sd, "CTS %s mode: N %d, CTS %d\n", | ||
474 | manual_cts ? "manual" : "automatic", N, CTS); | ||
475 | v4l2_info(sd, "VIC: detected %d, sent %d\n", | ||
476 | vic_detect, vic_sent); | ||
477 | } | ||
455 | if (state->dv_timings.type == V4L2_DV_BT_656_1120) | 478 | if (state->dv_timings.type == V4L2_DV_BT_656_1120) |
456 | v4l2_print_dv_timings(sd->name, "timings: ", | 479 | v4l2_print_dv_timings(sd->name, "timings: ", |
457 | &state->dv_timings, false); | 480 | &state->dv_timings, false); |
@@ -942,26 +965,38 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd) | |||
942 | 965 | ||
943 | static bool edid_block_verify_crc(uint8_t *edid_block) | 966 | static bool edid_block_verify_crc(uint8_t *edid_block) |
944 | { | 967 | { |
945 | int i; | ||
946 | uint8_t sum = 0; | 968 | uint8_t sum = 0; |
969 | int i; | ||
947 | 970 | ||
948 | for (i = 0; i < 128; i++) | 971 | for (i = 0; i < 128; i++) |
949 | sum += *(edid_block + i); | 972 | sum += edid_block[i]; |
950 | return (sum == 0); | 973 | return sum == 0; |
951 | } | 974 | } |
952 | 975 | ||
953 | static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment) | 976 | static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment) |
954 | { | 977 | { |
955 | struct adv7511_state *state = get_adv7511_state(sd); | 978 | struct adv7511_state *state = get_adv7511_state(sd); |
956 | u32 blocks = state->edid.blocks; | 979 | u32 blocks = state->edid.blocks; |
957 | uint8_t *data = state->edid.data; | 980 | uint8_t *data = state->edid.data; |
958 | 981 | ||
959 | if (edid_block_verify_crc(&data[segment * 256])) { | 982 | if (!edid_block_verify_crc(&data[segment * 256])) |
960 | if ((segment + 1) * 2 <= blocks) | 983 | return false; |
961 | return edid_block_verify_crc(&data[segment * 256 + 128]); | 984 | if ((segment + 1) * 2 <= blocks) |
985 | return edid_block_verify_crc(&data[segment * 256 + 128]); | ||
986 | return true; | ||
987 | } | ||
988 | |||
989 | static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment) | ||
990 | { | ||
991 | static const u8 hdmi_header[] = { | ||
992 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 | ||
993 | }; | ||
994 | struct adv7511_state *state = get_adv7511_state(sd); | ||
995 | u8 *data = state->edid.data; | ||
996 | |||
997 | if (segment != 0) | ||
962 | return true; | 998 | return true; |
963 | } | 999 | return !memcmp(data, hdmi_header, sizeof(hdmi_header)); |
964 | return false; | ||
965 | } | 1000 | } |
966 | 1001 | ||
967 | static bool adv7511_check_edid_status(struct v4l2_subdev *sd) | 1002 | static bool adv7511_check_edid_status(struct v4l2_subdev *sd) |
@@ -990,9 +1025,10 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) | |||
990 | state->edid.blocks = state->edid.data[0x7e] + 1; | 1025 | state->edid.blocks = state->edid.data[0x7e] + 1; |
991 | v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks); | 1026 | v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks); |
992 | } | 1027 | } |
993 | if (!edid_segment_verify_crc(sd, segment)) { | 1028 | if (!edid_verify_crc(sd, segment) || |
1029 | !edid_verify_header(sd, segment)) { | ||
994 | /* edid crc error, force reread of edid segment */ | 1030 | /* edid crc error, force reread of edid segment */ |
995 | v4l2_dbg(1, debug, sd, "%s: edid crc error\n", __func__); | 1031 | v4l2_err(sd, "%s: edid crc or header error\n", __func__); |
996 | state->have_monitor = false; | 1032 | state->have_monitor = false; |
997 | adv7511_s_power(sd, false); | 1033 | adv7511_s_power(sd, false); |
998 | adv7511_s_power(sd, true); | 1034 | adv7511_s_power(sd, true); |
@@ -1038,6 +1074,12 @@ static void adv7511_init_setup(struct v4l2_subdev *sd) | |||
1038 | 1074 | ||
1039 | /* clear all interrupts */ | 1075 | /* clear all interrupts */ |
1040 | adv7511_wr(sd, 0x96, 0xff); | 1076 | adv7511_wr(sd, 0x96, 0xff); |
1077 | /* | ||
1078 | * Stop HPD from resetting a lot of registers. | ||
1079 | * It might leave the chip in a partly un-initialized state, | ||
1080 | * in particular with regards to hotplug bounces. | ||
1081 | */ | ||
1082 | adv7511_wr_and_or(sd, 0xd6, 0x3f, 0xc0); | ||
1041 | memset(edid, 0, sizeof(struct adv7511_state_edid)); | 1083 | memset(edid, 0, sizeof(struct adv7511_state_edid)); |
1042 | state->have_monitor = false; | 1084 | state->have_monitor = false; |
1043 | adv7511_set_isr(sd, false); | 1085 | adv7511_set_isr(sd, false); |
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index a324106b9f11..71c8570bd9ea 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c | |||
@@ -53,8 +53,6 @@ MODULE_LICENSE("GPL"); | |||
53 | /* ADV7604 system clock frequency */ | 53 | /* ADV7604 system clock frequency */ |
54 | #define ADV7604_fsc (28636360) | 54 | #define ADV7604_fsc (28636360) |
55 | 55 | ||
56 | #define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI) | ||
57 | |||
58 | /* | 56 | /* |
59 | ********************************************************************** | 57 | ********************************************************************** |
60 | * | 58 | * |
@@ -67,17 +65,19 @@ struct adv7604_state { | |||
67 | struct v4l2_subdev sd; | 65 | struct v4l2_subdev sd; |
68 | struct media_pad pad; | 66 | struct media_pad pad; |
69 | struct v4l2_ctrl_handler hdl; | 67 | struct v4l2_ctrl_handler hdl; |
70 | enum adv7604_mode mode; | 68 | enum adv7604_input_port selected_input; |
71 | struct v4l2_dv_timings timings; | 69 | struct v4l2_dv_timings timings; |
72 | u8 edid[256]; | 70 | struct { |
73 | unsigned edid_blocks; | 71 | u8 edid[256]; |
72 | u32 present; | ||
73 | unsigned blocks; | ||
74 | } edid; | ||
75 | u16 spa_port_a[2]; | ||
74 | struct v4l2_fract aspect_ratio; | 76 | struct v4l2_fract aspect_ratio; |
75 | u32 rgb_quantization_range; | 77 | u32 rgb_quantization_range; |
76 | struct workqueue_struct *work_queues; | 78 | struct workqueue_struct *work_queues; |
77 | struct delayed_work delayed_work_enable_hotplug; | 79 | struct delayed_work delayed_work_enable_hotplug; |
78 | bool connector_hdmi; | ||
79 | bool restart_stdi_once; | 80 | bool restart_stdi_once; |
80 | u32 prev_input_status; | ||
81 | 81 | ||
82 | /* i2c clients */ | 82 | /* i2c clients */ |
83 | struct i2c_client *i2c_avlink; | 83 | struct i2c_client *i2c_avlink; |
@@ -160,6 +160,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = { | |||
160 | V4L2_DV_BT_DMT_1792X1344P60, | 160 | V4L2_DV_BT_DMT_1792X1344P60, |
161 | V4L2_DV_BT_DMT_1856X1392P60, | 161 | V4L2_DV_BT_DMT_1856X1392P60, |
162 | V4L2_DV_BT_DMT_1920X1200P60_RB, | 162 | V4L2_DV_BT_DMT_1920X1200P60_RB, |
163 | V4L2_DV_BT_DMT_1366X768P60_RB, | ||
163 | V4L2_DV_BT_DMT_1366X768P60, | 164 | V4L2_DV_BT_DMT_1366X768P60, |
164 | V4L2_DV_BT_DMT_1920X1080P60, | 165 | V4L2_DV_BT_DMT_1920X1080P60, |
165 | { }, | 166 | { }, |
@@ -507,57 +508,31 @@ static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) | |||
507 | return 0; | 508 | return 0; |
508 | } | 509 | } |
509 | 510 | ||
510 | static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) | ||
511 | { | ||
512 | struct delayed_work *dwork = to_delayed_work(work); | ||
513 | struct adv7604_state *state = container_of(dwork, struct adv7604_state, | ||
514 | delayed_work_enable_hotplug); | ||
515 | struct v4l2_subdev *sd = &state->sd; | ||
516 | |||
517 | v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); | ||
518 | |||
519 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)1); | ||
520 | } | ||
521 | |||
522 | static inline int edid_write_block(struct v4l2_subdev *sd, | 511 | static inline int edid_write_block(struct v4l2_subdev *sd, |
523 | unsigned len, const u8 *val) | 512 | unsigned len, const u8 *val) |
524 | { | 513 | { |
525 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
526 | struct adv7604_state *state = to_state(sd); | 514 | struct adv7604_state *state = to_state(sd); |
527 | int err = 0; | 515 | int err = 0; |
528 | int i; | 516 | int i; |
529 | 517 | ||
530 | v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); | 518 | v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); |
531 | 519 | ||
532 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0); | ||
533 | |||
534 | /* Disables I2C access to internal EDID ram from DDC port */ | ||
535 | rep_write_and_or(sd, 0x77, 0xf0, 0x0); | ||
536 | |||
537 | for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) | 520 | for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) |
538 | err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, | 521 | err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, |
539 | I2C_SMBUS_BLOCK_MAX, val + i); | 522 | I2C_SMBUS_BLOCK_MAX, val + i); |
540 | if (err) | 523 | return err; |
541 | return err; | 524 | } |
542 | 525 | ||
543 | /* adv7604 calculates the checksums and enables I2C access to internal | 526 | static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) |
544 | EDID ram from DDC port. */ | 527 | { |
545 | rep_write_and_or(sd, 0x77, 0xf0, 0x1); | 528 | struct delayed_work *dwork = to_delayed_work(work); |
529 | struct adv7604_state *state = container_of(dwork, struct adv7604_state, | ||
530 | delayed_work_enable_hotplug); | ||
531 | struct v4l2_subdev *sd = &state->sd; | ||
546 | 532 | ||
547 | for (i = 0; i < 1000; i++) { | 533 | v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); |
548 | if (rep_read(sd, 0x7d) & 1) | ||
549 | break; | ||
550 | mdelay(1); | ||
551 | } | ||
552 | if (i == 1000) { | ||
553 | v4l_err(client, "error enabling edid\n"); | ||
554 | return -EIO; | ||
555 | } | ||
556 | 534 | ||
557 | /* enable hotplug after 100 ms */ | 535 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); |
558 | queue_delayed_work(state->work_queues, | ||
559 | &state->delayed_work_enable_hotplug, HZ / 10); | ||
560 | return 0; | ||
561 | } | 536 | } |
562 | 537 | ||
563 | static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) | 538 | static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) |
@@ -574,6 +549,11 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) | |||
574 | return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); | 549 | return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); |
575 | } | 550 | } |
576 | 551 | ||
552 | static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | ||
553 | { | ||
554 | return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val); | ||
555 | } | ||
556 | |||
577 | static inline int test_read(struct v4l2_subdev *sd, u8 reg) | 557 | static inline int test_read(struct v4l2_subdev *sd, u8 reg) |
578 | { | 558 | { |
579 | struct adv7604_state *state = to_state(sd); | 559 | struct adv7604_state *state = to_state(sd); |
@@ -623,6 +603,26 @@ static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) | |||
623 | 603 | ||
624 | /* ----------------------------------------------------------------------- */ | 604 | /* ----------------------------------------------------------------------- */ |
625 | 605 | ||
606 | static inline bool is_analog_input(struct v4l2_subdev *sd) | ||
607 | { | ||
608 | struct adv7604_state *state = to_state(sd); | ||
609 | |||
610 | return state->selected_input == ADV7604_INPUT_VGA_RGB || | ||
611 | state->selected_input == ADV7604_INPUT_VGA_COMP; | ||
612 | } | ||
613 | |||
614 | static inline bool is_digital_input(struct v4l2_subdev *sd) | ||
615 | { | ||
616 | struct adv7604_state *state = to_state(sd); | ||
617 | |||
618 | return state->selected_input == ADV7604_INPUT_HDMI_PORT_A || | ||
619 | state->selected_input == ADV7604_INPUT_HDMI_PORT_B || | ||
620 | state->selected_input == ADV7604_INPUT_HDMI_PORT_C || | ||
621 | state->selected_input == ADV7604_INPUT_HDMI_PORT_D; | ||
622 | } | ||
623 | |||
624 | /* ----------------------------------------------------------------------- */ | ||
625 | |||
626 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 626 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
627 | static void adv7604_inv_register(struct v4l2_subdev *sd) | 627 | static void adv7604_inv_register(struct v4l2_subdev *sd) |
628 | { | 628 | { |
@@ -696,45 +696,47 @@ static int adv7604_g_register(struct v4l2_subdev *sd, | |||
696 | static int adv7604_s_register(struct v4l2_subdev *sd, | 696 | static int adv7604_s_register(struct v4l2_subdev *sd, |
697 | const struct v4l2_dbg_register *reg) | 697 | const struct v4l2_dbg_register *reg) |
698 | { | 698 | { |
699 | u8 val = reg->val & 0xff; | ||
700 | |||
699 | switch (reg->reg >> 8) { | 701 | switch (reg->reg >> 8) { |
700 | case 0: | 702 | case 0: |
701 | io_write(sd, reg->reg & 0xff, reg->val & 0xff); | 703 | io_write(sd, reg->reg & 0xff, val); |
702 | break; | 704 | break; |
703 | case 1: | 705 | case 1: |
704 | avlink_write(sd, reg->reg & 0xff, reg->val & 0xff); | 706 | avlink_write(sd, reg->reg & 0xff, val); |
705 | break; | 707 | break; |
706 | case 2: | 708 | case 2: |
707 | cec_write(sd, reg->reg & 0xff, reg->val & 0xff); | 709 | cec_write(sd, reg->reg & 0xff, val); |
708 | break; | 710 | break; |
709 | case 3: | 711 | case 3: |
710 | infoframe_write(sd, reg->reg & 0xff, reg->val & 0xff); | 712 | infoframe_write(sd, reg->reg & 0xff, val); |
711 | break; | 713 | break; |
712 | case 4: | 714 | case 4: |
713 | esdp_write(sd, reg->reg & 0xff, reg->val & 0xff); | 715 | esdp_write(sd, reg->reg & 0xff, val); |
714 | break; | 716 | break; |
715 | case 5: | 717 | case 5: |
716 | dpp_write(sd, reg->reg & 0xff, reg->val & 0xff); | 718 | dpp_write(sd, reg->reg & 0xff, val); |
717 | break; | 719 | break; |
718 | case 6: | 720 | case 6: |
719 | afe_write(sd, reg->reg & 0xff, reg->val & 0xff); | 721 | afe_write(sd, reg->reg & 0xff, val); |
720 | break; | 722 | break; |
721 | case 7: | 723 | case 7: |
722 | rep_write(sd, reg->reg & 0xff, reg->val & 0xff); | 724 | rep_write(sd, reg->reg & 0xff, val); |
723 | break; | 725 | break; |
724 | case 8: | 726 | case 8: |
725 | edid_write(sd, reg->reg & 0xff, reg->val & 0xff); | 727 | edid_write(sd, reg->reg & 0xff, val); |
726 | break; | 728 | break; |
727 | case 9: | 729 | case 9: |
728 | hdmi_write(sd, reg->reg & 0xff, reg->val & 0xff); | 730 | hdmi_write(sd, reg->reg & 0xff, val); |
729 | break; | 731 | break; |
730 | case 0xa: | 732 | case 0xa: |
731 | test_write(sd, reg->reg & 0xff, reg->val & 0xff); | 733 | test_write(sd, reg->reg & 0xff, val); |
732 | break; | 734 | break; |
733 | case 0xb: | 735 | case 0xb: |
734 | cp_write(sd, reg->reg & 0xff, reg->val & 0xff); | 736 | cp_write(sd, reg->reg & 0xff, val); |
735 | break; | 737 | break; |
736 | case 0xc: | 738 | case 0xc: |
737 | vdp_write(sd, reg->reg & 0xff, reg->val & 0xff); | 739 | vdp_write(sd, reg->reg & 0xff, val); |
738 | break; | 740 | break; |
739 | default: | 741 | default: |
740 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); | 742 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); |
@@ -748,10 +750,13 @@ static int adv7604_s_register(struct v4l2_subdev *sd, | |||
748 | static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) | 750 | static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) |
749 | { | 751 | { |
750 | struct adv7604_state *state = to_state(sd); | 752 | struct adv7604_state *state = to_state(sd); |
753 | u8 reg_io_6f = io_read(sd, 0x6f); | ||
751 | 754 | ||
752 | /* port A only */ | ||
753 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, | 755 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, |
754 | ((io_read(sd, 0x6f) & 0x10) >> 4)); | 756 | ((reg_io_6f & 0x10) >> 4) | |
757 | ((reg_io_6f & 0x08) >> 2) | | ||
758 | (reg_io_6f & 0x04) | | ||
759 | ((reg_io_6f & 0x02) << 2)); | ||
755 | } | 760 | } |
756 | 761 | ||
757 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, | 762 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, |
@@ -759,12 +764,11 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, | |||
759 | const struct adv7604_video_standards *predef_vid_timings, | 764 | const struct adv7604_video_standards *predef_vid_timings, |
760 | const struct v4l2_dv_timings *timings) | 765 | const struct v4l2_dv_timings *timings) |
761 | { | 766 | { |
762 | struct adv7604_state *state = to_state(sd); | ||
763 | int i; | 767 | int i; |
764 | 768 | ||
765 | for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { | 769 | for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { |
766 | if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings, | 770 | if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings, |
767 | DIGITAL_INPUT ? 250000 : 1000000)) | 771 | is_digital_input(sd) ? 250000 : 1000000)) |
768 | continue; | 772 | continue; |
769 | io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */ | 773 | io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */ |
770 | io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + | 774 | io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + |
@@ -799,27 +803,22 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, | |||
799 | cp_write(sd, 0xab, 0x00); | 803 | cp_write(sd, 0xab, 0x00); |
800 | cp_write(sd, 0xac, 0x00); | 804 | cp_write(sd, 0xac, 0x00); |
801 | 805 | ||
802 | switch (state->mode) { | 806 | if (is_analog_input(sd)) { |
803 | case ADV7604_MODE_COMP: | ||
804 | case ADV7604_MODE_GR: | ||
805 | err = find_and_set_predefined_video_timings(sd, | 807 | err = find_and_set_predefined_video_timings(sd, |
806 | 0x01, adv7604_prim_mode_comp, timings); | 808 | 0x01, adv7604_prim_mode_comp, timings); |
807 | if (err) | 809 | if (err) |
808 | err = find_and_set_predefined_video_timings(sd, | 810 | err = find_and_set_predefined_video_timings(sd, |
809 | 0x02, adv7604_prim_mode_gr, timings); | 811 | 0x02, adv7604_prim_mode_gr, timings); |
810 | break; | 812 | } else if (is_digital_input(sd)) { |
811 | case ADV7604_MODE_HDMI: | ||
812 | err = find_and_set_predefined_video_timings(sd, | 813 | err = find_and_set_predefined_video_timings(sd, |
813 | 0x05, adv7604_prim_mode_hdmi_comp, timings); | 814 | 0x05, adv7604_prim_mode_hdmi_comp, timings); |
814 | if (err) | 815 | if (err) |
815 | err = find_and_set_predefined_video_timings(sd, | 816 | err = find_and_set_predefined_video_timings(sd, |
816 | 0x06, adv7604_prim_mode_hdmi_gr, timings); | 817 | 0x06, adv7604_prim_mode_hdmi_gr, timings); |
817 | break; | 818 | } else { |
818 | default: | 819 | v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", |
819 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", | 820 | __func__, state->selected_input); |
820 | __func__, state->mode); | ||
821 | err = -1; | 821 | err = -1; |
822 | break; | ||
823 | } | 822 | } |
824 | 823 | ||
825 | 824 | ||
@@ -846,9 +845,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, | |||
846 | 845 | ||
847 | v4l2_dbg(2, debug, sd, "%s\n", __func__); | 846 | v4l2_dbg(2, debug, sd, "%s\n", __func__); |
848 | 847 | ||
849 | switch (state->mode) { | 848 | if (is_analog_input(sd)) { |
850 | case ADV7604_MODE_COMP: | ||
851 | case ADV7604_MODE_GR: | ||
852 | /* auto graphics */ | 849 | /* auto graphics */ |
853 | io_write(sd, 0x00, 0x07); /* video std */ | 850 | io_write(sd, 0x00, 0x07); /* video std */ |
854 | io_write(sd, 0x01, 0x02); /* prim mode */ | 851 | io_write(sd, 0x01, 0x02); /* prim mode */ |
@@ -858,33 +855,28 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, | |||
858 | /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ | 855 | /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ |
859 | /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ | 856 | /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ |
860 | /* IO-map reg. 0x16 and 0x17 should be written in sequence */ | 857 | /* IO-map reg. 0x16 and 0x17 should be written in sequence */ |
861 | if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { | 858 | if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) |
862 | v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); | 859 | v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); |
863 | break; | ||
864 | } | ||
865 | 860 | ||
866 | /* active video - horizontal timing */ | 861 | /* active video - horizontal timing */ |
867 | cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff); | 862 | cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff); |
868 | cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | | 863 | cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | |
869 | ((cp_start_eav >> 8) & 0x0f)); | 864 | ((cp_start_eav >> 8) & 0x0f)); |
870 | cp_write(sd, 0xa4, cp_start_eav & 0xff); | 865 | cp_write(sd, 0xa4, cp_start_eav & 0xff); |
871 | 866 | ||
872 | /* active video - vertical timing */ | 867 | /* active video - vertical timing */ |
873 | cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); | 868 | cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); |
874 | cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | | 869 | cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | |
875 | ((cp_end_vbi >> 8) & 0xf)); | 870 | ((cp_end_vbi >> 8) & 0xf)); |
876 | cp_write(sd, 0xa7, cp_end_vbi & 0xff); | 871 | cp_write(sd, 0xa7, cp_end_vbi & 0xff); |
877 | break; | 872 | } else if (is_digital_input(sd)) { |
878 | case ADV7604_MODE_HDMI: | ||
879 | /* set default prim_mode/vid_std for HDMI | 873 | /* set default prim_mode/vid_std for HDMI |
880 | according to [REF_03, c. 4.2] */ | 874 | according to [REF_03, c. 4.2] */ |
881 | io_write(sd, 0x00, 0x02); /* video std */ | 875 | io_write(sd, 0x00, 0x02); /* video std */ |
882 | io_write(sd, 0x01, 0x06); /* prim mode */ | 876 | io_write(sd, 0x01, 0x06); /* prim mode */ |
883 | break; | 877 | } else { |
884 | default: | 878 | v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", |
885 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", | 879 | __func__, state->selected_input); |
886 | __func__, state->mode); | ||
887 | break; | ||
888 | } | 880 | } |
889 | 881 | ||
890 | cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); | 882 | cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); |
@@ -893,43 +885,149 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, | |||
893 | cp_write(sd, 0xac, (height & 0x0f) << 4); | 885 | cp_write(sd, 0xac, (height & 0x0f) << 4); |
894 | } | 886 | } |
895 | 887 | ||
888 | static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) | ||
889 | { | ||
890 | struct adv7604_state *state = to_state(sd); | ||
891 | u8 offset_buf[4]; | ||
892 | |||
893 | if (auto_offset) { | ||
894 | offset_a = 0x3ff; | ||
895 | offset_b = 0x3ff; | ||
896 | offset_c = 0x3ff; | ||
897 | } | ||
898 | |||
899 | v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n", | ||
900 | __func__, auto_offset ? "Auto" : "Manual", | ||
901 | offset_a, offset_b, offset_c); | ||
902 | |||
903 | offset_buf[0] = (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4); | ||
904 | offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6); | ||
905 | offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8); | ||
906 | offset_buf[3] = offset_c & 0x0ff; | ||
907 | |||
908 | /* Registers must be written in this order with no i2c access in between */ | ||
909 | if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) | ||
910 | v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); | ||
911 | } | ||
912 | |||
913 | static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) | ||
914 | { | ||
915 | struct adv7604_state *state = to_state(sd); | ||
916 | u8 gain_buf[4]; | ||
917 | u8 gain_man = 1; | ||
918 | u8 agc_mode_man = 1; | ||
919 | |||
920 | if (auto_gain) { | ||
921 | gain_man = 0; | ||
922 | agc_mode_man = 0; | ||
923 | gain_a = 0x100; | ||
924 | gain_b = 0x100; | ||
925 | gain_c = 0x100; | ||
926 | } | ||
927 | |||
928 | v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n", | ||
929 | __func__, auto_gain ? "Auto" : "Manual", | ||
930 | gain_a, gain_b, gain_c); | ||
931 | |||
932 | gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4)); | ||
933 | gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6)); | ||
934 | gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8)); | ||
935 | gain_buf[3] = ((gain_c & 0x0ff)); | ||
936 | |||
937 | /* Registers must be written in this order with no i2c access in between */ | ||
938 | if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) | ||
939 | v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); | ||
940 | } | ||
941 | |||
896 | static void set_rgb_quantization_range(struct v4l2_subdev *sd) | 942 | static void set_rgb_quantization_range(struct v4l2_subdev *sd) |
897 | { | 943 | { |
898 | struct adv7604_state *state = to_state(sd); | 944 | struct adv7604_state *state = to_state(sd); |
945 | bool rgb_output = io_read(sd, 0x02) & 0x02; | ||
946 | bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; | ||
947 | |||
948 | v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", | ||
949 | __func__, state->rgb_quantization_range, | ||
950 | rgb_output, hdmi_signal); | ||
951 | |||
952 | adv7604_set_gain(sd, true, 0x0, 0x0, 0x0); | ||
953 | adv7604_set_offset(sd, true, 0x0, 0x0, 0x0); | ||
899 | 954 | ||
900 | switch (state->rgb_quantization_range) { | 955 | switch (state->rgb_quantization_range) { |
901 | case V4L2_DV_RGB_RANGE_AUTO: | 956 | case V4L2_DV_RGB_RANGE_AUTO: |
902 | /* automatic */ | 957 | if (state->selected_input == ADV7604_INPUT_VGA_RGB) { |
903 | if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) { | 958 | /* Receiving analog RGB signal |
904 | /* receiving DVI-D signal */ | 959 | * Set RGB full range (0-255) */ |
960 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | ||
961 | break; | ||
962 | } | ||
963 | |||
964 | if (state->selected_input == ADV7604_INPUT_VGA_COMP) { | ||
965 | /* Receiving analog YPbPr signal | ||
966 | * Set automode */ | ||
967 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | ||
968 | break; | ||
969 | } | ||
970 | |||
971 | if (hdmi_signal) { | ||
972 | /* Receiving HDMI signal | ||
973 | * Set automode */ | ||
974 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | ||
975 | break; | ||
976 | } | ||
905 | 977 | ||
906 | /* ADV7604 selects RGB limited range regardless of | 978 | /* Receiving DVI-D signal |
907 | input format (CE/IT) in automatic mode */ | 979 | * ADV7604 selects RGB limited range regardless of |
908 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { | 980 | * input format (CE/IT) in automatic mode */ |
909 | /* RGB limited range (16-235) */ | 981 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { |
910 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | 982 | /* RGB limited range (16-235) */ |
983 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | ||
984 | } else { | ||
985 | /* RGB full range (0-255) */ | ||
986 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | ||
911 | 987 | ||
988 | if (is_digital_input(sd) && rgb_output) { | ||
989 | adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); | ||
912 | } else { | 990 | } else { |
913 | /* RGB full range (0-255) */ | 991 | adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); |
914 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 992 | adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); |
915 | } | 993 | } |
916 | } else { | ||
917 | /* receiving HDMI or analog signal, set automode */ | ||
918 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | ||
919 | } | 994 | } |
920 | break; | 995 | break; |
921 | case V4L2_DV_RGB_RANGE_LIMITED: | 996 | case V4L2_DV_RGB_RANGE_LIMITED: |
997 | if (state->selected_input == ADV7604_INPUT_VGA_COMP) { | ||
998 | /* YCrCb limited range (16-235) */ | ||
999 | io_write_and_or(sd, 0x02, 0x0f, 0x20); | ||
1000 | break; | ||
1001 | } | ||
1002 | |||
922 | /* RGB limited range (16-235) */ | 1003 | /* RGB limited range (16-235) */ |
923 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | 1004 | io_write_and_or(sd, 0x02, 0x0f, 0x00); |
1005 | |||
924 | break; | 1006 | break; |
925 | case V4L2_DV_RGB_RANGE_FULL: | 1007 | case V4L2_DV_RGB_RANGE_FULL: |
1008 | if (state->selected_input == ADV7604_INPUT_VGA_COMP) { | ||
1009 | /* YCrCb full range (0-255) */ | ||
1010 | io_write_and_or(sd, 0x02, 0x0f, 0x60); | ||
1011 | break; | ||
1012 | } | ||
1013 | |||
926 | /* RGB full range (0-255) */ | 1014 | /* RGB full range (0-255) */ |
927 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 1015 | io_write_and_or(sd, 0x02, 0x0f, 0x10); |
1016 | |||
1017 | if (is_analog_input(sd) || hdmi_signal) | ||
1018 | break; | ||
1019 | |||
1020 | /* Adjust gain/offset for DVI-D signals only */ | ||
1021 | if (rgb_output) { | ||
1022 | adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); | ||
1023 | } else { | ||
1024 | adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); | ||
1025 | adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); | ||
1026 | } | ||
928 | break; | 1027 | break; |
929 | } | 1028 | } |
930 | } | 1029 | } |
931 | 1030 | ||
932 | |||
933 | static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) | 1031 | static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) |
934 | { | 1032 | { |
935 | struct v4l2_subdev *sd = to_sd(ctrl); | 1033 | struct v4l2_subdev *sd = to_sd(ctrl); |
@@ -983,8 +1081,9 @@ static inline bool no_power(struct v4l2_subdev *sd) | |||
983 | 1081 | ||
984 | static inline bool no_signal_tmds(struct v4l2_subdev *sd) | 1082 | static inline bool no_signal_tmds(struct v4l2_subdev *sd) |
985 | { | 1083 | { |
986 | /* TODO port B, C and D */ | 1084 | struct adv7604_state *state = to_state(sd); |
987 | return !(io_read(sd, 0x6a) & 0x10); | 1085 | |
1086 | return !(io_read(sd, 0x6a) & (0x10 >> state->selected_input)); | ||
988 | } | 1087 | } |
989 | 1088 | ||
990 | static inline bool no_lock_tmds(struct v4l2_subdev *sd) | 1089 | static inline bool no_lock_tmds(struct v4l2_subdev *sd) |
@@ -1011,7 +1110,6 @@ static inline bool no_lock_stdi(struct v4l2_subdev *sd) | |||
1011 | 1110 | ||
1012 | static inline bool no_signal(struct v4l2_subdev *sd) | 1111 | static inline bool no_signal(struct v4l2_subdev *sd) |
1013 | { | 1112 | { |
1014 | struct adv7604_state *state = to_state(sd); | ||
1015 | bool ret; | 1113 | bool ret; |
1016 | 1114 | ||
1017 | ret = no_power(sd); | 1115 | ret = no_power(sd); |
@@ -1019,7 +1117,7 @@ static inline bool no_signal(struct v4l2_subdev *sd) | |||
1019 | ret |= no_lock_stdi(sd); | 1117 | ret |= no_lock_stdi(sd); |
1020 | ret |= no_lock_sspd(sd); | 1118 | ret |= no_lock_sspd(sd); |
1021 | 1119 | ||
1022 | if (DIGITAL_INPUT) { | 1120 | if (is_digital_input(sd)) { |
1023 | ret |= no_lock_tmds(sd); | 1121 | ret |= no_lock_tmds(sd); |
1024 | ret |= no_signal_tmds(sd); | 1122 | ret |= no_signal_tmds(sd); |
1025 | } | 1123 | } |
@@ -1036,13 +1134,11 @@ static inline bool no_lock_cp(struct v4l2_subdev *sd) | |||
1036 | 1134 | ||
1037 | static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status) | 1135 | static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status) |
1038 | { | 1136 | { |
1039 | struct adv7604_state *state = to_state(sd); | ||
1040 | |||
1041 | *status = 0; | 1137 | *status = 0; |
1042 | *status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0; | 1138 | *status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0; |
1043 | *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; | 1139 | *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; |
1044 | if (no_lock_cp(sd)) | 1140 | if (no_lock_cp(sd)) |
1045 | *status |= DIGITAL_INPUT ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK; | 1141 | *status |= is_digital_input(sd) ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK; |
1046 | 1142 | ||
1047 | v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); | 1143 | v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); |
1048 | 1144 | ||
@@ -1157,13 +1253,11 @@ static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, | |||
1157 | static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, | 1253 | static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, |
1158 | struct v4l2_dv_timings_cap *cap) | 1254 | struct v4l2_dv_timings_cap *cap) |
1159 | { | 1255 | { |
1160 | struct adv7604_state *state = to_state(sd); | ||
1161 | |||
1162 | cap->type = V4L2_DV_BT_656_1120; | 1256 | cap->type = V4L2_DV_BT_656_1120; |
1163 | cap->bt.max_width = 1920; | 1257 | cap->bt.max_width = 1920; |
1164 | cap->bt.max_height = 1200; | 1258 | cap->bt.max_height = 1200; |
1165 | cap->bt.min_pixelclock = 25000000; | 1259 | cap->bt.min_pixelclock = 25000000; |
1166 | if (DIGITAL_INPUT) | 1260 | if (is_digital_input(sd)) |
1167 | cap->bt.max_pixelclock = 225000000; | 1261 | cap->bt.max_pixelclock = 225000000; |
1168 | else | 1262 | else |
1169 | cap->bt.max_pixelclock = 170000000; | 1263 | cap->bt.max_pixelclock = 170000000; |
@@ -1179,12 +1273,11 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, | |||
1179 | static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, | 1273 | static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, |
1180 | struct v4l2_dv_timings *timings) | 1274 | struct v4l2_dv_timings *timings) |
1181 | { | 1275 | { |
1182 | struct adv7604_state *state = to_state(sd); | ||
1183 | int i; | 1276 | int i; |
1184 | 1277 | ||
1185 | for (i = 0; adv7604_timings[i].bt.width; i++) { | 1278 | for (i = 0; adv7604_timings[i].bt.width; i++) { |
1186 | if (v4l2_match_dv_timings(timings, &adv7604_timings[i], | 1279 | if (v4l2_match_dv_timings(timings, &adv7604_timings[i], |
1187 | DIGITAL_INPUT ? 250000 : 1000000)) { | 1280 | is_digital_input(sd) ? 250000 : 1000000)) { |
1188 | *timings = adv7604_timings[i]; | 1281 | *timings = adv7604_timings[i]; |
1189 | break; | 1282 | break; |
1190 | } | 1283 | } |
@@ -1204,6 +1297,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, | |||
1204 | memset(timings, 0, sizeof(struct v4l2_dv_timings)); | 1297 | memset(timings, 0, sizeof(struct v4l2_dv_timings)); |
1205 | 1298 | ||
1206 | if (no_signal(sd)) { | 1299 | if (no_signal(sd)) { |
1300 | state->restart_stdi_once = true; | ||
1207 | v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); | 1301 | v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); |
1208 | return -ENOLINK; | 1302 | return -ENOLINK; |
1209 | } | 1303 | } |
@@ -1216,7 +1310,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, | |||
1216 | bt->interlaced = stdi.interlaced ? | 1310 | bt->interlaced = stdi.interlaced ? |
1217 | V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; | 1311 | V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; |
1218 | 1312 | ||
1219 | if (DIGITAL_INPUT) { | 1313 | if (is_digital_input(sd)) { |
1220 | uint32_t freq; | 1314 | uint32_t freq; |
1221 | 1315 | ||
1222 | timings->type = V4L2_DV_BT_656_1120; | 1316 | timings->type = V4L2_DV_BT_656_1120; |
@@ -1305,8 +1399,8 @@ found: | |||
1305 | return -ENOLINK; | 1399 | return -ENOLINK; |
1306 | } | 1400 | } |
1307 | 1401 | ||
1308 | if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) || | 1402 | if ((is_analog_input(sd) && bt->pixelclock > 170000000) || |
1309 | (DIGITAL_INPUT && bt->pixelclock > 225000000)) { | 1403 | (is_digital_input(sd) && bt->pixelclock > 225000000)) { |
1310 | v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n", | 1404 | v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n", |
1311 | __func__, (u32)bt->pixelclock); | 1405 | __func__, (u32)bt->pixelclock); |
1312 | return -ERANGE; | 1406 | return -ERANGE; |
@@ -1329,10 +1423,15 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, | |||
1329 | if (!timings) | 1423 | if (!timings) |
1330 | return -EINVAL; | 1424 | return -EINVAL; |
1331 | 1425 | ||
1426 | if (v4l2_match_dv_timings(&state->timings, timings, 0)) { | ||
1427 | v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); | ||
1428 | return 0; | ||
1429 | } | ||
1430 | |||
1332 | bt = &timings->bt; | 1431 | bt = &timings->bt; |
1333 | 1432 | ||
1334 | if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) || | 1433 | if ((is_analog_input(sd) && bt->pixelclock > 170000000) || |
1335 | (DIGITAL_INPUT && bt->pixelclock > 225000000)) { | 1434 | (is_digital_input(sd) && bt->pixelclock > 225000000)) { |
1336 | v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n", | 1435 | v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n", |
1337 | __func__, (u32)bt->pixelclock); | 1436 | __func__, (u32)bt->pixelclock); |
1338 | return -ERANGE; | 1437 | return -ERANGE; |
@@ -1354,7 +1453,6 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, | |||
1354 | 1453 | ||
1355 | set_rgb_quantization_range(sd); | 1454 | set_rgb_quantization_range(sd); |
1356 | 1455 | ||
1357 | |||
1358 | if (debug > 1) | 1456 | if (debug > 1) |
1359 | v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ", | 1457 | v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ", |
1360 | timings, true); | 1458 | timings, true); |
@@ -1374,30 +1472,24 @@ static void enable_input(struct v4l2_subdev *sd) | |||
1374 | { | 1472 | { |
1375 | struct adv7604_state *state = to_state(sd); | 1473 | struct adv7604_state *state = to_state(sd); |
1376 | 1474 | ||
1377 | switch (state->mode) { | 1475 | if (is_analog_input(sd)) { |
1378 | case ADV7604_MODE_COMP: | ||
1379 | case ADV7604_MODE_GR: | ||
1380 | /* enable */ | ||
1381 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ | 1476 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ |
1382 | break; | 1477 | } else if (is_digital_input(sd)) { |
1383 | case ADV7604_MODE_HDMI: | 1478 | hdmi_write_and_or(sd, 0x00, 0xfc, state->selected_input); |
1384 | /* enable */ | ||
1385 | hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ | ||
1386 | hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ | 1479 | hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ |
1387 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ | 1480 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ |
1388 | break; | 1481 | hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */ |
1389 | default: | 1482 | } else { |
1390 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", | 1483 | v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", |
1391 | __func__, state->mode); | 1484 | __func__, state->selected_input); |
1392 | break; | ||
1393 | } | 1485 | } |
1394 | } | 1486 | } |
1395 | 1487 | ||
1396 | static void disable_input(struct v4l2_subdev *sd) | 1488 | static void disable_input(struct v4l2_subdev *sd) |
1397 | { | 1489 | { |
1398 | /* disable */ | 1490 | hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio */ |
1491 | msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */ | ||
1399 | io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ | 1492 | io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ |
1400 | hdmi_write(sd, 0x1a, 0x1a); /* Mute audio */ | ||
1401 | hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ | 1493 | hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ |
1402 | } | 1494 | } |
1403 | 1495 | ||
@@ -1405,9 +1497,7 @@ static void select_input(struct v4l2_subdev *sd) | |||
1405 | { | 1497 | { |
1406 | struct adv7604_state *state = to_state(sd); | 1498 | struct adv7604_state *state = to_state(sd); |
1407 | 1499 | ||
1408 | switch (state->mode) { | 1500 | if (is_analog_input(sd)) { |
1409 | case ADV7604_MODE_COMP: | ||
1410 | case ADV7604_MODE_GR: | ||
1411 | /* reset ADI recommended settings for HDMI: */ | 1501 | /* reset ADI recommended settings for HDMI: */ |
1412 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | 1502 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ |
1413 | hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ | 1503 | hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ |
@@ -1433,9 +1523,9 @@ static void select_input(struct v4l2_subdev *sd) | |||
1433 | cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */ | 1523 | cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */ |
1434 | cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ | 1524 | cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ |
1435 | cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ | 1525 | cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ |
1436 | break; | 1526 | } else if (is_digital_input(sd)) { |
1527 | hdmi_write(sd, 0x00, state->selected_input & 0x03); | ||
1437 | 1528 | ||
1438 | case ADV7604_MODE_HDMI: | ||
1439 | /* set ADI recommended settings for HDMI: */ | 1529 | /* set ADI recommended settings for HDMI: */ |
1440 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | 1530 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ |
1441 | hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ | 1531 | hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ |
@@ -1461,12 +1551,9 @@ static void select_input(struct v4l2_subdev *sd) | |||
1461 | cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ | 1551 | cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ |
1462 | cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ | 1552 | cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ |
1463 | cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */ | 1553 | cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */ |
1464 | 1554 | } else { | |
1465 | break; | 1555 | v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", |
1466 | default: | 1556 | __func__, state->selected_input); |
1467 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", | ||
1468 | __func__, state->mode); | ||
1469 | break; | ||
1470 | } | 1557 | } |
1471 | } | 1558 | } |
1472 | 1559 | ||
@@ -1475,9 +1562,13 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, | |||
1475 | { | 1562 | { |
1476 | struct adv7604_state *state = to_state(sd); | 1563 | struct adv7604_state *state = to_state(sd); |
1477 | 1564 | ||
1478 | v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input); | 1565 | v4l2_dbg(2, debug, sd, "%s: input %d, selected input %d", |
1566 | __func__, input, state->selected_input); | ||
1567 | |||
1568 | if (input == state->selected_input) | ||
1569 | return 0; | ||
1479 | 1570 | ||
1480 | state->mode = input; | 1571 | state->selected_input = input; |
1481 | 1572 | ||
1482 | disable_input(sd); | 1573 | disable_input(sd); |
1483 | 1574 | ||
@@ -1516,36 +1607,47 @@ static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd, | |||
1516 | 1607 | ||
1517 | static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | 1608 | static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
1518 | { | 1609 | { |
1519 | struct adv7604_state *state = to_state(sd); | 1610 | const u8 irq_reg_0x43 = io_read(sd, 0x43); |
1520 | u8 fmt_change, fmt_change_digital, tx_5v; | 1611 | const u8 irq_reg_0x6b = io_read(sd, 0x6b); |
1521 | u32 input_status; | 1612 | const u8 irq_reg_0x70 = io_read(sd, 0x70); |
1613 | u8 fmt_change_digital; | ||
1614 | u8 fmt_change; | ||
1615 | u8 tx_5v; | ||
1616 | |||
1617 | if (irq_reg_0x43) | ||
1618 | io_write(sd, 0x44, irq_reg_0x43); | ||
1619 | if (irq_reg_0x70) | ||
1620 | io_write(sd, 0x71, irq_reg_0x70); | ||
1621 | if (irq_reg_0x6b) | ||
1622 | io_write(sd, 0x6c, irq_reg_0x6b); | ||
1623 | |||
1624 | v4l2_dbg(2, debug, sd, "%s: ", __func__); | ||
1522 | 1625 | ||
1523 | /* format change */ | 1626 | /* format change */ |
1524 | fmt_change = io_read(sd, 0x43) & 0x98; | 1627 | fmt_change = irq_reg_0x43 & 0x98; |
1525 | if (fmt_change) | 1628 | fmt_change_digital = is_digital_input(sd) ? (irq_reg_0x6b & 0xc0) : 0; |
1526 | io_write(sd, 0x44, fmt_change); | 1629 | |
1527 | fmt_change_digital = DIGITAL_INPUT ? (io_read(sd, 0x6b) & 0xc0) : 0; | ||
1528 | if (fmt_change_digital) | ||
1529 | io_write(sd, 0x6c, fmt_change_digital); | ||
1530 | if (fmt_change || fmt_change_digital) { | 1630 | if (fmt_change || fmt_change_digital) { |
1531 | v4l2_dbg(1, debug, sd, | 1631 | v4l2_dbg(1, debug, sd, |
1532 | "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", | 1632 | "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", |
1533 | __func__, fmt_change, fmt_change_digital); | 1633 | __func__, fmt_change, fmt_change_digital); |
1534 | 1634 | ||
1535 | adv7604_g_input_status(sd, &input_status); | 1635 | v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL); |
1536 | if (input_status != state->prev_input_status) { | ||
1537 | v4l2_dbg(1, debug, sd, | ||
1538 | "%s: input_status = 0x%x, prev_input_status = 0x%x\n", | ||
1539 | __func__, input_status, state->prev_input_status); | ||
1540 | state->prev_input_status = input_status; | ||
1541 | v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL); | ||
1542 | } | ||
1543 | 1636 | ||
1544 | if (handled) | 1637 | if (handled) |
1545 | *handled = true; | 1638 | *handled = true; |
1546 | } | 1639 | } |
1640 | /* HDMI/DVI mode */ | ||
1641 | if (irq_reg_0x6b & 0x01) { | ||
1642 | v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__, | ||
1643 | (io_read(sd, 0x6a) & 0x01) ? "HDMI" : "DVI"); | ||
1644 | set_rgb_quantization_range(sd); | ||
1645 | if (handled) | ||
1646 | *handled = true; | ||
1647 | } | ||
1648 | |||
1547 | /* tx 5v detect */ | 1649 | /* tx 5v detect */ |
1548 | tx_5v = io_read(sd, 0x70) & 0x10; | 1650 | tx_5v = io_read(sd, 0x70) & 0x1e; |
1549 | if (tx_5v) { | 1651 | if (tx_5v) { |
1550 | v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); | 1652 | v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); |
1551 | io_write(sd, 0x71, tx_5v); | 1653 | io_write(sd, 0x71, tx_5v); |
@@ -1559,55 +1661,178 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
1559 | static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) | 1661 | static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) |
1560 | { | 1662 | { |
1561 | struct adv7604_state *state = to_state(sd); | 1663 | struct adv7604_state *state = to_state(sd); |
1664 | u8 *data = NULL; | ||
1562 | 1665 | ||
1563 | if (edid->pad != 0) | 1666 | if (edid->pad > ADV7604_EDID_PORT_D) |
1564 | return -EINVAL; | 1667 | return -EINVAL; |
1565 | if (edid->blocks == 0) | 1668 | if (edid->blocks == 0) |
1566 | return -EINVAL; | 1669 | return -EINVAL; |
1567 | if (edid->start_block >= state->edid_blocks) | 1670 | if (edid->blocks > 2) |
1671 | return -EINVAL; | ||
1672 | if (edid->start_block > 1) | ||
1568 | return -EINVAL; | 1673 | return -EINVAL; |
1569 | if (edid->start_block + edid->blocks > state->edid_blocks) | 1674 | if (edid->start_block == 1) |
1570 | edid->blocks = state->edid_blocks - edid->start_block; | 1675 | edid->blocks = 1; |
1571 | if (!edid->edid) | 1676 | if (!edid->edid) |
1572 | return -EINVAL; | 1677 | return -EINVAL; |
1573 | memcpy(edid->edid + edid->start_block * 128, | 1678 | |
1574 | state->edid + edid->start_block * 128, | 1679 | if (edid->blocks > state->edid.blocks) |
1680 | edid->blocks = state->edid.blocks; | ||
1681 | |||
1682 | switch (edid->pad) { | ||
1683 | case ADV7604_EDID_PORT_A: | ||
1684 | case ADV7604_EDID_PORT_B: | ||
1685 | case ADV7604_EDID_PORT_C: | ||
1686 | case ADV7604_EDID_PORT_D: | ||
1687 | if (state->edid.present & (1 << edid->pad)) | ||
1688 | data = state->edid.edid; | ||
1689 | break; | ||
1690 | default: | ||
1691 | return -EINVAL; | ||
1692 | break; | ||
1693 | } | ||
1694 | if (!data) | ||
1695 | return -ENODATA; | ||
1696 | |||
1697 | memcpy(edid->edid, | ||
1698 | data + edid->start_block * 128, | ||
1575 | edid->blocks * 128); | 1699 | edid->blocks * 128); |
1576 | return 0; | 1700 | return 0; |
1577 | } | 1701 | } |
1578 | 1702 | ||
1703 | static int get_edid_spa_location(const u8 *edid) | ||
1704 | { | ||
1705 | u8 d; | ||
1706 | |||
1707 | if ((edid[0x7e] != 1) || | ||
1708 | (edid[0x80] != 0x02) || | ||
1709 | (edid[0x81] != 0x03)) { | ||
1710 | return -1; | ||
1711 | } | ||
1712 | |||
1713 | /* search Vendor Specific Data Block (tag 3) */ | ||
1714 | d = edid[0x82] & 0x7f; | ||
1715 | if (d > 4) { | ||
1716 | int i = 0x84; | ||
1717 | int end = 0x80 + d; | ||
1718 | |||
1719 | do { | ||
1720 | u8 tag = edid[i] >> 5; | ||
1721 | u8 len = edid[i] & 0x1f; | ||
1722 | |||
1723 | if ((tag == 3) && (len >= 5)) | ||
1724 | return i + 4; | ||
1725 | i += len + 1; | ||
1726 | } while (i < end); | ||
1727 | } | ||
1728 | return -1; | ||
1729 | } | ||
1730 | |||
1579 | static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) | 1731 | static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) |
1580 | { | 1732 | { |
1581 | struct adv7604_state *state = to_state(sd); | 1733 | struct adv7604_state *state = to_state(sd); |
1734 | int spa_loc; | ||
1735 | int tmp = 0; | ||
1582 | int err; | 1736 | int err; |
1737 | int i; | ||
1583 | 1738 | ||
1584 | if (edid->pad != 0) | 1739 | if (edid->pad > ADV7604_EDID_PORT_D) |
1585 | return -EINVAL; | 1740 | return -EINVAL; |
1586 | if (edid->start_block != 0) | 1741 | if (edid->start_block != 0) |
1587 | return -EINVAL; | 1742 | return -EINVAL; |
1588 | if (edid->blocks == 0) { | 1743 | if (edid->blocks == 0) { |
1589 | /* Pull down the hotplug pin */ | 1744 | /* Disable hotplug and I2C access to EDID RAM from DDC port */ |
1590 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0); | 1745 | state->edid.present &= ~(1 << edid->pad); |
1591 | /* Disables I2C access to internal EDID ram from DDC port */ | 1746 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); |
1592 | rep_write_and_or(sd, 0x77, 0xf0, 0x0); | 1747 | rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); |
1593 | state->edid_blocks = 0; | 1748 | |
1594 | /* Fall back to a 16:9 aspect ratio */ | 1749 | /* Fall back to a 16:9 aspect ratio */ |
1595 | state->aspect_ratio.numerator = 16; | 1750 | state->aspect_ratio.numerator = 16; |
1596 | state->aspect_ratio.denominator = 9; | 1751 | state->aspect_ratio.denominator = 9; |
1752 | |||
1753 | if (!state->edid.present) | ||
1754 | state->edid.blocks = 0; | ||
1755 | |||
1756 | v4l2_dbg(2, debug, sd, "%s: clear EDID pad %d, edid.present = 0x%x\n", | ||
1757 | __func__, edid->pad, state->edid.present); | ||
1597 | return 0; | 1758 | return 0; |
1598 | } | 1759 | } |
1599 | if (edid->blocks > 2) | 1760 | if (edid->blocks > 2) { |
1761 | edid->blocks = 2; | ||
1600 | return -E2BIG; | 1762 | return -E2BIG; |
1763 | } | ||
1601 | if (!edid->edid) | 1764 | if (!edid->edid) |
1602 | return -EINVAL; | 1765 | return -EINVAL; |
1603 | memcpy(state->edid, edid->edid, 128 * edid->blocks); | 1766 | |
1604 | state->edid_blocks = edid->blocks; | 1767 | v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", |
1768 | __func__, edid->pad, state->edid.present); | ||
1769 | |||
1770 | /* Disable hotplug and I2C access to EDID RAM from DDC port */ | ||
1771 | cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); | ||
1772 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp); | ||
1773 | rep_write_and_or(sd, 0x77, 0xf0, 0x00); | ||
1774 | |||
1775 | spa_loc = get_edid_spa_location(edid->edid); | ||
1776 | if (spa_loc < 0) | ||
1777 | spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ | ||
1778 | |||
1779 | switch (edid->pad) { | ||
1780 | case ADV7604_EDID_PORT_A: | ||
1781 | state->spa_port_a[0] = edid->edid[spa_loc]; | ||
1782 | state->spa_port_a[1] = edid->edid[spa_loc + 1]; | ||
1783 | break; | ||
1784 | case ADV7604_EDID_PORT_B: | ||
1785 | rep_write(sd, 0x70, edid->edid[spa_loc]); | ||
1786 | rep_write(sd, 0x71, edid->edid[spa_loc + 1]); | ||
1787 | break; | ||
1788 | case ADV7604_EDID_PORT_C: | ||
1789 | rep_write(sd, 0x72, edid->edid[spa_loc]); | ||
1790 | rep_write(sd, 0x73, edid->edid[spa_loc + 1]); | ||
1791 | break; | ||
1792 | case ADV7604_EDID_PORT_D: | ||
1793 | rep_write(sd, 0x74, edid->edid[spa_loc]); | ||
1794 | rep_write(sd, 0x75, edid->edid[spa_loc + 1]); | ||
1795 | break; | ||
1796 | default: | ||
1797 | return -EINVAL; | ||
1798 | } | ||
1799 | rep_write(sd, 0x76, spa_loc & 0xff); | ||
1800 | rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); | ||
1801 | |||
1802 | edid->edid[spa_loc] = state->spa_port_a[0]; | ||
1803 | edid->edid[spa_loc + 1] = state->spa_port_a[1]; | ||
1804 | |||
1805 | memcpy(state->edid.edid, edid->edid, 128 * edid->blocks); | ||
1806 | state->edid.blocks = edid->blocks; | ||
1605 | state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15], | 1807 | state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15], |
1606 | edid->edid[0x16]); | 1808 | edid->edid[0x16]); |
1607 | err = edid_write_block(sd, 128 * edid->blocks, state->edid); | 1809 | state->edid.present |= 1 << edid->pad; |
1608 | if (err < 0) | 1810 | |
1609 | v4l2_err(sd, "error %d writing edid\n", err); | 1811 | err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid); |
1610 | return err; | 1812 | if (err < 0) { |
1813 | v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad); | ||
1814 | return err; | ||
1815 | } | ||
1816 | |||
1817 | /* adv7604 calculates the checksums and enables I2C access to internal | ||
1818 | EDID RAM from DDC port. */ | ||
1819 | rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); | ||
1820 | |||
1821 | for (i = 0; i < 1000; i++) { | ||
1822 | if (rep_read(sd, 0x7d) & state->edid.present) | ||
1823 | break; | ||
1824 | mdelay(1); | ||
1825 | } | ||
1826 | if (i == 1000) { | ||
1827 | v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present); | ||
1828 | return -EIO; | ||
1829 | } | ||
1830 | |||
1831 | |||
1832 | /* enable hotplug after 100 ms */ | ||
1833 | queue_delayed_work(state->work_queues, | ||
1834 | &state->delayed_work_enable_hotplug, HZ / 10); | ||
1835 | return 0; | ||
1611 | } | 1836 | } |
1612 | 1837 | ||
1613 | /*********** avi info frame CEA-861-E **************/ | 1838 | /*********** avi info frame CEA-861-E **************/ |
@@ -1670,7 +1895,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd) | |||
1670 | char *input_color_space_txt[16] = { | 1895 | char *input_color_space_txt[16] = { |
1671 | "RGB limited range (16-235)", "RGB full range (0-255)", | 1896 | "RGB limited range (16-235)", "RGB full range (0-255)", |
1672 | "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", | 1897 | "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", |
1673 | "XvYCC Bt.601", "XvYCC Bt.709", | 1898 | "xvYCC Bt.601", "xvYCC Bt.709", |
1674 | "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", | 1899 | "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", |
1675 | "invalid", "invalid", "invalid", "invalid", "invalid", | 1900 | "invalid", "invalid", "invalid", "invalid", "invalid", |
1676 | "invalid", "invalid", "automatic" | 1901 | "invalid", "invalid", "automatic" |
@@ -1689,16 +1914,20 @@ static int adv7604_log_status(struct v4l2_subdev *sd) | |||
1689 | 1914 | ||
1690 | v4l2_info(sd, "-----Chip status-----\n"); | 1915 | v4l2_info(sd, "-----Chip status-----\n"); |
1691 | v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); | 1916 | v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); |
1692 | v4l2_info(sd, "Connector type: %s\n", state->connector_hdmi ? | 1917 | v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n", |
1693 | "HDMI" : (DIGITAL_INPUT ? "DVI-D" : "DVI-A")); | 1918 | ((rep_read(sd, 0x7d) & 0x01) ? "Yes" : "No"), |
1694 | v4l2_info(sd, "EDID: %s\n", ((rep_read(sd, 0x7d) & 0x01) && | 1919 | ((rep_read(sd, 0x7d) & 0x02) ? "Yes" : "No"), |
1695 | (rep_read(sd, 0x77) & 0x01)) ? "enabled" : "disabled "); | 1920 | ((rep_read(sd, 0x7d) & 0x04) ? "Yes" : "No"), |
1921 | ((rep_read(sd, 0x7d) & 0x08) ? "Yes" : "No")); | ||
1696 | v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? | 1922 | v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? |
1697 | "enabled" : "disabled"); | 1923 | "enabled" : "disabled"); |
1698 | 1924 | ||
1699 | v4l2_info(sd, "-----Signal status-----\n"); | 1925 | v4l2_info(sd, "-----Signal status-----\n"); |
1700 | v4l2_info(sd, "Cable detected (+5V power): %s\n", | 1926 | v4l2_info(sd, "Cable detected (+5V power) port A: %s, B: %s, C: %s, D: %s\n", |
1701 | (io_read(sd, 0x6f) & 0x10) ? "true" : "false"); | 1927 | ((io_read(sd, 0x6f) & 0x10) ? "Yes" : "No"), |
1928 | ((io_read(sd, 0x6f) & 0x08) ? "Yes" : "No"), | ||
1929 | ((io_read(sd, 0x6f) & 0x04) ? "Yes" : "No"), | ||
1930 | ((io_read(sd, 0x6f) & 0x02) ? "Yes" : "No")); | ||
1702 | v4l2_info(sd, "TMDS signal detected: %s\n", | 1931 | v4l2_info(sd, "TMDS signal detected: %s\n", |
1703 | no_signal_tmds(sd) ? "false" : "true"); | 1932 | no_signal_tmds(sd) ? "false" : "true"); |
1704 | v4l2_info(sd, "TMDS signal locked: %s\n", | 1933 | v4l2_info(sd, "TMDS signal locked: %s\n", |
@@ -1744,11 +1973,14 @@ static int adv7604_log_status(struct v4l2_subdev *sd) | |||
1744 | v4l2_info(sd, "Color space conversion: %s\n", | 1973 | v4l2_info(sd, "Color space conversion: %s\n", |
1745 | csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]); | 1974 | csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]); |
1746 | 1975 | ||
1747 | if (!DIGITAL_INPUT) | 1976 | if (!is_digital_input(sd)) |
1748 | return 0; | 1977 | return 0; |
1749 | 1978 | ||
1750 | v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); | 1979 | v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); |
1751 | v4l2_info(sd, "HDCP encrypted content: %s\n", (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false"); | 1980 | v4l2_info(sd, "Digital video port selected: %c\n", |
1981 | (hdmi_read(sd, 0x00) & 0x03) + 'A'); | ||
1982 | v4l2_info(sd, "HDCP encrypted content: %s\n", | ||
1983 | (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false"); | ||
1752 | v4l2_info(sd, "HDCP keys read: %s%s\n", | 1984 | v4l2_info(sd, "HDCP keys read: %s%s\n", |
1753 | (hdmi_read(sd, 0x04) & 0x20) ? "yes" : "no", | 1985 | (hdmi_read(sd, 0x04) & 0x20) ? "yes" : "no", |
1754 | (hdmi_read(sd, 0x04) & 0x10) ? "ERROR" : ""); | 1986 | (hdmi_read(sd, 0x04) & 0x10) ? "ERROR" : ""); |
@@ -1894,10 +2126,16 @@ static int adv7604_core_init(struct v4l2_subdev *sd) | |||
1894 | pdata->replicate_av_codes << 1 | | 2126 | pdata->replicate_av_codes << 1 | |
1895 | pdata->invert_cbcr << 0); | 2127 | pdata->invert_cbcr << 0); |
1896 | 2128 | ||
1897 | /* TODO from platform data */ | ||
1898 | cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ | 2129 | cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ |
1899 | io_write(sd, 0x06, 0xa6); /* positive VS and HS */ | 2130 | |
1900 | io_write(sd, 0x14, 0x7f); /* Drive strength adjusted to max */ | 2131 | /* VS, HS polarities */ |
2132 | io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | pdata->inv_hs_pol << 1); | ||
2133 | |||
2134 | /* Adjust drive strength */ | ||
2135 | io_write(sd, 0x14, 0x40 | pdata->dr_str_data << 4 | | ||
2136 | pdata->dr_str_clk << 2 | | ||
2137 | pdata->dr_str_sync); | ||
2138 | |||
1901 | cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */ | 2139 | cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */ |
1902 | cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ | 2140 | cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ |
1903 | cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold - | 2141 | cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold - |
@@ -1907,6 +2145,11 @@ static int adv7604_core_init(struct v4l2_subdev *sd) | |||
1907 | cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution | 2145 | cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution |
1908 | for digital formats */ | 2146 | for digital formats */ |
1909 | 2147 | ||
2148 | /* HDMI audio */ | ||
2149 | hdmi_write_and_or(sd, 0x15, 0xfc, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */ | ||
2150 | hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ | ||
2151 | hdmi_write_and_or(sd, 0x68, 0xf9, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */ | ||
2152 | |||
1910 | /* TODO from platform data */ | 2153 | /* TODO from platform data */ |
1911 | afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ | 2154 | afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ |
1912 | 2155 | ||
@@ -1917,8 +2160,8 @@ static int adv7604_core_init(struct v4l2_subdev *sd) | |||
1917 | io_write(sd, 0x40, 0xc2); /* Configure INT1 */ | 2160 | io_write(sd, 0x40, 0xc2); /* Configure INT1 */ |
1918 | io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ | 2161 | io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ |
1919 | io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */ | 2162 | io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */ |
1920 | io_write(sd, 0x6e, 0xc0); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */ | 2163 | io_write(sd, 0x6e, 0xc1); /* Enable V_LOCKED, DE_REGEN_LCK, HDMI_MODE interrupts */ |
1921 | io_write(sd, 0x73, 0x10); /* Enable CABLE_DET_A_ST (+5v) interrupt */ | 2164 | io_write(sd, 0x73, 0x1e); /* Enable CABLE_DET_A_ST (+5v) interrupts */ |
1922 | 2165 | ||
1923 | return v4l2_ctrl_handler_setup(sd->ctrl_handler); | 2166 | return v4l2_ctrl_handler_setup(sd->ctrl_handler); |
1924 | } | 2167 | } |
@@ -1964,6 +2207,8 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, | |||
1964 | static int adv7604_probe(struct i2c_client *client, | 2207 | static int adv7604_probe(struct i2c_client *client, |
1965 | const struct i2c_device_id *id) | 2208 | const struct i2c_device_id *id) |
1966 | { | 2209 | { |
2210 | static const struct v4l2_dv_timings cea640x480 = | ||
2211 | V4L2_DV_BT_CEA_640X480P59_94; | ||
1967 | struct adv7604_state *state; | 2212 | struct adv7604_state *state; |
1968 | struct adv7604_platform_data *pdata = client->dev.platform_data; | 2213 | struct adv7604_platform_data *pdata = client->dev.platform_data; |
1969 | struct v4l2_ctrl_handler *hdl; | 2214 | struct v4l2_ctrl_handler *hdl; |
@@ -1984,19 +2229,19 @@ static int adv7604_probe(struct i2c_client *client, | |||
1984 | 2229 | ||
1985 | /* initialize variables */ | 2230 | /* initialize variables */ |
1986 | state->restart_stdi_once = true; | 2231 | state->restart_stdi_once = true; |
1987 | state->prev_input_status = ~0; | 2232 | state->selected_input = ~0; |
1988 | 2233 | ||
1989 | /* platform data */ | 2234 | /* platform data */ |
1990 | if (!pdata) { | 2235 | if (!pdata) { |
1991 | v4l_err(client, "No platform data!\n"); | 2236 | v4l_err(client, "No platform data!\n"); |
1992 | return -ENODEV; | 2237 | return -ENODEV; |
1993 | } | 2238 | } |
1994 | memcpy(&state->pdata, pdata, sizeof(state->pdata)); | 2239 | state->pdata = *pdata; |
2240 | state->timings = cea640x480; | ||
1995 | 2241 | ||
1996 | sd = &state->sd; | 2242 | sd = &state->sd; |
1997 | v4l2_i2c_subdev_init(sd, client, &adv7604_ops); | 2243 | v4l2_i2c_subdev_init(sd, client, &adv7604_ops); |
1998 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 2244 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1999 | state->connector_hdmi = pdata->connector_hdmi; | ||
2000 | 2245 | ||
2001 | /* i2c access to adv7604? */ | 2246 | /* i2c access to adv7604? */ |
2002 | if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) { | 2247 | if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) { |
@@ -2020,7 +2265,7 @@ static int adv7604_probe(struct i2c_client *client, | |||
2020 | 2265 | ||
2021 | /* private controls */ | 2266 | /* private controls */ |
2022 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, | 2267 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, |
2023 | V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); | 2268 | V4L2_CID_DV_RX_POWER_PRESENT, 0, 0x0f, 0, 0); |
2024 | state->rgb_quantization_range_ctrl = | 2269 | state->rgb_quantization_range_ctrl = |
2025 | v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, | 2270 | v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, |
2026 | V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, | 2271 | V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, |
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index b154f36740b4..1effc21e1cdd 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c | |||
@@ -20,10 +20,13 @@ | |||
20 | 20 | ||
21 | /* | 21 | /* |
22 | * References (c = chapter, p = page): | 22 | * References (c = chapter, p = page): |
23 | * REF_01 - Analog devices, ADV7842, Register Settings Recommendations, | 23 | * REF_01 - Analog devices, ADV7842, |
24 | * Revision 2.5, June 2010 | 24 | * Register Settings Recommendations, Rev. 1.9, April 2011 |
25 | * REF_02 - Analog devices, Register map documentation, Documentation of | 25 | * REF_02 - Analog devices, Software User Guide, UG-206, |
26 | * the register maps, Software manual, Rev. F, June 2010 | 26 | * ADV7842 I2C Register Maps, Rev. 0, November 2010 |
27 | * REF_03 - Analog devices, Hardware User Guide, UG-214, | ||
28 | * ADV7842 Fast Switching 2:1 HDMI 1.4 Receiver with 3D-Comb | ||
29 | * Decoder and Digitizer , Rev. 0, January 2011 | ||
27 | */ | 30 | */ |
28 | 31 | ||
29 | 32 | ||
@@ -61,6 +64,7 @@ MODULE_LICENSE("GPL"); | |||
61 | */ | 64 | */ |
62 | 65 | ||
63 | struct adv7842_state { | 66 | struct adv7842_state { |
67 | struct adv7842_platform_data pdata; | ||
64 | struct v4l2_subdev sd; | 68 | struct v4l2_subdev sd; |
65 | struct media_pad pad; | 69 | struct media_pad pad; |
66 | struct v4l2_ctrl_handler hdl; | 70 | struct v4l2_ctrl_handler hdl; |
@@ -81,7 +85,7 @@ struct adv7842_state { | |||
81 | bool is_cea_format; | 85 | bool is_cea_format; |
82 | struct workqueue_struct *work_queues; | 86 | struct workqueue_struct *work_queues; |
83 | struct delayed_work delayed_work_enable_hotplug; | 87 | struct delayed_work delayed_work_enable_hotplug; |
84 | bool connector_hdmi; | 88 | bool restart_stdi_once; |
85 | bool hdmi_port_a; | 89 | bool hdmi_port_a; |
86 | 90 | ||
87 | /* i2c clients */ | 91 | /* i2c clients */ |
@@ -491,6 +495,11 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) | |||
491 | return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); | 495 | return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); |
492 | } | 496 | } |
493 | 497 | ||
498 | static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | ||
499 | { | ||
500 | return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val); | ||
501 | } | ||
502 | |||
494 | static inline int cp_read(struct v4l2_subdev *sd, u8 reg) | 503 | static inline int cp_read(struct v4l2_subdev *sd, u8 reg) |
495 | { | 504 | { |
496 | struct adv7842_state *state = to_state(sd); | 505 | struct adv7842_state *state = to_state(sd); |
@@ -532,7 +541,7 @@ static void main_reset(struct v4l2_subdev *sd) | |||
532 | 541 | ||
533 | adv_smbus_write_byte_no_check(client, 0xff, 0x80); | 542 | adv_smbus_write_byte_no_check(client, 0xff, 0x80); |
534 | 543 | ||
535 | mdelay(2); | 544 | mdelay(5); |
536 | } | 545 | } |
537 | 546 | ||
538 | /* ----------------------------------------------------------------------- */ | 547 | /* ----------------------------------------------------------------------- */ |
@@ -587,10 +596,10 @@ static void adv7842_delayed_work_enable_hotplug(struct work_struct *work) | |||
587 | v4l2_dbg(2, debug, sd, "%s: enable hotplug on ports: 0x%x\n", | 596 | v4l2_dbg(2, debug, sd, "%s: enable hotplug on ports: 0x%x\n", |
588 | __func__, present); | 597 | __func__, present); |
589 | 598 | ||
590 | if (present & 0x1) | 599 | if (present & (0x04 << ADV7842_EDID_PORT_A)) |
591 | mask |= 0x20; /* port A */ | 600 | mask |= 0x20; |
592 | if (present & 0x2) | 601 | if (present & (0x04 << ADV7842_EDID_PORT_B)) |
593 | mask |= 0x10; /* port B */ | 602 | mask |= 0x10; |
594 | io_write_and_or(sd, 0x20, 0xcf, mask); | 603 | io_write_and_or(sd, 0x20, 0xcf, mask); |
595 | } | 604 | } |
596 | 605 | ||
@@ -679,14 +688,12 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) | |||
679 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 688 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
680 | struct adv7842_state *state = to_state(sd); | 689 | struct adv7842_state *state = to_state(sd); |
681 | const u8 *val = state->hdmi_edid.edid; | 690 | const u8 *val = state->hdmi_edid.edid; |
682 | u8 cur_mask = rep_read(sd, 0x77) & 0x0c; | ||
683 | u8 mask = port == 0 ? 0x4 : 0x8; | ||
684 | int spa_loc = edid_spa_location(val); | 691 | int spa_loc = edid_spa_location(val); |
685 | int err = 0; | 692 | int err = 0; |
686 | int i; | 693 | int i; |
687 | 694 | ||
688 | v4l2_dbg(2, debug, sd, "%s: write EDID on port %d (spa at 0x%x)\n", | 695 | v4l2_dbg(2, debug, sd, "%s: write EDID on port %c (spa at 0x%x)\n", |
689 | __func__, port, spa_loc); | 696 | __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B', spa_loc); |
690 | 697 | ||
691 | /* HPA disable on port A and B */ | 698 | /* HPA disable on port A and B */ |
692 | io_write_and_or(sd, 0x20, 0xcf, 0x00); | 699 | io_write_and_or(sd, 0x20, 0xcf, 0x00); |
@@ -694,6 +701,9 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) | |||
694 | /* Disable I2C access to internal EDID ram from HDMI DDC ports */ | 701 | /* Disable I2C access to internal EDID ram from HDMI DDC ports */ |
695 | rep_write_and_or(sd, 0x77, 0xf3, 0x00); | 702 | rep_write_and_or(sd, 0x77, 0xf3, 0x00); |
696 | 703 | ||
704 | if (!state->hdmi_edid.present) | ||
705 | return 0; | ||
706 | |||
697 | /* edid segment pointer '0' for HDMI ports */ | 707 | /* edid segment pointer '0' for HDMI ports */ |
698 | rep_write_and_or(sd, 0x77, 0xef, 0x00); | 708 | rep_write_and_or(sd, 0x77, 0xef, 0x00); |
699 | 709 | ||
@@ -703,44 +713,32 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) | |||
703 | if (err) | 713 | if (err) |
704 | return err; | 714 | return err; |
705 | 715 | ||
706 | if (spa_loc > 0) { | 716 | if (spa_loc < 0) |
707 | if (port == 0) { | 717 | spa_loc = 0xc0; /* Default value [REF_02, p. 199] */ |
708 | /* port A SPA */ | 718 | |
709 | rep_write(sd, 0x72, val[spa_loc]); | 719 | if (port == ADV7842_EDID_PORT_A) { |
710 | rep_write(sd, 0x73, val[spa_loc + 1]); | 720 | rep_write(sd, 0x72, val[spa_loc]); |
711 | } else { | 721 | rep_write(sd, 0x73, val[spa_loc + 1]); |
712 | /* port B SPA */ | ||
713 | rep_write(sd, 0x74, val[spa_loc]); | ||
714 | rep_write(sd, 0x75, val[spa_loc + 1]); | ||
715 | } | ||
716 | rep_write(sd, 0x76, spa_loc); | ||
717 | } else { | 722 | } else { |
718 | /* default register values for SPA */ | 723 | rep_write(sd, 0x74, val[spa_loc]); |
719 | if (port == 0) { | 724 | rep_write(sd, 0x75, val[spa_loc + 1]); |
720 | /* port A SPA */ | ||
721 | rep_write(sd, 0x72, 0); | ||
722 | rep_write(sd, 0x73, 0); | ||
723 | } else { | ||
724 | /* port B SPA */ | ||
725 | rep_write(sd, 0x74, 0); | ||
726 | rep_write(sd, 0x75, 0); | ||
727 | } | ||
728 | rep_write(sd, 0x76, 0xc0); | ||
729 | } | 725 | } |
730 | rep_write_and_or(sd, 0x77, 0xbf, 0x00); | 726 | rep_write(sd, 0x76, spa_loc & 0xff); |
727 | rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); | ||
731 | 728 | ||
732 | /* Calculates the checksums and enables I2C access to internal | 729 | /* Calculates the checksums and enables I2C access to internal |
733 | * EDID ram from HDMI DDC ports | 730 | * EDID ram from HDMI DDC ports |
734 | */ | 731 | */ |
735 | rep_write_and_or(sd, 0x77, 0xf3, mask | cur_mask); | 732 | rep_write_and_or(sd, 0x77, 0xf3, state->hdmi_edid.present); |
736 | 733 | ||
737 | for (i = 0; i < 1000; i++) { | 734 | for (i = 0; i < 1000; i++) { |
738 | if (rep_read(sd, 0x7d) & mask) | 735 | if (rep_read(sd, 0x7d) & state->hdmi_edid.present) |
739 | break; | 736 | break; |
740 | mdelay(1); | 737 | mdelay(1); |
741 | } | 738 | } |
742 | if (i == 1000) { | 739 | if (i == 1000) { |
743 | v4l_err(client, "error enabling edid on port %d\n", port); | 740 | v4l_err(client, "error enabling edid on port %c\n", |
741 | (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); | ||
744 | return -EIO; | 742 | return -EIO; |
745 | } | 743 | } |
746 | 744 | ||
@@ -927,7 +925,7 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, | |||
927 | cp_write(sd, 0x27, 0x00); | 925 | cp_write(sd, 0x27, 0x00); |
928 | cp_write(sd, 0x28, 0x00); | 926 | cp_write(sd, 0x28, 0x00); |
929 | cp_write(sd, 0x29, 0x00); | 927 | cp_write(sd, 0x29, 0x00); |
930 | cp_write(sd, 0x8f, 0x00); | 928 | cp_write(sd, 0x8f, 0x40); |
931 | cp_write(sd, 0x90, 0x00); | 929 | cp_write(sd, 0x90, 0x00); |
932 | cp_write(sd, 0xa5, 0x00); | 930 | cp_write(sd, 0xa5, 0x00); |
933 | cp_write(sd, 0xa6, 0x00); | 931 | cp_write(sd, 0xa6, 0x00); |
@@ -1033,34 +1031,60 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) | |||
1033 | { | 1031 | { |
1034 | struct adv7842_state *state = to_state(sd); | 1032 | struct adv7842_state *state = to_state(sd); |
1035 | 1033 | ||
1034 | v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n", | ||
1035 | __func__, state->rgb_quantization_range); | ||
1036 | |||
1036 | switch (state->rgb_quantization_range) { | 1037 | switch (state->rgb_quantization_range) { |
1037 | case V4L2_DV_RGB_RANGE_AUTO: | 1038 | case V4L2_DV_RGB_RANGE_AUTO: |
1038 | /* automatic */ | 1039 | if (state->mode == ADV7842_MODE_RGB) { |
1039 | if (is_digital_input(sd) && !(hdmi_read(sd, 0x05) & 0x80)) { | 1040 | /* Receiving analog RGB signal |
1040 | /* receiving DVI-D signal */ | 1041 | * Set RGB full range (0-255) */ |
1041 | 1042 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | |
1042 | /* ADV7842 selects RGB limited range regardless of | 1043 | break; |
1043 | input format (CE/IT) in automatic mode */ | 1044 | } |
1044 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { | 1045 | |
1045 | /* RGB limited range (16-235) */ | 1046 | if (state->mode == ADV7842_MODE_COMP) { |
1046 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | 1047 | /* Receiving analog YPbPr signal |
1047 | 1048 | * Set automode */ | |
1048 | } else { | ||
1049 | /* RGB full range (0-255) */ | ||
1050 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | ||
1051 | } | ||
1052 | } else { | ||
1053 | /* receiving HDMI or analog signal, set automode */ | ||
1054 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | 1049 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); |
1050 | break; | ||
1051 | } | ||
1052 | |||
1053 | if (hdmi_read(sd, 0x05) & 0x80) { | ||
1054 | /* Receiving HDMI signal | ||
1055 | * Set automode */ | ||
1056 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | ||
1057 | break; | ||
1058 | } | ||
1059 | |||
1060 | /* Receiving DVI-D signal | ||
1061 | * ADV7842 selects RGB limited range regardless of | ||
1062 | * input format (CE/IT) in automatic mode */ | ||
1063 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { | ||
1064 | /* RGB limited range (16-235) */ | ||
1065 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | ||
1066 | } else { | ||
1067 | /* RGB full range (0-255) */ | ||
1068 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | ||
1055 | } | 1069 | } |
1056 | break; | 1070 | break; |
1057 | case V4L2_DV_RGB_RANGE_LIMITED: | 1071 | case V4L2_DV_RGB_RANGE_LIMITED: |
1058 | /* RGB limited range (16-235) */ | 1072 | if (state->mode == ADV7842_MODE_COMP) { |
1059 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | 1073 | /* YCrCb limited range (16-235) */ |
1074 | io_write_and_or(sd, 0x02, 0x0f, 0x20); | ||
1075 | } else { | ||
1076 | /* RGB limited range (16-235) */ | ||
1077 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | ||
1078 | } | ||
1060 | break; | 1079 | break; |
1061 | case V4L2_DV_RGB_RANGE_FULL: | 1080 | case V4L2_DV_RGB_RANGE_FULL: |
1062 | /* RGB full range (0-255) */ | 1081 | if (state->mode == ADV7842_MODE_COMP) { |
1063 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 1082 | /* YCrCb full range (0-255) */ |
1083 | io_write_and_or(sd, 0x02, 0x0f, 0x60); | ||
1084 | } else { | ||
1085 | /* RGB full range (0-255) */ | ||
1086 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | ||
1087 | } | ||
1064 | break; | 1088 | break; |
1065 | } | 1089 | } |
1066 | } | 1090 | } |
@@ -1298,7 +1322,7 @@ static int adv7842_dv_timings_cap(struct v4l2_subdev *sd, | |||
1298 | } | 1322 | } |
1299 | 1323 | ||
1300 | /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings | 1324 | /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings |
1301 | if the format is listed in adv7604_timings[] */ | 1325 | if the format is listed in adv7842_timings[] */ |
1302 | static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, | 1326 | static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, |
1303 | struct v4l2_dv_timings *timings) | 1327 | struct v4l2_dv_timings *timings) |
1304 | { | 1328 | { |
@@ -1314,119 +1338,106 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, | |||
1314 | struct v4l2_bt_timings *bt = &timings->bt; | 1338 | struct v4l2_bt_timings *bt = &timings->bt; |
1315 | struct stdi_readback stdi = { 0 }; | 1339 | struct stdi_readback stdi = { 0 }; |
1316 | 1340 | ||
1341 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); | ||
1342 | |||
1317 | /* SDP block */ | 1343 | /* SDP block */ |
1318 | if (state->mode == ADV7842_MODE_SDP) | 1344 | if (state->mode == ADV7842_MODE_SDP) |
1319 | return -ENODATA; | 1345 | return -ENODATA; |
1320 | 1346 | ||
1321 | /* read STDI */ | 1347 | /* read STDI */ |
1322 | if (read_stdi(sd, &stdi)) { | 1348 | if (read_stdi(sd, &stdi)) { |
1349 | state->restart_stdi_once = true; | ||
1323 | v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); | 1350 | v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); |
1324 | return -ENOLINK; | 1351 | return -ENOLINK; |
1325 | } | 1352 | } |
1326 | bt->interlaced = stdi.interlaced ? | 1353 | bt->interlaced = stdi.interlaced ? |
1327 | V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; | 1354 | V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; |
1328 | bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | | ||
1329 | ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); | ||
1330 | bt->vsync = stdi.lcvs; | ||
1331 | 1355 | ||
1332 | if (is_digital_input(sd)) { | 1356 | if (is_digital_input(sd)) { |
1333 | bool lock = hdmi_read(sd, 0x04) & 0x02; | 1357 | uint32_t freq; |
1334 | bool interlaced = hdmi_read(sd, 0x0b) & 0x20; | ||
1335 | unsigned w = (hdmi_read(sd, 0x07) & 0x1f) * 256 + hdmi_read(sd, 0x08); | ||
1336 | unsigned h = (hdmi_read(sd, 0x09) & 0x1f) * 256 + hdmi_read(sd, 0x0a); | ||
1337 | unsigned w_total = (hdmi_read(sd, 0x1e) & 0x3f) * 256 + | ||
1338 | hdmi_read(sd, 0x1f); | ||
1339 | unsigned h_total = ((hdmi_read(sd, 0x26) & 0x3f) * 256 + | ||
1340 | hdmi_read(sd, 0x27)) / 2; | ||
1341 | unsigned freq = (((hdmi_read(sd, 0x51) << 1) + | ||
1342 | (hdmi_read(sd, 0x52) >> 7)) * 1000000) + | ||
1343 | ((hdmi_read(sd, 0x52) & 0x7f) * 1000000) / 128; | ||
1344 | int i; | ||
1345 | 1358 | ||
1346 | if (is_hdmi(sd)) { | 1359 | timings->type = V4L2_DV_BT_656_1120; |
1347 | /* adjust for deep color mode */ | ||
1348 | freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0)>>6) * 2 + 8); | ||
1349 | } | ||
1350 | |||
1351 | /* No lock? */ | ||
1352 | if (!lock) { | ||
1353 | v4l2_dbg(1, debug, sd, "%s: no lock on TMDS signal\n", __func__); | ||
1354 | return -ENOLCK; | ||
1355 | } | ||
1356 | /* Interlaced? */ | ||
1357 | if (interlaced) { | ||
1358 | v4l2_dbg(1, debug, sd, "%s: interlaced video not supported\n", __func__); | ||
1359 | return -ERANGE; | ||
1360 | } | ||
1361 | |||
1362 | for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { | ||
1363 | const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; | ||
1364 | |||
1365 | if (!v4l2_valid_dv_timings(&v4l2_dv_timings_presets[i], | ||
1366 | adv7842_get_dv_timings_cap(sd), | ||
1367 | adv7842_check_dv_timings, NULL)) | ||
1368 | continue; | ||
1369 | if (w_total != htotal(bt) || h_total != vtotal(bt)) | ||
1370 | continue; | ||
1371 | 1360 | ||
1372 | if (w != bt->width || h != bt->height) | 1361 | bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08); |
1373 | continue; | 1362 | bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a); |
1363 | freq = (hdmi_read(sd, 0x06) * 1000000) + | ||
1364 | ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000; | ||
1374 | 1365 | ||
1375 | if (abs(freq - bt->pixelclock) > 1000000) | 1366 | if (is_hdmi(sd)) { |
1376 | continue; | 1367 | /* adjust for deep color mode */ |
1377 | *timings = v4l2_dv_timings_presets[i]; | 1368 | freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 5) + 8); |
1378 | return 0; | ||
1379 | } | 1369 | } |
1380 | 1370 | bt->pixelclock = freq; | |
1381 | timings->type = V4L2_DV_BT_656_1120; | 1371 | bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 + |
1382 | |||
1383 | bt->width = w; | ||
1384 | bt->height = h; | ||
1385 | bt->interlaced = (hdmi_read(sd, 0x0b) & 0x20) ? | ||
1386 | V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; | ||
1387 | bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? | ||
1388 | V4L2_DV_VSYNC_POS_POL : 0) | ((hdmi_read(sd, 0x05) & 0x20) ? | ||
1389 | V4L2_DV_HSYNC_POS_POL : 0); | ||
1390 | bt->pixelclock = (((hdmi_read(sd, 0x51) << 1) + | ||
1391 | (hdmi_read(sd, 0x52) >> 7)) * 1000000) + | ||
1392 | ((hdmi_read(sd, 0x52) & 0x7f) * 1000000) / 128; | ||
1393 | bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x1f) * 256 + | ||
1394 | hdmi_read(sd, 0x21); | 1372 | hdmi_read(sd, 0x21); |
1395 | bt->hsync = (hdmi_read(sd, 0x22) & 0x1f) * 256 + | 1373 | bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 + |
1396 | hdmi_read(sd, 0x23); | 1374 | hdmi_read(sd, 0x23); |
1397 | bt->hbackporch = (hdmi_read(sd, 0x24) & 0x1f) * 256 + | 1375 | bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 + |
1398 | hdmi_read(sd, 0x25); | 1376 | hdmi_read(sd, 0x25); |
1399 | bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x3f) * 256 + | 1377 | bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 + |
1400 | hdmi_read(sd, 0x2b)) / 2; | 1378 | hdmi_read(sd, 0x2b)) / 2; |
1401 | bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x3f) * 256 + | 1379 | bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 + |
1402 | hdmi_read(sd, 0x2d)) / 2; | 1380 | hdmi_read(sd, 0x2f)) / 2; |
1403 | bt->vsync = ((hdmi_read(sd, 0x2e) & 0x3f) * 256 + | 1381 | bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 + |
1404 | hdmi_read(sd, 0x2f)) / 2; | 1382 | hdmi_read(sd, 0x33)) / 2; |
1405 | bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x3f) * 256 + | 1383 | bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | |
1406 | hdmi_read(sd, 0x31)) / 2; | 1384 | ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); |
1407 | bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x3f) * 256 + | 1385 | if (bt->interlaced == V4L2_DV_INTERLACED) { |
1408 | hdmi_read(sd, 0x33)) / 2; | 1386 | bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 + |
1409 | bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x3f) * 256 + | 1387 | hdmi_read(sd, 0x0c); |
1410 | hdmi_read(sd, 0x35)) / 2; | 1388 | bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 + |
1411 | 1389 | hdmi_read(sd, 0x2d)) / 2; | |
1412 | bt->standards = 0; | 1390 | bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 + |
1413 | bt->flags = 0; | 1391 | hdmi_read(sd, 0x31)) / 2; |
1414 | } else { | 1392 | bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + |
1415 | /* Interlaced? */ | 1393 | hdmi_read(sd, 0x35)) / 2; |
1416 | if (stdi.interlaced) { | ||
1417 | v4l2_dbg(1, debug, sd, "%s: interlaced video not supported\n", __func__); | ||
1418 | return -ERANGE; | ||
1419 | } | 1394 | } |
1420 | 1395 | adv7842_fill_optional_dv_timings_fields(sd, timings); | |
1396 | } else { | ||
1397 | /* find format | ||
1398 | * Since LCVS values are inaccurate [REF_03, p. 339-340], | ||
1399 | * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails. | ||
1400 | */ | ||
1401 | if (!stdi2dv_timings(sd, &stdi, timings)) | ||
1402 | goto found; | ||
1403 | stdi.lcvs += 1; | ||
1404 | v4l2_dbg(1, debug, sd, "%s: lcvs + 1 = %d\n", __func__, stdi.lcvs); | ||
1405 | if (!stdi2dv_timings(sd, &stdi, timings)) | ||
1406 | goto found; | ||
1407 | stdi.lcvs -= 2; | ||
1408 | v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs); | ||
1421 | if (stdi2dv_timings(sd, &stdi, timings)) { | 1409 | if (stdi2dv_timings(sd, &stdi, timings)) { |
1410 | /* | ||
1411 | * The STDI block may measure wrong values, especially | ||
1412 | * for lcvs and lcf. If the driver can not find any | ||
1413 | * valid timing, the STDI block is restarted to measure | ||
1414 | * the video timings again. The function will return an | ||
1415 | * error, but the restart of STDI will generate a new | ||
1416 | * STDI interrupt and the format detection process will | ||
1417 | * restart. | ||
1418 | */ | ||
1419 | if (state->restart_stdi_once) { | ||
1420 | v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); | ||
1421 | /* TODO restart STDI for Sync Channel 2 */ | ||
1422 | /* enter one-shot mode */ | ||
1423 | cp_write_and_or(sd, 0x86, 0xf9, 0x00); | ||
1424 | /* trigger STDI restart */ | ||
1425 | cp_write_and_or(sd, 0x86, 0xf9, 0x04); | ||
1426 | /* reset to continuous mode */ | ||
1427 | cp_write_and_or(sd, 0x86, 0xf9, 0x02); | ||
1428 | state->restart_stdi_once = false; | ||
1429 | return -ENOLINK; | ||
1430 | } | ||
1422 | v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); | 1431 | v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); |
1423 | return -ERANGE; | 1432 | return -ERANGE; |
1424 | } | 1433 | } |
1434 | state->restart_stdi_once = true; | ||
1425 | } | 1435 | } |
1436 | found: | ||
1426 | 1437 | ||
1427 | if (debug > 1) | 1438 | if (debug > 1) |
1428 | v4l2_print_dv_timings(sd->name, "adv7842_query_dv_timings: ", | 1439 | v4l2_print_dv_timings(sd->name, "adv7842_query_dv_timings:", |
1429 | timings, true); | 1440 | timings, true); |
1430 | return 0; | 1441 | return 0; |
1431 | } | 1442 | } |
1432 | 1443 | ||
@@ -1437,9 +1448,16 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd, | |||
1437 | struct v4l2_bt_timings *bt; | 1448 | struct v4l2_bt_timings *bt; |
1438 | int err; | 1449 | int err; |
1439 | 1450 | ||
1451 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); | ||
1452 | |||
1440 | if (state->mode == ADV7842_MODE_SDP) | 1453 | if (state->mode == ADV7842_MODE_SDP) |
1441 | return -ENODATA; | 1454 | return -ENODATA; |
1442 | 1455 | ||
1456 | if (v4l2_match_dv_timings(&state->timings, timings, 0)) { | ||
1457 | v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); | ||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1443 | bt = &timings->bt; | 1461 | bt = &timings->bt; |
1444 | 1462 | ||
1445 | if (!v4l2_valid_dv_timings(timings, adv7842_get_dv_timings_cap(sd), | 1463 | if (!v4l2_valid_dv_timings(timings, adv7842_get_dv_timings_cap(sd), |
@@ -1450,7 +1468,7 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd, | |||
1450 | 1468 | ||
1451 | state->timings = *timings; | 1469 | state->timings = *timings; |
1452 | 1470 | ||
1453 | cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10); | 1471 | cp_write(sd, 0x91, bt->interlaced ? 0x40 : 0x00); |
1454 | 1472 | ||
1455 | /* Use prim_mode and vid_std when available */ | 1473 | /* Use prim_mode and vid_std when available */ |
1456 | err = configure_predefined_video_timings(sd, timings); | 1474 | err = configure_predefined_video_timings(sd, timings); |
@@ -1483,18 +1501,18 @@ static int adv7842_g_dv_timings(struct v4l2_subdev *sd, | |||
1483 | static void enable_input(struct v4l2_subdev *sd) | 1501 | static void enable_input(struct v4l2_subdev *sd) |
1484 | { | 1502 | { |
1485 | struct adv7842_state *state = to_state(sd); | 1503 | struct adv7842_state *state = to_state(sd); |
1504 | |||
1505 | set_rgb_quantization_range(sd); | ||
1486 | switch (state->mode) { | 1506 | switch (state->mode) { |
1487 | case ADV7842_MODE_SDP: | 1507 | case ADV7842_MODE_SDP: |
1488 | case ADV7842_MODE_COMP: | 1508 | case ADV7842_MODE_COMP: |
1489 | case ADV7842_MODE_RGB: | 1509 | case ADV7842_MODE_RGB: |
1490 | /* enable */ | ||
1491 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ | 1510 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ |
1492 | break; | 1511 | break; |
1493 | case ADV7842_MODE_HDMI: | 1512 | case ADV7842_MODE_HDMI: |
1494 | /* enable */ | ||
1495 | hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ | ||
1496 | hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ | 1513 | hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ |
1497 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ | 1514 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ |
1515 | hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */ | ||
1498 | break; | 1516 | break; |
1499 | default: | 1517 | default: |
1500 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", | 1518 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", |
@@ -1505,9 +1523,9 @@ static void enable_input(struct v4l2_subdev *sd) | |||
1505 | 1523 | ||
1506 | static void disable_input(struct v4l2_subdev *sd) | 1524 | static void disable_input(struct v4l2_subdev *sd) |
1507 | { | 1525 | { |
1508 | /* disable */ | 1526 | hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio [REF_01, c. 2.2.2] */ |
1527 | msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 8.29] */ | ||
1509 | io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ | 1528 | io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ |
1510 | hdmi_write(sd, 0x1a, 0x1a); /* Mute audio */ | ||
1511 | hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ | 1529 | hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ |
1512 | } | 1530 | } |
1513 | 1531 | ||
@@ -1575,9 +1593,6 @@ static void select_input(struct v4l2_subdev *sd, | |||
1575 | afe_write(sd, 0x00, 0x00); /* power up ADC */ | 1593 | afe_write(sd, 0x00, 0x00); /* power up ADC */ |
1576 | afe_write(sd, 0xc8, 0x00); /* phase control */ | 1594 | afe_write(sd, 0xc8, 0x00); /* phase control */ |
1577 | 1595 | ||
1578 | io_write(sd, 0x19, 0x83); /* LLC DLL phase */ | ||
1579 | io_write(sd, 0x33, 0x40); /* LLC DLL enable */ | ||
1580 | |||
1581 | io_write(sd, 0xdd, 0x90); /* Manual 2x output clock */ | 1596 | io_write(sd, 0xdd, 0x90); /* Manual 2x output clock */ |
1582 | /* script says register 0xde, which don't exist in manual */ | 1597 | /* script says register 0xde, which don't exist in manual */ |
1583 | 1598 | ||
@@ -1611,8 +1626,6 @@ static void select_input(struct v4l2_subdev *sd, | |||
1611 | /* deinterlacer enabled and 3D comb */ | 1626 | /* deinterlacer enabled and 3D comb */ |
1612 | sdp_write_and_or(sd, 0x12, 0xf6, 0x09); | 1627 | sdp_write_and_or(sd, 0x12, 0xf6, 0x09); |
1613 | 1628 | ||
1614 | sdp_write(sd, 0xdd, 0x08); /* free run auto */ | ||
1615 | |||
1616 | break; | 1629 | break; |
1617 | 1630 | ||
1618 | case ADV7842_MODE_COMP: | 1631 | case ADV7842_MODE_COMP: |
@@ -1627,6 +1640,13 @@ static void select_input(struct v4l2_subdev *sd, | |||
1627 | 1640 | ||
1628 | afe_write(sd, 0x00, 0x00); /* power up ADC */ | 1641 | afe_write(sd, 0x00, 0x00); /* power up ADC */ |
1629 | afe_write(sd, 0xc8, 0x00); /* phase control */ | 1642 | afe_write(sd, 0xc8, 0x00); /* phase control */ |
1643 | if (state->mode == ADV7842_MODE_COMP) { | ||
1644 | /* force to YCrCb */ | ||
1645 | io_write_and_or(sd, 0x02, 0x0f, 0x60); | ||
1646 | } else { | ||
1647 | /* force to RGB */ | ||
1648 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | ||
1649 | } | ||
1630 | 1650 | ||
1631 | /* set ADI recommended settings for digitizer */ | 1651 | /* set ADI recommended settings for digitizer */ |
1632 | /* "ADV7842 Register Settings Recommendations | 1652 | /* "ADV7842 Register Settings Recommendations |
@@ -1722,19 +1742,19 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, | |||
1722 | 1742 | ||
1723 | switch (input) { | 1743 | switch (input) { |
1724 | case ADV7842_SELECT_HDMI_PORT_A: | 1744 | case ADV7842_SELECT_HDMI_PORT_A: |
1725 | /* TODO select HDMI_COMP or HDMI_GR */ | ||
1726 | state->mode = ADV7842_MODE_HDMI; | 1745 | state->mode = ADV7842_MODE_HDMI; |
1727 | state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; | 1746 | state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; |
1728 | state->hdmi_port_a = true; | 1747 | state->hdmi_port_a = true; |
1729 | break; | 1748 | break; |
1730 | case ADV7842_SELECT_HDMI_PORT_B: | 1749 | case ADV7842_SELECT_HDMI_PORT_B: |
1731 | /* TODO select HDMI_COMP or HDMI_GR */ | ||
1732 | state->mode = ADV7842_MODE_HDMI; | 1750 | state->mode = ADV7842_MODE_HDMI; |
1733 | state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; | 1751 | state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; |
1734 | state->hdmi_port_a = false; | 1752 | state->hdmi_port_a = false; |
1735 | break; | 1753 | break; |
1736 | case ADV7842_SELECT_VGA_COMP: | 1754 | case ADV7842_SELECT_VGA_COMP: |
1737 | v4l2_info(sd, "%s: VGA component: todo\n", __func__); | 1755 | state->mode = ADV7842_MODE_COMP; |
1756 | state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE; | ||
1757 | break; | ||
1738 | case ADV7842_SELECT_VGA_RGB: | 1758 | case ADV7842_SELECT_VGA_RGB: |
1739 | state->mode = ADV7842_MODE_RGB; | 1759 | state->mode = ADV7842_MODE_RGB; |
1740 | state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE; | 1760 | state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE; |
@@ -1814,12 +1834,15 @@ static void adv7842_irq_enable(struct v4l2_subdev *sd, bool enable) | |||
1814 | io_write(sd, 0x78, 0x03); | 1834 | io_write(sd, 0x78, 0x03); |
1815 | /* Enable SDP Standard Detection Change and SDP Video Detected */ | 1835 | /* Enable SDP Standard Detection Change and SDP Video Detected */ |
1816 | io_write(sd, 0xa0, 0x09); | 1836 | io_write(sd, 0xa0, 0x09); |
1837 | /* Enable HDMI_MODE interrupt */ | ||
1838 | io_write(sd, 0x69, 0x08); | ||
1817 | } else { | 1839 | } else { |
1818 | io_write(sd, 0x46, 0x0); | 1840 | io_write(sd, 0x46, 0x0); |
1819 | io_write(sd, 0x5a, 0x0); | 1841 | io_write(sd, 0x5a, 0x0); |
1820 | io_write(sd, 0x73, 0x0); | 1842 | io_write(sd, 0x73, 0x0); |
1821 | io_write(sd, 0x78, 0x0); | 1843 | io_write(sd, 0x78, 0x0); |
1822 | io_write(sd, 0xa0, 0x0); | 1844 | io_write(sd, 0xa0, 0x0); |
1845 | io_write(sd, 0x69, 0x0); | ||
1823 | } | 1846 | } |
1824 | } | 1847 | } |
1825 | 1848 | ||
@@ -1827,11 +1850,9 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
1827 | { | 1850 | { |
1828 | struct adv7842_state *state = to_state(sd); | 1851 | struct adv7842_state *state = to_state(sd); |
1829 | u8 fmt_change_cp, fmt_change_digital, fmt_change_sdp; | 1852 | u8 fmt_change_cp, fmt_change_digital, fmt_change_sdp; |
1830 | u8 irq_status[5]; | 1853 | u8 irq_status[6]; |
1831 | u8 irq_cfg = io_read(sd, 0x40); | ||
1832 | 1854 | ||
1833 | /* disable irq-pin output */ | 1855 | adv7842_irq_enable(sd, false); |
1834 | io_write(sd, 0x40, irq_cfg | 0x3); | ||
1835 | 1856 | ||
1836 | /* read status */ | 1857 | /* read status */ |
1837 | irq_status[0] = io_read(sd, 0x43); | 1858 | irq_status[0] = io_read(sd, 0x43); |
@@ -1839,6 +1860,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
1839 | irq_status[2] = io_read(sd, 0x70); | 1860 | irq_status[2] = io_read(sd, 0x70); |
1840 | irq_status[3] = io_read(sd, 0x75); | 1861 | irq_status[3] = io_read(sd, 0x75); |
1841 | irq_status[4] = io_read(sd, 0x9d); | 1862 | irq_status[4] = io_read(sd, 0x9d); |
1863 | irq_status[5] = io_read(sd, 0x66); | ||
1842 | 1864 | ||
1843 | /* and clear */ | 1865 | /* and clear */ |
1844 | if (irq_status[0]) | 1866 | if (irq_status[0]) |
@@ -1851,10 +1873,14 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
1851 | io_write(sd, 0x76, irq_status[3]); | 1873 | io_write(sd, 0x76, irq_status[3]); |
1852 | if (irq_status[4]) | 1874 | if (irq_status[4]) |
1853 | io_write(sd, 0x9e, irq_status[4]); | 1875 | io_write(sd, 0x9e, irq_status[4]); |
1876 | if (irq_status[5]) | ||
1877 | io_write(sd, 0x67, irq_status[5]); | ||
1854 | 1878 | ||
1855 | v4l2_dbg(1, debug, sd, "%s: irq %x, %x, %x, %x, %x\n", __func__, | 1879 | adv7842_irq_enable(sd, true); |
1880 | |||
1881 | v4l2_dbg(1, debug, sd, "%s: irq %x, %x, %x, %x, %x, %x\n", __func__, | ||
1856 | irq_status[0], irq_status[1], irq_status[2], | 1882 | irq_status[0], irq_status[1], irq_status[2], |
1857 | irq_status[3], irq_status[4]); | 1883 | irq_status[3], irq_status[4], irq_status[5]); |
1858 | 1884 | ||
1859 | /* format change CP */ | 1885 | /* format change CP */ |
1860 | fmt_change_cp = irq_status[0] & 0x9c; | 1886 | fmt_change_cp = irq_status[0] & 0x9c; |
@@ -1871,25 +1897,72 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
1871 | else | 1897 | else |
1872 | fmt_change_digital = 0; | 1898 | fmt_change_digital = 0; |
1873 | 1899 | ||
1874 | /* notify */ | 1900 | /* format change */ |
1875 | if (fmt_change_cp || fmt_change_digital || fmt_change_sdp) { | 1901 | if (fmt_change_cp || fmt_change_digital || fmt_change_sdp) { |
1876 | v4l2_dbg(1, debug, sd, | 1902 | v4l2_dbg(1, debug, sd, |
1877 | "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n", | 1903 | "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n", |
1878 | __func__, fmt_change_cp, fmt_change_digital, | 1904 | __func__, fmt_change_cp, fmt_change_digital, |
1879 | fmt_change_sdp); | 1905 | fmt_change_sdp); |
1880 | v4l2_subdev_notify(sd, ADV7842_FMT_CHANGE, NULL); | 1906 | v4l2_subdev_notify(sd, ADV7842_FMT_CHANGE, NULL); |
1907 | if (handled) | ||
1908 | *handled = true; | ||
1881 | } | 1909 | } |
1882 | 1910 | ||
1883 | /* 5v cable detect */ | 1911 | /* HDMI/DVI mode */ |
1884 | if (irq_status[2]) | 1912 | if (irq_status[5] & 0x08) { |
1913 | v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__, | ||
1914 | (io_read(sd, 0x65) & 0x08) ? "HDMI" : "DVI"); | ||
1915 | if (handled) | ||
1916 | *handled = true; | ||
1917 | } | ||
1918 | |||
1919 | /* tx 5v detect */ | ||
1920 | if (irq_status[2] & 0x3) { | ||
1921 | v4l2_dbg(1, debug, sd, "%s: irq tx_5v\n", __func__); | ||
1885 | adv7842_s_detect_tx_5v_ctrl(sd); | 1922 | adv7842_s_detect_tx_5v_ctrl(sd); |
1923 | if (handled) | ||
1924 | *handled = true; | ||
1925 | } | ||
1926 | return 0; | ||
1927 | } | ||
1928 | |||
1929 | static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) | ||
1930 | { | ||
1931 | struct adv7842_state *state = to_state(sd); | ||
1932 | u8 *data = NULL; | ||
1886 | 1933 | ||
1887 | if (handled) | 1934 | if (edid->pad > ADV7842_EDID_PORT_VGA) |
1888 | *handled = true; | 1935 | return -EINVAL; |
1936 | if (edid->blocks == 0) | ||
1937 | return -EINVAL; | ||
1938 | if (edid->blocks > 2) | ||
1939 | return -EINVAL; | ||
1940 | if (edid->start_block > 1) | ||
1941 | return -EINVAL; | ||
1942 | if (edid->start_block == 1) | ||
1943 | edid->blocks = 1; | ||
1944 | if (!edid->edid) | ||
1945 | return -EINVAL; | ||
1889 | 1946 | ||
1890 | /* re-enable irq-pin output */ | 1947 | switch (edid->pad) { |
1891 | io_write(sd, 0x40, irq_cfg); | 1948 | case ADV7842_EDID_PORT_A: |
1949 | case ADV7842_EDID_PORT_B: | ||
1950 | if (state->hdmi_edid.present & (0x04 << edid->pad)) | ||
1951 | data = state->hdmi_edid.edid; | ||
1952 | break; | ||
1953 | case ADV7842_EDID_PORT_VGA: | ||
1954 | if (state->vga_edid.present) | ||
1955 | data = state->vga_edid.edid; | ||
1956 | break; | ||
1957 | default: | ||
1958 | return -EINVAL; | ||
1959 | } | ||
1960 | if (!data) | ||
1961 | return -ENODATA; | ||
1892 | 1962 | ||
1963 | memcpy(edid->edid, | ||
1964 | data + edid->start_block * 128, | ||
1965 | edid->blocks * 128); | ||
1893 | return 0; | 1966 | return 0; |
1894 | } | 1967 | } |
1895 | 1968 | ||
@@ -1898,7 +1971,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e) | |||
1898 | struct adv7842_state *state = to_state(sd); | 1971 | struct adv7842_state *state = to_state(sd); |
1899 | int err = 0; | 1972 | int err = 0; |
1900 | 1973 | ||
1901 | if (e->pad > 2) | 1974 | if (e->pad > ADV7842_EDID_PORT_VGA) |
1902 | return -EINVAL; | 1975 | return -EINVAL; |
1903 | if (e->start_block != 0) | 1976 | if (e->start_block != 0) |
1904 | return -EINVAL; | 1977 | return -EINVAL; |
@@ -1911,20 +1984,25 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e) | |||
1911 | state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15], | 1984 | state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15], |
1912 | e->edid[0x16]); | 1985 | e->edid[0x16]); |
1913 | 1986 | ||
1914 | if (e->pad == 2) { | 1987 | switch (e->pad) { |
1988 | case ADV7842_EDID_PORT_VGA: | ||
1915 | memset(&state->vga_edid.edid, 0, 256); | 1989 | memset(&state->vga_edid.edid, 0, 256); |
1916 | state->vga_edid.present = e->blocks ? 0x1 : 0x0; | 1990 | state->vga_edid.present = e->blocks ? 0x1 : 0x0; |
1917 | memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks); | 1991 | memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks); |
1918 | err = edid_write_vga_segment(sd); | 1992 | err = edid_write_vga_segment(sd); |
1919 | } else { | 1993 | break; |
1920 | u32 mask = 0x1<<e->pad; | 1994 | case ADV7842_EDID_PORT_A: |
1995 | case ADV7842_EDID_PORT_B: | ||
1921 | memset(&state->hdmi_edid.edid, 0, 256); | 1996 | memset(&state->hdmi_edid.edid, 0, 256); |
1922 | if (e->blocks) | 1997 | if (e->blocks) |
1923 | state->hdmi_edid.present |= mask; | 1998 | state->hdmi_edid.present |= 0x04 << e->pad; |
1924 | else | 1999 | else |
1925 | state->hdmi_edid.present &= ~mask; | 2000 | state->hdmi_edid.present &= ~(0x04 << e->pad); |
1926 | memcpy(&state->hdmi_edid.edid, e->edid, 128*e->blocks); | 2001 | memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); |
1927 | err = edid_write_hdmi_segment(sd, e->pad); | 2002 | err = edid_write_hdmi_segment(sd, e->pad); |
2003 | break; | ||
2004 | default: | ||
2005 | return -EINVAL; | ||
1928 | } | 2006 | } |
1929 | if (err < 0) | 2007 | if (err < 0) |
1930 | v4l2_err(sd, "error %d writing edid on port %d\n", err, e->pad); | 2008 | v4l2_err(sd, "error %d writing edid on port %d\n", err, e->pad); |
@@ -2156,7 +2234,7 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) | |||
2156 | static const char * const input_color_space_txt[16] = { | 2234 | static const char * const input_color_space_txt[16] = { |
2157 | "RGB limited range (16-235)", "RGB full range (0-255)", | 2235 | "RGB limited range (16-235)", "RGB full range (0-255)", |
2158 | "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", | 2236 | "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", |
2159 | "XvYCC Bt.601", "XvYCC Bt.709", | 2237 | "xvYCC Bt.601", "xvYCC Bt.709", |
2160 | "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", | 2238 | "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", |
2161 | "invalid", "invalid", "invalid", "invalid", "invalid", | 2239 | "invalid", "invalid", "invalid", "invalid", "invalid", |
2162 | "invalid", "invalid", "automatic" | 2240 | "invalid", "invalid", "automatic" |
@@ -2175,8 +2253,6 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) | |||
2175 | 2253 | ||
2176 | v4l2_info(sd, "-----Chip status-----\n"); | 2254 | v4l2_info(sd, "-----Chip status-----\n"); |
2177 | v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); | 2255 | v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); |
2178 | v4l2_info(sd, "Connector type: %s\n", state->connector_hdmi ? | ||
2179 | "HDMI" : (is_digital_input(sd) ? "DVI-D" : "DVI-A")); | ||
2180 | v4l2_info(sd, "HDMI/DVI-D port selected: %s\n", | 2256 | v4l2_info(sd, "HDMI/DVI-D port selected: %s\n", |
2181 | state->hdmi_port_a ? "A" : "B"); | 2257 | state->hdmi_port_a ? "A" : "B"); |
2182 | v4l2_info(sd, "EDID A %s, B %s\n", | 2258 | v4l2_info(sd, "EDID A %s, B %s\n", |
@@ -2354,15 +2430,63 @@ static int adv7842_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) | |||
2354 | return 0; | 2430 | return 0; |
2355 | } | 2431 | } |
2356 | 2432 | ||
2433 | static void adv7842_s_sdp_io(struct v4l2_subdev *sd, struct adv7842_sdp_io_sync_adjustment *s) | ||
2434 | { | ||
2435 | if (s && s->adjust) { | ||
2436 | sdp_io_write(sd, 0x94, (s->hs_beg >> 8) & 0xf); | ||
2437 | sdp_io_write(sd, 0x95, s->hs_beg & 0xff); | ||
2438 | sdp_io_write(sd, 0x96, (s->hs_width >> 8) & 0xf); | ||
2439 | sdp_io_write(sd, 0x97, s->hs_width & 0xff); | ||
2440 | sdp_io_write(sd, 0x98, (s->de_beg >> 8) & 0xf); | ||
2441 | sdp_io_write(sd, 0x99, s->de_beg & 0xff); | ||
2442 | sdp_io_write(sd, 0x9a, (s->de_end >> 8) & 0xf); | ||
2443 | sdp_io_write(sd, 0x9b, s->de_end & 0xff); | ||
2444 | sdp_io_write(sd, 0xa8, s->vs_beg_o); | ||
2445 | sdp_io_write(sd, 0xa9, s->vs_beg_e); | ||
2446 | sdp_io_write(sd, 0xaa, s->vs_end_o); | ||
2447 | sdp_io_write(sd, 0xab, s->vs_end_e); | ||
2448 | sdp_io_write(sd, 0xac, s->de_v_beg_o); | ||
2449 | sdp_io_write(sd, 0xad, s->de_v_beg_e); | ||
2450 | sdp_io_write(sd, 0xae, s->de_v_end_o); | ||
2451 | sdp_io_write(sd, 0xaf, s->de_v_end_e); | ||
2452 | } else { | ||
2453 | /* set to default */ | ||
2454 | sdp_io_write(sd, 0x94, 0x00); | ||
2455 | sdp_io_write(sd, 0x95, 0x00); | ||
2456 | sdp_io_write(sd, 0x96, 0x00); | ||
2457 | sdp_io_write(sd, 0x97, 0x20); | ||
2458 | sdp_io_write(sd, 0x98, 0x00); | ||
2459 | sdp_io_write(sd, 0x99, 0x00); | ||
2460 | sdp_io_write(sd, 0x9a, 0x00); | ||
2461 | sdp_io_write(sd, 0x9b, 0x00); | ||
2462 | sdp_io_write(sd, 0xa8, 0x04); | ||
2463 | sdp_io_write(sd, 0xa9, 0x04); | ||
2464 | sdp_io_write(sd, 0xaa, 0x04); | ||
2465 | sdp_io_write(sd, 0xab, 0x04); | ||
2466 | sdp_io_write(sd, 0xac, 0x04); | ||
2467 | sdp_io_write(sd, 0xad, 0x04); | ||
2468 | sdp_io_write(sd, 0xae, 0x04); | ||
2469 | sdp_io_write(sd, 0xaf, 0x04); | ||
2470 | } | ||
2471 | } | ||
2472 | |||
2357 | static int adv7842_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) | 2473 | static int adv7842_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) |
2358 | { | 2474 | { |
2359 | struct adv7842_state *state = to_state(sd); | 2475 | struct adv7842_state *state = to_state(sd); |
2476 | struct adv7842_platform_data *pdata = &state->pdata; | ||
2360 | 2477 | ||
2361 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); | 2478 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); |
2362 | 2479 | ||
2363 | if (state->mode != ADV7842_MODE_SDP) | 2480 | if (state->mode != ADV7842_MODE_SDP) |
2364 | return -ENODATA; | 2481 | return -ENODATA; |
2365 | 2482 | ||
2483 | if (norm & V4L2_STD_625_50) | ||
2484 | adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_625); | ||
2485 | else if (norm & V4L2_STD_525_60) | ||
2486 | adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_525); | ||
2487 | else | ||
2488 | adv7842_s_sdp_io(sd, NULL); | ||
2489 | |||
2366 | if (norm & V4L2_STD_ALL) { | 2490 | if (norm & V4L2_STD_ALL) { |
2367 | state->norm = norm; | 2491 | state->norm = norm; |
2368 | return 0; | 2492 | return 0; |
@@ -2385,9 +2509,10 @@ static int adv7842_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) | |||
2385 | 2509 | ||
2386 | /* ----------------------------------------------------------------------- */ | 2510 | /* ----------------------------------------------------------------------- */ |
2387 | 2511 | ||
2388 | static int adv7842_core_init(struct v4l2_subdev *sd, | 2512 | static int adv7842_core_init(struct v4l2_subdev *sd) |
2389 | const struct adv7842_platform_data *pdata) | ||
2390 | { | 2513 | { |
2514 | struct adv7842_state *state = to_state(sd); | ||
2515 | struct adv7842_platform_data *pdata = &state->pdata; | ||
2391 | hdmi_write(sd, 0x48, | 2516 | hdmi_write(sd, 0x48, |
2392 | (pdata->disable_pwrdnb ? 0x80 : 0) | | 2517 | (pdata->disable_pwrdnb ? 0x80 : 0) | |
2393 | (pdata->disable_cable_det_rst ? 0x40 : 0)); | 2518 | (pdata->disable_cable_det_rst ? 0x40 : 0)); |
@@ -2400,7 +2525,7 @@ static int adv7842_core_init(struct v4l2_subdev *sd, | |||
2400 | 2525 | ||
2401 | /* video format */ | 2526 | /* video format */ |
2402 | io_write(sd, 0x02, | 2527 | io_write(sd, 0x02, |
2403 | pdata->inp_color_space << 4 | | 2528 | 0xf0 | |
2404 | pdata->alt_gamma << 3 | | 2529 | pdata->alt_gamma << 3 | |
2405 | pdata->op_656_range << 2 | | 2530 | pdata->op_656_range << 2 | |
2406 | pdata->rgb_out << 1 | | 2531 | pdata->rgb_out << 1 | |
@@ -2412,13 +2537,24 @@ static int adv7842_core_init(struct v4l2_subdev *sd, | |||
2412 | pdata->replicate_av_codes << 1 | | 2537 | pdata->replicate_av_codes << 1 | |
2413 | pdata->invert_cbcr << 0); | 2538 | pdata->invert_cbcr << 0); |
2414 | 2539 | ||
2540 | /* HDMI audio */ | ||
2541 | hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ | ||
2542 | |||
2415 | /* Drive strength */ | 2543 | /* Drive strength */ |
2416 | io_write_and_or(sd, 0x14, 0xc0, pdata->drive_strength.data<<4 | | 2544 | io_write_and_or(sd, 0x14, 0xc0, |
2417 | pdata->drive_strength.clock<<2 | | 2545 | pdata->dr_str_data << 4 | |
2418 | pdata->drive_strength.sync); | 2546 | pdata->dr_str_clk << 2 | |
2547 | pdata->dr_str_sync); | ||
2419 | 2548 | ||
2420 | /* HDMI free run */ | 2549 | /* HDMI free run */ |
2421 | cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); | 2550 | cp_write_and_or(sd, 0xba, 0xfc, pdata->hdmi_free_run_enable | |
2551 | (pdata->hdmi_free_run_mode << 1)); | ||
2552 | |||
2553 | /* SPD free run */ | ||
2554 | sdp_write_and_or(sd, 0xdd, 0xf0, pdata->sdp_free_run_force | | ||
2555 | (pdata->sdp_free_run_cbar_en << 1) | | ||
2556 | (pdata->sdp_free_run_man_col_en << 2) | | ||
2557 | (pdata->sdp_free_run_force << 3)); | ||
2422 | 2558 | ||
2423 | /* TODO from platform data */ | 2559 | /* TODO from platform data */ |
2424 | cp_write(sd, 0x69, 0x14); /* Enable CP CSC */ | 2560 | cp_write(sd, 0x69, 0x14); /* Enable CP CSC */ |
@@ -2431,18 +2567,6 @@ static int adv7842_core_init(struct v4l2_subdev *sd, | |||
2431 | 2567 | ||
2432 | sdp_csc_coeff(sd, &pdata->sdp_csc_coeff); | 2568 | sdp_csc_coeff(sd, &pdata->sdp_csc_coeff); |
2433 | 2569 | ||
2434 | if (pdata->sdp_io_sync.adjust) { | ||
2435 | const struct adv7842_sdp_io_sync_adjustment *s = &pdata->sdp_io_sync; | ||
2436 | sdp_io_write(sd, 0x94, (s->hs_beg>>8) & 0xf); | ||
2437 | sdp_io_write(sd, 0x95, s->hs_beg & 0xff); | ||
2438 | sdp_io_write(sd, 0x96, (s->hs_width>>8) & 0xf); | ||
2439 | sdp_io_write(sd, 0x97, s->hs_width & 0xff); | ||
2440 | sdp_io_write(sd, 0x98, (s->de_beg>>8) & 0xf); | ||
2441 | sdp_io_write(sd, 0x99, s->de_beg & 0xff); | ||
2442 | sdp_io_write(sd, 0x9a, (s->de_end>>8) & 0xf); | ||
2443 | sdp_io_write(sd, 0x9b, s->de_end & 0xff); | ||
2444 | } | ||
2445 | |||
2446 | /* todo, improve settings for sdram */ | 2570 | /* todo, improve settings for sdram */ |
2447 | if (pdata->sd_ram_size >= 128) { | 2571 | if (pdata->sd_ram_size >= 128) { |
2448 | sdp_write(sd, 0x12, 0x0d); /* Frame TBC,3D comb enabled */ | 2572 | sdp_write(sd, 0x12, 0x0d); /* Frame TBC,3D comb enabled */ |
@@ -2483,12 +2607,11 @@ static int adv7842_core_init(struct v4l2_subdev *sd, | |||
2483 | io_write_and_or(sd, 0x20, 0xcf, 0x00); | 2607 | io_write_and_or(sd, 0x20, 0xcf, 0x00); |
2484 | 2608 | ||
2485 | /* LLC */ | 2609 | /* LLC */ |
2486 | /* Set phase to 16. TODO: get this from platform_data */ | 2610 | io_write(sd, 0x19, 0x80 | pdata->llc_dll_phase); |
2487 | io_write(sd, 0x19, 0x90); | ||
2488 | io_write(sd, 0x33, 0x40); | 2611 | io_write(sd, 0x33, 0x40); |
2489 | 2612 | ||
2490 | /* interrupts */ | 2613 | /* interrupts */ |
2491 | io_write(sd, 0x40, 0xe2); /* Configure INT1 */ | 2614 | io_write(sd, 0x40, 0xf2); /* Configure INT1 */ |
2492 | 2615 | ||
2493 | adv7842_irq_enable(sd, true); | 2616 | adv7842_irq_enable(sd, true); |
2494 | 2617 | ||
@@ -2588,6 +2711,7 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd) | |||
2588 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 2711 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
2589 | struct adv7842_state *state = to_state(sd); | 2712 | struct adv7842_state *state = to_state(sd); |
2590 | struct adv7842_platform_data *pdata = client->dev.platform_data; | 2713 | struct adv7842_platform_data *pdata = client->dev.platform_data; |
2714 | struct v4l2_dv_timings timings; | ||
2591 | int ret = 0; | 2715 | int ret = 0; |
2592 | 2716 | ||
2593 | if (!pdata) | 2717 | if (!pdata) |
@@ -2610,7 +2734,7 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd) | |||
2610 | adv7842_rewrite_i2c_addresses(sd, pdata); | 2734 | adv7842_rewrite_i2c_addresses(sd, pdata); |
2611 | 2735 | ||
2612 | /* and re-init chip and state */ | 2736 | /* and re-init chip and state */ |
2613 | adv7842_core_init(sd, pdata); | 2737 | adv7842_core_init(sd); |
2614 | 2738 | ||
2615 | disable_input(sd); | 2739 | disable_input(sd); |
2616 | 2740 | ||
@@ -2618,11 +2742,15 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd) | |||
2618 | 2742 | ||
2619 | enable_input(sd); | 2743 | enable_input(sd); |
2620 | 2744 | ||
2621 | adv7842_s_dv_timings(sd, &state->timings); | ||
2622 | |||
2623 | edid_write_vga_segment(sd); | 2745 | edid_write_vga_segment(sd); |
2624 | edid_write_hdmi_segment(sd, 0); | 2746 | edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_A); |
2625 | edid_write_hdmi_segment(sd, 1); | 2747 | edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_B); |
2748 | |||
2749 | timings = state->timings; | ||
2750 | |||
2751 | memset(&state->timings, 0, sizeof(struct v4l2_dv_timings)); | ||
2752 | |||
2753 | adv7842_s_dv_timings(sd, &timings); | ||
2626 | 2754 | ||
2627 | return ret; | 2755 | return ret; |
2628 | } | 2756 | } |
@@ -2670,6 +2798,7 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = { | |||
2670 | }; | 2798 | }; |
2671 | 2799 | ||
2672 | static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { | 2800 | static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { |
2801 | .get_edid = adv7842_get_edid, | ||
2673 | .set_edid = adv7842_set_edid, | 2802 | .set_edid = adv7842_set_edid, |
2674 | }; | 2803 | }; |
2675 | 2804 | ||
@@ -2712,8 +2841,9 @@ static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color = { | |||
2712 | }; | 2841 | }; |
2713 | 2842 | ||
2714 | 2843 | ||
2715 | static void adv7842_unregister_clients(struct adv7842_state *state) | 2844 | static void adv7842_unregister_clients(struct v4l2_subdev *sd) |
2716 | { | 2845 | { |
2846 | struct adv7842_state *state = to_state(sd); | ||
2717 | if (state->i2c_avlink) | 2847 | if (state->i2c_avlink) |
2718 | i2c_unregister_device(state->i2c_avlink); | 2848 | i2c_unregister_device(state->i2c_avlink); |
2719 | if (state->i2c_cec) | 2849 | if (state->i2c_cec) |
@@ -2736,21 +2866,79 @@ static void adv7842_unregister_clients(struct adv7842_state *state) | |||
2736 | i2c_unregister_device(state->i2c_cp); | 2866 | i2c_unregister_device(state->i2c_cp); |
2737 | if (state->i2c_vdp) | 2867 | if (state->i2c_vdp) |
2738 | i2c_unregister_device(state->i2c_vdp); | 2868 | i2c_unregister_device(state->i2c_vdp); |
2869 | |||
2870 | state->i2c_avlink = NULL; | ||
2871 | state->i2c_cec = NULL; | ||
2872 | state->i2c_infoframe = NULL; | ||
2873 | state->i2c_sdp_io = NULL; | ||
2874 | state->i2c_sdp = NULL; | ||
2875 | state->i2c_afe = NULL; | ||
2876 | state->i2c_repeater = NULL; | ||
2877 | state->i2c_edid = NULL; | ||
2878 | state->i2c_hdmi = NULL; | ||
2879 | state->i2c_cp = NULL; | ||
2880 | state->i2c_vdp = NULL; | ||
2739 | } | 2881 | } |
2740 | 2882 | ||
2741 | static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, | 2883 | static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, const char *desc, |
2742 | u8 addr, u8 io_reg) | 2884 | u8 addr, u8 io_reg) |
2743 | { | 2885 | { |
2744 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 2886 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
2887 | struct i2c_client *cp; | ||
2745 | 2888 | ||
2746 | io_write(sd, io_reg, addr << 1); | 2889 | io_write(sd, io_reg, addr << 1); |
2747 | return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); | 2890 | |
2891 | if (addr == 0) { | ||
2892 | v4l2_err(sd, "no %s i2c addr configured\n", desc); | ||
2893 | return NULL; | ||
2894 | } | ||
2895 | |||
2896 | cp = i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); | ||
2897 | if (!cp) | ||
2898 | v4l2_err(sd, "register %s on i2c addr 0x%x failed\n", desc, addr); | ||
2899 | |||
2900 | return cp; | ||
2901 | } | ||
2902 | |||
2903 | static int adv7842_register_clients(struct v4l2_subdev *sd) | ||
2904 | { | ||
2905 | struct adv7842_state *state = to_state(sd); | ||
2906 | struct adv7842_platform_data *pdata = &state->pdata; | ||
2907 | |||
2908 | state->i2c_avlink = adv7842_dummy_client(sd, "avlink", pdata->i2c_avlink, 0xf3); | ||
2909 | state->i2c_cec = adv7842_dummy_client(sd, "cec", pdata->i2c_cec, 0xf4); | ||
2910 | state->i2c_infoframe = adv7842_dummy_client(sd, "infoframe", pdata->i2c_infoframe, 0xf5); | ||
2911 | state->i2c_sdp_io = adv7842_dummy_client(sd, "sdp_io", pdata->i2c_sdp_io, 0xf2); | ||
2912 | state->i2c_sdp = adv7842_dummy_client(sd, "sdp", pdata->i2c_sdp, 0xf1); | ||
2913 | state->i2c_afe = adv7842_dummy_client(sd, "afe", pdata->i2c_afe, 0xf8); | ||
2914 | state->i2c_repeater = adv7842_dummy_client(sd, "repeater", pdata->i2c_repeater, 0xf9); | ||
2915 | state->i2c_edid = adv7842_dummy_client(sd, "edid", pdata->i2c_edid, 0xfa); | ||
2916 | state->i2c_hdmi = adv7842_dummy_client(sd, "hdmi", pdata->i2c_hdmi, 0xfb); | ||
2917 | state->i2c_cp = adv7842_dummy_client(sd, "cp", pdata->i2c_cp, 0xfd); | ||
2918 | state->i2c_vdp = adv7842_dummy_client(sd, "vdp", pdata->i2c_vdp, 0xfe); | ||
2919 | |||
2920 | if (!state->i2c_avlink || | ||
2921 | !state->i2c_cec || | ||
2922 | !state->i2c_infoframe || | ||
2923 | !state->i2c_sdp_io || | ||
2924 | !state->i2c_sdp || | ||
2925 | !state->i2c_afe || | ||
2926 | !state->i2c_repeater || | ||
2927 | !state->i2c_edid || | ||
2928 | !state->i2c_hdmi || | ||
2929 | !state->i2c_cp || | ||
2930 | !state->i2c_vdp) | ||
2931 | return -1; | ||
2932 | |||
2933 | return 0; | ||
2748 | } | 2934 | } |
2749 | 2935 | ||
2750 | static int adv7842_probe(struct i2c_client *client, | 2936 | static int adv7842_probe(struct i2c_client *client, |
2751 | const struct i2c_device_id *id) | 2937 | const struct i2c_device_id *id) |
2752 | { | 2938 | { |
2753 | struct adv7842_state *state; | 2939 | struct adv7842_state *state; |
2940 | static const struct v4l2_dv_timings cea640x480 = | ||
2941 | V4L2_DV_BT_CEA_640X480P59_94; | ||
2754 | struct adv7842_platform_data *pdata = client->dev.platform_data; | 2942 | struct adv7842_platform_data *pdata = client->dev.platform_data; |
2755 | struct v4l2_ctrl_handler *hdl; | 2943 | struct v4l2_ctrl_handler *hdl; |
2756 | struct v4l2_subdev *sd; | 2944 | struct v4l2_subdev *sd; |
@@ -2775,13 +2963,17 @@ static int adv7842_probe(struct i2c_client *client, | |||
2775 | return -ENOMEM; | 2963 | return -ENOMEM; |
2776 | } | 2964 | } |
2777 | 2965 | ||
2966 | /* platform data */ | ||
2967 | state->pdata = *pdata; | ||
2968 | state->timings = cea640x480; | ||
2969 | |||
2778 | sd = &state->sd; | 2970 | sd = &state->sd; |
2779 | v4l2_i2c_subdev_init(sd, client, &adv7842_ops); | 2971 | v4l2_i2c_subdev_init(sd, client, &adv7842_ops); |
2780 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 2972 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
2781 | state->connector_hdmi = pdata->connector_hdmi; | ||
2782 | state->mode = pdata->mode; | 2973 | state->mode = pdata->mode; |
2783 | 2974 | ||
2784 | state->hdmi_port_a = true; | 2975 | state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; |
2976 | state->restart_stdi_once = true; | ||
2785 | 2977 | ||
2786 | /* i2c access to adv7842? */ | 2978 | /* i2c access to adv7842? */ |
2787 | rev = adv_smbus_read_byte_data_check(client, 0xea, false) << 8 | | 2979 | rev = adv_smbus_read_byte_data_check(client, 0xea, false) << 8 | |
@@ -2843,21 +3035,7 @@ static int adv7842_probe(struct i2c_client *client, | |||
2843 | goto err_hdl; | 3035 | goto err_hdl; |
2844 | } | 3036 | } |
2845 | 3037 | ||
2846 | state->i2c_avlink = adv7842_dummy_client(sd, pdata->i2c_avlink, 0xf3); | 3038 | if (adv7842_register_clients(sd) < 0) { |
2847 | state->i2c_cec = adv7842_dummy_client(sd, pdata->i2c_cec, 0xf4); | ||
2848 | state->i2c_infoframe = adv7842_dummy_client(sd, pdata->i2c_infoframe, 0xf5); | ||
2849 | state->i2c_sdp_io = adv7842_dummy_client(sd, pdata->i2c_sdp_io, 0xf2); | ||
2850 | state->i2c_sdp = adv7842_dummy_client(sd, pdata->i2c_sdp, 0xf1); | ||
2851 | state->i2c_afe = adv7842_dummy_client(sd, pdata->i2c_afe, 0xf8); | ||
2852 | state->i2c_repeater = adv7842_dummy_client(sd, pdata->i2c_repeater, 0xf9); | ||
2853 | state->i2c_edid = adv7842_dummy_client(sd, pdata->i2c_edid, 0xfa); | ||
2854 | state->i2c_hdmi = adv7842_dummy_client(sd, pdata->i2c_hdmi, 0xfb); | ||
2855 | state->i2c_cp = adv7842_dummy_client(sd, pdata->i2c_cp, 0xfd); | ||
2856 | state->i2c_vdp = adv7842_dummy_client(sd, pdata->i2c_vdp, 0xfe); | ||
2857 | if (!state->i2c_avlink || !state->i2c_cec || !state->i2c_infoframe || | ||
2858 | !state->i2c_sdp_io || !state->i2c_sdp || !state->i2c_afe || | ||
2859 | !state->i2c_repeater || !state->i2c_edid || !state->i2c_hdmi || | ||
2860 | !state->i2c_cp || !state->i2c_vdp) { | ||
2861 | err = -ENOMEM; | 3039 | err = -ENOMEM; |
2862 | v4l2_err(sd, "failed to create all i2c clients\n"); | 3040 | v4l2_err(sd, "failed to create all i2c clients\n"); |
2863 | goto err_i2c; | 3041 | goto err_i2c; |
@@ -2879,7 +3057,7 @@ static int adv7842_probe(struct i2c_client *client, | |||
2879 | if (err) | 3057 | if (err) |
2880 | goto err_work_queues; | 3058 | goto err_work_queues; |
2881 | 3059 | ||
2882 | err = adv7842_core_init(sd, pdata); | 3060 | err = adv7842_core_init(sd); |
2883 | if (err) | 3061 | if (err) |
2884 | goto err_entity; | 3062 | goto err_entity; |
2885 | 3063 | ||
@@ -2893,7 +3071,7 @@ err_work_queues: | |||
2893 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 3071 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
2894 | destroy_workqueue(state->work_queues); | 3072 | destroy_workqueue(state->work_queues); |
2895 | err_i2c: | 3073 | err_i2c: |
2896 | adv7842_unregister_clients(state); | 3074 | adv7842_unregister_clients(sd); |
2897 | err_hdl: | 3075 | err_hdl: |
2898 | v4l2_ctrl_handler_free(hdl); | 3076 | v4l2_ctrl_handler_free(hdl); |
2899 | return err; | 3077 | return err; |
@@ -2912,7 +3090,7 @@ static int adv7842_remove(struct i2c_client *client) | |||
2912 | destroy_workqueue(state->work_queues); | 3090 | destroy_workqueue(state->work_queues); |
2913 | v4l2_device_unregister_subdev(sd); | 3091 | v4l2_device_unregister_subdev(sd); |
2914 | media_entity_cleanup(&sd->entity); | 3092 | media_entity_cleanup(&sd->entity); |
2915 | adv7842_unregister_clients(to_state(sd)); | 3093 | adv7842_unregister_clients(sd); |
2916 | v4l2_ctrl_handler_free(sd->ctrl_handler); | 3094 | v4l2_ctrl_handler_free(sd->ctrl_handler); |
2917 | return 0; | 3095 | return 0; |
2918 | } | 3096 | } |
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index 3317a9ae3961..d98ca3aebe23 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c | |||
@@ -172,28 +172,28 @@ static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash, | |||
172 | static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) | 172 | static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) |
173 | { | 173 | { |
174 | struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no); | 174 | struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no); |
175 | int rval = -EINVAL; | ||
175 | 176 | ||
176 | mutex_lock(&flash->lock); | 177 | mutex_lock(&flash->lock); |
177 | 178 | ||
178 | if (ctrl->id == V4L2_CID_FLASH_FAULT) { | 179 | if (ctrl->id == V4L2_CID_FLASH_FAULT) { |
179 | int rval; | ||
180 | s32 fault = 0; | 180 | s32 fault = 0; |
181 | unsigned int reg_val; | 181 | unsigned int reg_val; |
182 | rval = regmap_read(flash->regmap, REG_FLAG, ®_val); | 182 | rval = regmap_read(flash->regmap, REG_FLAG, ®_val); |
183 | if (rval < 0) | 183 | if (rval < 0) |
184 | return rval; | 184 | goto out; |
185 | if (rval & FAULT_SHORT_CIRCUIT) | 185 | if (reg_val & FAULT_SHORT_CIRCUIT) |
186 | fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; | 186 | fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; |
187 | if (rval & FAULT_OVERTEMP) | 187 | if (reg_val & FAULT_OVERTEMP) |
188 | fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; | 188 | fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; |
189 | if (rval & FAULT_TIMEOUT) | 189 | if (reg_val & FAULT_TIMEOUT) |
190 | fault |= V4L2_FLASH_FAULT_TIMEOUT; | 190 | fault |= V4L2_FLASH_FAULT_TIMEOUT; |
191 | ctrl->cur.val = fault; | 191 | ctrl->cur.val = fault; |
192 | return 0; | ||
193 | } | 192 | } |
194 | 193 | ||
194 | out: | ||
195 | mutex_unlock(&flash->lock); | 195 | mutex_unlock(&flash->lock); |
196 | return -EINVAL; | 196 | return rval; |
197 | } | 197 | } |
198 | 198 | ||
199 | static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) | 199 | static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) |
@@ -219,15 +219,19 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) | |||
219 | break; | 219 | break; |
220 | 220 | ||
221 | case V4L2_CID_FLASH_STROBE: | 221 | case V4L2_CID_FLASH_STROBE: |
222 | if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) | 222 | if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) { |
223 | return -EBUSY; | 223 | rval = -EBUSY; |
224 | goto err_out; | ||
225 | } | ||
224 | flash->led_mode = V4L2_FLASH_LED_MODE_FLASH; | 226 | flash->led_mode = V4L2_FLASH_LED_MODE_FLASH; |
225 | rval = lm3560_mode_ctrl(flash); | 227 | rval = lm3560_mode_ctrl(flash); |
226 | break; | 228 | break; |
227 | 229 | ||
228 | case V4L2_CID_FLASH_STROBE_STOP: | 230 | case V4L2_CID_FLASH_STROBE_STOP: |
229 | if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) | 231 | if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) { |
230 | return -EBUSY; | 232 | rval = -EBUSY; |
233 | goto err_out; | ||
234 | } | ||
231 | flash->led_mode = V4L2_FLASH_LED_MODE_NONE; | 235 | flash->led_mode = V4L2_FLASH_LED_MODE_NONE; |
232 | rval = lm3560_mode_ctrl(flash); | 236 | rval = lm3560_mode_ctrl(flash); |
233 | break; | 237 | break; |
@@ -247,8 +251,8 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) | |||
247 | break; | 251 | break; |
248 | } | 252 | } |
249 | 253 | ||
250 | mutex_unlock(&flash->lock); | ||
251 | err_out: | 254 | err_out: |
255 | mutex_unlock(&flash->lock); | ||
252 | return rval; | 256 | return rval; |
253 | } | 257 | } |
254 | 258 | ||
@@ -444,14 +448,14 @@ static int lm3560_probe(struct i2c_client *client, | |||
444 | if (rval < 0) | 448 | if (rval < 0) |
445 | return rval; | 449 | return rval; |
446 | 450 | ||
451 | i2c_set_clientdata(client, flash); | ||
452 | |||
447 | return 0; | 453 | return 0; |
448 | } | 454 | } |
449 | 455 | ||
450 | static int lm3560_remove(struct i2c_client *client) | 456 | static int lm3560_remove(struct i2c_client *client) |
451 | { | 457 | { |
452 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | 458 | struct lm3560_flash *flash = i2c_get_clientdata(client); |
453 | struct lm3560_flash *flash = container_of(subdev, struct lm3560_flash, | ||
454 | subdev_led[LM3560_LED_MAX]); | ||
455 | unsigned int i; | 459 | unsigned int i; |
456 | 460 | ||
457 | for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) { | 461 | for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) { |
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 846b15f0bf64..85ec3bacdf1c 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c | |||
@@ -459,13 +459,15 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, | |||
459 | MT9M032_COLUMN_START_MAX); | 459 | MT9M032_COLUMN_START_MAX); |
460 | rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN, | 460 | rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN, |
461 | MT9M032_ROW_START_MAX); | 461 | MT9M032_ROW_START_MAX); |
462 | rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN, | 462 | rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), |
463 | MT9M032_COLUMN_SIZE_MAX); | 463 | MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX); |
464 | rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN, | 464 | rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), |
465 | MT9M032_ROW_SIZE_MAX); | 465 | MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX); |
466 | 466 | ||
467 | rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left); | 467 | rect.width = min_t(unsigned int, rect.width, |
468 | rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); | 468 | MT9M032_PIXEL_ARRAY_WIDTH - rect.left); |
469 | rect.height = min_t(unsigned int, rect.height, | ||
470 | MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); | ||
469 | 471 | ||
470 | __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which); | 472 | __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which); |
471 | 473 | ||
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 1c2303d18bf4..e5ddf47030fd 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c | |||
@@ -519,11 +519,13 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, | |||
519 | 519 | ||
520 | /* Clamp the width and height to avoid dividing by zero. */ | 520 | /* Clamp the width and height to avoid dividing by zero. */ |
521 | width = clamp_t(unsigned int, ALIGN(format->format.width, 2), | 521 | width = clamp_t(unsigned int, ALIGN(format->format.width, 2), |
522 | max(__crop->width / 7, MT9P031_WINDOW_WIDTH_MIN), | 522 | max_t(unsigned int, __crop->width / 7, |
523 | MT9P031_WINDOW_WIDTH_MIN), | ||
523 | __crop->width); | 524 | __crop->width); |
524 | height = clamp_t(unsigned int, ALIGN(format->format.height, 2), | 525 | height = clamp_t(unsigned int, ALIGN(format->format.height, 2), |
525 | max(__crop->height / 8, MT9P031_WINDOW_HEIGHT_MIN), | 526 | max_t(unsigned int, __crop->height / 8, |
526 | __crop->height); | 527 | MT9P031_WINDOW_HEIGHT_MIN), |
528 | __crop->height); | ||
527 | 529 | ||
528 | hratio = DIV_ROUND_CLOSEST(__crop->width, width); | 530 | hratio = DIV_ROUND_CLOSEST(__crop->width, width); |
529 | vratio = DIV_ROUND_CLOSEST(__crop->height, height); | 531 | vratio = DIV_ROUND_CLOSEST(__crop->height, height); |
@@ -565,15 +567,17 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev, | |||
565 | MT9P031_COLUMN_START_MAX); | 567 | MT9P031_COLUMN_START_MAX); |
566 | rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN, | 568 | rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN, |
567 | MT9P031_ROW_START_MAX); | 569 | MT9P031_ROW_START_MAX); |
568 | rect.width = clamp(ALIGN(crop->rect.width, 2), | 570 | rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), |
569 | MT9P031_WINDOW_WIDTH_MIN, | 571 | MT9P031_WINDOW_WIDTH_MIN, |
570 | MT9P031_WINDOW_WIDTH_MAX); | 572 | MT9P031_WINDOW_WIDTH_MAX); |
571 | rect.height = clamp(ALIGN(crop->rect.height, 2), | 573 | rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), |
572 | MT9P031_WINDOW_HEIGHT_MIN, | 574 | MT9P031_WINDOW_HEIGHT_MIN, |
573 | MT9P031_WINDOW_HEIGHT_MAX); | 575 | MT9P031_WINDOW_HEIGHT_MAX); |
574 | 576 | ||
575 | rect.width = min(rect.width, MT9P031_PIXEL_ARRAY_WIDTH - rect.left); | 577 | rect.width = min_t(unsigned int, rect.width, |
576 | rect.height = min(rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top); | 578 | MT9P031_PIXEL_ARRAY_WIDTH - rect.left); |
579 | rect.height = min_t(unsigned int, rect.height, | ||
580 | MT9P031_PIXEL_ARRAY_HEIGHT - rect.top); | ||
577 | 581 | ||
578 | __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which); | 582 | __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which); |
579 | 583 | ||
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index 796463466ef0..d41c70eaf838 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c | |||
@@ -291,10 +291,12 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, | |||
291 | 291 | ||
292 | /* Clamp the width and height to avoid dividing by zero. */ | 292 | /* Clamp the width and height to avoid dividing by zero. */ |
293 | width = clamp_t(unsigned int, ALIGN(format->format.width, 2), | 293 | width = clamp_t(unsigned int, ALIGN(format->format.width, 2), |
294 | max(__crop->width / 8, MT9T001_WINDOW_HEIGHT_MIN + 1), | 294 | max_t(unsigned int, __crop->width / 8, |
295 | MT9T001_WINDOW_HEIGHT_MIN + 1), | ||
295 | __crop->width); | 296 | __crop->width); |
296 | height = clamp_t(unsigned int, ALIGN(format->format.height, 2), | 297 | height = clamp_t(unsigned int, ALIGN(format->format.height, 2), |
297 | max(__crop->height / 8, MT9T001_WINDOW_HEIGHT_MIN + 1), | 298 | max_t(unsigned int, __crop->height / 8, |
299 | MT9T001_WINDOW_HEIGHT_MIN + 1), | ||
298 | __crop->height); | 300 | __crop->height); |
299 | 301 | ||
300 | hratio = DIV_ROUND_CLOSEST(__crop->width, width); | 302 | hratio = DIV_ROUND_CLOSEST(__crop->width, width); |
@@ -339,15 +341,17 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev, | |||
339 | rect.top = clamp(ALIGN(crop->rect.top, 2), | 341 | rect.top = clamp(ALIGN(crop->rect.top, 2), |
340 | MT9T001_ROW_START_MIN, | 342 | MT9T001_ROW_START_MIN, |
341 | MT9T001_ROW_START_MAX); | 343 | MT9T001_ROW_START_MAX); |
342 | rect.width = clamp(ALIGN(crop->rect.width, 2), | 344 | rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), |
343 | MT9T001_WINDOW_WIDTH_MIN + 1, | 345 | MT9T001_WINDOW_WIDTH_MIN + 1, |
344 | MT9T001_WINDOW_WIDTH_MAX + 1); | 346 | MT9T001_WINDOW_WIDTH_MAX + 1); |
345 | rect.height = clamp(ALIGN(crop->rect.height, 2), | 347 | rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), |
346 | MT9T001_WINDOW_HEIGHT_MIN + 1, | 348 | MT9T001_WINDOW_HEIGHT_MIN + 1, |
347 | MT9T001_WINDOW_HEIGHT_MAX + 1); | 349 | MT9T001_WINDOW_HEIGHT_MAX + 1); |
348 | 350 | ||
349 | rect.width = min(rect.width, MT9T001_PIXEL_ARRAY_WIDTH - rect.left); | 351 | rect.width = min_t(unsigned int, rect.width, |
350 | rect.height = min(rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); | 352 | MT9T001_PIXEL_ARRAY_WIDTH - rect.left); |
353 | rect.height = min_t(unsigned int, rect.height, | ||
354 | MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); | ||
351 | 355 | ||
352 | __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which); | 356 | __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which); |
353 | 357 | ||
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 2c50effaa334..36c504b78f2c 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c | |||
@@ -27,14 +27,16 @@ | |||
27 | #include <media/v4l2-device.h> | 27 | #include <media/v4l2-device.h> |
28 | #include <media/v4l2-subdev.h> | 28 | #include <media/v4l2-subdev.h> |
29 | 29 | ||
30 | #define MT9V032_PIXEL_ARRAY_HEIGHT 492 | 30 | /* The first four rows are black rows. The active area spans 753x481 pixels. */ |
31 | #define MT9V032_PIXEL_ARRAY_WIDTH 782 | 31 | #define MT9V032_PIXEL_ARRAY_HEIGHT 485 |
32 | #define MT9V032_PIXEL_ARRAY_WIDTH 753 | ||
32 | 33 | ||
33 | #define MT9V032_SYSCLK_FREQ_DEF 26600000 | 34 | #define MT9V032_SYSCLK_FREQ_DEF 26600000 |
34 | 35 | ||
35 | #define MT9V032_CHIP_VERSION 0x00 | 36 | #define MT9V032_CHIP_VERSION 0x00 |
36 | #define MT9V032_CHIP_ID_REV1 0x1311 | 37 | #define MT9V032_CHIP_ID_REV1 0x1311 |
37 | #define MT9V032_CHIP_ID_REV3 0x1313 | 38 | #define MT9V032_CHIP_ID_REV3 0x1313 |
39 | #define MT9V034_CHIP_ID_REV1 0X1324 | ||
38 | #define MT9V032_COLUMN_START 0x01 | 40 | #define MT9V032_COLUMN_START 0x01 |
39 | #define MT9V032_COLUMN_START_MIN 1 | 41 | #define MT9V032_COLUMN_START_MIN 1 |
40 | #define MT9V032_COLUMN_START_DEF 1 | 42 | #define MT9V032_COLUMN_START_DEF 1 |
@@ -53,12 +55,15 @@ | |||
53 | #define MT9V032_WINDOW_WIDTH_MAX 752 | 55 | #define MT9V032_WINDOW_WIDTH_MAX 752 |
54 | #define MT9V032_HORIZONTAL_BLANKING 0x05 | 56 | #define MT9V032_HORIZONTAL_BLANKING 0x05 |
55 | #define MT9V032_HORIZONTAL_BLANKING_MIN 43 | 57 | #define MT9V032_HORIZONTAL_BLANKING_MIN 43 |
58 | #define MT9V034_HORIZONTAL_BLANKING_MIN 61 | ||
56 | #define MT9V032_HORIZONTAL_BLANKING_DEF 94 | 59 | #define MT9V032_HORIZONTAL_BLANKING_DEF 94 |
57 | #define MT9V032_HORIZONTAL_BLANKING_MAX 1023 | 60 | #define MT9V032_HORIZONTAL_BLANKING_MAX 1023 |
58 | #define MT9V032_VERTICAL_BLANKING 0x06 | 61 | #define MT9V032_VERTICAL_BLANKING 0x06 |
59 | #define MT9V032_VERTICAL_BLANKING_MIN 4 | 62 | #define MT9V032_VERTICAL_BLANKING_MIN 4 |
63 | #define MT9V034_VERTICAL_BLANKING_MIN 2 | ||
60 | #define MT9V032_VERTICAL_BLANKING_DEF 45 | 64 | #define MT9V032_VERTICAL_BLANKING_DEF 45 |
61 | #define MT9V032_VERTICAL_BLANKING_MAX 3000 | 65 | #define MT9V032_VERTICAL_BLANKING_MAX 3000 |
66 | #define MT9V034_VERTICAL_BLANKING_MAX 32288 | ||
62 | #define MT9V032_CHIP_CONTROL 0x07 | 67 | #define MT9V032_CHIP_CONTROL 0x07 |
63 | #define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3) | 68 | #define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3) |
64 | #define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7) | 69 | #define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7) |
@@ -68,8 +73,10 @@ | |||
68 | #define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a | 73 | #define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a |
69 | #define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b | 74 | #define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b |
70 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1 | 75 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1 |
76 | #define MT9V034_TOTAL_SHUTTER_WIDTH_MIN 0 | ||
71 | #define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480 | 77 | #define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480 |
72 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767 | 78 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767 |
79 | #define MT9V034_TOTAL_SHUTTER_WIDTH_MAX 32765 | ||
73 | #define MT9V032_RESET 0x0c | 80 | #define MT9V032_RESET 0x0c |
74 | #define MT9V032_READ_MODE 0x0d | 81 | #define MT9V032_READ_MODE 0x0d |
75 | #define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0) | 82 | #define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0) |
@@ -81,6 +88,8 @@ | |||
81 | #define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6) | 88 | #define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6) |
82 | #define MT9V032_READ_MODE_DARK_ROWS (1 << 7) | 89 | #define MT9V032_READ_MODE_DARK_ROWS (1 << 7) |
83 | #define MT9V032_PIXEL_OPERATION_MODE 0x0f | 90 | #define MT9V032_PIXEL_OPERATION_MODE 0x0f |
91 | #define MT9V034_PIXEL_OPERATION_MODE_HDR (1 << 0) | ||
92 | #define MT9V034_PIXEL_OPERATION_MODE_COLOR (1 << 1) | ||
84 | #define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2) | 93 | #define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2) |
85 | #define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6) | 94 | #define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6) |
86 | #define MT9V032_ANALOG_GAIN 0x35 | 95 | #define MT9V032_ANALOG_GAIN 0x35 |
@@ -96,9 +105,12 @@ | |||
96 | #define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8) | 105 | #define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8) |
97 | #define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8 | 106 | #define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8 |
98 | #define MT9V032_ROW_NOISE_CORR_CONTROL 0x70 | 107 | #define MT9V032_ROW_NOISE_CORR_CONTROL 0x70 |
108 | #define MT9V034_ROW_NOISE_CORR_ENABLE (1 << 0) | ||
109 | #define MT9V034_ROW_NOISE_CORR_USE_BLK_AVG (1 << 1) | ||
99 | #define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5) | 110 | #define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5) |
100 | #define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7) | 111 | #define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7) |
101 | #define MT9V032_PIXEL_CLOCK 0x74 | 112 | #define MT9V032_PIXEL_CLOCK 0x74 |
113 | #define MT9V034_PIXEL_CLOCK 0x72 | ||
102 | #define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0) | 114 | #define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0) |
103 | #define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1) | 115 | #define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1) |
104 | #define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2) | 116 | #define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2) |
@@ -120,12 +132,88 @@ | |||
120 | #define MT9V032_AGC_ENABLE (1 << 1) | 132 | #define MT9V032_AGC_ENABLE (1 << 1) |
121 | #define MT9V032_THERMAL_INFO 0xc1 | 133 | #define MT9V032_THERMAL_INFO 0xc1 |
122 | 134 | ||
135 | enum mt9v032_model { | ||
136 | MT9V032_MODEL_V032_COLOR, | ||
137 | MT9V032_MODEL_V032_MONO, | ||
138 | MT9V032_MODEL_V034_COLOR, | ||
139 | MT9V032_MODEL_V034_MONO, | ||
140 | }; | ||
141 | |||
142 | struct mt9v032_model_version { | ||
143 | unsigned int version; | ||
144 | const char *name; | ||
145 | }; | ||
146 | |||
147 | struct mt9v032_model_data { | ||
148 | unsigned int min_row_time; | ||
149 | unsigned int min_hblank; | ||
150 | unsigned int min_vblank; | ||
151 | unsigned int max_vblank; | ||
152 | unsigned int min_shutter; | ||
153 | unsigned int max_shutter; | ||
154 | unsigned int pclk_reg; | ||
155 | }; | ||
156 | |||
157 | struct mt9v032_model_info { | ||
158 | const struct mt9v032_model_data *data; | ||
159 | bool color; | ||
160 | }; | ||
161 | |||
162 | static const struct mt9v032_model_version mt9v032_versions[] = { | ||
163 | { MT9V032_CHIP_ID_REV1, "MT9V032 rev1/2" }, | ||
164 | { MT9V032_CHIP_ID_REV3, "MT9V032 rev3" }, | ||
165 | { MT9V034_CHIP_ID_REV1, "MT9V034 rev1" }, | ||
166 | }; | ||
167 | |||
168 | static const struct mt9v032_model_data mt9v032_model_data[] = { | ||
169 | { | ||
170 | /* MT9V032 revisions 1/2/3 */ | ||
171 | .min_row_time = 660, | ||
172 | .min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN, | ||
173 | .min_vblank = MT9V032_VERTICAL_BLANKING_MIN, | ||
174 | .max_vblank = MT9V032_VERTICAL_BLANKING_MAX, | ||
175 | .min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN, | ||
176 | .max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX, | ||
177 | .pclk_reg = MT9V032_PIXEL_CLOCK, | ||
178 | }, { | ||
179 | /* MT9V034 */ | ||
180 | .min_row_time = 690, | ||
181 | .min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN, | ||
182 | .min_vblank = MT9V034_VERTICAL_BLANKING_MIN, | ||
183 | .max_vblank = MT9V034_VERTICAL_BLANKING_MAX, | ||
184 | .min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN, | ||
185 | .max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX, | ||
186 | .pclk_reg = MT9V034_PIXEL_CLOCK, | ||
187 | }, | ||
188 | }; | ||
189 | |||
190 | static const struct mt9v032_model_info mt9v032_models[] = { | ||
191 | [MT9V032_MODEL_V032_COLOR] = { | ||
192 | .data = &mt9v032_model_data[0], | ||
193 | .color = true, | ||
194 | }, | ||
195 | [MT9V032_MODEL_V032_MONO] = { | ||
196 | .data = &mt9v032_model_data[0], | ||
197 | .color = false, | ||
198 | }, | ||
199 | [MT9V032_MODEL_V034_COLOR] = { | ||
200 | .data = &mt9v032_model_data[1], | ||
201 | .color = true, | ||
202 | }, | ||
203 | [MT9V032_MODEL_V034_MONO] = { | ||
204 | .data = &mt9v032_model_data[1], | ||
205 | .color = false, | ||
206 | }, | ||
207 | }; | ||
208 | |||
123 | struct mt9v032 { | 209 | struct mt9v032 { |
124 | struct v4l2_subdev subdev; | 210 | struct v4l2_subdev subdev; |
125 | struct media_pad pad; | 211 | struct media_pad pad; |
126 | 212 | ||
127 | struct v4l2_mbus_framefmt format; | 213 | struct v4l2_mbus_framefmt format; |
128 | struct v4l2_rect crop; | 214 | struct v4l2_rect crop; |
215 | unsigned int hratio; | ||
216 | unsigned int vratio; | ||
129 | 217 | ||
130 | struct v4l2_ctrl_handler ctrls; | 218 | struct v4l2_ctrl_handler ctrls; |
131 | struct { | 219 | struct { |
@@ -139,6 +227,8 @@ struct mt9v032 { | |||
139 | struct clk *clk; | 227 | struct clk *clk; |
140 | 228 | ||
141 | struct mt9v032_platform_data *pdata; | 229 | struct mt9v032_platform_data *pdata; |
230 | const struct mt9v032_model_info *model; | ||
231 | const struct mt9v032_model_version *version; | ||
142 | 232 | ||
143 | u32 sysclk; | 233 | u32 sysclk; |
144 | u16 chip_control; | 234 | u16 chip_control; |
@@ -210,12 +300,17 @@ mt9v032_update_hblank(struct mt9v032 *mt9v032) | |||
210 | { | 300 | { |
211 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | 301 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); |
212 | struct v4l2_rect *crop = &mt9v032->crop; | 302 | struct v4l2_rect *crop = &mt9v032->crop; |
303 | unsigned int min_hblank = mt9v032->model->data->min_hblank; | ||
304 | unsigned int hblank; | ||
213 | 305 | ||
214 | return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, | 306 | if (mt9v032->version->version == MT9V034_CHIP_ID_REV1) |
215 | max_t(s32, mt9v032->hblank, 660 - crop->width)); | 307 | min_hblank += (mt9v032->hratio - 1) * 10; |
216 | } | 308 | min_hblank = max_t(unsigned int, (int)mt9v032->model->data->min_row_time - crop->width, |
309 | (int)min_hblank); | ||
310 | hblank = max_t(unsigned int, mt9v032->hblank, min_hblank); | ||
217 | 311 | ||
218 | #define EXT_CLK 25000000 | 312 | return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, hblank); |
313 | } | ||
219 | 314 | ||
220 | static int mt9v032_power_on(struct mt9v032 *mt9v032) | 315 | static int mt9v032_power_on(struct mt9v032 *mt9v032) |
221 | { | 316 | { |
@@ -259,7 +354,7 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) | |||
259 | 354 | ||
260 | /* Configure the pixel clock polarity */ | 355 | /* Configure the pixel clock polarity */ |
261 | if (mt9v032->pdata && mt9v032->pdata->clk_pol) { | 356 | if (mt9v032->pdata && mt9v032->pdata->clk_pol) { |
262 | ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK, | 357 | ret = mt9v032_write(client, mt9v032->model->data->pclk_reg, |
263 | MT9V032_PIXEL_CLOCK_INV_PXL_CLK); | 358 | MT9V032_PIXEL_CLOCK_INV_PXL_CLK); |
264 | if (ret < 0) | 359 | if (ret < 0) |
265 | return ret; | 360 | return ret; |
@@ -312,22 +407,20 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) | |||
312 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; | 407 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; |
313 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | 408 | struct i2c_client *client = v4l2_get_subdevdata(subdev); |
314 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | 409 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); |
315 | struct v4l2_mbus_framefmt *format = &mt9v032->format; | ||
316 | struct v4l2_rect *crop = &mt9v032->crop; | 410 | struct v4l2_rect *crop = &mt9v032->crop; |
317 | unsigned int hratio; | 411 | unsigned int hbin; |
318 | unsigned int vratio; | 412 | unsigned int vbin; |
319 | int ret; | 413 | int ret; |
320 | 414 | ||
321 | if (!enable) | 415 | if (!enable) |
322 | return mt9v032_set_chip_control(mt9v032, mode, 0); | 416 | return mt9v032_set_chip_control(mt9v032, mode, 0); |
323 | 417 | ||
324 | /* Configure the window size and row/column bin */ | 418 | /* Configure the window size and row/column bin */ |
325 | hratio = DIV_ROUND_CLOSEST(crop->width, format->width); | 419 | hbin = fls(mt9v032->hratio) - 1; |
326 | vratio = DIV_ROUND_CLOSEST(crop->height, format->height); | 420 | vbin = fls(mt9v032->vratio) - 1; |
327 | |||
328 | ret = mt9v032_write(client, MT9V032_READ_MODE, | 421 | ret = mt9v032_write(client, MT9V032_READ_MODE, |
329 | (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT | | 422 | hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT | |
330 | (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT); | 423 | vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT); |
331 | if (ret < 0) | 424 | if (ret < 0) |
332 | return ret; | 425 | return ret; |
333 | 426 | ||
@@ -370,12 +463,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, | |||
370 | struct v4l2_subdev_fh *fh, | 463 | struct v4l2_subdev_fh *fh, |
371 | struct v4l2_subdev_frame_size_enum *fse) | 464 | struct v4l2_subdev_frame_size_enum *fse) |
372 | { | 465 | { |
373 | if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10) | 466 | if (fse->index >= 3 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10) |
374 | return -EINVAL; | 467 | return -EINVAL; |
375 | 468 | ||
376 | fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index; | 469 | fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index); |
377 | fse->max_width = fse->min_width; | 470 | fse->max_width = fse->min_width; |
378 | fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index; | 471 | fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / (1 << fse->index); |
379 | fse->max_height = fse->min_height; | 472 | fse->max_height = fse->min_height; |
380 | 473 | ||
381 | return 0; | 474 | return 0; |
@@ -392,18 +485,30 @@ static int mt9v032_get_format(struct v4l2_subdev *subdev, | |||
392 | return 0; | 485 | return 0; |
393 | } | 486 | } |
394 | 487 | ||
395 | static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032, | 488 | static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032) |
396 | unsigned int hratio) | ||
397 | { | 489 | { |
398 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | 490 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); |
399 | int ret; | 491 | int ret; |
400 | 492 | ||
401 | ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate, | 493 | ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate, |
402 | mt9v032->sysclk / hratio); | 494 | mt9v032->sysclk / mt9v032->hratio); |
403 | if (ret < 0) | 495 | if (ret < 0) |
404 | dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret); | 496 | dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret); |
405 | } | 497 | } |
406 | 498 | ||
499 | static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output) | ||
500 | { | ||
501 | /* Compute the power-of-two binning factor closest to the input size to | ||
502 | * output size ratio. Given that the output size is bounded by input/4 | ||
503 | * and input, a generic implementation would be an ineffective luxury. | ||
504 | */ | ||
505 | if (output * 3 > input * 2) | ||
506 | return 1; | ||
507 | if (output * 3 > input) | ||
508 | return 2; | ||
509 | return 4; | ||
510 | } | ||
511 | |||
407 | static int mt9v032_set_format(struct v4l2_subdev *subdev, | 512 | static int mt9v032_set_format(struct v4l2_subdev *subdev, |
408 | struct v4l2_subdev_fh *fh, | 513 | struct v4l2_subdev_fh *fh, |
409 | struct v4l2_subdev_format *format) | 514 | struct v4l2_subdev_format *format) |
@@ -420,22 +525,28 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, | |||
420 | format->which); | 525 | format->which); |
421 | 526 | ||
422 | /* Clamp the width and height to avoid dividing by zero. */ | 527 | /* Clamp the width and height to avoid dividing by zero. */ |
423 | width = clamp_t(unsigned int, ALIGN(format->format.width, 2), | 528 | width = clamp(ALIGN(format->format.width, 2), |
424 | max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN), | 529 | max_t(unsigned int, __crop->width / 4, |
425 | __crop->width); | 530 | MT9V032_WINDOW_WIDTH_MIN), |
426 | height = clamp_t(unsigned int, ALIGN(format->format.height, 2), | 531 | __crop->width); |
427 | max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN), | 532 | height = clamp(ALIGN(format->format.height, 2), |
428 | __crop->height); | 533 | max_t(unsigned int, __crop->height / 4, |
429 | 534 | MT9V032_WINDOW_HEIGHT_MIN), | |
430 | hratio = DIV_ROUND_CLOSEST(__crop->width, width); | 535 | __crop->height); |
431 | vratio = DIV_ROUND_CLOSEST(__crop->height, height); | 536 | |
537 | hratio = mt9v032_calc_ratio(__crop->width, width); | ||
538 | vratio = mt9v032_calc_ratio(__crop->height, height); | ||
432 | 539 | ||
433 | __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, | 540 | __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, |
434 | format->which); | 541 | format->which); |
435 | __format->width = __crop->width / hratio; | 542 | __format->width = __crop->width / hratio; |
436 | __format->height = __crop->height / vratio; | 543 | __format->height = __crop->height / vratio; |
437 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 544 | |
438 | mt9v032_configure_pixel_rate(mt9v032, hratio); | 545 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
546 | mt9v032->hratio = hratio; | ||
547 | mt9v032->vratio = vratio; | ||
548 | mt9v032_configure_pixel_rate(mt9v032); | ||
549 | } | ||
439 | 550 | ||
440 | format->format = *__format; | 551 | format->format = *__format; |
441 | 552 | ||
@@ -471,15 +582,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, | |||
471 | rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1, | 582 | rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1, |
472 | MT9V032_ROW_START_MIN, | 583 | MT9V032_ROW_START_MIN, |
473 | MT9V032_ROW_START_MAX); | 584 | MT9V032_ROW_START_MAX); |
474 | rect.width = clamp(ALIGN(crop->rect.width, 2), | 585 | rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), |
475 | MT9V032_WINDOW_WIDTH_MIN, | 586 | MT9V032_WINDOW_WIDTH_MIN, |
476 | MT9V032_WINDOW_WIDTH_MAX); | 587 | MT9V032_WINDOW_WIDTH_MAX); |
477 | rect.height = clamp(ALIGN(crop->rect.height, 2), | 588 | rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), |
478 | MT9V032_WINDOW_HEIGHT_MIN, | 589 | MT9V032_WINDOW_HEIGHT_MIN, |
479 | MT9V032_WINDOW_HEIGHT_MAX); | 590 | MT9V032_WINDOW_HEIGHT_MAX); |
480 | 591 | ||
481 | rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left); | 592 | rect.width = min_t(unsigned int, |
482 | rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); | 593 | rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left); |
594 | rect.height = min_t(unsigned int, | ||
595 | rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); | ||
483 | 596 | ||
484 | __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); | 597 | __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); |
485 | 598 | ||
@@ -491,8 +604,11 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, | |||
491 | crop->which); | 604 | crop->which); |
492 | __format->width = rect.width; | 605 | __format->width = rect.width; |
493 | __format->height = rect.height; | 606 | __format->height = rect.height; |
494 | if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 607 | if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
495 | mt9v032_configure_pixel_rate(mt9v032, 1); | 608 | mt9v032->hratio = 1; |
609 | mt9v032->vratio = 1; | ||
610 | mt9v032_configure_pixel_rate(mt9v032); | ||
611 | } | ||
496 | } | 612 | } |
497 | 613 | ||
498 | *__crop = rect; | 614 | *__crop = rect; |
@@ -641,7 +757,8 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) | |||
641 | { | 757 | { |
642 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | 758 | struct i2c_client *client = v4l2_get_subdevdata(subdev); |
643 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | 759 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); |
644 | s32 data; | 760 | unsigned int i; |
761 | s32 version; | ||
645 | int ret; | 762 | int ret; |
646 | 763 | ||
647 | dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", | 764 | dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", |
@@ -654,25 +771,38 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) | |||
654 | } | 771 | } |
655 | 772 | ||
656 | /* Read and check the sensor version */ | 773 | /* Read and check the sensor version */ |
657 | data = mt9v032_read(client, MT9V032_CHIP_VERSION); | 774 | version = mt9v032_read(client, MT9V032_CHIP_VERSION); |
658 | if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) { | 775 | if (version < 0) { |
659 | dev_err(&client->dev, "MT9V032 not detected, wrong version " | 776 | dev_err(&client->dev, "Failed reading chip version\n"); |
660 | "0x%04x\n", data); | 777 | return version; |
778 | } | ||
779 | |||
780 | for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) { | ||
781 | if (mt9v032_versions[i].version == version) { | ||
782 | mt9v032->version = &mt9v032_versions[i]; | ||
783 | break; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | if (mt9v032->version == NULL) { | ||
788 | dev_err(&client->dev, "Unsupported chip version 0x%04x\n", | ||
789 | version); | ||
661 | return -ENODEV; | 790 | return -ENODEV; |
662 | } | 791 | } |
663 | 792 | ||
664 | mt9v032_power_off(mt9v032); | 793 | mt9v032_power_off(mt9v032); |
665 | 794 | ||
666 | dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n", | 795 | dev_info(&client->dev, "%s detected at address 0x%02x\n", |
667 | client->addr); | 796 | mt9v032->version->name, client->addr); |
668 | 797 | ||
669 | mt9v032_configure_pixel_rate(mt9v032, 1); | 798 | mt9v032_configure_pixel_rate(mt9v032); |
670 | 799 | ||
671 | return ret; | 800 | return ret; |
672 | } | 801 | } |
673 | 802 | ||
674 | static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | 803 | static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) |
675 | { | 804 | { |
805 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
676 | struct v4l2_mbus_framefmt *format; | 806 | struct v4l2_mbus_framefmt *format; |
677 | struct v4l2_rect *crop; | 807 | struct v4l2_rect *crop; |
678 | 808 | ||
@@ -683,7 +813,12 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | |||
683 | crop->height = MT9V032_WINDOW_HEIGHT_DEF; | 813 | crop->height = MT9V032_WINDOW_HEIGHT_DEF; |
684 | 814 | ||
685 | format = v4l2_subdev_get_try_format(fh, 0); | 815 | format = v4l2_subdev_get_try_format(fh, 0); |
686 | format->code = V4L2_MBUS_FMT_SGRBG10_1X10; | 816 | |
817 | if (mt9v032->model->color) | ||
818 | format->code = V4L2_MBUS_FMT_SGRBG10_1X10; | ||
819 | else | ||
820 | format->code = V4L2_MBUS_FMT_Y10_1X10; | ||
821 | |||
687 | format->width = MT9V032_WINDOW_WIDTH_DEF; | 822 | format->width = MT9V032_WINDOW_WIDTH_DEF; |
688 | format->height = MT9V032_WINDOW_HEIGHT_DEF; | 823 | format->height = MT9V032_WINDOW_HEIGHT_DEF; |
689 | format->field = V4L2_FIELD_NONE; | 824 | format->field = V4L2_FIELD_NONE; |
@@ -755,6 +890,7 @@ static int mt9v032_probe(struct i2c_client *client, | |||
755 | 890 | ||
756 | mutex_init(&mt9v032->power_lock); | 891 | mutex_init(&mt9v032->power_lock); |
757 | mt9v032->pdata = pdata; | 892 | mt9v032->pdata = pdata; |
893 | mt9v032->model = (const void *)did->driver_data; | ||
758 | 894 | ||
759 | v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); | 895 | v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); |
760 | 896 | ||
@@ -767,16 +903,16 @@ static int mt9v032_probe(struct i2c_client *client, | |||
767 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, | 903 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, |
768 | V4L2_EXPOSURE_AUTO); | 904 | V4L2_EXPOSURE_AUTO); |
769 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | 905 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
770 | V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN, | 906 | V4L2_CID_EXPOSURE, mt9v032->model->data->min_shutter, |
771 | MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1, | 907 | mt9v032->model->data->max_shutter, 1, |
772 | MT9V032_TOTAL_SHUTTER_WIDTH_DEF); | 908 | MT9V032_TOTAL_SHUTTER_WIDTH_DEF); |
773 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | 909 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
774 | V4L2_CID_HBLANK, MT9V032_HORIZONTAL_BLANKING_MIN, | 910 | V4L2_CID_HBLANK, mt9v032->model->data->min_hblank, |
775 | MT9V032_HORIZONTAL_BLANKING_MAX, 1, | 911 | MT9V032_HORIZONTAL_BLANKING_MAX, 1, |
776 | MT9V032_HORIZONTAL_BLANKING_DEF); | 912 | MT9V032_HORIZONTAL_BLANKING_DEF); |
777 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | 913 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
778 | V4L2_CID_VBLANK, MT9V032_VERTICAL_BLANKING_MIN, | 914 | V4L2_CID_VBLANK, mt9v032->model->data->min_vblank, |
779 | MT9V032_VERTICAL_BLANKING_MAX, 1, | 915 | mt9v032->model->data->max_vblank, 1, |
780 | MT9V032_VERTICAL_BLANKING_DEF); | 916 | MT9V032_VERTICAL_BLANKING_DEF); |
781 | mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls, | 917 | mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls, |
782 | &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN, | 918 | &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN, |
@@ -819,12 +955,19 @@ static int mt9v032_probe(struct i2c_client *client, | |||
819 | mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF; | 955 | mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF; |
820 | mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF; | 956 | mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF; |
821 | 957 | ||
822 | mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10; | 958 | if (mt9v032->model->color) |
959 | mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10; | ||
960 | else | ||
961 | mt9v032->format.code = V4L2_MBUS_FMT_Y10_1X10; | ||
962 | |||
823 | mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF; | 963 | mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF; |
824 | mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF; | 964 | mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF; |
825 | mt9v032->format.field = V4L2_FIELD_NONE; | 965 | mt9v032->format.field = V4L2_FIELD_NONE; |
826 | mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB; | 966 | mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB; |
827 | 967 | ||
968 | mt9v032->hratio = 1; | ||
969 | mt9v032->vratio = 1; | ||
970 | |||
828 | mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE; | 971 | mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE; |
829 | mt9v032->hblank = MT9V032_HORIZONTAL_BLANKING_DEF; | 972 | mt9v032->hblank = MT9V032_HORIZONTAL_BLANKING_DEF; |
830 | mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF; | 973 | mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF; |
@@ -855,7 +998,10 @@ static int mt9v032_remove(struct i2c_client *client) | |||
855 | } | 998 | } |
856 | 999 | ||
857 | static const struct i2c_device_id mt9v032_id[] = { | 1000 | static const struct i2c_device_id mt9v032_id[] = { |
858 | { "mt9v032", 0 }, | 1001 | { "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] }, |
1002 | { "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] }, | ||
1003 | { "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] }, | ||
1004 | { "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] }, | ||
859 | { } | 1005 | { } |
860 | }; | 1006 | }; |
861 | MODULE_DEVICE_TABLE(i2c, mt9v032_id); | 1007 | MODULE_DEVICE_TABLE(i2c, mt9v032_id); |
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c new file mode 100644 index 000000000000..4b8381111cbd --- /dev/null +++ b/drivers/media/i2c/s5k5baf.c | |||
@@ -0,0 +1,2045 @@ | |||
1 | /* | ||
2 | * Driver for Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor | ||
3 | * with embedded SoC ISP. | ||
4 | * | ||
5 | * Copyright (C) 2013, Samsung Electronics Co., Ltd. | ||
6 | * Andrzej Hajda <a.hajda@samsung.com> | ||
7 | * | ||
8 | * Based on S5K6AA driver authored by Sylwester Nawrocki | ||
9 | * Copyright (C) 2013, Samsung Electronics Co., Ltd. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/firmware.h> | ||
19 | #include <linux/gpio.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/media.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of_gpio.h> | ||
24 | #include <linux/regulator/consumer.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include <media/media-entity.h> | ||
28 | #include <media/v4l2-ctrls.h> | ||
29 | #include <media/v4l2-device.h> | ||
30 | #include <media/v4l2-subdev.h> | ||
31 | #include <media/v4l2-mediabus.h> | ||
32 | #include <media/v4l2-of.h> | ||
33 | |||
34 | static int debug; | ||
35 | module_param(debug, int, 0644); | ||
36 | |||
37 | #define S5K5BAF_DRIVER_NAME "s5k5baf" | ||
38 | #define S5K5BAF_DEFAULT_MCLK_FREQ 24000000U | ||
39 | #define S5K5BAF_CLK_NAME "mclk" | ||
40 | |||
41 | #define S5K5BAF_FW_FILENAME "s5k5baf-cfg.bin" | ||
42 | #define S5K5BAF_FW_TAG "SF00" | ||
43 | #define S5K5BAG_FW_TAG_LEN 2 | ||
44 | #define S5K5BAG_FW_MAX_COUNT 16 | ||
45 | |||
46 | #define S5K5BAF_CIS_WIDTH 1600 | ||
47 | #define S5K5BAF_CIS_HEIGHT 1200 | ||
48 | #define S5K5BAF_WIN_WIDTH_MIN 8 | ||
49 | #define S5K5BAF_WIN_HEIGHT_MIN 8 | ||
50 | #define S5K5BAF_GAIN_RED_DEF 127 | ||
51 | #define S5K5BAF_GAIN_GREEN_DEF 95 | ||
52 | #define S5K5BAF_GAIN_BLUE_DEF 180 | ||
53 | /* Default number of MIPI CSI-2 data lanes used */ | ||
54 | #define S5K5BAF_DEF_NUM_LANES 1 | ||
55 | |||
56 | #define AHB_MSB_ADDR_PTR 0xfcfc | ||
57 | |||
58 | /* | ||
59 | * Register interface pages (the most significant word of the address) | ||
60 | */ | ||
61 | #define PAGE_IF_HW 0xd000 | ||
62 | #define PAGE_IF_SW 0x7000 | ||
63 | |||
64 | /* | ||
65 | * H/W register Interface (PAGE_IF_HW) | ||
66 | */ | ||
67 | #define REG_SW_LOAD_COMPLETE 0x0014 | ||
68 | #define REG_CMDWR_PAGE 0x0028 | ||
69 | #define REG_CMDWR_ADDR 0x002a | ||
70 | #define REG_CMDRD_PAGE 0x002c | ||
71 | #define REG_CMDRD_ADDR 0x002e | ||
72 | #define REG_CMD_BUF 0x0f12 | ||
73 | #define REG_SET_HOST_INT 0x1000 | ||
74 | #define REG_CLEAR_HOST_INT 0x1030 | ||
75 | #define REG_PATTERN_SET 0x3100 | ||
76 | #define REG_PATTERN_WIDTH 0x3118 | ||
77 | #define REG_PATTERN_HEIGHT 0x311a | ||
78 | #define REG_PATTERN_PARAM 0x311c | ||
79 | |||
80 | /* | ||
81 | * S/W register interface (PAGE_IF_SW) | ||
82 | */ | ||
83 | |||
84 | /* Firmware revision information */ | ||
85 | #define REG_FW_APIVER 0x012e | ||
86 | #define S5K5BAF_FW_APIVER 0x0001 | ||
87 | #define REG_FW_REVISION 0x0130 | ||
88 | #define REG_FW_SENSOR_ID 0x0152 | ||
89 | |||
90 | /* Initialization parameters */ | ||
91 | /* Master clock frequency in KHz */ | ||
92 | #define REG_I_INCLK_FREQ_L 0x01b8 | ||
93 | #define REG_I_INCLK_FREQ_H 0x01ba | ||
94 | #define MIN_MCLK_FREQ_KHZ 6000U | ||
95 | #define MAX_MCLK_FREQ_KHZ 48000U | ||
96 | #define REG_I_USE_NPVI_CLOCKS 0x01c6 | ||
97 | #define NPVI_CLOCKS 1 | ||
98 | #define REG_I_USE_NMIPI_CLOCKS 0x01c8 | ||
99 | #define NMIPI_CLOCKS 1 | ||
100 | #define REG_I_BLOCK_INTERNAL_PLL_CALC 0x01ca | ||
101 | |||
102 | /* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */ | ||
103 | #define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc) | ||
104 | #define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce) | ||
105 | #define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0) | ||
106 | #define SCLK_PVI_FREQ 24000 | ||
107 | #define SCLK_MIPI_FREQ 48000 | ||
108 | #define PCLK_MIN_FREQ 6000 | ||
109 | #define PCLK_MAX_FREQ 48000 | ||
110 | #define REG_I_USE_REGS_API 0x01de | ||
111 | #define REG_I_INIT_PARAMS_UPDATED 0x01e0 | ||
112 | #define REG_I_ERROR_INFO 0x01e2 | ||
113 | |||
114 | /* General purpose parameters */ | ||
115 | #define REG_USER_BRIGHTNESS 0x01e4 | ||
116 | #define REG_USER_CONTRAST 0x01e6 | ||
117 | #define REG_USER_SATURATION 0x01e8 | ||
118 | #define REG_USER_SHARPBLUR 0x01ea | ||
119 | |||
120 | #define REG_G_SPEC_EFFECTS 0x01ee | ||
121 | #define REG_G_ENABLE_PREV 0x01f0 | ||
122 | #define REG_G_ENABLE_PREV_CHG 0x01f2 | ||
123 | #define REG_G_NEW_CFG_SYNC 0x01f8 | ||
124 | #define REG_G_PREVREQ_IN_WIDTH 0x01fa | ||
125 | #define REG_G_PREVREQ_IN_HEIGHT 0x01fc | ||
126 | #define REG_G_PREVREQ_IN_XOFFS 0x01fe | ||
127 | #define REG_G_PREVREQ_IN_YOFFS 0x0200 | ||
128 | #define REG_G_PREVZOOM_IN_WIDTH 0x020a | ||
129 | #define REG_G_PREVZOOM_IN_HEIGHT 0x020c | ||
130 | #define REG_G_PREVZOOM_IN_XOFFS 0x020e | ||
131 | #define REG_G_PREVZOOM_IN_YOFFS 0x0210 | ||
132 | #define REG_G_INPUTS_CHANGE_REQ 0x021a | ||
133 | #define REG_G_ACTIVE_PREV_CFG 0x021c | ||
134 | #define REG_G_PREV_CFG_CHG 0x021e | ||
135 | #define REG_G_PREV_OPEN_AFTER_CH 0x0220 | ||
136 | #define REG_G_PREV_CFG_ERROR 0x0222 | ||
137 | #define CFG_ERROR_RANGE 0x0b | ||
138 | #define REG_G_PREV_CFG_BYPASS_CHANGED 0x022a | ||
139 | #define REG_G_ACTUAL_P_FR_TIME 0x023a | ||
140 | #define REG_G_ACTUAL_P_OUT_RATE 0x023c | ||
141 | #define REG_G_ACTUAL_C_FR_TIME 0x023e | ||
142 | #define REG_G_ACTUAL_C_OUT_RATE 0x0240 | ||
143 | |||
144 | /* Preview control section. n = 0...4. */ | ||
145 | #define PREG(n, x) ((n) * 0x26 + x) | ||
146 | #define REG_P_OUT_WIDTH(n) PREG(n, 0x0242) | ||
147 | #define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244) | ||
148 | #define REG_P_FMT(n) PREG(n, 0x0246) | ||
149 | #define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248) | ||
150 | #define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a) | ||
151 | #define REG_P_PVI_MASK(n) PREG(n, 0x024c) | ||
152 | #define PVI_MASK_MIPI 0x52 | ||
153 | #define REG_P_CLK_INDEX(n) PREG(n, 0x024e) | ||
154 | #define CLK_PVI_INDEX 0 | ||
155 | #define CLK_MIPI_INDEX NPVI_CLOCKS | ||
156 | #define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250) | ||
157 | #define FR_RATE_DYNAMIC 0 | ||
158 | #define FR_RATE_FIXED 1 | ||
159 | #define FR_RATE_FIXED_ACCURATE 2 | ||
160 | #define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252) | ||
161 | #define FR_RATE_Q_DYNAMIC 0 | ||
162 | #define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */ | ||
163 | #define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */ | ||
164 | /* Frame period in 0.1 ms units */ | ||
165 | #define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254) | ||
166 | #define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256) | ||
167 | #define S5K5BAF_MIN_FR_TIME 333 /* x100 us */ | ||
168 | #define S5K5BAF_MAX_FR_TIME 6500 /* x100 us */ | ||
169 | /* The below 5 registers are for "device correction" values */ | ||
170 | #define REG_P_SATURATION(n) PREG(n, 0x0258) | ||
171 | #define REG_P_SHARP_BLUR(n) PREG(n, 0x025a) | ||
172 | #define REG_P_GLAMOUR(n) PREG(n, 0x025c) | ||
173 | #define REG_P_COLORTEMP(n) PREG(n, 0x025e) | ||
174 | #define REG_P_GAMMA_INDEX(n) PREG(n, 0x0260) | ||
175 | #define REG_P_PREV_MIRROR(n) PREG(n, 0x0262) | ||
176 | #define REG_P_CAP_MIRROR(n) PREG(n, 0x0264) | ||
177 | #define REG_P_CAP_ROTATION(n) PREG(n, 0x0266) | ||
178 | |||
179 | /* Extended image property controls */ | ||
180 | /* Exposure time in 10 us units */ | ||
181 | #define REG_SF_USR_EXPOSURE_L 0x03bc | ||
182 | #define REG_SF_USR_EXPOSURE_H 0x03be | ||
183 | #define REG_SF_USR_EXPOSURE_CHG 0x03c0 | ||
184 | #define REG_SF_USR_TOT_GAIN 0x03c2 | ||
185 | #define REG_SF_USR_TOT_GAIN_CHG 0x03c4 | ||
186 | #define REG_SF_RGAIN 0x03c6 | ||
187 | #define REG_SF_RGAIN_CHG 0x03c8 | ||
188 | #define REG_SF_GGAIN 0x03ca | ||
189 | #define REG_SF_GGAIN_CHG 0x03cc | ||
190 | #define REG_SF_BGAIN 0x03ce | ||
191 | #define REG_SF_BGAIN_CHG 0x03d0 | ||
192 | #define REG_SF_WBGAIN_CHG 0x03d2 | ||
193 | #define REG_SF_FLICKER_QUANT 0x03d4 | ||
194 | #define REG_SF_FLICKER_QUANT_CHG 0x03d6 | ||
195 | |||
196 | /* Output interface (parallel/MIPI) setup */ | ||
197 | #define REG_OIF_EN_MIPI_LANES 0x03f2 | ||
198 | #define REG_OIF_EN_PACKETS 0x03f4 | ||
199 | #define EN_PACKETS_CSI2 0xc3 | ||
200 | #define REG_OIF_CFG_CHG 0x03f6 | ||
201 | |||
202 | /* Auto-algorithms enable mask */ | ||
203 | #define REG_DBG_AUTOALG_EN 0x03f8 | ||
204 | #define AALG_ALL_EN BIT(0) | ||
205 | #define AALG_AE_EN BIT(1) | ||
206 | #define AALG_DIVLEI_EN BIT(2) | ||
207 | #define AALG_WB_EN BIT(3) | ||
208 | #define AALG_USE_WB_FOR_ISP BIT(4) | ||
209 | #define AALG_FLICKER_EN BIT(5) | ||
210 | #define AALG_FIT_EN BIT(6) | ||
211 | #define AALG_WRHW_EN BIT(7) | ||
212 | |||
213 | /* Pointers to color correction matrices */ | ||
214 | #define REG_PTR_CCM_HORIZON 0x06d0 | ||
215 | #define REG_PTR_CCM_INCANDESCENT 0x06d4 | ||
216 | #define REG_PTR_CCM_WARM_WHITE 0x06d8 | ||
217 | #define REG_PTR_CCM_COOL_WHITE 0x06dc | ||
218 | #define REG_PTR_CCM_DL50 0x06e0 | ||
219 | #define REG_PTR_CCM_DL65 0x06e4 | ||
220 | #define REG_PTR_CCM_OUTDOOR 0x06ec | ||
221 | |||
222 | #define REG_ARR_CCM(n) (0x2800 + 36 * (n)) | ||
223 | |||
224 | static const char * const s5k5baf_supply_names[] = { | ||
225 | "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */ | ||
226 | "vddreg", /* Regulator input power supply 1.8V (1.7V to 1.9V) | ||
227 | or 2.8V (2.6V to 3.0) */ | ||
228 | "vddio", /* I/O power supply 1.8V (1.65V to 1.95V) | ||
229 | or 2.8V (2.5V to 3.1V) */ | ||
230 | }; | ||
231 | #define S5K5BAF_NUM_SUPPLIES ARRAY_SIZE(s5k5baf_supply_names) | ||
232 | |||
233 | struct s5k5baf_gpio { | ||
234 | int gpio; | ||
235 | int level; | ||
236 | }; | ||
237 | |||
238 | enum s5k5baf_gpio_id { | ||
239 | STBY, | ||
240 | RST, | ||
241 | NUM_GPIOS, | ||
242 | }; | ||
243 | |||
244 | #define PAD_CIS 0 | ||
245 | #define PAD_OUT 1 | ||
246 | #define NUM_CIS_PADS 1 | ||
247 | #define NUM_ISP_PADS 2 | ||
248 | |||
249 | struct s5k5baf_pixfmt { | ||
250 | enum v4l2_mbus_pixelcode code; | ||
251 | u32 colorspace; | ||
252 | /* REG_P_FMT(x) register value */ | ||
253 | u16 reg_p_fmt; | ||
254 | }; | ||
255 | |||
256 | struct s5k5baf_ctrls { | ||
257 | struct v4l2_ctrl_handler handler; | ||
258 | struct { /* Auto / manual white balance cluster */ | ||
259 | struct v4l2_ctrl *awb; | ||
260 | struct v4l2_ctrl *gain_red; | ||
261 | struct v4l2_ctrl *gain_blue; | ||
262 | }; | ||
263 | struct { /* Mirror cluster */ | ||
264 | struct v4l2_ctrl *hflip; | ||
265 | struct v4l2_ctrl *vflip; | ||
266 | }; | ||
267 | struct { /* Auto exposure / manual exposure and gain cluster */ | ||
268 | struct v4l2_ctrl *auto_exp; | ||
269 | struct v4l2_ctrl *exposure; | ||
270 | struct v4l2_ctrl *gain; | ||
271 | }; | ||
272 | }; | ||
273 | |||
274 | enum { | ||
275 | S5K5BAF_FW_ID_PATCH, | ||
276 | S5K5BAF_FW_ID_CCM, | ||
277 | S5K5BAF_FW_ID_CIS, | ||
278 | }; | ||
279 | |||
280 | struct s5k5baf_fw { | ||
281 | u16 count; | ||
282 | struct { | ||
283 | u16 id; | ||
284 | u16 offset; | ||
285 | } seq[0]; | ||
286 | u16 data[0]; | ||
287 | }; | ||
288 | |||
289 | struct s5k5baf { | ||
290 | struct s5k5baf_gpio gpios[NUM_GPIOS]; | ||
291 | enum v4l2_mbus_type bus_type; | ||
292 | u8 nlanes; | ||
293 | struct regulator_bulk_data supplies[S5K5BAF_NUM_SUPPLIES]; | ||
294 | |||
295 | struct clk *clock; | ||
296 | u32 mclk_frequency; | ||
297 | |||
298 | struct s5k5baf_fw *fw; | ||
299 | |||
300 | struct v4l2_subdev cis_sd; | ||
301 | struct media_pad cis_pad; | ||
302 | |||
303 | struct v4l2_subdev sd; | ||
304 | struct media_pad pads[NUM_ISP_PADS]; | ||
305 | |||
306 | /* protects the struct members below */ | ||
307 | struct mutex lock; | ||
308 | |||
309 | int error; | ||
310 | |||
311 | struct v4l2_rect crop_sink; | ||
312 | struct v4l2_rect compose; | ||
313 | struct v4l2_rect crop_source; | ||
314 | /* index to s5k5baf_formats array */ | ||
315 | int pixfmt; | ||
316 | /* actual frame interval in 100us */ | ||
317 | u16 fiv; | ||
318 | /* requested frame interval in 100us */ | ||
319 | u16 req_fiv; | ||
320 | /* cache for REG_DBG_AUTOALG_EN register */ | ||
321 | u16 auto_alg; | ||
322 | |||
323 | struct s5k5baf_ctrls ctrls; | ||
324 | |||
325 | unsigned int streaming:1; | ||
326 | unsigned int apply_cfg:1; | ||
327 | unsigned int apply_crop:1; | ||
328 | unsigned int valid_auto_alg:1; | ||
329 | unsigned int power; | ||
330 | }; | ||
331 | |||
332 | static const struct s5k5baf_pixfmt s5k5baf_formats[] = { | ||
333 | { V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG, 5 }, | ||
334 | /* range 16-240 */ | ||
335 | { V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_REC709, 6 }, | ||
336 | { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 }, | ||
337 | }; | ||
338 | |||
339 | static struct v4l2_rect s5k5baf_cis_rect = { | ||
340 | 0, 0, S5K5BAF_CIS_WIDTH, S5K5BAF_CIS_HEIGHT | ||
341 | }; | ||
342 | |||
343 | /* Setfile contains set of I2C command sequences. Each sequence has its ID. | ||
344 | * setfile format: | ||
345 | * u8 magic[4]; | ||
346 | * u16 count; number of sequences | ||
347 | * struct { | ||
348 | * u16 id; sequence id | ||
349 | * u16 offset; sequence offset in data array | ||
350 | * } seq[count]; | ||
351 | * u16 data[*]; array containing sequences | ||
352 | * | ||
353 | */ | ||
354 | static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw, | ||
355 | size_t count, const u16 *data) | ||
356 | { | ||
357 | struct s5k5baf_fw *f; | ||
358 | u16 *d, i, *end; | ||
359 | int ret; | ||
360 | |||
361 | if (count < S5K5BAG_FW_TAG_LEN + 1) { | ||
362 | dev_err(dev, "firmware file too short (%zu)\n", count); | ||
363 | return -EINVAL; | ||
364 | } | ||
365 | |||
366 | ret = memcmp(data, S5K5BAF_FW_TAG, S5K5BAG_FW_TAG_LEN * sizeof(u16)); | ||
367 | if (ret != 0) { | ||
368 | dev_err(dev, "invalid firmware magic number\n"); | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | |||
372 | data += S5K5BAG_FW_TAG_LEN; | ||
373 | count -= S5K5BAG_FW_TAG_LEN; | ||
374 | |||
375 | d = devm_kzalloc(dev, count * sizeof(u16), GFP_KERNEL); | ||
376 | |||
377 | for (i = 0; i < count; ++i) | ||
378 | d[i] = le16_to_cpu(data[i]); | ||
379 | |||
380 | f = (struct s5k5baf_fw *)d; | ||
381 | if (count < 1 + 2 * f->count) { | ||
382 | dev_err(dev, "invalid firmware header (count=%d size=%zu)\n", | ||
383 | f->count, 2 * (count + S5K5BAG_FW_TAG_LEN)); | ||
384 | return -EINVAL; | ||
385 | } | ||
386 | end = d + count; | ||
387 | d += 1 + 2 * f->count; | ||
388 | |||
389 | for (i = 0; i < f->count; ++i) { | ||
390 | if (f->seq[i].offset + d <= end) | ||
391 | continue; | ||
392 | dev_err(dev, "invalid firmware header (seq=%d)\n", i); | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | *fw = f; | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) | ||
402 | { | ||
403 | return &container_of(ctrl->handler, struct s5k5baf, ctrls.handler)->sd; | ||
404 | } | ||
405 | |||
406 | static inline bool s5k5baf_is_cis_subdev(struct v4l2_subdev *sd) | ||
407 | { | ||
408 | return sd->entity.type == MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
409 | } | ||
410 | |||
411 | static inline struct s5k5baf *to_s5k5baf(struct v4l2_subdev *sd) | ||
412 | { | ||
413 | if (s5k5baf_is_cis_subdev(sd)) | ||
414 | return container_of(sd, struct s5k5baf, cis_sd); | ||
415 | else | ||
416 | return container_of(sd, struct s5k5baf, sd); | ||
417 | } | ||
418 | |||
419 | static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr) | ||
420 | { | ||
421 | struct i2c_client *c = v4l2_get_subdevdata(&state->sd); | ||
422 | __be16 w, r; | ||
423 | struct i2c_msg msg[] = { | ||
424 | { .addr = c->addr, .flags = 0, | ||
425 | .len = 2, .buf = (u8 *)&w }, | ||
426 | { .addr = c->addr, .flags = I2C_M_RD, | ||
427 | .len = 2, .buf = (u8 *)&r }, | ||
428 | }; | ||
429 | int ret; | ||
430 | |||
431 | if (state->error) | ||
432 | return 0; | ||
433 | |||
434 | w = cpu_to_be16(addr); | ||
435 | ret = i2c_transfer(c->adapter, msg, 2); | ||
436 | r = be16_to_cpu(r); | ||
437 | |||
438 | v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, r); | ||
439 | |||
440 | if (ret != 2) { | ||
441 | v4l2_err(c, "i2c_read: error during transfer (%d)\n", ret); | ||
442 | state->error = ret; | ||
443 | } | ||
444 | return r; | ||
445 | } | ||
446 | |||
447 | static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val) | ||
448 | { | ||
449 | u8 buf[4] = { addr >> 8, addr & 0xFF, val >> 8, val & 0xFF }; | ||
450 | struct i2c_client *c = v4l2_get_subdevdata(&state->sd); | ||
451 | int ret; | ||
452 | |||
453 | if (state->error) | ||
454 | return; | ||
455 | |||
456 | ret = i2c_master_send(c, buf, 4); | ||
457 | v4l2_dbg(3, debug, c, "i2c_write: 0x%04x : 0x%04x\n", addr, val); | ||
458 | |||
459 | if (ret != 4) { | ||
460 | v4l2_err(c, "i2c_write: error during transfer (%d)\n", ret); | ||
461 | state->error = ret; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | static u16 s5k5baf_read(struct s5k5baf *state, u16 addr) | ||
466 | { | ||
467 | s5k5baf_i2c_write(state, REG_CMDRD_ADDR, addr); | ||
468 | return s5k5baf_i2c_read(state, REG_CMD_BUF); | ||
469 | } | ||
470 | |||
471 | static void s5k5baf_write(struct s5k5baf *state, u16 addr, u16 val) | ||
472 | { | ||
473 | s5k5baf_i2c_write(state, REG_CMDWR_ADDR, addr); | ||
474 | s5k5baf_i2c_write(state, REG_CMD_BUF, val); | ||
475 | } | ||
476 | |||
477 | static void s5k5baf_write_arr_seq(struct s5k5baf *state, u16 addr, | ||
478 | u16 count, const u16 *seq) | ||
479 | { | ||
480 | struct i2c_client *c = v4l2_get_subdevdata(&state->sd); | ||
481 | __be16 buf[count + 1]; | ||
482 | int ret, n; | ||
483 | |||
484 | s5k5baf_i2c_write(state, REG_CMDWR_ADDR, addr); | ||
485 | if (state->error) | ||
486 | return; | ||
487 | |||
488 | buf[0] = __constant_cpu_to_be16(REG_CMD_BUF); | ||
489 | for (n = 1; n <= count; ++n) | ||
490 | buf[n] = cpu_to_be16(*seq++); | ||
491 | |||
492 | n *= 2; | ||
493 | ret = i2c_master_send(c, (char *)buf, n); | ||
494 | v4l2_dbg(3, debug, c, "i2c_write_seq(count=%d): %*ph\n", count, | ||
495 | min(2 * count, 64), seq - count); | ||
496 | |||
497 | if (ret != n) { | ||
498 | v4l2_err(c, "i2c_write_seq: error during transfer (%d)\n", ret); | ||
499 | state->error = ret; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | #define s5k5baf_write_seq(state, addr, seq...) \ | ||
504 | s5k5baf_write_arr_seq(state, addr, sizeof((char[]){ seq }), \ | ||
505 | (const u16 []){ seq }); | ||
506 | |||
507 | /* add items count at the beginning of the list */ | ||
508 | #define NSEQ(seq...) sizeof((char[]){ seq }), seq | ||
509 | |||
510 | /* | ||
511 | * s5k5baf_write_nseq() - Writes sequences of values to sensor memory via i2c | ||
512 | * @nseq: sequence of u16 words in format: | ||
513 | * (N, address, value[1]...value[N-1])*,0 | ||
514 | * Ex.: | ||
515 | * u16 seq[] = { NSEQ(0x4000, 1, 1), NSEQ(0x4010, 640, 480), 0 }; | ||
516 | * ret = s5k5baf_write_nseq(c, seq); | ||
517 | */ | ||
518 | static void s5k5baf_write_nseq(struct s5k5baf *state, const u16 *nseq) | ||
519 | { | ||
520 | int count; | ||
521 | |||
522 | while ((count = *nseq++)) { | ||
523 | u16 addr = *nseq++; | ||
524 | --count; | ||
525 | |||
526 | s5k5baf_write_arr_seq(state, addr, count, nseq); | ||
527 | nseq += count; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | static void s5k5baf_synchronize(struct s5k5baf *state, int timeout, u16 addr) | ||
532 | { | ||
533 | unsigned long end = jiffies + msecs_to_jiffies(timeout); | ||
534 | u16 reg; | ||
535 | |||
536 | s5k5baf_write(state, addr, 1); | ||
537 | do { | ||
538 | reg = s5k5baf_read(state, addr); | ||
539 | if (state->error || !reg) | ||
540 | return; | ||
541 | usleep_range(5000, 10000); | ||
542 | } while (time_is_after_jiffies(end)); | ||
543 | |||
544 | v4l2_err(&state->sd, "timeout on register synchronize (%#x)\n", addr); | ||
545 | state->error = -ETIMEDOUT; | ||
546 | } | ||
547 | |||
548 | static u16 *s5k5baf_fw_get_seq(struct s5k5baf *state, u16 seq_id) | ||
549 | { | ||
550 | struct s5k5baf_fw *fw = state->fw; | ||
551 | u16 *data; | ||
552 | int i; | ||
553 | |||
554 | if (fw == NULL) | ||
555 | return NULL; | ||
556 | |||
557 | data = fw->data + 2 * fw->count; | ||
558 | |||
559 | for (i = 0; i < fw->count; ++i) { | ||
560 | if (fw->seq[i].id == seq_id) | ||
561 | return data + fw->seq[i].offset; | ||
562 | } | ||
563 | |||
564 | return NULL; | ||
565 | } | ||
566 | |||
567 | static void s5k5baf_hw_patch(struct s5k5baf *state) | ||
568 | { | ||
569 | u16 *seq = s5k5baf_fw_get_seq(state, S5K5BAF_FW_ID_PATCH); | ||
570 | |||
571 | if (seq) | ||
572 | s5k5baf_write_nseq(state, seq); | ||
573 | } | ||
574 | |||
575 | static void s5k5baf_hw_set_clocks(struct s5k5baf *state) | ||
576 | { | ||
577 | unsigned long mclk = state->mclk_frequency / 1000; | ||
578 | u16 status; | ||
579 | static const u16 nseq_clk_cfg[] = { | ||
580 | NSEQ(REG_I_USE_NPVI_CLOCKS, | ||
581 | NPVI_CLOCKS, NMIPI_CLOCKS, 0, | ||
582 | SCLK_PVI_FREQ / 4, PCLK_MIN_FREQ / 4, PCLK_MAX_FREQ / 4, | ||
583 | SCLK_MIPI_FREQ / 4, PCLK_MIN_FREQ / 4, PCLK_MAX_FREQ / 4), | ||
584 | NSEQ(REG_I_USE_REGS_API, 1), | ||
585 | 0 | ||
586 | }; | ||
587 | |||
588 | s5k5baf_write_seq(state, REG_I_INCLK_FREQ_L, mclk & 0xffff, mclk >> 16); | ||
589 | s5k5baf_write_nseq(state, nseq_clk_cfg); | ||
590 | |||
591 | s5k5baf_synchronize(state, 250, REG_I_INIT_PARAMS_UPDATED); | ||
592 | status = s5k5baf_read(state, REG_I_ERROR_INFO); | ||
593 | if (!state->error && status) { | ||
594 | v4l2_err(&state->sd, "error configuring PLL (%d)\n", status); | ||
595 | state->error = -EINVAL; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /* set custom color correction matrices for various illuminations */ | ||
600 | static void s5k5baf_hw_set_ccm(struct s5k5baf *state) | ||
601 | { | ||
602 | u16 *seq = s5k5baf_fw_get_seq(state, S5K5BAF_FW_ID_CCM); | ||
603 | |||
604 | if (seq) | ||
605 | s5k5baf_write_nseq(state, seq); | ||
606 | } | ||
607 | |||
608 | /* CIS sensor tuning, based on undocumented android driver code */ | ||
609 | static void s5k5baf_hw_set_cis(struct s5k5baf *state) | ||
610 | { | ||
611 | u16 *seq = s5k5baf_fw_get_seq(state, S5K5BAF_FW_ID_CIS); | ||
612 | |||
613 | if (!seq) | ||
614 | return; | ||
615 | |||
616 | s5k5baf_i2c_write(state, REG_CMDWR_PAGE, PAGE_IF_HW); | ||
617 | s5k5baf_write_nseq(state, seq); | ||
618 | s5k5baf_i2c_write(state, REG_CMDWR_PAGE, PAGE_IF_SW); | ||
619 | } | ||
620 | |||
621 | static void s5k5baf_hw_sync_cfg(struct s5k5baf *state) | ||
622 | { | ||
623 | s5k5baf_write(state, REG_G_PREV_CFG_CHG, 1); | ||
624 | if (state->apply_crop) { | ||
625 | s5k5baf_write(state, REG_G_INPUTS_CHANGE_REQ, 1); | ||
626 | s5k5baf_write(state, REG_G_PREV_CFG_BYPASS_CHANGED, 1); | ||
627 | } | ||
628 | s5k5baf_synchronize(state, 500, REG_G_NEW_CFG_SYNC); | ||
629 | } | ||
630 | /* Set horizontal and vertical image flipping */ | ||
631 | static void s5k5baf_hw_set_mirror(struct s5k5baf *state) | ||
632 | { | ||
633 | u16 flip = state->ctrls.vflip->val | (state->ctrls.vflip->val << 1); | ||
634 | |||
635 | s5k5baf_write(state, REG_P_PREV_MIRROR(0), flip); | ||
636 | if (state->streaming) | ||
637 | s5k5baf_hw_sync_cfg(state); | ||
638 | } | ||
639 | |||
640 | static void s5k5baf_hw_set_alg(struct s5k5baf *state, u16 alg, bool enable) | ||
641 | { | ||
642 | u16 cur_alg, new_alg; | ||
643 | |||
644 | if (!state->valid_auto_alg) | ||
645 | cur_alg = s5k5baf_read(state, REG_DBG_AUTOALG_EN); | ||
646 | else | ||
647 | cur_alg = state->auto_alg; | ||
648 | |||
649 | new_alg = enable ? (cur_alg | alg) : (cur_alg & ~alg); | ||
650 | |||
651 | if (new_alg != cur_alg) | ||
652 | s5k5baf_write(state, REG_DBG_AUTOALG_EN, new_alg); | ||
653 | |||
654 | if (state->error) | ||
655 | return; | ||
656 | |||
657 | state->valid_auto_alg = 1; | ||
658 | state->auto_alg = new_alg; | ||
659 | } | ||
660 | |||
661 | /* Configure auto/manual white balance and R/G/B gains */ | ||
662 | static void s5k5baf_hw_set_awb(struct s5k5baf *state, int awb) | ||
663 | { | ||
664 | struct s5k5baf_ctrls *ctrls = &state->ctrls; | ||
665 | |||
666 | if (!awb) | ||
667 | s5k5baf_write_seq(state, REG_SF_RGAIN, | ||
668 | ctrls->gain_red->val, 1, | ||
669 | S5K5BAF_GAIN_GREEN_DEF, 1, | ||
670 | ctrls->gain_blue->val, 1, | ||
671 | 1); | ||
672 | |||
673 | s5k5baf_hw_set_alg(state, AALG_WB_EN, awb); | ||
674 | } | ||
675 | |||
676 | /* Program FW with exposure time, 'exposure' in us units */ | ||
677 | static void s5k5baf_hw_set_user_exposure(struct s5k5baf *state, int exposure) | ||
678 | { | ||
679 | unsigned int time = exposure / 10; | ||
680 | |||
681 | s5k5baf_write_seq(state, REG_SF_USR_EXPOSURE_L, | ||
682 | time & 0xffff, time >> 16, 1); | ||
683 | } | ||
684 | |||
685 | static void s5k5baf_hw_set_user_gain(struct s5k5baf *state, int gain) | ||
686 | { | ||
687 | s5k5baf_write_seq(state, REG_SF_USR_TOT_GAIN, gain, 1); | ||
688 | } | ||
689 | |||
690 | /* Set auto/manual exposure and total gain */ | ||
691 | static void s5k5baf_hw_set_auto_exposure(struct s5k5baf *state, int value) | ||
692 | { | ||
693 | if (value == V4L2_EXPOSURE_AUTO) { | ||
694 | s5k5baf_hw_set_alg(state, AALG_AE_EN | AALG_DIVLEI_EN, true); | ||
695 | } else { | ||
696 | unsigned int exp_time = state->ctrls.exposure->val; | ||
697 | |||
698 | s5k5baf_hw_set_user_exposure(state, exp_time); | ||
699 | s5k5baf_hw_set_user_gain(state, state->ctrls.gain->val); | ||
700 | s5k5baf_hw_set_alg(state, AALG_AE_EN | AALG_DIVLEI_EN, false); | ||
701 | } | ||
702 | } | ||
703 | |||
704 | static void s5k5baf_hw_set_anti_flicker(struct s5k5baf *state, int v) | ||
705 | { | ||
706 | if (v == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) { | ||
707 | s5k5baf_hw_set_alg(state, AALG_FLICKER_EN, true); | ||
708 | } else { | ||
709 | /* The V4L2_CID_LINE_FREQUENCY control values match | ||
710 | * the register values */ | ||
711 | s5k5baf_write_seq(state, REG_SF_FLICKER_QUANT, v, 1); | ||
712 | s5k5baf_hw_set_alg(state, AALG_FLICKER_EN, false); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | static void s5k5baf_hw_set_colorfx(struct s5k5baf *state, int val) | ||
717 | { | ||
718 | static const u16 colorfx[] = { | ||
719 | [V4L2_COLORFX_NONE] = 0, | ||
720 | [V4L2_COLORFX_BW] = 1, | ||
721 | [V4L2_COLORFX_NEGATIVE] = 2, | ||
722 | [V4L2_COLORFX_SEPIA] = 3, | ||
723 | [V4L2_COLORFX_SKY_BLUE] = 4, | ||
724 | [V4L2_COLORFX_SKETCH] = 5, | ||
725 | }; | ||
726 | |||
727 | s5k5baf_write(state, REG_G_SPEC_EFFECTS, colorfx[val]); | ||
728 | } | ||
729 | |||
730 | static int s5k5baf_find_pixfmt(struct v4l2_mbus_framefmt *mf) | ||
731 | { | ||
732 | int i, c = -1; | ||
733 | |||
734 | for (i = 0; i < ARRAY_SIZE(s5k5baf_formats); i++) { | ||
735 | if (mf->colorspace != s5k5baf_formats[i].colorspace) | ||
736 | continue; | ||
737 | if (mf->code == s5k5baf_formats[i].code) | ||
738 | return i; | ||
739 | if (c < 0) | ||
740 | c = i; | ||
741 | } | ||
742 | return (c < 0) ? 0 : c; | ||
743 | } | ||
744 | |||
745 | static int s5k5baf_clear_error(struct s5k5baf *state) | ||
746 | { | ||
747 | int ret = state->error; | ||
748 | |||
749 | state->error = 0; | ||
750 | return ret; | ||
751 | } | ||
752 | |||
753 | static int s5k5baf_hw_set_video_bus(struct s5k5baf *state) | ||
754 | { | ||
755 | u16 en_pkts; | ||
756 | |||
757 | if (state->bus_type == V4L2_MBUS_CSI2) | ||
758 | en_pkts = EN_PACKETS_CSI2; | ||
759 | else | ||
760 | en_pkts = 0; | ||
761 | |||
762 | s5k5baf_write_seq(state, REG_OIF_EN_MIPI_LANES, | ||
763 | state->nlanes, en_pkts, 1); | ||
764 | |||
765 | return s5k5baf_clear_error(state); | ||
766 | } | ||
767 | |||
768 | static u16 s5k5baf_get_cfg_error(struct s5k5baf *state) | ||
769 | { | ||
770 | u16 err = s5k5baf_read(state, REG_G_PREV_CFG_ERROR); | ||
771 | if (err) | ||
772 | s5k5baf_write(state, REG_G_PREV_CFG_ERROR, 0); | ||
773 | return err; | ||
774 | } | ||
775 | |||
776 | static void s5k5baf_hw_set_fiv(struct s5k5baf *state, u16 fiv) | ||
777 | { | ||
778 | s5k5baf_write(state, REG_P_MAX_FR_TIME(0), fiv); | ||
779 | s5k5baf_hw_sync_cfg(state); | ||
780 | } | ||
781 | |||
782 | static void s5k5baf_hw_find_min_fiv(struct s5k5baf *state) | ||
783 | { | ||
784 | u16 err, fiv; | ||
785 | int n; | ||
786 | |||
787 | fiv = s5k5baf_read(state, REG_G_ACTUAL_P_FR_TIME); | ||
788 | if (state->error) | ||
789 | return; | ||
790 | |||
791 | for (n = 5; n > 0; --n) { | ||
792 | s5k5baf_hw_set_fiv(state, fiv); | ||
793 | err = s5k5baf_get_cfg_error(state); | ||
794 | if (state->error) | ||
795 | return; | ||
796 | switch (err) { | ||
797 | case CFG_ERROR_RANGE: | ||
798 | ++fiv; | ||
799 | break; | ||
800 | case 0: | ||
801 | state->fiv = fiv; | ||
802 | v4l2_info(&state->sd, | ||
803 | "found valid frame interval: %d00us\n", fiv); | ||
804 | return; | ||
805 | default: | ||
806 | v4l2_err(&state->sd, | ||
807 | "error setting frame interval: %d\n", err); | ||
808 | state->error = -EINVAL; | ||
809 | } | ||
810 | }; | ||
811 | v4l2_err(&state->sd, "cannot find correct frame interval\n"); | ||
812 | state->error = -ERANGE; | ||
813 | } | ||
814 | |||
815 | static void s5k5baf_hw_validate_cfg(struct s5k5baf *state) | ||
816 | { | ||
817 | u16 err; | ||
818 | |||
819 | err = s5k5baf_get_cfg_error(state); | ||
820 | if (state->error) | ||
821 | return; | ||
822 | |||
823 | switch (err) { | ||
824 | case 0: | ||
825 | state->apply_cfg = 1; | ||
826 | return; | ||
827 | case CFG_ERROR_RANGE: | ||
828 | s5k5baf_hw_find_min_fiv(state); | ||
829 | if (!state->error) | ||
830 | state->apply_cfg = 1; | ||
831 | return; | ||
832 | default: | ||
833 | v4l2_err(&state->sd, | ||
834 | "error setting format: %d\n", err); | ||
835 | state->error = -EINVAL; | ||
836 | } | ||
837 | } | ||
838 | |||
839 | static void s5k5baf_rescale(struct v4l2_rect *r, const struct v4l2_rect *v, | ||
840 | const struct v4l2_rect *n, | ||
841 | const struct v4l2_rect *d) | ||
842 | { | ||
843 | r->left = v->left * n->width / d->width; | ||
844 | r->top = v->top * n->height / d->height; | ||
845 | r->width = v->width * n->width / d->width; | ||
846 | r->height = v->height * n->height / d->height; | ||
847 | } | ||
848 | |||
849 | static int s5k5baf_hw_set_crop_rects(struct s5k5baf *state) | ||
850 | { | ||
851 | struct v4l2_rect *p, r; | ||
852 | u16 err; | ||
853 | int ret; | ||
854 | |||
855 | p = &state->crop_sink; | ||
856 | s5k5baf_write_seq(state, REG_G_PREVREQ_IN_WIDTH, p->width, p->height, | ||
857 | p->left, p->top); | ||
858 | |||
859 | s5k5baf_rescale(&r, &state->crop_source, &state->crop_sink, | ||
860 | &state->compose); | ||
861 | s5k5baf_write_seq(state, REG_G_PREVZOOM_IN_WIDTH, r.width, r.height, | ||
862 | r.left, r.top); | ||
863 | |||
864 | s5k5baf_synchronize(state, 500, REG_G_INPUTS_CHANGE_REQ); | ||
865 | s5k5baf_synchronize(state, 500, REG_G_PREV_CFG_BYPASS_CHANGED); | ||
866 | err = s5k5baf_get_cfg_error(state); | ||
867 | ret = s5k5baf_clear_error(state); | ||
868 | if (ret < 0) | ||
869 | return ret; | ||
870 | |||
871 | switch (err) { | ||
872 | case 0: | ||
873 | break; | ||
874 | case CFG_ERROR_RANGE: | ||
875 | /* retry crop with frame interval set to max */ | ||
876 | s5k5baf_hw_set_fiv(state, S5K5BAF_MAX_FR_TIME); | ||
877 | err = s5k5baf_get_cfg_error(state); | ||
878 | ret = s5k5baf_clear_error(state); | ||
879 | if (ret < 0) | ||
880 | return ret; | ||
881 | if (err) { | ||
882 | v4l2_err(&state->sd, | ||
883 | "crop error on max frame interval: %d\n", err); | ||
884 | state->error = -EINVAL; | ||
885 | } | ||
886 | s5k5baf_hw_set_fiv(state, state->req_fiv); | ||
887 | s5k5baf_hw_validate_cfg(state); | ||
888 | break; | ||
889 | default: | ||
890 | v4l2_err(&state->sd, "crop error: %d\n", err); | ||
891 | return -EINVAL; | ||
892 | } | ||
893 | |||
894 | if (!state->apply_cfg) | ||
895 | return 0; | ||
896 | |||
897 | p = &state->crop_source; | ||
898 | s5k5baf_write_seq(state, REG_P_OUT_WIDTH(0), p->width, p->height); | ||
899 | s5k5baf_hw_set_fiv(state, state->req_fiv); | ||
900 | s5k5baf_hw_validate_cfg(state); | ||
901 | |||
902 | return s5k5baf_clear_error(state); | ||
903 | } | ||
904 | |||
905 | static void s5k5baf_hw_set_config(struct s5k5baf *state) | ||
906 | { | ||
907 | u16 reg_fmt = s5k5baf_formats[state->pixfmt].reg_p_fmt; | ||
908 | struct v4l2_rect *r = &state->crop_source; | ||
909 | |||
910 | s5k5baf_write_seq(state, REG_P_OUT_WIDTH(0), | ||
911 | r->width, r->height, reg_fmt, | ||
912 | PCLK_MAX_FREQ >> 2, PCLK_MIN_FREQ >> 2, | ||
913 | PVI_MASK_MIPI, CLK_MIPI_INDEX, | ||
914 | FR_RATE_FIXED, FR_RATE_Q_DYNAMIC, | ||
915 | state->req_fiv, S5K5BAF_MIN_FR_TIME); | ||
916 | s5k5baf_hw_sync_cfg(state); | ||
917 | s5k5baf_hw_validate_cfg(state); | ||
918 | } | ||
919 | |||
920 | |||
921 | static void s5k5baf_hw_set_test_pattern(struct s5k5baf *state, int id) | ||
922 | { | ||
923 | s5k5baf_i2c_write(state, REG_PATTERN_WIDTH, 800); | ||
924 | s5k5baf_i2c_write(state, REG_PATTERN_HEIGHT, 511); | ||
925 | s5k5baf_i2c_write(state, REG_PATTERN_PARAM, 0); | ||
926 | s5k5baf_i2c_write(state, REG_PATTERN_SET, id); | ||
927 | } | ||
928 | |||
929 | static void s5k5baf_gpio_assert(struct s5k5baf *state, int id) | ||
930 | { | ||
931 | struct s5k5baf_gpio *gpio = &state->gpios[id]; | ||
932 | |||
933 | gpio_set_value(gpio->gpio, gpio->level); | ||
934 | } | ||
935 | |||
936 | static void s5k5baf_gpio_deassert(struct s5k5baf *state, int id) | ||
937 | { | ||
938 | struct s5k5baf_gpio *gpio = &state->gpios[id]; | ||
939 | |||
940 | gpio_set_value(gpio->gpio, !gpio->level); | ||
941 | } | ||
942 | |||
943 | static int s5k5baf_power_on(struct s5k5baf *state) | ||
944 | { | ||
945 | int ret; | ||
946 | |||
947 | ret = regulator_bulk_enable(S5K5BAF_NUM_SUPPLIES, state->supplies); | ||
948 | if (ret < 0) | ||
949 | goto err; | ||
950 | |||
951 | ret = clk_set_rate(state->clock, state->mclk_frequency); | ||
952 | if (ret < 0) | ||
953 | goto err_reg_dis; | ||
954 | |||
955 | ret = clk_prepare_enable(state->clock); | ||
956 | if (ret < 0) | ||
957 | goto err_reg_dis; | ||
958 | |||
959 | v4l2_dbg(1, debug, &state->sd, "clock frequency: %ld\n", | ||
960 | clk_get_rate(state->clock)); | ||
961 | |||
962 | s5k5baf_gpio_deassert(state, STBY); | ||
963 | usleep_range(50, 100); | ||
964 | s5k5baf_gpio_deassert(state, RST); | ||
965 | return 0; | ||
966 | |||
967 | err_reg_dis: | ||
968 | regulator_bulk_disable(S5K5BAF_NUM_SUPPLIES, state->supplies); | ||
969 | err: | ||
970 | v4l2_err(&state->sd, "%s() failed (%d)\n", __func__, ret); | ||
971 | return ret; | ||
972 | } | ||
973 | |||
974 | static int s5k5baf_power_off(struct s5k5baf *state) | ||
975 | { | ||
976 | int ret; | ||
977 | |||
978 | state->streaming = 0; | ||
979 | state->apply_cfg = 0; | ||
980 | state->apply_crop = 0; | ||
981 | |||
982 | s5k5baf_gpio_assert(state, RST); | ||
983 | s5k5baf_gpio_assert(state, STBY); | ||
984 | |||
985 | if (!IS_ERR(state->clock)) | ||
986 | clk_disable_unprepare(state->clock); | ||
987 | |||
988 | ret = regulator_bulk_disable(S5K5BAF_NUM_SUPPLIES, | ||
989 | state->supplies); | ||
990 | if (ret < 0) | ||
991 | v4l2_err(&state->sd, "failed to disable regulators\n"); | ||
992 | |||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | static void s5k5baf_hw_init(struct s5k5baf *state) | ||
997 | { | ||
998 | s5k5baf_i2c_write(state, AHB_MSB_ADDR_PTR, PAGE_IF_HW); | ||
999 | s5k5baf_i2c_write(state, REG_CLEAR_HOST_INT, 0); | ||
1000 | s5k5baf_i2c_write(state, REG_SW_LOAD_COMPLETE, 1); | ||
1001 | s5k5baf_i2c_write(state, REG_CMDRD_PAGE, PAGE_IF_SW); | ||
1002 | s5k5baf_i2c_write(state, REG_CMDWR_PAGE, PAGE_IF_SW); | ||
1003 | } | ||
1004 | |||
1005 | /* | ||
1006 | * V4L2 subdev core and video operations | ||
1007 | */ | ||
1008 | |||
1009 | static void s5k5baf_initialize_data(struct s5k5baf *state) | ||
1010 | { | ||
1011 | state->pixfmt = 0; | ||
1012 | state->req_fiv = 10000 / 15; | ||
1013 | state->fiv = state->req_fiv; | ||
1014 | state->valid_auto_alg = 0; | ||
1015 | } | ||
1016 | |||
1017 | static int s5k5baf_load_setfile(struct s5k5baf *state) | ||
1018 | { | ||
1019 | struct i2c_client *c = v4l2_get_subdevdata(&state->sd); | ||
1020 | const struct firmware *fw; | ||
1021 | int ret; | ||
1022 | |||
1023 | ret = request_firmware(&fw, S5K5BAF_FW_FILENAME, &c->dev); | ||
1024 | if (ret < 0) { | ||
1025 | dev_warn(&c->dev, "firmware file (%s) not loaded\n", | ||
1026 | S5K5BAF_FW_FILENAME); | ||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | ret = s5k5baf_fw_parse(&c->dev, &state->fw, fw->size / 2, | ||
1031 | (u16 *)fw->data); | ||
1032 | |||
1033 | release_firmware(fw); | ||
1034 | |||
1035 | return ret; | ||
1036 | } | ||
1037 | |||
1038 | static int s5k5baf_set_power(struct v4l2_subdev *sd, int on) | ||
1039 | { | ||
1040 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1041 | int ret = 0; | ||
1042 | |||
1043 | mutex_lock(&state->lock); | ||
1044 | |||
1045 | if (!on != state->power) | ||
1046 | goto out; | ||
1047 | |||
1048 | if (on) { | ||
1049 | if (state->fw == NULL) | ||
1050 | s5k5baf_load_setfile(state); | ||
1051 | |||
1052 | s5k5baf_initialize_data(state); | ||
1053 | ret = s5k5baf_power_on(state); | ||
1054 | if (ret < 0) | ||
1055 | goto out; | ||
1056 | |||
1057 | s5k5baf_hw_init(state); | ||
1058 | s5k5baf_hw_patch(state); | ||
1059 | s5k5baf_i2c_write(state, REG_SET_HOST_INT, 1); | ||
1060 | s5k5baf_hw_set_clocks(state); | ||
1061 | |||
1062 | ret = s5k5baf_hw_set_video_bus(state); | ||
1063 | if (ret < 0) | ||
1064 | goto out; | ||
1065 | |||
1066 | s5k5baf_hw_set_cis(state); | ||
1067 | s5k5baf_hw_set_ccm(state); | ||
1068 | |||
1069 | ret = s5k5baf_clear_error(state); | ||
1070 | if (!ret) | ||
1071 | state->power++; | ||
1072 | } else { | ||
1073 | s5k5baf_power_off(state); | ||
1074 | state->power--; | ||
1075 | } | ||
1076 | |||
1077 | out: | ||
1078 | mutex_unlock(&state->lock); | ||
1079 | |||
1080 | if (!ret && on) | ||
1081 | ret = v4l2_ctrl_handler_setup(&state->ctrls.handler); | ||
1082 | |||
1083 | return ret; | ||
1084 | } | ||
1085 | |||
1086 | static void s5k5baf_hw_set_stream(struct s5k5baf *state, int enable) | ||
1087 | { | ||
1088 | s5k5baf_write_seq(state, REG_G_ENABLE_PREV, enable, 1); | ||
1089 | } | ||
1090 | |||
1091 | static int s5k5baf_s_stream(struct v4l2_subdev *sd, int on) | ||
1092 | { | ||
1093 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1094 | int ret; | ||
1095 | |||
1096 | mutex_lock(&state->lock); | ||
1097 | |||
1098 | if (state->streaming == !!on) { | ||
1099 | ret = 0; | ||
1100 | goto out; | ||
1101 | } | ||
1102 | |||
1103 | if (on) { | ||
1104 | s5k5baf_hw_set_config(state); | ||
1105 | ret = s5k5baf_hw_set_crop_rects(state); | ||
1106 | if (ret < 0) | ||
1107 | goto out; | ||
1108 | s5k5baf_hw_set_stream(state, 1); | ||
1109 | s5k5baf_i2c_write(state, 0xb0cc, 0x000b); | ||
1110 | } else { | ||
1111 | s5k5baf_hw_set_stream(state, 0); | ||
1112 | } | ||
1113 | ret = s5k5baf_clear_error(state); | ||
1114 | if (!ret) | ||
1115 | state->streaming = !state->streaming; | ||
1116 | |||
1117 | out: | ||
1118 | mutex_unlock(&state->lock); | ||
1119 | |||
1120 | return ret; | ||
1121 | } | ||
1122 | |||
1123 | static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd, | ||
1124 | struct v4l2_subdev_frame_interval *fi) | ||
1125 | { | ||
1126 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1127 | |||
1128 | mutex_lock(&state->lock); | ||
1129 | fi->interval.numerator = state->fiv; | ||
1130 | fi->interval.denominator = 10000; | ||
1131 | mutex_unlock(&state->lock); | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static void s5k5baf_set_frame_interval(struct s5k5baf *state, | ||
1137 | struct v4l2_subdev_frame_interval *fi) | ||
1138 | { | ||
1139 | struct v4l2_fract *i = &fi->interval; | ||
1140 | |||
1141 | if (fi->interval.denominator == 0) | ||
1142 | state->req_fiv = S5K5BAF_MAX_FR_TIME; | ||
1143 | else | ||
1144 | state->req_fiv = clamp_t(u32, | ||
1145 | i->numerator * 10000 / i->denominator, | ||
1146 | S5K5BAF_MIN_FR_TIME, | ||
1147 | S5K5BAF_MAX_FR_TIME); | ||
1148 | |||
1149 | state->fiv = state->req_fiv; | ||
1150 | if (state->apply_cfg) { | ||
1151 | s5k5baf_hw_set_fiv(state, state->req_fiv); | ||
1152 | s5k5baf_hw_validate_cfg(state); | ||
1153 | } | ||
1154 | *i = (struct v4l2_fract){ state->fiv, 10000 }; | ||
1155 | if (state->fiv == state->req_fiv) | ||
1156 | v4l2_info(&state->sd, "frame interval changed to %d00us\n", | ||
1157 | state->fiv); | ||
1158 | } | ||
1159 | |||
1160 | static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd, | ||
1161 | struct v4l2_subdev_frame_interval *fi) | ||
1162 | { | ||
1163 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1164 | |||
1165 | mutex_lock(&state->lock); | ||
1166 | s5k5baf_set_frame_interval(state, fi); | ||
1167 | mutex_unlock(&state->lock); | ||
1168 | return 0; | ||
1169 | } | ||
1170 | |||
1171 | /* | ||
1172 | * V4L2 subdev pad level and video operations | ||
1173 | */ | ||
1174 | static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd, | ||
1175 | struct v4l2_subdev_fh *fh, | ||
1176 | struct v4l2_subdev_frame_interval_enum *fie) | ||
1177 | { | ||
1178 | if (fie->index > S5K5BAF_MAX_FR_TIME - S5K5BAF_MIN_FR_TIME || | ||
1179 | fie->pad != PAD_CIS) | ||
1180 | return -EINVAL; | ||
1181 | |||
1182 | v4l_bound_align_image(&fie->width, S5K5BAF_WIN_WIDTH_MIN, | ||
1183 | S5K5BAF_CIS_WIDTH, 1, | ||
1184 | &fie->height, S5K5BAF_WIN_HEIGHT_MIN, | ||
1185 | S5K5BAF_CIS_HEIGHT, 1, 0); | ||
1186 | |||
1187 | fie->interval.numerator = S5K5BAF_MIN_FR_TIME + fie->index; | ||
1188 | fie->interval.denominator = 10000; | ||
1189 | |||
1190 | return 0; | ||
1191 | } | ||
1192 | |||
1193 | static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd, | ||
1194 | struct v4l2_subdev_fh *fh, | ||
1195 | struct v4l2_subdev_mbus_code_enum *code) | ||
1196 | { | ||
1197 | if (code->pad == PAD_CIS) { | ||
1198 | if (code->index > 0) | ||
1199 | return -EINVAL; | ||
1200 | code->code = V4L2_MBUS_FMT_FIXED; | ||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | if (code->index >= ARRAY_SIZE(s5k5baf_formats)) | ||
1205 | return -EINVAL; | ||
1206 | |||
1207 | code->code = s5k5baf_formats[code->index].code; | ||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd, | ||
1212 | struct v4l2_subdev_fh *fh, | ||
1213 | struct v4l2_subdev_frame_size_enum *fse) | ||
1214 | { | ||
1215 | int i; | ||
1216 | |||
1217 | if (fse->index > 0) | ||
1218 | return -EINVAL; | ||
1219 | |||
1220 | if (fse->pad == PAD_CIS) { | ||
1221 | fse->code = V4L2_MBUS_FMT_FIXED; | ||
1222 | fse->min_width = S5K5BAF_CIS_WIDTH; | ||
1223 | fse->max_width = S5K5BAF_CIS_WIDTH; | ||
1224 | fse->min_height = S5K5BAF_CIS_HEIGHT; | ||
1225 | fse->max_height = S5K5BAF_CIS_HEIGHT; | ||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | i = ARRAY_SIZE(s5k5baf_formats); | ||
1230 | while (--i) | ||
1231 | if (fse->code == s5k5baf_formats[i].code) | ||
1232 | break; | ||
1233 | fse->code = s5k5baf_formats[i].code; | ||
1234 | fse->min_width = S5K5BAF_WIN_WIDTH_MIN; | ||
1235 | fse->max_width = S5K5BAF_CIS_WIDTH; | ||
1236 | fse->max_height = S5K5BAF_WIN_HEIGHT_MIN; | ||
1237 | fse->min_height = S5K5BAF_CIS_HEIGHT; | ||
1238 | |||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | static void s5k5baf_try_cis_format(struct v4l2_mbus_framefmt *mf) | ||
1243 | { | ||
1244 | mf->width = S5K5BAF_CIS_WIDTH; | ||
1245 | mf->height = S5K5BAF_CIS_HEIGHT; | ||
1246 | mf->code = V4L2_MBUS_FMT_FIXED; | ||
1247 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
1248 | mf->field = V4L2_FIELD_NONE; | ||
1249 | } | ||
1250 | |||
1251 | static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf) | ||
1252 | { | ||
1253 | int pixfmt; | ||
1254 | |||
1255 | v4l_bound_align_image(&mf->width, S5K5BAF_WIN_WIDTH_MIN, | ||
1256 | S5K5BAF_CIS_WIDTH, 1, | ||
1257 | &mf->height, S5K5BAF_WIN_HEIGHT_MIN, | ||
1258 | S5K5BAF_CIS_HEIGHT, 1, 0); | ||
1259 | |||
1260 | pixfmt = s5k5baf_find_pixfmt(mf); | ||
1261 | |||
1262 | mf->colorspace = s5k5baf_formats[pixfmt].colorspace; | ||
1263 | mf->code = s5k5baf_formats[pixfmt].code; | ||
1264 | mf->field = V4L2_FIELD_NONE; | ||
1265 | |||
1266 | return pixfmt; | ||
1267 | } | ||
1268 | |||
1269 | static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1270 | struct v4l2_subdev_format *fmt) | ||
1271 | { | ||
1272 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1273 | const struct s5k5baf_pixfmt *pixfmt; | ||
1274 | struct v4l2_mbus_framefmt *mf; | ||
1275 | |||
1276 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1277 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | ||
1278 | fmt->format = *mf; | ||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | mf = &fmt->format; | ||
1283 | if (fmt->pad == PAD_CIS) { | ||
1284 | s5k5baf_try_cis_format(mf); | ||
1285 | return 0; | ||
1286 | } | ||
1287 | mf->field = V4L2_FIELD_NONE; | ||
1288 | mutex_lock(&state->lock); | ||
1289 | pixfmt = &s5k5baf_formats[state->pixfmt]; | ||
1290 | mf->width = state->crop_source.width; | ||
1291 | mf->height = state->crop_source.height; | ||
1292 | mf->code = pixfmt->code; | ||
1293 | mf->colorspace = pixfmt->colorspace; | ||
1294 | mutex_unlock(&state->lock); | ||
1295 | |||
1296 | return 0; | ||
1297 | } | ||
1298 | |||
1299 | static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1300 | struct v4l2_subdev_format *fmt) | ||
1301 | { | ||
1302 | struct v4l2_mbus_framefmt *mf = &fmt->format; | ||
1303 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1304 | const struct s5k5baf_pixfmt *pixfmt; | ||
1305 | int ret = 0; | ||
1306 | |||
1307 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1308 | *v4l2_subdev_get_try_format(fh, fmt->pad) = *mf; | ||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | if (fmt->pad == PAD_CIS) { | ||
1313 | s5k5baf_try_cis_format(mf); | ||
1314 | return 0; | ||
1315 | } | ||
1316 | |||
1317 | mutex_lock(&state->lock); | ||
1318 | |||
1319 | if (state->streaming) { | ||
1320 | mutex_unlock(&state->lock); | ||
1321 | return -EBUSY; | ||
1322 | } | ||
1323 | |||
1324 | state->pixfmt = s5k5baf_try_isp_format(mf); | ||
1325 | pixfmt = &s5k5baf_formats[state->pixfmt]; | ||
1326 | mf->code = pixfmt->code; | ||
1327 | mf->colorspace = pixfmt->colorspace; | ||
1328 | mf->width = state->crop_source.width; | ||
1329 | mf->height = state->crop_source.height; | ||
1330 | |||
1331 | mutex_unlock(&state->lock); | ||
1332 | return ret; | ||
1333 | } | ||
1334 | |||
1335 | enum selection_rect { R_CIS, R_CROP_SINK, R_COMPOSE, R_CROP_SOURCE, R_INVALID }; | ||
1336 | |||
1337 | static enum selection_rect s5k5baf_get_sel_rect(u32 pad, u32 target) | ||
1338 | { | ||
1339 | switch (target) { | ||
1340 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1341 | return pad ? R_COMPOSE : R_CIS; | ||
1342 | case V4L2_SEL_TGT_CROP: | ||
1343 | return pad ? R_CROP_SOURCE : R_CROP_SINK; | ||
1344 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
1345 | return pad ? R_INVALID : R_CROP_SINK; | ||
1346 | case V4L2_SEL_TGT_COMPOSE: | ||
1347 | return pad ? R_INVALID : R_COMPOSE; | ||
1348 | default: | ||
1349 | return R_INVALID; | ||
1350 | } | ||
1351 | } | ||
1352 | |||
1353 | static int s5k5baf_is_bound_target(u32 target) | ||
1354 | { | ||
1355 | return target == V4L2_SEL_TGT_CROP_BOUNDS || | ||
1356 | target == V4L2_SEL_TGT_COMPOSE_BOUNDS; | ||
1357 | } | ||
1358 | |||
1359 | static int s5k5baf_get_selection(struct v4l2_subdev *sd, | ||
1360 | struct v4l2_subdev_fh *fh, | ||
1361 | struct v4l2_subdev_selection *sel) | ||
1362 | { | ||
1363 | static enum selection_rect rtype; | ||
1364 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1365 | |||
1366 | rtype = s5k5baf_get_sel_rect(sel->pad, sel->target); | ||
1367 | |||
1368 | switch (rtype) { | ||
1369 | case R_INVALID: | ||
1370 | return -EINVAL; | ||
1371 | case R_CIS: | ||
1372 | sel->r = s5k5baf_cis_rect; | ||
1373 | return 0; | ||
1374 | default: | ||
1375 | break; | ||
1376 | } | ||
1377 | |||
1378 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1379 | if (rtype == R_COMPOSE) | ||
1380 | sel->r = *v4l2_subdev_get_try_compose(fh, sel->pad); | ||
1381 | else | ||
1382 | sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); | ||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | mutex_lock(&state->lock); | ||
1387 | switch (rtype) { | ||
1388 | case R_CROP_SINK: | ||
1389 | sel->r = state->crop_sink; | ||
1390 | break; | ||
1391 | case R_COMPOSE: | ||
1392 | sel->r = state->compose; | ||
1393 | break; | ||
1394 | case R_CROP_SOURCE: | ||
1395 | sel->r = state->crop_source; | ||
1396 | break; | ||
1397 | default: | ||
1398 | break; | ||
1399 | } | ||
1400 | if (s5k5baf_is_bound_target(sel->target)) { | ||
1401 | sel->r.left = 0; | ||
1402 | sel->r.top = 0; | ||
1403 | } | ||
1404 | mutex_unlock(&state->lock); | ||
1405 | |||
1406 | return 0; | ||
1407 | } | ||
1408 | |||
1409 | /* bounds range [start, start+len) to [0, max) and aligns to 2 */ | ||
1410 | static void s5k5baf_bound_range(u32 *start, u32 *len, u32 max) | ||
1411 | { | ||
1412 | if (*len > max) | ||
1413 | *len = max; | ||
1414 | if (*start + *len > max) | ||
1415 | *start = max - *len; | ||
1416 | *start &= ~1; | ||
1417 | *len &= ~1; | ||
1418 | if (*len < S5K5BAF_WIN_WIDTH_MIN) | ||
1419 | *len = S5K5BAF_WIN_WIDTH_MIN; | ||
1420 | } | ||
1421 | |||
1422 | static void s5k5baf_bound_rect(struct v4l2_rect *r, u32 width, u32 height) | ||
1423 | { | ||
1424 | s5k5baf_bound_range(&r->left, &r->width, width); | ||
1425 | s5k5baf_bound_range(&r->top, &r->height, height); | ||
1426 | } | ||
1427 | |||
1428 | static void s5k5baf_set_rect_and_adjust(struct v4l2_rect **rects, | ||
1429 | enum selection_rect first, | ||
1430 | struct v4l2_rect *v) | ||
1431 | { | ||
1432 | struct v4l2_rect *r, *br; | ||
1433 | enum selection_rect i = first; | ||
1434 | |||
1435 | *rects[first] = *v; | ||
1436 | do { | ||
1437 | r = rects[i]; | ||
1438 | br = rects[i - 1]; | ||
1439 | s5k5baf_bound_rect(r, br->width, br->height); | ||
1440 | } while (++i != R_INVALID); | ||
1441 | *v = *rects[first]; | ||
1442 | } | ||
1443 | |||
1444 | static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1, | ||
1445 | const struct v4l2_rect *r2) | ||
1446 | { | ||
1447 | return !memcmp(r1, r2, sizeof(*r1)); | ||
1448 | } | ||
1449 | |||
1450 | static int s5k5baf_set_selection(struct v4l2_subdev *sd, | ||
1451 | struct v4l2_subdev_fh *fh, | ||
1452 | struct v4l2_subdev_selection *sel) | ||
1453 | { | ||
1454 | static enum selection_rect rtype; | ||
1455 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1456 | struct v4l2_rect **rects; | ||
1457 | int ret = 0; | ||
1458 | |||
1459 | rtype = s5k5baf_get_sel_rect(sel->pad, sel->target); | ||
1460 | if (rtype == R_INVALID || s5k5baf_is_bound_target(sel->target)) | ||
1461 | return -EINVAL; | ||
1462 | |||
1463 | /* allow only scaling on compose */ | ||
1464 | if (rtype == R_COMPOSE) { | ||
1465 | sel->r.left = 0; | ||
1466 | sel->r.top = 0; | ||
1467 | } | ||
1468 | |||
1469 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1470 | rects = (struct v4l2_rect * []) { | ||
1471 | &s5k5baf_cis_rect, | ||
1472 | v4l2_subdev_get_try_crop(fh, PAD_CIS), | ||
1473 | v4l2_subdev_get_try_compose(fh, PAD_CIS), | ||
1474 | v4l2_subdev_get_try_crop(fh, PAD_OUT) | ||
1475 | }; | ||
1476 | s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r); | ||
1477 | return 0; | ||
1478 | } | ||
1479 | |||
1480 | rects = (struct v4l2_rect * []) { | ||
1481 | &s5k5baf_cis_rect, | ||
1482 | &state->crop_sink, | ||
1483 | &state->compose, | ||
1484 | &state->crop_source | ||
1485 | }; | ||
1486 | mutex_lock(&state->lock); | ||
1487 | if (state->streaming) { | ||
1488 | /* adjust sel->r to avoid output resolution change */ | ||
1489 | if (rtype < R_CROP_SOURCE) { | ||
1490 | if (sel->r.width < state->crop_source.width) | ||
1491 | sel->r.width = state->crop_source.width; | ||
1492 | if (sel->r.height < state->crop_source.height) | ||
1493 | sel->r.height = state->crop_source.height; | ||
1494 | } else { | ||
1495 | sel->r.width = state->crop_source.width; | ||
1496 | sel->r.height = state->crop_source.height; | ||
1497 | } | ||
1498 | } | ||
1499 | s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r); | ||
1500 | if (!s5k5baf_cmp_rect(&state->crop_sink, &s5k5baf_cis_rect) || | ||
1501 | !s5k5baf_cmp_rect(&state->compose, &s5k5baf_cis_rect)) | ||
1502 | state->apply_crop = 1; | ||
1503 | if (state->streaming) | ||
1504 | ret = s5k5baf_hw_set_crop_rects(state); | ||
1505 | mutex_unlock(&state->lock); | ||
1506 | |||
1507 | return ret; | ||
1508 | } | ||
1509 | |||
1510 | static const struct v4l2_subdev_pad_ops s5k5baf_cis_pad_ops = { | ||
1511 | .enum_mbus_code = s5k5baf_enum_mbus_code, | ||
1512 | .enum_frame_size = s5k5baf_enum_frame_size, | ||
1513 | .get_fmt = s5k5baf_get_fmt, | ||
1514 | .set_fmt = s5k5baf_set_fmt, | ||
1515 | }; | ||
1516 | |||
1517 | static const struct v4l2_subdev_pad_ops s5k5baf_pad_ops = { | ||
1518 | .enum_mbus_code = s5k5baf_enum_mbus_code, | ||
1519 | .enum_frame_size = s5k5baf_enum_frame_size, | ||
1520 | .enum_frame_interval = s5k5baf_enum_frame_interval, | ||
1521 | .get_fmt = s5k5baf_get_fmt, | ||
1522 | .set_fmt = s5k5baf_set_fmt, | ||
1523 | .get_selection = s5k5baf_get_selection, | ||
1524 | .set_selection = s5k5baf_set_selection, | ||
1525 | }; | ||
1526 | |||
1527 | static const struct v4l2_subdev_video_ops s5k5baf_video_ops = { | ||
1528 | .g_frame_interval = s5k5baf_g_frame_interval, | ||
1529 | .s_frame_interval = s5k5baf_s_frame_interval, | ||
1530 | .s_stream = s5k5baf_s_stream, | ||
1531 | }; | ||
1532 | |||
1533 | /* | ||
1534 | * V4L2 subdev controls | ||
1535 | */ | ||
1536 | |||
1537 | static int s5k5baf_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1538 | { | ||
1539 | struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | ||
1540 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1541 | int ret; | ||
1542 | |||
1543 | v4l2_dbg(1, debug, sd, "ctrl: %s, value: %d\n", ctrl->name, ctrl->val); | ||
1544 | |||
1545 | mutex_lock(&state->lock); | ||
1546 | |||
1547 | if (state->power == 0) | ||
1548 | goto unlock; | ||
1549 | |||
1550 | switch (ctrl->id) { | ||
1551 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
1552 | s5k5baf_hw_set_awb(state, ctrl->val); | ||
1553 | break; | ||
1554 | |||
1555 | case V4L2_CID_BRIGHTNESS: | ||
1556 | s5k5baf_write(state, REG_USER_BRIGHTNESS, ctrl->val); | ||
1557 | break; | ||
1558 | |||
1559 | case V4L2_CID_COLORFX: | ||
1560 | s5k5baf_hw_set_colorfx(state, ctrl->val); | ||
1561 | break; | ||
1562 | |||
1563 | case V4L2_CID_CONTRAST: | ||
1564 | s5k5baf_write(state, REG_USER_CONTRAST, ctrl->val); | ||
1565 | break; | ||
1566 | |||
1567 | case V4L2_CID_EXPOSURE_AUTO: | ||
1568 | s5k5baf_hw_set_auto_exposure(state, ctrl->val); | ||
1569 | break; | ||
1570 | |||
1571 | case V4L2_CID_HFLIP: | ||
1572 | s5k5baf_hw_set_mirror(state); | ||
1573 | break; | ||
1574 | |||
1575 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
1576 | s5k5baf_hw_set_anti_flicker(state, ctrl->val); | ||
1577 | break; | ||
1578 | |||
1579 | case V4L2_CID_SATURATION: | ||
1580 | s5k5baf_write(state, REG_USER_SATURATION, ctrl->val); | ||
1581 | break; | ||
1582 | |||
1583 | case V4L2_CID_SHARPNESS: | ||
1584 | s5k5baf_write(state, REG_USER_SHARPBLUR, ctrl->val); | ||
1585 | break; | ||
1586 | |||
1587 | case V4L2_CID_WHITE_BALANCE_TEMPERATURE: | ||
1588 | s5k5baf_write(state, REG_P_COLORTEMP(0), ctrl->val); | ||
1589 | if (state->apply_cfg) | ||
1590 | s5k5baf_hw_sync_cfg(state); | ||
1591 | break; | ||
1592 | |||
1593 | case V4L2_CID_TEST_PATTERN: | ||
1594 | s5k5baf_hw_set_test_pattern(state, ctrl->val); | ||
1595 | break; | ||
1596 | } | ||
1597 | unlock: | ||
1598 | ret = s5k5baf_clear_error(state); | ||
1599 | mutex_unlock(&state->lock); | ||
1600 | return ret; | ||
1601 | } | ||
1602 | |||
1603 | static const struct v4l2_ctrl_ops s5k5baf_ctrl_ops = { | ||
1604 | .s_ctrl = s5k5baf_s_ctrl, | ||
1605 | }; | ||
1606 | |||
1607 | static const char * const s5k5baf_test_pattern_menu[] = { | ||
1608 | "Disabled", | ||
1609 | "Blank", | ||
1610 | "Bars", | ||
1611 | "Gradients", | ||
1612 | "Textile", | ||
1613 | "Textile2", | ||
1614 | "Squares" | ||
1615 | }; | ||
1616 | |||
1617 | static int s5k5baf_initialize_ctrls(struct s5k5baf *state) | ||
1618 | { | ||
1619 | const struct v4l2_ctrl_ops *ops = &s5k5baf_ctrl_ops; | ||
1620 | struct s5k5baf_ctrls *ctrls = &state->ctrls; | ||
1621 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; | ||
1622 | int ret; | ||
1623 | |||
1624 | ret = v4l2_ctrl_handler_init(hdl, 16); | ||
1625 | if (ret < 0) { | ||
1626 | v4l2_err(&state->sd, "cannot init ctrl handler (%d)\n", ret); | ||
1627 | return ret; | ||
1628 | } | ||
1629 | |||
1630 | /* Auto white balance cluster */ | ||
1631 | ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, | ||
1632 | 0, 1, 1, 1); | ||
1633 | ctrls->gain_red = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, | ||
1634 | 0, 255, 1, S5K5BAF_GAIN_RED_DEF); | ||
1635 | ctrls->gain_blue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, | ||
1636 | 0, 255, 1, S5K5BAF_GAIN_BLUE_DEF); | ||
1637 | v4l2_ctrl_auto_cluster(3, &ctrls->awb, 0, false); | ||
1638 | |||
1639 | ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1640 | ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1641 | v4l2_ctrl_cluster(2, &ctrls->hflip); | ||
1642 | |||
1643 | ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, | ||
1644 | V4L2_CID_EXPOSURE_AUTO, | ||
1645 | V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); | ||
1646 | /* Exposure time: x 1 us */ | ||
1647 | ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, | ||
1648 | 0, 6000000U, 1, 100000U); | ||
1649 | /* Total gain: 256 <=> 1x */ | ||
1650 | ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, | ||
1651 | 0, 256, 1, 256); | ||
1652 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false); | ||
1653 | |||
1654 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, | ||
1655 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, | ||
1656 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO); | ||
1657 | |||
1658 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, | ||
1659 | V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE); | ||
1660 | |||
1661 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE, | ||
1662 | 0, 256, 1, 0); | ||
1663 | |||
1664 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0); | ||
1665 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0); | ||
1666 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0); | ||
1667 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0); | ||
1668 | |||
1669 | v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, | ||
1670 | ARRAY_SIZE(s5k5baf_test_pattern_menu) - 1, | ||
1671 | 0, 0, s5k5baf_test_pattern_menu); | ||
1672 | |||
1673 | if (hdl->error) { | ||
1674 | v4l2_err(&state->sd, "error creating controls (%d)\n", | ||
1675 | hdl->error); | ||
1676 | ret = hdl->error; | ||
1677 | v4l2_ctrl_handler_free(hdl); | ||
1678 | return ret; | ||
1679 | } | ||
1680 | |||
1681 | state->sd.ctrl_handler = hdl; | ||
1682 | return 0; | ||
1683 | } | ||
1684 | |||
1685 | /* | ||
1686 | * V4L2 subdev internal operations | ||
1687 | */ | ||
1688 | static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1689 | { | ||
1690 | struct v4l2_mbus_framefmt *mf; | ||
1691 | |||
1692 | mf = v4l2_subdev_get_try_format(fh, PAD_CIS); | ||
1693 | s5k5baf_try_cis_format(mf); | ||
1694 | |||
1695 | if (s5k5baf_is_cis_subdev(sd)) | ||
1696 | return 0; | ||
1697 | |||
1698 | mf = v4l2_subdev_get_try_format(fh, PAD_OUT); | ||
1699 | mf->colorspace = s5k5baf_formats[0].colorspace; | ||
1700 | mf->code = s5k5baf_formats[0].code; | ||
1701 | mf->width = s5k5baf_cis_rect.width; | ||
1702 | mf->height = s5k5baf_cis_rect.height; | ||
1703 | mf->field = V4L2_FIELD_NONE; | ||
1704 | |||
1705 | *v4l2_subdev_get_try_crop(fh, PAD_CIS) = s5k5baf_cis_rect; | ||
1706 | *v4l2_subdev_get_try_compose(fh, PAD_CIS) = s5k5baf_cis_rect; | ||
1707 | *v4l2_subdev_get_try_crop(fh, PAD_OUT) = s5k5baf_cis_rect; | ||
1708 | |||
1709 | return 0; | ||
1710 | } | ||
1711 | |||
1712 | static int s5k5baf_check_fw_revision(struct s5k5baf *state) | ||
1713 | { | ||
1714 | u16 api_ver = 0, fw_rev = 0, s_id = 0; | ||
1715 | int ret; | ||
1716 | |||
1717 | api_ver = s5k5baf_read(state, REG_FW_APIVER); | ||
1718 | fw_rev = s5k5baf_read(state, REG_FW_REVISION) & 0xff; | ||
1719 | s_id = s5k5baf_read(state, REG_FW_SENSOR_ID); | ||
1720 | ret = s5k5baf_clear_error(state); | ||
1721 | if (ret < 0) | ||
1722 | return ret; | ||
1723 | |||
1724 | v4l2_info(&state->sd, "FW API=%#x, revision=%#x sensor_id=%#x\n", | ||
1725 | api_ver, fw_rev, s_id); | ||
1726 | |||
1727 | if (api_ver != S5K5BAF_FW_APIVER) { | ||
1728 | v4l2_err(&state->sd, "FW API version not supported\n"); | ||
1729 | return -ENODEV; | ||
1730 | } | ||
1731 | |||
1732 | return 0; | ||
1733 | } | ||
1734 | |||
1735 | static int s5k5baf_registered(struct v4l2_subdev *sd) | ||
1736 | { | ||
1737 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1738 | int ret; | ||
1739 | |||
1740 | ret = v4l2_device_register_subdev(sd->v4l2_dev, &state->cis_sd); | ||
1741 | if (ret < 0) | ||
1742 | v4l2_err(sd, "failed to register subdev %s\n", | ||
1743 | state->cis_sd.name); | ||
1744 | else | ||
1745 | ret = media_entity_create_link(&state->cis_sd.entity, PAD_CIS, | ||
1746 | &state->sd.entity, PAD_CIS, | ||
1747 | MEDIA_LNK_FL_IMMUTABLE | | ||
1748 | MEDIA_LNK_FL_ENABLED); | ||
1749 | return ret; | ||
1750 | } | ||
1751 | |||
1752 | static void s5k5baf_unregistered(struct v4l2_subdev *sd) | ||
1753 | { | ||
1754 | struct s5k5baf *state = to_s5k5baf(sd); | ||
1755 | v4l2_device_unregister_subdev(&state->cis_sd); | ||
1756 | } | ||
1757 | |||
1758 | static const struct v4l2_subdev_ops s5k5baf_cis_subdev_ops = { | ||
1759 | .pad = &s5k5baf_cis_pad_ops, | ||
1760 | }; | ||
1761 | |||
1762 | static const struct v4l2_subdev_internal_ops s5k5baf_cis_subdev_internal_ops = { | ||
1763 | .open = s5k5baf_open, | ||
1764 | }; | ||
1765 | |||
1766 | static const struct v4l2_subdev_internal_ops s5k5baf_subdev_internal_ops = { | ||
1767 | .registered = s5k5baf_registered, | ||
1768 | .unregistered = s5k5baf_unregistered, | ||
1769 | .open = s5k5baf_open, | ||
1770 | }; | ||
1771 | |||
1772 | static const struct v4l2_subdev_core_ops s5k5baf_core_ops = { | ||
1773 | .s_power = s5k5baf_set_power, | ||
1774 | .log_status = v4l2_ctrl_subdev_log_status, | ||
1775 | }; | ||
1776 | |||
1777 | static const struct v4l2_subdev_ops s5k5baf_subdev_ops = { | ||
1778 | .core = &s5k5baf_core_ops, | ||
1779 | .pad = &s5k5baf_pad_ops, | ||
1780 | .video = &s5k5baf_video_ops, | ||
1781 | }; | ||
1782 | |||
1783 | static int s5k5baf_configure_gpios(struct s5k5baf *state) | ||
1784 | { | ||
1785 | static const char const *name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" }; | ||
1786 | struct i2c_client *c = v4l2_get_subdevdata(&state->sd); | ||
1787 | struct s5k5baf_gpio *g = state->gpios; | ||
1788 | int ret, i; | ||
1789 | |||
1790 | for (i = 0; i < NUM_GPIOS; ++i) { | ||
1791 | int flags = GPIOF_DIR_OUT; | ||
1792 | if (g[i].level) | ||
1793 | flags |= GPIOF_INIT_HIGH; | ||
1794 | ret = devm_gpio_request_one(&c->dev, g[i].gpio, flags, name[i]); | ||
1795 | if (ret < 0) { | ||
1796 | v4l2_err(c, "failed to request gpio %s\n", name[i]); | ||
1797 | return ret; | ||
1798 | } | ||
1799 | } | ||
1800 | return 0; | ||
1801 | } | ||
1802 | |||
1803 | static int s5k5baf_parse_gpios(struct s5k5baf_gpio *gpios, struct device *dev) | ||
1804 | { | ||
1805 | static const char * const names[] = { | ||
1806 | "stbyn-gpios", | ||
1807 | "rstn-gpios", | ||
1808 | }; | ||
1809 | struct device_node *node = dev->of_node; | ||
1810 | enum of_gpio_flags flags; | ||
1811 | int ret, i; | ||
1812 | |||
1813 | for (i = 0; i < NUM_GPIOS; ++i) { | ||
1814 | ret = of_get_named_gpio_flags(node, names[i], 0, &flags); | ||
1815 | if (ret < 0) { | ||
1816 | dev_err(dev, "no %s GPIO pin provided\n", names[i]); | ||
1817 | return ret; | ||
1818 | } | ||
1819 | gpios[i].gpio = ret; | ||
1820 | gpios[i].level = !(flags & OF_GPIO_ACTIVE_LOW); | ||
1821 | } | ||
1822 | |||
1823 | return 0; | ||
1824 | } | ||
1825 | |||
1826 | static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) | ||
1827 | { | ||
1828 | struct device_node *node = dev->of_node; | ||
1829 | struct device_node *node_ep; | ||
1830 | struct v4l2_of_endpoint ep; | ||
1831 | int ret; | ||
1832 | |||
1833 | if (!node) { | ||
1834 | dev_err(dev, "no device-tree node provided\n"); | ||
1835 | return -EINVAL; | ||
1836 | } | ||
1837 | |||
1838 | ret = of_property_read_u32(node, "clock-frequency", | ||
1839 | &state->mclk_frequency); | ||
1840 | if (ret < 0) { | ||
1841 | state->mclk_frequency = S5K5BAF_DEFAULT_MCLK_FREQ; | ||
1842 | dev_info(dev, "using default %u Hz clock frequency\n", | ||
1843 | state->mclk_frequency); | ||
1844 | } | ||
1845 | |||
1846 | ret = s5k5baf_parse_gpios(state->gpios, dev); | ||
1847 | if (ret < 0) | ||
1848 | return ret; | ||
1849 | |||
1850 | node_ep = v4l2_of_get_next_endpoint(node, NULL); | ||
1851 | if (!node_ep) { | ||
1852 | dev_err(dev, "no endpoint defined at node %s\n", | ||
1853 | node->full_name); | ||
1854 | return -EINVAL; | ||
1855 | } | ||
1856 | |||
1857 | v4l2_of_parse_endpoint(node_ep, &ep); | ||
1858 | of_node_put(node_ep); | ||
1859 | state->bus_type = ep.bus_type; | ||
1860 | |||
1861 | switch (state->bus_type) { | ||
1862 | case V4L2_MBUS_CSI2: | ||
1863 | state->nlanes = ep.bus.mipi_csi2.num_data_lanes; | ||
1864 | break; | ||
1865 | case V4L2_MBUS_PARALLEL: | ||
1866 | break; | ||
1867 | default: | ||
1868 | dev_err(dev, "unsupported bus in endpoint defined at node %s\n", | ||
1869 | node->full_name); | ||
1870 | return -EINVAL; | ||
1871 | } | ||
1872 | |||
1873 | return 0; | ||
1874 | } | ||
1875 | |||
1876 | static int s5k5baf_configure_subdevs(struct s5k5baf *state, | ||
1877 | struct i2c_client *c) | ||
1878 | { | ||
1879 | struct v4l2_subdev *sd; | ||
1880 | int ret; | ||
1881 | |||
1882 | sd = &state->cis_sd; | ||
1883 | v4l2_subdev_init(sd, &s5k5baf_cis_subdev_ops); | ||
1884 | sd->owner = THIS_MODULE; | ||
1885 | v4l2_set_subdevdata(sd, state); | ||
1886 | snprintf(sd->name, sizeof(sd->name), "S5K5BAF-CIS %d-%04x", | ||
1887 | i2c_adapter_id(c->adapter), c->addr); | ||
1888 | |||
1889 | sd->internal_ops = &s5k5baf_cis_subdev_internal_ops; | ||
1890 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1891 | |||
1892 | state->cis_pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1893 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1894 | ret = media_entity_init(&sd->entity, NUM_CIS_PADS, &state->cis_pad, 0); | ||
1895 | if (ret < 0) | ||
1896 | goto err; | ||
1897 | |||
1898 | sd = &state->sd; | ||
1899 | v4l2_i2c_subdev_init(sd, c, &s5k5baf_subdev_ops); | ||
1900 | snprintf(sd->name, sizeof(sd->name), "S5K5BAF-ISP %d-%04x", | ||
1901 | i2c_adapter_id(c->adapter), c->addr); | ||
1902 | |||
1903 | sd->internal_ops = &s5k5baf_subdev_internal_ops; | ||
1904 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1905 | |||
1906 | state->pads[PAD_CIS].flags = MEDIA_PAD_FL_SINK; | ||
1907 | state->pads[PAD_OUT].flags = MEDIA_PAD_FL_SOURCE; | ||
1908 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; | ||
1909 | ret = media_entity_init(&sd->entity, NUM_ISP_PADS, state->pads, 0); | ||
1910 | |||
1911 | if (!ret) | ||
1912 | return 0; | ||
1913 | |||
1914 | media_entity_cleanup(&state->cis_sd.entity); | ||
1915 | err: | ||
1916 | dev_err(&c->dev, "cannot init media entity %s\n", sd->name); | ||
1917 | return ret; | ||
1918 | } | ||
1919 | |||
1920 | static int s5k5baf_configure_regulators(struct s5k5baf *state) | ||
1921 | { | ||
1922 | struct i2c_client *c = v4l2_get_subdevdata(&state->sd); | ||
1923 | int ret; | ||
1924 | int i; | ||
1925 | |||
1926 | for (i = 0; i < S5K5BAF_NUM_SUPPLIES; i++) | ||
1927 | state->supplies[i].supply = s5k5baf_supply_names[i]; | ||
1928 | |||
1929 | ret = devm_regulator_bulk_get(&c->dev, S5K5BAF_NUM_SUPPLIES, | ||
1930 | state->supplies); | ||
1931 | if (ret < 0) | ||
1932 | v4l2_err(c, "failed to get regulators\n"); | ||
1933 | return ret; | ||
1934 | } | ||
1935 | |||
1936 | static int s5k5baf_probe(struct i2c_client *c, | ||
1937 | const struct i2c_device_id *id) | ||
1938 | { | ||
1939 | struct s5k5baf *state; | ||
1940 | int ret; | ||
1941 | |||
1942 | state = devm_kzalloc(&c->dev, sizeof(*state), GFP_KERNEL); | ||
1943 | if (!state) | ||
1944 | return -ENOMEM; | ||
1945 | |||
1946 | mutex_init(&state->lock); | ||
1947 | state->crop_sink = s5k5baf_cis_rect; | ||
1948 | state->compose = s5k5baf_cis_rect; | ||
1949 | state->crop_source = s5k5baf_cis_rect; | ||
1950 | |||
1951 | ret = s5k5baf_parse_device_node(state, &c->dev); | ||
1952 | if (ret < 0) | ||
1953 | return ret; | ||
1954 | |||
1955 | ret = s5k5baf_configure_subdevs(state, c); | ||
1956 | if (ret < 0) | ||
1957 | return ret; | ||
1958 | |||
1959 | ret = s5k5baf_configure_gpios(state); | ||
1960 | if (ret < 0) | ||
1961 | goto err_me; | ||
1962 | |||
1963 | ret = s5k5baf_configure_regulators(state); | ||
1964 | if (ret < 0) | ||
1965 | goto err_me; | ||
1966 | |||
1967 | state->clock = devm_clk_get(state->sd.dev, S5K5BAF_CLK_NAME); | ||
1968 | if (IS_ERR(state->clock)) { | ||
1969 | ret = -EPROBE_DEFER; | ||
1970 | goto err_me; | ||
1971 | } | ||
1972 | |||
1973 | ret = s5k5baf_power_on(state); | ||
1974 | if (ret < 0) { | ||
1975 | ret = -EPROBE_DEFER; | ||
1976 | goto err_me; | ||
1977 | } | ||
1978 | s5k5baf_hw_init(state); | ||
1979 | ret = s5k5baf_check_fw_revision(state); | ||
1980 | |||
1981 | s5k5baf_power_off(state); | ||
1982 | if (ret < 0) | ||
1983 | goto err_me; | ||
1984 | |||
1985 | ret = s5k5baf_initialize_ctrls(state); | ||
1986 | if (ret < 0) | ||
1987 | goto err_me; | ||
1988 | |||
1989 | ret = v4l2_async_register_subdev(&state->sd); | ||
1990 | if (ret < 0) | ||
1991 | goto err_ctrl; | ||
1992 | |||
1993 | return 0; | ||
1994 | |||
1995 | err_ctrl: | ||
1996 | v4l2_ctrl_handler_free(state->sd.ctrl_handler); | ||
1997 | err_me: | ||
1998 | media_entity_cleanup(&state->sd.entity); | ||
1999 | media_entity_cleanup(&state->cis_sd.entity); | ||
2000 | return ret; | ||
2001 | } | ||
2002 | |||
2003 | static int s5k5baf_remove(struct i2c_client *c) | ||
2004 | { | ||
2005 | struct v4l2_subdev *sd = i2c_get_clientdata(c); | ||
2006 | struct s5k5baf *state = to_s5k5baf(sd); | ||
2007 | |||
2008 | v4l2_async_unregister_subdev(sd); | ||
2009 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
2010 | media_entity_cleanup(&sd->entity); | ||
2011 | |||
2012 | sd = &state->cis_sd; | ||
2013 | v4l2_device_unregister_subdev(sd); | ||
2014 | media_entity_cleanup(&sd->entity); | ||
2015 | |||
2016 | return 0; | ||
2017 | } | ||
2018 | |||
2019 | static const struct i2c_device_id s5k5baf_id[] = { | ||
2020 | { S5K5BAF_DRIVER_NAME, 0 }, | ||
2021 | { }, | ||
2022 | }; | ||
2023 | MODULE_DEVICE_TABLE(i2c, s5k5baf_id); | ||
2024 | |||
2025 | static const struct of_device_id s5k5baf_of_match[] = { | ||
2026 | { .compatible = "samsung,s5k5baf" }, | ||
2027 | { } | ||
2028 | }; | ||
2029 | MODULE_DEVICE_TABLE(of, s5k5baf_of_match); | ||
2030 | |||
2031 | static struct i2c_driver s5k5baf_i2c_driver = { | ||
2032 | .driver = { | ||
2033 | .of_match_table = s5k5baf_of_match, | ||
2034 | .name = S5K5BAF_DRIVER_NAME | ||
2035 | }, | ||
2036 | .probe = s5k5baf_probe, | ||
2037 | .remove = s5k5baf_remove, | ||
2038 | .id_table = s5k5baf_id, | ||
2039 | }; | ||
2040 | |||
2041 | module_i2c_driver(s5k5baf_i2c_driver); | ||
2042 | |||
2043 | MODULE_DESCRIPTION("Samsung S5K5BAF(X) UXGA camera driver"); | ||
2044 | MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); | ||
2045 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 70bc72e795d0..2960b5a8362a 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c | |||
@@ -150,14 +150,14 @@ static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd) | |||
150 | 150 | ||
151 | /* ---------------------------------------------------------------------- */ | 151 | /* ---------------------------------------------------------------------- */ |
152 | 152 | ||
153 | static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf) | 153 | static bool block_from_buf(struct saa6588 *s, unsigned char *buf) |
154 | { | 154 | { |
155 | int i; | 155 | int i; |
156 | 156 | ||
157 | if (s->rd_index == s->wr_index) { | 157 | if (s->rd_index == s->wr_index) { |
158 | if (debug > 2) | 158 | if (debug > 2) |
159 | dprintk(PREFIX "Read: buffer empty.\n"); | 159 | dprintk(PREFIX "Read: buffer empty.\n"); |
160 | return 0; | 160 | return false; |
161 | } | 161 | } |
162 | 162 | ||
163 | if (debug > 2) { | 163 | if (debug > 2) { |
@@ -166,8 +166,7 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf) | |||
166 | dprintk("0x%02x ", s->buffer[i]); | 166 | dprintk("0x%02x ", s->buffer[i]); |
167 | } | 167 | } |
168 | 168 | ||
169 | if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3)) | 169 | memcpy(buf, &s->buffer[s->rd_index], 3); |
170 | return -EFAULT; | ||
171 | 170 | ||
172 | s->rd_index += 3; | 171 | s->rd_index += 3; |
173 | if (s->rd_index >= s->buf_size) | 172 | if (s->rd_index >= s->buf_size) |
@@ -177,22 +176,22 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf) | |||
177 | if (debug > 2) | 176 | if (debug > 2) |
178 | dprintk("%d blocks total.\n", s->block_count); | 177 | dprintk("%d blocks total.\n", s->block_count); |
179 | 178 | ||
180 | return 1; | 179 | return true; |
181 | } | 180 | } |
182 | 181 | ||
183 | static void read_from_buf(struct saa6588 *s, struct saa6588_command *a) | 182 | static void read_from_buf(struct saa6588 *s, struct saa6588_command *a) |
184 | { | 183 | { |
185 | unsigned long flags; | ||
186 | |||
187 | unsigned char __user *buf_ptr = a->buffer; | 184 | unsigned char __user *buf_ptr = a->buffer; |
188 | unsigned int i; | 185 | unsigned char buf[3]; |
186 | unsigned long flags; | ||
189 | unsigned int rd_blocks; | 187 | unsigned int rd_blocks; |
188 | unsigned int i; | ||
190 | 189 | ||
191 | a->result = 0; | 190 | a->result = 0; |
192 | if (!a->buffer) | 191 | if (!a->buffer) |
193 | return; | 192 | return; |
194 | 193 | ||
195 | while (!s->data_available_for_read) { | 194 | while (!a->nonblocking && !s->data_available_for_read) { |
196 | int ret = wait_event_interruptible(s->read_queue, | 195 | int ret = wait_event_interruptible(s->read_queue, |
197 | s->data_available_for_read); | 196 | s->data_available_for_read); |
198 | if (ret == -ERESTARTSYS) { | 197 | if (ret == -ERESTARTSYS) { |
@@ -201,24 +200,31 @@ static void read_from_buf(struct saa6588 *s, struct saa6588_command *a) | |||
201 | } | 200 | } |
202 | } | 201 | } |
203 | 202 | ||
204 | spin_lock_irqsave(&s->lock, flags); | ||
205 | rd_blocks = a->block_count; | 203 | rd_blocks = a->block_count; |
204 | spin_lock_irqsave(&s->lock, flags); | ||
206 | if (rd_blocks > s->block_count) | 205 | if (rd_blocks > s->block_count) |
207 | rd_blocks = s->block_count; | 206 | rd_blocks = s->block_count; |
207 | spin_unlock_irqrestore(&s->lock, flags); | ||
208 | 208 | ||
209 | if (!rd_blocks) { | 209 | if (!rd_blocks) |
210 | spin_unlock_irqrestore(&s->lock, flags); | ||
211 | return; | 210 | return; |
212 | } | ||
213 | 211 | ||
214 | for (i = 0; i < rd_blocks; i++) { | 212 | for (i = 0; i < rd_blocks; i++) { |
215 | if (block_to_user_buf(s, buf_ptr)) { | 213 | bool got_block; |
216 | buf_ptr += 3; | 214 | |
217 | a->result++; | 215 | spin_lock_irqsave(&s->lock, flags); |
218 | } else | 216 | got_block = block_from_buf(s, buf); |
217 | spin_unlock_irqrestore(&s->lock, flags); | ||
218 | if (!got_block) | ||
219 | break; | 219 | break; |
220 | if (copy_to_user(buf_ptr, buf, 3)) { | ||
221 | a->result = -EFAULT; | ||
222 | return; | ||
223 | } | ||
224 | buf_ptr += 3; | ||
225 | a->result += 3; | ||
220 | } | 226 | } |
221 | a->result *= 3; | 227 | spin_lock_irqsave(&s->lock, flags); |
222 | s->data_available_for_read = (s->block_count > 0); | 228 | s->data_available_for_read = (s->block_count > 0); |
223 | spin_unlock_irqrestore(&s->lock, flags); | 229 | spin_unlock_irqrestore(&s->lock, flags); |
224 | } | 230 | } |
@@ -394,14 +400,11 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) | |||
394 | struct saa6588_command *a = arg; | 400 | struct saa6588_command *a = arg; |
395 | 401 | ||
396 | switch (cmd) { | 402 | switch (cmd) { |
397 | /* --- open() for /dev/radio --- */ | ||
398 | case SAA6588_CMD_OPEN: | ||
399 | a->result = 0; /* return error if chip doesn't work ??? */ | ||
400 | break; | ||
401 | /* --- close() for /dev/radio --- */ | 403 | /* --- close() for /dev/radio --- */ |
402 | case SAA6588_CMD_CLOSE: | 404 | case SAA6588_CMD_CLOSE: |
403 | s->data_available_for_read = 1; | 405 | s->data_available_for_read = 1; |
404 | wake_up_interruptible(&s->read_queue); | 406 | wake_up_interruptible(&s->read_queue); |
407 | s->data_available_for_read = 0; | ||
405 | a->result = 0; | 408 | a->result = 0; |
406 | break; | 409 | break; |
407 | /* --- read() for /dev/radio --- */ | 410 | /* --- read() for /dev/radio --- */ |
@@ -411,9 +414,8 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) | |||
411 | /* --- poll() for /dev/radio --- */ | 414 | /* --- poll() for /dev/radio --- */ |
412 | case SAA6588_CMD_POLL: | 415 | case SAA6588_CMD_POLL: |
413 | a->result = 0; | 416 | a->result = 0; |
414 | if (s->data_available_for_read) { | 417 | if (s->data_available_for_read) |
415 | a->result |= POLLIN | POLLRDNORM; | 418 | a->result |= POLLIN | POLLRDNORM; |
416 | } | ||
417 | poll_wait(a->instance, &s->read_queue, a->event_list); | 419 | poll_wait(a->instance, &s->read_queue, a->event_list); |
418 | break; | 420 | break; |
419 | 421 | ||
diff --git a/drivers/media/pci/saa7134/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 8ac4b1f2322d..8272c0b9c5bf 100644 --- a/drivers/media/pci/saa7134/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c | |||
@@ -33,11 +33,11 @@ | |||
33 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
34 | #include <linux/types.h> | 34 | #include <linux/types.h> |
35 | #include <linux/videodev2.h> | 35 | #include <linux/videodev2.h> |
36 | #include <linux/init.h> | ||
37 | #include <linux/crc32.h> | ||
36 | #include <media/v4l2-device.h> | 38 | #include <media/v4l2-device.h> |
37 | #include <media/v4l2-ctrls.h> | 39 | #include <media/v4l2-ctrls.h> |
38 | #include <media/v4l2-common.h> | 40 | #include <media/v4l2-common.h> |
39 | #include <linux/init.h> | ||
40 | #include <linux/crc32.h> | ||
41 | 41 | ||
42 | #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 | 42 | #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 |
43 | #define MPEG_VIDEO_MAX_BITRATE_MAX 27000 | 43 | #define MPEG_VIDEO_MAX_BITRATE_MAX 27000 |
@@ -124,7 +124,7 @@ static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd) | |||
124 | 124 | ||
125 | /* ---------------------------------------------------------------------- */ | 125 | /* ---------------------------------------------------------------------- */ |
126 | 126 | ||
127 | static u8 PAT[] = { | 127 | static const u8 PAT[] = { |
128 | 0xc2, /* i2c register */ | 128 | 0xc2, /* i2c register */ |
129 | 0x00, /* table number for encoder */ | 129 | 0x00, /* table number for encoder */ |
130 | 130 | ||
@@ -150,7 +150,7 @@ static u8 PAT[] = { | |||
150 | 0x00, 0x00, 0x00, 0x00 /* CRC32 */ | 150 | 0x00, 0x00, 0x00, 0x00 /* CRC32 */ |
151 | }; | 151 | }; |
152 | 152 | ||
153 | static u8 PMT[] = { | 153 | static const u8 PMT[] = { |
154 | 0xc2, /* i2c register */ | 154 | 0xc2, /* i2c register */ |
155 | 0x01, /* table number for encoder */ | 155 | 0x01, /* table number for encoder */ |
156 | 156 | ||
@@ -179,7 +179,7 @@ static u8 PMT[] = { | |||
179 | 0x00, 0x00, 0x00, 0x00 /* CRC32 */ | 179 | 0x00, 0x00, 0x00, 0x00 /* CRC32 */ |
180 | }; | 180 | }; |
181 | 181 | ||
182 | static u8 PMT_AC3[] = { | 182 | static const u8 PMT_AC3[] = { |
183 | 0xc2, /* i2c register */ | 183 | 0xc2, /* i2c register */ |
184 | 0x01, /* table number for encoder(1) */ | 184 | 0x01, /* table number for encoder(1) */ |
185 | 0x47, /* sync */ | 185 | 0x47, /* sync */ |
@@ -212,7 +212,7 @@ static u8 PMT_AC3[] = { | |||
212 | 0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */ | 212 | 0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */ |
213 | }; | 213 | }; |
214 | 214 | ||
215 | static struct saa6752hs_mpeg_params param_defaults = | 215 | static const struct saa6752hs_mpeg_params param_defaults = |
216 | { | 216 | { |
217 | .ts_pid_pmt = 16, | 217 | .ts_pid_pmt = 16, |
218 | .ts_pid_video = 260, | 218 | .ts_pid_video = 260, |
@@ -643,13 +643,6 @@ static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = { | |||
643 | 643 | ||
644 | static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { | 644 | static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { |
645 | .init = saa6752hs_init, | 645 | .init = saa6752hs_init, |
646 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
647 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
648 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
649 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
650 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
651 | .queryctrl = v4l2_subdev_queryctrl, | ||
652 | .querymenu = v4l2_subdev_querymenu, | ||
653 | .s_std = saa6752hs_s_std, | 646 | .s_std = saa6752hs_s_std, |
654 | }; | 647 | }; |
655 | 648 | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index ae66d91bf713..8741cae9c9f2 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c | |||
@@ -399,7 +399,6 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor) | |||
399 | 399 | ||
400 | BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order | 400 | BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order |
401 | >= ARRAY_SIZE(smiapp_csi_data_formats)); | 401 | >= ARRAY_SIZE(smiapp_csi_data_formats)); |
402 | BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0); | ||
403 | 402 | ||
404 | dev_dbg(&client->dev, "new pixel order %s\n", | 403 | dev_dbg(&client->dev, "new pixel order %s\n", |
405 | pixel_order_str[pixel_order]); | 404 | pixel_order_str[pixel_order]); |
@@ -2028,8 +2027,8 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, | |||
2028 | sel->r.width = min(sel->r.width, src_size->width); | 2027 | sel->r.width = min(sel->r.width, src_size->width); |
2029 | sel->r.height = min(sel->r.height, src_size->height); | 2028 | sel->r.height = min(sel->r.height, src_size->height); |
2030 | 2029 | ||
2031 | sel->r.left = min(sel->r.left, src_size->width - sel->r.width); | 2030 | sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width); |
2032 | sel->r.top = min(sel->r.top, src_size->height - sel->r.height); | 2031 | sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height); |
2033 | 2032 | ||
2034 | *crops[sel->pad] = sel->r; | 2033 | *crops[sel->pad] = sel->r; |
2035 | 2034 | ||
@@ -2121,8 +2120,8 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, | |||
2121 | 2120 | ||
2122 | sel->r.left = max(0, sel->r.left & ~1); | 2121 | sel->r.left = max(0, sel->r.left & ~1); |
2123 | sel->r.top = max(0, sel->r.top & ~1); | 2122 | sel->r.top = max(0, sel->r.top & ~1); |
2124 | sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags)); | 2123 | sel->r.width = SMIAPP_ALIGN_DIM(sel->r.width, sel->flags); |
2125 | sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags)); | 2124 | sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags); |
2126 | 2125 | ||
2127 | sel->r.width = max_t(unsigned int, | 2126 | sel->r.width = max_t(unsigned int, |
2128 | sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE], | 2127 | sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE], |
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 6f4056668bbc..ccf59406a172 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c | |||
@@ -208,8 +208,8 @@ struct mt9m111 { | |||
208 | struct mt9m111_context *ctx; | 208 | struct mt9m111_context *ctx; |
209 | struct v4l2_rect rect; /* cropping rectangle */ | 209 | struct v4l2_rect rect; /* cropping rectangle */ |
210 | struct v4l2_clk *clk; | 210 | struct v4l2_clk *clk; |
211 | int width; /* output */ | 211 | unsigned int width; /* output */ |
212 | int height; /* sizes */ | 212 | unsigned int height; /* sizes */ |
213 | struct mutex power_lock; /* lock to protect power_count */ | 213 | struct mutex power_lock; /* lock to protect power_count */ |
214 | int power_count; | 214 | int power_count; |
215 | const struct mt9m111_datafmt *fmt; | 215 | const struct mt9m111_datafmt *fmt; |
diff --git a/drivers/media/i2c/tcm825x.c b/drivers/media/i2c/tcm825x.c deleted file mode 100644 index 9252529fc5dd..000000000000 --- a/drivers/media/i2c/tcm825x.c +++ /dev/null | |||
@@ -1,937 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/tcm825x.c | ||
3 | * | ||
4 | * TCM825X camera sensor driver. | ||
5 | * | ||
6 | * Copyright (C) 2007 Nokia Corporation. | ||
7 | * | ||
8 | * Contact: Sakari Ailus <sakari.ailus@nokia.com> | ||
9 | * | ||
10 | * Based on code from David Cohen <david.cohen@indt.org.br> | ||
11 | * | ||
12 | * This driver was based on ov9640 sensor driver from MontaVista | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * version 2 as published by the Free Software Foundation. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
26 | * 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <media/v4l2-int-device.h> | ||
32 | |||
33 | #include "tcm825x.h" | ||
34 | |||
35 | /* | ||
36 | * The sensor has two fps modes: the lower one just gives half the fps | ||
37 | * at the same xclk than the high one. | ||
38 | */ | ||
39 | #define MAX_FPS 30 | ||
40 | #define MIN_FPS 8 | ||
41 | #define MAX_HALF_FPS (MAX_FPS / 2) | ||
42 | #define HIGH_FPS_MODE_LOWER_LIMIT 14 | ||
43 | #define DEFAULT_FPS MAX_HALF_FPS | ||
44 | |||
45 | struct tcm825x_sensor { | ||
46 | const struct tcm825x_platform_data *platform_data; | ||
47 | struct v4l2_int_device *v4l2_int_device; | ||
48 | struct i2c_client *i2c_client; | ||
49 | struct v4l2_pix_format pix; | ||
50 | struct v4l2_fract timeperframe; | ||
51 | }; | ||
52 | |||
53 | /* list of image formats supported by TCM825X sensor */ | ||
54 | static const struct v4l2_fmtdesc tcm825x_formats[] = { | ||
55 | { | ||
56 | .description = "YUYV (YUV 4:2:2), packed", | ||
57 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
58 | }, { | ||
59 | /* Note: V4L2 defines RGB565 as: | ||
60 | * | ||
61 | * Byte 0 Byte 1 | ||
62 | * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 | ||
63 | * | ||
64 | * We interpret RGB565 as: | ||
65 | * | ||
66 | * Byte 0 Byte 1 | ||
67 | * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 | ||
68 | */ | ||
69 | .description = "RGB565, le", | ||
70 | .pixelformat = V4L2_PIX_FMT_RGB565, | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | #define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats) | ||
75 | |||
76 | /* | ||
77 | * TCM825X register configuration for all combinations of pixel format and | ||
78 | * image size | ||
79 | */ | ||
80 | static const struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ }; | ||
81 | static const struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ }; | ||
82 | static const struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ }; | ||
83 | static const struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ }; | ||
84 | static const struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ }; | ||
85 | static const struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ }; | ||
86 | |||
87 | static const struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT }; | ||
88 | static const struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT }; | ||
89 | |||
90 | /* Our own specific controls */ | ||
91 | #define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE | ||
92 | #define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1 | ||
93 | #define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2 | ||
94 | #define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3 | ||
95 | #define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4 | ||
96 | #define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME | ||
97 | |||
98 | /* Video controls */ | ||
99 | static struct vcontrol { | ||
100 | struct v4l2_queryctrl qc; | ||
101 | u16 reg; | ||
102 | u16 start_bit; | ||
103 | } video_control[] = { | ||
104 | { | ||
105 | { | ||
106 | .id = V4L2_CID_GAIN, | ||
107 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
108 | .name = "Gain", | ||
109 | .minimum = 0, | ||
110 | .maximum = 63, | ||
111 | .step = 1, | ||
112 | }, | ||
113 | .reg = TCM825X_AG, | ||
114 | .start_bit = 0, | ||
115 | }, | ||
116 | { | ||
117 | { | ||
118 | .id = V4L2_CID_RED_BALANCE, | ||
119 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
120 | .name = "Red Balance", | ||
121 | .minimum = 0, | ||
122 | .maximum = 255, | ||
123 | .step = 1, | ||
124 | }, | ||
125 | .reg = TCM825X_MRG, | ||
126 | .start_bit = 0, | ||
127 | }, | ||
128 | { | ||
129 | { | ||
130 | .id = V4L2_CID_BLUE_BALANCE, | ||
131 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
132 | .name = "Blue Balance", | ||
133 | .minimum = 0, | ||
134 | .maximum = 255, | ||
135 | .step = 1, | ||
136 | }, | ||
137 | .reg = TCM825X_MBG, | ||
138 | .start_bit = 0, | ||
139 | }, | ||
140 | { | ||
141 | { | ||
142 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
143 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
144 | .name = "Auto White Balance", | ||
145 | .minimum = 0, | ||
146 | .maximum = 1, | ||
147 | .step = 0, | ||
148 | }, | ||
149 | .reg = TCM825X_AWBSW, | ||
150 | .start_bit = 7, | ||
151 | }, | ||
152 | { | ||
153 | { | ||
154 | .id = V4L2_CID_EXPOSURE, | ||
155 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
156 | .name = "Exposure Time", | ||
157 | .minimum = 0, | ||
158 | .maximum = 0x1fff, | ||
159 | .step = 1, | ||
160 | }, | ||
161 | .reg = TCM825X_ESRSPD_U, | ||
162 | .start_bit = 0, | ||
163 | }, | ||
164 | { | ||
165 | { | ||
166 | .id = V4L2_CID_HFLIP, | ||
167 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
168 | .name = "Mirror Image", | ||
169 | .minimum = 0, | ||
170 | .maximum = 1, | ||
171 | .step = 0, | ||
172 | }, | ||
173 | .reg = TCM825X_H_INV, | ||
174 | .start_bit = 6, | ||
175 | }, | ||
176 | { | ||
177 | { | ||
178 | .id = V4L2_CID_VFLIP, | ||
179 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
180 | .name = "Vertical Flip", | ||
181 | .minimum = 0, | ||
182 | .maximum = 1, | ||
183 | .step = 0, | ||
184 | }, | ||
185 | .reg = TCM825X_V_INV, | ||
186 | .start_bit = 7, | ||
187 | }, | ||
188 | /* Private controls */ | ||
189 | { | ||
190 | { | ||
191 | .id = V4L2_CID_ALC, | ||
192 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
193 | .name = "Auto Luminance Control", | ||
194 | .minimum = 0, | ||
195 | .maximum = 1, | ||
196 | .step = 0, | ||
197 | }, | ||
198 | .reg = TCM825X_ALCSW, | ||
199 | .start_bit = 7, | ||
200 | }, | ||
201 | { | ||
202 | { | ||
203 | .id = V4L2_CID_H_EDGE_EN, | ||
204 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
205 | .name = "Horizontal Edge Enhancement", | ||
206 | .minimum = 0, | ||
207 | .maximum = 0xff, | ||
208 | .step = 1, | ||
209 | }, | ||
210 | .reg = TCM825X_HDTG, | ||
211 | .start_bit = 0, | ||
212 | }, | ||
213 | { | ||
214 | { | ||
215 | .id = V4L2_CID_V_EDGE_EN, | ||
216 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
217 | .name = "Vertical Edge Enhancement", | ||
218 | .minimum = 0, | ||
219 | .maximum = 0xff, | ||
220 | .step = 1, | ||
221 | }, | ||
222 | .reg = TCM825X_VDTG, | ||
223 | .start_bit = 0, | ||
224 | }, | ||
225 | { | ||
226 | { | ||
227 | .id = V4L2_CID_LENS, | ||
228 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
229 | .name = "Lens Shading Compensation", | ||
230 | .minimum = 0, | ||
231 | .maximum = 0x3f, | ||
232 | .step = 1, | ||
233 | }, | ||
234 | .reg = TCM825X_LENS, | ||
235 | .start_bit = 0, | ||
236 | }, | ||
237 | { | ||
238 | { | ||
239 | .id = V4L2_CID_MAX_EXPOSURE_TIME, | ||
240 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
241 | .name = "Maximum Exposure Time", | ||
242 | .minimum = 0, | ||
243 | .maximum = 0x3, | ||
244 | .step = 1, | ||
245 | }, | ||
246 | .reg = TCM825X_ESRLIM, | ||
247 | .start_bit = 5, | ||
248 | }, | ||
249 | }; | ||
250 | |||
251 | |||
252 | static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = | ||
253 | { &subqcif, &qqvga, &qcif, &qvga, &cif, &vga }; | ||
254 | |||
255 | static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = | ||
256 | { &yuv422, &rgb565 }; | ||
257 | |||
258 | /* | ||
259 | * Read a value from a register in an TCM825X sensor device. The value is | ||
260 | * returned in 'val'. | ||
261 | * Returns zero if successful, or non-zero otherwise. | ||
262 | */ | ||
263 | static int tcm825x_read_reg(struct i2c_client *client, int reg) | ||
264 | { | ||
265 | int err; | ||
266 | struct i2c_msg msg[2]; | ||
267 | u8 reg_buf, data_buf = 0; | ||
268 | |||
269 | if (!client->adapter) | ||
270 | return -ENODEV; | ||
271 | |||
272 | msg[0].addr = client->addr; | ||
273 | msg[0].flags = 0; | ||
274 | msg[0].len = 1; | ||
275 | msg[0].buf = ®_buf; | ||
276 | msg[1].addr = client->addr; | ||
277 | msg[1].flags = I2C_M_RD; | ||
278 | msg[1].len = 1; | ||
279 | msg[1].buf = &data_buf; | ||
280 | |||
281 | reg_buf = reg; | ||
282 | |||
283 | err = i2c_transfer(client->adapter, msg, 2); | ||
284 | if (err < 0) | ||
285 | return err; | ||
286 | return data_buf; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * Write a value to a register in an TCM825X sensor device. | ||
291 | * Returns zero if successful, or non-zero otherwise. | ||
292 | */ | ||
293 | static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val) | ||
294 | { | ||
295 | int err; | ||
296 | struct i2c_msg msg[1]; | ||
297 | unsigned char data[2]; | ||
298 | |||
299 | if (!client->adapter) | ||
300 | return -ENODEV; | ||
301 | |||
302 | msg->addr = client->addr; | ||
303 | msg->flags = 0; | ||
304 | msg->len = 2; | ||
305 | msg->buf = data; | ||
306 | data[0] = reg; | ||
307 | data[1] = val; | ||
308 | err = i2c_transfer(client->adapter, msg, 1); | ||
309 | if (err >= 0) | ||
310 | return 0; | ||
311 | return err; | ||
312 | } | ||
313 | |||
314 | static int __tcm825x_write_reg_mask(struct i2c_client *client, | ||
315 | u8 reg, u8 val, u8 mask) | ||
316 | { | ||
317 | int rc; | ||
318 | |||
319 | /* need to do read - modify - write */ | ||
320 | rc = tcm825x_read_reg(client, reg); | ||
321 | if (rc < 0) | ||
322 | return rc; | ||
323 | |||
324 | rc &= (~mask); /* Clear the masked bits */ | ||
325 | val &= mask; /* Enforce mask on value */ | ||
326 | val |= rc; | ||
327 | |||
328 | /* write the new value to the register */ | ||
329 | rc = tcm825x_write_reg(client, reg, val); | ||
330 | if (rc) | ||
331 | return rc; | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | #define tcm825x_write_reg_mask(client, regmask, val) \ | ||
337 | __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \ | ||
338 | TCM825X_MASK((regmask))) | ||
339 | |||
340 | |||
341 | /* | ||
342 | * Initialize a list of TCM825X registers. | ||
343 | * The list of registers is terminated by the pair of values | ||
344 | * { TCM825X_REG_TERM, TCM825X_VAL_TERM }. | ||
345 | * Returns zero if successful, or non-zero otherwise. | ||
346 | */ | ||
347 | static int tcm825x_write_default_regs(struct i2c_client *client, | ||
348 | const struct tcm825x_reg *reglist) | ||
349 | { | ||
350 | int err; | ||
351 | const struct tcm825x_reg *next = reglist; | ||
352 | |||
353 | while (!((next->reg == TCM825X_REG_TERM) | ||
354 | && (next->val == TCM825X_VAL_TERM))) { | ||
355 | err = tcm825x_write_reg(client, next->reg, next->val); | ||
356 | if (err) { | ||
357 | dev_err(&client->dev, "register writing failed\n"); | ||
358 | return err; | ||
359 | } | ||
360 | next++; | ||
361 | } | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static struct vcontrol *find_vctrl(int id) | ||
367 | { | ||
368 | int i; | ||
369 | |||
370 | if (id < V4L2_CID_BASE) | ||
371 | return NULL; | ||
372 | |||
373 | for (i = 0; i < ARRAY_SIZE(video_control); i++) | ||
374 | if (video_control[i].qc.id == id) | ||
375 | return &video_control[i]; | ||
376 | |||
377 | return NULL; | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Find the best match for a requested image capture size. The best match | ||
382 | * is chosen as the nearest match that has the same number or fewer pixels | ||
383 | * as the requested size, or the smallest image size if the requested size | ||
384 | * has fewer pixels than the smallest image. | ||
385 | */ | ||
386 | static enum image_size tcm825x_find_size(struct v4l2_int_device *s, | ||
387 | unsigned int width, | ||
388 | unsigned int height) | ||
389 | { | ||
390 | enum image_size isize; | ||
391 | unsigned long pixels = width * height; | ||
392 | struct tcm825x_sensor *sensor = s->priv; | ||
393 | |||
394 | for (isize = subQCIF; isize < VGA; isize++) { | ||
395 | if (tcm825x_sizes[isize + 1].height | ||
396 | * tcm825x_sizes[isize + 1].width > pixels) { | ||
397 | dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize); | ||
398 | |||
399 | return isize; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | dev_dbg(&sensor->i2c_client->dev, "format default VGA\n"); | ||
404 | |||
405 | return VGA; | ||
406 | } | ||
407 | |||
408 | /* | ||
409 | * Configure the TCM825X for current image size, pixel format, and | ||
410 | * frame period. fper is the frame period (in seconds) expressed as a | ||
411 | * fraction. Returns zero if successful, or non-zero otherwise. The | ||
412 | * actual frame period is returned in fper. | ||
413 | */ | ||
414 | static int tcm825x_configure(struct v4l2_int_device *s) | ||
415 | { | ||
416 | struct tcm825x_sensor *sensor = s->priv; | ||
417 | struct v4l2_pix_format *pix = &sensor->pix; | ||
418 | enum image_size isize = tcm825x_find_size(s, pix->width, pix->height); | ||
419 | struct v4l2_fract *fper = &sensor->timeperframe; | ||
420 | enum pixel_format pfmt; | ||
421 | int err; | ||
422 | u32 tgt_fps; | ||
423 | u8 val; | ||
424 | |||
425 | /* common register initialization */ | ||
426 | err = tcm825x_write_default_regs( | ||
427 | sensor->i2c_client, sensor->platform_data->default_regs()); | ||
428 | if (err) | ||
429 | return err; | ||
430 | |||
431 | /* configure image size */ | ||
432 | val = tcm825x_siz_reg[isize]->val; | ||
433 | dev_dbg(&sensor->i2c_client->dev, | ||
434 | "configuring image size %d\n", isize); | ||
435 | err = tcm825x_write_reg_mask(sensor->i2c_client, | ||
436 | tcm825x_siz_reg[isize]->reg, val); | ||
437 | if (err) | ||
438 | return err; | ||
439 | |||
440 | /* configure pixel format */ | ||
441 | switch (pix->pixelformat) { | ||
442 | default: | ||
443 | case V4L2_PIX_FMT_RGB565: | ||
444 | pfmt = RGB565; | ||
445 | break; | ||
446 | case V4L2_PIX_FMT_UYVY: | ||
447 | pfmt = YUV422; | ||
448 | break; | ||
449 | } | ||
450 | |||
451 | dev_dbg(&sensor->i2c_client->dev, | ||
452 | "configuring pixel format %d\n", pfmt); | ||
453 | val = tcm825x_fmt_reg[pfmt]->val; | ||
454 | |||
455 | err = tcm825x_write_reg_mask(sensor->i2c_client, | ||
456 | tcm825x_fmt_reg[pfmt]->reg, val); | ||
457 | if (err) | ||
458 | return err; | ||
459 | |||
460 | /* | ||
461 | * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be | ||
462 | * set. Frame rate will be halved from the normal. | ||
463 | */ | ||
464 | tgt_fps = fper->denominator / fper->numerator; | ||
465 | if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) { | ||
466 | val = tcm825x_read_reg(sensor->i2c_client, 0x02); | ||
467 | val |= 0x80; | ||
468 | tcm825x_write_reg(sensor->i2c_client, 0x02, val); | ||
469 | } | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int ioctl_queryctrl(struct v4l2_int_device *s, | ||
475 | struct v4l2_queryctrl *qc) | ||
476 | { | ||
477 | struct vcontrol *control; | ||
478 | |||
479 | control = find_vctrl(qc->id); | ||
480 | |||
481 | if (control == NULL) | ||
482 | return -EINVAL; | ||
483 | |||
484 | *qc = control->qc; | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int ioctl_g_ctrl(struct v4l2_int_device *s, | ||
490 | struct v4l2_control *vc) | ||
491 | { | ||
492 | struct tcm825x_sensor *sensor = s->priv; | ||
493 | struct i2c_client *client = sensor->i2c_client; | ||
494 | int val, r; | ||
495 | struct vcontrol *lvc; | ||
496 | |||
497 | /* exposure time is special, spread across 2 registers */ | ||
498 | if (vc->id == V4L2_CID_EXPOSURE) { | ||
499 | int val_lower, val_upper; | ||
500 | |||
501 | val_upper = tcm825x_read_reg(client, | ||
502 | TCM825X_ADDR(TCM825X_ESRSPD_U)); | ||
503 | if (val_upper < 0) | ||
504 | return val_upper; | ||
505 | val_lower = tcm825x_read_reg(client, | ||
506 | TCM825X_ADDR(TCM825X_ESRSPD_L)); | ||
507 | if (val_lower < 0) | ||
508 | return val_lower; | ||
509 | |||
510 | vc->value = ((val_upper & 0x1f) << 8) | (val_lower); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | lvc = find_vctrl(vc->id); | ||
515 | if (lvc == NULL) | ||
516 | return -EINVAL; | ||
517 | |||
518 | r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg)); | ||
519 | if (r < 0) | ||
520 | return r; | ||
521 | val = r & TCM825X_MASK(lvc->reg); | ||
522 | val >>= lvc->start_bit; | ||
523 | |||
524 | if (val < 0) | ||
525 | return val; | ||
526 | |||
527 | if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP) | ||
528 | val ^= sensor->platform_data->is_upside_down(); | ||
529 | |||
530 | vc->value = val; | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static int ioctl_s_ctrl(struct v4l2_int_device *s, | ||
535 | struct v4l2_control *vc) | ||
536 | { | ||
537 | struct tcm825x_sensor *sensor = s->priv; | ||
538 | struct i2c_client *client = sensor->i2c_client; | ||
539 | struct vcontrol *lvc; | ||
540 | int val = vc->value; | ||
541 | |||
542 | /* exposure time is special, spread across 2 registers */ | ||
543 | if (vc->id == V4L2_CID_EXPOSURE) { | ||
544 | int val_lower, val_upper; | ||
545 | val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L); | ||
546 | val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U); | ||
547 | |||
548 | if (tcm825x_write_reg_mask(client, | ||
549 | TCM825X_ESRSPD_U, val_upper)) | ||
550 | return -EIO; | ||
551 | |||
552 | if (tcm825x_write_reg_mask(client, | ||
553 | TCM825X_ESRSPD_L, val_lower)) | ||
554 | return -EIO; | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | lvc = find_vctrl(vc->id); | ||
560 | if (lvc == NULL) | ||
561 | return -EINVAL; | ||
562 | |||
563 | if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP) | ||
564 | val ^= sensor->platform_data->is_upside_down(); | ||
565 | |||
566 | val = val << lvc->start_bit; | ||
567 | if (tcm825x_write_reg_mask(client, lvc->reg, val)) | ||
568 | return -EIO; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, | ||
574 | struct v4l2_fmtdesc *fmt) | ||
575 | { | ||
576 | int index = fmt->index; | ||
577 | |||
578 | switch (fmt->type) { | ||
579 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
580 | if (index >= TCM825X_NUM_CAPTURE_FORMATS) | ||
581 | return -EINVAL; | ||
582 | break; | ||
583 | |||
584 | default: | ||
585 | return -EINVAL; | ||
586 | } | ||
587 | |||
588 | fmt->flags = tcm825x_formats[index].flags; | ||
589 | strlcpy(fmt->description, tcm825x_formats[index].description, | ||
590 | sizeof(fmt->description)); | ||
591 | fmt->pixelformat = tcm825x_formats[index].pixelformat; | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int ioctl_try_fmt_cap(struct v4l2_int_device *s, | ||
597 | struct v4l2_format *f) | ||
598 | { | ||
599 | struct tcm825x_sensor *sensor = s->priv; | ||
600 | enum image_size isize; | ||
601 | int ifmt; | ||
602 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
603 | |||
604 | isize = tcm825x_find_size(s, pix->width, pix->height); | ||
605 | dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n", | ||
606 | isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS); | ||
607 | |||
608 | pix->width = tcm825x_sizes[isize].width; | ||
609 | pix->height = tcm825x_sizes[isize].height; | ||
610 | |||
611 | for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++) | ||
612 | if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat) | ||
613 | break; | ||
614 | |||
615 | if (ifmt == TCM825X_NUM_CAPTURE_FORMATS) | ||
616 | ifmt = 0; /* Default = YUV 4:2:2 */ | ||
617 | |||
618 | pix->pixelformat = tcm825x_formats[ifmt].pixelformat; | ||
619 | pix->field = V4L2_FIELD_NONE; | ||
620 | pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL; | ||
621 | pix->sizeimage = pix->bytesperline * pix->height; | ||
622 | pix->priv = 0; | ||
623 | dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n", | ||
624 | pix->pixelformat); | ||
625 | |||
626 | switch (pix->pixelformat) { | ||
627 | case V4L2_PIX_FMT_UYVY: | ||
628 | default: | ||
629 | pix->colorspace = V4L2_COLORSPACE_JPEG; | ||
630 | break; | ||
631 | case V4L2_PIX_FMT_RGB565: | ||
632 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
633 | break; | ||
634 | } | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int ioctl_s_fmt_cap(struct v4l2_int_device *s, | ||
640 | struct v4l2_format *f) | ||
641 | { | ||
642 | struct tcm825x_sensor *sensor = s->priv; | ||
643 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
644 | int rval; | ||
645 | |||
646 | rval = ioctl_try_fmt_cap(s, f); | ||
647 | if (rval) | ||
648 | return rval; | ||
649 | |||
650 | rval = tcm825x_configure(s); | ||
651 | |||
652 | sensor->pix = *pix; | ||
653 | |||
654 | return rval; | ||
655 | } | ||
656 | |||
657 | static int ioctl_g_fmt_cap(struct v4l2_int_device *s, | ||
658 | struct v4l2_format *f) | ||
659 | { | ||
660 | struct tcm825x_sensor *sensor = s->priv; | ||
661 | |||
662 | f->fmt.pix = sensor->pix; | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int ioctl_g_parm(struct v4l2_int_device *s, | ||
668 | struct v4l2_streamparm *a) | ||
669 | { | ||
670 | struct tcm825x_sensor *sensor = s->priv; | ||
671 | struct v4l2_captureparm *cparm = &a->parm.capture; | ||
672 | |||
673 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
674 | return -EINVAL; | ||
675 | |||
676 | memset(a, 0, sizeof(*a)); | ||
677 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
678 | |||
679 | cparm->capability = V4L2_CAP_TIMEPERFRAME; | ||
680 | cparm->timeperframe = sensor->timeperframe; | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static int ioctl_s_parm(struct v4l2_int_device *s, | ||
686 | struct v4l2_streamparm *a) | ||
687 | { | ||
688 | struct tcm825x_sensor *sensor = s->priv; | ||
689 | struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; | ||
690 | u32 tgt_fps; /* target frames per secound */ | ||
691 | int rval; | ||
692 | |||
693 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
694 | return -EINVAL; | ||
695 | |||
696 | if ((timeperframe->numerator == 0) | ||
697 | || (timeperframe->denominator == 0)) { | ||
698 | timeperframe->denominator = DEFAULT_FPS; | ||
699 | timeperframe->numerator = 1; | ||
700 | } | ||
701 | |||
702 | tgt_fps = timeperframe->denominator / timeperframe->numerator; | ||
703 | |||
704 | if (tgt_fps > MAX_FPS) { | ||
705 | timeperframe->denominator = MAX_FPS; | ||
706 | timeperframe->numerator = 1; | ||
707 | } else if (tgt_fps < MIN_FPS) { | ||
708 | timeperframe->denominator = MIN_FPS; | ||
709 | timeperframe->numerator = 1; | ||
710 | } | ||
711 | |||
712 | sensor->timeperframe = *timeperframe; | ||
713 | |||
714 | rval = tcm825x_configure(s); | ||
715 | |||
716 | return rval; | ||
717 | } | ||
718 | |||
719 | static int ioctl_s_power(struct v4l2_int_device *s, int on) | ||
720 | { | ||
721 | struct tcm825x_sensor *sensor = s->priv; | ||
722 | |||
723 | return sensor->platform_data->power_set(on); | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | * Given the image capture format in pix, the nominal frame period in | ||
728 | * timeperframe, calculate the required xclk frequency. | ||
729 | * | ||
730 | * TCM825X input frequency characteristics are: | ||
731 | * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz | ||
732 | */ | ||
733 | |||
734 | static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) | ||
735 | { | ||
736 | struct tcm825x_sensor *sensor = s->priv; | ||
737 | struct v4l2_fract *timeperframe = &sensor->timeperframe; | ||
738 | u32 tgt_xclk; /* target xclk */ | ||
739 | u32 tgt_fps; /* target frames per secound */ | ||
740 | int rval; | ||
741 | |||
742 | rval = sensor->platform_data->ifparm(p); | ||
743 | if (rval) | ||
744 | return rval; | ||
745 | |||
746 | tgt_fps = timeperframe->denominator / timeperframe->numerator; | ||
747 | |||
748 | tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? | ||
749 | (2457 * tgt_fps) / MAX_HALF_FPS : | ||
750 | (2457 * tgt_fps) / MAX_FPS; | ||
751 | tgt_xclk *= 10000; | ||
752 | |||
753 | tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX); | ||
754 | tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN); | ||
755 | |||
756 | p->u.bt656.clock_curr = tgt_xclk; | ||
757 | |||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) | ||
762 | { | ||
763 | struct tcm825x_sensor *sensor = s->priv; | ||
764 | |||
765 | return sensor->platform_data->needs_reset(s, buf, &sensor->pix); | ||
766 | } | ||
767 | |||
768 | static int ioctl_reset(struct v4l2_int_device *s) | ||
769 | { | ||
770 | return -EBUSY; | ||
771 | } | ||
772 | |||
773 | static int ioctl_init(struct v4l2_int_device *s) | ||
774 | { | ||
775 | return tcm825x_configure(s); | ||
776 | } | ||
777 | |||
778 | static int ioctl_dev_exit(struct v4l2_int_device *s) | ||
779 | { | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static int ioctl_dev_init(struct v4l2_int_device *s) | ||
784 | { | ||
785 | struct tcm825x_sensor *sensor = s->priv; | ||
786 | int r; | ||
787 | |||
788 | r = tcm825x_read_reg(sensor->i2c_client, 0x01); | ||
789 | if (r < 0) | ||
790 | return r; | ||
791 | if (r == 0) { | ||
792 | dev_err(&sensor->i2c_client->dev, "device not detected\n"); | ||
793 | return -EIO; | ||
794 | } | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = { | ||
799 | { vidioc_int_dev_init_num, | ||
800 | (v4l2_int_ioctl_func *)ioctl_dev_init }, | ||
801 | { vidioc_int_dev_exit_num, | ||
802 | (v4l2_int_ioctl_func *)ioctl_dev_exit }, | ||
803 | { vidioc_int_s_power_num, | ||
804 | (v4l2_int_ioctl_func *)ioctl_s_power }, | ||
805 | { vidioc_int_g_ifparm_num, | ||
806 | (v4l2_int_ioctl_func *)ioctl_g_ifparm }, | ||
807 | { vidioc_int_g_needs_reset_num, | ||
808 | (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, | ||
809 | { vidioc_int_reset_num, | ||
810 | (v4l2_int_ioctl_func *)ioctl_reset }, | ||
811 | { vidioc_int_init_num, | ||
812 | (v4l2_int_ioctl_func *)ioctl_init }, | ||
813 | { vidioc_int_enum_fmt_cap_num, | ||
814 | (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, | ||
815 | { vidioc_int_try_fmt_cap_num, | ||
816 | (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, | ||
817 | { vidioc_int_g_fmt_cap_num, | ||
818 | (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, | ||
819 | { vidioc_int_s_fmt_cap_num, | ||
820 | (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, | ||
821 | { vidioc_int_g_parm_num, | ||
822 | (v4l2_int_ioctl_func *)ioctl_g_parm }, | ||
823 | { vidioc_int_s_parm_num, | ||
824 | (v4l2_int_ioctl_func *)ioctl_s_parm }, | ||
825 | { vidioc_int_queryctrl_num, | ||
826 | (v4l2_int_ioctl_func *)ioctl_queryctrl }, | ||
827 | { vidioc_int_g_ctrl_num, | ||
828 | (v4l2_int_ioctl_func *)ioctl_g_ctrl }, | ||
829 | { vidioc_int_s_ctrl_num, | ||
830 | (v4l2_int_ioctl_func *)ioctl_s_ctrl }, | ||
831 | }; | ||
832 | |||
833 | static struct v4l2_int_slave tcm825x_slave = { | ||
834 | .ioctls = tcm825x_ioctl_desc, | ||
835 | .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc), | ||
836 | }; | ||
837 | |||
838 | static struct tcm825x_sensor tcm825x; | ||
839 | |||
840 | static struct v4l2_int_device tcm825x_int_device = { | ||
841 | .module = THIS_MODULE, | ||
842 | .name = TCM825X_NAME, | ||
843 | .priv = &tcm825x, | ||
844 | .type = v4l2_int_type_slave, | ||
845 | .u = { | ||
846 | .slave = &tcm825x_slave, | ||
847 | }, | ||
848 | }; | ||
849 | |||
850 | static int tcm825x_probe(struct i2c_client *client, | ||
851 | const struct i2c_device_id *did) | ||
852 | { | ||
853 | struct tcm825x_sensor *sensor = &tcm825x; | ||
854 | |||
855 | if (i2c_get_clientdata(client)) | ||
856 | return -EBUSY; | ||
857 | |||
858 | sensor->platform_data = client->dev.platform_data; | ||
859 | |||
860 | if (sensor->platform_data == NULL | ||
861 | || !sensor->platform_data->is_okay()) | ||
862 | return -ENODEV; | ||
863 | |||
864 | sensor->v4l2_int_device = &tcm825x_int_device; | ||
865 | |||
866 | sensor->i2c_client = client; | ||
867 | i2c_set_clientdata(client, sensor); | ||
868 | |||
869 | /* Make the default capture format QVGA RGB565 */ | ||
870 | sensor->pix.width = tcm825x_sizes[QVGA].width; | ||
871 | sensor->pix.height = tcm825x_sizes[QVGA].height; | ||
872 | sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; | ||
873 | |||
874 | return v4l2_int_device_register(sensor->v4l2_int_device); | ||
875 | } | ||
876 | |||
877 | static int tcm825x_remove(struct i2c_client *client) | ||
878 | { | ||
879 | struct tcm825x_sensor *sensor = i2c_get_clientdata(client); | ||
880 | |||
881 | if (!client->adapter) | ||
882 | return -ENODEV; /* our client isn't attached */ | ||
883 | |||
884 | v4l2_int_device_unregister(sensor->v4l2_int_device); | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static const struct i2c_device_id tcm825x_id[] = { | ||
890 | { "tcm825x", 0 }, | ||
891 | { } | ||
892 | }; | ||
893 | MODULE_DEVICE_TABLE(i2c, tcm825x_id); | ||
894 | |||
895 | static struct i2c_driver tcm825x_i2c_driver = { | ||
896 | .driver = { | ||
897 | .name = TCM825X_NAME, | ||
898 | }, | ||
899 | .probe = tcm825x_probe, | ||
900 | .remove = tcm825x_remove, | ||
901 | .id_table = tcm825x_id, | ||
902 | }; | ||
903 | |||
904 | static struct tcm825x_sensor tcm825x = { | ||
905 | .timeperframe = { | ||
906 | .numerator = 1, | ||
907 | .denominator = DEFAULT_FPS, | ||
908 | }, | ||
909 | }; | ||
910 | |||
911 | static int __init tcm825x_init(void) | ||
912 | { | ||
913 | int rval; | ||
914 | |||
915 | rval = i2c_add_driver(&tcm825x_i2c_driver); | ||
916 | if (rval) | ||
917 | printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n", | ||
918 | __func__); | ||
919 | |||
920 | return rval; | ||
921 | } | ||
922 | |||
923 | static void __exit tcm825x_exit(void) | ||
924 | { | ||
925 | i2c_del_driver(&tcm825x_i2c_driver); | ||
926 | } | ||
927 | |||
928 | /* | ||
929 | * FIXME: Menelaus isn't ready (?) at module_init stage, so use | ||
930 | * late_initcall for now. | ||
931 | */ | ||
932 | late_initcall(tcm825x_init); | ||
933 | module_exit(tcm825x_exit); | ||
934 | |||
935 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>"); | ||
936 | MODULE_DESCRIPTION("TCM825x camera sensor driver"); | ||
937 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/i2c/tcm825x.h b/drivers/media/i2c/tcm825x.h deleted file mode 100644 index 8ebab953963f..000000000000 --- a/drivers/media/i2c/tcm825x.h +++ /dev/null | |||
@@ -1,200 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/tcm825x.h | ||
3 | * | ||
4 | * Register definitions for the TCM825X CameraChip. | ||
5 | * | ||
6 | * Author: David Cohen (david.cohen@indt.org.br) | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | * | ||
12 | * This file was based on ov9640.h from MontaVista | ||
13 | */ | ||
14 | |||
15 | #ifndef TCM825X_H | ||
16 | #define TCM825X_H | ||
17 | |||
18 | #include <linux/videodev2.h> | ||
19 | |||
20 | #include <media/v4l2-int-device.h> | ||
21 | |||
22 | #define TCM825X_NAME "tcm825x" | ||
23 | |||
24 | #define TCM825X_MASK(x) x & 0x00ff | ||
25 | #define TCM825X_ADDR(x) (x & 0xff00) >> 8 | ||
26 | |||
27 | /* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */ | ||
28 | #define TCM825X_I2C_ADDR 0x3d | ||
29 | |||
30 | /* | ||
31 | * define register offsets for the TCM825X sensor chip | ||
32 | * OFFSET(8 bits) + MASK(8 bits) | ||
33 | * MASK bit 4 and 3 are used when the register uses more than one address | ||
34 | */ | ||
35 | #define TCM825X_FPS 0x0280 | ||
36 | #define TCM825X_ACF 0x0240 | ||
37 | #define TCM825X_DOUTBUF 0x020C | ||
38 | #define TCM825X_DCLKP 0x0202 | ||
39 | #define TCM825X_ACFDET 0x0201 | ||
40 | #define TCM825X_DOUTSW 0x0380 | ||
41 | #define TCM825X_DATAHZ 0x0340 | ||
42 | #define TCM825X_PICSIZ 0x033c | ||
43 | #define TCM825X_PICFMT 0x0302 | ||
44 | #define TCM825X_V_INV 0x0480 | ||
45 | #define TCM825X_H_INV 0x0440 | ||
46 | #define TCM825X_ESRLSW 0x0430 | ||
47 | #define TCM825X_V_LENGTH 0x040F | ||
48 | #define TCM825X_ALCSW 0x0580 | ||
49 | #define TCM825X_ESRLIM 0x0560 | ||
50 | #define TCM825X_ESRSPD_U 0x051F | ||
51 | #define TCM825X_ESRSPD_L 0x06FF | ||
52 | #define TCM825X_AG 0x07FF | ||
53 | #define TCM825X_ESRSPD2 0x06FF | ||
54 | #define TCM825X_ALCMODE 0x0830 | ||
55 | #define TCM825X_ALCH 0x080F | ||
56 | #define TCM825X_ALCL 0x09FF | ||
57 | #define TCM825X_AWBSW 0x0A80 | ||
58 | #define TCM825X_MRG 0x0BFF | ||
59 | #define TCM825X_MBG 0x0CFF | ||
60 | #define TCM825X_GAMSW 0x0D80 | ||
61 | #define TCM825X_HDTG 0x0EFF | ||
62 | #define TCM825X_VDTG 0x0FFF | ||
63 | #define TCM825X_HDTCORE 0x10F0 | ||
64 | #define TCM825X_VDTCORE 0x100F | ||
65 | #define TCM825X_CONT 0x11FF | ||
66 | #define TCM825X_BRIGHT 0x12FF | ||
67 | #define TCM825X_VHUE 0x137F | ||
68 | #define TCM825X_UHUE 0x147F | ||
69 | #define TCM825X_VGAIN 0x153F | ||
70 | #define TCM825X_UGAIN 0x163F | ||
71 | #define TCM825X_UVCORE 0x170F | ||
72 | #define TCM825X_SATU 0x187F | ||
73 | #define TCM825X_MHMODE 0x1980 | ||
74 | #define TCM825X_MHLPFSEL 0x1940 | ||
75 | #define TCM825X_YMODE 0x1930 | ||
76 | #define TCM825X_MIXHG 0x1907 | ||
77 | #define TCM825X_LENS 0x1A3F | ||
78 | #define TCM825X_AGLIM 0x1BE0 | ||
79 | #define TCM825X_LENSRPOL 0x1B10 | ||
80 | #define TCM825X_LENSRGAIN 0x1B0F | ||
81 | #define TCM825X_ES100S 0x1CFF | ||
82 | #define TCM825X_ES120S 0x1DFF | ||
83 | #define TCM825X_DMASK 0x1EC0 | ||
84 | #define TCM825X_CODESW 0x1E20 | ||
85 | #define TCM825X_CODESEL 0x1E10 | ||
86 | #define TCM825X_TESPIC 0x1E04 | ||
87 | #define TCM825X_PICSEL 0x1E03 | ||
88 | #define TCM825X_HNUM 0x20FF | ||
89 | #define TCM825X_VOUTPH 0x287F | ||
90 | #define TCM825X_ESROUT 0x327F | ||
91 | #define TCM825X_ESROUT2 0x33FF | ||
92 | #define TCM825X_AGOUT 0x34FF | ||
93 | #define TCM825X_DGOUT 0x353F | ||
94 | #define TCM825X_AGSLOW1 0x39C0 | ||
95 | #define TCM825X_FLLSMODE 0x3930 | ||
96 | #define TCM825X_FLLSLIM 0x390F | ||
97 | #define TCM825X_DETSEL 0x3AF0 | ||
98 | #define TCM825X_ACDETNC 0x3A0F | ||
99 | #define TCM825X_AGSLOW2 0x3BC0 | ||
100 | #define TCM825X_DG 0x3B3F | ||
101 | #define TCM825X_REJHLEV 0x3CFF | ||
102 | #define TCM825X_ALCLOCK 0x3D80 | ||
103 | #define TCM825X_FPSLNKSW 0x3D40 | ||
104 | #define TCM825X_ALCSPD 0x3D30 | ||
105 | #define TCM825X_REJH 0x3D03 | ||
106 | #define TCM825X_SHESRSW 0x3E80 | ||
107 | #define TCM825X_ESLIMSEL 0x3E40 | ||
108 | #define TCM825X_SHESRSPD 0x3E30 | ||
109 | #define TCM825X_ELSTEP 0x3E0C | ||
110 | #define TCM825X_ELSTART 0x3E03 | ||
111 | #define TCM825X_AGMIN 0x3FFF | ||
112 | #define TCM825X_PREGRG 0x423F | ||
113 | #define TCM825X_PREGBG 0x433F | ||
114 | #define TCM825X_PRERG 0x443F | ||
115 | #define TCM825X_PREBG 0x453F | ||
116 | #define TCM825X_MSKBR 0x477F | ||
117 | #define TCM825X_MSKGR 0x487F | ||
118 | #define TCM825X_MSKRB 0x497F | ||
119 | #define TCM825X_MSKGB 0x4A7F | ||
120 | #define TCM825X_MSKRG 0x4B7F | ||
121 | #define TCM825X_MSKBG 0x4C7F | ||
122 | #define TCM825X_HDTCSW 0x4D80 | ||
123 | #define TCM825X_VDTCSW 0x4D40 | ||
124 | #define TCM825X_DTCYL 0x4D3F | ||
125 | #define TCM825X_HDTPSW 0x4E80 | ||
126 | #define TCM825X_VDTPSW 0x4E40 | ||
127 | #define TCM825X_DTCGAIN 0x4E3F | ||
128 | #define TCM825X_DTLLIMSW 0x4F10 | ||
129 | #define TCM825X_DTLYLIM 0x4F0F | ||
130 | #define TCM825X_YLCUTLMSK 0x5080 | ||
131 | #define TCM825X_YLCUTL 0x503F | ||
132 | #define TCM825X_YLCUTHMSK 0x5180 | ||
133 | #define TCM825X_YLCUTH 0x513F | ||
134 | #define TCM825X_UVSKNC 0x527F | ||
135 | #define TCM825X_UVLJ 0x537F | ||
136 | #define TCM825X_WBGMIN 0x54FF | ||
137 | #define TCM825X_WBGMAX 0x55FF | ||
138 | #define TCM825X_WBSPDUP 0x5603 | ||
139 | #define TCM825X_ALLAREA 0x5820 | ||
140 | #define TCM825X_WBLOCK 0x5810 | ||
141 | #define TCM825X_WB2SP 0x580F | ||
142 | #define TCM825X_KIZUSW 0x5920 | ||
143 | #define TCM825X_PBRSW 0x5910 | ||
144 | #define TCM825X_ABCSW 0x5903 | ||
145 | #define TCM825X_PBDLV 0x5AFF | ||
146 | #define TCM825X_PBC1LV 0x5BFF | ||
147 | |||
148 | #define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1) | ||
149 | |||
150 | #define TCM825X_BYTES_PER_PIXEL 2 | ||
151 | |||
152 | #define TCM825X_REG_TERM 0xff /* terminating list entry for reg */ | ||
153 | #define TCM825X_VAL_TERM 0xff /* terminating list entry for val */ | ||
154 | |||
155 | /* define a structure for tcm825x register initialization values */ | ||
156 | struct tcm825x_reg { | ||
157 | u8 val; | ||
158 | u16 reg; | ||
159 | }; | ||
160 | |||
161 | enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA }; | ||
162 | enum pixel_format { YUV422 = 0, RGB565 }; | ||
163 | #define NUM_IMAGE_SIZES 6 | ||
164 | #define NUM_PIXEL_FORMATS 2 | ||
165 | |||
166 | #define TCM825X_XCLK_MIN 11900000 | ||
167 | #define TCM825X_XCLK_MAX 25000000 | ||
168 | |||
169 | struct capture_size { | ||
170 | unsigned long width; | ||
171 | unsigned long height; | ||
172 | }; | ||
173 | |||
174 | struct tcm825x_platform_data { | ||
175 | /* Is the sensor usable? Doesn't yet mean it's there, but you | ||
176 | * can try! */ | ||
177 | int (*is_okay)(void); | ||
178 | /* Set power state, zero is off, non-zero is on. */ | ||
179 | int (*power_set)(int power); | ||
180 | /* Default registers written after power-on or reset. */ | ||
181 | const struct tcm825x_reg *(*default_regs)(void); | ||
182 | int (*needs_reset)(struct v4l2_int_device *s, void *buf, | ||
183 | struct v4l2_pix_format *fmt); | ||
184 | int (*ifparm)(struct v4l2_ifparm *p); | ||
185 | int (*is_upside_down)(void); | ||
186 | }; | ||
187 | |||
188 | /* Array of image sizes supported by TCM825X. These must be ordered from | ||
189 | * smallest image size to largest. | ||
190 | */ | ||
191 | static const struct capture_size tcm825x_sizes[] = { | ||
192 | { 128, 96 }, /* subQCIF */ | ||
193 | { 160, 120 }, /* QQVGA */ | ||
194 | { 176, 144 }, /* QCIF */ | ||
195 | { 320, 240 }, /* QVGA */ | ||
196 | { 352, 288 }, /* CIF */ | ||
197 | { 640, 480 }, /* VGA */ | ||
198 | }; | ||
199 | |||
200 | #endif /* ifndef TCM825X_H */ | ||
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 89c0b13463b7..542d2528b3f9 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c | |||
@@ -58,21 +58,17 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) | |||
58 | struct i2c_client *c = v4l2_get_subdevdata(sd); | 58 | struct i2c_client *c = v4l2_get_subdevdata(sd); |
59 | unsigned char buffer[1]; | 59 | unsigned char buffer[1]; |
60 | int rc; | 60 | int rc; |
61 | 61 | struct i2c_msg msg[] = { | |
62 | buffer[0] = addr; | 62 | { .addr = c->addr, .flags = 0, |
63 | 63 | .buf = &addr, .len = 1 }, | |
64 | rc = i2c_master_send(c, buffer, 1); | 64 | { .addr = c->addr, .flags = I2C_M_RD, |
65 | if (rc < 0) { | 65 | .buf = buffer, .len = 1 } |
66 | v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc); | 66 | }; |
67 | return rc; | 67 | |
68 | } | 68 | rc = i2c_transfer(c->adapter, msg, 2); |
69 | 69 | if (rc < 0 || rc != 2) { | |
70 | msleep(10); | 70 | v4l2_err(sd, "i2c i/o error: rc == %d (should be 2)\n", rc); |
71 | 71 | return rc < 0 ? rc : -EIO; | |
72 | rc = i2c_master_recv(c, buffer, 1); | ||
73 | if (rc < 0) { | ||
74 | v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc); | ||
75 | return rc; | ||
76 | } | 72 | } |
77 | 73 | ||
78 | v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]); | 74 | v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]); |
@@ -867,7 +863,7 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
867 | struct v4l2_rect rect = a->c; | 863 | struct v4l2_rect rect = a->c; |
868 | struct tvp5150 *decoder = to_tvp5150(sd); | 864 | struct tvp5150 *decoder = to_tvp5150(sd); |
869 | v4l2_std_id std; | 865 | v4l2_std_id std; |
870 | int hmax; | 866 | unsigned int hmax; |
871 | 867 | ||
872 | v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", | 868 | v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", |
873 | __func__, rect.left, rect.top, rect.width, rect.height); | 869 | __func__, rect.left, rect.top, rect.width, rect.height); |
@@ -877,9 +873,9 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
877 | 873 | ||
878 | /* tvp5150 has some special limits */ | 874 | /* tvp5150 has some special limits */ |
879 | rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); | 875 | rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); |
880 | rect.width = clamp(rect.width, | 876 | rect.width = clamp_t(unsigned int, rect.width, |
881 | TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, | 877 | TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, |
882 | TVP5150_H_MAX - rect.left); | 878 | TVP5150_H_MAX - rect.left); |
883 | rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); | 879 | rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); |
884 | 880 | ||
885 | /* Calculate height based on current standard */ | 881 | /* Calculate height based on current standard */ |
@@ -893,9 +889,9 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
893 | else | 889 | else |
894 | hmax = TVP5150_V_MAX_OTHERS; | 890 | hmax = TVP5150_V_MAX_OTHERS; |
895 | 891 | ||
896 | rect.height = clamp(rect.height, | 892 | rect.height = clamp_t(unsigned int, rect.height, |
897 | hmax - TVP5150_MAX_CROP_TOP - rect.top, | 893 | hmax - TVP5150_MAX_CROP_TOP - rect.top, |
898 | hmax - rect.top); | 894 | hmax - rect.top); |
899 | 895 | ||
900 | tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); | 896 | tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); |
901 | tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, | 897 | tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, |
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 25bdd9312fea..23f4f65fccd7 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c | |||
@@ -503,6 +503,7 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | |||
503 | return &container_of(ctrl->handler, struct vs6624, hdl)->sd; | 503 | return &container_of(ctrl->handler, struct vs6624, hdl)->sd; |
504 | } | 504 | } |
505 | 505 | ||
506 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
506 | static int vs6624_read(struct v4l2_subdev *sd, u16 index) | 507 | static int vs6624_read(struct v4l2_subdev *sd, u16 index) |
507 | { | 508 | { |
508 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 509 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -515,6 +516,7 @@ static int vs6624_read(struct v4l2_subdev *sd, u16 index) | |||
515 | 516 | ||
516 | return buf[0]; | 517 | return buf[0]; |
517 | } | 518 | } |
519 | #endif | ||
518 | 520 | ||
519 | static int vs6624_write(struct v4l2_subdev *sd, u16 index, | 521 | static int vs6624_write(struct v4l2_subdev *sd, u16 index, |
520 | u8 value) | 522 | u8 value) |
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 2c286c307145..37c334edc7e8 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c | |||
@@ -235,6 +235,8 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity, | |||
235 | media_entity_graph_walk_start(&graph, entity); | 235 | media_entity_graph_walk_start(&graph, entity); |
236 | 236 | ||
237 | while ((entity = media_entity_graph_walk_next(&graph))) { | 237 | while ((entity = media_entity_graph_walk_next(&graph))) { |
238 | DECLARE_BITMAP(active, entity->num_pads); | ||
239 | DECLARE_BITMAP(has_no_links, entity->num_pads); | ||
238 | unsigned int i; | 240 | unsigned int i; |
239 | 241 | ||
240 | entity->stream_count++; | 242 | entity->stream_count++; |
@@ -248,21 +250,46 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity, | |||
248 | if (!entity->ops || !entity->ops->link_validate) | 250 | if (!entity->ops || !entity->ops->link_validate) |
249 | continue; | 251 | continue; |
250 | 252 | ||
253 | bitmap_zero(active, entity->num_pads); | ||
254 | bitmap_fill(has_no_links, entity->num_pads); | ||
255 | |||
251 | for (i = 0; i < entity->num_links; i++) { | 256 | for (i = 0; i < entity->num_links; i++) { |
252 | struct media_link *link = &entity->links[i]; | 257 | struct media_link *link = &entity->links[i]; |
253 | 258 | struct media_pad *pad = link->sink->entity == entity | |
254 | /* Is this pad part of an enabled link? */ | 259 | ? link->sink : link->source; |
255 | if (!(link->flags & MEDIA_LNK_FL_ENABLED)) | 260 | |
256 | continue; | 261 | /* Mark that a pad is connected by a link. */ |
257 | 262 | bitmap_clear(has_no_links, pad->index, 1); | |
258 | /* Are we the sink or not? */ | 263 | |
259 | if (link->sink->entity != entity) | 264 | /* |
265 | * Pads that either do not need to connect or | ||
266 | * are connected through an enabled link are | ||
267 | * fine. | ||
268 | */ | ||
269 | if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) || | ||
270 | link->flags & MEDIA_LNK_FL_ENABLED) | ||
271 | bitmap_set(active, pad->index, 1); | ||
272 | |||
273 | /* | ||
274 | * Link validation will only take place for | ||
275 | * sink ends of the link that are enabled. | ||
276 | */ | ||
277 | if (link->sink != pad || | ||
278 | !(link->flags & MEDIA_LNK_FL_ENABLED)) | ||
260 | continue; | 279 | continue; |
261 | 280 | ||
262 | ret = entity->ops->link_validate(link); | 281 | ret = entity->ops->link_validate(link); |
263 | if (ret < 0 && ret != -ENOIOCTLCMD) | 282 | if (ret < 0 && ret != -ENOIOCTLCMD) |
264 | goto error; | 283 | goto error; |
265 | } | 284 | } |
285 | |||
286 | /* Either no links or validated links are fine. */ | ||
287 | bitmap_or(active, active, has_no_links, entity->num_pads); | ||
288 | |||
289 | if (!bitmap_full(active, entity->num_pads)) { | ||
290 | ret = -EPIPE; | ||
291 | goto error; | ||
292 | } | ||
266 | } | 293 | } |
267 | 294 | ||
268 | mutex_unlock(&mdev->graph_mutex); | 295 | mutex_unlock(&mdev->graph_mutex); |
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 92a06fd85865..afcd53bfcf8e 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c | |||
@@ -1126,9 +1126,9 @@ bttv_crop_calc_limits(struct bttv_crop *c) | |||
1126 | c->min_scaled_height = 32; | 1126 | c->min_scaled_height = 32; |
1127 | } else { | 1127 | } else { |
1128 | c->min_scaled_width = | 1128 | c->min_scaled_width = |
1129 | (max(48, c->rect.width >> 4) + 3) & ~3; | 1129 | (max_t(unsigned int, 48, c->rect.width >> 4) + 3) & ~3; |
1130 | c->min_scaled_height = | 1130 | c->min_scaled_height = |
1131 | max(32, c->rect.height >> 4); | 1131 | max_t(unsigned int, 32, c->rect.height >> 4); |
1132 | } | 1132 | } |
1133 | 1133 | ||
1134 | c->max_scaled_width = c->rect.width & ~3; | 1134 | c->max_scaled_width = c->rect.width & ~3; |
@@ -2024,7 +2024,7 @@ limit_scaled_size_lock (struct bttv_fh * fh, | |||
2024 | /* We cannot scale up. When the scaled image is larger | 2024 | /* We cannot scale up. When the scaled image is larger |
2025 | than crop.rect we adjust the crop.rect as required | 2025 | than crop.rect we adjust the crop.rect as required |
2026 | by the V4L2 spec, hence cropcap.bounds are our limit. */ | 2026 | by the V4L2 spec, hence cropcap.bounds are our limit. */ |
2027 | max_width = min(b->width, (__s32) MAX_HACTIVE); | 2027 | max_width = min_t(unsigned int, b->width, MAX_HACTIVE); |
2028 | max_height = b->height; | 2028 | max_height = b->height; |
2029 | 2029 | ||
2030 | /* We cannot capture the same line as video and VBI data. | 2030 | /* We cannot capture the same line as video and VBI data. |
@@ -3266,7 +3266,9 @@ static ssize_t radio_read(struct file *file, char __user *data, | |||
3266 | struct bttv_fh *fh = file->private_data; | 3266 | struct bttv_fh *fh = file->private_data; |
3267 | struct bttv *btv = fh->btv; | 3267 | struct bttv *btv = fh->btv; |
3268 | struct saa6588_command cmd; | 3268 | struct saa6588_command cmd; |
3269 | cmd.block_count = count/3; | 3269 | |
3270 | cmd.block_count = count / 3; | ||
3271 | cmd.nonblocking = file->f_flags & O_NONBLOCK; | ||
3270 | cmd.buffer = data; | 3272 | cmd.buffer = data; |
3271 | cmd.instance = file; | 3273 | cmd.instance = file; |
3272 | cmd.result = -ENODEV; | 3274 | cmd.result = -ENODEV; |
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index c1f8cc6f14b2..716bdc57fac6 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c | |||
@@ -327,13 +327,16 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) | |||
327 | struct i2c_client *c; | 327 | struct i2c_client *c; |
328 | u8 eedata[256]; | 328 | u8 eedata[256]; |
329 | 329 | ||
330 | memset(tv, 0, sizeof(*tv)); | ||
331 | |||
330 | c = kzalloc(sizeof(*c), GFP_KERNEL); | 332 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
333 | if (!c) | ||
334 | return; | ||
331 | 335 | ||
332 | strlcpy(c->name, "cx18 tveeprom tmp", sizeof(c->name)); | 336 | strlcpy(c->name, "cx18 tveeprom tmp", sizeof(c->name)); |
333 | c->adapter = &cx->i2c_adap[0]; | 337 | c->adapter = &cx->i2c_adap[0]; |
334 | c->addr = 0xa0 >> 1; | 338 | c->addr = 0xa0 >> 1; |
335 | 339 | ||
336 | memset(tv, 0, sizeof(*tv)); | ||
337 | if (tveeprom_read(c, eedata, sizeof(eedata))) | 340 | if (tveeprom_read(c, eedata, sizeof(eedata))) |
338 | goto ret; | 341 | goto ret; |
339 | 342 | ||
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 6e91e84d6bf9..b1e08c3e55cd 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c | |||
@@ -618,7 +618,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, | |||
618 | * Only boards with eeprom and byte 1 at eeprom=1 have it | 618 | * Only boards with eeprom and byte 1 at eeprom=1 have it |
619 | */ | 619 | */ |
620 | 620 | ||
621 | static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = { | 621 | static const struct pci_device_id cx25821_audio_pci_tbl[] = { |
622 | {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 622 | {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
623 | {0,} | 623 | {0,} |
624 | }; | 624 | }; |
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index b762c5b2ca10..e81173c41e5a 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c | |||
@@ -1361,7 +1361,7 @@ static void cx25821_finidev(struct pci_dev *pci_dev) | |||
1361 | kfree(dev); | 1361 | kfree(dev); |
1362 | } | 1362 | } |
1363 | 1363 | ||
1364 | static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = { | 1364 | static const struct pci_device_id cx25821_pci_tbl[] = { |
1365 | { | 1365 | { |
1366 | /* CX25821 Athena */ | 1366 | /* CX25821 Athena */ |
1367 | .vendor = 0x14f1, | 1367 | .vendor = 0x14f1, |
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 400eb1c42d3f..d014206e7176 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c | |||
@@ -931,9 +931,9 @@ error: | |||
931 | */ | 931 | */ |
932 | static void cx88_audio_finidev(struct pci_dev *pci) | 932 | static void cx88_audio_finidev(struct pci_dev *pci) |
933 | { | 933 | { |
934 | struct cx88_audio_dev *card = pci_get_drvdata(pci); | 934 | struct snd_card *card = pci_get_drvdata(pci); |
935 | 935 | ||
936 | snd_card_free((void *)card); | 936 | snd_card_free(card); |
937 | 937 | ||
938 | devno--; | 938 | devno--; |
939 | } | 939 | } |
diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig index 15b90d6e9130..7883393571e5 100644 --- a/drivers/media/pci/saa7134/Kconfig +++ b/drivers/media/pci/saa7134/Kconfig | |||
@@ -6,6 +6,7 @@ config VIDEO_SAA7134 | |||
6 | select VIDEO_TVEEPROM | 6 | select VIDEO_TVEEPROM |
7 | select CRC32 | 7 | select CRC32 |
8 | select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT | 8 | select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT |
9 | select VIDEO_SAA6752HS if MEDIA_SUBDRV_AUTOSELECT | ||
9 | ---help--- | 10 | ---help--- |
10 | This is a video4linux driver for Philips SAA713x based | 11 | This is a video4linux driver for Philips SAA713x based |
11 | TV cards. | 12 | TV cards. |
diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile index 35375480ed4d..58de9b085689 100644 --- a/drivers/media/pci/saa7134/Makefile +++ b/drivers/media/pci/saa7134/Makefile | |||
@@ -4,7 +4,7 @@ saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o | |||
4 | saa7134-y += saa7134-video.o | 4 | saa7134-y += saa7134-video.o |
5 | saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o | 5 | saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o |
6 | 6 | ||
7 | obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o | 7 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o |
8 | 8 | ||
9 | obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o | 9 | obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o |
10 | 10 | ||
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 27d7ee709c58..1362b4aab473 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c | |||
@@ -751,6 +751,7 @@ static int saa7134_hwfini(struct saa7134_dev *dev) | |||
751 | saa7134_input_fini(dev); | 751 | saa7134_input_fini(dev); |
752 | saa7134_vbi_fini(dev); | 752 | saa7134_vbi_fini(dev); |
753 | saa7134_tvaudio_fini(dev); | 753 | saa7134_tvaudio_fini(dev); |
754 | saa7134_video_fini(dev); | ||
754 | return 0; | 755 | return 0; |
755 | } | 756 | } |
756 | 757 | ||
@@ -802,7 +803,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, | |||
802 | *vfd = *template; | 803 | *vfd = *template; |
803 | vfd->v4l2_dev = &dev->v4l2_dev; | 804 | vfd->v4l2_dev = &dev->v4l2_dev; |
804 | vfd->release = video_device_release; | 805 | vfd->release = video_device_release; |
805 | vfd->debug = video_debug; | ||
806 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | 806 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", |
807 | dev->name, type, saa7134_boards[dev->board].name); | 807 | dev->name, type, saa7134_boards[dev->board].name); |
808 | set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); | 808 | set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); |
@@ -1008,13 +1008,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev, | |||
1008 | 1008 | ||
1009 | /* load i2c helpers */ | 1009 | /* load i2c helpers */ |
1010 | if (card_is_empress(dev)) { | 1010 | if (card_is_empress(dev)) { |
1011 | struct v4l2_subdev *sd = | 1011 | dev->empress_sd = |
1012 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 1012 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
1013 | "saa6752hs", | 1013 | "saa6752hs", |
1014 | saa7134_boards[dev->board].empress_addr, NULL); | 1014 | saa7134_boards[dev->board].empress_addr, NULL); |
1015 | 1015 | ||
1016 | if (sd) | 1016 | if (dev->empress_sd) |
1017 | sd->grp_id = GRP_EMPRESS; | 1017 | dev->empress_sd->grp_id = GRP_EMPRESS; |
1018 | } | 1018 | } |
1019 | 1019 | ||
1020 | if (saa7134_boards[dev->board].rds_addr) { | 1020 | if (saa7134_boards[dev->board].rds_addr) { |
@@ -1046,6 +1046,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, | |||
1046 | printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); | 1046 | printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); |
1047 | 1047 | ||
1048 | dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); | 1048 | dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); |
1049 | dev->video_dev->ctrl_handler = &dev->ctrl_handler; | ||
1049 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, | 1050 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, |
1050 | video_nr[dev->nr]); | 1051 | video_nr[dev->nr]); |
1051 | if (err < 0) { | 1052 | if (err < 0) { |
@@ -1057,6 +1058,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, | |||
1057 | dev->name, video_device_node_name(dev->video_dev)); | 1058 | dev->name, video_device_node_name(dev->video_dev)); |
1058 | 1059 | ||
1059 | dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); | 1060 | dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); |
1061 | dev->vbi_dev->ctrl_handler = &dev->ctrl_handler; | ||
1060 | 1062 | ||
1061 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, | 1063 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, |
1062 | vbi_nr[dev->nr]); | 1064 | vbi_nr[dev->nr]); |
@@ -1067,6 +1069,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, | |||
1067 | 1069 | ||
1068 | if (card_has_radio(dev)) { | 1070 | if (card_has_radio(dev)) { |
1069 | dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); | 1071 | dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); |
1072 | dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler; | ||
1070 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, | 1073 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, |
1071 | radio_nr[dev->nr]); | 1074 | radio_nr[dev->nr]); |
1072 | if (err < 0) | 1075 | if (err < 0) |
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 3022eb2a7925..0a9047e754b9 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c | |||
@@ -23,12 +23,12 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | 25 | ||
26 | #include <media/v4l2-common.h> | ||
27 | #include <media/v4l2-event.h> | ||
28 | |||
26 | #include "saa7134-reg.h" | 29 | #include "saa7134-reg.h" |
27 | #include "saa7134.h" | 30 | #include "saa7134.h" |
28 | 31 | ||
29 | #include <media/saa6752hs.h> | ||
30 | #include <media/v4l2-common.h> | ||
31 | |||
32 | /* ------------------------------------------------------------------ */ | 32 | /* ------------------------------------------------------------------ */ |
33 | 33 | ||
34 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 34 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
@@ -85,52 +85,54 @@ static int ts_open(struct file *file) | |||
85 | { | 85 | { |
86 | struct video_device *vdev = video_devdata(file); | 86 | struct video_device *vdev = video_devdata(file); |
87 | struct saa7134_dev *dev = video_drvdata(file); | 87 | struct saa7134_dev *dev = video_drvdata(file); |
88 | int err; | 88 | struct saa7134_fh *fh; |
89 | 89 | ||
90 | dprintk("open dev=%s\n", video_device_node_name(vdev)); | 90 | /* allocate + initialize per filehandle data */ |
91 | err = -EBUSY; | 91 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
92 | if (!mutex_trylock(&dev->empress_tsq.vb_lock)) | 92 | if (NULL == fh) |
93 | return err; | 93 | return -ENOMEM; |
94 | if (atomic_read(&dev->empress_users)) | 94 | |
95 | goto done; | 95 | v4l2_fh_init(&fh->fh, vdev); |
96 | file->private_data = fh; | ||
97 | fh->is_empress = true; | ||
98 | v4l2_fh_add(&fh->fh); | ||
96 | 99 | ||
97 | /* Unmute audio */ | 100 | /* Unmute audio */ |
98 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, | 101 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, |
99 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); | 102 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); |
100 | 103 | ||
101 | atomic_inc(&dev->empress_users); | 104 | return 0; |
102 | file->private_data = dev; | ||
103 | err = 0; | ||
104 | |||
105 | done: | ||
106 | mutex_unlock(&dev->empress_tsq.vb_lock); | ||
107 | return err; | ||
108 | } | 105 | } |
109 | 106 | ||
110 | static int ts_release(struct file *file) | 107 | static int ts_release(struct file *file) |
111 | { | 108 | { |
112 | struct saa7134_dev *dev = file->private_data; | 109 | struct saa7134_dev *dev = video_drvdata(file); |
110 | struct saa7134_fh *fh = file->private_data; | ||
113 | 111 | ||
114 | videobuf_stop(&dev->empress_tsq); | 112 | if (res_check(fh, RESOURCE_EMPRESS)) { |
115 | videobuf_mmap_free(&dev->empress_tsq); | 113 | videobuf_stop(&dev->empress_tsq); |
114 | videobuf_mmap_free(&dev->empress_tsq); | ||
116 | 115 | ||
117 | /* stop the encoder */ | 116 | /* stop the encoder */ |
118 | ts_reset_encoder(dev); | 117 | ts_reset_encoder(dev); |
119 | 118 | ||
120 | /* Mute audio */ | 119 | /* Mute audio */ |
121 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, | 120 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, |
122 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); | 121 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); |
123 | 122 | } | |
124 | atomic_dec(&dev->empress_users); | ||
125 | 123 | ||
124 | v4l2_fh_del(&fh->fh); | ||
125 | v4l2_fh_exit(&fh->fh); | ||
126 | return 0; | 126 | return 0; |
127 | } | 127 | } |
128 | 128 | ||
129 | static ssize_t | 129 | static ssize_t |
130 | ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | 130 | ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) |
131 | { | 131 | { |
132 | struct saa7134_dev *dev = file->private_data; | 132 | struct saa7134_dev *dev = video_drvdata(file); |
133 | 133 | ||
134 | if (res_locked(dev, RESOURCE_EMPRESS)) | ||
135 | return -EBUSY; | ||
134 | if (!dev->empress_started) | 136 | if (!dev->empress_started) |
135 | ts_init_encoder(dev); | 137 | ts_init_encoder(dev); |
136 | 138 | ||
@@ -142,68 +144,27 @@ ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | |||
142 | static unsigned int | 144 | static unsigned int |
143 | ts_poll(struct file *file, struct poll_table_struct *wait) | 145 | ts_poll(struct file *file, struct poll_table_struct *wait) |
144 | { | 146 | { |
145 | struct saa7134_dev *dev = file->private_data; | 147 | unsigned long req_events = poll_requested_events(wait); |
148 | struct saa7134_dev *dev = video_drvdata(file); | ||
149 | struct saa7134_fh *fh = file->private_data; | ||
150 | unsigned int rc = 0; | ||
146 | 151 | ||
147 | return videobuf_poll_stream(file, &dev->empress_tsq, wait); | 152 | if (v4l2_event_pending(&fh->fh)) |
153 | rc = POLLPRI; | ||
154 | else if (req_events & POLLPRI) | ||
155 | poll_wait(file, &fh->fh.wait, wait); | ||
156 | return rc | videobuf_poll_stream(file, &dev->empress_tsq, wait); | ||
148 | } | 157 | } |
149 | 158 | ||
150 | 159 | ||
151 | static int | 160 | static int |
152 | ts_mmap(struct file *file, struct vm_area_struct * vma) | 161 | ts_mmap(struct file *file, struct vm_area_struct * vma) |
153 | { | 162 | { |
154 | struct saa7134_dev *dev = file->private_data; | 163 | struct saa7134_dev *dev = video_drvdata(file); |
155 | 164 | ||
156 | return videobuf_mmap_mapper(&dev->empress_tsq, vma); | 165 | return videobuf_mmap_mapper(&dev->empress_tsq, vma); |
157 | } | 166 | } |
158 | 167 | ||
159 | /* | ||
160 | * This function is _not_ called directly, but from | ||
161 | * video_generic_ioctl (and maybe others). userspace | ||
162 | * copying is done already, arg is a kernel pointer. | ||
163 | */ | ||
164 | |||
165 | static int empress_querycap(struct file *file, void *priv, | ||
166 | struct v4l2_capability *cap) | ||
167 | { | ||
168 | struct saa7134_dev *dev = file->private_data; | ||
169 | |||
170 | strcpy(cap->driver, "saa7134"); | ||
171 | strlcpy(cap->card, saa7134_boards[dev->board].name, | ||
172 | sizeof(cap->card)); | ||
173 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | ||
174 | cap->capabilities = | ||
175 | V4L2_CAP_VIDEO_CAPTURE | | ||
176 | V4L2_CAP_READWRITE | | ||
177 | V4L2_CAP_STREAMING; | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int empress_enum_input(struct file *file, void *priv, | ||
182 | struct v4l2_input *i) | ||
183 | { | ||
184 | if (i->index != 0) | ||
185 | return -EINVAL; | ||
186 | |||
187 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
188 | strcpy(i->name, "CCIR656"); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int empress_g_input(struct file *file, void *priv, unsigned int *i) | ||
194 | { | ||
195 | *i = 0; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int empress_s_input(struct file *file, void *priv, unsigned int i) | ||
200 | { | ||
201 | if (i != 0) | ||
202 | return -EINVAL; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int empress_enum_fmt_vid_cap(struct file *file, void *priv, | 168 | static int empress_enum_fmt_vid_cap(struct file *file, void *priv, |
208 | struct v4l2_fmtdesc *f) | 169 | struct v4l2_fmtdesc *f) |
209 | { | 170 | { |
@@ -219,7 +180,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv, | |||
219 | static int empress_g_fmt_vid_cap(struct file *file, void *priv, | 180 | static int empress_g_fmt_vid_cap(struct file *file, void *priv, |
220 | struct v4l2_format *f) | 181 | struct v4l2_format *f) |
221 | { | 182 | { |
222 | struct saa7134_dev *dev = file->private_data; | 183 | struct saa7134_dev *dev = video_drvdata(file); |
223 | struct v4l2_mbus_framefmt mbus_fmt; | 184 | struct v4l2_mbus_framefmt mbus_fmt; |
224 | 185 | ||
225 | saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); | 186 | saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); |
@@ -236,7 +197,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, | |||
236 | static int empress_s_fmt_vid_cap(struct file *file, void *priv, | 197 | static int empress_s_fmt_vid_cap(struct file *file, void *priv, |
237 | struct v4l2_format *f) | 198 | struct v4l2_format *f) |
238 | { | 199 | { |
239 | struct saa7134_dev *dev = file->private_data; | 200 | struct saa7134_dev *dev = video_drvdata(file); |
240 | struct v4l2_mbus_framefmt mbus_fmt; | 201 | struct v4l2_mbus_framefmt mbus_fmt; |
241 | 202 | ||
242 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); | 203 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); |
@@ -254,7 +215,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, | |||
254 | static int empress_try_fmt_vid_cap(struct file *file, void *priv, | 215 | static int empress_try_fmt_vid_cap(struct file *file, void *priv, |
255 | struct v4l2_format *f) | 216 | struct v4l2_format *f) |
256 | { | 217 | { |
257 | struct saa7134_dev *dev = file->private_data; | 218 | struct saa7134_dev *dev = video_drvdata(file); |
258 | struct v4l2_mbus_framefmt mbus_fmt; | 219 | struct v4l2_mbus_framefmt mbus_fmt; |
259 | 220 | ||
260 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); | 221 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); |
@@ -269,175 +230,6 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv, | |||
269 | return 0; | 230 | return 0; |
270 | } | 231 | } |
271 | 232 | ||
272 | static int empress_reqbufs(struct file *file, void *priv, | ||
273 | struct v4l2_requestbuffers *p) | ||
274 | { | ||
275 | struct saa7134_dev *dev = file->private_data; | ||
276 | |||
277 | return videobuf_reqbufs(&dev->empress_tsq, p); | ||
278 | } | ||
279 | |||
280 | static int empress_querybuf(struct file *file, void *priv, | ||
281 | struct v4l2_buffer *b) | ||
282 | { | ||
283 | struct saa7134_dev *dev = file->private_data; | ||
284 | |||
285 | return videobuf_querybuf(&dev->empress_tsq, b); | ||
286 | } | ||
287 | |||
288 | static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
289 | { | ||
290 | struct saa7134_dev *dev = file->private_data; | ||
291 | |||
292 | return videobuf_qbuf(&dev->empress_tsq, b); | ||
293 | } | ||
294 | |||
295 | static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
296 | { | ||
297 | struct saa7134_dev *dev = file->private_data; | ||
298 | |||
299 | return videobuf_dqbuf(&dev->empress_tsq, b, | ||
300 | file->f_flags & O_NONBLOCK); | ||
301 | } | ||
302 | |||
303 | static int empress_streamon(struct file *file, void *priv, | ||
304 | enum v4l2_buf_type type) | ||
305 | { | ||
306 | struct saa7134_dev *dev = file->private_data; | ||
307 | |||
308 | return videobuf_streamon(&dev->empress_tsq); | ||
309 | } | ||
310 | |||
311 | static int empress_streamoff(struct file *file, void *priv, | ||
312 | enum v4l2_buf_type type) | ||
313 | { | ||
314 | struct saa7134_dev *dev = file->private_data; | ||
315 | |||
316 | return videobuf_streamoff(&dev->empress_tsq); | ||
317 | } | ||
318 | |||
319 | static int empress_s_ext_ctrls(struct file *file, void *priv, | ||
320 | struct v4l2_ext_controls *ctrls) | ||
321 | { | ||
322 | struct saa7134_dev *dev = file->private_data; | ||
323 | int err; | ||
324 | |||
325 | /* count == 0 is abused in saa6752hs.c, so that special | ||
326 | case is handled here explicitly. */ | ||
327 | if (ctrls->count == 0) | ||
328 | return 0; | ||
329 | |||
330 | if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
331 | return -EINVAL; | ||
332 | |||
333 | err = saa_call_empress(dev, core, s_ext_ctrls, ctrls); | ||
334 | ts_init_encoder(dev); | ||
335 | |||
336 | return err; | ||
337 | } | ||
338 | |||
339 | static int empress_g_ext_ctrls(struct file *file, void *priv, | ||
340 | struct v4l2_ext_controls *ctrls) | ||
341 | { | ||
342 | struct saa7134_dev *dev = file->private_data; | ||
343 | |||
344 | if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
345 | return -EINVAL; | ||
346 | return saa_call_empress(dev, core, g_ext_ctrls, ctrls); | ||
347 | } | ||
348 | |||
349 | static int empress_g_ctrl(struct file *file, void *priv, | ||
350 | struct v4l2_control *c) | ||
351 | { | ||
352 | struct saa7134_dev *dev = file->private_data; | ||
353 | |||
354 | return saa7134_g_ctrl_internal(dev, NULL, c); | ||
355 | } | ||
356 | |||
357 | static int empress_s_ctrl(struct file *file, void *priv, | ||
358 | struct v4l2_control *c) | ||
359 | { | ||
360 | struct saa7134_dev *dev = file->private_data; | ||
361 | |||
362 | return saa7134_s_ctrl_internal(dev, NULL, c); | ||
363 | } | ||
364 | |||
365 | static int empress_queryctrl(struct file *file, void *priv, | ||
366 | struct v4l2_queryctrl *c) | ||
367 | { | ||
368 | /* Must be sorted from low to high control ID! */ | ||
369 | static const u32 user_ctrls[] = { | ||
370 | V4L2_CID_USER_CLASS, | ||
371 | V4L2_CID_BRIGHTNESS, | ||
372 | V4L2_CID_CONTRAST, | ||
373 | V4L2_CID_SATURATION, | ||
374 | V4L2_CID_HUE, | ||
375 | V4L2_CID_AUDIO_VOLUME, | ||
376 | V4L2_CID_AUDIO_MUTE, | ||
377 | V4L2_CID_HFLIP, | ||
378 | 0 | ||
379 | }; | ||
380 | |||
381 | /* Must be sorted from low to high control ID! */ | ||
382 | static const u32 mpeg_ctrls[] = { | ||
383 | V4L2_CID_MPEG_CLASS, | ||
384 | V4L2_CID_MPEG_STREAM_TYPE, | ||
385 | V4L2_CID_MPEG_STREAM_PID_PMT, | ||
386 | V4L2_CID_MPEG_STREAM_PID_AUDIO, | ||
387 | V4L2_CID_MPEG_STREAM_PID_VIDEO, | ||
388 | V4L2_CID_MPEG_STREAM_PID_PCR, | ||
389 | V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, | ||
390 | V4L2_CID_MPEG_AUDIO_ENCODING, | ||
391 | V4L2_CID_MPEG_AUDIO_L2_BITRATE, | ||
392 | V4L2_CID_MPEG_VIDEO_ENCODING, | ||
393 | V4L2_CID_MPEG_VIDEO_ASPECT, | ||
394 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, | ||
395 | V4L2_CID_MPEG_VIDEO_BITRATE, | ||
396 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, | ||
397 | 0 | ||
398 | }; | ||
399 | static const u32 *ctrl_classes[] = { | ||
400 | user_ctrls, | ||
401 | mpeg_ctrls, | ||
402 | NULL | ||
403 | }; | ||
404 | struct saa7134_dev *dev = file->private_data; | ||
405 | |||
406 | c->id = v4l2_ctrl_next(ctrl_classes, c->id); | ||
407 | if (c->id == 0) | ||
408 | return -EINVAL; | ||
409 | if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS) | ||
410 | return v4l2_ctrl_query_fill(c, 0, 0, 0, 0); | ||
411 | if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) | ||
412 | return saa7134_queryctrl(file, priv, c); | ||
413 | return saa_call_empress(dev, core, queryctrl, c); | ||
414 | } | ||
415 | |||
416 | static int empress_querymenu(struct file *file, void *priv, | ||
417 | struct v4l2_querymenu *c) | ||
418 | { | ||
419 | struct saa7134_dev *dev = file->private_data; | ||
420 | |||
421 | if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) | ||
422 | return -EINVAL; | ||
423 | return saa_call_empress(dev, core, querymenu, c); | ||
424 | } | ||
425 | |||
426 | static int empress_s_std(struct file *file, void *priv, v4l2_std_id id) | ||
427 | { | ||
428 | struct saa7134_dev *dev = file->private_data; | ||
429 | |||
430 | return saa7134_s_std_internal(dev, NULL, id); | ||
431 | } | ||
432 | |||
433 | static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id) | ||
434 | { | ||
435 | struct saa7134_dev *dev = file->private_data; | ||
436 | |||
437 | *id = dev->tvnorm->id; | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static const struct v4l2_file_operations ts_fops = | 233 | static const struct v4l2_file_operations ts_fops = |
442 | { | 234 | { |
443 | .owner = THIS_MODULE, | 235 | .owner = THIS_MODULE, |
@@ -450,28 +242,29 @@ static const struct v4l2_file_operations ts_fops = | |||
450 | }; | 242 | }; |
451 | 243 | ||
452 | static const struct v4l2_ioctl_ops ts_ioctl_ops = { | 244 | static const struct v4l2_ioctl_ops ts_ioctl_ops = { |
453 | .vidioc_querycap = empress_querycap, | 245 | .vidioc_querycap = saa7134_querycap, |
454 | .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, | 246 | .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, |
455 | .vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap, | 247 | .vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap, |
456 | .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap, | 248 | .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap, |
457 | .vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap, | 249 | .vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap, |
458 | .vidioc_reqbufs = empress_reqbufs, | 250 | .vidioc_reqbufs = saa7134_reqbufs, |
459 | .vidioc_querybuf = empress_querybuf, | 251 | .vidioc_querybuf = saa7134_querybuf, |
460 | .vidioc_qbuf = empress_qbuf, | 252 | .vidioc_qbuf = saa7134_qbuf, |
461 | .vidioc_dqbuf = empress_dqbuf, | 253 | .vidioc_dqbuf = saa7134_dqbuf, |
462 | .vidioc_streamon = empress_streamon, | 254 | .vidioc_streamon = saa7134_streamon, |
463 | .vidioc_streamoff = empress_streamoff, | 255 | .vidioc_streamoff = saa7134_streamoff, |
464 | .vidioc_s_ext_ctrls = empress_s_ext_ctrls, | 256 | .vidioc_g_frequency = saa7134_g_frequency, |
465 | .vidioc_g_ext_ctrls = empress_g_ext_ctrls, | 257 | .vidioc_s_frequency = saa7134_s_frequency, |
466 | .vidioc_enum_input = empress_enum_input, | 258 | .vidioc_g_tuner = saa7134_g_tuner, |
467 | .vidioc_g_input = empress_g_input, | 259 | .vidioc_s_tuner = saa7134_s_tuner, |
468 | .vidioc_s_input = empress_s_input, | 260 | .vidioc_enum_input = saa7134_enum_input, |
469 | .vidioc_queryctrl = empress_queryctrl, | 261 | .vidioc_g_input = saa7134_g_input, |
470 | .vidioc_querymenu = empress_querymenu, | 262 | .vidioc_s_input = saa7134_s_input, |
471 | .vidioc_g_ctrl = empress_g_ctrl, | 263 | .vidioc_s_std = saa7134_s_std, |
472 | .vidioc_s_ctrl = empress_s_ctrl, | 264 | .vidioc_g_std = saa7134_g_std, |
473 | .vidioc_s_std = empress_s_std, | 265 | .vidioc_log_status = v4l2_ctrl_log_status, |
474 | .vidioc_g_std = empress_g_std, | 266 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
267 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
475 | }; | 268 | }; |
476 | 269 | ||
477 | /* ----------------------------------------------------------- */ | 270 | /* ----------------------------------------------------------- */ |
@@ -501,9 +294,26 @@ static void empress_signal_change(struct saa7134_dev *dev) | |||
501 | schedule_work(&dev->empress_workqueue); | 294 | schedule_work(&dev->empress_workqueue); |
502 | } | 295 | } |
503 | 296 | ||
297 | static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl) | ||
298 | { | ||
299 | switch (ctrl->id) { | ||
300 | case V4L2_CID_BRIGHTNESS: | ||
301 | case V4L2_CID_HUE: | ||
302 | case V4L2_CID_CONTRAST: | ||
303 | case V4L2_CID_SATURATION: | ||
304 | case V4L2_CID_AUDIO_MUTE: | ||
305 | case V4L2_CID_AUDIO_VOLUME: | ||
306 | case V4L2_CID_PRIVATE_INVERT: | ||
307 | case V4L2_CID_PRIVATE_AUTOMUTE: | ||
308 | return true; | ||
309 | default: | ||
310 | return false; | ||
311 | } | ||
312 | } | ||
504 | 313 | ||
505 | static int empress_init(struct saa7134_dev *dev) | 314 | static int empress_init(struct saa7134_dev *dev) |
506 | { | 315 | { |
316 | struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler; | ||
507 | int err; | 317 | int err; |
508 | 318 | ||
509 | dprintk("%s: %s\n",dev->name,__func__); | 319 | dprintk("%s: %s\n",dev->name,__func__); |
@@ -516,6 +326,16 @@ static int empress_init(struct saa7134_dev *dev) | |||
516 | snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name), | 326 | snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name), |
517 | "%s empress (%s)", dev->name, | 327 | "%s empress (%s)", dev->name, |
518 | saa7134_boards[dev->board].name); | 328 | saa7134_boards[dev->board].name); |
329 | set_bit(V4L2_FL_USE_FH_PRIO, &dev->empress_dev->flags); | ||
330 | v4l2_ctrl_handler_init(hdl, 21); | ||
331 | v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter); | ||
332 | if (dev->empress_sd) | ||
333 | v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL); | ||
334 | if (hdl->error) { | ||
335 | video_device_release(dev->empress_dev); | ||
336 | return hdl->error; | ||
337 | } | ||
338 | dev->empress_dev->ctrl_handler = hdl; | ||
519 | 339 | ||
520 | INIT_WORK(&dev->empress_workqueue, empress_signal_update); | 340 | INIT_WORK(&dev->empress_workqueue, empress_signal_update); |
521 | 341 | ||
@@ -551,6 +371,7 @@ static int empress_fini(struct saa7134_dev *dev) | |||
551 | return 0; | 371 | return 0; |
552 | flush_work(&dev->empress_workqueue); | 372 | flush_work(&dev->empress_workqueue); |
553 | video_unregister_device(dev->empress_dev); | 373 | video_unregister_device(dev->empress_dev); |
374 | v4l2_ctrl_handler_free(&dev->empress_ctrl_handler); | ||
554 | dev->empress_dev = NULL; | 375 | dev->empress_dev = NULL; |
555 | return 0; | 376 | return 0; |
556 | } | 377 | } |
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index e9aa94b807f1..d4da18d049f3 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c | |||
@@ -117,8 +117,7 @@ static int buffer_prepare(struct videobuf_queue *q, | |||
117 | struct videobuf_buffer *vb, | 117 | struct videobuf_buffer *vb, |
118 | enum v4l2_field field) | 118 | enum v4l2_field field) |
119 | { | 119 | { |
120 | struct saa7134_fh *fh = q->priv_data; | 120 | struct saa7134_dev *dev = q->priv_data; |
121 | struct saa7134_dev *dev = fh->dev; | ||
122 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | 121 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); |
123 | struct saa7134_tvnorm *norm = dev->tvnorm; | 122 | struct saa7134_tvnorm *norm = dev->tvnorm; |
124 | unsigned int lines, llength, size; | 123 | unsigned int lines, llength, size; |
@@ -141,7 +140,7 @@ static int buffer_prepare(struct videobuf_queue *q, | |||
141 | buf->vb.width = llength; | 140 | buf->vb.width = llength; |
142 | buf->vb.height = lines; | 141 | buf->vb.height = lines; |
143 | buf->vb.size = size; | 142 | buf->vb.size = size; |
144 | buf->pt = &fh->pt_vbi; | 143 | buf->pt = &dev->pt_vbi; |
145 | 144 | ||
146 | err = videobuf_iolock(q,&buf->vb,NULL); | 145 | err = videobuf_iolock(q,&buf->vb,NULL); |
147 | if (err) | 146 | if (err) |
@@ -166,8 +165,7 @@ static int buffer_prepare(struct videobuf_queue *q, | |||
166 | static int | 165 | static int |
167 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | 166 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) |
168 | { | 167 | { |
169 | struct saa7134_fh *fh = q->priv_data; | 168 | struct saa7134_dev *dev = q->priv_data; |
170 | struct saa7134_dev *dev = fh->dev; | ||
171 | int llength,lines; | 169 | int llength,lines; |
172 | 170 | ||
173 | lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1; | 171 | lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1; |
@@ -181,8 +179,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | |||
181 | 179 | ||
182 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | 180 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) |
183 | { | 181 | { |
184 | struct saa7134_fh *fh = q->priv_data; | 182 | struct saa7134_dev *dev = q->priv_data; |
185 | struct saa7134_dev *dev = fh->dev; | ||
186 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | 183 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); |
187 | 184 | ||
188 | saa7134_buffer_queue(dev,&dev->vbi_q,buf); | 185 | saa7134_buffer_queue(dev,&dev->vbi_q,buf); |
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index fb60da85bc2c..eb472b5b26a0 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c | |||
@@ -27,11 +27,13 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/sort.h> | 28 | #include <linux/sort.h> |
29 | 29 | ||
30 | #include "saa7134-reg.h" | ||
31 | #include "saa7134.h" | ||
32 | #include <media/v4l2-common.h> | 30 | #include <media/v4l2-common.h> |
31 | #include <media/v4l2-event.h> | ||
33 | #include <media/saa6588.h> | 32 | #include <media/saa6588.h> |
34 | 33 | ||
34 | #include "saa7134-reg.h" | ||
35 | #include "saa7134.h" | ||
36 | |||
35 | /* ------------------------------------------------------------------ */ | 37 | /* ------------------------------------------------------------------ */ |
36 | 38 | ||
37 | unsigned int video_debug; | 39 | unsigned int video_debug; |
@@ -369,117 +371,6 @@ static struct saa7134_tvnorm tvnorms[] = { | |||
369 | }; | 371 | }; |
370 | #define TVNORMS ARRAY_SIZE(tvnorms) | 372 | #define TVNORMS ARRAY_SIZE(tvnorms) |
371 | 373 | ||
372 | #define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) | ||
373 | #define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) | ||
374 | #define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) | ||
375 | #define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 3) | ||
376 | #define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 4) | ||
377 | |||
378 | static const struct v4l2_queryctrl no_ctrl = { | ||
379 | .name = "42", | ||
380 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
381 | }; | ||
382 | static const struct v4l2_queryctrl video_ctrls[] = { | ||
383 | /* --- video --- */ | ||
384 | { | ||
385 | .id = V4L2_CID_BRIGHTNESS, | ||
386 | .name = "Brightness", | ||
387 | .minimum = 0, | ||
388 | .maximum = 255, | ||
389 | .step = 1, | ||
390 | .default_value = 128, | ||
391 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
392 | },{ | ||
393 | .id = V4L2_CID_CONTRAST, | ||
394 | .name = "Contrast", | ||
395 | .minimum = 0, | ||
396 | .maximum = 127, | ||
397 | .step = 1, | ||
398 | .default_value = 68, | ||
399 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
400 | },{ | ||
401 | .id = V4L2_CID_SATURATION, | ||
402 | .name = "Saturation", | ||
403 | .minimum = 0, | ||
404 | .maximum = 127, | ||
405 | .step = 1, | ||
406 | .default_value = 64, | ||
407 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
408 | },{ | ||
409 | .id = V4L2_CID_HUE, | ||
410 | .name = "Hue", | ||
411 | .minimum = -128, | ||
412 | .maximum = 127, | ||
413 | .step = 1, | ||
414 | .default_value = 0, | ||
415 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
416 | },{ | ||
417 | .id = V4L2_CID_HFLIP, | ||
418 | .name = "Mirror", | ||
419 | .minimum = 0, | ||
420 | .maximum = 1, | ||
421 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
422 | }, | ||
423 | /* --- audio --- */ | ||
424 | { | ||
425 | .id = V4L2_CID_AUDIO_MUTE, | ||
426 | .name = "Mute", | ||
427 | .minimum = 0, | ||
428 | .maximum = 1, | ||
429 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
430 | },{ | ||
431 | .id = V4L2_CID_AUDIO_VOLUME, | ||
432 | .name = "Volume", | ||
433 | .minimum = -15, | ||
434 | .maximum = 15, | ||
435 | .step = 1, | ||
436 | .default_value = 0, | ||
437 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
438 | }, | ||
439 | /* --- private --- */ | ||
440 | { | ||
441 | .id = V4L2_CID_PRIVATE_INVERT, | ||
442 | .name = "Invert", | ||
443 | .minimum = 0, | ||
444 | .maximum = 1, | ||
445 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
446 | },{ | ||
447 | .id = V4L2_CID_PRIVATE_Y_ODD, | ||
448 | .name = "y offset odd field", | ||
449 | .minimum = 0, | ||
450 | .maximum = 128, | ||
451 | .step = 1, | ||
452 | .default_value = 0, | ||
453 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
454 | },{ | ||
455 | .id = V4L2_CID_PRIVATE_Y_EVEN, | ||
456 | .name = "y offset even field", | ||
457 | .minimum = 0, | ||
458 | .maximum = 128, | ||
459 | .step = 1, | ||
460 | .default_value = 0, | ||
461 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
462 | },{ | ||
463 | .id = V4L2_CID_PRIVATE_AUTOMUTE, | ||
464 | .name = "automute", | ||
465 | .minimum = 0, | ||
466 | .maximum = 1, | ||
467 | .default_value = 1, | ||
468 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
469 | } | ||
470 | }; | ||
471 | static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); | ||
472 | |||
473 | static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id) | ||
474 | { | ||
475 | unsigned int i; | ||
476 | |||
477 | for (i = 0; i < CTRLS; i++) | ||
478 | if (video_ctrls[i].id == id) | ||
479 | return video_ctrls+i; | ||
480 | return NULL; | ||
481 | } | ||
482 | |||
483 | static struct saa7134_format* format_by_fourcc(unsigned int fourcc) | 374 | static struct saa7134_format* format_by_fourcc(unsigned int fourcc) |
484 | { | 375 | { |
485 | unsigned int i; | 376 | unsigned int i; |
@@ -514,16 +405,6 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int | |||
514 | return 1; | 405 | return 1; |
515 | } | 406 | } |
516 | 407 | ||
517 | static int res_check(struct saa7134_fh *fh, unsigned int bit) | ||
518 | { | ||
519 | return (fh->resources & bit); | ||
520 | } | ||
521 | |||
522 | static int res_locked(struct saa7134_dev *dev, unsigned int bit) | ||
523 | { | ||
524 | return (dev->resources & bit); | ||
525 | } | ||
526 | |||
527 | static | 408 | static |
528 | void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) | 409 | void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) |
529 | { | 410 | { |
@@ -868,7 +749,7 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win, bool | |||
868 | return 0; | 749 | return 0; |
869 | } | 750 | } |
870 | 751 | ||
871 | static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) | 752 | static int start_preview(struct saa7134_dev *dev) |
872 | { | 753 | { |
873 | unsigned long base,control,bpl; | 754 | unsigned long base,control,bpl; |
874 | int err; | 755 | int err; |
@@ -923,7 +804,7 @@ static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) | |||
923 | return 0; | 804 | return 0; |
924 | } | 805 | } |
925 | 806 | ||
926 | static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) | 807 | static int stop_preview(struct saa7134_dev *dev) |
927 | { | 808 | { |
928 | dev->ovenable = 0; | 809 | dev->ovenable = 0; |
929 | saa7134_set_dmabits(dev); | 810 | saa7134_set_dmabits(dev); |
@@ -1018,8 +899,7 @@ static int buffer_prepare(struct videobuf_queue *q, | |||
1018 | struct videobuf_buffer *vb, | 899 | struct videobuf_buffer *vb, |
1019 | enum v4l2_field field) | 900 | enum v4l2_field field) |
1020 | { | 901 | { |
1021 | struct saa7134_fh *fh = q->priv_data; | 902 | struct saa7134_dev *dev = q->priv_data; |
1022 | struct saa7134_dev *dev = fh->dev; | ||
1023 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | 903 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); |
1024 | unsigned int size; | 904 | unsigned int size; |
1025 | int err; | 905 | int err; |
@@ -1057,7 +937,7 @@ static int buffer_prepare(struct videobuf_queue *q, | |||
1057 | buf->vb.size = size; | 937 | buf->vb.size = size; |
1058 | buf->vb.field = field; | 938 | buf->vb.field = field; |
1059 | buf->fmt = dev->fmt; | 939 | buf->fmt = dev->fmt; |
1060 | buf->pt = &fh->pt_cap; | 940 | buf->pt = &dev->pt_cap; |
1061 | dev->video_q.curr = NULL; | 941 | dev->video_q.curr = NULL; |
1062 | 942 | ||
1063 | err = videobuf_iolock(q,&buf->vb,&dev->ovbuf); | 943 | err = videobuf_iolock(q,&buf->vb,&dev->ovbuf); |
@@ -1082,8 +962,7 @@ static int buffer_prepare(struct videobuf_queue *q, | |||
1082 | static int | 962 | static int |
1083 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | 963 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) |
1084 | { | 964 | { |
1085 | struct saa7134_fh *fh = q->priv_data; | 965 | struct saa7134_dev *dev = q->priv_data; |
1086 | struct saa7134_dev *dev = fh->dev; | ||
1087 | 966 | ||
1088 | *size = dev->fmt->depth * dev->width * dev->height >> 3; | 967 | *size = dev->fmt->depth * dev->width * dev->height >> 3; |
1089 | if (0 == *count) | 968 | if (0 == *count) |
@@ -1094,10 +973,10 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | |||
1094 | 973 | ||
1095 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | 974 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) |
1096 | { | 975 | { |
1097 | struct saa7134_fh *fh = q->priv_data; | 976 | struct saa7134_dev *dev = q->priv_data; |
1098 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | 977 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); |
1099 | 978 | ||
1100 | saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf); | 979 | saa7134_buffer_queue(dev, &dev->video_q, buf); |
1101 | } | 980 | } |
1102 | 981 | ||
1103 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | 982 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) |
@@ -1116,133 +995,56 @@ static struct videobuf_queue_ops video_qops = { | |||
1116 | 995 | ||
1117 | /* ------------------------------------------------------------------ */ | 996 | /* ------------------------------------------------------------------ */ |
1118 | 997 | ||
1119 | int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) | 998 | static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl) |
1120 | { | 999 | { |
1121 | const struct v4l2_queryctrl* ctrl; | 1000 | struct saa7134_dev *dev = container_of(ctrl->handler, struct saa7134_dev, ctrl_handler); |
1122 | |||
1123 | ctrl = ctrl_by_id(c->id); | ||
1124 | if (NULL == ctrl) | ||
1125 | return -EINVAL; | ||
1126 | switch (c->id) { | ||
1127 | case V4L2_CID_BRIGHTNESS: | ||
1128 | c->value = dev->ctl_bright; | ||
1129 | break; | ||
1130 | case V4L2_CID_HUE: | ||
1131 | c->value = dev->ctl_hue; | ||
1132 | break; | ||
1133 | case V4L2_CID_CONTRAST: | ||
1134 | c->value = dev->ctl_contrast; | ||
1135 | break; | ||
1136 | case V4L2_CID_SATURATION: | ||
1137 | c->value = dev->ctl_saturation; | ||
1138 | break; | ||
1139 | case V4L2_CID_AUDIO_MUTE: | ||
1140 | c->value = dev->ctl_mute; | ||
1141 | break; | ||
1142 | case V4L2_CID_AUDIO_VOLUME: | ||
1143 | c->value = dev->ctl_volume; | ||
1144 | break; | ||
1145 | case V4L2_CID_PRIVATE_INVERT: | ||
1146 | c->value = dev->ctl_invert; | ||
1147 | break; | ||
1148 | case V4L2_CID_HFLIP: | ||
1149 | c->value = dev->ctl_mirror; | ||
1150 | break; | ||
1151 | case V4L2_CID_PRIVATE_Y_EVEN: | ||
1152 | c->value = dev->ctl_y_even; | ||
1153 | break; | ||
1154 | case V4L2_CID_PRIVATE_Y_ODD: | ||
1155 | c->value = dev->ctl_y_odd; | ||
1156 | break; | ||
1157 | case V4L2_CID_PRIVATE_AUTOMUTE: | ||
1158 | c->value = dev->ctl_automute; | ||
1159 | break; | ||
1160 | default: | ||
1161 | return -EINVAL; | ||
1162 | } | ||
1163 | return 0; | ||
1164 | } | ||
1165 | EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal); | ||
1166 | |||
1167 | static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) | ||
1168 | { | ||
1169 | struct saa7134_fh *fh = priv; | ||
1170 | |||
1171 | return saa7134_g_ctrl_internal(fh->dev, fh, c); | ||
1172 | } | ||
1173 | |||
1174 | int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) | ||
1175 | { | ||
1176 | const struct v4l2_queryctrl* ctrl; | ||
1177 | unsigned long flags; | 1001 | unsigned long flags; |
1178 | int restart_overlay = 0; | 1002 | int restart_overlay = 0; |
1179 | int err; | ||
1180 | 1003 | ||
1181 | err = -EINVAL; | 1004 | switch (ctrl->id) { |
1182 | |||
1183 | mutex_lock(&dev->lock); | ||
1184 | |||
1185 | ctrl = ctrl_by_id(c->id); | ||
1186 | if (NULL == ctrl) | ||
1187 | goto error; | ||
1188 | |||
1189 | dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); | ||
1190 | switch (ctrl->type) { | ||
1191 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
1192 | case V4L2_CTRL_TYPE_MENU: | ||
1193 | case V4L2_CTRL_TYPE_INTEGER: | ||
1194 | if (c->value < ctrl->minimum) | ||
1195 | c->value = ctrl->minimum; | ||
1196 | if (c->value > ctrl->maximum) | ||
1197 | c->value = ctrl->maximum; | ||
1198 | break; | ||
1199 | default: | ||
1200 | /* nothing */; | ||
1201 | } | ||
1202 | switch (c->id) { | ||
1203 | case V4L2_CID_BRIGHTNESS: | 1005 | case V4L2_CID_BRIGHTNESS: |
1204 | dev->ctl_bright = c->value; | 1006 | dev->ctl_bright = ctrl->val; |
1205 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); | 1007 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, ctrl->val); |
1206 | break; | 1008 | break; |
1207 | case V4L2_CID_HUE: | 1009 | case V4L2_CID_HUE: |
1208 | dev->ctl_hue = c->value; | 1010 | dev->ctl_hue = ctrl->val; |
1209 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); | 1011 | saa_writeb(SAA7134_DEC_CHROMA_HUE, ctrl->val); |
1210 | break; | 1012 | break; |
1211 | case V4L2_CID_CONTRAST: | 1013 | case V4L2_CID_CONTRAST: |
1212 | dev->ctl_contrast = c->value; | 1014 | dev->ctl_contrast = ctrl->val; |
1213 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, | 1015 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
1214 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); | 1016 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
1215 | break; | 1017 | break; |
1216 | case V4L2_CID_SATURATION: | 1018 | case V4L2_CID_SATURATION: |
1217 | dev->ctl_saturation = c->value; | 1019 | dev->ctl_saturation = ctrl->val; |
1218 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, | 1020 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
1219 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); | 1021 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
1220 | break; | 1022 | break; |
1221 | case V4L2_CID_AUDIO_MUTE: | 1023 | case V4L2_CID_AUDIO_MUTE: |
1222 | dev->ctl_mute = c->value; | 1024 | dev->ctl_mute = ctrl->val; |
1223 | saa7134_tvaudio_setmute(dev); | 1025 | saa7134_tvaudio_setmute(dev); |
1224 | break; | 1026 | break; |
1225 | case V4L2_CID_AUDIO_VOLUME: | 1027 | case V4L2_CID_AUDIO_VOLUME: |
1226 | dev->ctl_volume = c->value; | 1028 | dev->ctl_volume = ctrl->val; |
1227 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); | 1029 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); |
1228 | break; | 1030 | break; |
1229 | case V4L2_CID_PRIVATE_INVERT: | 1031 | case V4L2_CID_PRIVATE_INVERT: |
1230 | dev->ctl_invert = c->value; | 1032 | dev->ctl_invert = ctrl->val; |
1231 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, | 1033 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
1232 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); | 1034 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
1233 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, | 1035 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
1234 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); | 1036 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
1235 | break; | 1037 | break; |
1236 | case V4L2_CID_HFLIP: | 1038 | case V4L2_CID_HFLIP: |
1237 | dev->ctl_mirror = c->value; | 1039 | dev->ctl_mirror = ctrl->val; |
1238 | restart_overlay = 1; | 1040 | restart_overlay = 1; |
1239 | break; | 1041 | break; |
1240 | case V4L2_CID_PRIVATE_Y_EVEN: | 1042 | case V4L2_CID_PRIVATE_Y_EVEN: |
1241 | dev->ctl_y_even = c->value; | 1043 | dev->ctl_y_even = ctrl->val; |
1242 | restart_overlay = 1; | 1044 | restart_overlay = 1; |
1243 | break; | 1045 | break; |
1244 | case V4L2_CID_PRIVATE_Y_ODD: | 1046 | case V4L2_CID_PRIVATE_Y_ODD: |
1245 | dev->ctl_y_odd = c->value; | 1047 | dev->ctl_y_odd = ctrl->val; |
1246 | restart_overlay = 1; | 1048 | restart_overlay = 1; |
1247 | break; | 1049 | break; |
1248 | case V4L2_CID_PRIVATE_AUTOMUTE: | 1050 | case V4L2_CID_PRIVATE_AUTOMUTE: |
@@ -1252,7 +1054,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str | |||
1252 | tda9887_cfg.tuner = TUNER_TDA9887; | 1054 | tda9887_cfg.tuner = TUNER_TDA9887; |
1253 | tda9887_cfg.priv = &dev->tda9887_conf; | 1055 | tda9887_cfg.priv = &dev->tda9887_conf; |
1254 | 1056 | ||
1255 | dev->ctl_automute = c->value; | 1057 | dev->ctl_automute = ctrl->val; |
1256 | if (dev->tda9887_conf) { | 1058 | if (dev->tda9887_conf) { |
1257 | if (dev->ctl_automute) | 1059 | if (dev->ctl_automute) |
1258 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | 1060 | dev->tda9887_conf |= TDA9887_AUTOMUTE; |
@@ -1264,27 +1066,15 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str | |||
1264 | break; | 1066 | break; |
1265 | } | 1067 | } |
1266 | default: | 1068 | default: |
1267 | goto error; | 1069 | return -EINVAL; |
1268 | } | 1070 | } |
1269 | if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { | 1071 | if (restart_overlay && res_locked(dev, RESOURCE_OVERLAY)) { |
1270 | spin_lock_irqsave(&dev->slock,flags); | 1072 | spin_lock_irqsave(&dev->slock, flags); |
1271 | stop_preview(dev,fh); | 1073 | stop_preview(dev); |
1272 | start_preview(dev,fh); | 1074 | start_preview(dev); |
1273 | spin_unlock_irqrestore(&dev->slock,flags); | 1075 | spin_unlock_irqrestore(&dev->slock, flags); |
1274 | } | 1076 | } |
1275 | err = 0; | 1077 | return 0; |
1276 | |||
1277 | error: | ||
1278 | mutex_unlock(&dev->lock); | ||
1279 | return err; | ||
1280 | } | ||
1281 | EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal); | ||
1282 | |||
1283 | static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) | ||
1284 | { | ||
1285 | struct saa7134_fh *fh = f; | ||
1286 | |||
1287 | return saa7134_s_ctrl_internal(fh->dev, fh, c); | ||
1288 | } | 1078 | } |
1289 | 1079 | ||
1290 | /* ------------------------------------------------------------------ */ | 1080 | /* ------------------------------------------------------------------ */ |
@@ -1292,15 +1082,16 @@ static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) | |||
1292 | static struct videobuf_queue *saa7134_queue(struct file *file) | 1082 | static struct videobuf_queue *saa7134_queue(struct file *file) |
1293 | { | 1083 | { |
1294 | struct video_device *vdev = video_devdata(file); | 1084 | struct video_device *vdev = video_devdata(file); |
1085 | struct saa7134_dev *dev = video_drvdata(file); | ||
1295 | struct saa7134_fh *fh = file->private_data; | 1086 | struct saa7134_fh *fh = file->private_data; |
1296 | struct videobuf_queue *q = NULL; | 1087 | struct videobuf_queue *q = NULL; |
1297 | 1088 | ||
1298 | switch (vdev->vfl_type) { | 1089 | switch (vdev->vfl_type) { |
1299 | case VFL_TYPE_GRABBER: | 1090 | case VFL_TYPE_GRABBER: |
1300 | q = &fh->cap; | 1091 | q = fh->is_empress ? &dev->empress_tsq : &dev->cap; |
1301 | break; | 1092 | break; |
1302 | case VFL_TYPE_VBI: | 1093 | case VFL_TYPE_VBI: |
1303 | q = &fh->vbi; | 1094 | q = &dev->vbi; |
1304 | break; | 1095 | break; |
1305 | default: | 1096 | default: |
1306 | BUG(); | 1097 | BUG(); |
@@ -1311,9 +1102,10 @@ static struct videobuf_queue *saa7134_queue(struct file *file) | |||
1311 | static int saa7134_resource(struct file *file) | 1102 | static int saa7134_resource(struct file *file) |
1312 | { | 1103 | { |
1313 | struct video_device *vdev = video_devdata(file); | 1104 | struct video_device *vdev = video_devdata(file); |
1105 | struct saa7134_fh *fh = file->private_data; | ||
1314 | 1106 | ||
1315 | if (vdev->vfl_type == VFL_TYPE_GRABBER) | 1107 | if (vdev->vfl_type == VFL_TYPE_GRABBER) |
1316 | return RESOURCE_VIDEO; | 1108 | return fh->is_empress ? RESOURCE_EMPRESS : RESOURCE_VIDEO; |
1317 | 1109 | ||
1318 | if (vdev->vfl_type == VFL_TYPE_VBI) | 1110 | if (vdev->vfl_type == VFL_TYPE_VBI) |
1319 | return RESOURCE_VBI; | 1111 | return RESOURCE_VBI; |
@@ -1335,22 +1127,6 @@ static int video_open(struct file *file) | |||
1335 | 1127 | ||
1336 | v4l2_fh_init(&fh->fh, vdev); | 1128 | v4l2_fh_init(&fh->fh, vdev); |
1337 | file->private_data = fh; | 1129 | file->private_data = fh; |
1338 | fh->dev = dev; | ||
1339 | |||
1340 | videobuf_queue_sg_init(&fh->cap, &video_qops, | ||
1341 | &dev->pci->dev, &dev->slock, | ||
1342 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1343 | V4L2_FIELD_INTERLACED, | ||
1344 | sizeof(struct saa7134_buf), | ||
1345 | fh, NULL); | ||
1346 | videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops, | ||
1347 | &dev->pci->dev, &dev->slock, | ||
1348 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
1349 | V4L2_FIELD_SEQ_TB, | ||
1350 | sizeof(struct saa7134_buf), | ||
1351 | fh, NULL); | ||
1352 | saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); | ||
1353 | saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); | ||
1354 | 1130 | ||
1355 | if (vdev->vfl_type == VFL_TYPE_RADIO) { | 1131 | if (vdev->vfl_type == VFL_TYPE_RADIO) { |
1356 | /* switch to radio mode */ | 1132 | /* switch to radio mode */ |
@@ -1369,17 +1145,18 @@ static ssize_t | |||
1369 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | 1145 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) |
1370 | { | 1146 | { |
1371 | struct video_device *vdev = video_devdata(file); | 1147 | struct video_device *vdev = video_devdata(file); |
1148 | struct saa7134_dev *dev = video_drvdata(file); | ||
1372 | struct saa7134_fh *fh = file->private_data; | 1149 | struct saa7134_fh *fh = file->private_data; |
1373 | 1150 | ||
1374 | switch (vdev->vfl_type) { | 1151 | switch (vdev->vfl_type) { |
1375 | case VFL_TYPE_GRABBER: | 1152 | case VFL_TYPE_GRABBER: |
1376 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | 1153 | if (res_locked(dev, RESOURCE_VIDEO)) |
1377 | return -EBUSY; | 1154 | return -EBUSY; |
1378 | return videobuf_read_one(saa7134_queue(file), | 1155 | return videobuf_read_one(saa7134_queue(file), |
1379 | data, count, ppos, | 1156 | data, count, ppos, |
1380 | file->f_flags & O_NONBLOCK); | 1157 | file->f_flags & O_NONBLOCK); |
1381 | case VFL_TYPE_VBI: | 1158 | case VFL_TYPE_VBI: |
1382 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) | 1159 | if (!res_get(dev, fh, RESOURCE_VBI)) |
1383 | return -EBUSY; | 1160 | return -EBUSY; |
1384 | return videobuf_read_stream(saa7134_queue(file), | 1161 | return videobuf_read_stream(saa7134_queue(file), |
1385 | data, count, ppos, 1, | 1162 | data, count, ppos, 1, |
@@ -1394,52 +1171,59 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | |||
1394 | static unsigned int | 1171 | static unsigned int |
1395 | video_poll(struct file *file, struct poll_table_struct *wait) | 1172 | video_poll(struct file *file, struct poll_table_struct *wait) |
1396 | { | 1173 | { |
1174 | unsigned long req_events = poll_requested_events(wait); | ||
1397 | struct video_device *vdev = video_devdata(file); | 1175 | struct video_device *vdev = video_devdata(file); |
1176 | struct saa7134_dev *dev = video_drvdata(file); | ||
1398 | struct saa7134_fh *fh = file->private_data; | 1177 | struct saa7134_fh *fh = file->private_data; |
1399 | struct videobuf_buffer *buf = NULL; | 1178 | struct videobuf_buffer *buf = NULL; |
1400 | unsigned int rc = 0; | 1179 | unsigned int rc = 0; |
1401 | 1180 | ||
1181 | if (v4l2_event_pending(&fh->fh)) | ||
1182 | rc = POLLPRI; | ||
1183 | else if (req_events & POLLPRI) | ||
1184 | poll_wait(file, &fh->fh.wait, wait); | ||
1185 | |||
1402 | if (vdev->vfl_type == VFL_TYPE_VBI) | 1186 | if (vdev->vfl_type == VFL_TYPE_VBI) |
1403 | return videobuf_poll_stream(file, &fh->vbi, wait); | 1187 | return rc | videobuf_poll_stream(file, &dev->vbi, wait); |
1404 | 1188 | ||
1405 | if (res_check(fh,RESOURCE_VIDEO)) { | 1189 | if (res_check(fh, RESOURCE_VIDEO)) { |
1406 | mutex_lock(&fh->cap.vb_lock); | 1190 | mutex_lock(&dev->cap.vb_lock); |
1407 | if (!list_empty(&fh->cap.stream)) | 1191 | if (!list_empty(&dev->cap.stream)) |
1408 | buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); | 1192 | buf = list_entry(dev->cap.stream.next, struct videobuf_buffer, stream); |
1409 | } else { | 1193 | } else { |
1410 | mutex_lock(&fh->cap.vb_lock); | 1194 | mutex_lock(&dev->cap.vb_lock); |
1411 | if (UNSET == fh->cap.read_off) { | 1195 | if (UNSET == dev->cap.read_off) { |
1412 | /* need to capture a new frame */ | 1196 | /* need to capture a new frame */ |
1413 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | 1197 | if (res_locked(dev, RESOURCE_VIDEO)) |
1414 | goto err; | 1198 | goto err; |
1415 | if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) | 1199 | if (0 != dev->cap.ops->buf_prepare(&dev->cap, |
1200 | dev->cap.read_buf, dev->cap.field)) | ||
1416 | goto err; | 1201 | goto err; |
1417 | fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); | 1202 | dev->cap.ops->buf_queue(&dev->cap, dev->cap.read_buf); |
1418 | fh->cap.read_off = 0; | 1203 | dev->cap.read_off = 0; |
1419 | } | 1204 | } |
1420 | buf = fh->cap.read_buf; | 1205 | buf = dev->cap.read_buf; |
1421 | } | 1206 | } |
1422 | 1207 | ||
1423 | if (!buf) | 1208 | if (!buf) |
1424 | goto err; | 1209 | goto err; |
1425 | 1210 | ||
1426 | poll_wait(file, &buf->done, wait); | 1211 | poll_wait(file, &buf->done, wait); |
1427 | if (buf->state == VIDEOBUF_DONE || | 1212 | if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) |
1428 | buf->state == VIDEOBUF_ERROR) | 1213 | rc |= POLLIN | POLLRDNORM; |
1429 | rc = POLLIN|POLLRDNORM; | 1214 | mutex_unlock(&dev->cap.vb_lock); |
1430 | mutex_unlock(&fh->cap.vb_lock); | ||
1431 | return rc; | 1215 | return rc; |
1432 | 1216 | ||
1433 | err: | 1217 | err: |
1434 | mutex_unlock(&fh->cap.vb_lock); | 1218 | mutex_unlock(&dev->cap.vb_lock); |
1435 | return POLLERR; | 1219 | return rc | POLLERR; |
1436 | } | 1220 | } |
1437 | 1221 | ||
1438 | static int video_release(struct file *file) | 1222 | static int video_release(struct file *file) |
1439 | { | 1223 | { |
1440 | struct video_device *vdev = video_devdata(file); | 1224 | struct video_device *vdev = video_devdata(file); |
1441 | struct saa7134_fh *fh = file->private_data; | 1225 | struct saa7134_dev *dev = video_drvdata(file); |
1442 | struct saa7134_dev *dev = fh->dev; | 1226 | struct saa7134_fh *fh = file->private_data; |
1443 | struct saa6588_command cmd; | 1227 | struct saa6588_command cmd; |
1444 | unsigned long flags; | 1228 | unsigned long flags; |
1445 | 1229 | ||
@@ -1448,26 +1232,28 @@ static int video_release(struct file *file) | |||
1448 | /* turn off overlay */ | 1232 | /* turn off overlay */ |
1449 | if (res_check(fh, RESOURCE_OVERLAY)) { | 1233 | if (res_check(fh, RESOURCE_OVERLAY)) { |
1450 | spin_lock_irqsave(&dev->slock,flags); | 1234 | spin_lock_irqsave(&dev->slock,flags); |
1451 | stop_preview(dev,fh); | 1235 | stop_preview(dev); |
1452 | spin_unlock_irqrestore(&dev->slock,flags); | 1236 | spin_unlock_irqrestore(&dev->slock,flags); |
1453 | res_free(dev,fh,RESOURCE_OVERLAY); | 1237 | res_free(dev, fh, RESOURCE_OVERLAY); |
1454 | } | 1238 | } |
1455 | 1239 | ||
1456 | /* stop video capture */ | 1240 | /* stop video capture */ |
1457 | if (res_check(fh, RESOURCE_VIDEO)) { | 1241 | if (res_check(fh, RESOURCE_VIDEO)) { |
1458 | pm_qos_remove_request(&dev->qos_request); | 1242 | pm_qos_remove_request(&dev->qos_request); |
1459 | videobuf_streamoff(&fh->cap); | 1243 | videobuf_streamoff(&dev->cap); |
1460 | res_free(dev,fh,RESOURCE_VIDEO); | 1244 | res_free(dev, fh, RESOURCE_VIDEO); |
1245 | videobuf_mmap_free(&dev->cap); | ||
1461 | } | 1246 | } |
1462 | if (fh->cap.read_buf) { | 1247 | if (dev->cap.read_buf) { |
1463 | buffer_release(&fh->cap,fh->cap.read_buf); | 1248 | buffer_release(&dev->cap, dev->cap.read_buf); |
1464 | kfree(fh->cap.read_buf); | 1249 | kfree(dev->cap.read_buf); |
1465 | } | 1250 | } |
1466 | 1251 | ||
1467 | /* stop vbi capture */ | 1252 | /* stop vbi capture */ |
1468 | if (res_check(fh, RESOURCE_VBI)) { | 1253 | if (res_check(fh, RESOURCE_VBI)) { |
1469 | videobuf_stop(&fh->vbi); | 1254 | videobuf_stop(&dev->vbi); |
1470 | res_free(dev,fh,RESOURCE_VBI); | 1255 | res_free(dev, fh, RESOURCE_VBI); |
1256 | videobuf_mmap_free(&dev->vbi); | ||
1471 | } | 1257 | } |
1472 | 1258 | ||
1473 | /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ | 1259 | /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ |
@@ -1480,12 +1266,6 @@ static int video_release(struct file *file) | |||
1480 | if (vdev->vfl_type == VFL_TYPE_RADIO) | 1266 | if (vdev->vfl_type == VFL_TYPE_RADIO) |
1481 | saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd); | 1267 | saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd); |
1482 | 1268 | ||
1483 | /* free stuff */ | ||
1484 | videobuf_mmap_free(&fh->cap); | ||
1485 | videobuf_mmap_free(&fh->vbi); | ||
1486 | saa7134_pgtable_free(dev->pci,&fh->pt_cap); | ||
1487 | saa7134_pgtable_free(dev->pci,&fh->pt_vbi); | ||
1488 | |||
1489 | v4l2_fh_del(&fh->fh); | 1269 | v4l2_fh_del(&fh->fh); |
1490 | v4l2_fh_exit(&fh->fh); | 1270 | v4l2_fh_exit(&fh->fh); |
1491 | file->private_data = NULL; | 1271 | file->private_data = NULL; |
@@ -1501,11 +1281,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) | |||
1501 | static ssize_t radio_read(struct file *file, char __user *data, | 1281 | static ssize_t radio_read(struct file *file, char __user *data, |
1502 | size_t count, loff_t *ppos) | 1282 | size_t count, loff_t *ppos) |
1503 | { | 1283 | { |
1504 | struct saa7134_fh *fh = file->private_data; | 1284 | struct saa7134_dev *dev = video_drvdata(file); |
1505 | struct saa7134_dev *dev = fh->dev; | ||
1506 | struct saa6588_command cmd; | 1285 | struct saa6588_command cmd; |
1507 | 1286 | ||
1508 | cmd.block_count = count/3; | 1287 | cmd.block_count = count/3; |
1288 | cmd.nonblocking = file->f_flags & O_NONBLOCK; | ||
1509 | cmd.buffer = data; | 1289 | cmd.buffer = data; |
1510 | cmd.instance = file; | 1290 | cmd.instance = file; |
1511 | cmd.result = -ENODEV; | 1291 | cmd.result = -ENODEV; |
@@ -1517,16 +1297,16 @@ static ssize_t radio_read(struct file *file, char __user *data, | |||
1517 | 1297 | ||
1518 | static unsigned int radio_poll(struct file *file, poll_table *wait) | 1298 | static unsigned int radio_poll(struct file *file, poll_table *wait) |
1519 | { | 1299 | { |
1520 | struct saa7134_fh *fh = file->private_data; | 1300 | struct saa7134_dev *dev = video_drvdata(file); |
1521 | struct saa7134_dev *dev = fh->dev; | ||
1522 | struct saa6588_command cmd; | 1301 | struct saa6588_command cmd; |
1302 | unsigned int rc = v4l2_ctrl_poll(file, wait); | ||
1523 | 1303 | ||
1524 | cmd.instance = file; | 1304 | cmd.instance = file; |
1525 | cmd.event_list = wait; | 1305 | cmd.event_list = wait; |
1526 | cmd.result = -ENODEV; | 1306 | cmd.result = 0; |
1527 | saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd); | 1307 | saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd); |
1528 | 1308 | ||
1529 | return cmd.result; | 1309 | return rc | cmd.result; |
1530 | } | 1310 | } |
1531 | 1311 | ||
1532 | /* ------------------------------------------------------------------ */ | 1312 | /* ------------------------------------------------------------------ */ |
@@ -1534,8 +1314,7 @@ static unsigned int radio_poll(struct file *file, poll_table *wait) | |||
1534 | static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, | 1314 | static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, |
1535 | struct v4l2_format *f) | 1315 | struct v4l2_format *f) |
1536 | { | 1316 | { |
1537 | struct saa7134_fh *fh = priv; | 1317 | struct saa7134_dev *dev = video_drvdata(file); |
1538 | struct saa7134_dev *dev = fh->dev; | ||
1539 | struct saa7134_tvnorm *norm = dev->tvnorm; | 1318 | struct saa7134_tvnorm *norm = dev->tvnorm; |
1540 | 1319 | ||
1541 | memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved)); | 1320 | memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved)); |
@@ -1555,12 +1334,11 @@ static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, | |||
1555 | static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, | 1334 | static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, |
1556 | struct v4l2_format *f) | 1335 | struct v4l2_format *f) |
1557 | { | 1336 | { |
1558 | struct saa7134_fh *fh = priv; | 1337 | struct saa7134_dev *dev = video_drvdata(file); |
1559 | struct saa7134_dev *dev = fh->dev; | ||
1560 | 1338 | ||
1561 | f->fmt.pix.width = dev->width; | 1339 | f->fmt.pix.width = dev->width; |
1562 | f->fmt.pix.height = dev->height; | 1340 | f->fmt.pix.height = dev->height; |
1563 | f->fmt.pix.field = fh->cap.field; | 1341 | f->fmt.pix.field = dev->cap.field; |
1564 | f->fmt.pix.pixelformat = dev->fmt->fourcc; | 1342 | f->fmt.pix.pixelformat = dev->fmt->fourcc; |
1565 | f->fmt.pix.bytesperline = | 1343 | f->fmt.pix.bytesperline = |
1566 | (f->fmt.pix.width * dev->fmt->depth) >> 3; | 1344 | (f->fmt.pix.width * dev->fmt->depth) >> 3; |
@@ -1574,8 +1352,7 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, | |||
1574 | static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, | 1352 | static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, |
1575 | struct v4l2_format *f) | 1353 | struct v4l2_format *f) |
1576 | { | 1354 | { |
1577 | struct saa7134_fh *fh = priv; | 1355 | struct saa7134_dev *dev = video_drvdata(file); |
1578 | struct saa7134_dev *dev = fh->dev; | ||
1579 | struct v4l2_clip __user *clips = f->fmt.win.clips; | 1356 | struct v4l2_clip __user *clips = f->fmt.win.clips; |
1580 | u32 clipcount = f->fmt.win.clipcount; | 1357 | u32 clipcount = f->fmt.win.clipcount; |
1581 | int err = 0; | 1358 | int err = 0; |
@@ -1607,8 +1384,7 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, | |||
1607 | static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, | 1384 | static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, |
1608 | struct v4l2_format *f) | 1385 | struct v4l2_format *f) |
1609 | { | 1386 | { |
1610 | struct saa7134_fh *fh = priv; | 1387 | struct saa7134_dev *dev = video_drvdata(file); |
1611 | struct saa7134_dev *dev = fh->dev; | ||
1612 | struct saa7134_format *fmt; | 1388 | struct saa7134_format *fmt; |
1613 | enum v4l2_field field; | 1389 | enum v4l2_field field; |
1614 | unsigned int maxw, maxh; | 1390 | unsigned int maxw, maxh; |
@@ -1659,8 +1435,7 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, | |||
1659 | static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, | 1435 | static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, |
1660 | struct v4l2_format *f) | 1436 | struct v4l2_format *f) |
1661 | { | 1437 | { |
1662 | struct saa7134_fh *fh = priv; | 1438 | struct saa7134_dev *dev = video_drvdata(file); |
1663 | struct saa7134_dev *dev = fh->dev; | ||
1664 | 1439 | ||
1665 | if (saa7134_no_overlay > 0) { | 1440 | if (saa7134_no_overlay > 0) { |
1666 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); | 1441 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); |
@@ -1675,8 +1450,7 @@ static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, | |||
1675 | static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, | 1450 | static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, |
1676 | struct v4l2_format *f) | 1451 | struct v4l2_format *f) |
1677 | { | 1452 | { |
1678 | struct saa7134_fh *fh = priv; | 1453 | struct saa7134_dev *dev = video_drvdata(file); |
1679 | struct saa7134_dev *dev = fh->dev; | ||
1680 | int err; | 1454 | int err; |
1681 | 1455 | ||
1682 | err = saa7134_try_fmt_vid_cap(file, priv, f); | 1456 | err = saa7134_try_fmt_vid_cap(file, priv, f); |
@@ -1686,15 +1460,14 @@ static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, | |||
1686 | dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 1460 | dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1687 | dev->width = f->fmt.pix.width; | 1461 | dev->width = f->fmt.pix.width; |
1688 | dev->height = f->fmt.pix.height; | 1462 | dev->height = f->fmt.pix.height; |
1689 | fh->cap.field = f->fmt.pix.field; | 1463 | dev->cap.field = f->fmt.pix.field; |
1690 | return 0; | 1464 | return 0; |
1691 | } | 1465 | } |
1692 | 1466 | ||
1693 | static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, | 1467 | static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, |
1694 | struct v4l2_format *f) | 1468 | struct v4l2_format *f) |
1695 | { | 1469 | { |
1696 | struct saa7134_fh *fh = priv; | 1470 | struct saa7134_dev *dev = video_drvdata(file); |
1697 | struct saa7134_dev *dev = fh->dev; | ||
1698 | int err; | 1471 | int err; |
1699 | unsigned long flags; | 1472 | unsigned long flags; |
1700 | 1473 | ||
@@ -1719,10 +1492,10 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, | |||
1719 | return -EFAULT; | 1492 | return -EFAULT; |
1720 | } | 1493 | } |
1721 | 1494 | ||
1722 | if (res_check(fh, RESOURCE_OVERLAY)) { | 1495 | if (res_check(priv, RESOURCE_OVERLAY)) { |
1723 | spin_lock_irqsave(&dev->slock, flags); | 1496 | spin_lock_irqsave(&dev->slock, flags); |
1724 | stop_preview(dev, fh); | 1497 | stop_preview(dev); |
1725 | start_preview(dev, fh); | 1498 | start_preview(dev); |
1726 | spin_unlock_irqrestore(&dev->slock, flags); | 1499 | spin_unlock_irqrestore(&dev->slock, flags); |
1727 | } | 1500 | } |
1728 | 1501 | ||
@@ -1730,26 +1503,9 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, | |||
1730 | return 0; | 1503 | return 0; |
1731 | } | 1504 | } |
1732 | 1505 | ||
1733 | int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) | 1506 | int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i) |
1734 | { | ||
1735 | const struct v4l2_queryctrl *ctrl; | ||
1736 | |||
1737 | if ((c->id < V4L2_CID_BASE || | ||
1738 | c->id >= V4L2_CID_LASTP1) && | ||
1739 | (c->id < V4L2_CID_PRIVATE_BASE || | ||
1740 | c->id >= V4L2_CID_PRIVATE_LASTP1)) | ||
1741 | return -EINVAL; | ||
1742 | ctrl = ctrl_by_id(c->id); | ||
1743 | *c = (NULL != ctrl) ? *ctrl : no_ctrl; | ||
1744 | return 0; | ||
1745 | } | ||
1746 | EXPORT_SYMBOL_GPL(saa7134_queryctrl); | ||
1747 | |||
1748 | static int saa7134_enum_input(struct file *file, void *priv, | ||
1749 | struct v4l2_input *i) | ||
1750 | { | 1507 | { |
1751 | struct saa7134_fh *fh = priv; | 1508 | struct saa7134_dev *dev = video_drvdata(file); |
1752 | struct saa7134_dev *dev = fh->dev; | ||
1753 | unsigned int n; | 1509 | unsigned int n; |
1754 | 1510 | ||
1755 | n = i->index; | 1511 | n = i->index; |
@@ -1769,27 +1525,27 @@ static int saa7134_enum_input(struct file *file, void *priv, | |||
1769 | if (0 != (v1 & 0x40)) | 1525 | if (0 != (v1 & 0x40)) |
1770 | i->status |= V4L2_IN_ST_NO_H_LOCK; | 1526 | i->status |= V4L2_IN_ST_NO_H_LOCK; |
1771 | if (0 != (v2 & 0x40)) | 1527 | if (0 != (v2 & 0x40)) |
1772 | i->status |= V4L2_IN_ST_NO_SYNC; | 1528 | i->status |= V4L2_IN_ST_NO_SIGNAL; |
1773 | if (0 != (v2 & 0x0e)) | 1529 | if (0 != (v2 & 0x0e)) |
1774 | i->status |= V4L2_IN_ST_MACROVISION; | 1530 | i->status |= V4L2_IN_ST_MACROVISION; |
1775 | } | 1531 | } |
1776 | i->std = SAA7134_NORMS; | 1532 | i->std = SAA7134_NORMS; |
1777 | return 0; | 1533 | return 0; |
1778 | } | 1534 | } |
1535 | EXPORT_SYMBOL_GPL(saa7134_enum_input); | ||
1779 | 1536 | ||
1780 | static int saa7134_g_input(struct file *file, void *priv, unsigned int *i) | 1537 | int saa7134_g_input(struct file *file, void *priv, unsigned int *i) |
1781 | { | 1538 | { |
1782 | struct saa7134_fh *fh = priv; | 1539 | struct saa7134_dev *dev = video_drvdata(file); |
1783 | struct saa7134_dev *dev = fh->dev; | ||
1784 | 1540 | ||
1785 | *i = dev->ctl_input; | 1541 | *i = dev->ctl_input; |
1786 | return 0; | 1542 | return 0; |
1787 | } | 1543 | } |
1544 | EXPORT_SYMBOL_GPL(saa7134_g_input); | ||
1788 | 1545 | ||
1789 | static int saa7134_s_input(struct file *file, void *priv, unsigned int i) | 1546 | int saa7134_s_input(struct file *file, void *priv, unsigned int i) |
1790 | { | 1547 | { |
1791 | struct saa7134_fh *fh = priv; | 1548 | struct saa7134_dev *dev = video_drvdata(file); |
1792 | struct saa7134_dev *dev = fh->dev; | ||
1793 | 1549 | ||
1794 | if (i >= SAA7134_INPUT_MAX) | 1550 | if (i >= SAA7134_INPUT_MAX) |
1795 | return -EINVAL; | 1551 | return -EINVAL; |
@@ -1800,13 +1556,14 @@ static int saa7134_s_input(struct file *file, void *priv, unsigned int i) | |||
1800 | mutex_unlock(&dev->lock); | 1556 | mutex_unlock(&dev->lock); |
1801 | return 0; | 1557 | return 0; |
1802 | } | 1558 | } |
1559 | EXPORT_SYMBOL_GPL(saa7134_s_input); | ||
1803 | 1560 | ||
1804 | static int saa7134_querycap(struct file *file, void *priv, | 1561 | int saa7134_querycap(struct file *file, void *priv, |
1805 | struct v4l2_capability *cap) | 1562 | struct v4l2_capability *cap) |
1806 | { | 1563 | { |
1807 | struct saa7134_fh *fh = priv; | 1564 | struct saa7134_dev *dev = video_drvdata(file); |
1808 | struct saa7134_dev *dev = fh->dev; | ||
1809 | struct video_device *vdev = video_devdata(file); | 1565 | struct video_device *vdev = video_devdata(file); |
1566 | struct saa7134_fh *fh = priv; | ||
1810 | u32 radio_caps, video_caps, vbi_caps; | 1567 | u32 radio_caps, video_caps, vbi_caps; |
1811 | 1568 | ||
1812 | unsigned int tuner_type = dev->tuner_type; | 1569 | unsigned int tuner_type = dev->tuner_type; |
@@ -1825,7 +1582,7 @@ static int saa7134_querycap(struct file *file, void *priv, | |||
1825 | radio_caps |= V4L2_CAP_RDS_CAPTURE; | 1582 | radio_caps |= V4L2_CAP_RDS_CAPTURE; |
1826 | 1583 | ||
1827 | video_caps = V4L2_CAP_VIDEO_CAPTURE; | 1584 | video_caps = V4L2_CAP_VIDEO_CAPTURE; |
1828 | if (saa7134_no_overlay <= 0) | 1585 | if (saa7134_no_overlay <= 0 && !fh->is_empress) |
1829 | video_caps |= V4L2_CAP_VIDEO_OVERLAY; | 1586 | video_caps |= V4L2_CAP_VIDEO_OVERLAY; |
1830 | 1587 | ||
1831 | vbi_caps = V4L2_CAP_VBI_CAPTURE; | 1588 | vbi_caps = V4L2_CAP_VBI_CAPTURE; |
@@ -1851,14 +1608,17 @@ static int saa7134_querycap(struct file *file, void *priv, | |||
1851 | 1608 | ||
1852 | return 0; | 1609 | return 0; |
1853 | } | 1610 | } |
1611 | EXPORT_SYMBOL_GPL(saa7134_querycap); | ||
1854 | 1612 | ||
1855 | int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id) | 1613 | int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id) |
1856 | { | 1614 | { |
1615 | struct saa7134_dev *dev = video_drvdata(file); | ||
1616 | struct saa7134_fh *fh = priv; | ||
1857 | unsigned long flags; | 1617 | unsigned long flags; |
1858 | unsigned int i; | 1618 | unsigned int i; |
1859 | v4l2_std_id fixup; | 1619 | v4l2_std_id fixup; |
1860 | 1620 | ||
1861 | if (!fh && res_locked(dev, RESOURCE_OVERLAY)) { | 1621 | if (fh->is_empress && res_locked(dev, RESOURCE_OVERLAY)) { |
1862 | /* Don't change the std from the mpeg device | 1622 | /* Don't change the std from the mpeg device |
1863 | if overlay is active. */ | 1623 | if overlay is active. */ |
1864 | return -EBUSY; | 1624 | return -EBUSY; |
@@ -1898,15 +1658,15 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ | |||
1898 | id = tvnorms[i].id; | 1658 | id = tvnorms[i].id; |
1899 | 1659 | ||
1900 | mutex_lock(&dev->lock); | 1660 | mutex_lock(&dev->lock); |
1901 | if (fh && res_check(fh, RESOURCE_OVERLAY)) { | 1661 | if (!fh->is_empress && res_check(fh, RESOURCE_OVERLAY)) { |
1902 | spin_lock_irqsave(&dev->slock, flags); | 1662 | spin_lock_irqsave(&dev->slock, flags); |
1903 | stop_preview(dev, fh); | 1663 | stop_preview(dev); |
1904 | spin_unlock_irqrestore(&dev->slock, flags); | 1664 | spin_unlock_irqrestore(&dev->slock, flags); |
1905 | 1665 | ||
1906 | set_tvnorm(dev, &tvnorms[i]); | 1666 | set_tvnorm(dev, &tvnorms[i]); |
1907 | 1667 | ||
1908 | spin_lock_irqsave(&dev->slock, flags); | 1668 | spin_lock_irqsave(&dev->slock, flags); |
1909 | start_preview(dev, fh); | 1669 | start_preview(dev); |
1910 | spin_unlock_irqrestore(&dev->slock, flags); | 1670 | spin_unlock_irqrestore(&dev->slock, flags); |
1911 | } else | 1671 | } else |
1912 | set_tvnorm(dev, &tvnorms[i]); | 1672 | set_tvnorm(dev, &tvnorms[i]); |
@@ -1915,29 +1675,21 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ | |||
1915 | mutex_unlock(&dev->lock); | 1675 | mutex_unlock(&dev->lock); |
1916 | return 0; | 1676 | return 0; |
1917 | } | 1677 | } |
1918 | EXPORT_SYMBOL_GPL(saa7134_s_std_internal); | 1678 | EXPORT_SYMBOL_GPL(saa7134_s_std); |
1919 | 1679 | ||
1920 | static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id) | 1680 | int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id) |
1921 | { | 1681 | { |
1922 | struct saa7134_fh *fh = priv; | 1682 | struct saa7134_dev *dev = video_drvdata(file); |
1923 | |||
1924 | return saa7134_s_std_internal(fh->dev, fh, id); | ||
1925 | } | ||
1926 | |||
1927 | static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id) | ||
1928 | { | ||
1929 | struct saa7134_fh *fh = priv; | ||
1930 | struct saa7134_dev *dev = fh->dev; | ||
1931 | 1683 | ||
1932 | *id = dev->tvnorm->id; | 1684 | *id = dev->tvnorm->id; |
1933 | return 0; | 1685 | return 0; |
1934 | } | 1686 | } |
1687 | EXPORT_SYMBOL_GPL(saa7134_g_std); | ||
1935 | 1688 | ||
1936 | static int saa7134_cropcap(struct file *file, void *priv, | 1689 | static int saa7134_cropcap(struct file *file, void *priv, |
1937 | struct v4l2_cropcap *cap) | 1690 | struct v4l2_cropcap *cap) |
1938 | { | 1691 | { |
1939 | struct saa7134_fh *fh = priv; | 1692 | struct saa7134_dev *dev = video_drvdata(file); |
1940 | struct saa7134_dev *dev = fh->dev; | ||
1941 | 1693 | ||
1942 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1694 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1943 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1695 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
@@ -1959,8 +1711,7 @@ static int saa7134_cropcap(struct file *file, void *priv, | |||
1959 | 1711 | ||
1960 | static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) | 1712 | static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) |
1961 | { | 1713 | { |
1962 | struct saa7134_fh *fh = f; | 1714 | struct saa7134_dev *dev = video_drvdata(file); |
1963 | struct saa7134_dev *dev = fh->dev; | ||
1964 | 1715 | ||
1965 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1716 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1966 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1717 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
@@ -1971,22 +1722,17 @@ static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) | |||
1971 | 1722 | ||
1972 | static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) | 1723 | static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) |
1973 | { | 1724 | { |
1974 | struct saa7134_fh *fh = f; | 1725 | struct saa7134_dev *dev = video_drvdata(file); |
1975 | struct saa7134_dev *dev = fh->dev; | ||
1976 | struct v4l2_rect *b = &dev->crop_bounds; | 1726 | struct v4l2_rect *b = &dev->crop_bounds; |
1977 | struct v4l2_rect *c = &dev->crop_current; | 1727 | struct v4l2_rect *c = &dev->crop_current; |
1978 | 1728 | ||
1979 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1729 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1980 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1730 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
1981 | return -EINVAL; | 1731 | return -EINVAL; |
1982 | if (crop->c.height < 0) | ||
1983 | return -EINVAL; | ||
1984 | if (crop->c.width < 0) | ||
1985 | return -EINVAL; | ||
1986 | 1732 | ||
1987 | if (res_locked(fh->dev, RESOURCE_OVERLAY)) | 1733 | if (res_locked(dev, RESOURCE_OVERLAY)) |
1988 | return -EBUSY; | 1734 | return -EBUSY; |
1989 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | 1735 | if (res_locked(dev, RESOURCE_VIDEO)) |
1990 | return -EBUSY; | 1736 | return -EBUSY; |
1991 | 1737 | ||
1992 | *c = crop->c; | 1738 | *c = crop->c; |
@@ -2006,11 +1752,10 @@ static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *cr | |||
2006 | return 0; | 1752 | return 0; |
2007 | } | 1753 | } |
2008 | 1754 | ||
2009 | static int saa7134_g_tuner(struct file *file, void *priv, | 1755 | int saa7134_g_tuner(struct file *file, void *priv, |
2010 | struct v4l2_tuner *t) | 1756 | struct v4l2_tuner *t) |
2011 | { | 1757 | { |
2012 | struct saa7134_fh *fh = priv; | 1758 | struct saa7134_dev *dev = video_drvdata(file); |
2013 | struct saa7134_dev *dev = fh->dev; | ||
2014 | int n; | 1759 | int n; |
2015 | 1760 | ||
2016 | if (0 != t->index) | 1761 | if (0 != t->index) |
@@ -2037,12 +1782,12 @@ static int saa7134_g_tuner(struct file *file, void *priv, | |||
2037 | t->signal = 0xffff; | 1782 | t->signal = 0xffff; |
2038 | return 0; | 1783 | return 0; |
2039 | } | 1784 | } |
1785 | EXPORT_SYMBOL_GPL(saa7134_g_tuner); | ||
2040 | 1786 | ||
2041 | static int saa7134_s_tuner(struct file *file, void *priv, | 1787 | int saa7134_s_tuner(struct file *file, void *priv, |
2042 | const struct v4l2_tuner *t) | 1788 | const struct v4l2_tuner *t) |
2043 | { | 1789 | { |
2044 | struct saa7134_fh *fh = priv; | 1790 | struct saa7134_dev *dev = video_drvdata(file); |
2045 | struct saa7134_dev *dev = fh->dev; | ||
2046 | int rx, mode; | 1791 | int rx, mode; |
2047 | 1792 | ||
2048 | if (0 != t->index) | 1793 | if (0 != t->index) |
@@ -2058,12 +1803,12 @@ static int saa7134_s_tuner(struct file *file, void *priv, | |||
2058 | 1803 | ||
2059 | return 0; | 1804 | return 0; |
2060 | } | 1805 | } |
1806 | EXPORT_SYMBOL_GPL(saa7134_s_tuner); | ||
2061 | 1807 | ||
2062 | static int saa7134_g_frequency(struct file *file, void *priv, | 1808 | int saa7134_g_frequency(struct file *file, void *priv, |
2063 | struct v4l2_frequency *f) | 1809 | struct v4l2_frequency *f) |
2064 | { | 1810 | { |
2065 | struct saa7134_fh *fh = priv; | 1811 | struct saa7134_dev *dev = video_drvdata(file); |
2066 | struct saa7134_dev *dev = fh->dev; | ||
2067 | 1812 | ||
2068 | if (0 != f->tuner) | 1813 | if (0 != f->tuner) |
2069 | return -EINVAL; | 1814 | return -EINVAL; |
@@ -2072,12 +1817,12 @@ static int saa7134_g_frequency(struct file *file, void *priv, | |||
2072 | 1817 | ||
2073 | return 0; | 1818 | return 0; |
2074 | } | 1819 | } |
1820 | EXPORT_SYMBOL_GPL(saa7134_g_frequency); | ||
2075 | 1821 | ||
2076 | static int saa7134_s_frequency(struct file *file, void *priv, | 1822 | int saa7134_s_frequency(struct file *file, void *priv, |
2077 | const struct v4l2_frequency *f) | 1823 | const struct v4l2_frequency *f) |
2078 | { | 1824 | { |
2079 | struct saa7134_fh *fh = priv; | 1825 | struct saa7134_dev *dev = video_drvdata(file); |
2080 | struct saa7134_dev *dev = fh->dev; | ||
2081 | 1826 | ||
2082 | if (0 != f->tuner) | 1827 | if (0 != f->tuner) |
2083 | return -EINVAL; | 1828 | return -EINVAL; |
@@ -2089,6 +1834,7 @@ static int saa7134_s_frequency(struct file *file, void *priv, | |||
2089 | mutex_unlock(&dev->lock); | 1834 | mutex_unlock(&dev->lock); |
2090 | return 0; | 1835 | return 0; |
2091 | } | 1836 | } |
1837 | EXPORT_SYMBOL_GPL(saa7134_s_frequency); | ||
2092 | 1838 | ||
2093 | static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, | 1839 | static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, |
2094 | struct v4l2_fmtdesc *f) | 1840 | struct v4l2_fmtdesc *f) |
@@ -2126,8 +1872,7 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, | |||
2126 | static int saa7134_g_fbuf(struct file *file, void *f, | 1872 | static int saa7134_g_fbuf(struct file *file, void *f, |
2127 | struct v4l2_framebuffer *fb) | 1873 | struct v4l2_framebuffer *fb) |
2128 | { | 1874 | { |
2129 | struct saa7134_fh *fh = f; | 1875 | struct saa7134_dev *dev = video_drvdata(file); |
2130 | struct saa7134_dev *dev = fh->dev; | ||
2131 | 1876 | ||
2132 | *fb = dev->ovbuf; | 1877 | *fb = dev->ovbuf; |
2133 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | 1878 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; |
@@ -2138,8 +1883,7 @@ static int saa7134_g_fbuf(struct file *file, void *f, | |||
2138 | static int saa7134_s_fbuf(struct file *file, void *f, | 1883 | static int saa7134_s_fbuf(struct file *file, void *f, |
2139 | const struct v4l2_framebuffer *fb) | 1884 | const struct v4l2_framebuffer *fb) |
2140 | { | 1885 | { |
2141 | struct saa7134_fh *fh = f; | 1886 | struct saa7134_dev *dev = video_drvdata(file); |
2142 | struct saa7134_dev *dev = fh->dev; | ||
2143 | struct saa7134_format *fmt; | 1887 | struct saa7134_format *fmt; |
2144 | 1888 | ||
2145 | if (!capable(CAP_SYS_ADMIN) && | 1889 | if (!capable(CAP_SYS_ADMIN) && |
@@ -2160,10 +1904,9 @@ static int saa7134_s_fbuf(struct file *file, void *f, | |||
2160 | return 0; | 1904 | return 0; |
2161 | } | 1905 | } |
2162 | 1906 | ||
2163 | static int saa7134_overlay(struct file *file, void *f, unsigned int on) | 1907 | static int saa7134_overlay(struct file *file, void *priv, unsigned int on) |
2164 | { | 1908 | { |
2165 | struct saa7134_fh *fh = f; | 1909 | struct saa7134_dev *dev = video_drvdata(file); |
2166 | struct saa7134_dev *dev = fh->dev; | ||
2167 | unsigned long flags; | 1910 | unsigned long flags; |
2168 | 1911 | ||
2169 | if (on) { | 1912 | if (on) { |
@@ -2172,54 +1915,57 @@ static int saa7134_overlay(struct file *file, void *f, unsigned int on) | |||
2172 | return -EINVAL; | 1915 | return -EINVAL; |
2173 | } | 1916 | } |
2174 | 1917 | ||
2175 | if (!res_get(dev, fh, RESOURCE_OVERLAY)) | 1918 | if (!res_get(dev, priv, RESOURCE_OVERLAY)) |
2176 | return -EBUSY; | 1919 | return -EBUSY; |
2177 | spin_lock_irqsave(&dev->slock, flags); | 1920 | spin_lock_irqsave(&dev->slock, flags); |
2178 | start_preview(dev, fh); | 1921 | start_preview(dev); |
2179 | spin_unlock_irqrestore(&dev->slock, flags); | 1922 | spin_unlock_irqrestore(&dev->slock, flags); |
2180 | } | 1923 | } |
2181 | if (!on) { | 1924 | if (!on) { |
2182 | if (!res_check(fh, RESOURCE_OVERLAY)) | 1925 | if (!res_check(priv, RESOURCE_OVERLAY)) |
2183 | return -EINVAL; | 1926 | return -EINVAL; |
2184 | spin_lock_irqsave(&dev->slock, flags); | 1927 | spin_lock_irqsave(&dev->slock, flags); |
2185 | stop_preview(dev, fh); | 1928 | stop_preview(dev); |
2186 | spin_unlock_irqrestore(&dev->slock, flags); | 1929 | spin_unlock_irqrestore(&dev->slock, flags); |
2187 | res_free(dev, fh, RESOURCE_OVERLAY); | 1930 | res_free(dev, priv, RESOURCE_OVERLAY); |
2188 | } | 1931 | } |
2189 | return 0; | 1932 | return 0; |
2190 | } | 1933 | } |
2191 | 1934 | ||
2192 | static int saa7134_reqbufs(struct file *file, void *priv, | 1935 | int saa7134_reqbufs(struct file *file, void *priv, |
2193 | struct v4l2_requestbuffers *p) | 1936 | struct v4l2_requestbuffers *p) |
2194 | { | 1937 | { |
2195 | return videobuf_reqbufs(saa7134_queue(file), p); | 1938 | return videobuf_reqbufs(saa7134_queue(file), p); |
2196 | } | 1939 | } |
1940 | EXPORT_SYMBOL_GPL(saa7134_reqbufs); | ||
2197 | 1941 | ||
2198 | static int saa7134_querybuf(struct file *file, void *priv, | 1942 | int saa7134_querybuf(struct file *file, void *priv, |
2199 | struct v4l2_buffer *b) | 1943 | struct v4l2_buffer *b) |
2200 | { | 1944 | { |
2201 | return videobuf_querybuf(saa7134_queue(file), b); | 1945 | return videobuf_querybuf(saa7134_queue(file), b); |
2202 | } | 1946 | } |
1947 | EXPORT_SYMBOL_GPL(saa7134_querybuf); | ||
2203 | 1948 | ||
2204 | static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 1949 | int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
2205 | { | 1950 | { |
2206 | return videobuf_qbuf(saa7134_queue(file), b); | 1951 | return videobuf_qbuf(saa7134_queue(file), b); |
2207 | } | 1952 | } |
1953 | EXPORT_SYMBOL_GPL(saa7134_qbuf); | ||
2208 | 1954 | ||
2209 | static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 1955 | int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
2210 | { | 1956 | { |
2211 | return videobuf_dqbuf(saa7134_queue(file), b, | 1957 | return videobuf_dqbuf(saa7134_queue(file), b, |
2212 | file->f_flags & O_NONBLOCK); | 1958 | file->f_flags & O_NONBLOCK); |
2213 | } | 1959 | } |
1960 | EXPORT_SYMBOL_GPL(saa7134_dqbuf); | ||
2214 | 1961 | ||
2215 | static int saa7134_streamon(struct file *file, void *priv, | 1962 | int saa7134_streamon(struct file *file, void *priv, |
2216 | enum v4l2_buf_type type) | 1963 | enum v4l2_buf_type type) |
2217 | { | 1964 | { |
2218 | struct saa7134_fh *fh = priv; | 1965 | struct saa7134_dev *dev = video_drvdata(file); |
2219 | struct saa7134_dev *dev = fh->dev; | ||
2220 | int res = saa7134_resource(file); | 1966 | int res = saa7134_resource(file); |
2221 | 1967 | ||
2222 | if (!res_get(dev, fh, res)) | 1968 | if (!res_get(dev, priv, res)) |
2223 | return -EBUSY; | 1969 | return -EBUSY; |
2224 | 1970 | ||
2225 | /* The SAA7134 has a 1K FIFO; the datasheet suggests that when | 1971 | /* The SAA7134 has a 1K FIFO; the datasheet suggests that when |
@@ -2229,36 +1975,37 @@ static int saa7134_streamon(struct file *file, void *priv, | |||
2229 | * Unfortunately, I lack register-level documentation to check the | 1975 | * Unfortunately, I lack register-level documentation to check the |
2230 | * Linux FIFO setup and confirm the perfect value. | 1976 | * Linux FIFO setup and confirm the perfect value. |
2231 | */ | 1977 | */ |
2232 | pm_qos_add_request(&dev->qos_request, | 1978 | if (res != RESOURCE_EMPRESS) |
2233 | PM_QOS_CPU_DMA_LATENCY, | 1979 | pm_qos_add_request(&dev->qos_request, |
2234 | 20); | 1980 | PM_QOS_CPU_DMA_LATENCY, 20); |
2235 | 1981 | ||
2236 | return videobuf_streamon(saa7134_queue(file)); | 1982 | return videobuf_streamon(saa7134_queue(file)); |
2237 | } | 1983 | } |
1984 | EXPORT_SYMBOL_GPL(saa7134_streamon); | ||
2238 | 1985 | ||
2239 | static int saa7134_streamoff(struct file *file, void *priv, | 1986 | int saa7134_streamoff(struct file *file, void *priv, |
2240 | enum v4l2_buf_type type) | 1987 | enum v4l2_buf_type type) |
2241 | { | 1988 | { |
1989 | struct saa7134_dev *dev = video_drvdata(file); | ||
2242 | int err; | 1990 | int err; |
2243 | struct saa7134_fh *fh = priv; | ||
2244 | struct saa7134_dev *dev = fh->dev; | ||
2245 | int res = saa7134_resource(file); | 1991 | int res = saa7134_resource(file); |
2246 | 1992 | ||
2247 | pm_qos_remove_request(&dev->qos_request); | 1993 | if (res != RESOURCE_EMPRESS) |
1994 | pm_qos_remove_request(&dev->qos_request); | ||
2248 | 1995 | ||
2249 | err = videobuf_streamoff(saa7134_queue(file)); | 1996 | err = videobuf_streamoff(saa7134_queue(file)); |
2250 | if (err < 0) | 1997 | if (err < 0) |
2251 | return err; | 1998 | return err; |
2252 | res_free(dev, fh, res); | 1999 | res_free(dev, priv, res); |
2253 | return 0; | 2000 | return 0; |
2254 | } | 2001 | } |
2002 | EXPORT_SYMBOL_GPL(saa7134_streamoff); | ||
2255 | 2003 | ||
2256 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 2004 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
2257 | static int vidioc_g_register (struct file *file, void *priv, | 2005 | static int vidioc_g_register (struct file *file, void *priv, |
2258 | struct v4l2_dbg_register *reg) | 2006 | struct v4l2_dbg_register *reg) |
2259 | { | 2007 | { |
2260 | struct saa7134_fh *fh = priv; | 2008 | struct saa7134_dev *dev = video_drvdata(file); |
2261 | struct saa7134_dev *dev = fh->dev; | ||
2262 | 2009 | ||
2263 | reg->val = saa_readb(reg->reg & 0xffffff); | 2010 | reg->val = saa_readb(reg->reg & 0xffffff); |
2264 | reg->size = 1; | 2011 | reg->size = 1; |
@@ -2268,8 +2015,7 @@ static int vidioc_g_register (struct file *file, void *priv, | |||
2268 | static int vidioc_s_register (struct file *file, void *priv, | 2015 | static int vidioc_s_register (struct file *file, void *priv, |
2269 | const struct v4l2_dbg_register *reg) | 2016 | const struct v4l2_dbg_register *reg) |
2270 | { | 2017 | { |
2271 | struct saa7134_fh *fh = priv; | 2018 | struct saa7134_dev *dev = video_drvdata(file); |
2272 | struct saa7134_dev *dev = fh->dev; | ||
2273 | 2019 | ||
2274 | saa_writeb(reg->reg & 0xffffff, reg->val); | 2020 | saa_writeb(reg->reg & 0xffffff, reg->val); |
2275 | return 0; | 2021 | return 0; |
@@ -2279,8 +2025,7 @@ static int vidioc_s_register (struct file *file, void *priv, | |||
2279 | static int radio_g_tuner(struct file *file, void *priv, | 2025 | static int radio_g_tuner(struct file *file, void *priv, |
2280 | struct v4l2_tuner *t) | 2026 | struct v4l2_tuner *t) |
2281 | { | 2027 | { |
2282 | struct saa7134_fh *fh = file->private_data; | 2028 | struct saa7134_dev *dev = video_drvdata(file); |
2283 | struct saa7134_dev *dev = fh->dev; | ||
2284 | 2029 | ||
2285 | if (0 != t->index) | 2030 | if (0 != t->index) |
2286 | return -EINVAL; | 2031 | return -EINVAL; |
@@ -2299,8 +2044,7 @@ static int radio_g_tuner(struct file *file, void *priv, | |||
2299 | static int radio_s_tuner(struct file *file, void *priv, | 2044 | static int radio_s_tuner(struct file *file, void *priv, |
2300 | const struct v4l2_tuner *t) | 2045 | const struct v4l2_tuner *t) |
2301 | { | 2046 | { |
2302 | struct saa7134_fh *fh = file->private_data; | 2047 | struct saa7134_dev *dev = video_drvdata(file); |
2303 | struct saa7134_dev *dev = fh->dev; | ||
2304 | 2048 | ||
2305 | if (0 != t->index) | 2049 | if (0 != t->index) |
2306 | return -EINVAL; | 2050 | return -EINVAL; |
@@ -2309,50 +2053,6 @@ static int radio_s_tuner(struct file *file, void *priv, | |||
2309 | return 0; | 2053 | return 0; |
2310 | } | 2054 | } |
2311 | 2055 | ||
2312 | static int radio_enum_input(struct file *file, void *priv, | ||
2313 | struct v4l2_input *i) | ||
2314 | { | ||
2315 | if (i->index != 0) | ||
2316 | return -EINVAL; | ||
2317 | |||
2318 | strcpy(i->name, "Radio"); | ||
2319 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
2320 | |||
2321 | return 0; | ||
2322 | } | ||
2323 | |||
2324 | static int radio_g_input(struct file *filp, void *priv, unsigned int *i) | ||
2325 | { | ||
2326 | *i = 0; | ||
2327 | return 0; | ||
2328 | } | ||
2329 | |||
2330 | static int radio_s_input(struct file *filp, void *priv, unsigned int i) | ||
2331 | { | ||
2332 | return 0; | ||
2333 | } | ||
2334 | |||
2335 | static int radio_s_std(struct file *file, void *fh, v4l2_std_id norm) | ||
2336 | { | ||
2337 | return 0; | ||
2338 | } | ||
2339 | |||
2340 | static int radio_queryctrl(struct file *file, void *priv, | ||
2341 | struct v4l2_queryctrl *c) | ||
2342 | { | ||
2343 | const struct v4l2_queryctrl *ctrl; | ||
2344 | |||
2345 | if (c->id < V4L2_CID_BASE || | ||
2346 | c->id >= V4L2_CID_LASTP1) | ||
2347 | return -EINVAL; | ||
2348 | if (c->id == V4L2_CID_AUDIO_MUTE) { | ||
2349 | ctrl = ctrl_by_id(c->id); | ||
2350 | *c = *ctrl; | ||
2351 | } else | ||
2352 | *c = no_ctrl; | ||
2353 | return 0; | ||
2354 | } | ||
2355 | |||
2356 | static const struct v4l2_file_operations video_fops = | 2056 | static const struct v4l2_file_operations video_fops = |
2357 | { | 2057 | { |
2358 | .owner = THIS_MODULE, | 2058 | .owner = THIS_MODULE, |
@@ -2387,9 +2087,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
2387 | .vidioc_enum_input = saa7134_enum_input, | 2087 | .vidioc_enum_input = saa7134_enum_input, |
2388 | .vidioc_g_input = saa7134_g_input, | 2088 | .vidioc_g_input = saa7134_g_input, |
2389 | .vidioc_s_input = saa7134_s_input, | 2089 | .vidioc_s_input = saa7134_s_input, |
2390 | .vidioc_queryctrl = saa7134_queryctrl, | ||
2391 | .vidioc_g_ctrl = saa7134_g_ctrl, | ||
2392 | .vidioc_s_ctrl = saa7134_s_ctrl, | ||
2393 | .vidioc_streamon = saa7134_streamon, | 2090 | .vidioc_streamon = saa7134_streamon, |
2394 | .vidioc_streamoff = saa7134_streamoff, | 2091 | .vidioc_streamoff = saa7134_streamoff, |
2395 | .vidioc_g_tuner = saa7134_g_tuner, | 2092 | .vidioc_g_tuner = saa7134_g_tuner, |
@@ -2405,6 +2102,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
2405 | .vidioc_g_register = vidioc_g_register, | 2102 | .vidioc_g_register = vidioc_g_register, |
2406 | .vidioc_s_register = vidioc_s_register, | 2103 | .vidioc_s_register = vidioc_s_register, |
2407 | #endif | 2104 | #endif |
2105 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
2106 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
2107 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
2408 | }; | 2108 | }; |
2409 | 2109 | ||
2410 | static const struct v4l2_file_operations radio_fops = { | 2110 | static const struct v4l2_file_operations radio_fops = { |
@@ -2419,16 +2119,11 @@ static const struct v4l2_file_operations radio_fops = { | |||
2419 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { | 2119 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { |
2420 | .vidioc_querycap = saa7134_querycap, | 2120 | .vidioc_querycap = saa7134_querycap, |
2421 | .vidioc_g_tuner = radio_g_tuner, | 2121 | .vidioc_g_tuner = radio_g_tuner, |
2422 | .vidioc_enum_input = radio_enum_input, | ||
2423 | .vidioc_s_tuner = radio_s_tuner, | 2122 | .vidioc_s_tuner = radio_s_tuner, |
2424 | .vidioc_s_input = radio_s_input, | ||
2425 | .vidioc_s_std = radio_s_std, | ||
2426 | .vidioc_queryctrl = radio_queryctrl, | ||
2427 | .vidioc_g_input = radio_g_input, | ||
2428 | .vidioc_g_ctrl = saa7134_g_ctrl, | ||
2429 | .vidioc_s_ctrl = saa7134_s_ctrl, | ||
2430 | .vidioc_g_frequency = saa7134_g_frequency, | 2123 | .vidioc_g_frequency = saa7134_g_frequency, |
2431 | .vidioc_s_frequency = saa7134_s_frequency, | 2124 | .vidioc_s_frequency = saa7134_s_frequency, |
2125 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
2126 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
2432 | }; | 2127 | }; |
2433 | 2128 | ||
2434 | /* ----------------------------------------------------------- */ | 2129 | /* ----------------------------------------------------------- */ |
@@ -2447,8 +2142,55 @@ struct video_device saa7134_radio_template = { | |||
2447 | .ioctl_ops = &radio_ioctl_ops, | 2142 | .ioctl_ops = &radio_ioctl_ops, |
2448 | }; | 2143 | }; |
2449 | 2144 | ||
2145 | static const struct v4l2_ctrl_ops saa7134_ctrl_ops = { | ||
2146 | .s_ctrl = saa7134_s_ctrl, | ||
2147 | }; | ||
2148 | |||
2149 | static const struct v4l2_ctrl_config saa7134_ctrl_invert = { | ||
2150 | .ops = &saa7134_ctrl_ops, | ||
2151 | .id = V4L2_CID_PRIVATE_INVERT, | ||
2152 | .name = "Invert", | ||
2153 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
2154 | .min = 0, | ||
2155 | .max = 1, | ||
2156 | .step = 1, | ||
2157 | }; | ||
2158 | |||
2159 | static const struct v4l2_ctrl_config saa7134_ctrl_y_odd = { | ||
2160 | .ops = &saa7134_ctrl_ops, | ||
2161 | .id = V4L2_CID_PRIVATE_Y_ODD, | ||
2162 | .name = "Y Offset Odd Field", | ||
2163 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
2164 | .min = 0, | ||
2165 | .max = 128, | ||
2166 | .step = 1, | ||
2167 | }; | ||
2168 | |||
2169 | static const struct v4l2_ctrl_config saa7134_ctrl_y_even = { | ||
2170 | .ops = &saa7134_ctrl_ops, | ||
2171 | .id = V4L2_CID_PRIVATE_Y_EVEN, | ||
2172 | .name = "Y Offset Even Field", | ||
2173 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
2174 | .min = 0, | ||
2175 | .max = 128, | ||
2176 | .step = 1, | ||
2177 | }; | ||
2178 | |||
2179 | static const struct v4l2_ctrl_config saa7134_ctrl_automute = { | ||
2180 | .ops = &saa7134_ctrl_ops, | ||
2181 | .id = V4L2_CID_PRIVATE_AUTOMUTE, | ||
2182 | .name = "Automute", | ||
2183 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
2184 | .min = 0, | ||
2185 | .max = 1, | ||
2186 | .step = 1, | ||
2187 | .def = 1, | ||
2188 | }; | ||
2189 | |||
2450 | int saa7134_video_init1(struct saa7134_dev *dev) | 2190 | int saa7134_video_init1(struct saa7134_dev *dev) |
2451 | { | 2191 | { |
2192 | struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; | ||
2193 | |||
2452 | /* sanitycheck insmod options */ | 2194 | /* sanitycheck insmod options */ |
2453 | if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) | 2195 | if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) |
2454 | gbuffers = 2; | 2196 | gbuffers = 2; |
@@ -2456,17 +2198,38 @@ int saa7134_video_init1(struct saa7134_dev *dev) | |||
2456 | gbufsize = gbufsize_max; | 2198 | gbufsize = gbufsize_max; |
2457 | gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; | 2199 | gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; |
2458 | 2200 | ||
2459 | /* put some sensible defaults into the data structures ... */ | 2201 | v4l2_ctrl_handler_init(hdl, 11); |
2460 | dev->ctl_bright = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value; | 2202 | v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops, |
2461 | dev->ctl_contrast = ctrl_by_id(V4L2_CID_CONTRAST)->default_value; | 2203 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); |
2462 | dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; | 2204 | v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops, |
2463 | dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; | 2205 | V4L2_CID_CONTRAST, 0, 127, 1, 68); |
2464 | dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; | 2206 | v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops, |
2465 | dev->ctl_mute = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; | 2207 | V4L2_CID_SATURATION, 0, 127, 1, 64); |
2466 | dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; | 2208 | v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops, |
2467 | dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; | 2209 | V4L2_CID_HUE, -128, 127, 1, 0); |
2468 | 2210 | v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops, | |
2469 | if (dev->tda9887_conf && dev->ctl_automute) | 2211 | V4L2_CID_HFLIP, 0, 1, 1, 0); |
2212 | v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops, | ||
2213 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); | ||
2214 | v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops, | ||
2215 | V4L2_CID_AUDIO_VOLUME, -15, 15, 1, 0); | ||
2216 | v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_invert, NULL); | ||
2217 | v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_odd, NULL); | ||
2218 | v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_even, NULL); | ||
2219 | v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_automute, NULL); | ||
2220 | if (hdl->error) | ||
2221 | return hdl->error; | ||
2222 | if (card_has_radio(dev)) { | ||
2223 | hdl = &dev->radio_ctrl_handler; | ||
2224 | v4l2_ctrl_handler_init(hdl, 2); | ||
2225 | v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, | ||
2226 | v4l2_ctrl_radio_filter); | ||
2227 | if (hdl->error) | ||
2228 | return hdl->error; | ||
2229 | } | ||
2230 | dev->ctl_mute = 1; | ||
2231 | |||
2232 | if (dev->tda9887_conf && saa7134_ctrl_automute.def) | ||
2470 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | 2233 | dev->tda9887_conf |= TDA9887_AUTOMUTE; |
2471 | dev->automute = 0; | 2234 | dev->automute = 0; |
2472 | 2235 | ||
@@ -2489,9 +2252,34 @@ int saa7134_video_init1(struct saa7134_dev *dev) | |||
2489 | if (saa7134_boards[dev->board].video_out) | 2252 | if (saa7134_boards[dev->board].video_out) |
2490 | saa7134_videoport_init(dev); | 2253 | saa7134_videoport_init(dev); |
2491 | 2254 | ||
2255 | videobuf_queue_sg_init(&dev->cap, &video_qops, | ||
2256 | &dev->pci->dev, &dev->slock, | ||
2257 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
2258 | V4L2_FIELD_INTERLACED, | ||
2259 | sizeof(struct saa7134_buf), | ||
2260 | dev, NULL); | ||
2261 | videobuf_queue_sg_init(&dev->vbi, &saa7134_vbi_qops, | ||
2262 | &dev->pci->dev, &dev->slock, | ||
2263 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
2264 | V4L2_FIELD_SEQ_TB, | ||
2265 | sizeof(struct saa7134_buf), | ||
2266 | dev, NULL); | ||
2267 | saa7134_pgtable_alloc(dev->pci, &dev->pt_cap); | ||
2268 | saa7134_pgtable_alloc(dev->pci, &dev->pt_vbi); | ||
2269 | |||
2492 | return 0; | 2270 | return 0; |
2493 | } | 2271 | } |
2494 | 2272 | ||
2273 | void saa7134_video_fini(struct saa7134_dev *dev) | ||
2274 | { | ||
2275 | /* free stuff */ | ||
2276 | saa7134_pgtable_free(dev->pci, &dev->pt_cap); | ||
2277 | saa7134_pgtable_free(dev->pci, &dev->pt_vbi); | ||
2278 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
2279 | if (card_has_radio(dev)) | ||
2280 | v4l2_ctrl_handler_free(&dev->radio_ctrl_handler); | ||
2281 | } | ||
2282 | |||
2495 | int saa7134_videoport_init(struct saa7134_dev *dev) | 2283 | int saa7134_videoport_init(struct saa7134_dev *dev) |
2496 | { | 2284 | { |
2497 | /* enable video output */ | 2285 | /* enable video output */ |
@@ -2533,6 +2321,7 @@ int saa7134_video_init2(struct saa7134_dev *dev) | |||
2533 | /* init video hw */ | 2321 | /* init video hw */ |
2534 | set_tvnorm(dev,&tvnorms[0]); | 2322 | set_tvnorm(dev,&tvnorms[0]); |
2535 | video_mux(dev,0); | 2323 | video_mux(dev,0); |
2324 | v4l2_ctrl_handler_setup(&dev->ctrl_handler); | ||
2536 | saa7134_tvaudio_setmute(dev); | 2325 | saa7134_tvaudio_setmute(dev); |
2537 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); | 2326 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); |
2538 | return 0; | 2327 | return 0; |
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 8d1453a48014..2474e848f2c0 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
38 | #include <media/v4l2-device.h> | 38 | #include <media/v4l2-device.h> |
39 | #include <media/v4l2-fh.h> | 39 | #include <media/v4l2-fh.h> |
40 | #include <media/v4l2-ctrls.h> | ||
40 | #include <media/tuner.h> | 41 | #include <media/tuner.h> |
41 | #include <media/rc-core.h> | 42 | #include <media/rc-core.h> |
42 | #include <media/ir-kbd-i2c.h> | 43 | #include <media/ir-kbd-i2c.h> |
@@ -410,12 +411,18 @@ struct saa7134_board { | |||
410 | #define card(dev) (saa7134_boards[dev->board]) | 411 | #define card(dev) (saa7134_boards[dev->board]) |
411 | #define card_in(dev,n) (saa7134_boards[dev->board].inputs[n]) | 412 | #define card_in(dev,n) (saa7134_boards[dev->board].inputs[n]) |
412 | 413 | ||
414 | #define V4L2_CID_PRIVATE_INVERT (V4L2_CID_USER_SAA7134_BASE + 0) | ||
415 | #define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_USER_SAA7134_BASE + 1) | ||
416 | #define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_USER_SAA7134_BASE + 2) | ||
417 | #define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_USER_SAA7134_BASE + 3) | ||
418 | |||
413 | /* ----------------------------------------------------------- */ | 419 | /* ----------------------------------------------------------- */ |
414 | /* device / file handle status */ | 420 | /* device / file handle status */ |
415 | 421 | ||
416 | #define RESOURCE_OVERLAY 1 | 422 | #define RESOURCE_OVERLAY 1 |
417 | #define RESOURCE_VIDEO 2 | 423 | #define RESOURCE_VIDEO 2 |
418 | #define RESOURCE_VBI 4 | 424 | #define RESOURCE_VBI 4 |
425 | #define RESOURCE_EMPRESS 8 | ||
419 | 426 | ||
420 | #define INTERLACE_AUTO 0 | 427 | #define INTERLACE_AUTO 0 |
421 | #define INTERLACE_ON 1 | 428 | #define INTERLACE_ON 1 |
@@ -470,16 +477,8 @@ struct saa7134_dmaqueue { | |||
470 | /* video filehandle status */ | 477 | /* video filehandle status */ |
471 | struct saa7134_fh { | 478 | struct saa7134_fh { |
472 | struct v4l2_fh fh; | 479 | struct v4l2_fh fh; |
473 | struct saa7134_dev *dev; | 480 | bool is_empress; |
474 | unsigned int resources; | 481 | unsigned int resources; |
475 | |||
476 | /* video capture */ | ||
477 | struct videobuf_queue cap; | ||
478 | struct saa7134_pgtable pt_cap; | ||
479 | |||
480 | /* vbi capture */ | ||
481 | struct videobuf_queue vbi; | ||
482 | struct saa7134_pgtable pt_vbi; | ||
483 | }; | 482 | }; |
484 | 483 | ||
485 | /* dmasound dsp status */ | 484 | /* dmasound dsp status */ |
@@ -589,7 +588,11 @@ struct saa7134_dev { | |||
589 | 588 | ||
590 | /* video+ts+vbi capture */ | 589 | /* video+ts+vbi capture */ |
591 | struct saa7134_dmaqueue video_q; | 590 | struct saa7134_dmaqueue video_q; |
591 | struct videobuf_queue cap; | ||
592 | struct saa7134_pgtable pt_cap; | ||
592 | struct saa7134_dmaqueue vbi_q; | 593 | struct saa7134_dmaqueue vbi_q; |
594 | struct videobuf_queue vbi; | ||
595 | struct saa7134_pgtable pt_vbi; | ||
593 | unsigned int video_fieldcount; | 596 | unsigned int video_fieldcount; |
594 | unsigned int vbi_fieldcount; | 597 | unsigned int vbi_fieldcount; |
595 | struct saa7134_format *fmt; | 598 | struct saa7134_format *fmt; |
@@ -599,6 +602,7 @@ struct saa7134_dev { | |||
599 | /* various v4l controls */ | 602 | /* various v4l controls */ |
600 | struct saa7134_tvnorm *tvnorm; /* video */ | 603 | struct saa7134_tvnorm *tvnorm; /* video */ |
601 | struct saa7134_tvaudio *tvaudio; | 604 | struct saa7134_tvaudio *tvaudio; |
605 | struct v4l2_ctrl_handler ctrl_handler; | ||
602 | unsigned int ctl_input; | 606 | unsigned int ctl_input; |
603 | int ctl_bright; | 607 | int ctl_bright; |
604 | int ctl_contrast; | 608 | int ctl_contrast; |
@@ -626,6 +630,7 @@ struct saa7134_dev { | |||
626 | int last_carrier; | 630 | int last_carrier; |
627 | int nosignal; | 631 | int nosignal; |
628 | unsigned int insuspend; | 632 | unsigned int insuspend; |
633 | struct v4l2_ctrl_handler radio_ctrl_handler; | ||
629 | 634 | ||
630 | /* I2C keyboard data */ | 635 | /* I2C keyboard data */ |
631 | struct IR_i2c_init_data init_data; | 636 | struct IR_i2c_init_data init_data; |
@@ -638,10 +643,11 @@ struct saa7134_dev { | |||
638 | 643 | ||
639 | /* SAA7134_MPEG_EMPRESS only */ | 644 | /* SAA7134_MPEG_EMPRESS only */ |
640 | struct video_device *empress_dev; | 645 | struct video_device *empress_dev; |
646 | struct v4l2_subdev *empress_sd; | ||
641 | struct videobuf_queue empress_tsq; | 647 | struct videobuf_queue empress_tsq; |
642 | atomic_t empress_users; | ||
643 | struct work_struct empress_workqueue; | 648 | struct work_struct empress_workqueue; |
644 | int empress_started; | 649 | int empress_started; |
650 | struct v4l2_ctrl_handler empress_ctrl_handler; | ||
645 | 651 | ||
646 | #if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB) | 652 | #if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB) |
647 | /* SAA7134_MPEG_DVB only */ | 653 | /* SAA7134_MPEG_DVB only */ |
@@ -699,6 +705,16 @@ struct saa7134_dev { | |||
699 | _rc; \ | 705 | _rc; \ |
700 | }) | 706 | }) |
701 | 707 | ||
708 | static inline int res_check(struct saa7134_fh *fh, unsigned int bit) | ||
709 | { | ||
710 | return fh->resources & bit; | ||
711 | } | ||
712 | |||
713 | static inline int res_locked(struct saa7134_dev *dev, unsigned int bit) | ||
714 | { | ||
715 | return dev->resources & bit; | ||
716 | } | ||
717 | |||
702 | /* ----------------------------------------------------------- */ | 718 | /* ----------------------------------------------------------- */ |
703 | /* saa7134-core.c */ | 719 | /* saa7134-core.c */ |
704 | 720 | ||
@@ -761,10 +777,31 @@ extern unsigned int video_debug; | |||
761 | extern struct video_device saa7134_video_template; | 777 | extern struct video_device saa7134_video_template; |
762 | extern struct video_device saa7134_radio_template; | 778 | extern struct video_device saa7134_radio_template; |
763 | 779 | ||
764 | int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); | 780 | int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id); |
765 | int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); | 781 | int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id); |
766 | int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); | 782 | int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i); |
767 | int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id); | 783 | int saa7134_g_input(struct file *file, void *priv, unsigned int *i); |
784 | int saa7134_s_input(struct file *file, void *priv, unsigned int i); | ||
785 | int saa7134_querycap(struct file *file, void *priv, | ||
786 | struct v4l2_capability *cap); | ||
787 | int saa7134_g_tuner(struct file *file, void *priv, | ||
788 | struct v4l2_tuner *t); | ||
789 | int saa7134_s_tuner(struct file *file, void *priv, | ||
790 | const struct v4l2_tuner *t); | ||
791 | int saa7134_g_frequency(struct file *file, void *priv, | ||
792 | struct v4l2_frequency *f); | ||
793 | int saa7134_s_frequency(struct file *file, void *priv, | ||
794 | const struct v4l2_frequency *f); | ||
795 | int saa7134_reqbufs(struct file *file, void *priv, | ||
796 | struct v4l2_requestbuffers *p); | ||
797 | int saa7134_querybuf(struct file *file, void *priv, | ||
798 | struct v4l2_buffer *b); | ||
799 | int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b); | ||
800 | int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b); | ||
801 | int saa7134_streamon(struct file *file, void *priv, | ||
802 | enum v4l2_buf_type type); | ||
803 | int saa7134_streamoff(struct file *file, void *priv, | ||
804 | enum v4l2_buf_type type); | ||
768 | 805 | ||
769 | int saa7134_videoport_init(struct saa7134_dev *dev); | 806 | int saa7134_videoport_init(struct saa7134_dev *dev); |
770 | void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); | 807 | void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); |
@@ -773,6 +810,7 @@ int saa7134_video_init1(struct saa7134_dev *dev); | |||
773 | int saa7134_video_init2(struct saa7134_dev *dev); | 810 | int saa7134_video_init2(struct saa7134_dev *dev); |
774 | void saa7134_irq_video_signalchange(struct saa7134_dev *dev); | 811 | void saa7134_irq_video_signalchange(struct saa7134_dev *dev); |
775 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); | 812 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); |
813 | void saa7134_video_fini(struct saa7134_dev *dev); | ||
776 | 814 | ||
777 | 815 | ||
778 | /* ----------------------------------------------------------- */ | 816 | /* ----------------------------------------------------------- */ |
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 77edc113e485..e5cfb6cfa18d 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c | |||
@@ -1303,7 +1303,7 @@ static int sta2x11_vip_resume(struct pci_dev *pdev) | |||
1303 | 1303 | ||
1304 | #endif | 1304 | #endif |
1305 | 1305 | ||
1306 | static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = { | 1306 | static const struct pci_device_id sta2x11_vip_pci_tbl[] = { |
1307 | {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)}, | 1307 | {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)}, |
1308 | {0,} | 1308 | {0,} |
1309 | }; | 1309 | }; |
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index d7f0249e4050..b2a4403940c5 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
@@ -36,7 +36,8 @@ source "drivers/media/platform/blackfin/Kconfig" | |||
36 | config VIDEO_SH_VOU | 36 | config VIDEO_SH_VOU |
37 | tristate "SuperH VOU video output driver" | 37 | tristate "SuperH VOU video output driver" |
38 | depends on MEDIA_CAMERA_SUPPORT | 38 | depends on MEDIA_CAMERA_SUPPORT |
39 | depends on VIDEO_DEV && ARCH_SHMOBILE && I2C | 39 | depends on VIDEO_DEV && I2C |
40 | depends on ARCH_SHMOBILE || COMPILE_TEST | ||
40 | select VIDEOBUF_DMA_CONTIG | 41 | select VIDEOBUF_DMA_CONTIG |
41 | help | 42 | help |
42 | Support for the Video Output Unit (VOU) on SuperH SoCs. | 43 | Support for the Video Output Unit (VOU) on SuperH SoCs. |
@@ -90,13 +91,6 @@ config VIDEO_M32R_AR_M64278 | |||
90 | To compile this driver as a module, choose M here: the | 91 | To compile this driver as a module, choose M here: the |
91 | module will be called arv. | 92 | module will be called arv. |
92 | 93 | ||
93 | config VIDEO_OMAP2 | ||
94 | tristate "OMAP2 Camera Capture Interface driver" | ||
95 | depends on VIDEO_DEV && ARCH_OMAP2 && VIDEO_V4L2_INT_DEVICE | ||
96 | select VIDEOBUF_DMA_SG | ||
97 | ---help--- | ||
98 | This is a v4l2 driver for the TI OMAP2 camera capture interface | ||
99 | |||
100 | config VIDEO_OMAP3 | 94 | config VIDEO_OMAP3 |
101 | tristate "OMAP 3 Camera support" | 95 | tristate "OMAP 3 Camera support" |
102 | depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 | 96 | depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 |
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 1348ba1faf92..e5269da91906 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile | |||
@@ -2,8 +2,6 @@ | |||
2 | # Makefile for the video capture/playback device drivers. | 2 | # Makefile for the video capture/playback device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o | ||
6 | |||
7 | obj-$(CONFIG_VIDEO_VINO) += indycam.o | 5 | obj-$(CONFIG_VIDEO_VINO) += indycam.o |
8 | obj-$(CONFIG_VIDEO_VINO) += vino.o | 6 | obj-$(CONFIG_VIDEO_VINO) += vino.o |
9 | 7 | ||
@@ -14,7 +12,6 @@ obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o | |||
14 | obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ | 12 | obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ |
15 | obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ | 13 | obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ |
16 | 14 | ||
17 | obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o | ||
18 | obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ | 15 | obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ |
19 | 16 | ||
20 | obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o | 17 | obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o |
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index eac472b5ae83..b02aba488826 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c | |||
@@ -347,7 +347,7 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
347 | /* If buffer queue is empty, return error */ | 347 | /* If buffer queue is empty, return error */ |
348 | if (list_empty(&layer->dma_queue)) { | 348 | if (list_empty(&layer->dma_queue)) { |
349 | v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); | 349 | v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); |
350 | return -EINVAL; | 350 | return -ENOBUFS; |
351 | } | 351 | } |
352 | /* Get the next frame from the buffer queue */ | 352 | /* Get the next frame from the buffer queue */ |
353 | layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, | 353 | layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, |
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 52ac5e6c8625..735ec47601a9 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c | |||
@@ -277,7 +277,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
277 | if (list_empty(&common->dma_queue)) { | 277 | if (list_empty(&common->dma_queue)) { |
278 | spin_unlock_irqrestore(&common->irqlock, flags); | 278 | spin_unlock_irqrestore(&common->irqlock, flags); |
279 | vpif_dbg(1, debug, "buffer queue is empty\n"); | 279 | vpif_dbg(1, debug, "buffer queue is empty\n"); |
280 | return -EIO; | 280 | return -ENOBUFS; |
281 | } | 281 | } |
282 | 282 | ||
283 | /* Get the next frame from the buffer queue */ | 283 | /* Get the next frame from the buffer queue */ |
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index c31bcf129a5d..9d115cdc6bdb 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c | |||
@@ -239,7 +239,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
239 | if (list_empty(&common->dma_queue)) { | 239 | if (list_empty(&common->dma_queue)) { |
240 | spin_unlock_irqrestore(&common->irqlock, flags); | 240 | spin_unlock_irqrestore(&common->irqlock, flags); |
241 | vpif_err("buffer queue is empty\n"); | 241 | vpif_err("buffer queue is empty\n"); |
242 | return -EIO; | 242 | return -ENOBUFS; |
243 | } | 243 | } |
244 | 244 | ||
245 | /* Get the next frame from the buffer queue */ | 245 | /* Get the next frame from the buffer queue */ |
diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index d2d3b4b61435..01ed1ecdff7e 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | 1 | ||
2 | config VIDEO_SAMSUNG_EXYNOS4_IS | 2 | config VIDEO_SAMSUNG_EXYNOS4_IS |
3 | bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" | 3 | bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" |
4 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PM_RUNTIME | 4 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
5 | depends on (PLAT_S5P || ARCH_EXYNOS) | 5 | depends on (PLAT_S5P || ARCH_EXYNOS) |
6 | help | 6 | help |
7 | Say Y here to enable camera host interface devices for | 7 | Say Y here to enable camera host interface devices for |
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index fb27ff7e1e07..8a712ca91d11 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c | |||
@@ -549,7 +549,7 @@ static int fimc_capture_release(struct file *file) | |||
549 | vc->streaming = false; | 549 | vc->streaming = false; |
550 | } | 550 | } |
551 | 551 | ||
552 | ret = vb2_fop_release(file); | 552 | ret = _vb2_fop_release(file, NULL); |
553 | 553 | ||
554 | if (close) { | 554 | if (close) { |
555 | clear_bit(ST_CAPT_BUSY, &fimc->state); | 555 | clear_bit(ST_CAPT_BUSY, &fimc->state); |
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index f7915695c907..a7dfd07e8389 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c | |||
@@ -998,36 +998,39 @@ static int fimc_probe(struct platform_device *pdev) | |||
998 | 998 | ||
999 | ret = devm_request_irq(dev, res->start, fimc_irq_handler, | 999 | ret = devm_request_irq(dev, res->start, fimc_irq_handler, |
1000 | 0, dev_name(dev), fimc); | 1000 | 0, dev_name(dev), fimc); |
1001 | if (ret) { | 1001 | if (ret < 0) { |
1002 | dev_err(dev, "failed to install irq (%d)\n", ret); | 1002 | dev_err(dev, "failed to install irq (%d)\n", ret); |
1003 | goto err_clk; | 1003 | goto err_sclk; |
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | ret = fimc_initialize_capture_subdev(fimc); | 1006 | ret = fimc_initialize_capture_subdev(fimc); |
1007 | if (ret) | 1007 | if (ret < 0) |
1008 | goto err_clk; | 1008 | goto err_sclk; |
1009 | 1009 | ||
1010 | platform_set_drvdata(pdev, fimc); | 1010 | platform_set_drvdata(pdev, fimc); |
1011 | pm_runtime_enable(dev); | 1011 | pm_runtime_enable(dev); |
1012 | ret = pm_runtime_get_sync(dev); | 1012 | |
1013 | if (ret < 0) | 1013 | if (!pm_runtime_enabled(dev)) { |
1014 | goto err_sd; | 1014 | ret = clk_enable(fimc->clock[CLK_GATE]); |
1015 | if (ret < 0) | ||
1016 | goto err_sd; | ||
1017 | } | ||
1018 | |||
1015 | /* Initialize contiguous memory allocator */ | 1019 | /* Initialize contiguous memory allocator */ |
1016 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 1020 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); |
1017 | if (IS_ERR(fimc->alloc_ctx)) { | 1021 | if (IS_ERR(fimc->alloc_ctx)) { |
1018 | ret = PTR_ERR(fimc->alloc_ctx); | 1022 | ret = PTR_ERR(fimc->alloc_ctx); |
1019 | goto err_pm; | 1023 | goto err_gclk; |
1020 | } | 1024 | } |
1021 | 1025 | ||
1022 | dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); | 1026 | dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); |
1023 | |||
1024 | pm_runtime_put(dev); | ||
1025 | return 0; | 1027 | return 0; |
1026 | err_pm: | 1028 | |
1027 | pm_runtime_put(dev); | 1029 | err_gclk: |
1030 | clk_disable(fimc->clock[CLK_GATE]); | ||
1028 | err_sd: | 1031 | err_sd: |
1029 | fimc_unregister_capture_subdev(fimc); | 1032 | fimc_unregister_capture_subdev(fimc); |
1030 | err_clk: | 1033 | err_sclk: |
1031 | clk_disable(fimc->clock[CLK_BUS]); | 1034 | clk_disable(fimc->clock[CLK_BUS]); |
1032 | fimc_clk_put(fimc); | 1035 | fimc_clk_put(fimc); |
1033 | return ret; | 1036 | return ret; |
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 3d376faec777..1790fb4e32ea 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h | |||
@@ -481,7 +481,6 @@ struct fimc_ctrls { | |||
481 | * @flags: additional flags for image conversion | 481 | * @flags: additional flags for image conversion |
482 | * @state: flags to keep track of user configuration | 482 | * @state: flags to keep track of user configuration |
483 | * @fimc_dev: the FIMC device this context applies to | 483 | * @fimc_dev: the FIMC device this context applies to |
484 | * @m2m_ctx: memory-to-memory device context | ||
485 | * @fh: v4l2 file handle | 484 | * @fh: v4l2 file handle |
486 | * @ctrls: v4l2 controls structure | 485 | * @ctrls: v4l2 controls structure |
487 | */ | 486 | */ |
@@ -502,7 +501,6 @@ struct fimc_ctx { | |||
502 | u32 flags; | 501 | u32 flags; |
503 | u32 state; | 502 | u32 state; |
504 | struct fimc_dev *fimc_dev; | 503 | struct fimc_dev *fimc_dev; |
505 | struct v4l2_m2m_ctx *m2m_ctx; | ||
506 | struct v4l2_fh fh; | 504 | struct v4l2_fh fh; |
507 | struct fimc_ctrls ctrls; | 505 | struct fimc_ctrls ctrls; |
508 | }; | 506 | }; |
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index f758e2694fa3..2628733c4e10 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c | |||
@@ -33,47 +33,23 @@ void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is) | |||
33 | mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0); | 33 | mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0); |
34 | } | 34 | } |
35 | 35 | ||
36 | int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is) | ||
37 | { | ||
38 | unsigned int timeout = 2000; | ||
39 | u32 cfg, status; | ||
40 | |||
41 | cfg = mcuctl_read(is, MCUCTL_REG_INTSR0); | ||
42 | status = INTSR0_GET_INTSD(0, cfg); | ||
43 | |||
44 | while (status) { | ||
45 | cfg = mcuctl_read(is, MCUCTL_REG_INTSR0); | ||
46 | status = INTSR0_GET_INTSD(0, cfg); | ||
47 | if (timeout == 0) { | ||
48 | dev_warn(&is->pdev->dev, "%s timeout\n", | ||
49 | __func__); | ||
50 | return -ETIME; | ||
51 | } | ||
52 | timeout--; | ||
53 | udelay(1); | ||
54 | } | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is) | 36 | int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is) |
59 | { | 37 | { |
60 | unsigned int timeout = 2000; | 38 | unsigned int timeout = 2000; |
61 | u32 cfg, status; | 39 | u32 cfg, status; |
62 | 40 | ||
63 | cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0); | 41 | do { |
64 | status = INTMSR0_GET_INTMSD(0, cfg); | ||
65 | |||
66 | while (status) { | ||
67 | cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0); | 42 | cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0); |
68 | status = INTMSR0_GET_INTMSD(0, cfg); | 43 | status = INTMSR0_GET_INTMSD(0, cfg); |
69 | if (timeout == 0) { | 44 | |
45 | if (--timeout == 0) { | ||
70 | dev_warn(&is->pdev->dev, "%s timeout\n", | 46 | dev_warn(&is->pdev->dev, "%s timeout\n", |
71 | __func__); | 47 | __func__); |
72 | return -ETIME; | 48 | return -ETIMEDOUT; |
73 | } | 49 | } |
74 | timeout--; | ||
75 | udelay(1); | 50 | udelay(1); |
76 | } | 51 | } while (status != 0); |
52 | |||
77 | return 0; | 53 | return 0; |
78 | } | 54 | } |
79 | 55 | ||
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.h b/drivers/media/platform/exynos4-is/fimc-is-regs.h index 5fa2fda46742..1d9d4ffc6ad5 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.h +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.h | |||
@@ -145,7 +145,6 @@ void fimc_is_fw_clear_irq2(struct fimc_is *is); | |||
145 | int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num); | 145 | int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num); |
146 | 146 | ||
147 | void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is); | 147 | void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is); |
148 | int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is); | ||
149 | int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is); | 148 | int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is); |
150 | void fimc_is_hw_set_sensor_num(struct fimc_is *is); | 149 | void fimc_is_hw_set_sensor_num(struct fimc_is *is); |
151 | void fimc_is_hw_stream_on(struct fimc_is *is); | 150 | void fimc_is_hw_stream_on(struct fimc_is *is); |
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 9770fa98d6a1..13a4228952e3 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c | |||
@@ -781,6 +781,9 @@ static int fimc_is_debugfs_create(struct fimc_is *is) | |||
781 | return is->debugfs_entry == NULL ? -EIO : 0; | 781 | return is->debugfs_entry == NULL ? -EIO : 0; |
782 | } | 782 | } |
783 | 783 | ||
784 | static int fimc_is_runtime_resume(struct device *dev); | ||
785 | static int fimc_is_runtime_suspend(struct device *dev); | ||
786 | |||
784 | static int fimc_is_probe(struct platform_device *pdev) | 787 | static int fimc_is_probe(struct platform_device *pdev) |
785 | { | 788 | { |
786 | struct device *dev = &pdev->dev; | 789 | struct device *dev = &pdev->dev; |
@@ -835,14 +838,20 @@ static int fimc_is_probe(struct platform_device *pdev) | |||
835 | } | 838 | } |
836 | pm_runtime_enable(dev); | 839 | pm_runtime_enable(dev); |
837 | 840 | ||
841 | if (!pm_runtime_enabled(dev)) { | ||
842 | ret = fimc_is_runtime_resume(dev); | ||
843 | if (ret < 0) | ||
844 | goto err_irq; | ||
845 | } | ||
846 | |||
838 | ret = pm_runtime_get_sync(dev); | 847 | ret = pm_runtime_get_sync(dev); |
839 | if (ret < 0) | 848 | if (ret < 0) |
840 | goto err_irq; | 849 | goto err_pm; |
841 | 850 | ||
842 | is->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 851 | is->alloc_ctx = vb2_dma_contig_init_ctx(dev); |
843 | if (IS_ERR(is->alloc_ctx)) { | 852 | if (IS_ERR(is->alloc_ctx)) { |
844 | ret = PTR_ERR(is->alloc_ctx); | 853 | ret = PTR_ERR(is->alloc_ctx); |
845 | goto err_irq; | 854 | goto err_pm; |
846 | } | 855 | } |
847 | /* | 856 | /* |
848 | * Register FIMC-IS V4L2 subdevs to this driver. The video nodes | 857 | * Register FIMC-IS V4L2 subdevs to this driver. The video nodes |
@@ -867,10 +876,13 @@ static int fimc_is_probe(struct platform_device *pdev) | |||
867 | 876 | ||
868 | err_dfs: | 877 | err_dfs: |
869 | fimc_is_debugfs_remove(is); | 878 | fimc_is_debugfs_remove(is); |
870 | err_vb: | ||
871 | vb2_dma_contig_cleanup_ctx(is->alloc_ctx); | ||
872 | err_sd: | 879 | err_sd: |
873 | fimc_is_unregister_subdevs(is); | 880 | fimc_is_unregister_subdevs(is); |
881 | err_vb: | ||
882 | vb2_dma_contig_cleanup_ctx(is->alloc_ctx); | ||
883 | err_pm: | ||
884 | if (!pm_runtime_enabled(dev)) | ||
885 | fimc_is_runtime_suspend(dev); | ||
874 | err_irq: | 886 | err_irq: |
875 | free_irq(is->irq, is); | 887 | free_irq(is->irq, is); |
876 | err_clk: | 888 | err_clk: |
@@ -919,10 +931,13 @@ static int fimc_is_suspend(struct device *dev) | |||
919 | 931 | ||
920 | static int fimc_is_remove(struct platform_device *pdev) | 932 | static int fimc_is_remove(struct platform_device *pdev) |
921 | { | 933 | { |
922 | struct fimc_is *is = platform_get_drvdata(pdev); | 934 | struct device *dev = &pdev->dev; |
935 | struct fimc_is *is = dev_get_drvdata(dev); | ||
923 | 936 | ||
924 | pm_runtime_disable(&pdev->dev); | 937 | pm_runtime_disable(dev); |
925 | pm_runtime_set_suspended(&pdev->dev); | 938 | pm_runtime_set_suspended(dev); |
939 | if (!pm_runtime_status_suspended(dev)) | ||
940 | fimc_is_runtime_suspend(dev); | ||
926 | free_irq(is->irq, is); | 941 | free_irq(is->irq, is); |
927 | fimc_is_unregister_subdevs(is); | 942 | fimc_is_unregister_subdevs(is); |
928 | vb2_dma_contig_cleanup_ctx(is->alloc_ctx); | 943 | vb2_dma_contig_cleanup_ctx(is->alloc_ctx); |
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index 72a343e3b5e8..d0dc7ee04452 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c | |||
@@ -133,7 +133,7 @@ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) | |||
133 | int i = ARRAY_SIZE(src_pixfmt_map); | 133 | int i = ARRAY_SIZE(src_pixfmt_map); |
134 | u32 cfg; | 134 | u32 cfg; |
135 | 135 | ||
136 | while (--i >= 0) { | 136 | while (--i) { |
137 | if (src_pixfmt_map[i][0] == pixelcode) | 137 | if (src_pixfmt_map[i][0] == pixelcode) |
138 | break; | 138 | break; |
139 | } | 139 | } |
@@ -240,7 +240,7 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) | |||
240 | u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); | 240 | u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); |
241 | int i = ARRAY_SIZE(pixcode); | 241 | int i = ARRAY_SIZE(pixcode); |
242 | 242 | ||
243 | while (--i >= 0) | 243 | while (--i) |
244 | if (pixcode[i][0] == f->fmt->mbus_code) | 244 | if (pixcode[i][0] == f->fmt->mbus_code) |
245 | break; | 245 | break; |
246 | cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; | 246 | cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; |
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index e5798f70d149..1234734bccf4 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c | |||
@@ -546,7 +546,7 @@ static int fimc_lite_release(struct file *file) | |||
546 | mutex_unlock(&entity->parent->graph_mutex); | 546 | mutex_unlock(&entity->parent->graph_mutex); |
547 | } | 547 | } |
548 | 548 | ||
549 | vb2_fop_release(file); | 549 | _vb2_fop_release(file, NULL); |
550 | pm_runtime_put(&fimc->pdev->dev); | 550 | pm_runtime_put(&fimc->pdev->dev); |
551 | clear_bit(ST_FLITE_SUSPENDED, &fimc->state); | 551 | clear_bit(ST_FLITE_SUSPENDED, &fimc->state); |
552 | 552 | ||
@@ -1549,38 +1549,40 @@ static int fimc_lite_probe(struct platform_device *pdev) | |||
1549 | 0, dev_name(dev), fimc); | 1549 | 0, dev_name(dev), fimc); |
1550 | if (ret) { | 1550 | if (ret) { |
1551 | dev_err(dev, "Failed to install irq (%d)\n", ret); | 1551 | dev_err(dev, "Failed to install irq (%d)\n", ret); |
1552 | goto err_clk; | 1552 | goto err_clk_put; |
1553 | } | 1553 | } |
1554 | 1554 | ||
1555 | /* The video node will be created within the subdev's registered() op */ | 1555 | /* The video node will be created within the subdev's registered() op */ |
1556 | ret = fimc_lite_create_capture_subdev(fimc); | 1556 | ret = fimc_lite_create_capture_subdev(fimc); |
1557 | if (ret) | 1557 | if (ret) |
1558 | goto err_clk; | 1558 | goto err_clk_put; |
1559 | 1559 | ||
1560 | platform_set_drvdata(pdev, fimc); | 1560 | platform_set_drvdata(pdev, fimc); |
1561 | pm_runtime_enable(dev); | 1561 | pm_runtime_enable(dev); |
1562 | ret = pm_runtime_get_sync(dev); | 1562 | |
1563 | if (ret < 0) | 1563 | if (!pm_runtime_enabled(dev)) { |
1564 | goto err_sd; | 1564 | ret = clk_enable(fimc->clock); |
1565 | if (ret < 0) | ||
1566 | goto err_clk_put; | ||
1567 | } | ||
1565 | 1568 | ||
1566 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 1569 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); |
1567 | if (IS_ERR(fimc->alloc_ctx)) { | 1570 | if (IS_ERR(fimc->alloc_ctx)) { |
1568 | ret = PTR_ERR(fimc->alloc_ctx); | 1571 | ret = PTR_ERR(fimc->alloc_ctx); |
1569 | goto err_pm; | 1572 | goto err_clk_dis; |
1570 | } | 1573 | } |
1571 | 1574 | ||
1572 | pm_runtime_put(dev); | ||
1573 | |||
1574 | fimc_lite_set_default_config(fimc); | 1575 | fimc_lite_set_default_config(fimc); |
1575 | 1576 | ||
1576 | dev_dbg(dev, "FIMC-LITE.%d registered successfully\n", | 1577 | dev_dbg(dev, "FIMC-LITE.%d registered successfully\n", |
1577 | fimc->index); | 1578 | fimc->index); |
1578 | return 0; | 1579 | return 0; |
1579 | err_pm: | 1580 | |
1580 | pm_runtime_put(dev); | 1581 | err_clk_dis: |
1582 | clk_disable(fimc->clock); | ||
1581 | err_sd: | 1583 | err_sd: |
1582 | fimc_lite_unregister_capture_subdev(fimc); | 1584 | fimc_lite_unregister_capture_subdev(fimc); |
1583 | err_clk: | 1585 | err_clk_put: |
1584 | fimc_lite_clk_put(fimc); | 1586 | fimc_lite_clk_put(fimc); |
1585 | return ret; | 1587 | return ret; |
1586 | } | 1588 | } |
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 8d33b68c76ba..9da95bd14820 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c | |||
@@ -44,17 +44,17 @@ void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) | |||
44 | { | 44 | { |
45 | struct vb2_buffer *src_vb, *dst_vb; | 45 | struct vb2_buffer *src_vb, *dst_vb; |
46 | 46 | ||
47 | if (!ctx || !ctx->m2m_ctx) | 47 | if (!ctx || !ctx->fh.m2m_ctx) |
48 | return; | 48 | return; |
49 | 49 | ||
50 | src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | 50 | src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
51 | dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | 51 | dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); |
52 | 52 | ||
53 | if (src_vb && dst_vb) { | 53 | if (src_vb && dst_vb) { |
54 | v4l2_m2m_buf_done(src_vb, vb_state); | 54 | v4l2_m2m_buf_done(src_vb, vb_state); |
55 | v4l2_m2m_buf_done(dst_vb, vb_state); | 55 | v4l2_m2m_buf_done(dst_vb, vb_state); |
56 | v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, | 56 | v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, |
57 | ctx->m2m_ctx); | 57 | ctx->fh.m2m_ctx); |
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
@@ -123,12 +123,12 @@ static void fimc_device_run(void *priv) | |||
123 | fimc_prepare_dma_offset(ctx, df); | 123 | fimc_prepare_dma_offset(ctx, df); |
124 | } | 124 | } |
125 | 125 | ||
126 | src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); | 126 | src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
127 | ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr); | 127 | ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr); |
128 | if (ret) | 128 | if (ret) |
129 | goto dma_unlock; | 129 | goto dma_unlock; |
130 | 130 | ||
131 | dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); | 131 | dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
132 | ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr); | 132 | ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr); |
133 | if (ret) | 133 | if (ret) |
134 | goto dma_unlock; | 134 | goto dma_unlock; |
@@ -219,31 +219,15 @@ static int fimc_buf_prepare(struct vb2_buffer *vb) | |||
219 | static void fimc_buf_queue(struct vb2_buffer *vb) | 219 | static void fimc_buf_queue(struct vb2_buffer *vb) |
220 | { | 220 | { |
221 | struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | 221 | struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
222 | 222 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); | |
223 | dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state); | ||
224 | |||
225 | if (ctx->m2m_ctx) | ||
226 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); | ||
227 | } | ||
228 | |||
229 | static void fimc_lock(struct vb2_queue *vq) | ||
230 | { | ||
231 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); | ||
232 | mutex_lock(&ctx->fimc_dev->lock); | ||
233 | } | ||
234 | |||
235 | static void fimc_unlock(struct vb2_queue *vq) | ||
236 | { | ||
237 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); | ||
238 | mutex_unlock(&ctx->fimc_dev->lock); | ||
239 | } | 223 | } |
240 | 224 | ||
241 | static struct vb2_ops fimc_qops = { | 225 | static struct vb2_ops fimc_qops = { |
242 | .queue_setup = fimc_queue_setup, | 226 | .queue_setup = fimc_queue_setup, |
243 | .buf_prepare = fimc_buf_prepare, | 227 | .buf_prepare = fimc_buf_prepare, |
244 | .buf_queue = fimc_buf_queue, | 228 | .buf_queue = fimc_buf_queue, |
245 | .wait_prepare = fimc_unlock, | 229 | .wait_prepare = vb2_ops_wait_prepare, |
246 | .wait_finish = fimc_lock, | 230 | .wait_finish = vb2_ops_wait_finish, |
247 | .stop_streaming = stop_streaming, | 231 | .stop_streaming = stop_streaming, |
248 | .start_streaming = start_streaming, | 232 | .start_streaming = start_streaming, |
249 | }; | 233 | }; |
@@ -385,7 +369,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, | |||
385 | if (ret) | 369 | if (ret) |
386 | return ret; | 370 | return ret; |
387 | 371 | ||
388 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | 372 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
389 | 373 | ||
390 | if (vb2_is_busy(vq)) { | 374 | if (vb2_is_busy(vq)) { |
391 | v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type); | 375 | v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type); |
@@ -410,56 +394,6 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, | |||
410 | return 0; | 394 | return 0; |
411 | } | 395 | } |
412 | 396 | ||
413 | static int fimc_m2m_reqbufs(struct file *file, void *fh, | ||
414 | struct v4l2_requestbuffers *reqbufs) | ||
415 | { | ||
416 | struct fimc_ctx *ctx = fh_to_ctx(fh); | ||
417 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | ||
418 | } | ||
419 | |||
420 | static int fimc_m2m_querybuf(struct file *file, void *fh, | ||
421 | struct v4l2_buffer *buf) | ||
422 | { | ||
423 | struct fimc_ctx *ctx = fh_to_ctx(fh); | ||
424 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); | ||
425 | } | ||
426 | |||
427 | static int fimc_m2m_qbuf(struct file *file, void *fh, | ||
428 | struct v4l2_buffer *buf) | ||
429 | { | ||
430 | struct fimc_ctx *ctx = fh_to_ctx(fh); | ||
431 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | ||
432 | } | ||
433 | |||
434 | static int fimc_m2m_dqbuf(struct file *file, void *fh, | ||
435 | struct v4l2_buffer *buf) | ||
436 | { | ||
437 | struct fimc_ctx *ctx = fh_to_ctx(fh); | ||
438 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | ||
439 | } | ||
440 | |||
441 | static int fimc_m2m_expbuf(struct file *file, void *fh, | ||
442 | struct v4l2_exportbuffer *eb) | ||
443 | { | ||
444 | struct fimc_ctx *ctx = fh_to_ctx(fh); | ||
445 | return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); | ||
446 | } | ||
447 | |||
448 | |||
449 | static int fimc_m2m_streamon(struct file *file, void *fh, | ||
450 | enum v4l2_buf_type type) | ||
451 | { | ||
452 | struct fimc_ctx *ctx = fh_to_ctx(fh); | ||
453 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); | ||
454 | } | ||
455 | |||
456 | static int fimc_m2m_streamoff(struct file *file, void *fh, | ||
457 | enum v4l2_buf_type type) | ||
458 | { | ||
459 | struct fimc_ctx *ctx = fh_to_ctx(fh); | ||
460 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | ||
461 | } | ||
462 | |||
463 | static int fimc_m2m_cropcap(struct file *file, void *fh, | 397 | static int fimc_m2m_cropcap(struct file *file, void *fh, |
464 | struct v4l2_cropcap *cr) | 398 | struct v4l2_cropcap *cr) |
465 | { | 399 | { |
@@ -598,13 +532,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { | |||
598 | .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane, | 532 | .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane, |
599 | .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, | 533 | .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, |
600 | .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, | 534 | .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, |
601 | .vidioc_reqbufs = fimc_m2m_reqbufs, | 535 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
602 | .vidioc_querybuf = fimc_m2m_querybuf, | 536 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
603 | .vidioc_qbuf = fimc_m2m_qbuf, | 537 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, |
604 | .vidioc_dqbuf = fimc_m2m_dqbuf, | 538 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, |
605 | .vidioc_expbuf = fimc_m2m_expbuf, | 539 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, |
606 | .vidioc_streamon = fimc_m2m_streamon, | 540 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
607 | .vidioc_streamoff = fimc_m2m_streamoff, | 541 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
608 | .vidioc_g_crop = fimc_m2m_g_crop, | 542 | .vidioc_g_crop = fimc_m2m_g_crop, |
609 | .vidioc_s_crop = fimc_m2m_s_crop, | 543 | .vidioc_s_crop = fimc_m2m_s_crop, |
610 | .vidioc_cropcap = fimc_m2m_cropcap | 544 | .vidioc_cropcap = fimc_m2m_cropcap |
@@ -624,6 +558,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, | |||
624 | src_vq->mem_ops = &vb2_dma_contig_memops; | 558 | src_vq->mem_ops = &vb2_dma_contig_memops; |
625 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 559 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
626 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 560 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
561 | src_vq->lock = &ctx->fimc_dev->lock; | ||
627 | 562 | ||
628 | ret = vb2_queue_init(src_vq); | 563 | ret = vb2_queue_init(src_vq); |
629 | if (ret) | 564 | if (ret) |
@@ -636,6 +571,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, | |||
636 | dst_vq->mem_ops = &vb2_dma_contig_memops; | 571 | dst_vq->mem_ops = &vb2_dma_contig_memops; |
637 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 572 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
638 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 573 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
574 | dst_vq->lock = &ctx->fimc_dev->lock; | ||
639 | 575 | ||
640 | return vb2_queue_init(dst_vq); | 576 | return vb2_queue_init(dst_vq); |
641 | } | 577 | } |
@@ -708,9 +644,9 @@ static int fimc_m2m_open(struct file *file) | |||
708 | ctx->out_path = FIMC_IO_DMA; | 644 | ctx->out_path = FIMC_IO_DMA; |
709 | ctx->scaler.enabled = 1; | 645 | ctx->scaler.enabled = 1; |
710 | 646 | ||
711 | ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); | 647 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); |
712 | if (IS_ERR(ctx->m2m_ctx)) { | 648 | if (IS_ERR(ctx->fh.m2m_ctx)) { |
713 | ret = PTR_ERR(ctx->m2m_ctx); | 649 | ret = PTR_ERR(ctx->fh.m2m_ctx); |
714 | goto error_c; | 650 | goto error_c; |
715 | } | 651 | } |
716 | 652 | ||
@@ -725,7 +661,7 @@ static int fimc_m2m_open(struct file *file) | |||
725 | return 0; | 661 | return 0; |
726 | 662 | ||
727 | error_m2m_ctx: | 663 | error_m2m_ctx: |
728 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | 664 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
729 | error_c: | 665 | error_c: |
730 | fimc_ctrls_delete(ctx); | 666 | fimc_ctrls_delete(ctx); |
731 | error_fh: | 667 | error_fh: |
@@ -747,7 +683,7 @@ static int fimc_m2m_release(struct file *file) | |||
747 | 683 | ||
748 | mutex_lock(&fimc->lock); | 684 | mutex_lock(&fimc->lock); |
749 | 685 | ||
750 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | 686 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
751 | fimc_ctrls_delete(ctx); | 687 | fimc_ctrls_delete(ctx); |
752 | v4l2_fh_del(&ctx->fh); | 688 | v4l2_fh_del(&ctx->fh); |
753 | v4l2_fh_exit(&ctx->fh); | 689 | v4l2_fh_exit(&ctx->fh); |
@@ -760,45 +696,13 @@ static int fimc_m2m_release(struct file *file) | |||
760 | return 0; | 696 | return 0; |
761 | } | 697 | } |
762 | 698 | ||
763 | static unsigned int fimc_m2m_poll(struct file *file, | ||
764 | struct poll_table_struct *wait) | ||
765 | { | ||
766 | struct fimc_ctx *ctx = fh_to_ctx(file->private_data); | ||
767 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
768 | int ret; | ||
769 | |||
770 | if (mutex_lock_interruptible(&fimc->lock)) | ||
771 | return -ERESTARTSYS; | ||
772 | |||
773 | ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | ||
774 | mutex_unlock(&fimc->lock); | ||
775 | |||
776 | return ret; | ||
777 | } | ||
778 | |||
779 | |||
780 | static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) | ||
781 | { | ||
782 | struct fimc_ctx *ctx = fh_to_ctx(file->private_data); | ||
783 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
784 | int ret; | ||
785 | |||
786 | if (mutex_lock_interruptible(&fimc->lock)) | ||
787 | return -ERESTARTSYS; | ||
788 | |||
789 | ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | ||
790 | mutex_unlock(&fimc->lock); | ||
791 | |||
792 | return ret; | ||
793 | } | ||
794 | |||
795 | static const struct v4l2_file_operations fimc_m2m_fops = { | 699 | static const struct v4l2_file_operations fimc_m2m_fops = { |
796 | .owner = THIS_MODULE, | 700 | .owner = THIS_MODULE, |
797 | .open = fimc_m2m_open, | 701 | .open = fimc_m2m_open, |
798 | .release = fimc_m2m_release, | 702 | .release = fimc_m2m_release, |
799 | .poll = fimc_m2m_poll, | 703 | .poll = v4l2_m2m_fop_poll, |
800 | .unlocked_ioctl = video_ioctl2, | 704 | .unlocked_ioctl = video_ioctl2, |
801 | .mmap = fimc_m2m_mmap, | 705 | .mmap = v4l2_m2m_fop_mmap, |
802 | }; | 706 | }; |
803 | 707 | ||
804 | static struct v4l2_m2m_ops m2m_ops = { | 708 | static struct v4l2_m2m_ops m2m_ops = { |
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 9fc2af6a0446..f3c3591fdc5d 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c | |||
@@ -91,7 +91,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); | |||
91 | #define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29) | 91 | #define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29) |
92 | #define S5PCSIS_INTSRC_ODD_AFTER (1 << 28) | 92 | #define S5PCSIS_INTSRC_ODD_AFTER (1 << 28) |
93 | #define S5PCSIS_INTSRC_ODD (0x3 << 28) | 93 | #define S5PCSIS_INTSRC_ODD (0x3 << 28) |
94 | #define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xff << 28) | 94 | #define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xf << 28) |
95 | #define S5PCSIS_INTSRC_FRAME_START (1 << 27) | 95 | #define S5PCSIS_INTSRC_FRAME_START (1 << 27) |
96 | #define S5PCSIS_INTSRC_FRAME_END (1 << 26) | 96 | #define S5PCSIS_INTSRC_FRAME_END (1 << 26) |
97 | #define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12) | 97 | #define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12) |
@@ -790,6 +790,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, | |||
790 | #define s5pcsis_parse_dt(pdev, state) (-ENOSYS) | 790 | #define s5pcsis_parse_dt(pdev, state) (-ENOSYS) |
791 | #endif | 791 | #endif |
792 | 792 | ||
793 | static int s5pcsis_pm_resume(struct device *dev, bool runtime); | ||
793 | static const struct of_device_id s5pcsis_of_match[]; | 794 | static const struct of_device_id s5pcsis_of_match[]; |
794 | 795 | ||
795 | static int s5pcsis_probe(struct platform_device *pdev) | 796 | static int s5pcsis_probe(struct platform_device *pdev) |
@@ -902,13 +903,21 @@ static int s5pcsis_probe(struct platform_device *pdev) | |||
902 | /* .. and a pointer to the subdev. */ | 903 | /* .. and a pointer to the subdev. */ |
903 | platform_set_drvdata(pdev, &state->sd); | 904 | platform_set_drvdata(pdev, &state->sd); |
904 | memcpy(state->events, s5pcsis_events, sizeof(state->events)); | 905 | memcpy(state->events, s5pcsis_events, sizeof(state->events)); |
906 | |||
905 | pm_runtime_enable(dev); | 907 | pm_runtime_enable(dev); |
908 | if (!pm_runtime_enabled(dev)) { | ||
909 | ret = s5pcsis_pm_resume(dev, true); | ||
910 | if (ret < 0) | ||
911 | goto e_m_ent; | ||
912 | } | ||
906 | 913 | ||
907 | dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", | 914 | dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", |
908 | state->num_lanes, state->hs_settle, state->wclk_ext, | 915 | state->num_lanes, state->hs_settle, state->wclk_ext, |
909 | state->clk_frequency); | 916 | state->clk_frequency); |
910 | return 0; | 917 | return 0; |
911 | 918 | ||
919 | e_m_ent: | ||
920 | media_entity_cleanup(&state->sd.entity); | ||
912 | e_clkdis: | 921 | e_clkdis: |
913 | clk_disable(state->clock[CSIS_CLK_MUX]); | 922 | clk_disable(state->clock[CSIS_CLK_MUX]); |
914 | e_clkput: | 923 | e_clkput: |
@@ -1014,7 +1023,7 @@ static int s5pcsis_remove(struct platform_device *pdev) | |||
1014 | struct csis_state *state = sd_to_csis_state(sd); | 1023 | struct csis_state *state = sd_to_csis_state(sd); |
1015 | 1024 | ||
1016 | pm_runtime_disable(&pdev->dev); | 1025 | pm_runtime_disable(&pdev->dev); |
1017 | s5pcsis_pm_suspend(&pdev->dev, false); | 1026 | s5pcsis_pm_suspend(&pdev->dev, true); |
1018 | clk_disable(state->clock[CSIS_CLK_MUX]); | 1027 | clk_disable(state->clock[CSIS_CLK_MUX]); |
1019 | pm_runtime_set_suspended(&pdev->dev); | 1028 | pm_runtime_set_suspended(&pdev->dev); |
1020 | s5pcsis_clk_put(state); | 1029 | s5pcsis_clk_put(state); |
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 65cab70fefcb..6bb86b581a34 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c | |||
@@ -918,7 +918,7 @@ static int deinterlace_open(struct file *file) | |||
918 | return ret; | 918 | return ret; |
919 | } | 919 | } |
920 | 920 | ||
921 | ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) + | 921 | ctx->xt = kzalloc(sizeof(struct dma_interleaved_template) + |
922 | sizeof(struct data_chunk), GFP_KERNEL); | 922 | sizeof(struct data_chunk), GFP_KERNEL); |
923 | if (!ctx->xt) { | 923 | if (!ctx->xt) { |
924 | kfree(ctx); | 924 | kfree(ctx); |
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 8df5975b700a..08e24379b794 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c | |||
@@ -177,8 +177,6 @@ struct m2mtest_ctx { | |||
177 | 177 | ||
178 | enum v4l2_colorspace colorspace; | 178 | enum v4l2_colorspace colorspace; |
179 | 179 | ||
180 | struct v4l2_m2m_ctx *m2m_ctx; | ||
181 | |||
182 | /* Source and destination queue data */ | 180 | /* Source and destination queue data */ |
183 | struct m2mtest_q_data q_data[2]; | 181 | struct m2mtest_q_data q_data[2]; |
184 | }; | 182 | }; |
@@ -342,8 +340,8 @@ static int job_ready(void *priv) | |||
342 | { | 340 | { |
343 | struct m2mtest_ctx *ctx = priv; | 341 | struct m2mtest_ctx *ctx = priv; |
344 | 342 | ||
345 | if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen | 343 | if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen |
346 | || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) { | 344 | || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) { |
347 | dprintk(ctx->dev, "Not enough buffers available\n"); | 345 | dprintk(ctx->dev, "Not enough buffers available\n"); |
348 | return 0; | 346 | return 0; |
349 | } | 347 | } |
@@ -359,21 +357,6 @@ static void job_abort(void *priv) | |||
359 | ctx->aborting = 1; | 357 | ctx->aborting = 1; |
360 | } | 358 | } |
361 | 359 | ||
362 | static void m2mtest_lock(void *priv) | ||
363 | { | ||
364 | struct m2mtest_ctx *ctx = priv; | ||
365 | struct m2mtest_dev *dev = ctx->dev; | ||
366 | mutex_lock(&dev->dev_mutex); | ||
367 | } | ||
368 | |||
369 | static void m2mtest_unlock(void *priv) | ||
370 | { | ||
371 | struct m2mtest_ctx *ctx = priv; | ||
372 | struct m2mtest_dev *dev = ctx->dev; | ||
373 | mutex_unlock(&dev->dev_mutex); | ||
374 | } | ||
375 | |||
376 | |||
377 | /* device_run() - prepares and starts the device | 360 | /* device_run() - prepares and starts the device |
378 | * | 361 | * |
379 | * This simulates all the immediate preparations required before starting | 362 | * This simulates all the immediate preparations required before starting |
@@ -386,8 +369,8 @@ static void device_run(void *priv) | |||
386 | struct m2mtest_dev *dev = ctx->dev; | 369 | struct m2mtest_dev *dev = ctx->dev; |
387 | struct vb2_buffer *src_buf, *dst_buf; | 370 | struct vb2_buffer *src_buf, *dst_buf; |
388 | 371 | ||
389 | src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); | 372 | src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
390 | dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); | 373 | dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
391 | 374 | ||
392 | device_process(ctx, src_buf, dst_buf); | 375 | device_process(ctx, src_buf, dst_buf); |
393 | 376 | ||
@@ -409,8 +392,8 @@ static void device_isr(unsigned long priv) | |||
409 | return; | 392 | return; |
410 | } | 393 | } |
411 | 394 | ||
412 | src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); | 395 | src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); |
413 | dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); | 396 | dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); |
414 | 397 | ||
415 | curr_ctx->num_processed++; | 398 | curr_ctx->num_processed++; |
416 | 399 | ||
@@ -423,7 +406,7 @@ static void device_isr(unsigned long priv) | |||
423 | || curr_ctx->aborting) { | 406 | || curr_ctx->aborting) { |
424 | dprintk(curr_ctx->dev, "Finishing transaction\n"); | 407 | dprintk(curr_ctx->dev, "Finishing transaction\n"); |
425 | curr_ctx->num_processed = 0; | 408 | curr_ctx->num_processed = 0; |
426 | v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx); | 409 | v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->fh.m2m_ctx); |
427 | } else { | 410 | } else { |
428 | device_run(curr_ctx); | 411 | device_run(curr_ctx); |
429 | } | 412 | } |
@@ -491,7 +474,7 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) | |||
491 | struct vb2_queue *vq; | 474 | struct vb2_queue *vq; |
492 | struct m2mtest_q_data *q_data; | 475 | struct m2mtest_q_data *q_data; |
493 | 476 | ||
494 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | 477 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
495 | if (!vq) | 478 | if (!vq) |
496 | return -EINVAL; | 479 | return -EINVAL; |
497 | 480 | ||
@@ -594,7 +577,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) | |||
594 | struct m2mtest_q_data *q_data; | 577 | struct m2mtest_q_data *q_data; |
595 | struct vb2_queue *vq; | 578 | struct vb2_queue *vq; |
596 | 579 | ||
597 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | 580 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
598 | if (!vq) | 581 | if (!vq) |
599 | return -EINVAL; | 582 | return -EINVAL; |
600 | 583 | ||
@@ -648,52 +631,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, | |||
648 | return ret; | 631 | return ret; |
649 | } | 632 | } |
650 | 633 | ||
651 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
652 | struct v4l2_requestbuffers *reqbufs) | ||
653 | { | ||
654 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
655 | |||
656 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | ||
657 | } | ||
658 | |||
659 | static int vidioc_querybuf(struct file *file, void *priv, | ||
660 | struct v4l2_buffer *buf) | ||
661 | { | ||
662 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
663 | |||
664 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); | ||
665 | } | ||
666 | |||
667 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
668 | { | ||
669 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
670 | |||
671 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | ||
672 | } | ||
673 | |||
674 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
675 | { | ||
676 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
677 | |||
678 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | ||
679 | } | ||
680 | |||
681 | static int vidioc_streamon(struct file *file, void *priv, | ||
682 | enum v4l2_buf_type type) | ||
683 | { | ||
684 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
685 | |||
686 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); | ||
687 | } | ||
688 | |||
689 | static int vidioc_streamoff(struct file *file, void *priv, | ||
690 | enum v4l2_buf_type type) | ||
691 | { | ||
692 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
693 | |||
694 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | ||
695 | } | ||
696 | |||
697 | static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl) | 634 | static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl) |
698 | { | 635 | { |
699 | struct m2mtest_ctx *ctx = | 636 | struct m2mtest_ctx *ctx = |
@@ -748,14 +685,14 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { | |||
748 | .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, | 685 | .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, |
749 | .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, | 686 | .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, |
750 | 687 | ||
751 | .vidioc_reqbufs = vidioc_reqbufs, | 688 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
752 | .vidioc_querybuf = vidioc_querybuf, | 689 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
690 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, | ||
691 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | ||
753 | 692 | ||
754 | .vidioc_qbuf = vidioc_qbuf, | 693 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
755 | .vidioc_dqbuf = vidioc_dqbuf, | 694 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
756 | 695 | ||
757 | .vidioc_streamon = vidioc_streamon, | ||
758 | .vidioc_streamoff = vidioc_streamoff, | ||
759 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | 696 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
760 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | 697 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
761 | }; | 698 | }; |
@@ -818,27 +755,15 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb) | |||
818 | static void m2mtest_buf_queue(struct vb2_buffer *vb) | 755 | static void m2mtest_buf_queue(struct vb2_buffer *vb) |
819 | { | 756 | { |
820 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | 757 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
821 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); | 758 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); |
822 | } | ||
823 | |||
824 | static void m2mtest_wait_prepare(struct vb2_queue *q) | ||
825 | { | ||
826 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(q); | ||
827 | m2mtest_unlock(ctx); | ||
828 | } | ||
829 | |||
830 | static void m2mtest_wait_finish(struct vb2_queue *q) | ||
831 | { | ||
832 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(q); | ||
833 | m2mtest_lock(ctx); | ||
834 | } | 759 | } |
835 | 760 | ||
836 | static struct vb2_ops m2mtest_qops = { | 761 | static struct vb2_ops m2mtest_qops = { |
837 | .queue_setup = m2mtest_queue_setup, | 762 | .queue_setup = m2mtest_queue_setup, |
838 | .buf_prepare = m2mtest_buf_prepare, | 763 | .buf_prepare = m2mtest_buf_prepare, |
839 | .buf_queue = m2mtest_buf_queue, | 764 | .buf_queue = m2mtest_buf_queue, |
840 | .wait_prepare = m2mtest_wait_prepare, | 765 | .wait_prepare = vb2_ops_wait_prepare, |
841 | .wait_finish = m2mtest_wait_finish, | 766 | .wait_finish = vb2_ops_wait_finish, |
842 | }; | 767 | }; |
843 | 768 | ||
844 | static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) | 769 | static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) |
@@ -853,6 +778,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds | |||
853 | src_vq->ops = &m2mtest_qops; | 778 | src_vq->ops = &m2mtest_qops; |
854 | src_vq->mem_ops = &vb2_vmalloc_memops; | 779 | src_vq->mem_ops = &vb2_vmalloc_memops; |
855 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 780 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
781 | src_vq->lock = &ctx->dev->dev_mutex; | ||
856 | 782 | ||
857 | ret = vb2_queue_init(src_vq); | 783 | ret = vb2_queue_init(src_vq); |
858 | if (ret) | 784 | if (ret) |
@@ -865,6 +791,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds | |||
865 | dst_vq->ops = &m2mtest_qops; | 791 | dst_vq->ops = &m2mtest_qops; |
866 | dst_vq->mem_ops = &vb2_vmalloc_memops; | 792 | dst_vq->mem_ops = &vb2_vmalloc_memops; |
867 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 793 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
794 | dst_vq->lock = &ctx->dev->dev_mutex; | ||
868 | 795 | ||
869 | return vb2_queue_init(dst_vq); | 796 | return vb2_queue_init(dst_vq); |
870 | } | 797 | } |
@@ -936,10 +863,10 @@ static int m2mtest_open(struct file *file) | |||
936 | ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; | 863 | ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; |
937 | ctx->colorspace = V4L2_COLORSPACE_REC709; | 864 | ctx->colorspace = V4L2_COLORSPACE_REC709; |
938 | 865 | ||
939 | ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); | 866 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); |
940 | 867 | ||
941 | if (IS_ERR(ctx->m2m_ctx)) { | 868 | if (IS_ERR(ctx->fh.m2m_ctx)) { |
942 | rc = PTR_ERR(ctx->m2m_ctx); | 869 | rc = PTR_ERR(ctx->fh.m2m_ctx); |
943 | 870 | ||
944 | v4l2_ctrl_handler_free(hdl); | 871 | v4l2_ctrl_handler_free(hdl); |
945 | kfree(ctx); | 872 | kfree(ctx); |
@@ -949,7 +876,8 @@ static int m2mtest_open(struct file *file) | |||
949 | v4l2_fh_add(&ctx->fh); | 876 | v4l2_fh_add(&ctx->fh); |
950 | atomic_inc(&dev->num_inst); | 877 | atomic_inc(&dev->num_inst); |
951 | 878 | ||
952 | dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); | 879 | dprintk(dev, "Created instance: %p, m2m_ctx: %p\n", |
880 | ctx, ctx->fh.m2m_ctx); | ||
953 | 881 | ||
954 | open_unlock: | 882 | open_unlock: |
955 | mutex_unlock(&dev->dev_mutex); | 883 | mutex_unlock(&dev->dev_mutex); |
@@ -967,7 +895,7 @@ static int m2mtest_release(struct file *file) | |||
967 | v4l2_fh_exit(&ctx->fh); | 895 | v4l2_fh_exit(&ctx->fh); |
968 | v4l2_ctrl_handler_free(&ctx->hdl); | 896 | v4l2_ctrl_handler_free(&ctx->hdl); |
969 | mutex_lock(&dev->dev_mutex); | 897 | mutex_lock(&dev->dev_mutex); |
970 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | 898 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
971 | mutex_unlock(&dev->dev_mutex); | 899 | mutex_unlock(&dev->dev_mutex); |
972 | kfree(ctx); | 900 | kfree(ctx); |
973 | 901 | ||
@@ -976,34 +904,13 @@ static int m2mtest_release(struct file *file) | |||
976 | return 0; | 904 | return 0; |
977 | } | 905 | } |
978 | 906 | ||
979 | static unsigned int m2mtest_poll(struct file *file, | ||
980 | struct poll_table_struct *wait) | ||
981 | { | ||
982 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
983 | |||
984 | return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | ||
985 | } | ||
986 | |||
987 | static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma) | ||
988 | { | ||
989 | struct m2mtest_dev *dev = video_drvdata(file); | ||
990 | struct m2mtest_ctx *ctx = file2ctx(file); | ||
991 | int res; | ||
992 | |||
993 | if (mutex_lock_interruptible(&dev->dev_mutex)) | ||
994 | return -ERESTARTSYS; | ||
995 | res = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | ||
996 | mutex_unlock(&dev->dev_mutex); | ||
997 | return res; | ||
998 | } | ||
999 | |||
1000 | static const struct v4l2_file_operations m2mtest_fops = { | 907 | static const struct v4l2_file_operations m2mtest_fops = { |
1001 | .owner = THIS_MODULE, | 908 | .owner = THIS_MODULE, |
1002 | .open = m2mtest_open, | 909 | .open = m2mtest_open, |
1003 | .release = m2mtest_release, | 910 | .release = m2mtest_release, |
1004 | .poll = m2mtest_poll, | 911 | .poll = v4l2_m2m_fop_poll, |
1005 | .unlocked_ioctl = video_ioctl2, | 912 | .unlocked_ioctl = video_ioctl2, |
1006 | .mmap = m2mtest_mmap, | 913 | .mmap = v4l2_m2m_fop_mmap, |
1007 | }; | 914 | }; |
1008 | 915 | ||
1009 | static struct video_device m2mtest_videodev = { | 916 | static struct video_device m2mtest_videodev = { |
@@ -1019,8 +926,6 @@ static struct v4l2_m2m_ops m2m_ops = { | |||
1019 | .device_run = device_run, | 926 | .device_run = device_run, |
1020 | .job_ready = job_ready, | 927 | .job_ready = job_ready, |
1021 | .job_abort = job_abort, | 928 | .job_abort = job_abort, |
1022 | .lock = m2mtest_lock, | ||
1023 | .unlock = m2mtest_unlock, | ||
1024 | }; | 929 | }; |
1025 | 930 | ||
1026 | static int m2mtest_probe(struct platform_device *pdev) | 931 | static int m2mtest_probe(struct platform_device *pdev) |
@@ -1133,4 +1038,3 @@ static int __init m2mtest_init(void) | |||
1133 | 1038 | ||
1134 | module_init(m2mtest_init); | 1039 | module_init(m2mtest_init); |
1135 | module_exit(m2mtest_exit); | 1040 | module_exit(m2mtest_exit); |
1136 | |||
diff --git a/drivers/media/platform/omap24xxcam-dma.c b/drivers/media/platform/omap24xxcam-dma.c deleted file mode 100644 index 9c00776d6583..000000000000 --- a/drivers/media/platform/omap24xxcam-dma.c +++ /dev/null | |||
@@ -1,601 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/omap24xxcam-dma.c | ||
3 | * | ||
4 | * Copyright (C) 2004 MontaVista Software, Inc. | ||
5 | * Copyright (C) 2004 Texas Instruments. | ||
6 | * Copyright (C) 2007 Nokia Corporation. | ||
7 | * | ||
8 | * Contact: Sakari Ailus <sakari.ailus@nokia.com> | ||
9 | * | ||
10 | * Based on code from Andy Lowe <source@mvista.com> and | ||
11 | * David Cohen <david.cohen@indt.org.br>. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * version 2 as published by the Free Software Foundation. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, but | ||
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
20 | * General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
25 | * 02110-1301 USA | ||
26 | */ | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <linux/scatterlist.h> | ||
31 | |||
32 | #include "omap24xxcam.h" | ||
33 | |||
34 | /* | ||
35 | * | ||
36 | * DMA hardware. | ||
37 | * | ||
38 | */ | ||
39 | |||
40 | /* Ack all interrupt on CSR and IRQSTATUS_L0 */ | ||
41 | static void omap24xxcam_dmahw_ack_all(void __iomem *base) | ||
42 | { | ||
43 | u32 csr; | ||
44 | int i; | ||
45 | |||
46 | for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) { | ||
47 | csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i)); | ||
48 | /* ack interrupt in CSR */ | ||
49 | omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr); | ||
50 | } | ||
51 | omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf); | ||
52 | } | ||
53 | |||
54 | /* Ack dmach on CSR and IRQSTATUS_L0 */ | ||
55 | static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach) | ||
56 | { | ||
57 | u32 csr; | ||
58 | |||
59 | csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach)); | ||
60 | /* ack interrupt in CSR */ | ||
61 | omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr); | ||
62 | /* ack interrupt in IRQSTATUS */ | ||
63 | omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach)); | ||
64 | |||
65 | return csr; | ||
66 | } | ||
67 | |||
68 | static int omap24xxcam_dmahw_running(void __iomem *base, int dmach) | ||
69 | { | ||
70 | return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE; | ||
71 | } | ||
72 | |||
73 | static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach, | ||
74 | dma_addr_t start, u32 len) | ||
75 | { | ||
76 | omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), | ||
77 | CAMDMA_CCR_SEL_SRC_DST_SYNC | ||
78 | | CAMDMA_CCR_BS | ||
79 | | CAMDMA_CCR_DST_AMODE_POST_INC | ||
80 | | CAMDMA_CCR_SRC_AMODE_POST_INC | ||
81 | | CAMDMA_CCR_FS | ||
82 | | CAMDMA_CCR_WR_ACTIVE | ||
83 | | CAMDMA_CCR_RD_ACTIVE | ||
84 | | CAMDMA_CCR_SYNCHRO_CAMERA); | ||
85 | omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0); | ||
86 | omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len); | ||
87 | omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1); | ||
88 | omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach), | ||
89 | CAMDMA_CSDP_WRITE_MODE_POSTED | ||
90 | | CAMDMA_CSDP_DST_BURST_EN_32 | ||
91 | | CAMDMA_CSDP_DST_PACKED | ||
92 | | CAMDMA_CSDP_SRC_BURST_EN_32 | ||
93 | | CAMDMA_CSDP_SRC_PACKED | ||
94 | | CAMDMA_CSDP_DATA_TYPE_8BITS); | ||
95 | omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0); | ||
96 | omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start); | ||
97 | omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0); | ||
98 | omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD); | ||
99 | omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0); | ||
100 | omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0); | ||
101 | omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), | ||
102 | CAMDMA_CSR_MISALIGNED_ERR | ||
103 | | CAMDMA_CSR_SECURE_ERR | ||
104 | | CAMDMA_CSR_TRANS_ERR | ||
105 | | CAMDMA_CSR_BLOCK | ||
106 | | CAMDMA_CSR_DROP); | ||
107 | omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), | ||
108 | CAMDMA_CICR_MISALIGNED_ERR_IE | ||
109 | | CAMDMA_CICR_SECURE_ERR_IE | ||
110 | | CAMDMA_CICR_TRANS_ERR_IE | ||
111 | | CAMDMA_CICR_BLOCK_IE | ||
112 | | CAMDMA_CICR_DROP_IE); | ||
113 | } | ||
114 | |||
115 | static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach) | ||
116 | { | ||
117 | omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), | ||
118 | CAMDMA_CCR_SEL_SRC_DST_SYNC | ||
119 | | CAMDMA_CCR_BS | ||
120 | | CAMDMA_CCR_DST_AMODE_POST_INC | ||
121 | | CAMDMA_CCR_SRC_AMODE_POST_INC | ||
122 | | CAMDMA_CCR_ENABLE | ||
123 | | CAMDMA_CCR_FS | ||
124 | | CAMDMA_CCR_SYNCHRO_CAMERA); | ||
125 | } | ||
126 | |||
127 | static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach, | ||
128 | int free_dmach) | ||
129 | { | ||
130 | int prev_dmach, ch; | ||
131 | |||
132 | if (dmach == 0) | ||
133 | prev_dmach = NUM_CAMDMA_CHANNELS - 1; | ||
134 | else | ||
135 | prev_dmach = dmach - 1; | ||
136 | omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach), | ||
137 | CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach); | ||
138 | /* Did we chain the DMA transfer before the previous one | ||
139 | * finished? | ||
140 | */ | ||
141 | ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS; | ||
142 | while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch)) | ||
143 | & CAMDMA_CCR_ENABLE)) { | ||
144 | if (ch == dmach) { | ||
145 | /* The previous transfer has ended and this one | ||
146 | * hasn't started, so we must not have chained | ||
147 | * to the previous one in time. We'll have to | ||
148 | * start it now. | ||
149 | */ | ||
150 | omap24xxcam_dmahw_transfer_start(base, dmach); | ||
151 | break; | ||
152 | } else | ||
153 | ch = (ch + 1) % NUM_CAMDMA_CHANNELS; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | /* Abort all chained DMA transfers. After all transfers have been | ||
158 | * aborted and the DMA controller is idle, the completion routines for | ||
159 | * any aborted transfers will be called in sequence. The DMA | ||
160 | * controller may not be idle after this routine completes, because | ||
161 | * the completion routines might start new transfers. | ||
162 | */ | ||
163 | static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach) | ||
164 | { | ||
165 | /* mask all interrupts from this channel */ | ||
166 | omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0); | ||
167 | /* unlink this channel */ | ||
168 | omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0, | ||
169 | CAMDMA_CLNK_CTRL_ENABLE_LNK); | ||
170 | /* disable this channel */ | ||
171 | omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE); | ||
172 | } | ||
173 | |||
174 | static void omap24xxcam_dmahw_init(void __iomem *base) | ||
175 | { | ||
176 | omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG, | ||
177 | CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY | ||
178 | | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE | ||
179 | | CAMDMA_OCP_SYSCONFIG_AUTOIDLE); | ||
180 | |||
181 | omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10, | ||
182 | CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH); | ||
183 | |||
184 | omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * | ||
189 | * Individual DMA channel handling. | ||
190 | * | ||
191 | */ | ||
192 | |||
193 | /* Start a DMA transfer from the camera to memory. | ||
194 | * Returns zero if the transfer was successfully started, or non-zero if all | ||
195 | * DMA channels are already in use or starting is currently inhibited. | ||
196 | */ | ||
197 | static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start, | ||
198 | u32 len, dma_callback_t callback, void *arg) | ||
199 | { | ||
200 | unsigned long flags; | ||
201 | int dmach; | ||
202 | |||
203 | spin_lock_irqsave(&dma->lock, flags); | ||
204 | |||
205 | if (!dma->free_dmach || atomic_read(&dma->dma_stop)) { | ||
206 | spin_unlock_irqrestore(&dma->lock, flags); | ||
207 | return -EBUSY; | ||
208 | } | ||
209 | |||
210 | dmach = dma->next_dmach; | ||
211 | |||
212 | dma->ch_state[dmach].callback = callback; | ||
213 | dma->ch_state[dmach].arg = arg; | ||
214 | |||
215 | omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len); | ||
216 | |||
217 | /* We're ready to start the DMA transfer. */ | ||
218 | |||
219 | if (dma->free_dmach < NUM_CAMDMA_CHANNELS) { | ||
220 | /* A transfer is already in progress, so try to chain to it. */ | ||
221 | omap24xxcam_dmahw_transfer_chain(dma->base, dmach, | ||
222 | dma->free_dmach); | ||
223 | } else { | ||
224 | /* No transfer is in progress, so we'll just start this one | ||
225 | * now. | ||
226 | */ | ||
227 | omap24xxcam_dmahw_transfer_start(dma->base, dmach); | ||
228 | } | ||
229 | |||
230 | dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS; | ||
231 | dma->free_dmach--; | ||
232 | |||
233 | spin_unlock_irqrestore(&dma->lock, flags); | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | /* Abort all chained DMA transfers. After all transfers have been | ||
239 | * aborted and the DMA controller is idle, the completion routines for | ||
240 | * any aborted transfers will be called in sequence. The DMA | ||
241 | * controller may not be idle after this routine completes, because | ||
242 | * the completion routines might start new transfers. | ||
243 | */ | ||
244 | static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr) | ||
245 | { | ||
246 | unsigned long flags; | ||
247 | int dmach, i, free_dmach; | ||
248 | dma_callback_t callback; | ||
249 | void *arg; | ||
250 | |||
251 | spin_lock_irqsave(&dma->lock, flags); | ||
252 | |||
253 | /* stop any DMA transfers in progress */ | ||
254 | dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS; | ||
255 | for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) { | ||
256 | omap24xxcam_dmahw_abort_ch(dma->base, dmach); | ||
257 | dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS; | ||
258 | } | ||
259 | |||
260 | /* We have to be careful here because the callback routine | ||
261 | * might start a new DMA transfer, and we only want to abort | ||
262 | * transfers that were started before this routine was called. | ||
263 | */ | ||
264 | free_dmach = dma->free_dmach; | ||
265 | while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) && | ||
266 | (free_dmach < NUM_CAMDMA_CHANNELS)) { | ||
267 | dmach = (dma->next_dmach + dma->free_dmach) | ||
268 | % NUM_CAMDMA_CHANNELS; | ||
269 | callback = dma->ch_state[dmach].callback; | ||
270 | arg = dma->ch_state[dmach].arg; | ||
271 | dma->free_dmach++; | ||
272 | free_dmach++; | ||
273 | if (callback) { | ||
274 | /* leave interrupts disabled during callback */ | ||
275 | spin_unlock(&dma->lock); | ||
276 | (*callback) (dma, csr, arg); | ||
277 | spin_lock(&dma->lock); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | spin_unlock_irqrestore(&dma->lock, flags); | ||
282 | } | ||
283 | |||
284 | /* Abort all chained DMA transfers. After all transfers have been | ||
285 | * aborted and the DMA controller is idle, the completion routines for | ||
286 | * any aborted transfers will be called in sequence. If the completion | ||
287 | * routines attempt to start a new DMA transfer it will fail, so the | ||
288 | * DMA controller will be idle after this routine completes. | ||
289 | */ | ||
290 | static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr) | ||
291 | { | ||
292 | atomic_inc(&dma->dma_stop); | ||
293 | omap24xxcam_dma_abort(dma, csr); | ||
294 | atomic_dec(&dma->dma_stop); | ||
295 | } | ||
296 | |||
297 | /* Camera DMA interrupt service routine. */ | ||
298 | void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma) | ||
299 | { | ||
300 | int dmach; | ||
301 | dma_callback_t callback; | ||
302 | void *arg; | ||
303 | u32 csr; | ||
304 | const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR | ||
305 | | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR | ||
306 | | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; | ||
307 | |||
308 | spin_lock(&dma->lock); | ||
309 | |||
310 | if (dma->free_dmach == NUM_CAMDMA_CHANNELS) { | ||
311 | /* A camera DMA interrupt occurred while all channels | ||
312 | * are idle, so we'll acknowledge the interrupt in the | ||
313 | * IRQSTATUS register and exit. | ||
314 | */ | ||
315 | omap24xxcam_dmahw_ack_all(dma->base); | ||
316 | spin_unlock(&dma->lock); | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | while (dma->free_dmach < NUM_CAMDMA_CHANNELS) { | ||
321 | dmach = (dma->next_dmach + dma->free_dmach) | ||
322 | % NUM_CAMDMA_CHANNELS; | ||
323 | if (omap24xxcam_dmahw_running(dma->base, dmach)) { | ||
324 | /* This buffer hasn't finished yet, so we're done. */ | ||
325 | break; | ||
326 | } | ||
327 | csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach); | ||
328 | if (csr & csr_error) { | ||
329 | /* A DMA error occurred, so stop all DMA | ||
330 | * transfers in progress. | ||
331 | */ | ||
332 | spin_unlock(&dma->lock); | ||
333 | omap24xxcam_dma_stop(dma, csr); | ||
334 | return; | ||
335 | } else { | ||
336 | callback = dma->ch_state[dmach].callback; | ||
337 | arg = dma->ch_state[dmach].arg; | ||
338 | dma->free_dmach++; | ||
339 | if (callback) { | ||
340 | spin_unlock(&dma->lock); | ||
341 | (*callback) (dma, csr, arg); | ||
342 | spin_lock(&dma->lock); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | spin_unlock(&dma->lock); | ||
348 | |||
349 | omap24xxcam_sgdma_process( | ||
350 | container_of(dma, struct omap24xxcam_sgdma, dma)); | ||
351 | } | ||
352 | |||
353 | void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma) | ||
354 | { | ||
355 | unsigned long flags; | ||
356 | |||
357 | spin_lock_irqsave(&dma->lock, flags); | ||
358 | |||
359 | omap24xxcam_dmahw_init(dma->base); | ||
360 | |||
361 | spin_unlock_irqrestore(&dma->lock, flags); | ||
362 | } | ||
363 | |||
364 | static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma, | ||
365 | void __iomem *base) | ||
366 | { | ||
367 | int ch; | ||
368 | |||
369 | /* group all channels on DMA IRQ0 and unmask irq */ | ||
370 | spin_lock_init(&dma->lock); | ||
371 | dma->base = base; | ||
372 | dma->free_dmach = NUM_CAMDMA_CHANNELS; | ||
373 | dma->next_dmach = 0; | ||
374 | for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) { | ||
375 | dma->ch_state[ch].callback = NULL; | ||
376 | dma->ch_state[ch].arg = NULL; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * | ||
382 | * Scatter-gather DMA. | ||
383 | * | ||
384 | * High-level DMA construct for transferring whole picture frames to | ||
385 | * memory that is discontinuous. | ||
386 | * | ||
387 | */ | ||
388 | |||
389 | /* DMA completion routine for the scatter-gather DMA fragments. */ | ||
390 | static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr, | ||
391 | void *arg) | ||
392 | { | ||
393 | struct omap24xxcam_sgdma *sgdma = | ||
394 | container_of(dma, struct omap24xxcam_sgdma, dma); | ||
395 | int sgslot = (int)arg; | ||
396 | struct sgdma_state *sg_state; | ||
397 | const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR | ||
398 | | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR | ||
399 | | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; | ||
400 | |||
401 | spin_lock(&sgdma->lock); | ||
402 | |||
403 | /* We got an interrupt, we can remove the timer */ | ||
404 | del_timer(&sgdma->reset_timer); | ||
405 | |||
406 | sg_state = sgdma->sg_state + sgslot; | ||
407 | if (!sg_state->queued_sglist) { | ||
408 | spin_unlock(&sgdma->lock); | ||
409 | printk(KERN_ERR "%s: sgdma completed when none queued!\n", | ||
410 | __func__); | ||
411 | return; | ||
412 | } | ||
413 | |||
414 | sg_state->csr |= csr; | ||
415 | if (!--sg_state->queued_sglist) { | ||
416 | /* Queue for this sglist is empty, so check to see if we're | ||
417 | * done. | ||
418 | */ | ||
419 | if ((sg_state->next_sglist == sg_state->sglen) | ||
420 | || (sg_state->csr & csr_error)) { | ||
421 | sgdma_callback_t callback = sg_state->callback; | ||
422 | void *arg = sg_state->arg; | ||
423 | u32 sg_csr = sg_state->csr; | ||
424 | /* All done with this sglist */ | ||
425 | sgdma->free_sgdma++; | ||
426 | if (callback) { | ||
427 | spin_unlock(&sgdma->lock); | ||
428 | (*callback) (sgdma, sg_csr, arg); | ||
429 | return; | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | |||
434 | spin_unlock(&sgdma->lock); | ||
435 | } | ||
436 | |||
437 | /* Start queued scatter-gather DMA transfers. */ | ||
438 | void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma) | ||
439 | { | ||
440 | unsigned long flags; | ||
441 | int queued_sgdma, sgslot; | ||
442 | struct sgdma_state *sg_state; | ||
443 | const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR | ||
444 | | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR | ||
445 | | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; | ||
446 | |||
447 | spin_lock_irqsave(&sgdma->lock, flags); | ||
448 | |||
449 | queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma; | ||
450 | sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA; | ||
451 | while (queued_sgdma > 0) { | ||
452 | sg_state = sgdma->sg_state + sgslot; | ||
453 | while ((sg_state->next_sglist < sg_state->sglen) && | ||
454 | !(sg_state->csr & csr_error)) { | ||
455 | const struct scatterlist *sglist; | ||
456 | unsigned int len; | ||
457 | |||
458 | sglist = sg_state->sglist + sg_state->next_sglist; | ||
459 | /* try to start the next DMA transfer */ | ||
460 | if (sg_state->next_sglist + 1 == sg_state->sglen) { | ||
461 | /* | ||
462 | * On the last sg, we handle the case where | ||
463 | * cam->img.pix.sizeimage % PAGE_ALIGN != 0 | ||
464 | */ | ||
465 | len = sg_state->len - sg_state->bytes_read; | ||
466 | } else { | ||
467 | len = sg_dma_len(sglist); | ||
468 | } | ||
469 | |||
470 | if (omap24xxcam_dma_start(&sgdma->dma, | ||
471 | sg_dma_address(sglist), | ||
472 | len, | ||
473 | omap24xxcam_sgdma_callback, | ||
474 | (void *)sgslot)) { | ||
475 | /* DMA start failed */ | ||
476 | spin_unlock_irqrestore(&sgdma->lock, flags); | ||
477 | return; | ||
478 | } else { | ||
479 | unsigned long expires; | ||
480 | /* DMA start was successful */ | ||
481 | sg_state->next_sglist++; | ||
482 | sg_state->bytes_read += len; | ||
483 | sg_state->queued_sglist++; | ||
484 | |||
485 | /* We start the reset timer */ | ||
486 | expires = jiffies + HZ; | ||
487 | mod_timer(&sgdma->reset_timer, expires); | ||
488 | } | ||
489 | } | ||
490 | queued_sgdma--; | ||
491 | sgslot = (sgslot + 1) % NUM_SG_DMA; | ||
492 | } | ||
493 | |||
494 | spin_unlock_irqrestore(&sgdma->lock, flags); | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * Queue a scatter-gather DMA transfer from the camera to memory. | ||
499 | * Returns zero if the transfer was successfully queued, or non-zero | ||
500 | * if all of the scatter-gather slots are already in use. | ||
501 | */ | ||
502 | int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma, | ||
503 | const struct scatterlist *sglist, int sglen, | ||
504 | int len, sgdma_callback_t callback, void *arg) | ||
505 | { | ||
506 | unsigned long flags; | ||
507 | struct sgdma_state *sg_state; | ||
508 | |||
509 | if ((sglen < 0) || ((sglen > 0) && !sglist)) | ||
510 | return -EINVAL; | ||
511 | |||
512 | spin_lock_irqsave(&sgdma->lock, flags); | ||
513 | |||
514 | if (!sgdma->free_sgdma) { | ||
515 | spin_unlock_irqrestore(&sgdma->lock, flags); | ||
516 | return -EBUSY; | ||
517 | } | ||
518 | |||
519 | sg_state = sgdma->sg_state + sgdma->next_sgdma; | ||
520 | |||
521 | sg_state->sglist = sglist; | ||
522 | sg_state->sglen = sglen; | ||
523 | sg_state->next_sglist = 0; | ||
524 | sg_state->bytes_read = 0; | ||
525 | sg_state->len = len; | ||
526 | sg_state->queued_sglist = 0; | ||
527 | sg_state->csr = 0; | ||
528 | sg_state->callback = callback; | ||
529 | sg_state->arg = arg; | ||
530 | |||
531 | sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA; | ||
532 | sgdma->free_sgdma--; | ||
533 | |||
534 | spin_unlock_irqrestore(&sgdma->lock, flags); | ||
535 | |||
536 | omap24xxcam_sgdma_process(sgdma); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | /* Sync scatter-gather DMA by aborting any DMA transfers currently in progress. | ||
542 | * Any queued scatter-gather DMA transactions that have not yet been started | ||
543 | * will remain queued. The DMA controller will be idle after this routine | ||
544 | * completes. When the scatter-gather queue is restarted, the next | ||
545 | * scatter-gather DMA transfer will begin at the start of a new transaction. | ||
546 | */ | ||
547 | void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma) | ||
548 | { | ||
549 | unsigned long flags; | ||
550 | int sgslot; | ||
551 | struct sgdma_state *sg_state; | ||
552 | u32 csr = CAMDMA_CSR_TRANS_ERR; | ||
553 | |||
554 | /* stop any DMA transfers in progress */ | ||
555 | omap24xxcam_dma_stop(&sgdma->dma, csr); | ||
556 | |||
557 | spin_lock_irqsave(&sgdma->lock, flags); | ||
558 | |||
559 | if (sgdma->free_sgdma < NUM_SG_DMA) { | ||
560 | sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA; | ||
561 | sg_state = sgdma->sg_state + sgslot; | ||
562 | if (sg_state->next_sglist != 0) { | ||
563 | /* This DMA transfer was in progress, so abort it. */ | ||
564 | sgdma_callback_t callback = sg_state->callback; | ||
565 | void *arg = sg_state->arg; | ||
566 | sgdma->free_sgdma++; | ||
567 | if (callback) { | ||
568 | /* leave interrupts masked */ | ||
569 | spin_unlock(&sgdma->lock); | ||
570 | (*callback) (sgdma, csr, arg); | ||
571 | spin_lock(&sgdma->lock); | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | |||
576 | spin_unlock_irqrestore(&sgdma->lock, flags); | ||
577 | } | ||
578 | |||
579 | void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma, | ||
580 | void __iomem *base, | ||
581 | void (*reset_callback)(unsigned long data), | ||
582 | unsigned long reset_callback_data) | ||
583 | { | ||
584 | int sg; | ||
585 | |||
586 | spin_lock_init(&sgdma->lock); | ||
587 | sgdma->free_sgdma = NUM_SG_DMA; | ||
588 | sgdma->next_sgdma = 0; | ||
589 | for (sg = 0; sg < NUM_SG_DMA; sg++) { | ||
590 | sgdma->sg_state[sg].sglen = 0; | ||
591 | sgdma->sg_state[sg].next_sglist = 0; | ||
592 | sgdma->sg_state[sg].bytes_read = 0; | ||
593 | sgdma->sg_state[sg].queued_sglist = 0; | ||
594 | sgdma->sg_state[sg].csr = 0; | ||
595 | sgdma->sg_state[sg].callback = NULL; | ||
596 | sgdma->sg_state[sg].arg = NULL; | ||
597 | } | ||
598 | |||
599 | omap24xxcam_dma_init(&sgdma->dma, base); | ||
600 | setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data); | ||
601 | } | ||
diff --git a/drivers/media/platform/omap24xxcam.c b/drivers/media/platform/omap24xxcam.c deleted file mode 100644 index d2b440c842b3..000000000000 --- a/drivers/media/platform/omap24xxcam.c +++ /dev/null | |||
@@ -1,1888 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/omap24xxcam.c | ||
3 | * | ||
4 | * OMAP 2 camera block driver. | ||
5 | * | ||
6 | * Copyright (C) 2004 MontaVista Software, Inc. | ||
7 | * Copyright (C) 2004 Texas Instruments. | ||
8 | * Copyright (C) 2007-2008 Nokia Corporation. | ||
9 | * | ||
10 | * Contact: Sakari Ailus <sakari.ailus@nokia.com> | ||
11 | * | ||
12 | * Based on code from Andy Lowe <source@mvista.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * version 2 as published by the Free Software Foundation. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
26 | * 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/delay.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/videodev2.h> | ||
33 | #include <linux/pci.h> /* needed for videobufs */ | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/clk.h> | ||
36 | #include <linux/io.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/sched.h> | ||
39 | #include <linux/module.h> | ||
40 | |||
41 | #include <media/v4l2-common.h> | ||
42 | #include <media/v4l2-ioctl.h> | ||
43 | |||
44 | #include "omap24xxcam.h" | ||
45 | |||
46 | #define OMAP24XXCAM_VERSION "0.0.1" | ||
47 | |||
48 | #define RESET_TIMEOUT_NS 10000 | ||
49 | |||
50 | static void omap24xxcam_reset(struct omap24xxcam_device *cam); | ||
51 | static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam); | ||
52 | static void omap24xxcam_device_unregister(struct v4l2_int_device *s); | ||
53 | static int omap24xxcam_remove(struct platform_device *pdev); | ||
54 | |||
55 | /* module parameters */ | ||
56 | static int video_nr = -1; /* video device minor (-1 ==> auto assign) */ | ||
57 | /* | ||
58 | * Maximum amount of memory to use for capture buffers. | ||
59 | * Default is 4800KB, enough to double-buffer SXGA. | ||
60 | */ | ||
61 | static int capture_mem = 1280 * 960 * 2 * 2; | ||
62 | |||
63 | static struct v4l2_int_device omap24xxcam; | ||
64 | |||
65 | /* | ||
66 | * | ||
67 | * Clocks. | ||
68 | * | ||
69 | */ | ||
70 | |||
71 | static void omap24xxcam_clock_put(struct omap24xxcam_device *cam) | ||
72 | { | ||
73 | if (cam->ick != NULL && !IS_ERR(cam->ick)) | ||
74 | clk_put(cam->ick); | ||
75 | if (cam->fck != NULL && !IS_ERR(cam->fck)) | ||
76 | clk_put(cam->fck); | ||
77 | |||
78 | cam->ick = cam->fck = NULL; | ||
79 | } | ||
80 | |||
81 | static int omap24xxcam_clock_get(struct omap24xxcam_device *cam) | ||
82 | { | ||
83 | int rval = 0; | ||
84 | |||
85 | cam->fck = clk_get(cam->dev, "fck"); | ||
86 | if (IS_ERR(cam->fck)) { | ||
87 | dev_err(cam->dev, "can't get camera fck"); | ||
88 | rval = PTR_ERR(cam->fck); | ||
89 | omap24xxcam_clock_put(cam); | ||
90 | return rval; | ||
91 | } | ||
92 | |||
93 | cam->ick = clk_get(cam->dev, "ick"); | ||
94 | if (IS_ERR(cam->ick)) { | ||
95 | dev_err(cam->dev, "can't get camera ick"); | ||
96 | rval = PTR_ERR(cam->ick); | ||
97 | omap24xxcam_clock_put(cam); | ||
98 | } | ||
99 | |||
100 | return rval; | ||
101 | } | ||
102 | |||
103 | static void omap24xxcam_clock_on(struct omap24xxcam_device *cam) | ||
104 | { | ||
105 | clk_enable(cam->fck); | ||
106 | clk_enable(cam->ick); | ||
107 | } | ||
108 | |||
109 | static void omap24xxcam_clock_off(struct omap24xxcam_device *cam) | ||
110 | { | ||
111 | clk_disable(cam->fck); | ||
112 | clk_disable(cam->ick); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * | ||
117 | * Camera core | ||
118 | * | ||
119 | */ | ||
120 | |||
121 | /* | ||
122 | * Set xclk. | ||
123 | * | ||
124 | * To disable xclk, use value zero. | ||
125 | */ | ||
126 | static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam, | ||
127 | u32 xclk) | ||
128 | { | ||
129 | if (xclk) { | ||
130 | u32 divisor = CAM_MCLK / xclk; | ||
131 | |||
132 | if (divisor == 1) | ||
133 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, | ||
134 | CC_CTRL_XCLK, | ||
135 | CC_CTRL_XCLK_DIV_BYPASS); | ||
136 | else | ||
137 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, | ||
138 | CC_CTRL_XCLK, divisor); | ||
139 | } else | ||
140 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, | ||
141 | CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW); | ||
142 | } | ||
143 | |||
144 | static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam) | ||
145 | { | ||
146 | /* | ||
147 | * Setting the camera core AUTOIDLE bit causes problems with frame | ||
148 | * synchronization, so we will clear the AUTOIDLE bit instead. | ||
149 | */ | ||
150 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG, | ||
151 | CC_SYSCONFIG_AUTOIDLE); | ||
152 | |||
153 | /* program the camera interface DMA packet size */ | ||
154 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA, | ||
155 | CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1)); | ||
156 | |||
157 | /* enable camera core error interrupts */ | ||
158 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE, | ||
159 | CC_IRQENABLE_FW_ERR_IRQ | ||
160 | | CC_IRQENABLE_FSC_ERR_IRQ | ||
161 | | CC_IRQENABLE_SSC_ERR_IRQ | ||
162 | | CC_IRQENABLE_FIFO_OF_IRQ); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Enable the camera core. | ||
167 | * | ||
168 | * Data transfer to the camera DMA starts from next starting frame. | ||
169 | */ | ||
170 | static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam) | ||
171 | { | ||
172 | |||
173 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL, | ||
174 | cam->cc_ctrl); | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Disable camera core. | ||
179 | * | ||
180 | * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The | ||
181 | * core internal state machines will be reset. Use | ||
182 | * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current | ||
183 | * frame completely. | ||
184 | */ | ||
185 | static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam) | ||
186 | { | ||
187 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL, | ||
188 | CC_CTRL_CC_RST); | ||
189 | } | ||
190 | |||
191 | /* Interrupt service routine for camera core interrupts. */ | ||
192 | static void omap24xxcam_core_isr(struct omap24xxcam_device *cam) | ||
193 | { | ||
194 | u32 cc_irqstatus; | ||
195 | const u32 cc_irqstatus_err = | ||
196 | CC_IRQSTATUS_FW_ERR_IRQ | ||
197 | | CC_IRQSTATUS_FSC_ERR_IRQ | ||
198 | | CC_IRQSTATUS_SSC_ERR_IRQ | ||
199 | | CC_IRQSTATUS_FIFO_UF_IRQ | ||
200 | | CC_IRQSTATUS_FIFO_OF_IRQ; | ||
201 | |||
202 | cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET, | ||
203 | CC_IRQSTATUS); | ||
204 | omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS, | ||
205 | cc_irqstatus); | ||
206 | |||
207 | if (cc_irqstatus & cc_irqstatus_err | ||
208 | && !atomic_read(&cam->in_reset)) { | ||
209 | dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n", | ||
210 | cc_irqstatus); | ||
211 | omap24xxcam_reset(cam); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * | ||
217 | * videobuf_buffer handling. | ||
218 | * | ||
219 | * Memory for mmapped videobuf_buffers is not allocated | ||
220 | * conventionally, but by several kmalloc allocations and then | ||
221 | * creating the scatterlist on our own. User-space buffers are handled | ||
222 | * normally. | ||
223 | * | ||
224 | */ | ||
225 | |||
226 | /* | ||
227 | * Free the memory-mapped buffer memory allocated for a | ||
228 | * videobuf_buffer and the associated scatterlist. | ||
229 | */ | ||
230 | static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb) | ||
231 | { | ||
232 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
233 | size_t alloc_size; | ||
234 | struct page *page; | ||
235 | int i; | ||
236 | |||
237 | if (dma->sglist == NULL) | ||
238 | return; | ||
239 | |||
240 | i = dma->sglen; | ||
241 | while (i) { | ||
242 | i--; | ||
243 | alloc_size = sg_dma_len(&dma->sglist[i]); | ||
244 | page = sg_page(&dma->sglist[i]); | ||
245 | do { | ||
246 | ClearPageReserved(page++); | ||
247 | } while (alloc_size -= PAGE_SIZE); | ||
248 | __free_pages(sg_page(&dma->sglist[i]), | ||
249 | get_order(sg_dma_len(&dma->sglist[i]))); | ||
250 | } | ||
251 | |||
252 | kfree(dma->sglist); | ||
253 | dma->sglist = NULL; | ||
254 | } | ||
255 | |||
256 | /* Release all memory related to the videobuf_queue. */ | ||
257 | static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq) | ||
258 | { | ||
259 | int i; | ||
260 | |||
261 | mutex_lock(&vbq->vb_lock); | ||
262 | |||
263 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | ||
264 | if (NULL == vbq->bufs[i]) | ||
265 | continue; | ||
266 | if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory) | ||
267 | continue; | ||
268 | vbq->ops->buf_release(vbq, vbq->bufs[i]); | ||
269 | omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]); | ||
270 | kfree(vbq->bufs[i]); | ||
271 | vbq->bufs[i] = NULL; | ||
272 | } | ||
273 | |||
274 | mutex_unlock(&vbq->vb_lock); | ||
275 | |||
276 | videobuf_mmap_free(vbq); | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * Allocate physically as contiguous as possible buffer for video | ||
281 | * frame and allocate and build DMA scatter-gather list for it. | ||
282 | */ | ||
283 | static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb) | ||
284 | { | ||
285 | unsigned int order; | ||
286 | size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */ | ||
287 | struct page *page; | ||
288 | int max_pages, err = 0, i = 0; | ||
289 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
290 | |||
291 | /* | ||
292 | * allocate maximum size scatter-gather list. Note this is | ||
293 | * overhead. We may not use as many entries as we allocate | ||
294 | */ | ||
295 | max_pages = vb->bsize >> PAGE_SHIFT; | ||
296 | dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL); | ||
297 | if (dma->sglist == NULL) { | ||
298 | err = -ENOMEM; | ||
299 | goto out; | ||
300 | } | ||
301 | |||
302 | while (size) { | ||
303 | order = get_order(size); | ||
304 | /* | ||
305 | * do not over-allocate even if we would get larger | ||
306 | * contiguous chunk that way | ||
307 | */ | ||
308 | if ((PAGE_SIZE << order) > size) | ||
309 | order--; | ||
310 | |||
311 | /* try to allocate as many contiguous pages as possible */ | ||
312 | page = alloc_pages(GFP_KERNEL, order); | ||
313 | /* if allocation fails, try to allocate smaller amount */ | ||
314 | while (page == NULL) { | ||
315 | order--; | ||
316 | page = alloc_pages(GFP_KERNEL, order); | ||
317 | if (page == NULL && !order) { | ||
318 | err = -ENOMEM; | ||
319 | goto out; | ||
320 | } | ||
321 | } | ||
322 | size -= (PAGE_SIZE << order); | ||
323 | |||
324 | /* append allocated chunk of pages into scatter-gather list */ | ||
325 | sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0); | ||
326 | dma->sglen++; | ||
327 | i++; | ||
328 | |||
329 | alloc_size = (PAGE_SIZE << order); | ||
330 | |||
331 | /* clear pages before giving them to user space */ | ||
332 | memset(page_address(page), 0, alloc_size); | ||
333 | |||
334 | /* mark allocated pages reserved */ | ||
335 | do { | ||
336 | SetPageReserved(page++); | ||
337 | } while (alloc_size -= PAGE_SIZE); | ||
338 | } | ||
339 | /* | ||
340 | * REVISIT: not fully correct to assign nr_pages == sglen but | ||
341 | * video-buf is passing nr_pages for e.g. unmap_sg calls | ||
342 | */ | ||
343 | dma->nr_pages = dma->sglen; | ||
344 | dma->direction = PCI_DMA_FROMDEVICE; | ||
345 | |||
346 | return 0; | ||
347 | |||
348 | out: | ||
349 | omap24xxcam_vbq_free_mmap_buffer(vb); | ||
350 | return err; | ||
351 | } | ||
352 | |||
353 | static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq, | ||
354 | unsigned int count) | ||
355 | { | ||
356 | int i, err = 0; | ||
357 | struct omap24xxcam_fh *fh = | ||
358 | container_of(vbq, struct omap24xxcam_fh, vbq); | ||
359 | |||
360 | mutex_lock(&vbq->vb_lock); | ||
361 | |||
362 | for (i = 0; i < count; i++) { | ||
363 | err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]); | ||
364 | if (err) | ||
365 | goto out; | ||
366 | dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n", | ||
367 | videobuf_to_dma(vbq->bufs[i])->sglen, i); | ||
368 | } | ||
369 | |||
370 | mutex_unlock(&vbq->vb_lock); | ||
371 | |||
372 | return 0; | ||
373 | out: | ||
374 | while (i) { | ||
375 | i--; | ||
376 | omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]); | ||
377 | } | ||
378 | |||
379 | mutex_unlock(&vbq->vb_lock); | ||
380 | |||
381 | return err; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * This routine is called from interrupt context when a scatter-gather DMA | ||
386 | * transfer of a videobuf_buffer completes. | ||
387 | */ | ||
388 | static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma, | ||
389 | u32 csr, void *arg) | ||
390 | { | ||
391 | struct omap24xxcam_device *cam = | ||
392 | container_of(sgdma, struct omap24xxcam_device, sgdma); | ||
393 | struct omap24xxcam_fh *fh = cam->streaming->private_data; | ||
394 | struct videobuf_buffer *vb = (struct videobuf_buffer *)arg; | ||
395 | const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR | ||
396 | | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR | ||
397 | | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; | ||
398 | unsigned long flags; | ||
399 | |||
400 | spin_lock_irqsave(&cam->core_enable_disable_lock, flags); | ||
401 | if (--cam->sgdma_in_queue == 0) | ||
402 | omap24xxcam_core_disable(cam); | ||
403 | spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); | ||
404 | |||
405 | v4l2_get_timestamp(&vb->ts); | ||
406 | vb->field_count = atomic_add_return(2, &fh->field_count); | ||
407 | if (csr & csr_error) { | ||
408 | vb->state = VIDEOBUF_ERROR; | ||
409 | if (!atomic_read(&fh->cam->in_reset)) { | ||
410 | dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr); | ||
411 | omap24xxcam_reset(cam); | ||
412 | } | ||
413 | } else | ||
414 | vb->state = VIDEOBUF_DONE; | ||
415 | wake_up(&vb->done); | ||
416 | } | ||
417 | |||
418 | static void omap24xxcam_vbq_release(struct videobuf_queue *vbq, | ||
419 | struct videobuf_buffer *vb) | ||
420 | { | ||
421 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
422 | |||
423 | /* wait for buffer, especially to get out of the sgdma queue */ | ||
424 | videobuf_waiton(vbq, vb, 0, 0); | ||
425 | if (vb->memory == V4L2_MEMORY_MMAP) { | ||
426 | dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen, | ||
427 | dma->direction); | ||
428 | dma->direction = DMA_NONE; | ||
429 | } else { | ||
430 | videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb)); | ||
431 | videobuf_dma_free(videobuf_to_dma(vb)); | ||
432 | } | ||
433 | |||
434 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
435 | } | ||
436 | |||
437 | /* | ||
438 | * Limit the number of available kernel image capture buffers based on the | ||
439 | * number requested, the currently selected image size, and the maximum | ||
440 | * amount of memory permitted for kernel capture buffers. | ||
441 | */ | ||
442 | static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt, | ||
443 | unsigned int *size) | ||
444 | { | ||
445 | struct omap24xxcam_fh *fh = vbq->priv_data; | ||
446 | |||
447 | if (*cnt <= 0) | ||
448 | *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */ | ||
449 | |||
450 | if (*cnt > VIDEO_MAX_FRAME) | ||
451 | *cnt = VIDEO_MAX_FRAME; | ||
452 | |||
453 | *size = fh->pix.sizeimage; | ||
454 | |||
455 | /* accessing fh->cam->capture_mem is ok, it's constant */ | ||
456 | if (*size * *cnt > fh->cam->capture_mem) | ||
457 | *cnt = fh->cam->capture_mem / *size; | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq, | ||
463 | struct videobuf_dmabuf *dma) | ||
464 | { | ||
465 | int err = 0; | ||
466 | |||
467 | dma->direction = PCI_DMA_FROMDEVICE; | ||
468 | if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) { | ||
469 | kfree(dma->sglist); | ||
470 | dma->sglist = NULL; | ||
471 | dma->sglen = 0; | ||
472 | err = -EIO; | ||
473 | } | ||
474 | |||
475 | return err; | ||
476 | } | ||
477 | |||
478 | static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq, | ||
479 | struct videobuf_buffer *vb, | ||
480 | enum v4l2_field field) | ||
481 | { | ||
482 | struct omap24xxcam_fh *fh = vbq->priv_data; | ||
483 | int err = 0; | ||
484 | |||
485 | /* | ||
486 | * Accessing pix here is okay since it's constant while | ||
487 | * streaming is on (and we only get called then). | ||
488 | */ | ||
489 | if (vb->baddr) { | ||
490 | /* This is a userspace buffer. */ | ||
491 | if (fh->pix.sizeimage > vb->bsize) { | ||
492 | /* The buffer isn't big enough. */ | ||
493 | err = -EINVAL; | ||
494 | } else | ||
495 | vb->size = fh->pix.sizeimage; | ||
496 | } else { | ||
497 | if (vb->state != VIDEOBUF_NEEDS_INIT) { | ||
498 | /* | ||
499 | * We have a kernel bounce buffer that has | ||
500 | * already been allocated. | ||
501 | */ | ||
502 | if (fh->pix.sizeimage > vb->size) { | ||
503 | /* | ||
504 | * The image size has been changed to | ||
505 | * a larger size since this buffer was | ||
506 | * allocated, so we need to free and | ||
507 | * reallocate it. | ||
508 | */ | ||
509 | omap24xxcam_vbq_release(vbq, vb); | ||
510 | vb->size = fh->pix.sizeimage; | ||
511 | } | ||
512 | } else { | ||
513 | /* We need to allocate a new kernel bounce buffer. */ | ||
514 | vb->size = fh->pix.sizeimage; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | if (err) | ||
519 | return err; | ||
520 | |||
521 | vb->width = fh->pix.width; | ||
522 | vb->height = fh->pix.height; | ||
523 | vb->field = field; | ||
524 | |||
525 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
526 | if (vb->memory == V4L2_MEMORY_MMAP) | ||
527 | /* | ||
528 | * we have built the scatter-gather list by ourself so | ||
529 | * do the scatter-gather mapping as well | ||
530 | */ | ||
531 | err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb)); | ||
532 | else | ||
533 | err = videobuf_iolock(vbq, vb, NULL); | ||
534 | } | ||
535 | |||
536 | if (!err) | ||
537 | vb->state = VIDEOBUF_PREPARED; | ||
538 | else | ||
539 | omap24xxcam_vbq_release(vbq, vb); | ||
540 | |||
541 | return err; | ||
542 | } | ||
543 | |||
544 | static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq, | ||
545 | struct videobuf_buffer *vb) | ||
546 | { | ||
547 | struct omap24xxcam_fh *fh = vbq->priv_data; | ||
548 | struct omap24xxcam_device *cam = fh->cam; | ||
549 | enum videobuf_state state = vb->state; | ||
550 | unsigned long flags; | ||
551 | int err; | ||
552 | |||
553 | /* | ||
554 | * FIXME: We're marking the buffer active since we have no | ||
555 | * pretty way of marking it active exactly when the | ||
556 | * scatter-gather transfer starts. | ||
557 | */ | ||
558 | vb->state = VIDEOBUF_ACTIVE; | ||
559 | |||
560 | err = omap24xxcam_sgdma_queue(&fh->cam->sgdma, | ||
561 | videobuf_to_dma(vb)->sglist, | ||
562 | videobuf_to_dma(vb)->sglen, vb->size, | ||
563 | omap24xxcam_vbq_complete, vb); | ||
564 | |||
565 | if (!err) { | ||
566 | spin_lock_irqsave(&cam->core_enable_disable_lock, flags); | ||
567 | if (++cam->sgdma_in_queue == 1 | ||
568 | && !atomic_read(&cam->in_reset)) | ||
569 | omap24xxcam_core_enable(cam); | ||
570 | spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); | ||
571 | } else { | ||
572 | /* | ||
573 | * Oops. We're not supposed to get any errors here. | ||
574 | * The only way we could get an error is if we ran out | ||
575 | * of scatter-gather DMA slots, but we are supposed to | ||
576 | * have at least as many scatter-gather DMA slots as | ||
577 | * video buffers so that can't happen. | ||
578 | */ | ||
579 | dev_err(cam->dev, "failed to queue a video buffer for dma!\n"); | ||
580 | dev_err(cam->dev, "likely a bug in the driver!\n"); | ||
581 | vb->state = state; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | static struct videobuf_queue_ops omap24xxcam_vbq_ops = { | ||
586 | .buf_setup = omap24xxcam_vbq_setup, | ||
587 | .buf_prepare = omap24xxcam_vbq_prepare, | ||
588 | .buf_queue = omap24xxcam_vbq_queue, | ||
589 | .buf_release = omap24xxcam_vbq_release, | ||
590 | }; | ||
591 | |||
592 | /* | ||
593 | * | ||
594 | * OMAP main camera system | ||
595 | * | ||
596 | */ | ||
597 | |||
598 | /* | ||
599 | * Reset camera block to power-on state. | ||
600 | */ | ||
601 | static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam) | ||
602 | { | ||
603 | int max_loop = RESET_TIMEOUT_NS; | ||
604 | |||
605 | /* Reset whole camera subsystem */ | ||
606 | omap24xxcam_reg_out(cam->mmio_base, | ||
607 | CAM_SYSCONFIG, | ||
608 | CAM_SYSCONFIG_SOFTRESET); | ||
609 | |||
610 | /* Wait till it's finished */ | ||
611 | while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS) | ||
612 | & CAM_SYSSTATUS_RESETDONE) | ||
613 | && --max_loop) { | ||
614 | ndelay(1); | ||
615 | } | ||
616 | |||
617 | if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS) | ||
618 | & CAM_SYSSTATUS_RESETDONE)) | ||
619 | dev_err(cam->dev, "camera soft reset timeout\n"); | ||
620 | } | ||
621 | |||
622 | /* | ||
623 | * (Re)initialise the camera block. | ||
624 | */ | ||
625 | static void omap24xxcam_hwinit(struct omap24xxcam_device *cam) | ||
626 | { | ||
627 | omap24xxcam_poweron_reset(cam); | ||
628 | |||
629 | /* set the camera subsystem autoidle bit */ | ||
630 | omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG, | ||
631 | CAM_SYSCONFIG_AUTOIDLE); | ||
632 | |||
633 | /* set the camera MMU autoidle bit */ | ||
634 | omap24xxcam_reg_out(cam->mmio_base, | ||
635 | CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG, | ||
636 | CAMMMU_SYSCONFIG_AUTOIDLE); | ||
637 | |||
638 | omap24xxcam_core_hwinit(cam); | ||
639 | |||
640 | omap24xxcam_dma_hwinit(&cam->sgdma.dma); | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * Callback for dma transfer stalling. | ||
645 | */ | ||
646 | static void omap24xxcam_stalled_dma_reset(unsigned long data) | ||
647 | { | ||
648 | struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data; | ||
649 | |||
650 | if (!atomic_read(&cam->in_reset)) { | ||
651 | dev_dbg(cam->dev, "dma stalled, resetting camera\n"); | ||
652 | omap24xxcam_reset(cam); | ||
653 | } | ||
654 | } | ||
655 | |||
656 | /* | ||
657 | * Stop capture. Mark we're doing a reset, stop DMA transfers and | ||
658 | * core. (No new scatter-gather transfers will be queued whilst | ||
659 | * in_reset is non-zero.) | ||
660 | * | ||
661 | * If omap24xxcam_capture_stop is called from several places at | ||
662 | * once, only the first call will have an effect. Similarly, the last | ||
663 | * call omap24xxcam_streaming_cont will have effect. | ||
664 | * | ||
665 | * Serialisation is ensured by using cam->core_enable_disable_lock. | ||
666 | */ | ||
667 | static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam) | ||
668 | { | ||
669 | unsigned long flags; | ||
670 | |||
671 | spin_lock_irqsave(&cam->core_enable_disable_lock, flags); | ||
672 | |||
673 | if (atomic_inc_return(&cam->in_reset) != 1) { | ||
674 | spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); | ||
675 | return; | ||
676 | } | ||
677 | |||
678 | omap24xxcam_core_disable(cam); | ||
679 | |||
680 | spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); | ||
681 | |||
682 | omap24xxcam_sgdma_sync(&cam->sgdma); | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * Reset and continue streaming. | ||
687 | * | ||
688 | * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL | ||
689 | * register is supposed to be sufficient to recover from a camera | ||
690 | * interface error, but it doesn't seem to be enough. If we only do | ||
691 | * that then subsequent image captures are out of sync by either one | ||
692 | * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the | ||
693 | * entire camera subsystem prevents the problem with frame | ||
694 | * synchronization. | ||
695 | */ | ||
696 | static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam) | ||
697 | { | ||
698 | unsigned long flags; | ||
699 | |||
700 | spin_lock_irqsave(&cam->core_enable_disable_lock, flags); | ||
701 | |||
702 | if (atomic_read(&cam->in_reset) != 1) | ||
703 | goto out; | ||
704 | |||
705 | omap24xxcam_hwinit(cam); | ||
706 | |||
707 | omap24xxcam_sensor_if_enable(cam); | ||
708 | |||
709 | omap24xxcam_sgdma_process(&cam->sgdma); | ||
710 | |||
711 | if (cam->sgdma_in_queue) | ||
712 | omap24xxcam_core_enable(cam); | ||
713 | |||
714 | out: | ||
715 | atomic_dec(&cam->in_reset); | ||
716 | spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); | ||
717 | } | ||
718 | |||
719 | static ssize_t | ||
720 | omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr, | ||
721 | char *buf) | ||
722 | { | ||
723 | struct omap24xxcam_device *cam = dev_get_drvdata(dev); | ||
724 | |||
725 | return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive"); | ||
726 | } | ||
727 | static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL); | ||
728 | |||
729 | /* | ||
730 | * Stop capture and restart it. I.e. reset the camera during use. | ||
731 | */ | ||
732 | static void omap24xxcam_reset(struct omap24xxcam_device *cam) | ||
733 | { | ||
734 | omap24xxcam_capture_stop(cam); | ||
735 | omap24xxcam_capture_cont(cam); | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * The main interrupt handler. | ||
740 | */ | ||
741 | static irqreturn_t omap24xxcam_isr(int irq, void *arg) | ||
742 | { | ||
743 | struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg; | ||
744 | u32 irqstatus; | ||
745 | unsigned int irqhandled = 0; | ||
746 | |||
747 | irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS); | ||
748 | |||
749 | if (irqstatus & | ||
750 | (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1 | ||
751 | | CAM_IRQSTATUS_DMA_IRQ0)) { | ||
752 | omap24xxcam_dma_isr(&cam->sgdma.dma); | ||
753 | irqhandled = 1; | ||
754 | } | ||
755 | if (irqstatus & CAM_IRQSTATUS_CC_IRQ) { | ||
756 | omap24xxcam_core_isr(cam); | ||
757 | irqhandled = 1; | ||
758 | } | ||
759 | if (irqstatus & CAM_IRQSTATUS_MMU_IRQ) | ||
760 | dev_err(cam->dev, "unhandled camera MMU interrupt!\n"); | ||
761 | |||
762 | return IRQ_RETVAL(irqhandled); | ||
763 | } | ||
764 | |||
765 | /* | ||
766 | * | ||
767 | * Sensor handling. | ||
768 | * | ||
769 | */ | ||
770 | |||
771 | /* | ||
772 | * Enable the external sensor interface. Try to negotiate interface | ||
773 | * parameters with the sensor and start using the new ones. The calls | ||
774 | * to sensor_if_enable and sensor_if_disable need not to be balanced. | ||
775 | */ | ||
776 | static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam) | ||
777 | { | ||
778 | int rval; | ||
779 | struct v4l2_ifparm p; | ||
780 | |||
781 | rval = vidioc_int_g_ifparm(cam->sdev, &p); | ||
782 | if (rval) { | ||
783 | dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval); | ||
784 | return rval; | ||
785 | } | ||
786 | |||
787 | cam->if_type = p.if_type; | ||
788 | |||
789 | cam->cc_ctrl = CC_CTRL_CC_EN; | ||
790 | |||
791 | switch (p.if_type) { | ||
792 | case V4L2_IF_TYPE_BT656: | ||
793 | if (p.u.bt656.frame_start_on_rising_vs) | ||
794 | cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO; | ||
795 | if (p.u.bt656.bt_sync_correct) | ||
796 | cam->cc_ctrl |= CC_CTRL_BT_CORRECT; | ||
797 | if (p.u.bt656.swap) | ||
798 | cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM; | ||
799 | if (p.u.bt656.latch_clk_inv) | ||
800 | cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL; | ||
801 | if (p.u.bt656.nobt_hs_inv) | ||
802 | cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL; | ||
803 | if (p.u.bt656.nobt_vs_inv) | ||
804 | cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL; | ||
805 | |||
806 | switch (p.u.bt656.mode) { | ||
807 | case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT: | ||
808 | cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8; | ||
809 | break; | ||
810 | case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT: | ||
811 | cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10; | ||
812 | break; | ||
813 | case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT: | ||
814 | cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12; | ||
815 | break; | ||
816 | case V4L2_IF_TYPE_BT656_MODE_BT_8BIT: | ||
817 | cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8; | ||
818 | break; | ||
819 | case V4L2_IF_TYPE_BT656_MODE_BT_10BIT: | ||
820 | cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10; | ||
821 | break; | ||
822 | default: | ||
823 | dev_err(cam->dev, | ||
824 | "bt656 interface mode %d not supported\n", | ||
825 | p.u.bt656.mode); | ||
826 | return -EINVAL; | ||
827 | } | ||
828 | /* | ||
829 | * The clock rate that the sensor wants has changed. | ||
830 | * We have to adjust the xclk from OMAP 2 side to | ||
831 | * match the sensor's wish as closely as possible. | ||
832 | */ | ||
833 | if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) { | ||
834 | u32 xclk = p.u.bt656.clock_curr; | ||
835 | u32 divisor; | ||
836 | |||
837 | if (xclk == 0) | ||
838 | return -EINVAL; | ||
839 | |||
840 | if (xclk > CAM_MCLK) | ||
841 | xclk = CAM_MCLK; | ||
842 | |||
843 | divisor = CAM_MCLK / xclk; | ||
844 | if (divisor * xclk < CAM_MCLK) | ||
845 | divisor++; | ||
846 | if (CAM_MCLK / divisor < p.u.bt656.clock_min | ||
847 | && divisor > 1) | ||
848 | divisor--; | ||
849 | if (divisor > 30) | ||
850 | divisor = 30; | ||
851 | |||
852 | xclk = CAM_MCLK / divisor; | ||
853 | |||
854 | if (xclk < p.u.bt656.clock_min | ||
855 | || xclk > p.u.bt656.clock_max) | ||
856 | return -EINVAL; | ||
857 | |||
858 | cam->if_u.bt656.xclk = xclk; | ||
859 | } | ||
860 | omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk); | ||
861 | break; | ||
862 | default: | ||
863 | /* FIXME: how about other interfaces? */ | ||
864 | dev_err(cam->dev, "interface type %d not supported\n", | ||
865 | p.if_type); | ||
866 | return -EINVAL; | ||
867 | } | ||
868 | |||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam) | ||
873 | { | ||
874 | switch (cam->if_type) { | ||
875 | case V4L2_IF_TYPE_BT656: | ||
876 | omap24xxcam_core_xclk_set(cam, 0); | ||
877 | break; | ||
878 | } | ||
879 | } | ||
880 | |||
881 | /* | ||
882 | * Initialise the sensor hardware. | ||
883 | */ | ||
884 | static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam) | ||
885 | { | ||
886 | int err = 0; | ||
887 | struct v4l2_int_device *sdev = cam->sdev; | ||
888 | |||
889 | omap24xxcam_clock_on(cam); | ||
890 | err = omap24xxcam_sensor_if_enable(cam); | ||
891 | if (err) { | ||
892 | dev_err(cam->dev, "sensor interface could not be enabled at " | ||
893 | "initialisation, %d\n", err); | ||
894 | cam->sdev = NULL; | ||
895 | goto out; | ||
896 | } | ||
897 | |||
898 | /* power up sensor during sensor initialization */ | ||
899 | vidioc_int_s_power(sdev, 1); | ||
900 | |||
901 | err = vidioc_int_dev_init(sdev); | ||
902 | if (err) { | ||
903 | dev_err(cam->dev, "cannot initialize sensor, error %d\n", err); | ||
904 | /* Sensor init failed --- it's nonexistent to us! */ | ||
905 | cam->sdev = NULL; | ||
906 | goto out; | ||
907 | } | ||
908 | |||
909 | dev_info(cam->dev, "sensor is %s\n", sdev->name); | ||
910 | |||
911 | out: | ||
912 | omap24xxcam_sensor_if_disable(cam); | ||
913 | omap24xxcam_clock_off(cam); | ||
914 | |||
915 | vidioc_int_s_power(sdev, 0); | ||
916 | |||
917 | return err; | ||
918 | } | ||
919 | |||
920 | static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam) | ||
921 | { | ||
922 | if (cam->sdev) | ||
923 | vidioc_int_dev_exit(cam->sdev); | ||
924 | } | ||
925 | |||
926 | static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam) | ||
927 | { | ||
928 | omap24xxcam_sensor_if_disable(cam); | ||
929 | omap24xxcam_clock_off(cam); | ||
930 | vidioc_int_s_power(cam->sdev, 0); | ||
931 | } | ||
932 | |||
933 | /* | ||
934 | * Power-up and configure camera sensor. It's ready for capturing now. | ||
935 | */ | ||
936 | static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam) | ||
937 | { | ||
938 | int rval; | ||
939 | |||
940 | omap24xxcam_clock_on(cam); | ||
941 | |||
942 | omap24xxcam_sensor_if_enable(cam); | ||
943 | |||
944 | rval = vidioc_int_s_power(cam->sdev, 1); | ||
945 | if (rval) | ||
946 | goto out; | ||
947 | |||
948 | rval = vidioc_int_init(cam->sdev); | ||
949 | if (rval) | ||
950 | goto out; | ||
951 | |||
952 | return 0; | ||
953 | |||
954 | out: | ||
955 | omap24xxcam_sensor_disable(cam); | ||
956 | |||
957 | return rval; | ||
958 | } | ||
959 | |||
960 | static void omap24xxcam_sensor_reset_work(struct work_struct *work) | ||
961 | { | ||
962 | struct omap24xxcam_device *cam = | ||
963 | container_of(work, struct omap24xxcam_device, | ||
964 | sensor_reset_work); | ||
965 | |||
966 | if (atomic_read(&cam->reset_disable)) | ||
967 | return; | ||
968 | |||
969 | omap24xxcam_capture_stop(cam); | ||
970 | |||
971 | if (vidioc_int_reset(cam->sdev) == 0) { | ||
972 | vidioc_int_init(cam->sdev); | ||
973 | } else { | ||
974 | /* Can't reset it by vidioc_int_reset. */ | ||
975 | omap24xxcam_sensor_disable(cam); | ||
976 | omap24xxcam_sensor_enable(cam); | ||
977 | } | ||
978 | |||
979 | omap24xxcam_capture_cont(cam); | ||
980 | } | ||
981 | |||
982 | /* | ||
983 | * | ||
984 | * IOCTL interface. | ||
985 | * | ||
986 | */ | ||
987 | |||
988 | static int vidioc_querycap(struct file *file, void *fh, | ||
989 | struct v4l2_capability *cap) | ||
990 | { | ||
991 | struct omap24xxcam_fh *ofh = fh; | ||
992 | struct omap24xxcam_device *cam = ofh->cam; | ||
993 | |||
994 | strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver)); | ||
995 | strlcpy(cap->card, cam->vfd->name, sizeof(cap->card)); | ||
996 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, | ||
1002 | struct v4l2_fmtdesc *f) | ||
1003 | { | ||
1004 | struct omap24xxcam_fh *ofh = fh; | ||
1005 | struct omap24xxcam_device *cam = ofh->cam; | ||
1006 | int rval; | ||
1007 | |||
1008 | rval = vidioc_int_enum_fmt_cap(cam->sdev, f); | ||
1009 | |||
1010 | return rval; | ||
1011 | } | ||
1012 | |||
1013 | static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, | ||
1014 | struct v4l2_format *f) | ||
1015 | { | ||
1016 | struct omap24xxcam_fh *ofh = fh; | ||
1017 | struct omap24xxcam_device *cam = ofh->cam; | ||
1018 | int rval; | ||
1019 | |||
1020 | mutex_lock(&cam->mutex); | ||
1021 | rval = vidioc_int_g_fmt_cap(cam->sdev, f); | ||
1022 | mutex_unlock(&cam->mutex); | ||
1023 | |||
1024 | return rval; | ||
1025 | } | ||
1026 | |||
1027 | static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, | ||
1028 | struct v4l2_format *f) | ||
1029 | { | ||
1030 | struct omap24xxcam_fh *ofh = fh; | ||
1031 | struct omap24xxcam_device *cam = ofh->cam; | ||
1032 | int rval; | ||
1033 | |||
1034 | mutex_lock(&cam->mutex); | ||
1035 | if (cam->streaming) { | ||
1036 | rval = -EBUSY; | ||
1037 | goto out; | ||
1038 | } | ||
1039 | |||
1040 | rval = vidioc_int_s_fmt_cap(cam->sdev, f); | ||
1041 | |||
1042 | out: | ||
1043 | mutex_unlock(&cam->mutex); | ||
1044 | |||
1045 | if (!rval) { | ||
1046 | mutex_lock(&ofh->vbq.vb_lock); | ||
1047 | ofh->pix = f->fmt.pix; | ||
1048 | mutex_unlock(&ofh->vbq.vb_lock); | ||
1049 | } | ||
1050 | |||
1051 | memset(f, 0, sizeof(*f)); | ||
1052 | vidioc_g_fmt_vid_cap(file, fh, f); | ||
1053 | |||
1054 | return rval; | ||
1055 | } | ||
1056 | |||
1057 | static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, | ||
1058 | struct v4l2_format *f) | ||
1059 | { | ||
1060 | struct omap24xxcam_fh *ofh = fh; | ||
1061 | struct omap24xxcam_device *cam = ofh->cam; | ||
1062 | int rval; | ||
1063 | |||
1064 | mutex_lock(&cam->mutex); | ||
1065 | rval = vidioc_int_try_fmt_cap(cam->sdev, f); | ||
1066 | mutex_unlock(&cam->mutex); | ||
1067 | |||
1068 | return rval; | ||
1069 | } | ||
1070 | |||
1071 | static int vidioc_reqbufs(struct file *file, void *fh, | ||
1072 | struct v4l2_requestbuffers *b) | ||
1073 | { | ||
1074 | struct omap24xxcam_fh *ofh = fh; | ||
1075 | struct omap24xxcam_device *cam = ofh->cam; | ||
1076 | int rval; | ||
1077 | |||
1078 | mutex_lock(&cam->mutex); | ||
1079 | if (cam->streaming) { | ||
1080 | mutex_unlock(&cam->mutex); | ||
1081 | return -EBUSY; | ||
1082 | } | ||
1083 | |||
1084 | omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq); | ||
1085 | mutex_unlock(&cam->mutex); | ||
1086 | |||
1087 | rval = videobuf_reqbufs(&ofh->vbq, b); | ||
1088 | |||
1089 | /* | ||
1090 | * Either videobuf_reqbufs failed or the buffers are not | ||
1091 | * memory-mapped (which would need special attention). | ||
1092 | */ | ||
1093 | if (rval < 0 || b->memory != V4L2_MEMORY_MMAP) | ||
1094 | goto out; | ||
1095 | |||
1096 | rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval); | ||
1097 | if (rval) | ||
1098 | omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq); | ||
1099 | |||
1100 | out: | ||
1101 | return rval; | ||
1102 | } | ||
1103 | |||
1104 | static int vidioc_querybuf(struct file *file, void *fh, | ||
1105 | struct v4l2_buffer *b) | ||
1106 | { | ||
1107 | struct omap24xxcam_fh *ofh = fh; | ||
1108 | |||
1109 | return videobuf_querybuf(&ofh->vbq, b); | ||
1110 | } | ||
1111 | |||
1112 | static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) | ||
1113 | { | ||
1114 | struct omap24xxcam_fh *ofh = fh; | ||
1115 | |||
1116 | return videobuf_qbuf(&ofh->vbq, b); | ||
1117 | } | ||
1118 | |||
1119 | static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) | ||
1120 | { | ||
1121 | struct omap24xxcam_fh *ofh = fh; | ||
1122 | struct omap24xxcam_device *cam = ofh->cam; | ||
1123 | struct videobuf_buffer *vb; | ||
1124 | int rval; | ||
1125 | |||
1126 | videobuf_dqbuf_again: | ||
1127 | rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK); | ||
1128 | if (rval) | ||
1129 | goto out; | ||
1130 | |||
1131 | vb = ofh->vbq.bufs[b->index]; | ||
1132 | |||
1133 | mutex_lock(&cam->mutex); | ||
1134 | /* _needs_reset returns -EIO if reset is required. */ | ||
1135 | rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr); | ||
1136 | mutex_unlock(&cam->mutex); | ||
1137 | if (rval == -EIO) | ||
1138 | schedule_work(&cam->sensor_reset_work); | ||
1139 | else | ||
1140 | rval = 0; | ||
1141 | |||
1142 | out: | ||
1143 | /* | ||
1144 | * This is a hack. We don't want to show -EIO to the user | ||
1145 | * space. Requeue the buffer and try again if we're not doing | ||
1146 | * this in non-blocking mode. | ||
1147 | */ | ||
1148 | if (rval == -EIO) { | ||
1149 | videobuf_qbuf(&ofh->vbq, b); | ||
1150 | if (!(file->f_flags & O_NONBLOCK)) | ||
1151 | goto videobuf_dqbuf_again; | ||
1152 | /* | ||
1153 | * We don't have a videobuf_buffer now --- maybe next | ||
1154 | * time... | ||
1155 | */ | ||
1156 | rval = -EAGAIN; | ||
1157 | } | ||
1158 | |||
1159 | return rval; | ||
1160 | } | ||
1161 | |||
1162 | static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) | ||
1163 | { | ||
1164 | struct omap24xxcam_fh *ofh = fh; | ||
1165 | struct omap24xxcam_device *cam = ofh->cam; | ||
1166 | int rval; | ||
1167 | |||
1168 | mutex_lock(&cam->mutex); | ||
1169 | if (cam->streaming) { | ||
1170 | rval = -EBUSY; | ||
1171 | goto out; | ||
1172 | } | ||
1173 | |||
1174 | rval = omap24xxcam_sensor_if_enable(cam); | ||
1175 | if (rval) { | ||
1176 | dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n"); | ||
1177 | goto out; | ||
1178 | } | ||
1179 | |||
1180 | rval = videobuf_streamon(&ofh->vbq); | ||
1181 | if (!rval) { | ||
1182 | cam->streaming = file; | ||
1183 | sysfs_notify(&cam->dev->kobj, NULL, "streaming"); | ||
1184 | } | ||
1185 | |||
1186 | out: | ||
1187 | mutex_unlock(&cam->mutex); | ||
1188 | |||
1189 | return rval; | ||
1190 | } | ||
1191 | |||
1192 | static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) | ||
1193 | { | ||
1194 | struct omap24xxcam_fh *ofh = fh; | ||
1195 | struct omap24xxcam_device *cam = ofh->cam; | ||
1196 | struct videobuf_queue *q = &ofh->vbq; | ||
1197 | int rval; | ||
1198 | |||
1199 | atomic_inc(&cam->reset_disable); | ||
1200 | |||
1201 | flush_work(&cam->sensor_reset_work); | ||
1202 | |||
1203 | rval = videobuf_streamoff(q); | ||
1204 | if (!rval) { | ||
1205 | mutex_lock(&cam->mutex); | ||
1206 | cam->streaming = NULL; | ||
1207 | mutex_unlock(&cam->mutex); | ||
1208 | sysfs_notify(&cam->dev->kobj, NULL, "streaming"); | ||
1209 | } | ||
1210 | |||
1211 | atomic_dec(&cam->reset_disable); | ||
1212 | |||
1213 | return rval; | ||
1214 | } | ||
1215 | |||
1216 | static int vidioc_enum_input(struct file *file, void *fh, | ||
1217 | struct v4l2_input *inp) | ||
1218 | { | ||
1219 | if (inp->index > 0) | ||
1220 | return -EINVAL; | ||
1221 | |||
1222 | strlcpy(inp->name, "camera", sizeof(inp->name)); | ||
1223 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
1224 | |||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) | ||
1229 | { | ||
1230 | *i = 0; | ||
1231 | |||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1235 | static int vidioc_s_input(struct file *file, void *fh, unsigned int i) | ||
1236 | { | ||
1237 | if (i > 0) | ||
1238 | return -EINVAL; | ||
1239 | |||
1240 | return 0; | ||
1241 | } | ||
1242 | |||
1243 | static int vidioc_queryctrl(struct file *file, void *fh, | ||
1244 | struct v4l2_queryctrl *a) | ||
1245 | { | ||
1246 | struct omap24xxcam_fh *ofh = fh; | ||
1247 | struct omap24xxcam_device *cam = ofh->cam; | ||
1248 | int rval; | ||
1249 | |||
1250 | rval = vidioc_int_queryctrl(cam->sdev, a); | ||
1251 | |||
1252 | return rval; | ||
1253 | } | ||
1254 | |||
1255 | static int vidioc_g_ctrl(struct file *file, void *fh, | ||
1256 | struct v4l2_control *a) | ||
1257 | { | ||
1258 | struct omap24xxcam_fh *ofh = fh; | ||
1259 | struct omap24xxcam_device *cam = ofh->cam; | ||
1260 | int rval; | ||
1261 | |||
1262 | mutex_lock(&cam->mutex); | ||
1263 | rval = vidioc_int_g_ctrl(cam->sdev, a); | ||
1264 | mutex_unlock(&cam->mutex); | ||
1265 | |||
1266 | return rval; | ||
1267 | } | ||
1268 | |||
1269 | static int vidioc_s_ctrl(struct file *file, void *fh, | ||
1270 | struct v4l2_control *a) | ||
1271 | { | ||
1272 | struct omap24xxcam_fh *ofh = fh; | ||
1273 | struct omap24xxcam_device *cam = ofh->cam; | ||
1274 | int rval; | ||
1275 | |||
1276 | mutex_lock(&cam->mutex); | ||
1277 | rval = vidioc_int_s_ctrl(cam->sdev, a); | ||
1278 | mutex_unlock(&cam->mutex); | ||
1279 | |||
1280 | return rval; | ||
1281 | } | ||
1282 | |||
1283 | static int vidioc_g_parm(struct file *file, void *fh, | ||
1284 | struct v4l2_streamparm *a) { | ||
1285 | struct omap24xxcam_fh *ofh = fh; | ||
1286 | struct omap24xxcam_device *cam = ofh->cam; | ||
1287 | int rval; | ||
1288 | |||
1289 | mutex_lock(&cam->mutex); | ||
1290 | rval = vidioc_int_g_parm(cam->sdev, a); | ||
1291 | mutex_unlock(&cam->mutex); | ||
1292 | |||
1293 | return rval; | ||
1294 | } | ||
1295 | |||
1296 | static int vidioc_s_parm(struct file *file, void *fh, | ||
1297 | struct v4l2_streamparm *a) | ||
1298 | { | ||
1299 | struct omap24xxcam_fh *ofh = fh; | ||
1300 | struct omap24xxcam_device *cam = ofh->cam; | ||
1301 | struct v4l2_streamparm old_streamparm; | ||
1302 | int rval; | ||
1303 | |||
1304 | mutex_lock(&cam->mutex); | ||
1305 | if (cam->streaming) { | ||
1306 | rval = -EBUSY; | ||
1307 | goto out; | ||
1308 | } | ||
1309 | |||
1310 | old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1311 | rval = vidioc_int_g_parm(cam->sdev, &old_streamparm); | ||
1312 | if (rval) | ||
1313 | goto out; | ||
1314 | |||
1315 | rval = vidioc_int_s_parm(cam->sdev, a); | ||
1316 | if (rval) | ||
1317 | goto out; | ||
1318 | |||
1319 | rval = omap24xxcam_sensor_if_enable(cam); | ||
1320 | /* | ||
1321 | * Revert to old streaming parameters if enabling sensor | ||
1322 | * interface with the new ones failed. | ||
1323 | */ | ||
1324 | if (rval) | ||
1325 | vidioc_int_s_parm(cam->sdev, &old_streamparm); | ||
1326 | |||
1327 | out: | ||
1328 | mutex_unlock(&cam->mutex); | ||
1329 | |||
1330 | return rval; | ||
1331 | } | ||
1332 | |||
1333 | /* | ||
1334 | * | ||
1335 | * File operations. | ||
1336 | * | ||
1337 | */ | ||
1338 | |||
1339 | static unsigned int omap24xxcam_poll(struct file *file, | ||
1340 | struct poll_table_struct *wait) | ||
1341 | { | ||
1342 | struct omap24xxcam_fh *fh = file->private_data; | ||
1343 | struct omap24xxcam_device *cam = fh->cam; | ||
1344 | struct videobuf_buffer *vb; | ||
1345 | |||
1346 | mutex_lock(&cam->mutex); | ||
1347 | if (cam->streaming != file) { | ||
1348 | mutex_unlock(&cam->mutex); | ||
1349 | return POLLERR; | ||
1350 | } | ||
1351 | mutex_unlock(&cam->mutex); | ||
1352 | |||
1353 | mutex_lock(&fh->vbq.vb_lock); | ||
1354 | if (list_empty(&fh->vbq.stream)) { | ||
1355 | mutex_unlock(&fh->vbq.vb_lock); | ||
1356 | return POLLERR; | ||
1357 | } | ||
1358 | vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream); | ||
1359 | mutex_unlock(&fh->vbq.vb_lock); | ||
1360 | |||
1361 | poll_wait(file, &vb->done, wait); | ||
1362 | |||
1363 | if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR) | ||
1364 | return POLLIN | POLLRDNORM; | ||
1365 | |||
1366 | return 0; | ||
1367 | } | ||
1368 | |||
1369 | static int omap24xxcam_mmap_buffers(struct file *file, | ||
1370 | struct vm_area_struct *vma) | ||
1371 | { | ||
1372 | struct omap24xxcam_fh *fh = file->private_data; | ||
1373 | struct omap24xxcam_device *cam = fh->cam; | ||
1374 | struct videobuf_queue *vbq = &fh->vbq; | ||
1375 | unsigned int first, last, size, i, j; | ||
1376 | int err = 0; | ||
1377 | |||
1378 | mutex_lock(&cam->mutex); | ||
1379 | if (cam->streaming) { | ||
1380 | mutex_unlock(&cam->mutex); | ||
1381 | return -EBUSY; | ||
1382 | } | ||
1383 | mutex_unlock(&cam->mutex); | ||
1384 | mutex_lock(&vbq->vb_lock); | ||
1385 | |||
1386 | /* look for first buffer to map */ | ||
1387 | for (first = 0; first < VIDEO_MAX_FRAME; first++) { | ||
1388 | if (NULL == vbq->bufs[first]) | ||
1389 | continue; | ||
1390 | if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory) | ||
1391 | continue; | ||
1392 | if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) | ||
1393 | break; | ||
1394 | } | ||
1395 | |||
1396 | /* look for last buffer to map */ | ||
1397 | for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { | ||
1398 | if (NULL == vbq->bufs[last]) | ||
1399 | continue; | ||
1400 | if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory) | ||
1401 | continue; | ||
1402 | size += vbq->bufs[last]->bsize; | ||
1403 | if (size == (vma->vm_end - vma->vm_start)) | ||
1404 | break; | ||
1405 | } | ||
1406 | |||
1407 | size = 0; | ||
1408 | for (i = first; i <= last && i < VIDEO_MAX_FRAME; i++) { | ||
1409 | struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]); | ||
1410 | |||
1411 | for (j = 0; j < dma->sglen; j++) { | ||
1412 | err = remap_pfn_range( | ||
1413 | vma, vma->vm_start + size, | ||
1414 | page_to_pfn(sg_page(&dma->sglist[j])), | ||
1415 | sg_dma_len(&dma->sglist[j]), vma->vm_page_prot); | ||
1416 | if (err) | ||
1417 | goto out; | ||
1418 | size += sg_dma_len(&dma->sglist[j]); | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | out: | ||
1423 | mutex_unlock(&vbq->vb_lock); | ||
1424 | |||
1425 | return err; | ||
1426 | } | ||
1427 | |||
1428 | static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma) | ||
1429 | { | ||
1430 | struct omap24xxcam_fh *fh = file->private_data; | ||
1431 | int rval; | ||
1432 | |||
1433 | /* let the video-buf mapper check arguments and set-up structures */ | ||
1434 | rval = videobuf_mmap_mapper(&fh->vbq, vma); | ||
1435 | if (rval) | ||
1436 | return rval; | ||
1437 | |||
1438 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
1439 | |||
1440 | /* do mapping to our allocated buffers */ | ||
1441 | rval = omap24xxcam_mmap_buffers(file, vma); | ||
1442 | /* | ||
1443 | * In case of error, free vma->vm_private_data allocated by | ||
1444 | * videobuf_mmap_mapper. | ||
1445 | */ | ||
1446 | if (rval) | ||
1447 | kfree(vma->vm_private_data); | ||
1448 | |||
1449 | return rval; | ||
1450 | } | ||
1451 | |||
1452 | static int omap24xxcam_open(struct file *file) | ||
1453 | { | ||
1454 | struct omap24xxcam_device *cam = omap24xxcam.priv; | ||
1455 | struct omap24xxcam_fh *fh; | ||
1456 | struct v4l2_format format; | ||
1457 | |||
1458 | if (!cam || !cam->vfd) | ||
1459 | return -ENODEV; | ||
1460 | |||
1461 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
1462 | if (fh == NULL) | ||
1463 | return -ENOMEM; | ||
1464 | |||
1465 | mutex_lock(&cam->mutex); | ||
1466 | if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) { | ||
1467 | mutex_unlock(&cam->mutex); | ||
1468 | goto out_try_module_get; | ||
1469 | } | ||
1470 | |||
1471 | if (atomic_inc_return(&cam->users) == 1) { | ||
1472 | omap24xxcam_hwinit(cam); | ||
1473 | if (omap24xxcam_sensor_enable(cam)) { | ||
1474 | mutex_unlock(&cam->mutex); | ||
1475 | goto out_omap24xxcam_sensor_enable; | ||
1476 | } | ||
1477 | } | ||
1478 | mutex_unlock(&cam->mutex); | ||
1479 | |||
1480 | fh->cam = cam; | ||
1481 | mutex_lock(&cam->mutex); | ||
1482 | vidioc_int_g_fmt_cap(cam->sdev, &format); | ||
1483 | mutex_unlock(&cam->mutex); | ||
1484 | /* FIXME: how about fh->pix when there are more users? */ | ||
1485 | fh->pix = format.fmt.pix; | ||
1486 | |||
1487 | file->private_data = fh; | ||
1488 | |||
1489 | spin_lock_init(&fh->vbq_lock); | ||
1490 | |||
1491 | videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL, | ||
1492 | &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1493 | V4L2_FIELD_NONE, | ||
1494 | sizeof(struct videobuf_buffer), fh, NULL); | ||
1495 | |||
1496 | return 0; | ||
1497 | |||
1498 | out_omap24xxcam_sensor_enable: | ||
1499 | omap24xxcam_poweron_reset(cam); | ||
1500 | module_put(cam->sdev->module); | ||
1501 | |||
1502 | out_try_module_get: | ||
1503 | kfree(fh); | ||
1504 | |||
1505 | return -ENODEV; | ||
1506 | } | ||
1507 | |||
1508 | static int omap24xxcam_release(struct file *file) | ||
1509 | { | ||
1510 | struct omap24xxcam_fh *fh = file->private_data; | ||
1511 | struct omap24xxcam_device *cam = fh->cam; | ||
1512 | |||
1513 | atomic_inc(&cam->reset_disable); | ||
1514 | |||
1515 | flush_work(&cam->sensor_reset_work); | ||
1516 | |||
1517 | /* stop streaming capture */ | ||
1518 | videobuf_streamoff(&fh->vbq); | ||
1519 | |||
1520 | mutex_lock(&cam->mutex); | ||
1521 | if (cam->streaming == file) { | ||
1522 | cam->streaming = NULL; | ||
1523 | mutex_unlock(&cam->mutex); | ||
1524 | sysfs_notify(&cam->dev->kobj, NULL, "streaming"); | ||
1525 | } else { | ||
1526 | mutex_unlock(&cam->mutex); | ||
1527 | } | ||
1528 | |||
1529 | atomic_dec(&cam->reset_disable); | ||
1530 | |||
1531 | omap24xxcam_vbq_free_mmap_buffers(&fh->vbq); | ||
1532 | |||
1533 | /* | ||
1534 | * Make sure the reset work we might have scheduled is not | ||
1535 | * pending! It may be run *only* if we have users. (And it may | ||
1536 | * not be scheduled anymore since streaming is already | ||
1537 | * disabled.) | ||
1538 | */ | ||
1539 | flush_work(&cam->sensor_reset_work); | ||
1540 | |||
1541 | mutex_lock(&cam->mutex); | ||
1542 | if (atomic_dec_return(&cam->users) == 0) { | ||
1543 | omap24xxcam_sensor_disable(cam); | ||
1544 | omap24xxcam_poweron_reset(cam); | ||
1545 | } | ||
1546 | mutex_unlock(&cam->mutex); | ||
1547 | |||
1548 | file->private_data = NULL; | ||
1549 | |||
1550 | module_put(cam->sdev->module); | ||
1551 | kfree(fh); | ||
1552 | |||
1553 | return 0; | ||
1554 | } | ||
1555 | |||
1556 | static struct v4l2_file_operations omap24xxcam_fops = { | ||
1557 | .ioctl = video_ioctl2, | ||
1558 | .poll = omap24xxcam_poll, | ||
1559 | .mmap = omap24xxcam_mmap, | ||
1560 | .open = omap24xxcam_open, | ||
1561 | .release = omap24xxcam_release, | ||
1562 | }; | ||
1563 | |||
1564 | /* | ||
1565 | * | ||
1566 | * Power management. | ||
1567 | * | ||
1568 | */ | ||
1569 | |||
1570 | #ifdef CONFIG_PM | ||
1571 | static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state) | ||
1572 | { | ||
1573 | struct omap24xxcam_device *cam = platform_get_drvdata(pdev); | ||
1574 | |||
1575 | if (atomic_read(&cam->users) == 0) | ||
1576 | return 0; | ||
1577 | |||
1578 | if (!atomic_read(&cam->reset_disable)) | ||
1579 | omap24xxcam_capture_stop(cam); | ||
1580 | |||
1581 | omap24xxcam_sensor_disable(cam); | ||
1582 | omap24xxcam_poweron_reset(cam); | ||
1583 | |||
1584 | return 0; | ||
1585 | } | ||
1586 | |||
1587 | static int omap24xxcam_resume(struct platform_device *pdev) | ||
1588 | { | ||
1589 | struct omap24xxcam_device *cam = platform_get_drvdata(pdev); | ||
1590 | |||
1591 | if (atomic_read(&cam->users) == 0) | ||
1592 | return 0; | ||
1593 | |||
1594 | omap24xxcam_hwinit(cam); | ||
1595 | omap24xxcam_sensor_enable(cam); | ||
1596 | |||
1597 | if (!atomic_read(&cam->reset_disable)) | ||
1598 | omap24xxcam_capture_cont(cam); | ||
1599 | |||
1600 | return 0; | ||
1601 | } | ||
1602 | #endif /* CONFIG_PM */ | ||
1603 | |||
1604 | static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = { | ||
1605 | .vidioc_querycap = vidioc_querycap, | ||
1606 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1607 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1608 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1609 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1610 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1611 | .vidioc_querybuf = vidioc_querybuf, | ||
1612 | .vidioc_qbuf = vidioc_qbuf, | ||
1613 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1614 | .vidioc_streamon = vidioc_streamon, | ||
1615 | .vidioc_streamoff = vidioc_streamoff, | ||
1616 | .vidioc_enum_input = vidioc_enum_input, | ||
1617 | .vidioc_g_input = vidioc_g_input, | ||
1618 | .vidioc_s_input = vidioc_s_input, | ||
1619 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1620 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1621 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1622 | .vidioc_g_parm = vidioc_g_parm, | ||
1623 | .vidioc_s_parm = vidioc_s_parm, | ||
1624 | }; | ||
1625 | |||
1626 | /* | ||
1627 | * | ||
1628 | * Camera device (i.e. /dev/video). | ||
1629 | * | ||
1630 | */ | ||
1631 | |||
1632 | static int omap24xxcam_device_register(struct v4l2_int_device *s) | ||
1633 | { | ||
1634 | struct omap24xxcam_device *cam = s->u.slave->master->priv; | ||
1635 | struct video_device *vfd; | ||
1636 | int rval; | ||
1637 | |||
1638 | /* We already have a slave. */ | ||
1639 | if (cam->sdev) | ||
1640 | return -EBUSY; | ||
1641 | |||
1642 | cam->sdev = s; | ||
1643 | |||
1644 | if (device_create_file(cam->dev, &dev_attr_streaming) != 0) { | ||
1645 | dev_err(cam->dev, "could not register sysfs entry\n"); | ||
1646 | rval = -EBUSY; | ||
1647 | goto err; | ||
1648 | } | ||
1649 | |||
1650 | /* initialize the video_device struct */ | ||
1651 | vfd = cam->vfd = video_device_alloc(); | ||
1652 | if (!vfd) { | ||
1653 | dev_err(cam->dev, "could not allocate video device struct\n"); | ||
1654 | rval = -ENOMEM; | ||
1655 | goto err; | ||
1656 | } | ||
1657 | vfd->release = video_device_release; | ||
1658 | |||
1659 | vfd->v4l2_dev = &cam->v4l2_dev; | ||
1660 | |||
1661 | strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name)); | ||
1662 | vfd->fops = &omap24xxcam_fops; | ||
1663 | vfd->ioctl_ops = &omap24xxcam_ioctl_fops; | ||
1664 | |||
1665 | omap24xxcam_hwinit(cam); | ||
1666 | |||
1667 | rval = omap24xxcam_sensor_init(cam); | ||
1668 | if (rval) | ||
1669 | goto err; | ||
1670 | |||
1671 | if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) { | ||
1672 | dev_err(cam->dev, "could not register V4L device\n"); | ||
1673 | rval = -EBUSY; | ||
1674 | goto err; | ||
1675 | } | ||
1676 | |||
1677 | omap24xxcam_poweron_reset(cam); | ||
1678 | |||
1679 | dev_info(cam->dev, "registered device %s\n", | ||
1680 | video_device_node_name(vfd)); | ||
1681 | |||
1682 | return 0; | ||
1683 | |||
1684 | err: | ||
1685 | omap24xxcam_device_unregister(s); | ||
1686 | |||
1687 | return rval; | ||
1688 | } | ||
1689 | |||
1690 | static void omap24xxcam_device_unregister(struct v4l2_int_device *s) | ||
1691 | { | ||
1692 | struct omap24xxcam_device *cam = s->u.slave->master->priv; | ||
1693 | |||
1694 | omap24xxcam_sensor_exit(cam); | ||
1695 | |||
1696 | if (cam->vfd) { | ||
1697 | if (!video_is_registered(cam->vfd)) { | ||
1698 | /* | ||
1699 | * The device was never registered, so release the | ||
1700 | * video_device struct directly. | ||
1701 | */ | ||
1702 | video_device_release(cam->vfd); | ||
1703 | } else { | ||
1704 | /* | ||
1705 | * The unregister function will release the | ||
1706 | * video_device struct as well as | ||
1707 | * unregistering it. | ||
1708 | */ | ||
1709 | video_unregister_device(cam->vfd); | ||
1710 | } | ||
1711 | cam->vfd = NULL; | ||
1712 | } | ||
1713 | |||
1714 | device_remove_file(cam->dev, &dev_attr_streaming); | ||
1715 | |||
1716 | cam->sdev = NULL; | ||
1717 | } | ||
1718 | |||
1719 | static struct v4l2_int_master omap24xxcam_master = { | ||
1720 | .attach = omap24xxcam_device_register, | ||
1721 | .detach = omap24xxcam_device_unregister, | ||
1722 | }; | ||
1723 | |||
1724 | static struct v4l2_int_device omap24xxcam = { | ||
1725 | .module = THIS_MODULE, | ||
1726 | .name = CAM_NAME, | ||
1727 | .type = v4l2_int_type_master, | ||
1728 | .u = { | ||
1729 | .master = &omap24xxcam_master | ||
1730 | }, | ||
1731 | }; | ||
1732 | |||
1733 | /* | ||
1734 | * | ||
1735 | * Driver initialisation and deinitialisation. | ||
1736 | * | ||
1737 | */ | ||
1738 | |||
1739 | static int omap24xxcam_probe(struct platform_device *pdev) | ||
1740 | { | ||
1741 | struct omap24xxcam_device *cam; | ||
1742 | struct resource *mem; | ||
1743 | int irq; | ||
1744 | |||
1745 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
1746 | if (!cam) { | ||
1747 | dev_err(&pdev->dev, "could not allocate memory\n"); | ||
1748 | goto err; | ||
1749 | } | ||
1750 | |||
1751 | platform_set_drvdata(pdev, cam); | ||
1752 | |||
1753 | cam->dev = &pdev->dev; | ||
1754 | |||
1755 | if (v4l2_device_register(&pdev->dev, &cam->v4l2_dev)) { | ||
1756 | dev_err(&pdev->dev, "v4l2_device_register failed\n"); | ||
1757 | goto err; | ||
1758 | } | ||
1759 | |||
1760 | /* | ||
1761 | * Impose a lower limit on the amount of memory allocated for | ||
1762 | * capture. We require at least enough memory to double-buffer | ||
1763 | * QVGA (300KB). | ||
1764 | */ | ||
1765 | if (capture_mem < 320 * 240 * 2 * 2) | ||
1766 | capture_mem = 320 * 240 * 2 * 2; | ||
1767 | cam->capture_mem = capture_mem; | ||
1768 | |||
1769 | /* request the mem region for the camera registers */ | ||
1770 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1771 | if (!mem) { | ||
1772 | dev_err(cam->dev, "no mem resource?\n"); | ||
1773 | goto err; | ||
1774 | } | ||
1775 | if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) { | ||
1776 | dev_err(cam->dev, | ||
1777 | "cannot reserve camera register I/O region\n"); | ||
1778 | goto err; | ||
1779 | } | ||
1780 | cam->mmio_base_phys = mem->start; | ||
1781 | cam->mmio_size = resource_size(mem); | ||
1782 | |||
1783 | /* map the region */ | ||
1784 | cam->mmio_base = ioremap_nocache(cam->mmio_base_phys, cam->mmio_size); | ||
1785 | if (!cam->mmio_base) { | ||
1786 | dev_err(cam->dev, "cannot map camera register I/O region\n"); | ||
1787 | goto err; | ||
1788 | } | ||
1789 | |||
1790 | irq = platform_get_irq(pdev, 0); | ||
1791 | if (irq <= 0) { | ||
1792 | dev_err(cam->dev, "no irq for camera?\n"); | ||
1793 | goto err; | ||
1794 | } | ||
1795 | |||
1796 | /* install the interrupt service routine */ | ||
1797 | if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) { | ||
1798 | dev_err(cam->dev, | ||
1799 | "could not install interrupt service routine\n"); | ||
1800 | goto err; | ||
1801 | } | ||
1802 | cam->irq = irq; | ||
1803 | |||
1804 | if (omap24xxcam_clock_get(cam)) | ||
1805 | goto err; | ||
1806 | |||
1807 | INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work); | ||
1808 | |||
1809 | mutex_init(&cam->mutex); | ||
1810 | spin_lock_init(&cam->core_enable_disable_lock); | ||
1811 | |||
1812 | omap24xxcam_sgdma_init(&cam->sgdma, | ||
1813 | cam->mmio_base + CAMDMA_REG_OFFSET, | ||
1814 | omap24xxcam_stalled_dma_reset, | ||
1815 | (unsigned long)cam); | ||
1816 | |||
1817 | omap24xxcam.priv = cam; | ||
1818 | |||
1819 | if (v4l2_int_device_register(&omap24xxcam)) | ||
1820 | goto err; | ||
1821 | |||
1822 | return 0; | ||
1823 | |||
1824 | err: | ||
1825 | omap24xxcam_remove(pdev); | ||
1826 | return -ENODEV; | ||
1827 | } | ||
1828 | |||
1829 | static int omap24xxcam_remove(struct platform_device *pdev) | ||
1830 | { | ||
1831 | struct omap24xxcam_device *cam = platform_get_drvdata(pdev); | ||
1832 | |||
1833 | if (!cam) | ||
1834 | return 0; | ||
1835 | |||
1836 | if (omap24xxcam.priv != NULL) | ||
1837 | v4l2_int_device_unregister(&omap24xxcam); | ||
1838 | omap24xxcam.priv = NULL; | ||
1839 | |||
1840 | omap24xxcam_clock_put(cam); | ||
1841 | |||
1842 | if (cam->irq) { | ||
1843 | free_irq(cam->irq, cam); | ||
1844 | cam->irq = 0; | ||
1845 | } | ||
1846 | |||
1847 | if (cam->mmio_base) { | ||
1848 | iounmap((void *)cam->mmio_base); | ||
1849 | cam->mmio_base = 0; | ||
1850 | } | ||
1851 | |||
1852 | if (cam->mmio_base_phys) { | ||
1853 | release_mem_region(cam->mmio_base_phys, cam->mmio_size); | ||
1854 | cam->mmio_base_phys = 0; | ||
1855 | } | ||
1856 | |||
1857 | v4l2_device_unregister(&cam->v4l2_dev); | ||
1858 | |||
1859 | kfree(cam); | ||
1860 | |||
1861 | return 0; | ||
1862 | } | ||
1863 | |||
1864 | static struct platform_driver omap24xxcam_driver = { | ||
1865 | .probe = omap24xxcam_probe, | ||
1866 | .remove = omap24xxcam_remove, | ||
1867 | #ifdef CONFIG_PM | ||
1868 | .suspend = omap24xxcam_suspend, | ||
1869 | .resume = omap24xxcam_resume, | ||
1870 | #endif | ||
1871 | .driver = { | ||
1872 | .name = CAM_NAME, | ||
1873 | .owner = THIS_MODULE, | ||
1874 | }, | ||
1875 | }; | ||
1876 | |||
1877 | module_platform_driver(omap24xxcam_driver); | ||
1878 | |||
1879 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>"); | ||
1880 | MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver"); | ||
1881 | MODULE_LICENSE("GPL"); | ||
1882 | MODULE_VERSION(OMAP24XXCAM_VERSION); | ||
1883 | module_param(video_nr, int, 0); | ||
1884 | MODULE_PARM_DESC(video_nr, | ||
1885 | "Minor number for video device (-1 ==> auto assign)"); | ||
1886 | module_param(capture_mem, int, 0); | ||
1887 | MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture " | ||
1888 | "buffers (default 4800kiB)"); | ||
diff --git a/drivers/media/platform/omap24xxcam.h b/drivers/media/platform/omap24xxcam.h deleted file mode 100644 index 7f6f79155537..000000000000 --- a/drivers/media/platform/omap24xxcam.h +++ /dev/null | |||
@@ -1,596 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/omap24xxcam.h | ||
3 | * | ||
4 | * Copyright (C) 2004 MontaVista Software, Inc. | ||
5 | * Copyright (C) 2004 Texas Instruments. | ||
6 | * Copyright (C) 2007 Nokia Corporation. | ||
7 | * | ||
8 | * Contact: Sakari Ailus <sakari.ailus@nokia.com> | ||
9 | * | ||
10 | * Based on code from Andy Lowe <source@mvista.com>. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * version 2 as published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but | ||
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
24 | * 02110-1301 USA | ||
25 | */ | ||
26 | |||
27 | #ifndef OMAP24XXCAM_H | ||
28 | #define OMAP24XXCAM_H | ||
29 | |||
30 | #include <media/videobuf-dma-sg.h> | ||
31 | #include <media/v4l2-int-device.h> | ||
32 | #include <media/v4l2-device.h> | ||
33 | |||
34 | /* | ||
35 | * | ||
36 | * General driver related definitions. | ||
37 | * | ||
38 | */ | ||
39 | |||
40 | #define CAM_NAME "omap24xxcam" | ||
41 | |||
42 | #define CAM_MCLK 96000000 | ||
43 | |||
44 | /* number of bytes transferred per DMA request */ | ||
45 | #define DMA_THRESHOLD 32 | ||
46 | |||
47 | /* | ||
48 | * NUM_CAMDMA_CHANNELS is the number of logical channels provided by | ||
49 | * the camera DMA controller. | ||
50 | */ | ||
51 | #define NUM_CAMDMA_CHANNELS 4 | ||
52 | |||
53 | /* | ||
54 | * NUM_SG_DMA is the number of scatter-gather DMA transfers that can | ||
55 | * be queued. (We don't have any overlay sglists now.) | ||
56 | */ | ||
57 | #define NUM_SG_DMA (VIDEO_MAX_FRAME) | ||
58 | |||
59 | /* | ||
60 | * | ||
61 | * Register definitions. | ||
62 | * | ||
63 | */ | ||
64 | |||
65 | /* subsystem register block offsets */ | ||
66 | #define CC_REG_OFFSET 0x00000400 | ||
67 | #define CAMDMA_REG_OFFSET 0x00000800 | ||
68 | #define CAMMMU_REG_OFFSET 0x00000C00 | ||
69 | |||
70 | /* define camera subsystem register offsets */ | ||
71 | #define CAM_REVISION 0x000 | ||
72 | #define CAM_SYSCONFIG 0x010 | ||
73 | #define CAM_SYSSTATUS 0x014 | ||
74 | #define CAM_IRQSTATUS 0x018 | ||
75 | #define CAM_GPO 0x040 | ||
76 | #define CAM_GPI 0x050 | ||
77 | |||
78 | /* define camera core register offsets */ | ||
79 | #define CC_REVISION 0x000 | ||
80 | #define CC_SYSCONFIG 0x010 | ||
81 | #define CC_SYSSTATUS 0x014 | ||
82 | #define CC_IRQSTATUS 0x018 | ||
83 | #define CC_IRQENABLE 0x01C | ||
84 | #define CC_CTRL 0x040 | ||
85 | #define CC_CTRL_DMA 0x044 | ||
86 | #define CC_CTRL_XCLK 0x048 | ||
87 | #define CC_FIFODATA 0x04C | ||
88 | #define CC_TEST 0x050 | ||
89 | #define CC_GENPAR 0x054 | ||
90 | #define CC_CCPFSCR 0x058 | ||
91 | #define CC_CCPFECR 0x05C | ||
92 | #define CC_CCPLSCR 0x060 | ||
93 | #define CC_CCPLECR 0x064 | ||
94 | #define CC_CCPDFR 0x068 | ||
95 | |||
96 | /* define camera dma register offsets */ | ||
97 | #define CAMDMA_REVISION 0x000 | ||
98 | #define CAMDMA_IRQSTATUS_L0 0x008 | ||
99 | #define CAMDMA_IRQSTATUS_L1 0x00C | ||
100 | #define CAMDMA_IRQSTATUS_L2 0x010 | ||
101 | #define CAMDMA_IRQSTATUS_L3 0x014 | ||
102 | #define CAMDMA_IRQENABLE_L0 0x018 | ||
103 | #define CAMDMA_IRQENABLE_L1 0x01C | ||
104 | #define CAMDMA_IRQENABLE_L2 0x020 | ||
105 | #define CAMDMA_IRQENABLE_L3 0x024 | ||
106 | #define CAMDMA_SYSSTATUS 0x028 | ||
107 | #define CAMDMA_OCP_SYSCONFIG 0x02C | ||
108 | #define CAMDMA_CAPS_0 0x064 | ||
109 | #define CAMDMA_CAPS_2 0x06C | ||
110 | #define CAMDMA_CAPS_3 0x070 | ||
111 | #define CAMDMA_CAPS_4 0x074 | ||
112 | #define CAMDMA_GCR 0x078 | ||
113 | #define CAMDMA_CCR(n) (0x080 + (n)*0x60) | ||
114 | #define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60) | ||
115 | #define CAMDMA_CICR(n) (0x088 + (n)*0x60) | ||
116 | #define CAMDMA_CSR(n) (0x08C + (n)*0x60) | ||
117 | #define CAMDMA_CSDP(n) (0x090 + (n)*0x60) | ||
118 | #define CAMDMA_CEN(n) (0x094 + (n)*0x60) | ||
119 | #define CAMDMA_CFN(n) (0x098 + (n)*0x60) | ||
120 | #define CAMDMA_CSSA(n) (0x09C + (n)*0x60) | ||
121 | #define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60) | ||
122 | #define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60) | ||
123 | #define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60) | ||
124 | #define CAMDMA_CDEI(n) (0x0AC + (n)*0x60) | ||
125 | #define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60) | ||
126 | #define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60) | ||
127 | #define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60) | ||
128 | #define CAMDMA_CCEN(n) (0x0BC + (n)*0x60) | ||
129 | #define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60) | ||
130 | #define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60) | ||
131 | |||
132 | /* define camera mmu register offsets */ | ||
133 | #define CAMMMU_REVISION 0x000 | ||
134 | #define CAMMMU_SYSCONFIG 0x010 | ||
135 | #define CAMMMU_SYSSTATUS 0x014 | ||
136 | #define CAMMMU_IRQSTATUS 0x018 | ||
137 | #define CAMMMU_IRQENABLE 0x01C | ||
138 | #define CAMMMU_WALKING_ST 0x040 | ||
139 | #define CAMMMU_CNTL 0x044 | ||
140 | #define CAMMMU_FAULT_AD 0x048 | ||
141 | #define CAMMMU_TTB 0x04C | ||
142 | #define CAMMMU_LOCK 0x050 | ||
143 | #define CAMMMU_LD_TLB 0x054 | ||
144 | #define CAMMMU_CAM 0x058 | ||
145 | #define CAMMMU_RAM 0x05C | ||
146 | #define CAMMMU_GFLUSH 0x060 | ||
147 | #define CAMMMU_FLUSH_ENTRY 0x064 | ||
148 | #define CAMMMU_READ_CAM 0x068 | ||
149 | #define CAMMMU_READ_RAM 0x06C | ||
150 | #define CAMMMU_EMU_FAULT_AD 0x070 | ||
151 | |||
152 | /* Define bit fields within selected registers */ | ||
153 | #define CAM_REVISION_MAJOR (15 << 4) | ||
154 | #define CAM_REVISION_MAJOR_SHIFT 4 | ||
155 | #define CAM_REVISION_MINOR (15 << 0) | ||
156 | #define CAM_REVISION_MINOR_SHIFT 0 | ||
157 | |||
158 | #define CAM_SYSCONFIG_SOFTRESET (1 << 1) | ||
159 | #define CAM_SYSCONFIG_AUTOIDLE (1 << 0) | ||
160 | |||
161 | #define CAM_SYSSTATUS_RESETDONE (1 << 0) | ||
162 | |||
163 | #define CAM_IRQSTATUS_CC_IRQ (1 << 4) | ||
164 | #define CAM_IRQSTATUS_MMU_IRQ (1 << 3) | ||
165 | #define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2) | ||
166 | #define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1) | ||
167 | #define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0) | ||
168 | |||
169 | #define CAM_GPO_CAM_S_P_EN (1 << 1) | ||
170 | #define CAM_GPO_CAM_CCP_MODE (1 << 0) | ||
171 | |||
172 | #define CAM_GPI_CC_DMA_REQ1 (1 << 24) | ||
173 | #define CAP_GPI_CC_DMA_REQ0 (1 << 23) | ||
174 | #define CAP_GPI_CAM_MSTANDBY (1 << 21) | ||
175 | #define CAP_GPI_CAM_WAIT (1 << 20) | ||
176 | #define CAP_GPI_CAM_S_DATA (1 << 17) | ||
177 | #define CAP_GPI_CAM_S_CLK (1 << 16) | ||
178 | #define CAP_GPI_CAM_P_DATA (0xFFF << 3) | ||
179 | #define CAP_GPI_CAM_P_DATA_SHIFT 3 | ||
180 | #define CAP_GPI_CAM_P_VS (1 << 2) | ||
181 | #define CAP_GPI_CAM_P_HS (1 << 1) | ||
182 | #define CAP_GPI_CAM_P_CLK (1 << 0) | ||
183 | |||
184 | #define CC_REVISION_MAJOR (15 << 4) | ||
185 | #define CC_REVISION_MAJOR_SHIFT 4 | ||
186 | #define CC_REVISION_MINOR (15 << 0) | ||
187 | #define CC_REVISION_MINOR_SHIFT 0 | ||
188 | |||
189 | #define CC_SYSCONFIG_SIDLEMODE (3 << 3) | ||
190 | #define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3) | ||
191 | #define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3) | ||
192 | #define CC_SYSCONFIG_SOFTRESET (1 << 1) | ||
193 | #define CC_SYSCONFIG_AUTOIDLE (1 << 0) | ||
194 | |||
195 | #define CC_SYSSTATUS_RESETDONE (1 << 0) | ||
196 | |||
197 | #define CC_IRQSTATUS_FS_IRQ (1 << 19) | ||
198 | #define CC_IRQSTATUS_LE_IRQ (1 << 18) | ||
199 | #define CC_IRQSTATUS_LS_IRQ (1 << 17) | ||
200 | #define CC_IRQSTATUS_FE_IRQ (1 << 16) | ||
201 | #define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10) | ||
202 | #define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9) | ||
203 | #define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8) | ||
204 | #define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4) | ||
205 | #define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3) | ||
206 | #define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2) | ||
207 | #define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1) | ||
208 | #define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0) | ||
209 | |||
210 | #define CC_IRQENABLE_FS_IRQ (1 << 19) | ||
211 | #define CC_IRQENABLE_LE_IRQ (1 << 18) | ||
212 | #define CC_IRQENABLE_LS_IRQ (1 << 17) | ||
213 | #define CC_IRQENABLE_FE_IRQ (1 << 16) | ||
214 | #define CC_IRQENABLE_FW_ERR_IRQ (1 << 10) | ||
215 | #define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9) | ||
216 | #define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8) | ||
217 | #define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4) | ||
218 | #define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3) | ||
219 | #define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2) | ||
220 | #define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1) | ||
221 | #define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0) | ||
222 | |||
223 | #define CC_CTRL_CC_ONE_SHOT (1 << 20) | ||
224 | #define CC_CTRL_CC_IF_SYNCHRO (1 << 19) | ||
225 | #define CC_CTRL_CC_RST (1 << 18) | ||
226 | #define CC_CTRL_CC_FRAME_TRIG (1 << 17) | ||
227 | #define CC_CTRL_CC_EN (1 << 16) | ||
228 | #define CC_CTRL_NOBT_SYNCHRO (1 << 13) | ||
229 | #define CC_CTRL_BT_CORRECT (1 << 12) | ||
230 | #define CC_CTRL_PAR_ORDERCAM (1 << 11) | ||
231 | #define CC_CTRL_PAR_CLK_POL (1 << 10) | ||
232 | #define CC_CTRL_NOBT_HS_POL (1 << 9) | ||
233 | #define CC_CTRL_NOBT_VS_POL (1 << 8) | ||
234 | #define CC_CTRL_PAR_MODE (7 << 1) | ||
235 | #define CC_CTRL_PAR_MODE_SHIFT 1 | ||
236 | #define CC_CTRL_PAR_MODE_NOBT8 (0 << 1) | ||
237 | #define CC_CTRL_PAR_MODE_NOBT10 (1 << 1) | ||
238 | #define CC_CTRL_PAR_MODE_NOBT12 (2 << 1) | ||
239 | #define CC_CTRL_PAR_MODE_BT8 (4 << 1) | ||
240 | #define CC_CTRL_PAR_MODE_BT10 (5 << 1) | ||
241 | #define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1) | ||
242 | #define CC_CTRL_CCP_MODE (1 << 0) | ||
243 | |||
244 | #define CC_CTRL_DMA_EN (1 << 8) | ||
245 | #define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0) | ||
246 | #define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0 | ||
247 | |||
248 | #define CC_CTRL_XCLK_DIV (0x1F << 0) | ||
249 | #define CC_CTRL_XCLK_DIV_SHIFT 0 | ||
250 | #define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0) | ||
251 | #define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0) | ||
252 | #define CC_CTRL_XCLK_DIV_BYPASS (31 << 0) | ||
253 | |||
254 | #define CC_TEST_FIFO_RD_POINTER (0xFF << 24) | ||
255 | #define CC_TEST_FIFO_RD_POINTER_SHIFT 24 | ||
256 | #define CC_TEST_FIFO_WR_POINTER (0xFF << 16) | ||
257 | #define CC_TEST_FIFO_WR_POINTER_SHIFT 16 | ||
258 | #define CC_TEST_FIFO_LEVEL (0xFF << 8) | ||
259 | #define CC_TEST_FIFO_LEVEL_SHIFT 8 | ||
260 | #define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0) | ||
261 | #define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0 | ||
262 | |||
263 | #define CC_GENPAR_FIFO_DEPTH (7 << 0) | ||
264 | #define CC_GENPAR_FIFO_DEPTH_SHIFT 0 | ||
265 | |||
266 | #define CC_CCPDFR_ALPHA (0xFF << 8) | ||
267 | #define CC_CCPDFR_ALPHA_SHIFT 8 | ||
268 | #define CC_CCPDFR_DATAFORMAT (15 << 0) | ||
269 | #define CC_CCPDFR_DATAFORMAT_SHIFT 0 | ||
270 | #define CC_CCPDFR_DATAFORMAT_YUV422BE (0 << 0) | ||
271 | #define CC_CCPDFR_DATAFORMAT_YUV422 (1 << 0) | ||
272 | #define CC_CCPDFR_DATAFORMAT_YUV420 (2 << 0) | ||
273 | #define CC_CCPDFR_DATAFORMAT_RGB444 (4 << 0) | ||
274 | #define CC_CCPDFR_DATAFORMAT_RGB565 (5 << 0) | ||
275 | #define CC_CCPDFR_DATAFORMAT_RGB888NDE (6 << 0) | ||
276 | #define CC_CCPDFR_DATAFORMAT_RGB888 (7 << 0) | ||
277 | #define CC_CCPDFR_DATAFORMAT_RAW8NDE (8 << 0) | ||
278 | #define CC_CCPDFR_DATAFORMAT_RAW8 (9 << 0) | ||
279 | #define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0) | ||
280 | #define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0) | ||
281 | #define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0) | ||
282 | #define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0) | ||
283 | #define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0) | ||
284 | |||
285 | #define CAMDMA_REVISION_MAJOR (15 << 4) | ||
286 | #define CAMDMA_REVISION_MAJOR_SHIFT 4 | ||
287 | #define CAMDMA_REVISION_MINOR (15 << 0) | ||
288 | #define CAMDMA_REVISION_MINOR_SHIFT 0 | ||
289 | |||
290 | #define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12) | ||
291 | #define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12) | ||
292 | #define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12) | ||
293 | #define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12) | ||
294 | #define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9) | ||
295 | #define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8) | ||
296 | #define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5) | ||
297 | #define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3) | ||
298 | #define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3) | ||
299 | #define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3) | ||
300 | #define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3) | ||
301 | #define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1) | ||
302 | #define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0) | ||
303 | |||
304 | #define CAMDMA_SYSSTATUS_RESETDONE (1 << 0) | ||
305 | |||
306 | #define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16) | ||
307 | #define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16 | ||
308 | #define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0) | ||
309 | #define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0 | ||
310 | |||
311 | #define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24) | ||
312 | #define CAMDMA_CCR_PREFETCH (1 << 23) | ||
313 | #define CAMDMA_CCR_SUPERVISOR (1 << 22) | ||
314 | #define CAMDMA_CCR_SECURE (1 << 21) | ||
315 | #define CAMDMA_CCR_BS (1 << 18) | ||
316 | #define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17) | ||
317 | #define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16) | ||
318 | #define CAMDMA_CCR_DST_AMODE (3 << 14) | ||
319 | #define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14) | ||
320 | #define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14) | ||
321 | #define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14) | ||
322 | #define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14) | ||
323 | #define CAMDMA_CCR_SRC_AMODE (3 << 12) | ||
324 | #define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12) | ||
325 | #define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12) | ||
326 | #define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12) | ||
327 | #define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12) | ||
328 | #define CAMDMA_CCR_WR_ACTIVE (1 << 10) | ||
329 | #define CAMDMA_CCR_RD_ACTIVE (1 << 9) | ||
330 | #define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8) | ||
331 | #define CAMDMA_CCR_ENABLE (1 << 7) | ||
332 | #define CAMDMA_CCR_PRIO (1 << 6) | ||
333 | #define CAMDMA_CCR_FS (1 << 5) | ||
334 | #define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0)) | ||
335 | #define CAMDMA_CCR_SYNCHRO_CAMERA 0x01 | ||
336 | |||
337 | #define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15) | ||
338 | #define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0) | ||
339 | #define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0 | ||
340 | |||
341 | #define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11) | ||
342 | #define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10) | ||
343 | #define CAMDMA_CICR_SECURE_ERR_IE (1 << 9) | ||
344 | #define CAMDMA_CICR_TRANS_ERR_IE (1 << 8) | ||
345 | #define CAMDMA_CICR_PACKET_IE (1 << 7) | ||
346 | #define CAMDMA_CICR_BLOCK_IE (1 << 5) | ||
347 | #define CAMDMA_CICR_LAST_IE (1 << 4) | ||
348 | #define CAMDMA_CICR_FRAME_IE (1 << 3) | ||
349 | #define CAMDMA_CICR_HALF_IE (1 << 2) | ||
350 | #define CAMDMA_CICR_DROP_IE (1 << 1) | ||
351 | |||
352 | #define CAMDMA_CSR_MISALIGNED_ERR (1 << 11) | ||
353 | #define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10) | ||
354 | #define CAMDMA_CSR_SECURE_ERR (1 << 9) | ||
355 | #define CAMDMA_CSR_TRANS_ERR (1 << 8) | ||
356 | #define CAMDMA_CSR_PACKET (1 << 7) | ||
357 | #define CAMDMA_CSR_SYNC (1 << 6) | ||
358 | #define CAMDMA_CSR_BLOCK (1 << 5) | ||
359 | #define CAMDMA_CSR_LAST (1 << 4) | ||
360 | #define CAMDMA_CSR_FRAME (1 << 3) | ||
361 | #define CAMDMA_CSR_HALF (1 << 2) | ||
362 | #define CAMDMA_CSR_DROP (1 << 1) | ||
363 | |||
364 | #define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21) | ||
365 | #define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20) | ||
366 | #define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19) | ||
367 | #define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18) | ||
368 | #define CAMDMA_CSDP_WRITE_MODE (3 << 16) | ||
369 | #define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16) | ||
370 | #define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16) | ||
371 | #define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16) | ||
372 | #define CAMDMA_CSDP_DST_BURST_EN (3 << 14) | ||
373 | #define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14) | ||
374 | #define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14) | ||
375 | #define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14) | ||
376 | #define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14) | ||
377 | #define CAMDMA_CSDP_DST_PACKED (1 << 13) | ||
378 | #define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9) | ||
379 | #define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9) | ||
380 | #define CAMDMA_CSDP_SRC_BURST_EN (3 << 7) | ||
381 | #define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7) | ||
382 | #define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7) | ||
383 | #define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7) | ||
384 | #define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7) | ||
385 | #define CAMDMA_CSDP_SRC_PACKED (1 << 6) | ||
386 | #define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2) | ||
387 | #define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2) | ||
388 | #define CAMDMA_CSDP_DATA_TYPE (3 << 0) | ||
389 | #define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0) | ||
390 | #define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0) | ||
391 | #define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0) | ||
392 | |||
393 | #define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0) | ||
394 | |||
395 | /* | ||
396 | * | ||
397 | * Declarations. | ||
398 | * | ||
399 | */ | ||
400 | |||
401 | /* forward declarations */ | ||
402 | struct omap24xxcam_sgdma; | ||
403 | struct omap24xxcam_dma; | ||
404 | |||
405 | typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam, | ||
406 | u32 status, void *arg); | ||
407 | typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam, | ||
408 | u32 status, void *arg); | ||
409 | |||
410 | struct channel_state { | ||
411 | dma_callback_t callback; | ||
412 | void *arg; | ||
413 | }; | ||
414 | |||
415 | /* sgdma state for each of the possible videobuf_buffers + 2 overlays */ | ||
416 | struct sgdma_state { | ||
417 | const struct scatterlist *sglist; | ||
418 | int sglen; /* number of sglist entries */ | ||
419 | int next_sglist; /* index of next sglist entry to process */ | ||
420 | unsigned int bytes_read; /* number of bytes read */ | ||
421 | unsigned int len; /* total length of sglist (excluding | ||
422 | * bytes due to page alignment) */ | ||
423 | int queued_sglist; /* number of sglist entries queued for DMA */ | ||
424 | u32 csr; /* DMA return code */ | ||
425 | sgdma_callback_t callback; | ||
426 | void *arg; | ||
427 | }; | ||
428 | |||
429 | /* physical DMA channel management */ | ||
430 | struct omap24xxcam_dma { | ||
431 | spinlock_t lock; /* Lock for the whole structure. */ | ||
432 | |||
433 | void __iomem *base; /* base address for dma controller */ | ||
434 | |||
435 | /* While dma_stop!=0, an attempt to start a new DMA transfer will | ||
436 | * fail. | ||
437 | */ | ||
438 | atomic_t dma_stop; | ||
439 | int free_dmach; /* number of dma channels free */ | ||
440 | int next_dmach; /* index of next dma channel to use */ | ||
441 | struct channel_state ch_state[NUM_CAMDMA_CHANNELS]; | ||
442 | }; | ||
443 | |||
444 | /* scatter-gather DMA (scatterlist stuff) management */ | ||
445 | struct omap24xxcam_sgdma { | ||
446 | struct omap24xxcam_dma dma; | ||
447 | |||
448 | spinlock_t lock; /* Lock for the fields below. */ | ||
449 | int free_sgdma; /* number of free sg dma slots */ | ||
450 | int next_sgdma; /* index of next sg dma slot to use */ | ||
451 | struct sgdma_state sg_state[NUM_SG_DMA]; | ||
452 | |||
453 | /* Reset timer data */ | ||
454 | struct timer_list reset_timer; | ||
455 | }; | ||
456 | |||
457 | /* per-device data structure */ | ||
458 | struct omap24xxcam_device { | ||
459 | /*** mutex ***/ | ||
460 | /* | ||
461 | * mutex serialises access to this structure. Also camera | ||
462 | * opening and releasing is synchronised by this. | ||
463 | */ | ||
464 | struct mutex mutex; | ||
465 | |||
466 | struct v4l2_device v4l2_dev; | ||
467 | |||
468 | /*** general driver state information ***/ | ||
469 | atomic_t users; | ||
470 | /* | ||
471 | * Lock to serialise core enabling and disabling and access to | ||
472 | * sgdma_in_queue. | ||
473 | */ | ||
474 | spinlock_t core_enable_disable_lock; | ||
475 | /* | ||
476 | * Number or sgdma requests in scatter-gather queue, protected | ||
477 | * by the lock above. | ||
478 | */ | ||
479 | int sgdma_in_queue; | ||
480 | /* | ||
481 | * Sensor interface parameters: interface type, CC_CTRL | ||
482 | * register value and interface specific data. | ||
483 | */ | ||
484 | int if_type; | ||
485 | union { | ||
486 | struct parallel { | ||
487 | u32 xclk; | ||
488 | } bt656; | ||
489 | } if_u; | ||
490 | u32 cc_ctrl; | ||
491 | |||
492 | /*** subsystem structures ***/ | ||
493 | struct omap24xxcam_sgdma sgdma; | ||
494 | |||
495 | /*** hardware resources ***/ | ||
496 | unsigned int irq; | ||
497 | void __iomem *mmio_base; | ||
498 | unsigned long mmio_base_phys; | ||
499 | unsigned long mmio_size; | ||
500 | |||
501 | /*** interfaces and device ***/ | ||
502 | struct v4l2_int_device *sdev; | ||
503 | struct device *dev; | ||
504 | struct video_device *vfd; | ||
505 | |||
506 | /*** camera and sensor reset related stuff ***/ | ||
507 | struct work_struct sensor_reset_work; | ||
508 | /* | ||
509 | * We're in the middle of a reset. Don't enable core if this | ||
510 | * is non-zero! This exists to help decisionmaking in a case | ||
511 | * where videobuf_qbuf is called while we are in the middle of | ||
512 | * a reset. | ||
513 | */ | ||
514 | atomic_t in_reset; | ||
515 | /* | ||
516 | * Non-zero if we don't want any resets for now. Used to | ||
517 | * prevent reset work to run when we're about to stop | ||
518 | * streaming. | ||
519 | */ | ||
520 | atomic_t reset_disable; | ||
521 | |||
522 | /*** video device parameters ***/ | ||
523 | int capture_mem; | ||
524 | |||
525 | /*** camera module clocks ***/ | ||
526 | struct clk *fck; | ||
527 | struct clk *ick; | ||
528 | |||
529 | /*** capture data ***/ | ||
530 | /* file handle, if streaming is on */ | ||
531 | struct file *streaming; | ||
532 | }; | ||
533 | |||
534 | /* Per-file handle data. */ | ||
535 | struct omap24xxcam_fh { | ||
536 | spinlock_t vbq_lock; /* spinlock for the videobuf queue */ | ||
537 | struct videobuf_queue vbq; | ||
538 | struct v4l2_pix_format pix; /* serialise pix by vbq->lock */ | ||
539 | atomic_t field_count; /* field counter for videobuf_buffer */ | ||
540 | /* accessing cam here doesn't need serialisation: it's constant */ | ||
541 | struct omap24xxcam_device *cam; | ||
542 | }; | ||
543 | |||
544 | /* | ||
545 | * | ||
546 | * Register I/O functions. | ||
547 | * | ||
548 | */ | ||
549 | |||
550 | static inline u32 omap24xxcam_reg_in(u32 __iomem *base, u32 offset) | ||
551 | { | ||
552 | return readl(base + offset); | ||
553 | } | ||
554 | |||
555 | static inline u32 omap24xxcam_reg_out(u32 __iomem *base, u32 offset, | ||
556 | u32 val) | ||
557 | { | ||
558 | writel(val, base + offset); | ||
559 | return val; | ||
560 | } | ||
561 | |||
562 | static inline u32 omap24xxcam_reg_merge(u32 __iomem *base, u32 offset, | ||
563 | u32 val, u32 mask) | ||
564 | { | ||
565 | u32 __iomem *addr = base + offset; | ||
566 | u32 new_val = (readl(addr) & ~mask) | (val & mask); | ||
567 | |||
568 | writel(new_val, addr); | ||
569 | return new_val; | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * | ||
574 | * Function prototypes. | ||
575 | * | ||
576 | */ | ||
577 | |||
578 | /* dma prototypes */ | ||
579 | |||
580 | void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma); | ||
581 | void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma); | ||
582 | |||
583 | /* sgdma prototypes */ | ||
584 | |||
585 | void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma); | ||
586 | int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma, | ||
587 | const struct scatterlist *sglist, int sglen, | ||
588 | int len, sgdma_callback_t callback, void *arg); | ||
589 | void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma); | ||
590 | void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma, | ||
591 | void __iomem *base, | ||
592 | void (*reset_callback)(unsigned long data), | ||
593 | unsigned long reset_callback_data); | ||
594 | void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma); | ||
595 | |||
596 | #endif | ||
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index fdbdeae3900d..5807185262fe 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c | |||
@@ -873,15 +873,12 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, | |||
873 | unsigned long flags; | 873 | unsigned long flags; |
874 | int ret; | 874 | int ret; |
875 | 875 | ||
876 | /* If the preview engine crashed it might not respond to read/write | 876 | /* Refuse to start streaming if an entity included in the pipeline has |
877 | * operations on the L4 bus. This would result in a bus fault and a | 877 | * crashed. This check must be performed before the loop below to avoid |
878 | * kernel oops. Refuse to start streaming in that case. This check must | 878 | * starting entities if the pipeline won't start anyway (those entities |
879 | * be performed before the loop below to avoid starting entities if the | 879 | * would then likely fail to stop, making the problem worse). |
880 | * pipeline won't start anyway (those entities would then likely fail to | ||
881 | * stop, making the problem worse). | ||
882 | */ | 880 | */ |
883 | if ((pipe->entities & isp->crashed) & | 881 | if (pipe->entities & isp->crashed) |
884 | (1U << isp->isp_prev.subdev.entity.id)) | ||
885 | return -EIO; | 882 | return -EIO; |
886 | 883 | ||
887 | spin_lock_irqsave(&pipe->lock, flags); | 884 | spin_lock_irqsave(&pipe->lock, flags); |
@@ -1014,13 +1011,23 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) | |||
1014 | else | 1011 | else |
1015 | ret = 0; | 1012 | ret = 0; |
1016 | 1013 | ||
1014 | /* Handle stop failures. An entity that fails to stop can | ||
1015 | * usually just be restarted. Flag the stop failure nonetheless | ||
1016 | * to trigger an ISP reset the next time the device is released, | ||
1017 | * just in case. | ||
1018 | * | ||
1019 | * The preview engine is a special case. A failure to stop can | ||
1020 | * mean a hardware crash. When that happens the preview engine | ||
1021 | * won't respond to read/write operations on the L4 bus anymore, | ||
1022 | * resulting in a bus fault and a kernel oops next time it gets | ||
1023 | * accessed. Mark it as crashed to prevent pipelines including | ||
1024 | * it from being started. | ||
1025 | */ | ||
1017 | if (ret) { | 1026 | if (ret) { |
1018 | dev_info(isp->dev, "Unable to stop %s\n", subdev->name); | 1027 | dev_info(isp->dev, "Unable to stop %s\n", subdev->name); |
1019 | /* If the entity failed to stopped, assume it has | 1028 | isp->stop_failure = true; |
1020 | * crashed. Mark it as such, the ISP will be reset when | 1029 | if (subdev == &isp->isp_prev.subdev) |
1021 | * applications will release it. | 1030 | isp->crashed |= 1U << subdev->entity.id; |
1022 | */ | ||
1023 | isp->crashed |= 1U << subdev->entity.id; | ||
1024 | failure = -ETIMEDOUT; | 1031 | failure = -ETIMEDOUT; |
1025 | } | 1032 | } |
1026 | } | 1033 | } |
@@ -1057,6 +1064,23 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, | |||
1057 | } | 1064 | } |
1058 | 1065 | ||
1059 | /* | 1066 | /* |
1067 | * omap3isp_pipeline_cancel_stream - Cancel stream on a pipeline | ||
1068 | * @pipe: ISP pipeline | ||
1069 | * | ||
1070 | * Cancelling a stream mark all buffers on all video nodes in the pipeline as | ||
1071 | * erroneous and makes sure no new buffer can be queued. This function is called | ||
1072 | * when a fatal error that prevents any further operation on the pipeline | ||
1073 | * occurs. | ||
1074 | */ | ||
1075 | void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe) | ||
1076 | { | ||
1077 | if (pipe->input) | ||
1078 | omap3isp_video_cancel_stream(pipe->input); | ||
1079 | if (pipe->output) | ||
1080 | omap3isp_video_cancel_stream(pipe->output); | ||
1081 | } | ||
1082 | |||
1083 | /* | ||
1060 | * isp_pipeline_resume - Resume streaming on a pipeline | 1084 | * isp_pipeline_resume - Resume streaming on a pipeline |
1061 | * @pipe: ISP pipeline | 1085 | * @pipe: ISP pipeline |
1062 | * | 1086 | * |
@@ -1208,6 +1232,7 @@ static int isp_reset(struct isp_device *isp) | |||
1208 | udelay(1); | 1232 | udelay(1); |
1209 | } | 1233 | } |
1210 | 1234 | ||
1235 | isp->stop_failure = false; | ||
1211 | isp->crashed = 0; | 1236 | isp->crashed = 0; |
1212 | return 0; | 1237 | return 0; |
1213 | } | 1238 | } |
@@ -1619,7 +1644,7 @@ void omap3isp_put(struct isp_device *isp) | |||
1619 | /* Reset the ISP if an entity has failed to stop. This is the | 1644 | /* Reset the ISP if an entity has failed to stop. This is the |
1620 | * only way to recover from such conditions. | 1645 | * only way to recover from such conditions. |
1621 | */ | 1646 | */ |
1622 | if (isp->crashed) | 1647 | if (isp->crashed || isp->stop_failure) |
1623 | isp_reset(isp); | 1648 | isp_reset(isp); |
1624 | isp_disable_clocks(isp); | 1649 | isp_disable_clocks(isp); |
1625 | } | 1650 | } |
@@ -2130,28 +2155,13 @@ static int isp_map_mem_resource(struct platform_device *pdev, | |||
2130 | /* request the mem region for the camera registers */ | 2155 | /* request the mem region for the camera registers */ |
2131 | 2156 | ||
2132 | mem = platform_get_resource(pdev, IORESOURCE_MEM, res); | 2157 | mem = platform_get_resource(pdev, IORESOURCE_MEM, res); |
2133 | if (!mem) { | ||
2134 | dev_err(isp->dev, "no mem resource?\n"); | ||
2135 | return -ENODEV; | ||
2136 | } | ||
2137 | |||
2138 | if (!devm_request_mem_region(isp->dev, mem->start, resource_size(mem), | ||
2139 | pdev->name)) { | ||
2140 | dev_err(isp->dev, | ||
2141 | "cannot reserve camera register I/O region\n"); | ||
2142 | return -ENODEV; | ||
2143 | } | ||
2144 | isp->mmio_base_phys[res] = mem->start; | ||
2145 | isp->mmio_size[res] = resource_size(mem); | ||
2146 | 2158 | ||
2147 | /* map the region */ | 2159 | /* map the region */ |
2148 | isp->mmio_base[res] = devm_ioremap_nocache(isp->dev, | 2160 | isp->mmio_base[res] = devm_ioremap_resource(isp->dev, mem); |
2149 | isp->mmio_base_phys[res], | 2161 | if (IS_ERR(isp->mmio_base[res])) |
2150 | isp->mmio_size[res]); | 2162 | return PTR_ERR(isp->mmio_base[res]); |
2151 | if (!isp->mmio_base[res]) { | 2163 | |
2152 | dev_err(isp->dev, "cannot map camera register I/O region\n"); | 2164 | isp->mmio_base_phys[res] = mem->start; |
2153 | return -ENODEV; | ||
2154 | } | ||
2155 | 2165 | ||
2156 | return 0; | 2166 | return 0; |
2157 | } | 2167 | } |
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index d1e857e41731..081f5ec5a663 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h | |||
@@ -152,9 +152,9 @@ struct isp_xclk { | |||
152 | * regions. | 152 | * regions. |
153 | * @mmio_base_phys: Array with physical L4 bus addresses for ISP register | 153 | * @mmio_base_phys: Array with physical L4 bus addresses for ISP register |
154 | * regions. | 154 | * regions. |
155 | * @mmio_size: Array with ISP register regions size in bytes. | ||
156 | * @stat_lock: Spinlock for handling statistics | 155 | * @stat_lock: Spinlock for handling statistics |
157 | * @isp_mutex: Mutex for serializing requests to ISP. | 156 | * @isp_mutex: Mutex for serializing requests to ISP. |
157 | * @stop_failure: Indicates that an entity failed to stop. | ||
158 | * @crashed: Bitmask of crashed entities (indexed by entity ID) | 158 | * @crashed: Bitmask of crashed entities (indexed by entity ID) |
159 | * @has_context: Context has been saved at least once and can be restored. | 159 | * @has_context: Context has been saved at least once and can be restored. |
160 | * @ref_count: Reference count for handling multiple ISP requests. | 160 | * @ref_count: Reference count for handling multiple ISP requests. |
@@ -188,11 +188,11 @@ struct isp_device { | |||
188 | 188 | ||
189 | void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; | 189 | void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; |
190 | unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; | 190 | unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; |
191 | resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST]; | ||
192 | 191 | ||
193 | /* ISP Obj */ | 192 | /* ISP Obj */ |
194 | spinlock_t stat_lock; /* common lock for statistic drivers */ | 193 | spinlock_t stat_lock; /* common lock for statistic drivers */ |
195 | struct mutex isp_mutex; /* For handling ref_count field */ | 194 | struct mutex isp_mutex; /* For handling ref_count field */ |
195 | bool stop_failure; | ||
196 | u32 crashed; | 196 | u32 crashed; |
197 | int has_context; | 197 | int has_context; |
198 | int ref_count; | 198 | int ref_count; |
@@ -238,6 +238,7 @@ int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait, | |||
238 | 238 | ||
239 | int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, | 239 | int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, |
240 | enum isp_pipeline_stream_state state); | 240 | enum isp_pipeline_stream_state state); |
241 | void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe); | ||
241 | void omap3isp_configure_bridge(struct isp_device *isp, | 242 | void omap3isp_configure_bridge(struct isp_device *isp, |
242 | enum ccdc_input_entity input, | 243 | enum ccdc_input_entity input, |
243 | const struct isp_parallel_platform_data *pdata, | 244 | const struct isp_parallel_platform_data *pdata, |
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 907a205da5a5..5db2c88b9ad8 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c | |||
@@ -1516,6 +1516,8 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) | |||
1516 | 1516 | ||
1517 | if (ccdc_sbl_wait_idle(ccdc, 1000)) { | 1517 | if (ccdc_sbl_wait_idle(ccdc, 1000)) { |
1518 | dev_info(isp->dev, "CCDC won't become idle!\n"); | 1518 | dev_info(isp->dev, "CCDC won't become idle!\n"); |
1519 | isp->crashed |= 1U << ccdc->subdev.entity.id; | ||
1520 | omap3isp_pipeline_cancel_stream(pipe); | ||
1519 | goto done; | 1521 | goto done; |
1520 | } | 1522 | } |
1521 | 1523 | ||
@@ -2484,7 +2486,8 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) | |||
2484 | v4l2_set_subdevdata(sd, ccdc); | 2486 | v4l2_set_subdevdata(sd, ccdc); |
2485 | sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; | 2487 | sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; |
2486 | 2488 | ||
2487 | pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 2489 | pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
2490 | | MEDIA_PAD_FL_MUST_CONNECT; | ||
2488 | pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; | 2491 | pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; |
2489 | pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE; | 2492 | pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE; |
2490 | 2493 | ||
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index e71651429dda..e84fe0543e47 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c | |||
@@ -1076,7 +1076,8 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) | |||
1076 | v4l2_set_subdevdata(sd, ccp2); | 1076 | v4l2_set_subdevdata(sd, ccp2); |
1077 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 1077 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1078 | 1078 | ||
1079 | pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 1079 | pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
1080 | | MEDIA_PAD_FL_MUST_CONNECT; | ||
1080 | pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | 1081 | pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; |
1081 | 1082 | ||
1082 | me->ops = &ccp2_media_ops; | 1083 | me->ops = &ccp2_media_ops; |
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 6db245d84bbb..620560828a48 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c | |||
@@ -1245,7 +1245,8 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) | |||
1245 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 1245 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1246 | 1246 | ||
1247 | pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | 1247 | pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; |
1248 | pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 1248 | pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
1249 | | MEDIA_PAD_FL_MUST_CONNECT; | ||
1249 | 1250 | ||
1250 | me->ops = &csi2_media_ops; | 1251 | me->ops = &csi2_media_ops; |
1251 | ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0); | 1252 | ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0); |
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index cd8831aebdeb..1c776c1186f1 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c | |||
@@ -2283,7 +2283,8 @@ static int preview_init_entities(struct isp_prev_device *prev) | |||
2283 | v4l2_ctrl_handler_setup(&prev->ctrls); | 2283 | v4l2_ctrl_handler_setup(&prev->ctrls); |
2284 | sd->ctrl_handler = &prev->ctrls; | 2284 | sd->ctrl_handler = &prev->ctrls; |
2285 | 2285 | ||
2286 | pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 2286 | pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
2287 | | MEDIA_PAD_FL_MUST_CONNECT; | ||
2287 | pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | 2288 | pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; |
2288 | 2289 | ||
2289 | me->ops = &preview_media_ops; | 2290 | me->ops = &preview_media_ops; |
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c index e15f01342058..5f0f8fab1d17 100644 --- a/drivers/media/platform/omap3isp/ispqueue.c +++ b/drivers/media/platform/omap3isp/ispqueue.c | |||
@@ -553,8 +553,10 @@ static void isp_video_buffer_query(struct isp_video_buffer *buf, | |||
553 | switch (buf->state) { | 553 | switch (buf->state) { |
554 | case ISP_BUF_STATE_ERROR: | 554 | case ISP_BUF_STATE_ERROR: |
555 | vbuf->flags |= V4L2_BUF_FLAG_ERROR; | 555 | vbuf->flags |= V4L2_BUF_FLAG_ERROR; |
556 | /* Fallthrough */ | ||
556 | case ISP_BUF_STATE_DONE: | 557 | case ISP_BUF_STATE_DONE: |
557 | vbuf->flags |= V4L2_BUF_FLAG_DONE; | 558 | vbuf->flags |= V4L2_BUF_FLAG_DONE; |
559 | break; | ||
558 | case ISP_BUF_STATE_QUEUED: | 560 | case ISP_BUF_STATE_QUEUED: |
559 | case ISP_BUF_STATE_ACTIVE: | 561 | case ISP_BUF_STATE_ACTIVE: |
560 | vbuf->flags |= V4L2_BUF_FLAG_QUEUED; | 562 | vbuf->flags |= V4L2_BUF_FLAG_QUEUED; |
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index d11fb261d530..0d36b8bc9f98 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c | |||
@@ -1532,6 +1532,20 @@ static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
1532 | return 0; | 1532 | return 0; |
1533 | } | 1533 | } |
1534 | 1534 | ||
1535 | static int resizer_link_validate(struct v4l2_subdev *sd, | ||
1536 | struct media_link *link, | ||
1537 | struct v4l2_subdev_format *source_fmt, | ||
1538 | struct v4l2_subdev_format *sink_fmt) | ||
1539 | { | ||
1540 | struct isp_res_device *res = v4l2_get_subdevdata(sd); | ||
1541 | struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity); | ||
1542 | |||
1543 | omap3isp_resizer_max_rate(res, &pipe->max_rate); | ||
1544 | |||
1545 | return v4l2_subdev_link_validate_default(sd, link, | ||
1546 | source_fmt, sink_fmt); | ||
1547 | } | ||
1548 | |||
1535 | /* | 1549 | /* |
1536 | * resizer_init_formats - Initialize formats on all pads | 1550 | * resizer_init_formats - Initialize formats on all pads |
1537 | * @sd: ISP resizer V4L2 subdevice | 1551 | * @sd: ISP resizer V4L2 subdevice |
@@ -1570,6 +1584,7 @@ static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = { | |||
1570 | .set_fmt = resizer_set_format, | 1584 | .set_fmt = resizer_set_format, |
1571 | .get_selection = resizer_get_selection, | 1585 | .get_selection = resizer_get_selection, |
1572 | .set_selection = resizer_set_selection, | 1586 | .set_selection = resizer_set_selection, |
1587 | .link_validate = resizer_link_validate, | ||
1573 | }; | 1588 | }; |
1574 | 1589 | ||
1575 | /* subdev operations */ | 1590 | /* subdev operations */ |
@@ -1701,7 +1716,8 @@ static int resizer_init_entities(struct isp_res_device *res) | |||
1701 | v4l2_set_subdevdata(sd, res); | 1716 | v4l2_set_subdevdata(sd, res); |
1702 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 1717 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1703 | 1718 | ||
1704 | pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 1719 | pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
1720 | | MEDIA_PAD_FL_MUST_CONNECT; | ||
1705 | pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | 1721 | pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; |
1706 | 1722 | ||
1707 | me->ops = &resizer_media_ops; | 1723 | me->ops = &resizer_media_ops; |
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 61e17f9bd8b9..a75407c3a726 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c | |||
@@ -1067,7 +1067,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, | |||
1067 | subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; | 1067 | subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; |
1068 | v4l2_set_subdevdata(subdev, stat); | 1068 | v4l2_set_subdevdata(subdev, stat); |
1069 | 1069 | ||
1070 | stat->pad.flags = MEDIA_PAD_FL_SINK; | 1070 | stat->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; |
1071 | me->ops = NULL; | 1071 | me->ops = NULL; |
1072 | 1072 | ||
1073 | return media_entity_init(me, 1, &stat->pad, 0); | 1073 | return media_entity_init(me, 1, &stat->pad, 0); |
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index f6304bb074f5..856fdf554035 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c | |||
@@ -278,55 +278,6 @@ static int isp_video_get_graph_data(struct isp_video *video, | |||
278 | return 0; | 278 | return 0; |
279 | } | 279 | } |
280 | 280 | ||
281 | /* | ||
282 | * Validate a pipeline by checking both ends of all links for format | ||
283 | * discrepancies. | ||
284 | * | ||
285 | * Compute the minimum time per frame value as the maximum of time per frame | ||
286 | * limits reported by every block in the pipeline. | ||
287 | * | ||
288 | * Return 0 if all formats match, or -EPIPE if at least one link is found with | ||
289 | * different formats on its two ends or if the pipeline doesn't start with a | ||
290 | * video source (either a subdev with no input pad, or a non-subdev entity). | ||
291 | */ | ||
292 | static int isp_video_validate_pipeline(struct isp_pipeline *pipe) | ||
293 | { | ||
294 | struct isp_device *isp = pipe->output->isp; | ||
295 | struct media_pad *pad; | ||
296 | struct v4l2_subdev *subdev; | ||
297 | |||
298 | subdev = isp_video_remote_subdev(pipe->output, NULL); | ||
299 | if (subdev == NULL) | ||
300 | return -EPIPE; | ||
301 | |||
302 | while (1) { | ||
303 | /* Retrieve the sink format */ | ||
304 | pad = &subdev->entity.pads[0]; | ||
305 | if (!(pad->flags & MEDIA_PAD_FL_SINK)) | ||
306 | break; | ||
307 | |||
308 | /* Update the maximum frame rate */ | ||
309 | if (subdev == &isp->isp_res.subdev) | ||
310 | omap3isp_resizer_max_rate(&isp->isp_res, | ||
311 | &pipe->max_rate); | ||
312 | |||
313 | /* Retrieve the source format. Return an error if no source | ||
314 | * entity can be found, and stop checking the pipeline if the | ||
315 | * source entity isn't a subdev. | ||
316 | */ | ||
317 | pad = media_entity_remote_pad(pad); | ||
318 | if (pad == NULL) | ||
319 | return -EPIPE; | ||
320 | |||
321 | if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) | ||
322 | break; | ||
323 | |||
324 | subdev = media_entity_to_v4l2_subdev(pad->entity); | ||
325 | } | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int | 281 | static int |
331 | __isp_video_get_format(struct isp_video *video, struct v4l2_format *format) | 282 | __isp_video_get_format(struct isp_video *video, struct v4l2_format *format) |
332 | { | 283 | { |
@@ -460,6 +411,15 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf) | |||
460 | struct isp_video *video = vfh->video; | 411 | struct isp_video *video = vfh->video; |
461 | unsigned long addr; | 412 | unsigned long addr; |
462 | 413 | ||
414 | /* Refuse to prepare the buffer is the video node has registered an | ||
415 | * error. We don't need to take any lock here as the operation is | ||
416 | * inherently racy. The authoritative check will be performed in the | ||
417 | * queue handler, which can't return an error, this check is just a best | ||
418 | * effort to notify userspace as early as possible. | ||
419 | */ | ||
420 | if (unlikely(video->error)) | ||
421 | return -EIO; | ||
422 | |||
463 | addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); | 423 | addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); |
464 | if (IS_ERR_VALUE(addr)) | 424 | if (IS_ERR_VALUE(addr)) |
465 | return -EIO; | 425 | return -EIO; |
@@ -496,6 +456,12 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf) | |||
496 | unsigned int empty; | 456 | unsigned int empty; |
497 | unsigned int start; | 457 | unsigned int start; |
498 | 458 | ||
459 | if (unlikely(video->error)) { | ||
460 | buf->state = ISP_BUF_STATE_ERROR; | ||
461 | wake_up(&buf->wait); | ||
462 | return; | ||
463 | } | ||
464 | |||
499 | empty = list_empty(&video->dmaqueue); | 465 | empty = list_empty(&video->dmaqueue); |
500 | list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue); | 466 | list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue); |
501 | 467 | ||
@@ -618,6 +584,36 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) | |||
618 | } | 584 | } |
619 | 585 | ||
620 | /* | 586 | /* |
587 | * omap3isp_video_cancel_stream - Cancel stream on a video node | ||
588 | * @video: ISP video object | ||
589 | * | ||
590 | * Cancelling a stream mark all buffers on the video node as erroneous and makes | ||
591 | * sure no new buffer can be queued. | ||
592 | */ | ||
593 | void omap3isp_video_cancel_stream(struct isp_video *video) | ||
594 | { | ||
595 | struct isp_video_queue *queue = video->queue; | ||
596 | unsigned long flags; | ||
597 | |||
598 | spin_lock_irqsave(&queue->irqlock, flags); | ||
599 | |||
600 | while (!list_empty(&video->dmaqueue)) { | ||
601 | struct isp_video_buffer *buf; | ||
602 | |||
603 | buf = list_first_entry(&video->dmaqueue, | ||
604 | struct isp_video_buffer, irqlist); | ||
605 | list_del(&buf->irqlist); | ||
606 | |||
607 | buf->state = ISP_BUF_STATE_ERROR; | ||
608 | wake_up(&buf->wait); | ||
609 | } | ||
610 | |||
611 | video->error = true; | ||
612 | |||
613 | spin_unlock_irqrestore(&queue->irqlock, flags); | ||
614 | } | ||
615 | |||
616 | /* | ||
621 | * omap3isp_video_resume - Perform resume operation on the buffers | 617 | * omap3isp_video_resume - Perform resume operation on the buffers |
622 | * @video: ISP video object | 618 | * @video: ISP video object |
623 | * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise | 619 | * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise |
@@ -1051,11 +1047,6 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
1051 | if (ret < 0) | 1047 | if (ret < 0) |
1052 | goto err_check_format; | 1048 | goto err_check_format; |
1053 | 1049 | ||
1054 | /* Validate the pipeline and update its state. */ | ||
1055 | ret = isp_video_validate_pipeline(pipe); | ||
1056 | if (ret < 0) | ||
1057 | goto err_check_format; | ||
1058 | |||
1059 | pipe->error = false; | 1050 | pipe->error = false; |
1060 | 1051 | ||
1061 | spin_lock_irqsave(&pipe->lock, flags); | 1052 | spin_lock_irqsave(&pipe->lock, flags); |
@@ -1159,6 +1150,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) | |||
1159 | omap3isp_video_queue_streamoff(&vfh->queue); | 1150 | omap3isp_video_queue_streamoff(&vfh->queue); |
1160 | video->queue = NULL; | 1151 | video->queue = NULL; |
1161 | video->streaming = 0; | 1152 | video->streaming = 0; |
1153 | video->error = false; | ||
1162 | 1154 | ||
1163 | if (video->isp->pdata->set_constraints) | 1155 | if (video->isp->pdata->set_constraints) |
1164 | video->isp->pdata->set_constraints(video->isp, false); | 1156 | video->isp->pdata->set_constraints(video->isp, false); |
@@ -1332,11 +1324,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name) | |||
1332 | switch (video->type) { | 1324 | switch (video->type) { |
1333 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1325 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1334 | direction = "output"; | 1326 | direction = "output"; |
1335 | video->pad.flags = MEDIA_PAD_FL_SINK; | 1327 | video->pad.flags = MEDIA_PAD_FL_SINK |
1328 | | MEDIA_PAD_FL_MUST_CONNECT; | ||
1336 | break; | 1329 | break; |
1337 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 1330 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
1338 | direction = "input"; | 1331 | direction = "input"; |
1339 | video->pad.flags = MEDIA_PAD_FL_SOURCE; | 1332 | video->pad.flags = MEDIA_PAD_FL_SOURCE |
1333 | | MEDIA_PAD_FL_MUST_CONNECT; | ||
1340 | video->video.vfl_dir = VFL_DIR_TX; | 1334 | video->video.vfl_dir = VFL_DIR_TX; |
1341 | break; | 1335 | break; |
1342 | 1336 | ||
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index 1ad470ec2b9d..4e194076cc60 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h | |||
@@ -178,6 +178,7 @@ struct isp_video { | |||
178 | /* Pipeline state */ | 178 | /* Pipeline state */ |
179 | struct isp_pipeline pipe; | 179 | struct isp_pipeline pipe; |
180 | struct mutex stream_lock; /* pipeline and stream states */ | 180 | struct mutex stream_lock; /* pipeline and stream states */ |
181 | bool error; | ||
181 | 182 | ||
182 | /* Video buffers queue */ | 183 | /* Video buffers queue */ |
183 | struct isp_video_queue *queue; | 184 | struct isp_video_queue *queue; |
@@ -207,6 +208,7 @@ int omap3isp_video_register(struct isp_video *video, | |||
207 | struct v4l2_device *vdev); | 208 | struct v4l2_device *vdev); |
208 | void omap3isp_video_unregister(struct isp_video *video); | 209 | void omap3isp_video_unregister(struct isp_video *video); |
209 | struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video); | 210 | struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video); |
211 | void omap3isp_video_cancel_stream(struct isp_video *video); | ||
210 | void omap3isp_video_resume(struct isp_video *video, int continuous); | 212 | void omap3isp_video_resume(struct isp_video *video, int continuous); |
211 | struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); | 213 | struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); |
212 | 214 | ||
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 0b2948376aee..0fcf7d75e841 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c | |||
@@ -136,10 +136,9 @@ static int g2d_buf_prepare(struct vb2_buffer *vb) | |||
136 | static void g2d_buf_queue(struct vb2_buffer *vb) | 136 | static void g2d_buf_queue(struct vb2_buffer *vb) |
137 | { | 137 | { |
138 | struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | 138 | struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
139 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); | 139 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); |
140 | } | 140 | } |
141 | 141 | ||
142 | |||
143 | static struct vb2_ops g2d_qops = { | 142 | static struct vb2_ops g2d_qops = { |
144 | .queue_setup = g2d_queue_setup, | 143 | .queue_setup = g2d_queue_setup, |
145 | .buf_prepare = g2d_buf_prepare, | 144 | .buf_prepare = g2d_buf_prepare, |
@@ -159,6 +158,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, | |||
159 | src_vq->mem_ops = &vb2_dma_contig_memops; | 158 | src_vq->mem_ops = &vb2_dma_contig_memops; |
160 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 159 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
161 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 160 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
161 | src_vq->lock = &ctx->dev->mutex; | ||
162 | 162 | ||
163 | ret = vb2_queue_init(src_vq); | 163 | ret = vb2_queue_init(src_vq); |
164 | if (ret) | 164 | if (ret) |
@@ -171,6 +171,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, | |||
171 | dst_vq->mem_ops = &vb2_dma_contig_memops; | 171 | dst_vq->mem_ops = &vb2_dma_contig_memops; |
172 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 172 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
173 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 173 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
174 | dst_vq->lock = &ctx->dev->mutex; | ||
174 | 175 | ||
175 | return vb2_queue_init(dst_vq); | 176 | return vb2_queue_init(dst_vq); |
176 | } | 177 | } |
@@ -253,9 +254,9 @@ static int g2d_open(struct file *file) | |||
253 | kfree(ctx); | 254 | kfree(ctx); |
254 | return -ERESTARTSYS; | 255 | return -ERESTARTSYS; |
255 | } | 256 | } |
256 | ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); | 257 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); |
257 | if (IS_ERR(ctx->m2m_ctx)) { | 258 | if (IS_ERR(ctx->fh.m2m_ctx)) { |
258 | ret = PTR_ERR(ctx->m2m_ctx); | 259 | ret = PTR_ERR(ctx->fh.m2m_ctx); |
259 | mutex_unlock(&dev->mutex); | 260 | mutex_unlock(&dev->mutex); |
260 | kfree(ctx); | 261 | kfree(ctx); |
261 | return ret; | 262 | return ret; |
@@ -324,7 +325,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) | |||
324 | struct vb2_queue *vq; | 325 | struct vb2_queue *vq; |
325 | struct g2d_frame *frm; | 326 | struct g2d_frame *frm; |
326 | 327 | ||
327 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | 328 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
328 | if (!vq) | 329 | if (!vq) |
329 | return -EINVAL; | 330 | return -EINVAL; |
330 | frm = get_frame(ctx, f->type); | 331 | frm = get_frame(ctx, f->type); |
@@ -384,7 +385,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) | |||
384 | ret = vidioc_try_fmt(file, prv, f); | 385 | ret = vidioc_try_fmt(file, prv, f); |
385 | if (ret) | 386 | if (ret) |
386 | return ret; | 387 | return ret; |
387 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | 388 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
388 | if (vb2_is_busy(vq)) { | 389 | if (vb2_is_busy(vq)) { |
389 | v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); | 390 | v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); |
390 | return -EBUSY; | 391 | return -EBUSY; |
@@ -410,72 +411,6 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) | |||
410 | return 0; | 411 | return 0; |
411 | } | 412 | } |
412 | 413 | ||
413 | static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait) | ||
414 | { | ||
415 | struct g2d_ctx *ctx = fh2ctx(file->private_data); | ||
416 | struct g2d_dev *dev = ctx->dev; | ||
417 | unsigned int res; | ||
418 | |||
419 | mutex_lock(&dev->mutex); | ||
420 | res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | ||
421 | mutex_unlock(&dev->mutex); | ||
422 | return res; | ||
423 | } | ||
424 | |||
425 | static int g2d_mmap(struct file *file, struct vm_area_struct *vma) | ||
426 | { | ||
427 | struct g2d_ctx *ctx = fh2ctx(file->private_data); | ||
428 | struct g2d_dev *dev = ctx->dev; | ||
429 | int ret; | ||
430 | |||
431 | if (mutex_lock_interruptible(&dev->mutex)) | ||
432 | return -ERESTARTSYS; | ||
433 | ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | ||
434 | mutex_unlock(&dev->mutex); | ||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
439 | struct v4l2_requestbuffers *reqbufs) | ||
440 | { | ||
441 | struct g2d_ctx *ctx = priv; | ||
442 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | ||
443 | } | ||
444 | |||
445 | static int vidioc_querybuf(struct file *file, void *priv, | ||
446 | struct v4l2_buffer *buf) | ||
447 | { | ||
448 | struct g2d_ctx *ctx = priv; | ||
449 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); | ||
450 | } | ||
451 | |||
452 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
453 | { | ||
454 | struct g2d_ctx *ctx = priv; | ||
455 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | ||
456 | } | ||
457 | |||
458 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
459 | { | ||
460 | struct g2d_ctx *ctx = priv; | ||
461 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | ||
462 | } | ||
463 | |||
464 | |||
465 | static int vidioc_streamon(struct file *file, void *priv, | ||
466 | enum v4l2_buf_type type) | ||
467 | { | ||
468 | struct g2d_ctx *ctx = priv; | ||
469 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); | ||
470 | } | ||
471 | |||
472 | static int vidioc_streamoff(struct file *file, void *priv, | ||
473 | enum v4l2_buf_type type) | ||
474 | { | ||
475 | struct g2d_ctx *ctx = priv; | ||
476 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | ||
477 | } | ||
478 | |||
479 | static int vidioc_cropcap(struct file *file, void *priv, | 414 | static int vidioc_cropcap(struct file *file, void *priv, |
480 | struct v4l2_cropcap *cr) | 415 | struct v4l2_cropcap *cr) |
481 | { | 416 | { |
@@ -551,20 +486,6 @@ static int vidioc_s_crop(struct file *file, void *prv, const struct v4l2_crop *c | |||
551 | return 0; | 486 | return 0; |
552 | } | 487 | } |
553 | 488 | ||
554 | static void g2d_lock(void *prv) | ||
555 | { | ||
556 | struct g2d_ctx *ctx = prv; | ||
557 | struct g2d_dev *dev = ctx->dev; | ||
558 | mutex_lock(&dev->mutex); | ||
559 | } | ||
560 | |||
561 | static void g2d_unlock(void *prv) | ||
562 | { | ||
563 | struct g2d_ctx *ctx = prv; | ||
564 | struct g2d_dev *dev = ctx->dev; | ||
565 | mutex_unlock(&dev->mutex); | ||
566 | } | ||
567 | |||
568 | static void job_abort(void *prv) | 489 | static void job_abort(void *prv) |
569 | { | 490 | { |
570 | struct g2d_ctx *ctx = prv; | 491 | struct g2d_ctx *ctx = prv; |
@@ -589,8 +510,8 @@ static void device_run(void *prv) | |||
589 | 510 | ||
590 | dev->curr = ctx; | 511 | dev->curr = ctx; |
591 | 512 | ||
592 | src = v4l2_m2m_next_src_buf(ctx->m2m_ctx); | 513 | src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
593 | dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); | 514 | dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
594 | 515 | ||
595 | clk_enable(dev->gate); | 516 | clk_enable(dev->gate); |
596 | g2d_reset(dev); | 517 | g2d_reset(dev); |
@@ -631,8 +552,8 @@ static irqreturn_t g2d_isr(int irq, void *prv) | |||
631 | 552 | ||
632 | BUG_ON(ctx == NULL); | 553 | BUG_ON(ctx == NULL); |
633 | 554 | ||
634 | src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | 555 | src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
635 | dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | 556 | dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); |
636 | 557 | ||
637 | BUG_ON(src == NULL); | 558 | BUG_ON(src == NULL); |
638 | BUG_ON(dst == NULL); | 559 | BUG_ON(dst == NULL); |
@@ -642,7 +563,7 @@ static irqreturn_t g2d_isr(int irq, void *prv) | |||
642 | 563 | ||
643 | v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); | 564 | v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); |
644 | v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); | 565 | v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); |
645 | v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); | 566 | v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); |
646 | 567 | ||
647 | dev->curr = NULL; | 568 | dev->curr = NULL; |
648 | wake_up(&dev->irq_queue); | 569 | wake_up(&dev->irq_queue); |
@@ -653,9 +574,9 @@ static const struct v4l2_file_operations g2d_fops = { | |||
653 | .owner = THIS_MODULE, | 574 | .owner = THIS_MODULE, |
654 | .open = g2d_open, | 575 | .open = g2d_open, |
655 | .release = g2d_release, | 576 | .release = g2d_release, |
656 | .poll = g2d_poll, | 577 | .poll = v4l2_m2m_fop_poll, |
657 | .unlocked_ioctl = video_ioctl2, | 578 | .unlocked_ioctl = video_ioctl2, |
658 | .mmap = g2d_mmap, | 579 | .mmap = v4l2_m2m_fop_mmap, |
659 | }; | 580 | }; |
660 | 581 | ||
661 | static const struct v4l2_ioctl_ops g2d_ioctl_ops = { | 582 | static const struct v4l2_ioctl_ops g2d_ioctl_ops = { |
@@ -671,14 +592,13 @@ static const struct v4l2_ioctl_ops g2d_ioctl_ops = { | |||
671 | .vidioc_try_fmt_vid_out = vidioc_try_fmt, | 592 | .vidioc_try_fmt_vid_out = vidioc_try_fmt, |
672 | .vidioc_s_fmt_vid_out = vidioc_s_fmt, | 593 | .vidioc_s_fmt_vid_out = vidioc_s_fmt, |
673 | 594 | ||
674 | .vidioc_reqbufs = vidioc_reqbufs, | 595 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
675 | .vidioc_querybuf = vidioc_querybuf, | 596 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
676 | 597 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, | |
677 | .vidioc_qbuf = vidioc_qbuf, | 598 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, |
678 | .vidioc_dqbuf = vidioc_dqbuf, | ||
679 | 599 | ||
680 | .vidioc_streamon = vidioc_streamon, | 600 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
681 | .vidioc_streamoff = vidioc_streamoff, | 601 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
682 | 602 | ||
683 | .vidioc_g_crop = vidioc_g_crop, | 603 | .vidioc_g_crop = vidioc_g_crop, |
684 | .vidioc_s_crop = vidioc_s_crop, | 604 | .vidioc_s_crop = vidioc_s_crop, |
@@ -697,8 +617,6 @@ static struct video_device g2d_videodev = { | |||
697 | static struct v4l2_m2m_ops g2d_m2m_ops = { | 617 | static struct v4l2_m2m_ops g2d_m2m_ops = { |
698 | .device_run = device_run, | 618 | .device_run = device_run, |
699 | .job_abort = job_abort, | 619 | .job_abort = job_abort, |
700 | .lock = g2d_lock, | ||
701 | .unlock = g2d_unlock, | ||
702 | }; | 620 | }; |
703 | 621 | ||
704 | static const struct of_device_id exynos_g2d_match[]; | 622 | static const struct of_device_id exynos_g2d_match[]; |
diff --git a/drivers/media/platform/s5p-g2d/g2d.h b/drivers/media/platform/s5p-g2d/g2d.h index 300ca05ba404..b0e52ab7ecdb 100644 --- a/drivers/media/platform/s5p-g2d/g2d.h +++ b/drivers/media/platform/s5p-g2d/g2d.h | |||
@@ -57,7 +57,6 @@ struct g2d_frame { | |||
57 | struct g2d_ctx { | 57 | struct g2d_ctx { |
58 | struct v4l2_fh fh; | 58 | struct v4l2_fh fh; |
59 | struct g2d_dev *dev; | 59 | struct g2d_dev *dev; |
60 | struct v4l2_m2m_ctx *m2m_ctx; | ||
61 | struct g2d_frame in; | 60 | struct g2d_frame in; |
62 | struct g2d_frame out; | 61 | struct g2d_frame out; |
63 | struct v4l2_ctrl *ctrl_hflip; | 62 | struct v4l2_ctrl *ctrl_hflip; |
diff --git a/drivers/media/platform/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile index d18cb5edd2d5..a1a9169254c3 100644 --- a/drivers/media/platform/s5p-jpeg/Makefile +++ b/drivers/media/platform/s5p-jpeg/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | s5p-jpeg-objs := jpeg-core.o | 1 | s5p-jpeg-objs := jpeg-core.o jpeg-hw-exynos4.o jpeg-hw-s5p.o |
2 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o | 2 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 9b88a4601007..a1c78c870b68 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c | |||
@@ -1,9 +1,10 @@ | |||
1 | /* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c | 1 | /* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c |
2 | * | 2 | * |
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | 3 | * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd. |
4 | * http://www.samsung.com | 4 | * http://www.samsung.com |
5 | * | 5 | * |
6 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 6 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> |
7 | * Author: Jacek Anaszewski <j.anaszewski@samsung.com> | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
@@ -17,6 +18,7 @@ | |||
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
18 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/of.h> | ||
20 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
21 | #include <linux/pm_runtime.h> | 23 | #include <linux/pm_runtime.h> |
22 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -28,70 +30,234 @@ | |||
28 | #include <media/videobuf2-dma-contig.h> | 30 | #include <media/videobuf2-dma-contig.h> |
29 | 31 | ||
30 | #include "jpeg-core.h" | 32 | #include "jpeg-core.h" |
31 | #include "jpeg-hw.h" | 33 | #include "jpeg-hw-s5p.h" |
34 | #include "jpeg-hw-exynos4.h" | ||
35 | #include "jpeg-regs.h" | ||
32 | 36 | ||
33 | static struct s5p_jpeg_fmt formats_enc[] = { | 37 | static struct s5p_jpeg_fmt sjpeg_formats[] = { |
34 | { | 38 | { |
35 | .name = "JPEG JFIF", | 39 | .name = "JPEG JFIF", |
36 | .fourcc = V4L2_PIX_FMT_JPEG, | 40 | .fourcc = V4L2_PIX_FMT_JPEG, |
41 | .flags = SJPEG_FMT_FLAG_ENC_CAPTURE | | ||
42 | SJPEG_FMT_FLAG_DEC_OUTPUT | | ||
43 | SJPEG_FMT_FLAG_S5P | | ||
44 | SJPEG_FMT_FLAG_EXYNOS4, | ||
45 | }, | ||
46 | { | ||
47 | .name = "YUV 4:2:2 packed, YCbYCr", | ||
48 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
49 | .depth = 16, | ||
37 | .colplanes = 1, | 50 | .colplanes = 1, |
38 | .types = MEM2MEM_CAPTURE, | 51 | .h_align = 4, |
52 | .v_align = 3, | ||
53 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
54 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
55 | SJPEG_FMT_FLAG_S5P | | ||
56 | SJPEG_FMT_NON_RGB, | ||
57 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | ||
39 | }, | 58 | }, |
40 | { | 59 | { |
41 | .name = "YUV 4:2:2 packed, YCbYCr", | 60 | .name = "YUV 4:2:2 packed, YCbYCr", |
42 | .fourcc = V4L2_PIX_FMT_YUYV, | 61 | .fourcc = V4L2_PIX_FMT_YUYV, |
43 | .depth = 16, | 62 | .depth = 16, |
44 | .colplanes = 1, | 63 | .colplanes = 1, |
45 | .types = MEM2MEM_OUTPUT, | 64 | .h_align = 1, |
65 | .v_align = 0, | ||
66 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
67 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
68 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
69 | SJPEG_FMT_NON_RGB, | ||
70 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | ||
71 | }, | ||
72 | { | ||
73 | .name = "YUV 4:2:2 packed, YCrYCb", | ||
74 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
75 | .depth = 16, | ||
76 | .colplanes = 1, | ||
77 | .h_align = 1, | ||
78 | .v_align = 0, | ||
79 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
80 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
81 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
82 | SJPEG_FMT_NON_RGB, | ||
83 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | ||
46 | }, | 84 | }, |
47 | { | 85 | { |
48 | .name = "RGB565", | 86 | .name = "RGB565", |
49 | .fourcc = V4L2_PIX_FMT_RGB565, | 87 | .fourcc = V4L2_PIX_FMT_RGB565, |
50 | .depth = 16, | 88 | .depth = 16, |
51 | .colplanes = 1, | 89 | .colplanes = 1, |
52 | .types = MEM2MEM_OUTPUT, | 90 | .h_align = 0, |
91 | .v_align = 0, | ||
92 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
93 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
94 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
95 | SJPEG_FMT_RGB, | ||
96 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, | ||
53 | }, | 97 | }, |
54 | }; | ||
55 | #define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc) | ||
56 | |||
57 | static struct s5p_jpeg_fmt formats_dec[] = { | ||
58 | { | 98 | { |
59 | .name = "YUV 4:2:0 planar, YCbCr", | 99 | .name = "RGB565", |
60 | .fourcc = V4L2_PIX_FMT_YUV420, | 100 | .fourcc = V4L2_PIX_FMT_RGB565, |
61 | .depth = 12, | 101 | .depth = 16, |
62 | .colplanes = 3, | 102 | .colplanes = 1, |
63 | .h_align = 4, | 103 | .h_align = 0, |
64 | .v_align = 4, | 104 | .v_align = 0, |
65 | .types = MEM2MEM_CAPTURE, | 105 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | |
106 | SJPEG_FMT_FLAG_S5P | | ||
107 | SJPEG_FMT_RGB, | ||
108 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, | ||
66 | }, | 109 | }, |
67 | { | 110 | { |
68 | .name = "YUV 4:2:2 packed, YCbYCr", | 111 | .name = "ARGB8888, 32 bpp", |
69 | .fourcc = V4L2_PIX_FMT_YUYV, | 112 | .fourcc = V4L2_PIX_FMT_RGB32, |
70 | .depth = 16, | 113 | .depth = 32, |
71 | .colplanes = 1, | 114 | .colplanes = 1, |
115 | .h_align = 0, | ||
116 | .v_align = 0, | ||
117 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
118 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
119 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
120 | SJPEG_FMT_RGB, | ||
121 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, | ||
122 | }, | ||
123 | { | ||
124 | .name = "YUV 4:4:4 planar, Y/CbCr", | ||
125 | .fourcc = V4L2_PIX_FMT_NV24, | ||
126 | .depth = 24, | ||
127 | .colplanes = 2, | ||
128 | .h_align = 0, | ||
129 | .v_align = 0, | ||
130 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
131 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
132 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
133 | SJPEG_FMT_NON_RGB, | ||
134 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, | ||
135 | }, | ||
136 | { | ||
137 | .name = "YUV 4:4:4 planar, Y/CrCb", | ||
138 | .fourcc = V4L2_PIX_FMT_NV42, | ||
139 | .depth = 24, | ||
140 | .colplanes = 2, | ||
141 | .h_align = 0, | ||
142 | .v_align = 0, | ||
143 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
144 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
145 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
146 | SJPEG_FMT_NON_RGB, | ||
147 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, | ||
148 | }, | ||
149 | { | ||
150 | .name = "YUV 4:2:2 planar, Y/CrCb", | ||
151 | .fourcc = V4L2_PIX_FMT_NV61, | ||
152 | .depth = 16, | ||
153 | .colplanes = 2, | ||
154 | .h_align = 1, | ||
155 | .v_align = 0, | ||
156 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
157 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
158 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
159 | SJPEG_FMT_NON_RGB, | ||
160 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | ||
161 | }, | ||
162 | { | ||
163 | .name = "YUV 4:2:2 planar, Y/CbCr", | ||
164 | .fourcc = V4L2_PIX_FMT_NV16, | ||
165 | .depth = 16, | ||
166 | .colplanes = 2, | ||
167 | .h_align = 1, | ||
168 | .v_align = 0, | ||
169 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
170 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
171 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
172 | SJPEG_FMT_NON_RGB, | ||
173 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | ||
174 | }, | ||
175 | { | ||
176 | .name = "YUV 4:2:0 planar, Y/CbCr", | ||
177 | .fourcc = V4L2_PIX_FMT_NV12, | ||
178 | .depth = 16, | ||
179 | .colplanes = 2, | ||
180 | .h_align = 1, | ||
181 | .v_align = 1, | ||
182 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
183 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
184 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
185 | SJPEG_FMT_NON_RGB, | ||
186 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | ||
187 | }, | ||
188 | { | ||
189 | .name = "YUV 4:2:0 planar, Y/CbCr", | ||
190 | .fourcc = V4L2_PIX_FMT_NV12, | ||
191 | .depth = 16, | ||
192 | .colplanes = 4, | ||
72 | .h_align = 4, | 193 | .h_align = 4, |
73 | .v_align = 3, | 194 | .v_align = 1, |
74 | .types = MEM2MEM_CAPTURE, | 195 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | |
196 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
197 | SJPEG_FMT_FLAG_S5P | | ||
198 | SJPEG_FMT_NON_RGB, | ||
199 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | ||
75 | }, | 200 | }, |
76 | { | 201 | { |
77 | .name = "JPEG JFIF", | 202 | .name = "YUV 4:2:0 planar, Y/CrCb", |
78 | .fourcc = V4L2_PIX_FMT_JPEG, | 203 | .fourcc = V4L2_PIX_FMT_NV21, |
204 | .depth = 12, | ||
205 | .colplanes = 2, | ||
206 | .h_align = 1, | ||
207 | .v_align = 1, | ||
208 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
209 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
210 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
211 | SJPEG_FMT_NON_RGB, | ||
212 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | ||
213 | }, | ||
214 | { | ||
215 | .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr", | ||
216 | .fourcc = V4L2_PIX_FMT_YUV420, | ||
217 | .depth = 12, | ||
218 | .colplanes = 3, | ||
219 | .h_align = 1, | ||
220 | .v_align = 1, | ||
221 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | | ||
222 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
223 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
224 | SJPEG_FMT_NON_RGB, | ||
225 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | ||
226 | }, | ||
227 | { | ||
228 | .name = "Gray", | ||
229 | .fourcc = V4L2_PIX_FMT_GREY, | ||
230 | .depth = 8, | ||
79 | .colplanes = 1, | 231 | .colplanes = 1, |
80 | .types = MEM2MEM_OUTPUT, | 232 | .flags = SJPEG_FMT_FLAG_ENC_OUTPUT | |
233 | SJPEG_FMT_FLAG_DEC_CAPTURE | | ||
234 | SJPEG_FMT_FLAG_EXYNOS4 | | ||
235 | SJPEG_FMT_NON_RGB, | ||
236 | .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, | ||
81 | }, | 237 | }, |
82 | }; | 238 | }; |
83 | #define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec) | 239 | #define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats) |
84 | 240 | ||
85 | static const unsigned char qtbl_luminance[4][64] = { | 241 | static const unsigned char qtbl_luminance[4][64] = { |
86 | {/* level 1 - high quality */ | 242 | {/*level 0 - high compression quality */ |
87 | 8, 6, 6, 8, 12, 14, 16, 17, | 243 | 20, 16, 25, 39, 50, 46, 62, 68, |
88 | 6, 6, 6, 8, 10, 13, 12, 15, | 244 | 16, 18, 23, 38, 38, 53, 65, 68, |
89 | 6, 6, 7, 8, 13, 14, 18, 24, | 245 | 25, 23, 31, 38, 53, 65, 68, 68, |
90 | 8, 8, 8, 14, 13, 19, 24, 35, | 246 | 39, 38, 38, 53, 65, 68, 68, 68, |
91 | 12, 10, 13, 13, 20, 26, 34, 39, | 247 | 50, 38, 53, 65, 68, 68, 68, 68, |
92 | 14, 13, 14, 19, 26, 34, 39, 39, | 248 | 46, 53, 65, 68, 68, 68, 68, 68, |
93 | 16, 12, 18, 24, 34, 39, 39, 39, | 249 | 62, 65, 68, 68, 68, 68, 68, 68, |
94 | 17, 15, 24, 35, 39, 39, 39, 39 | 250 | 68, 68, 68, 68, 68, 68, 68, 68 |
251 | }, | ||
252 | {/* level 1 */ | ||
253 | 16, 11, 11, 16, 23, 27, 31, 30, | ||
254 | 11, 12, 12, 15, 20, 23, 23, 30, | ||
255 | 11, 12, 13, 16, 23, 26, 35, 47, | ||
256 | 16, 15, 16, 23, 26, 37, 47, 64, | ||
257 | 23, 20, 23, 26, 39, 51, 64, 64, | ||
258 | 27, 23, 26, 37, 51, 64, 64, 64, | ||
259 | 31, 23, 35, 47, 64, 64, 64, 64, | ||
260 | 30, 30, 47, 64, 64, 64, 64, 64 | ||
95 | }, | 261 | }, |
96 | {/* level 2 */ | 262 | {/* level 2 */ |
97 | 12, 8, 8, 12, 17, 21, 24, 23, | 263 | 12, 8, 8, 12, 17, 21, 24, 23, |
@@ -103,38 +269,38 @@ static const unsigned char qtbl_luminance[4][64] = { | |||
103 | 24, 18, 27, 36, 51, 59, 59, 59, | 269 | 24, 18, 27, 36, 51, 59, 59, 59, |
104 | 23, 23, 36, 53, 59, 59, 59, 59 | 270 | 23, 23, 36, 53, 59, 59, 59, 59 |
105 | }, | 271 | }, |
106 | {/* level 3 */ | 272 | {/* level 3 - low compression quality */ |
107 | 16, 11, 11, 16, 23, 27, 31, 30, | 273 | 8, 6, 6, 8, 12, 14, 16, 17, |
108 | 11, 12, 12, 15, 20, 23, 23, 30, | 274 | 6, 6, 6, 8, 10, 13, 12, 15, |
109 | 11, 12, 13, 16, 23, 26, 35, 47, | 275 | 6, 6, 7, 8, 13, 14, 18, 24, |
110 | 16, 15, 16, 23, 26, 37, 47, 64, | 276 | 8, 8, 8, 14, 13, 19, 24, 35, |
111 | 23, 20, 23, 26, 39, 51, 64, 64, | 277 | 12, 10, 13, 13, 20, 26, 34, 39, |
112 | 27, 23, 26, 37, 51, 64, 64, 64, | 278 | 14, 13, 14, 19, 26, 34, 39, 39, |
113 | 31, 23, 35, 47, 64, 64, 64, 64, | 279 | 16, 12, 18, 24, 34, 39, 39, 39, |
114 | 30, 30, 47, 64, 64, 64, 64, 64 | 280 | 17, 15, 24, 35, 39, 39, 39, 39 |
115 | }, | ||
116 | {/*level 4 - low quality */ | ||
117 | 20, 16, 25, 39, 50, 46, 62, 68, | ||
118 | 16, 18, 23, 38, 38, 53, 65, 68, | ||
119 | 25, 23, 31, 38, 53, 65, 68, 68, | ||
120 | 39, 38, 38, 53, 65, 68, 68, 68, | ||
121 | 50, 38, 53, 65, 68, 68, 68, 68, | ||
122 | 46, 53, 65, 68, 68, 68, 68, 68, | ||
123 | 62, 65, 68, 68, 68, 68, 68, 68, | ||
124 | 68, 68, 68, 68, 68, 68, 68, 68 | ||
125 | } | 281 | } |
126 | }; | 282 | }; |
127 | 283 | ||
128 | static const unsigned char qtbl_chrominance[4][64] = { | 284 | static const unsigned char qtbl_chrominance[4][64] = { |
129 | {/* level 1 - high quality */ | 285 | {/*level 0 - high compression quality */ |
130 | 9, 8, 9, 11, 14, 17, 19, 24, | 286 | 21, 25, 32, 38, 54, 68, 68, 68, |
131 | 8, 10, 9, 11, 14, 13, 17, 22, | 287 | 25, 28, 24, 38, 54, 68, 68, 68, |
132 | 9, 9, 13, 14, 13, 15, 23, 26, | 288 | 32, 24, 32, 43, 66, 68, 68, 68, |
133 | 11, 11, 14, 14, 15, 20, 26, 33, | 289 | 38, 38, 43, 53, 68, 68, 68, 68, |
134 | 14, 14, 13, 15, 20, 24, 33, 39, | 290 | 54, 54, 66, 68, 68, 68, 68, 68, |
135 | 17, 13, 15, 20, 24, 32, 39, 39, | 291 | 68, 68, 68, 68, 68, 68, 68, 68, |
136 | 19, 17, 23, 26, 33, 39, 39, 39, | 292 | 68, 68, 68, 68, 68, 68, 68, 68, |
137 | 24, 22, 26, 33, 39, 39, 39, 39 | 293 | 68, 68, 68, 68, 68, 68, 68, 68 |
294 | }, | ||
295 | {/* level 1 */ | ||
296 | 17, 15, 17, 21, 20, 26, 38, 48, | ||
297 | 15, 19, 18, 17, 20, 26, 35, 43, | ||
298 | 17, 18, 20, 22, 26, 30, 46, 53, | ||
299 | 21, 17, 22, 28, 30, 39, 53, 64, | ||
300 | 20, 20, 26, 30, 39, 48, 64, 64, | ||
301 | 26, 26, 30, 39, 48, 63, 64, 64, | ||
302 | 38, 35, 46, 53, 64, 64, 64, 64, | ||
303 | 48, 43, 53, 64, 64, 64, 64, 64 | ||
138 | }, | 304 | }, |
139 | {/* level 2 */ | 305 | {/* level 2 */ |
140 | 13, 11, 13, 16, 20, 20, 29, 37, | 306 | 13, 11, 13, 16, 20, 20, 29, 37, |
@@ -146,25 +312,15 @@ static const unsigned char qtbl_chrominance[4][64] = { | |||
146 | 29, 26, 35, 40, 50, 59, 59, 59, | 312 | 29, 26, 35, 40, 50, 59, 59, 59, |
147 | 37, 32, 40, 50, 59, 59, 59, 59 | 313 | 37, 32, 40, 50, 59, 59, 59, 59 |
148 | }, | 314 | }, |
149 | {/* level 3 */ | 315 | {/* level 3 - low compression quality */ |
150 | 17, 15, 17, 21, 20, 26, 38, 48, | 316 | 9, 8, 9, 11, 14, 17, 19, 24, |
151 | 15, 19, 18, 17, 20, 26, 35, 43, | 317 | 8, 10, 9, 11, 14, 13, 17, 22, |
152 | 17, 18, 20, 22, 26, 30, 46, 53, | 318 | 9, 9, 13, 14, 13, 15, 23, 26, |
153 | 21, 17, 22, 28, 30, 39, 53, 64, | 319 | 11, 11, 14, 14, 15, 20, 26, 33, |
154 | 20, 20, 26, 30, 39, 48, 64, 64, | 320 | 14, 14, 13, 15, 20, 24, 33, 39, |
155 | 26, 26, 30, 39, 48, 63, 64, 64, | 321 | 17, 13, 15, 20, 24, 32, 39, 39, |
156 | 38, 35, 46, 53, 64, 64, 64, 64, | 322 | 19, 17, 23, 26, 33, 39, 39, 39, |
157 | 48, 43, 53, 64, 64, 64, 64, 64 | 323 | 24, 22, 26, 33, 39, 39, 39, 39 |
158 | }, | ||
159 | {/*level 4 - low quality */ | ||
160 | 21, 25, 32, 38, 54, 68, 68, 68, | ||
161 | 25, 28, 24, 38, 54, 68, 68, 68, | ||
162 | 32, 24, 32, 43, 66, 68, 68, 68, | ||
163 | 38, 38, 43, 53, 68, 68, 68, 68, | ||
164 | 54, 54, 66, 68, 68, 68, 68, 68, | ||
165 | 68, 68, 68, 68, 68, 68, 68, 68, | ||
166 | 68, 68, 68, 68, 68, 68, 68, 68, | ||
167 | 68, 68, 68, 68, 68, 68, 68, 68 | ||
168 | } | 324 | } |
169 | }; | 325 | }; |
170 | 326 | ||
@@ -202,6 +358,106 @@ static const unsigned char hactblg0[162] = { | |||
202 | 0xf9, 0xfa | 358 | 0xf9, 0xfa |
203 | }; | 359 | }; |
204 | 360 | ||
361 | /* | ||
362 | * Fourcc downgrade schema lookup tables for 422 and 420 | ||
363 | * chroma subsampling - fourcc on each position maps on the | ||
364 | * fourcc from the table fourcc_to_dwngrd_schema_id which allows | ||
365 | * to get the most suitable fourcc counterpart for the given | ||
366 | * downgraded subsampling property. | ||
367 | */ | ||
368 | static const u32 subs422_fourcc_dwngrd_schema[] = { | ||
369 | V4L2_PIX_FMT_NV16, | ||
370 | V4L2_PIX_FMT_NV61, | ||
371 | }; | ||
372 | |||
373 | static const u32 subs420_fourcc_dwngrd_schema[] = { | ||
374 | V4L2_PIX_FMT_NV12, | ||
375 | V4L2_PIX_FMT_NV21, | ||
376 | V4L2_PIX_FMT_NV12, | ||
377 | V4L2_PIX_FMT_NV21, | ||
378 | V4L2_PIX_FMT_NV12, | ||
379 | V4L2_PIX_FMT_NV21, | ||
380 | V4L2_PIX_FMT_GREY, | ||
381 | V4L2_PIX_FMT_GREY, | ||
382 | V4L2_PIX_FMT_GREY, | ||
383 | V4L2_PIX_FMT_GREY, | ||
384 | }; | ||
385 | |||
386 | /* | ||
387 | * Lookup table for translation of a fourcc to the position | ||
388 | * of its downgraded counterpart in the *fourcc_dwngrd_schema | ||
389 | * tables. | ||
390 | */ | ||
391 | static const u32 fourcc_to_dwngrd_schema_id[] = { | ||
392 | V4L2_PIX_FMT_NV24, | ||
393 | V4L2_PIX_FMT_NV42, | ||
394 | V4L2_PIX_FMT_NV16, | ||
395 | V4L2_PIX_FMT_NV61, | ||
396 | V4L2_PIX_FMT_YUYV, | ||
397 | V4L2_PIX_FMT_YVYU, | ||
398 | V4L2_PIX_FMT_NV12, | ||
399 | V4L2_PIX_FMT_NV21, | ||
400 | V4L2_PIX_FMT_YUV420, | ||
401 | V4L2_PIX_FMT_GREY, | ||
402 | }; | ||
403 | |||
404 | static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc) | ||
405 | { | ||
406 | int i; | ||
407 | for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) { | ||
408 | if (fourcc_to_dwngrd_schema_id[i] == fourcc) | ||
409 | return i; | ||
410 | } | ||
411 | |||
412 | return -EINVAL; | ||
413 | } | ||
414 | |||
415 | static int s5p_jpeg_adjust_fourcc_to_subsampling( | ||
416 | enum v4l2_jpeg_chroma_subsampling subs, | ||
417 | u32 in_fourcc, | ||
418 | u32 *out_fourcc, | ||
419 | struct s5p_jpeg_ctx *ctx) | ||
420 | { | ||
421 | int dwngrd_sch_id; | ||
422 | |||
423 | if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) { | ||
424 | dwngrd_sch_id = | ||
425 | s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc); | ||
426 | if (dwngrd_sch_id < 0) | ||
427 | return -EINVAL; | ||
428 | } | ||
429 | |||
430 | switch (ctx->subsampling) { | ||
431 | case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY: | ||
432 | *out_fourcc = V4L2_PIX_FMT_GREY; | ||
433 | break; | ||
434 | case V4L2_JPEG_CHROMA_SUBSAMPLING_420: | ||
435 | if (dwngrd_sch_id > | ||
436 | ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1) | ||
437 | return -EINVAL; | ||
438 | *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id]; | ||
439 | break; | ||
440 | case V4L2_JPEG_CHROMA_SUBSAMPLING_422: | ||
441 | if (dwngrd_sch_id > | ||
442 | ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1) | ||
443 | return -EINVAL; | ||
444 | *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id]; | ||
445 | break; | ||
446 | default: | ||
447 | *out_fourcc = V4L2_PIX_FMT_GREY; | ||
448 | break; | ||
449 | } | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int exynos4x12_decoded_subsampling[] = { | ||
455 | V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, | ||
456 | V4L2_JPEG_CHROMA_SUBSAMPLING_444, | ||
457 | V4L2_JPEG_CHROMA_SUBSAMPLING_422, | ||
458 | V4L2_JPEG_CHROMA_SUBSAMPLING_420, | ||
459 | }; | ||
460 | |||
205 | static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) | 461 | static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) |
206 | { | 462 | { |
207 | return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler); | 463 | return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler); |
@@ -212,8 +468,24 @@ static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) | |||
212 | return container_of(fh, struct s5p_jpeg_ctx, fh); | 468 | return container_of(fh, struct s5p_jpeg_ctx, fh); |
213 | } | 469 | } |
214 | 470 | ||
215 | static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, | 471 | static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx) |
216 | unsigned long tab, int len) | 472 | { |
473 | WARN_ON(ctx->subsampling > 3); | ||
474 | |||
475 | if (ctx->jpeg->variant->version == SJPEG_S5P) { | ||
476 | if (ctx->subsampling > 2) | ||
477 | return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; | ||
478 | return ctx->subsampling; | ||
479 | } else { | ||
480 | if (ctx->subsampling > 2) | ||
481 | return V4L2_JPEG_CHROMA_SUBSAMPLING_420; | ||
482 | return exynos4x12_decoded_subsampling[ctx->subsampling]; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | static inline void s5p_jpeg_set_qtbl(void __iomem *regs, | ||
487 | const unsigned char *qtbl, | ||
488 | unsigned long tab, int len) | ||
217 | { | 489 | { |
218 | int i; | 490 | int i; |
219 | 491 | ||
@@ -221,22 +493,25 @@ static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, | |||
221 | writel((unsigned int)qtbl[i], regs + tab + (i * 0x04)); | 493 | writel((unsigned int)qtbl[i], regs + tab + (i * 0x04)); |
222 | } | 494 | } |
223 | 495 | ||
224 | static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality) | 496 | static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality) |
225 | { | 497 | { |
226 | /* this driver fills quantisation table 0 with data for luma */ | 498 | /* this driver fills quantisation table 0 with data for luma */ |
227 | jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0), | 499 | s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality], |
228 | ARRAY_SIZE(qtbl_luminance[quality])); | 500 | S5P_JPG_QTBL_CONTENT(0), |
501 | ARRAY_SIZE(qtbl_luminance[quality])); | ||
229 | } | 502 | } |
230 | 503 | ||
231 | static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality) | 504 | static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality) |
232 | { | 505 | { |
233 | /* this driver fills quantisation table 1 with data for chroma */ | 506 | /* this driver fills quantisation table 1 with data for chroma */ |
234 | jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1), | 507 | s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality], |
235 | ARRAY_SIZE(qtbl_chrominance[quality])); | 508 | S5P_JPG_QTBL_CONTENT(1), |
509 | ARRAY_SIZE(qtbl_chrominance[quality])); | ||
236 | } | 510 | } |
237 | 511 | ||
238 | static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl, | 512 | static inline void s5p_jpeg_set_htbl(void __iomem *regs, |
239 | unsigned long tab, int len) | 513 | const unsigned char *htbl, |
514 | unsigned long tab, int len) | ||
240 | { | 515 | { |
241 | int i; | 516 | int i; |
242 | 517 | ||
@@ -244,28 +519,84 @@ static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl, | |||
244 | writel((unsigned int)htbl[i], regs + tab + (i * 0x04)); | 519 | writel((unsigned int)htbl[i], regs + tab + (i * 0x04)); |
245 | } | 520 | } |
246 | 521 | ||
247 | static inline void jpeg_set_hdctbl(void __iomem *regs) | 522 | static inline void s5p_jpeg_set_hdctbl(void __iomem *regs) |
248 | { | 523 | { |
249 | /* this driver fills table 0 for this component */ | 524 | /* this driver fills table 0 for this component */ |
250 | jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0)); | 525 | s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), |
526 | ARRAY_SIZE(hdctbl0)); | ||
251 | } | 527 | } |
252 | 528 | ||
253 | static inline void jpeg_set_hdctblg(void __iomem *regs) | 529 | static inline void s5p_jpeg_set_hdctblg(void __iomem *regs) |
254 | { | 530 | { |
255 | /* this driver fills table 0 for this component */ | 531 | /* this driver fills table 0 for this component */ |
256 | jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0)); | 532 | s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), |
533 | ARRAY_SIZE(hdctblg0)); | ||
257 | } | 534 | } |
258 | 535 | ||
259 | static inline void jpeg_set_hactbl(void __iomem *regs) | 536 | static inline void s5p_jpeg_set_hactbl(void __iomem *regs) |
260 | { | 537 | { |
261 | /* this driver fills table 0 for this component */ | 538 | /* this driver fills table 0 for this component */ |
262 | jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0)); | 539 | s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), |
540 | ARRAY_SIZE(hactbl0)); | ||
263 | } | 541 | } |
264 | 542 | ||
265 | static inline void jpeg_set_hactblg(void __iomem *regs) | 543 | static inline void s5p_jpeg_set_hactblg(void __iomem *regs) |
266 | { | 544 | { |
267 | /* this driver fills table 0 for this component */ | 545 | /* this driver fills table 0 for this component */ |
268 | jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0)); | 546 | s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), |
547 | ARRAY_SIZE(hactblg0)); | ||
548 | } | ||
549 | |||
550 | static inline void exynos4_jpeg_set_tbl(void __iomem *regs, | ||
551 | const unsigned char *tbl, | ||
552 | unsigned long tab, int len) | ||
553 | { | ||
554 | int i; | ||
555 | unsigned int dword; | ||
556 | |||
557 | for (i = 0; i < len; i += 4) { | ||
558 | dword = tbl[i] | | ||
559 | (tbl[i + 1] << 8) | | ||
560 | (tbl[i + 2] << 16) | | ||
561 | (tbl[i + 3] << 24); | ||
562 | writel(dword, regs + tab + i); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality) | ||
567 | { | ||
568 | /* this driver fills quantisation table 0 with data for luma */ | ||
569 | exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality], | ||
570 | EXYNOS4_QTBL_CONTENT(0), | ||
571 | ARRAY_SIZE(qtbl_luminance[quality])); | ||
572 | } | ||
573 | |||
574 | static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality) | ||
575 | { | ||
576 | /* this driver fills quantisation table 1 with data for chroma */ | ||
577 | exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality], | ||
578 | EXYNOS4_QTBL_CONTENT(1), | ||
579 | ARRAY_SIZE(qtbl_chrominance[quality])); | ||
580 | } | ||
581 | |||
582 | void exynos4_jpeg_set_huff_tbl(void __iomem *base) | ||
583 | { | ||
584 | exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL, | ||
585 | ARRAY_SIZE(hdctbl0)); | ||
586 | exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL, | ||
587 | ARRAY_SIZE(hdctbl0)); | ||
588 | exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV, | ||
589 | ARRAY_SIZE(hdctblg0)); | ||
590 | exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV, | ||
591 | ARRAY_SIZE(hdctblg0)); | ||
592 | exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL, | ||
593 | ARRAY_SIZE(hactbl0)); | ||
594 | exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL, | ||
595 | ARRAY_SIZE(hactbl0)); | ||
596 | exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV, | ||
597 | ARRAY_SIZE(hactblg0)); | ||
598 | exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV, | ||
599 | ARRAY_SIZE(hactblg0)); | ||
269 | } | 600 | } |
270 | 601 | ||
271 | /* | 602 | /* |
@@ -276,8 +607,8 @@ static inline void jpeg_set_hactblg(void __iomem *regs) | |||
276 | 607 | ||
277 | static int queue_init(void *priv, struct vb2_queue *src_vq, | 608 | static int queue_init(void *priv, struct vb2_queue *src_vq, |
278 | struct vb2_queue *dst_vq); | 609 | struct vb2_queue *dst_vq); |
279 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, | 610 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx, |
280 | __u32 pixelformat); | 611 | __u32 pixelformat, unsigned int fmt_type); |
281 | static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx); | 612 | static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx); |
282 | 613 | ||
283 | static int s5p_jpeg_open(struct file *file) | 614 | static int s5p_jpeg_open(struct file *file) |
@@ -285,7 +616,7 @@ static int s5p_jpeg_open(struct file *file) | |||
285 | struct s5p_jpeg *jpeg = video_drvdata(file); | 616 | struct s5p_jpeg *jpeg = video_drvdata(file); |
286 | struct video_device *vfd = video_devdata(file); | 617 | struct video_device *vfd = video_devdata(file); |
287 | struct s5p_jpeg_ctx *ctx; | 618 | struct s5p_jpeg_ctx *ctx; |
288 | struct s5p_jpeg_fmt *out_fmt; | 619 | struct s5p_jpeg_fmt *out_fmt, *cap_fmt; |
289 | int ret = 0; | 620 | int ret = 0; |
290 | 621 | ||
291 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 622 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
@@ -306,24 +637,31 @@ static int s5p_jpeg_open(struct file *file) | |||
306 | ctx->jpeg = jpeg; | 637 | ctx->jpeg = jpeg; |
307 | if (vfd == jpeg->vfd_encoder) { | 638 | if (vfd == jpeg->vfd_encoder) { |
308 | ctx->mode = S5P_JPEG_ENCODE; | 639 | ctx->mode = S5P_JPEG_ENCODE; |
309 | out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565); | 640 | out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565, |
641 | FMT_TYPE_OUTPUT); | ||
642 | cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG, | ||
643 | FMT_TYPE_CAPTURE); | ||
310 | } else { | 644 | } else { |
311 | ctx->mode = S5P_JPEG_DECODE; | 645 | ctx->mode = S5P_JPEG_DECODE; |
312 | out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); | 646 | out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG, |
647 | FMT_TYPE_OUTPUT); | ||
648 | cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV, | ||
649 | FMT_TYPE_CAPTURE); | ||
313 | } | 650 | } |
314 | 651 | ||
315 | ret = s5p_jpeg_controls_create(ctx); | 652 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); |
316 | if (ret < 0) | 653 | if (IS_ERR(ctx->fh.m2m_ctx)) { |
317 | goto error; | 654 | ret = PTR_ERR(ctx->fh.m2m_ctx); |
318 | |||
319 | ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); | ||
320 | if (IS_ERR(ctx->m2m_ctx)) { | ||
321 | ret = PTR_ERR(ctx->m2m_ctx); | ||
322 | goto error; | 655 | goto error; |
323 | } | 656 | } |
324 | 657 | ||
325 | ctx->out_q.fmt = out_fmt; | 658 | ctx->out_q.fmt = out_fmt; |
326 | ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); | 659 | ctx->cap_q.fmt = cap_fmt; |
660 | |||
661 | ret = s5p_jpeg_controls_create(ctx); | ||
662 | if (ret < 0) | ||
663 | goto error; | ||
664 | |||
327 | mutex_unlock(&jpeg->lock); | 665 | mutex_unlock(&jpeg->lock); |
328 | return 0; | 666 | return 0; |
329 | 667 | ||
@@ -342,49 +680,23 @@ static int s5p_jpeg_release(struct file *file) | |||
342 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); | 680 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); |
343 | 681 | ||
344 | mutex_lock(&jpeg->lock); | 682 | mutex_lock(&jpeg->lock); |
345 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | 683 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
346 | mutex_unlock(&jpeg->lock); | ||
347 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | 684 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); |
348 | v4l2_fh_del(&ctx->fh); | 685 | v4l2_fh_del(&ctx->fh); |
349 | v4l2_fh_exit(&ctx->fh); | 686 | v4l2_fh_exit(&ctx->fh); |
350 | kfree(ctx); | 687 | kfree(ctx); |
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static unsigned int s5p_jpeg_poll(struct file *file, | ||
356 | struct poll_table_struct *wait) | ||
357 | { | ||
358 | struct s5p_jpeg *jpeg = video_drvdata(file); | ||
359 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); | ||
360 | unsigned int res; | ||
361 | |||
362 | mutex_lock(&jpeg->lock); | ||
363 | res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | ||
364 | mutex_unlock(&jpeg->lock); | 688 | mutex_unlock(&jpeg->lock); |
365 | return res; | ||
366 | } | ||
367 | |||
368 | static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) | ||
369 | { | ||
370 | struct s5p_jpeg *jpeg = video_drvdata(file); | ||
371 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); | ||
372 | int ret; | ||
373 | 689 | ||
374 | if (mutex_lock_interruptible(&jpeg->lock)) | 690 | return 0; |
375 | return -ERESTARTSYS; | ||
376 | ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | ||
377 | mutex_unlock(&jpeg->lock); | ||
378 | return ret; | ||
379 | } | 691 | } |
380 | 692 | ||
381 | static const struct v4l2_file_operations s5p_jpeg_fops = { | 693 | static const struct v4l2_file_operations s5p_jpeg_fops = { |
382 | .owner = THIS_MODULE, | 694 | .owner = THIS_MODULE, |
383 | .open = s5p_jpeg_open, | 695 | .open = s5p_jpeg_open, |
384 | .release = s5p_jpeg_release, | 696 | .release = s5p_jpeg_release, |
385 | .poll = s5p_jpeg_poll, | 697 | .poll = v4l2_m2m_fop_poll, |
386 | .unlocked_ioctl = video_ioctl2, | 698 | .unlocked_ioctl = video_ioctl2, |
387 | .mmap = s5p_jpeg_mmap, | 699 | .mmap = v4l2_m2m_fop_mmap, |
388 | }; | 700 | }; |
389 | 701 | ||
390 | /* | 702 | /* |
@@ -427,10 +739,11 @@ static void skip(struct s5p_jpeg_buffer *buf, long len) | |||
427 | } | 739 | } |
428 | 740 | ||
429 | static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, | 741 | static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, |
430 | unsigned long buffer, unsigned long size) | 742 | unsigned long buffer, unsigned long size, |
743 | struct s5p_jpeg_ctx *ctx) | ||
431 | { | 744 | { |
432 | int c, components, notfound; | 745 | int c, components, notfound; |
433 | unsigned int height, width, word; | 746 | unsigned int height, width, word, subsampling = 0; |
434 | long length; | 747 | long length; |
435 | struct s5p_jpeg_buffer jpeg_buffer; | 748 | struct s5p_jpeg_buffer jpeg_buffer; |
436 | 749 | ||
@@ -469,7 +782,15 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, | |||
469 | break; | 782 | break; |
470 | notfound = 0; | 783 | notfound = 0; |
471 | 784 | ||
472 | skip(&jpeg_buffer, components * 3); | 785 | if (components == 1) { |
786 | subsampling = 0x33; | ||
787 | } else { | ||
788 | skip(&jpeg_buffer, 1); | ||
789 | subsampling = get_byte(&jpeg_buffer); | ||
790 | skip(&jpeg_buffer, 1); | ||
791 | } | ||
792 | |||
793 | skip(&jpeg_buffer, components * 2); | ||
473 | break; | 794 | break; |
474 | 795 | ||
475 | /* skip payload-less markers */ | 796 | /* skip payload-less markers */ |
@@ -491,6 +812,24 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, | |||
491 | result->w = width; | 812 | result->w = width; |
492 | result->h = height; | 813 | result->h = height; |
493 | result->size = components; | 814 | result->size = components; |
815 | |||
816 | switch (subsampling) { | ||
817 | case 0x11: | ||
818 | ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444; | ||
819 | break; | ||
820 | case 0x21: | ||
821 | ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422; | ||
822 | break; | ||
823 | case 0x22: | ||
824 | ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420; | ||
825 | break; | ||
826 | case 0x33: | ||
827 | ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; | ||
828 | break; | ||
829 | default: | ||
830 | return false; | ||
831 | } | ||
832 | |||
494 | return !notfound; | 833 | return !notfound; |
495 | } | 834 | } |
496 | 835 | ||
@@ -521,13 +860,13 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, | |||
521 | return 0; | 860 | return 0; |
522 | } | 861 | } |
523 | 862 | ||
524 | static int enum_fmt(struct s5p_jpeg_fmt *formats, int n, | 863 | static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n, |
525 | struct v4l2_fmtdesc *f, u32 type) | 864 | struct v4l2_fmtdesc *f, u32 type) |
526 | { | 865 | { |
527 | int i, num = 0; | 866 | int i, num = 0; |
528 | 867 | ||
529 | for (i = 0; i < n; ++i) { | 868 | for (i = 0; i < n; ++i) { |
530 | if (formats[i].types & type) { | 869 | if (sjpeg_formats[i].flags & type) { |
531 | /* index-th format of type type found ? */ | 870 | /* index-th format of type type found ? */ |
532 | if (num == f->index) | 871 | if (num == f->index) |
533 | break; | 872 | break; |
@@ -541,8 +880,8 @@ static int enum_fmt(struct s5p_jpeg_fmt *formats, int n, | |||
541 | if (i >= n) | 880 | if (i >= n) |
542 | return -EINVAL; | 881 | return -EINVAL; |
543 | 882 | ||
544 | strlcpy(f->description, formats[i].name, sizeof(f->description)); | 883 | strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description)); |
545 | f->pixelformat = formats[i].fourcc; | 884 | f->pixelformat = sjpeg_formats[i].fourcc; |
546 | 885 | ||
547 | return 0; | 886 | return 0; |
548 | } | 887 | } |
@@ -553,10 +892,11 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, | |||
553 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | 892 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
554 | 893 | ||
555 | if (ctx->mode == S5P_JPEG_ENCODE) | 894 | if (ctx->mode == S5P_JPEG_ENCODE) |
556 | return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, | 895 | return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, |
557 | MEM2MEM_CAPTURE); | 896 | SJPEG_FMT_FLAG_ENC_CAPTURE); |
558 | 897 | ||
559 | return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE); | 898 | return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, |
899 | SJPEG_FMT_FLAG_DEC_CAPTURE); | ||
560 | } | 900 | } |
561 | 901 | ||
562 | static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, | 902 | static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, |
@@ -565,10 +905,11 @@ static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, | |||
565 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | 905 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
566 | 906 | ||
567 | if (ctx->mode == S5P_JPEG_ENCODE) | 907 | if (ctx->mode == S5P_JPEG_ENCODE) |
568 | return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, | 908 | return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, |
569 | MEM2MEM_OUTPUT); | 909 | SJPEG_FMT_FLAG_ENC_OUTPUT); |
570 | 910 | ||
571 | return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT); | 911 | return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, |
912 | SJPEG_FMT_FLAG_DEC_OUTPUT); | ||
572 | } | 913 | } |
573 | 914 | ||
574 | static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx, | 915 | static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx, |
@@ -589,7 +930,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
589 | struct v4l2_pix_format *pix = &f->fmt.pix; | 930 | struct v4l2_pix_format *pix = &f->fmt.pix; |
590 | struct s5p_jpeg_ctx *ct = fh_to_ctx(priv); | 931 | struct s5p_jpeg_ctx *ct = fh_to_ctx(priv); |
591 | 932 | ||
592 | vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); | 933 | vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type); |
593 | if (!vq) | 934 | if (!vq) |
594 | return -EINVAL; | 935 | return -EINVAL; |
595 | 936 | ||
@@ -615,29 +956,35 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
615 | return 0; | 956 | return 0; |
616 | } | 957 | } |
617 | 958 | ||
618 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, | 959 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx, |
619 | u32 pixelformat) | 960 | u32 pixelformat, unsigned int fmt_type) |
620 | { | 961 | { |
621 | unsigned int k; | 962 | unsigned int k, fmt_flag, ver_flag; |
622 | struct s5p_jpeg_fmt *formats; | ||
623 | int n; | ||
624 | 963 | ||
625 | if (mode == S5P_JPEG_ENCODE) { | 964 | if (ctx->mode == S5P_JPEG_ENCODE) |
626 | formats = formats_enc; | 965 | fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ? |
627 | n = NUM_FORMATS_ENC; | 966 | SJPEG_FMT_FLAG_ENC_OUTPUT : |
628 | } else { | 967 | SJPEG_FMT_FLAG_ENC_CAPTURE; |
629 | formats = formats_dec; | 968 | else |
630 | n = NUM_FORMATS_DEC; | 969 | fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ? |
631 | } | 970 | SJPEG_FMT_FLAG_DEC_OUTPUT : |
971 | SJPEG_FMT_FLAG_DEC_CAPTURE; | ||
972 | |||
973 | if (ctx->jpeg->variant->version == SJPEG_S5P) | ||
974 | ver_flag = SJPEG_FMT_FLAG_S5P; | ||
975 | else | ||
976 | ver_flag = SJPEG_FMT_FLAG_EXYNOS4; | ||
632 | 977 | ||
633 | for (k = 0; k < n; k++) { | 978 | for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) { |
634 | struct s5p_jpeg_fmt *fmt = &formats[k]; | 979 | struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k]; |
635 | if (fmt->fourcc == pixelformat) | 980 | if (fmt->fourcc == pixelformat && |
981 | fmt->flags & fmt_flag && | ||
982 | fmt->flags & ver_flag) { | ||
636 | return fmt; | 983 | return fmt; |
984 | } | ||
637 | } | 985 | } |
638 | 986 | ||
639 | return NULL; | 987 | return NULL; |
640 | |||
641 | } | 988 | } |
642 | 989 | ||
643 | static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, | 990 | static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, |
@@ -673,7 +1020,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, | |||
673 | 1020 | ||
674 | /* V4L2 specification suggests the driver corrects the format struct | 1021 | /* V4L2 specification suggests the driver corrects the format struct |
675 | * if any of the dimensions is unsupported */ | 1022 | * if any of the dimensions is unsupported */ |
676 | if (q_type == MEM2MEM_OUTPUT) | 1023 | if (q_type == FMT_TYPE_OUTPUT) |
677 | jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH, | 1024 | jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH, |
678 | S5P_JPEG_MAX_WIDTH, 0, | 1025 | S5P_JPEG_MAX_WIDTH, 0, |
679 | &pix->height, S5P_JPEG_MIN_HEIGHT, | 1026 | &pix->height, S5P_JPEG_MIN_HEIGHT, |
@@ -695,7 +1042,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, | |||
695 | bpl = pix->width; /* planar */ | 1042 | bpl = pix->width; /* planar */ |
696 | 1043 | ||
697 | if (fmt->colplanes == 1 && /* packed */ | 1044 | if (fmt->colplanes == 1 && /* packed */ |
698 | (bpl << 3) * fmt->depth < pix->width) | 1045 | (bpl << 3) / fmt->depth < pix->width) |
699 | bpl = (pix->width * fmt->depth) >> 3; | 1046 | bpl = (pix->width * fmt->depth) >> 3; |
700 | 1047 | ||
701 | pix->bytesperline = bpl; | 1048 | pix->bytesperline = bpl; |
@@ -709,17 +1056,41 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, | |||
709 | struct v4l2_format *f) | 1056 | struct v4l2_format *f) |
710 | { | 1057 | { |
711 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | 1058 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
1059 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
712 | struct s5p_jpeg_fmt *fmt; | 1060 | struct s5p_jpeg_fmt *fmt; |
1061 | int ret; | ||
713 | 1062 | ||
714 | fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); | 1063 | fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat, |
715 | if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { | 1064 | FMT_TYPE_CAPTURE); |
1065 | if (!fmt) { | ||
716 | v4l2_err(&ctx->jpeg->v4l2_dev, | 1066 | v4l2_err(&ctx->jpeg->v4l2_dev, |
717 | "Fourcc format (0x%08x) invalid.\n", | 1067 | "Fourcc format (0x%08x) invalid.\n", |
718 | f->fmt.pix.pixelformat); | 1068 | f->fmt.pix.pixelformat); |
719 | return -EINVAL; | 1069 | return -EINVAL; |
720 | } | 1070 | } |
721 | 1071 | ||
722 | return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE); | 1072 | /* |
1073 | * The exynos4x12 device requires resulting YUV image | ||
1074 | * subsampling not to be lower than the input jpeg subsampling. | ||
1075 | * If this requirement is not met then downgrade the requested | ||
1076 | * capture format to the one with subsampling equal to the input jpeg. | ||
1077 | */ | ||
1078 | if ((ctx->jpeg->variant->version != SJPEG_S5P) && | ||
1079 | (ctx->mode == S5P_JPEG_DECODE) && | ||
1080 | (fmt->flags & SJPEG_FMT_NON_RGB) && | ||
1081 | (fmt->subsampling < ctx->subsampling)) { | ||
1082 | ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling, | ||
1083 | fmt->fourcc, | ||
1084 | &pix->pixelformat, | ||
1085 | ctx); | ||
1086 | if (ret < 0) | ||
1087 | pix->pixelformat = V4L2_PIX_FMT_GREY; | ||
1088 | |||
1089 | fmt = s5p_jpeg_find_format(ctx, pix->pixelformat, | ||
1090 | FMT_TYPE_CAPTURE); | ||
1091 | } | ||
1092 | |||
1093 | return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE); | ||
723 | } | 1094 | } |
724 | 1095 | ||
725 | static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, | 1096 | static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, |
@@ -728,15 +1099,16 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, | |||
728 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | 1099 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
729 | struct s5p_jpeg_fmt *fmt; | 1100 | struct s5p_jpeg_fmt *fmt; |
730 | 1101 | ||
731 | fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); | 1102 | fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat, |
732 | if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { | 1103 | FMT_TYPE_OUTPUT); |
1104 | if (!fmt) { | ||
733 | v4l2_err(&ctx->jpeg->v4l2_dev, | 1105 | v4l2_err(&ctx->jpeg->v4l2_dev, |
734 | "Fourcc format (0x%08x) invalid.\n", | 1106 | "Fourcc format (0x%08x) invalid.\n", |
735 | f->fmt.pix.pixelformat); | 1107 | f->fmt.pix.pixelformat); |
736 | return -EINVAL; | 1108 | return -EINVAL; |
737 | } | 1109 | } |
738 | 1110 | ||
739 | return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT); | 1111 | return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT); |
740 | } | 1112 | } |
741 | 1113 | ||
742 | static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) | 1114 | static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) |
@@ -744,8 +1116,10 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) | |||
744 | struct vb2_queue *vq; | 1116 | struct vb2_queue *vq; |
745 | struct s5p_jpeg_q_data *q_data = NULL; | 1117 | struct s5p_jpeg_q_data *q_data = NULL; |
746 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1118 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1119 | struct v4l2_ctrl *ctrl_subs; | ||
1120 | unsigned int f_type; | ||
747 | 1121 | ||
748 | vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); | 1122 | vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type); |
749 | if (!vq) | 1123 | if (!vq) |
750 | return -EINVAL; | 1124 | return -EINVAL; |
751 | 1125 | ||
@@ -757,7 +1131,10 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) | |||
757 | return -EBUSY; | 1131 | return -EBUSY; |
758 | } | 1132 | } |
759 | 1133 | ||
760 | q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat); | 1134 | f_type = V4L2_TYPE_IS_OUTPUT(f->type) ? |
1135 | FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE; | ||
1136 | |||
1137 | q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type); | ||
761 | q_data->w = pix->width; | 1138 | q_data->w = pix->width; |
762 | q_data->h = pix->height; | 1139 | q_data->h = pix->height; |
763 | if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) | 1140 | if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) |
@@ -765,6 +1142,13 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) | |||
765 | else | 1142 | else |
766 | q_data->size = pix->sizeimage; | 1143 | q_data->size = pix->sizeimage; |
767 | 1144 | ||
1145 | if (f_type == FMT_TYPE_OUTPUT) { | ||
1146 | ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler, | ||
1147 | V4L2_CID_JPEG_CHROMA_SUBSAMPLING); | ||
1148 | if (ctrl_subs) | ||
1149 | v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling); | ||
1150 | } | ||
1151 | |||
768 | return 0; | 1152 | return 0; |
769 | } | 1153 | } |
770 | 1154 | ||
@@ -792,60 +1176,14 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, | |||
792 | return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); | 1176 | return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); |
793 | } | 1177 | } |
794 | 1178 | ||
795 | static int s5p_jpeg_reqbufs(struct file *file, void *priv, | ||
796 | struct v4l2_requestbuffers *reqbufs) | ||
797 | { | ||
798 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
799 | |||
800 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | ||
801 | } | ||
802 | |||
803 | static int s5p_jpeg_querybuf(struct file *file, void *priv, | ||
804 | struct v4l2_buffer *buf) | ||
805 | { | ||
806 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
807 | |||
808 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); | ||
809 | } | ||
810 | |||
811 | static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
812 | { | ||
813 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
814 | |||
815 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | ||
816 | } | ||
817 | |||
818 | static int s5p_jpeg_dqbuf(struct file *file, void *priv, | ||
819 | struct v4l2_buffer *buf) | ||
820 | { | ||
821 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
822 | |||
823 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | ||
824 | } | ||
825 | |||
826 | static int s5p_jpeg_streamon(struct file *file, void *priv, | ||
827 | enum v4l2_buf_type type) | ||
828 | { | ||
829 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
830 | |||
831 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); | ||
832 | } | ||
833 | |||
834 | static int s5p_jpeg_streamoff(struct file *file, void *priv, | ||
835 | enum v4l2_buf_type type) | ||
836 | { | ||
837 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | ||
838 | |||
839 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | ||
840 | } | ||
841 | |||
842 | static int s5p_jpeg_g_selection(struct file *file, void *priv, | 1179 | static int s5p_jpeg_g_selection(struct file *file, void *priv, |
843 | struct v4l2_selection *s) | 1180 | struct v4l2_selection *s) |
844 | { | 1181 | { |
845 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | 1182 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
846 | 1183 | ||
847 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 1184 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
848 | s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1185 | s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1186 | ctx->jpeg->variant->version != SJPEG_S5P) | ||
849 | return -EINVAL; | 1187 | return -EINVAL; |
850 | 1188 | ||
851 | /* For JPEG blob active == default == bounds */ | 1189 | /* For JPEG blob active == default == bounds */ |
@@ -884,12 +1222,7 @@ static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |||
884 | switch (ctrl->id) { | 1222 | switch (ctrl->id) { |
885 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: | 1223 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: |
886 | spin_lock_irqsave(&jpeg->slock, flags); | 1224 | spin_lock_irqsave(&jpeg->slock, flags); |
887 | 1225 | ctrl->val = s5p_jpeg_to_user_subsampling(ctx); | |
888 | WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY); | ||
889 | if (ctx->subsampling > 2) | ||
890 | ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; | ||
891 | else | ||
892 | ctrl->val = ctx->subsampling; | ||
893 | spin_unlock_irqrestore(&jpeg->slock, flags); | 1226 | spin_unlock_irqrestore(&jpeg->slock, flags); |
894 | break; | 1227 | break; |
895 | } | 1228 | } |
@@ -897,6 +1230,40 @@ static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |||
897 | return 0; | 1230 | return 0; |
898 | } | 1231 | } |
899 | 1232 | ||
1233 | static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl) | ||
1234 | { | ||
1235 | struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); | ||
1236 | unsigned long flags; | ||
1237 | int ret = 0; | ||
1238 | |||
1239 | spin_lock_irqsave(&ctx->jpeg->slock, flags); | ||
1240 | |||
1241 | if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING) { | ||
1242 | if (ctx->jpeg->variant->version == SJPEG_S5P) | ||
1243 | goto error_free; | ||
1244 | /* | ||
1245 | * The exynos4x12 device requires input raw image fourcc | ||
1246 | * to be V4L2_PIX_FMT_GREY if gray jpeg format | ||
1247 | * is to be set. | ||
1248 | */ | ||
1249 | if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY && | ||
1250 | ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) { | ||
1251 | ret = -EINVAL; | ||
1252 | goto error_free; | ||
1253 | } | ||
1254 | /* | ||
1255 | * The exynos4x12 device requires resulting jpeg subsampling | ||
1256 | * not to be lower than the input raw image subsampling. | ||
1257 | */ | ||
1258 | if (ctx->out_q.fmt->subsampling > ctrl->val) | ||
1259 | ctrl->val = ctx->out_q.fmt->subsampling; | ||
1260 | } | ||
1261 | |||
1262 | error_free: | ||
1263 | spin_unlock_irqrestore(&ctx->jpeg->slock, flags); | ||
1264 | return ret; | ||
1265 | } | ||
1266 | |||
900 | static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) | 1267 | static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) |
901 | { | 1268 | { |
902 | struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); | 1269 | struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); |
@@ -906,7 +1273,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) | |||
906 | 1273 | ||
907 | switch (ctrl->id) { | 1274 | switch (ctrl->id) { |
908 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: | 1275 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: |
909 | ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val; | 1276 | ctx->compr_quality = ctrl->val; |
910 | break; | 1277 | break; |
911 | case V4L2_CID_JPEG_RESTART_INTERVAL: | 1278 | case V4L2_CID_JPEG_RESTART_INTERVAL: |
912 | ctx->restart_interval = ctrl->val; | 1279 | ctx->restart_interval = ctrl->val; |
@@ -922,6 +1289,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) | |||
922 | 1289 | ||
923 | static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = { | 1290 | static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = { |
924 | .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl, | 1291 | .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl, |
1292 | .try_ctrl = s5p_jpeg_try_ctrl, | ||
925 | .s_ctrl = s5p_jpeg_s_ctrl, | 1293 | .s_ctrl = s5p_jpeg_s_ctrl, |
926 | }; | 1294 | }; |
927 | 1295 | ||
@@ -929,18 +1297,20 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) | |||
929 | { | 1297 | { |
930 | unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */ | 1298 | unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */ |
931 | struct v4l2_ctrl *ctrl; | 1299 | struct v4l2_ctrl *ctrl; |
1300 | int ret; | ||
932 | 1301 | ||
933 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); | 1302 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); |
934 | 1303 | ||
935 | if (ctx->mode == S5P_JPEG_ENCODE) { | 1304 | if (ctx->mode == S5P_JPEG_ENCODE) { |
936 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, | 1305 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, |
937 | V4L2_CID_JPEG_COMPRESSION_QUALITY, | 1306 | V4L2_CID_JPEG_COMPRESSION_QUALITY, |
938 | 0, 3, 1, 3); | 1307 | 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST); |
939 | 1308 | ||
940 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, | 1309 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, |
941 | V4L2_CID_JPEG_RESTART_INTERVAL, | 1310 | V4L2_CID_JPEG_RESTART_INTERVAL, |
942 | 0, 3, 0xffff, 0); | 1311 | 0, 3, 0xffff, 0); |
943 | mask = ~0x06; /* 422, 420 */ | 1312 | if (ctx->jpeg->variant->version == SJPEG_S5P) |
1313 | mask = ~0x06; /* 422, 420 */ | ||
944 | } | 1314 | } |
945 | 1315 | ||
946 | ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, | 1316 | ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, |
@@ -948,13 +1318,24 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) | |||
948 | V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask, | 1318 | V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask, |
949 | V4L2_JPEG_CHROMA_SUBSAMPLING_422); | 1319 | V4L2_JPEG_CHROMA_SUBSAMPLING_422); |
950 | 1320 | ||
951 | if (ctx->ctrl_handler.error) | 1321 | if (ctx->ctrl_handler.error) { |
952 | return ctx->ctrl_handler.error; | 1322 | ret = ctx->ctrl_handler.error; |
1323 | goto error_free; | ||
1324 | } | ||
953 | 1325 | ||
954 | if (ctx->mode == S5P_JPEG_DECODE) | 1326 | if (ctx->mode == S5P_JPEG_DECODE) |
955 | ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | | 1327 | ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | |
956 | V4L2_CTRL_FLAG_READ_ONLY; | 1328 | V4L2_CTRL_FLAG_READ_ONLY; |
957 | return 0; | 1329 | |
1330 | ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | ||
1331 | if (ret < 0) | ||
1332 | goto error_free; | ||
1333 | |||
1334 | return ret; | ||
1335 | |||
1336 | error_free: | ||
1337 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
1338 | return ret; | ||
958 | } | 1339 | } |
959 | 1340 | ||
960 | static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { | 1341 | static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { |
@@ -972,14 +1353,13 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { | |||
972 | .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap, | 1353 | .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap, |
973 | .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out, | 1354 | .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out, |
974 | 1355 | ||
975 | .vidioc_reqbufs = s5p_jpeg_reqbufs, | 1356 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
976 | .vidioc_querybuf = s5p_jpeg_querybuf, | 1357 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
1358 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, | ||
1359 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | ||
977 | 1360 | ||
978 | .vidioc_qbuf = s5p_jpeg_qbuf, | 1361 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
979 | .vidioc_dqbuf = s5p_jpeg_dqbuf, | 1362 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
980 | |||
981 | .vidioc_streamon = s5p_jpeg_streamon, | ||
982 | .vidioc_streamoff = s5p_jpeg_streamoff, | ||
983 | 1363 | ||
984 | .vidioc_g_selection = s5p_jpeg_g_selection, | 1364 | .vidioc_g_selection = s5p_jpeg_g_selection, |
985 | }; | 1365 | }; |
@@ -995,74 +1375,181 @@ static void s5p_jpeg_device_run(void *priv) | |||
995 | struct s5p_jpeg_ctx *ctx = priv; | 1375 | struct s5p_jpeg_ctx *ctx = priv; |
996 | struct s5p_jpeg *jpeg = ctx->jpeg; | 1376 | struct s5p_jpeg *jpeg = ctx->jpeg; |
997 | struct vb2_buffer *src_buf, *dst_buf; | 1377 | struct vb2_buffer *src_buf, *dst_buf; |
998 | unsigned long src_addr, dst_addr; | 1378 | unsigned long src_addr, dst_addr, flags; |
1379 | |||
1380 | spin_lock_irqsave(&ctx->jpeg->slock, flags); | ||
999 | 1381 | ||
1000 | src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); | 1382 | src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
1001 | dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); | 1383 | dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
1002 | src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); | 1384 | src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); |
1003 | dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); | 1385 | dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); |
1004 | 1386 | ||
1005 | jpeg_reset(jpeg->regs); | 1387 | s5p_jpeg_reset(jpeg->regs); |
1006 | jpeg_poweron(jpeg->regs); | 1388 | s5p_jpeg_poweron(jpeg->regs); |
1007 | jpeg_proc_mode(jpeg->regs, ctx->mode); | 1389 | s5p_jpeg_proc_mode(jpeg->regs, ctx->mode); |
1008 | if (ctx->mode == S5P_JPEG_ENCODE) { | 1390 | if (ctx->mode == S5P_JPEG_ENCODE) { |
1009 | if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565) | 1391 | if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565) |
1010 | jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); | 1392 | s5p_jpeg_input_raw_mode(jpeg->regs, |
1393 | S5P_JPEG_RAW_IN_565); | ||
1011 | else | 1394 | else |
1012 | jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); | 1395 | s5p_jpeg_input_raw_mode(jpeg->regs, |
1013 | jpeg_subsampling_mode(jpeg->regs, ctx->subsampling); | 1396 | S5P_JPEG_RAW_IN_422); |
1014 | jpeg_dri(jpeg->regs, ctx->restart_interval); | 1397 | s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling); |
1015 | jpeg_x(jpeg->regs, ctx->out_q.w); | 1398 | s5p_jpeg_dri(jpeg->regs, ctx->restart_interval); |
1016 | jpeg_y(jpeg->regs, ctx->out_q.h); | 1399 | s5p_jpeg_x(jpeg->regs, ctx->out_q.w); |
1017 | jpeg_imgadr(jpeg->regs, src_addr); | 1400 | s5p_jpeg_y(jpeg->regs, ctx->out_q.h); |
1018 | jpeg_jpgadr(jpeg->regs, dst_addr); | 1401 | s5p_jpeg_imgadr(jpeg->regs, src_addr); |
1402 | s5p_jpeg_jpgadr(jpeg->regs, dst_addr); | ||
1019 | 1403 | ||
1020 | /* ultimately comes from sizeimage from userspace */ | 1404 | /* ultimately comes from sizeimage from userspace */ |
1021 | jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size); | 1405 | s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size); |
1022 | 1406 | ||
1023 | /* JPEG RGB to YCbCr conversion matrix */ | 1407 | /* JPEG RGB to YCbCr conversion matrix */ |
1024 | jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11); | 1408 | s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11); |
1025 | jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12); | 1409 | s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12); |
1026 | jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13); | 1410 | s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13); |
1027 | jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21); | 1411 | s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21); |
1028 | jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22); | 1412 | s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22); |
1029 | jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23); | 1413 | s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23); |
1030 | jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31); | 1414 | s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31); |
1031 | jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32); | 1415 | s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32); |
1032 | jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33); | 1416 | s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33); |
1033 | 1417 | ||
1034 | /* | 1418 | /* |
1035 | * JPEG IP allows storing 4 quantization tables | 1419 | * JPEG IP allows storing 4 quantization tables |
1036 | * We fill table 0 for luma and table 1 for chroma | 1420 | * We fill table 0 for luma and table 1 for chroma |
1037 | */ | 1421 | */ |
1038 | jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality); | 1422 | s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality); |
1039 | jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality); | 1423 | s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality); |
1040 | /* use table 0 for Y */ | 1424 | /* use table 0 for Y */ |
1041 | jpeg_qtbl(jpeg->regs, 1, 0); | 1425 | s5p_jpeg_qtbl(jpeg->regs, 1, 0); |
1042 | /* use table 1 for Cb and Cr*/ | 1426 | /* use table 1 for Cb and Cr*/ |
1043 | jpeg_qtbl(jpeg->regs, 2, 1); | 1427 | s5p_jpeg_qtbl(jpeg->regs, 2, 1); |
1044 | jpeg_qtbl(jpeg->regs, 3, 1); | 1428 | s5p_jpeg_qtbl(jpeg->regs, 3, 1); |
1045 | 1429 | ||
1046 | /* Y, Cb, Cr use Huffman table 0 */ | 1430 | /* Y, Cb, Cr use Huffman table 0 */ |
1047 | jpeg_htbl_ac(jpeg->regs, 1); | 1431 | s5p_jpeg_htbl_ac(jpeg->regs, 1); |
1048 | jpeg_htbl_dc(jpeg->regs, 1); | 1432 | s5p_jpeg_htbl_dc(jpeg->regs, 1); |
1049 | jpeg_htbl_ac(jpeg->regs, 2); | 1433 | s5p_jpeg_htbl_ac(jpeg->regs, 2); |
1050 | jpeg_htbl_dc(jpeg->regs, 2); | 1434 | s5p_jpeg_htbl_dc(jpeg->regs, 2); |
1051 | jpeg_htbl_ac(jpeg->regs, 3); | 1435 | s5p_jpeg_htbl_ac(jpeg->regs, 3); |
1052 | jpeg_htbl_dc(jpeg->regs, 3); | 1436 | s5p_jpeg_htbl_dc(jpeg->regs, 3); |
1053 | } else { /* S5P_JPEG_DECODE */ | 1437 | } else { /* S5P_JPEG_DECODE */ |
1054 | jpeg_rst_int_enable(jpeg->regs, true); | 1438 | s5p_jpeg_rst_int_enable(jpeg->regs, true); |
1055 | jpeg_data_num_int_enable(jpeg->regs, true); | 1439 | s5p_jpeg_data_num_int_enable(jpeg->regs, true); |
1056 | jpeg_final_mcu_num_int_enable(jpeg->regs, true); | 1440 | s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true); |
1057 | if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) | 1441 | if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) |
1058 | jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); | 1442 | s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); |
1059 | else | 1443 | else |
1060 | jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420); | 1444 | s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420); |
1061 | jpeg_jpgadr(jpeg->regs, src_addr); | 1445 | s5p_jpeg_jpgadr(jpeg->regs, src_addr); |
1062 | jpeg_imgadr(jpeg->regs, dst_addr); | 1446 | s5p_jpeg_imgadr(jpeg->regs, dst_addr); |
1063 | } | 1447 | } |
1064 | 1448 | ||
1065 | jpeg_start(jpeg->regs); | 1449 | s5p_jpeg_start(jpeg->regs); |
1450 | |||
1451 | spin_unlock_irqrestore(&ctx->jpeg->slock, flags); | ||
1452 | } | ||
1453 | |||
1454 | static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) | ||
1455 | { | ||
1456 | struct s5p_jpeg *jpeg = ctx->jpeg; | ||
1457 | struct s5p_jpeg_fmt *fmt; | ||
1458 | struct vb2_buffer *vb; | ||
1459 | struct s5p_jpeg_addr jpeg_addr; | ||
1460 | u32 pix_size, padding_bytes = 0; | ||
1461 | |||
1462 | pix_size = ctx->cap_q.w * ctx->cap_q.h; | ||
1463 | |||
1464 | if (ctx->mode == S5P_JPEG_ENCODE) { | ||
1465 | vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | ||
1466 | fmt = ctx->out_q.fmt; | ||
1467 | if (ctx->out_q.w % 2 && fmt->h_align > 0) | ||
1468 | padding_bytes = ctx->out_q.h; | ||
1469 | } else { | ||
1470 | fmt = ctx->cap_q.fmt; | ||
1471 | vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | ||
1472 | } | ||
1473 | |||
1474 | jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
1475 | |||
1476 | if (fmt->colplanes == 2) { | ||
1477 | jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes; | ||
1478 | } else if (fmt->colplanes == 3) { | ||
1479 | jpeg_addr.cb = jpeg_addr.y + pix_size; | ||
1480 | if (fmt->fourcc == V4L2_PIX_FMT_YUV420) | ||
1481 | jpeg_addr.cr = jpeg_addr.cb + pix_size / 4; | ||
1482 | else | ||
1483 | jpeg_addr.cr = jpeg_addr.cb + pix_size / 2; | ||
1484 | } | ||
1485 | |||
1486 | exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr); | ||
1487 | } | ||
1488 | |||
1489 | static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx) | ||
1490 | { | ||
1491 | struct s5p_jpeg *jpeg = ctx->jpeg; | ||
1492 | struct vb2_buffer *vb; | ||
1493 | unsigned int jpeg_addr = 0; | ||
1494 | |||
1495 | if (ctx->mode == S5P_JPEG_ENCODE) | ||
1496 | vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | ||
1497 | else | ||
1498 | vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | ||
1499 | |||
1500 | jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
1501 | exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr); | ||
1502 | } | ||
1503 | |||
1504 | static void exynos4_jpeg_device_run(void *priv) | ||
1505 | { | ||
1506 | struct s5p_jpeg_ctx *ctx = priv; | ||
1507 | struct s5p_jpeg *jpeg = ctx->jpeg; | ||
1508 | unsigned int bitstream_size; | ||
1509 | unsigned long flags; | ||
1510 | |||
1511 | spin_lock_irqsave(&ctx->jpeg->slock, flags); | ||
1512 | |||
1513 | if (ctx->mode == S5P_JPEG_ENCODE) { | ||
1514 | exynos4_jpeg_sw_reset(jpeg->regs); | ||
1515 | exynos4_jpeg_set_interrupt(jpeg->regs); | ||
1516 | exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1); | ||
1517 | |||
1518 | exynos4_jpeg_set_huff_tbl(jpeg->regs); | ||
1519 | |||
1520 | /* | ||
1521 | * JPEG IP allows storing 4 quantization tables | ||
1522 | * We fill table 0 for luma and table 1 for chroma | ||
1523 | */ | ||
1524 | exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality); | ||
1525 | exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality); | ||
1526 | |||
1527 | exynos4_jpeg_set_encode_tbl_select(jpeg->regs, | ||
1528 | ctx->compr_quality); | ||
1529 | exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w, | ||
1530 | ctx->cap_q.h); | ||
1531 | |||
1532 | exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling); | ||
1533 | exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc); | ||
1534 | exynos4_jpeg_set_img_addr(ctx); | ||
1535 | exynos4_jpeg_set_jpeg_addr(ctx); | ||
1536 | exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs, | ||
1537 | ctx->out_q.fmt->fourcc); | ||
1538 | } else { | ||
1539 | exynos4_jpeg_sw_reset(jpeg->regs); | ||
1540 | exynos4_jpeg_set_interrupt(jpeg->regs); | ||
1541 | exynos4_jpeg_set_img_addr(ctx); | ||
1542 | exynos4_jpeg_set_jpeg_addr(ctx); | ||
1543 | exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc); | ||
1544 | |||
1545 | bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32); | ||
1546 | |||
1547 | exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size); | ||
1548 | } | ||
1549 | |||
1550 | exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode); | ||
1551 | |||
1552 | spin_unlock_irqrestore(&ctx->jpeg->slock, flags); | ||
1066 | } | 1553 | } |
1067 | 1554 | ||
1068 | static int s5p_jpeg_job_ready(void *priv) | 1555 | static int s5p_jpeg_job_ready(void *priv) |
@@ -1082,6 +1569,12 @@ static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = { | |||
1082 | .device_run = s5p_jpeg_device_run, | 1569 | .device_run = s5p_jpeg_device_run, |
1083 | .job_ready = s5p_jpeg_job_ready, | 1570 | .job_ready = s5p_jpeg_job_ready, |
1084 | .job_abort = s5p_jpeg_job_abort, | 1571 | .job_abort = s5p_jpeg_job_abort, |
1572 | } | ||
1573 | ; | ||
1574 | static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = { | ||
1575 | .device_run = exynos4_jpeg_device_run, | ||
1576 | .job_ready = s5p_jpeg_job_ready, | ||
1577 | .job_abort = s5p_jpeg_job_abort, | ||
1085 | }; | 1578 | }; |
1086 | 1579 | ||
1087 | /* | 1580 | /* |
@@ -1149,7 +1642,7 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) | |||
1149 | ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp, | 1642 | ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp, |
1150 | (unsigned long)vb2_plane_vaddr(vb, 0), | 1643 | (unsigned long)vb2_plane_vaddr(vb, 0), |
1151 | min((unsigned long)ctx->out_q.size, | 1644 | min((unsigned long)ctx->out_q.size, |
1152 | vb2_get_plane_payload(vb, 0))); | 1645 | vb2_get_plane_payload(vb, 0)), ctx); |
1153 | if (!ctx->hdr_parsed) { | 1646 | if (!ctx->hdr_parsed) { |
1154 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | 1647 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); |
1155 | return; | 1648 | return; |
@@ -1162,30 +1655,9 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) | |||
1162 | q_data = &ctx->cap_q; | 1655 | q_data = &ctx->cap_q; |
1163 | q_data->w = tmp.w; | 1656 | q_data->w = tmp.w; |
1164 | q_data->h = tmp.h; | 1657 | q_data->h = tmp.h; |
1165 | |||
1166 | jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH, | ||
1167 | S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align, | ||
1168 | &q_data->h, S5P_JPEG_MIN_HEIGHT, | ||
1169 | S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align | ||
1170 | ); | ||
1171 | q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3; | ||
1172 | } | 1658 | } |
1173 | if (ctx->m2m_ctx) | ||
1174 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); | ||
1175 | } | ||
1176 | |||
1177 | static void s5p_jpeg_wait_prepare(struct vb2_queue *vq) | ||
1178 | { | ||
1179 | struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); | ||
1180 | 1659 | ||
1181 | mutex_unlock(&ctx->jpeg->lock); | 1660 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); |
1182 | } | ||
1183 | |||
1184 | static void s5p_jpeg_wait_finish(struct vb2_queue *vq) | ||
1185 | { | ||
1186 | struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); | ||
1187 | |||
1188 | mutex_lock(&ctx->jpeg->lock); | ||
1189 | } | 1661 | } |
1190 | 1662 | ||
1191 | static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) | 1663 | static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) |
@@ -1211,8 +1683,8 @@ static struct vb2_ops s5p_jpeg_qops = { | |||
1211 | .queue_setup = s5p_jpeg_queue_setup, | 1683 | .queue_setup = s5p_jpeg_queue_setup, |
1212 | .buf_prepare = s5p_jpeg_buf_prepare, | 1684 | .buf_prepare = s5p_jpeg_buf_prepare, |
1213 | .buf_queue = s5p_jpeg_buf_queue, | 1685 | .buf_queue = s5p_jpeg_buf_queue, |
1214 | .wait_prepare = s5p_jpeg_wait_prepare, | 1686 | .wait_prepare = vb2_ops_wait_prepare, |
1215 | .wait_finish = s5p_jpeg_wait_finish, | 1687 | .wait_finish = vb2_ops_wait_finish, |
1216 | .start_streaming = s5p_jpeg_start_streaming, | 1688 | .start_streaming = s5p_jpeg_start_streaming, |
1217 | .stop_streaming = s5p_jpeg_stop_streaming, | 1689 | .stop_streaming = s5p_jpeg_stop_streaming, |
1218 | }; | 1690 | }; |
@@ -1230,6 +1702,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, | |||
1230 | src_vq->ops = &s5p_jpeg_qops; | 1702 | src_vq->ops = &s5p_jpeg_qops; |
1231 | src_vq->mem_ops = &vb2_dma_contig_memops; | 1703 | src_vq->mem_ops = &vb2_dma_contig_memops; |
1232 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 1704 | src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
1705 | src_vq->lock = &ctx->jpeg->lock; | ||
1233 | 1706 | ||
1234 | ret = vb2_queue_init(src_vq); | 1707 | ret = vb2_queue_init(src_vq); |
1235 | if (ret) | 1708 | if (ret) |
@@ -1242,6 +1715,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, | |||
1242 | dst_vq->ops = &s5p_jpeg_qops; | 1715 | dst_vq->ops = &s5p_jpeg_qops; |
1243 | dst_vq->mem_ops = &vb2_dma_contig_memops; | 1716 | dst_vq->mem_ops = &vb2_dma_contig_memops; |
1244 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 1717 | dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
1718 | dst_vq->lock = &ctx->jpeg->lock; | ||
1245 | 1719 | ||
1246 | return vb2_queue_init(dst_vq); | 1720 | return vb2_queue_init(dst_vq); |
1247 | } | 1721 | } |
@@ -1267,26 +1741,27 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) | |||
1267 | 1741 | ||
1268 | curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); | 1742 | curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); |
1269 | 1743 | ||
1270 | src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); | 1744 | src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); |
1271 | dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); | 1745 | dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); |
1272 | 1746 | ||
1273 | if (curr_ctx->mode == S5P_JPEG_ENCODE) | 1747 | if (curr_ctx->mode == S5P_JPEG_ENCODE) |
1274 | enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs); | 1748 | enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs); |
1275 | timer_elapsed = jpeg_timer_stat(jpeg->regs); | 1749 | timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs); |
1276 | op_completed = jpeg_result_stat_ok(jpeg->regs); | 1750 | op_completed = s5p_jpeg_result_stat_ok(jpeg->regs); |
1277 | if (curr_ctx->mode == S5P_JPEG_DECODE) | 1751 | if (curr_ctx->mode == S5P_JPEG_DECODE) |
1278 | op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs); | 1752 | op_completed = op_completed && |
1753 | s5p_jpeg_stream_stat_ok(jpeg->regs); | ||
1279 | 1754 | ||
1280 | if (enc_jpeg_too_large) { | 1755 | if (enc_jpeg_too_large) { |
1281 | state = VB2_BUF_STATE_ERROR; | 1756 | state = VB2_BUF_STATE_ERROR; |
1282 | jpeg_clear_enc_stream_stat(jpeg->regs); | 1757 | s5p_jpeg_clear_enc_stream_stat(jpeg->regs); |
1283 | } else if (timer_elapsed) { | 1758 | } else if (timer_elapsed) { |
1284 | state = VB2_BUF_STATE_ERROR; | 1759 | state = VB2_BUF_STATE_ERROR; |
1285 | jpeg_clear_timer_stat(jpeg->regs); | 1760 | s5p_jpeg_clear_timer_stat(jpeg->regs); |
1286 | } else if (!op_completed) { | 1761 | } else if (!op_completed) { |
1287 | state = VB2_BUF_STATE_ERROR; | 1762 | state = VB2_BUF_STATE_ERROR; |
1288 | } else { | 1763 | } else { |
1289 | payload_size = jpeg_compressed_size(jpeg->regs); | 1764 | payload_size = s5p_jpeg_compressed_size(jpeg->regs); |
1290 | } | 1765 | } |
1291 | 1766 | ||
1292 | dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; | 1767 | dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; |
@@ -1296,16 +1771,79 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) | |||
1296 | if (curr_ctx->mode == S5P_JPEG_ENCODE) | 1771 | if (curr_ctx->mode == S5P_JPEG_ENCODE) |
1297 | vb2_set_plane_payload(dst_buf, 0, payload_size); | 1772 | vb2_set_plane_payload(dst_buf, 0, payload_size); |
1298 | v4l2_m2m_buf_done(dst_buf, state); | 1773 | v4l2_m2m_buf_done(dst_buf, state); |
1299 | v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); | 1774 | v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx); |
1300 | 1775 | ||
1301 | curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs); | 1776 | curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs); |
1302 | spin_unlock(&jpeg->slock); | 1777 | spin_unlock(&jpeg->slock); |
1303 | 1778 | ||
1304 | jpeg_clear_int(jpeg->regs); | 1779 | s5p_jpeg_clear_int(jpeg->regs); |
1305 | 1780 | ||
1306 | return IRQ_HANDLED; | 1781 | return IRQ_HANDLED; |
1307 | } | 1782 | } |
1308 | 1783 | ||
1784 | static irqreturn_t exynos4_jpeg_irq(int irq, void *priv) | ||
1785 | { | ||
1786 | unsigned int int_status; | ||
1787 | struct vb2_buffer *src_vb, *dst_vb; | ||
1788 | struct s5p_jpeg *jpeg = priv; | ||
1789 | struct s5p_jpeg_ctx *curr_ctx; | ||
1790 | unsigned long payload_size = 0; | ||
1791 | |||
1792 | spin_lock(&jpeg->slock); | ||
1793 | |||
1794 | curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); | ||
1795 | |||
1796 | src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); | ||
1797 | dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); | ||
1798 | |||
1799 | int_status = exynos4_jpeg_get_int_status(jpeg->regs); | ||
1800 | |||
1801 | if (int_status) { | ||
1802 | switch (int_status & 0x1f) { | ||
1803 | case 0x1: | ||
1804 | jpeg->irq_ret = ERR_PROT; | ||
1805 | break; | ||
1806 | case 0x2: | ||
1807 | jpeg->irq_ret = OK_ENC_OR_DEC; | ||
1808 | break; | ||
1809 | case 0x4: | ||
1810 | jpeg->irq_ret = ERR_DEC_INVALID_FORMAT; | ||
1811 | break; | ||
1812 | case 0x8: | ||
1813 | jpeg->irq_ret = ERR_MULTI_SCAN; | ||
1814 | break; | ||
1815 | case 0x10: | ||
1816 | jpeg->irq_ret = ERR_FRAME; | ||
1817 | break; | ||
1818 | default: | ||
1819 | jpeg->irq_ret = ERR_UNKNOWN; | ||
1820 | break; | ||
1821 | } | ||
1822 | } else { | ||
1823 | jpeg->irq_ret = ERR_UNKNOWN; | ||
1824 | } | ||
1825 | |||
1826 | if (jpeg->irq_ret == OK_ENC_OR_DEC) { | ||
1827 | if (curr_ctx->mode == S5P_JPEG_ENCODE) { | ||
1828 | payload_size = exynos4_jpeg_get_stream_size(jpeg->regs); | ||
1829 | vb2_set_plane_payload(dst_vb, 0, payload_size); | ||
1830 | } | ||
1831 | v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); | ||
1832 | v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); | ||
1833 | } else { | ||
1834 | v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR); | ||
1835 | v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR); | ||
1836 | } | ||
1837 | |||
1838 | v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx); | ||
1839 | curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs); | ||
1840 | |||
1841 | spin_unlock(&jpeg->slock); | ||
1842 | return IRQ_HANDLED; | ||
1843 | } | ||
1844 | |||
1845 | static void *jpeg_get_drv_data(struct platform_device *pdev); | ||
1846 | |||
1309 | /* | 1847 | /* |
1310 | * ============================================================================ | 1848 | * ============================================================================ |
1311 | * Driver basic infrastructure | 1849 | * Driver basic infrastructure |
@@ -1316,13 +1854,19 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
1316 | { | 1854 | { |
1317 | struct s5p_jpeg *jpeg; | 1855 | struct s5p_jpeg *jpeg; |
1318 | struct resource *res; | 1856 | struct resource *res; |
1857 | struct v4l2_m2m_ops *samsung_jpeg_m2m_ops; | ||
1319 | int ret; | 1858 | int ret; |
1320 | 1859 | ||
1860 | if (!pdev->dev.of_node) | ||
1861 | return -ENODEV; | ||
1862 | |||
1321 | /* JPEG IP abstraction struct */ | 1863 | /* JPEG IP abstraction struct */ |
1322 | jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL); | 1864 | jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL); |
1323 | if (!jpeg) | 1865 | if (!jpeg) |
1324 | return -ENOMEM; | 1866 | return -ENOMEM; |
1325 | 1867 | ||
1868 | jpeg->variant = jpeg_get_drv_data(pdev); | ||
1869 | |||
1326 | mutex_init(&jpeg->lock); | 1870 | mutex_init(&jpeg->lock); |
1327 | spin_lock_init(&jpeg->slock); | 1871 | spin_lock_init(&jpeg->slock); |
1328 | jpeg->dev = &pdev->dev; | 1872 | jpeg->dev = &pdev->dev; |
@@ -1341,8 +1885,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
1341 | return ret; | 1885 | return ret; |
1342 | } | 1886 | } |
1343 | 1887 | ||
1344 | ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0, | 1888 | ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq, |
1345 | dev_name(&pdev->dev), jpeg); | 1889 | 0, dev_name(&pdev->dev), jpeg); |
1346 | if (ret) { | 1890 | if (ret) { |
1347 | dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq); | 1891 | dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq); |
1348 | return ret; | 1892 | return ret; |
@@ -1356,7 +1900,6 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
1356 | return ret; | 1900 | return ret; |
1357 | } | 1901 | } |
1358 | dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); | 1902 | dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); |
1359 | clk_prepare_enable(jpeg->clk); | ||
1360 | 1903 | ||
1361 | /* v4l2 device */ | 1904 | /* v4l2 device */ |
1362 | ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); | 1905 | ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); |
@@ -1365,8 +1908,13 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
1365 | goto clk_get_rollback; | 1908 | goto clk_get_rollback; |
1366 | } | 1909 | } |
1367 | 1910 | ||
1911 | if (jpeg->variant->version == SJPEG_S5P) | ||
1912 | samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops; | ||
1913 | else | ||
1914 | samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops; | ||
1915 | |||
1368 | /* mem2mem device */ | 1916 | /* mem2mem device */ |
1369 | jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops); | 1917 | jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops); |
1370 | if (IS_ERR(jpeg->m2m_dev)) { | 1918 | if (IS_ERR(jpeg->m2m_dev)) { |
1371 | v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n"); | 1919 | v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n"); |
1372 | ret = PTR_ERR(jpeg->m2m_dev); | 1920 | ret = PTR_ERR(jpeg->m2m_dev); |
@@ -1387,8 +1935,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
1387 | ret = -ENOMEM; | 1935 | ret = -ENOMEM; |
1388 | goto vb2_allocator_rollback; | 1936 | goto vb2_allocator_rollback; |
1389 | } | 1937 | } |
1390 | strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME, | 1938 | snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name), |
1391 | sizeof(jpeg->vfd_encoder->name)); | 1939 | "%s-enc", S5P_JPEG_M2M_NAME); |
1392 | jpeg->vfd_encoder->fops = &s5p_jpeg_fops; | 1940 | jpeg->vfd_encoder->fops = &s5p_jpeg_fops; |
1393 | jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops; | 1941 | jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops; |
1394 | jpeg->vfd_encoder->minor = -1; | 1942 | jpeg->vfd_encoder->minor = -1; |
@@ -1415,8 +1963,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
1415 | ret = -ENOMEM; | 1963 | ret = -ENOMEM; |
1416 | goto enc_vdev_register_rollback; | 1964 | goto enc_vdev_register_rollback; |
1417 | } | 1965 | } |
1418 | strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME, | 1966 | snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name), |
1419 | sizeof(jpeg->vfd_decoder->name)); | 1967 | "%s-dec", S5P_JPEG_M2M_NAME); |
1420 | jpeg->vfd_decoder->fops = &s5p_jpeg_fops; | 1968 | jpeg->vfd_decoder->fops = &s5p_jpeg_fops; |
1421 | jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops; | 1969 | jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops; |
1422 | jpeg->vfd_decoder->minor = -1; | 1970 | jpeg->vfd_decoder->minor = -1; |
@@ -1464,7 +2012,6 @@ device_register_rollback: | |||
1464 | v4l2_device_unregister(&jpeg->v4l2_dev); | 2012 | v4l2_device_unregister(&jpeg->v4l2_dev); |
1465 | 2013 | ||
1466 | clk_get_rollback: | 2014 | clk_get_rollback: |
1467 | clk_disable_unprepare(jpeg->clk); | ||
1468 | clk_put(jpeg->clk); | 2015 | clk_put(jpeg->clk); |
1469 | 2016 | ||
1470 | return ret; | 2017 | return ret; |
@@ -1484,7 +2031,9 @@ static int s5p_jpeg_remove(struct platform_device *pdev) | |||
1484 | v4l2_m2m_release(jpeg->m2m_dev); | 2031 | v4l2_m2m_release(jpeg->m2m_dev); |
1485 | v4l2_device_unregister(&jpeg->v4l2_dev); | 2032 | v4l2_device_unregister(&jpeg->v4l2_dev); |
1486 | 2033 | ||
1487 | clk_disable_unprepare(jpeg->clk); | 2034 | if (!pm_runtime_status_suspended(&pdev->dev)) |
2035 | clk_disable_unprepare(jpeg->clk); | ||
2036 | |||
1488 | clk_put(jpeg->clk); | 2037 | clk_put(jpeg->clk); |
1489 | 2038 | ||
1490 | return 0; | 2039 | return 0; |
@@ -1492,41 +2041,119 @@ static int s5p_jpeg_remove(struct platform_device *pdev) | |||
1492 | 2041 | ||
1493 | static int s5p_jpeg_runtime_suspend(struct device *dev) | 2042 | static int s5p_jpeg_runtime_suspend(struct device *dev) |
1494 | { | 2043 | { |
2044 | struct s5p_jpeg *jpeg = dev_get_drvdata(dev); | ||
2045 | |||
2046 | clk_disable_unprepare(jpeg->clk); | ||
2047 | |||
1495 | return 0; | 2048 | return 0; |
1496 | } | 2049 | } |
1497 | 2050 | ||
1498 | static int s5p_jpeg_runtime_resume(struct device *dev) | 2051 | static int s5p_jpeg_runtime_resume(struct device *dev) |
1499 | { | 2052 | { |
1500 | struct s5p_jpeg *jpeg = dev_get_drvdata(dev); | 2053 | struct s5p_jpeg *jpeg = dev_get_drvdata(dev); |
2054 | unsigned long flags; | ||
2055 | int ret; | ||
2056 | |||
2057 | ret = clk_prepare_enable(jpeg->clk); | ||
2058 | if (ret < 0) | ||
2059 | return ret; | ||
2060 | |||
2061 | spin_lock_irqsave(&jpeg->slock, flags); | ||
2062 | |||
1501 | /* | 2063 | /* |
1502 | * JPEG IP allows storing two Huffman tables for each component | 2064 | * JPEG IP allows storing two Huffman tables for each component |
1503 | * We fill table 0 for each component | 2065 | * We fill table 0 for each component and do this here only |
2066 | * for S5PC210 device as Exynos4x12 requires programming its | ||
2067 | * Huffman tables each time the encoding process is initialized. | ||
1504 | */ | 2068 | */ |
1505 | jpeg_set_hdctbl(jpeg->regs); | 2069 | if (jpeg->variant->version == SJPEG_S5P) { |
1506 | jpeg_set_hdctblg(jpeg->regs); | 2070 | s5p_jpeg_set_hdctbl(jpeg->regs); |
1507 | jpeg_set_hactbl(jpeg->regs); | 2071 | s5p_jpeg_set_hdctblg(jpeg->regs); |
1508 | jpeg_set_hactblg(jpeg->regs); | 2072 | s5p_jpeg_set_hactbl(jpeg->regs); |
2073 | s5p_jpeg_set_hactblg(jpeg->regs); | ||
2074 | } | ||
2075 | |||
2076 | spin_unlock_irqrestore(&jpeg->slock, flags); | ||
2077 | |||
1509 | return 0; | 2078 | return 0; |
1510 | } | 2079 | } |
1511 | 2080 | ||
2081 | static int s5p_jpeg_suspend(struct device *dev) | ||
2082 | { | ||
2083 | if (pm_runtime_suspended(dev)) | ||
2084 | return 0; | ||
2085 | |||
2086 | return s5p_jpeg_runtime_suspend(dev); | ||
2087 | } | ||
2088 | |||
2089 | static int s5p_jpeg_resume(struct device *dev) | ||
2090 | { | ||
2091 | if (pm_runtime_suspended(dev)) | ||
2092 | return 0; | ||
2093 | |||
2094 | return s5p_jpeg_runtime_resume(dev); | ||
2095 | } | ||
2096 | |||
1512 | static const struct dev_pm_ops s5p_jpeg_pm_ops = { | 2097 | static const struct dev_pm_ops s5p_jpeg_pm_ops = { |
1513 | .runtime_suspend = s5p_jpeg_runtime_suspend, | 2098 | SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume) |
1514 | .runtime_resume = s5p_jpeg_runtime_resume, | 2099 | SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL) |
2100 | }; | ||
2101 | |||
2102 | #ifdef CONFIG_OF | ||
2103 | static struct s5p_jpeg_variant s5p_jpeg_drvdata = { | ||
2104 | .version = SJPEG_S5P, | ||
2105 | .jpeg_irq = s5p_jpeg_irq, | ||
2106 | }; | ||
2107 | |||
2108 | static struct s5p_jpeg_variant exynos4_jpeg_drvdata = { | ||
2109 | .version = SJPEG_EXYNOS4, | ||
2110 | .jpeg_irq = exynos4_jpeg_irq, | ||
2111 | }; | ||
2112 | |||
2113 | static const struct of_device_id samsung_jpeg_match[] = { | ||
2114 | { | ||
2115 | .compatible = "samsung,s5pv210-jpeg", | ||
2116 | .data = &s5p_jpeg_drvdata, | ||
2117 | }, { | ||
2118 | .compatible = "samsung,exynos4210-jpeg", | ||
2119 | .data = &s5p_jpeg_drvdata, | ||
2120 | }, { | ||
2121 | .compatible = "samsung,exynos4212-jpeg", | ||
2122 | .data = &exynos4_jpeg_drvdata, | ||
2123 | }, | ||
2124 | {}, | ||
1515 | }; | 2125 | }; |
1516 | 2126 | ||
2127 | MODULE_DEVICE_TABLE(of, samsung_jpeg_match); | ||
2128 | |||
2129 | static void *jpeg_get_drv_data(struct platform_device *pdev) | ||
2130 | { | ||
2131 | struct s5p_jpeg_variant *driver_data = NULL; | ||
2132 | const struct of_device_id *match; | ||
2133 | |||
2134 | match = of_match_node(of_match_ptr(samsung_jpeg_match), | ||
2135 | pdev->dev.of_node); | ||
2136 | if (match) | ||
2137 | driver_data = (struct s5p_jpeg_variant *)match->data; | ||
2138 | |||
2139 | return driver_data; | ||
2140 | } | ||
2141 | #endif | ||
2142 | |||
1517 | static struct platform_driver s5p_jpeg_driver = { | 2143 | static struct platform_driver s5p_jpeg_driver = { |
1518 | .probe = s5p_jpeg_probe, | 2144 | .probe = s5p_jpeg_probe, |
1519 | .remove = s5p_jpeg_remove, | 2145 | .remove = s5p_jpeg_remove, |
1520 | .driver = { | 2146 | .driver = { |
1521 | .owner = THIS_MODULE, | 2147 | .of_match_table = of_match_ptr(samsung_jpeg_match), |
1522 | .name = S5P_JPEG_M2M_NAME, | 2148 | .owner = THIS_MODULE, |
1523 | .pm = &s5p_jpeg_pm_ops, | 2149 | .name = S5P_JPEG_M2M_NAME, |
2150 | .pm = &s5p_jpeg_pm_ops, | ||
1524 | }, | 2151 | }, |
1525 | }; | 2152 | }; |
1526 | 2153 | ||
1527 | module_platform_driver(s5p_jpeg_driver); | 2154 | module_platform_driver(s5p_jpeg_driver); |
1528 | 2155 | ||
1529 | MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>"); | 2156 | MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>"); |
2157 | MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); | ||
1530 | MODULE_DESCRIPTION("Samsung JPEG codec driver"); | 2158 | MODULE_DESCRIPTION("Samsung JPEG codec driver"); |
1531 | MODULE_LICENSE("GPL"); | 2159 | MODULE_LICENSE("GPL"); |
1532 | |||
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 8a4013e3aee7..f482dbf55d5f 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #ifndef JPEG_CORE_H_ | 13 | #ifndef JPEG_CORE_H_ |
14 | #define JPEG_CORE_H_ | 14 | #define JPEG_CORE_H_ |
15 | 15 | ||
16 | #include <linux/interrupt.h> | ||
16 | #include <media/v4l2-device.h> | 17 | #include <media/v4l2-device.h> |
17 | #include <media/v4l2-fh.h> | 18 | #include <media/v4l2-fh.h> |
18 | #include <media/v4l2-ctrls.h> | 19 | #include <media/v4l2-ctrls.h> |
@@ -43,8 +44,45 @@ | |||
43 | #define DHP 0xde | 44 | #define DHP 0xde |
44 | 45 | ||
45 | /* Flags that indicate a format can be used for capture/output */ | 46 | /* Flags that indicate a format can be used for capture/output */ |
46 | #define MEM2MEM_CAPTURE (1 << 0) | 47 | #define SJPEG_FMT_FLAG_ENC_CAPTURE (1 << 0) |
47 | #define MEM2MEM_OUTPUT (1 << 1) | 48 | #define SJPEG_FMT_FLAG_ENC_OUTPUT (1 << 1) |
49 | #define SJPEG_FMT_FLAG_DEC_CAPTURE (1 << 2) | ||
50 | #define SJPEG_FMT_FLAG_DEC_OUTPUT (1 << 3) | ||
51 | #define SJPEG_FMT_FLAG_S5P (1 << 4) | ||
52 | #define SJPEG_FMT_FLAG_EXYNOS4 (1 << 5) | ||
53 | #define SJPEG_FMT_RGB (1 << 6) | ||
54 | #define SJPEG_FMT_NON_RGB (1 << 7) | ||
55 | |||
56 | #define S5P_JPEG_ENCODE 0 | ||
57 | #define S5P_JPEG_DECODE 1 | ||
58 | |||
59 | #define FMT_TYPE_OUTPUT 0 | ||
60 | #define FMT_TYPE_CAPTURE 1 | ||
61 | |||
62 | #define SJPEG_SUBSAMPLING_444 0x11 | ||
63 | #define SJPEG_SUBSAMPLING_422 0x21 | ||
64 | #define SJPEG_SUBSAMPLING_420 0x22 | ||
65 | |||
66 | /* Version numbers */ | ||
67 | |||
68 | #define SJPEG_S5P 1 | ||
69 | #define SJPEG_EXYNOS4 2 | ||
70 | |||
71 | enum exynos4_jpeg_result { | ||
72 | OK_ENC_OR_DEC, | ||
73 | ERR_PROT, | ||
74 | ERR_DEC_INVALID_FORMAT, | ||
75 | ERR_MULTI_SCAN, | ||
76 | ERR_FRAME, | ||
77 | ERR_UNKNOWN, | ||
78 | }; | ||
79 | |||
80 | enum exynos4_jpeg_img_quality_level { | ||
81 | QUALITY_LEVEL_1 = 0, /* high */ | ||
82 | QUALITY_LEVEL_2, | ||
83 | QUALITY_LEVEL_3, | ||
84 | QUALITY_LEVEL_4, /* low */ | ||
85 | }; | ||
48 | 86 | ||
49 | /** | 87 | /** |
50 | * struct s5p_jpeg - JPEG IP abstraction | 88 | * struct s5p_jpeg - JPEG IP abstraction |
@@ -71,9 +109,16 @@ struct s5p_jpeg { | |||
71 | 109 | ||
72 | void __iomem *regs; | 110 | void __iomem *regs; |
73 | unsigned int irq; | 111 | unsigned int irq; |
112 | enum exynos4_jpeg_result irq_ret; | ||
74 | struct clk *clk; | 113 | struct clk *clk; |
75 | struct device *dev; | 114 | struct device *dev; |
76 | void *alloc_ctx; | 115 | void *alloc_ctx; |
116 | struct s5p_jpeg_variant *variant; | ||
117 | }; | ||
118 | |||
119 | struct s5p_jpeg_variant { | ||
120 | unsigned int version; | ||
121 | irqreturn_t (*jpeg_irq)(int irq, void *priv); | ||
77 | }; | 122 | }; |
78 | 123 | ||
79 | /** | 124 | /** |
@@ -84,16 +129,18 @@ struct s5p_jpeg { | |||
84 | * @colplanes: number of color planes (1 for packed formats) | 129 | * @colplanes: number of color planes (1 for packed formats) |
85 | * @h_align: horizontal alignment order (align to 2^h_align) | 130 | * @h_align: horizontal alignment order (align to 2^h_align) |
86 | * @v_align: vertical alignment order (align to 2^v_align) | 131 | * @v_align: vertical alignment order (align to 2^v_align) |
87 | * @types: types of queue this format is applicable to | 132 | * @flags: flags describing format applicability |
88 | */ | 133 | */ |
89 | struct s5p_jpeg_fmt { | 134 | struct s5p_jpeg_fmt { |
90 | char *name; | 135 | char *name; |
91 | u32 fourcc; | 136 | u32 fourcc; |
92 | int depth; | 137 | int depth; |
93 | int colplanes; | 138 | int colplanes; |
139 | int memplanes; | ||
94 | int h_align; | 140 | int h_align; |
95 | int v_align; | 141 | int v_align; |
96 | u32 types; | 142 | int subsampling; |
143 | u32 flags; | ||
97 | }; | 144 | }; |
98 | 145 | ||
99 | /** | 146 | /** |
@@ -115,7 +162,6 @@ struct s5p_jpeg_q_data { | |||
115 | * @jpeg: JPEG IP device for this context | 162 | * @jpeg: JPEG IP device for this context |
116 | * @mode: compression (encode) operation or decompression (decode) | 163 | * @mode: compression (encode) operation or decompression (decode) |
117 | * @compr_quality: destination image quality in compression (encode) mode | 164 | * @compr_quality: destination image quality in compression (encode) mode |
118 | * @m2m_ctx: mem2mem device context | ||
119 | * @out_q: source (output) queue information | 165 | * @out_q: source (output) queue information |
120 | * @cap_fmt: destination (capture) queue queue information | 166 | * @cap_fmt: destination (capture) queue queue information |
121 | * @hdr_parsed: set if header has been parsed during decompression | 167 | * @hdr_parsed: set if header has been parsed during decompression |
@@ -127,7 +173,6 @@ struct s5p_jpeg_ctx { | |||
127 | unsigned short compr_quality; | 173 | unsigned short compr_quality; |
128 | unsigned short restart_interval; | 174 | unsigned short restart_interval; |
129 | unsigned short subsampling; | 175 | unsigned short subsampling; |
130 | struct v4l2_m2m_ctx *m2m_ctx; | ||
131 | struct s5p_jpeg_q_data out_q; | 176 | struct s5p_jpeg_q_data out_q; |
132 | struct s5p_jpeg_q_data cap_q; | 177 | struct s5p_jpeg_q_data cap_q; |
133 | struct v4l2_fh fh; | 178 | struct v4l2_fh fh; |
@@ -147,4 +192,16 @@ struct s5p_jpeg_buffer { | |||
147 | unsigned long data; | 192 | unsigned long data; |
148 | }; | 193 | }; |
149 | 194 | ||
195 | /** | ||
196 | * struct s5p_jpeg_addr - JPEG converter physical address set for DMA | ||
197 | * @y: luminance plane physical address | ||
198 | * @cb: Cb plane physical address | ||
199 | * @cr: Cr plane physical address | ||
200 | */ | ||
201 | struct s5p_jpeg_addr { | ||
202 | u32 y; | ||
203 | u32 cb; | ||
204 | u32 cr; | ||
205 | }; | ||
206 | |||
150 | #endif /* JPEG_CORE_H */ | 207 | #endif /* JPEG_CORE_H */ |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c new file mode 100644 index 000000000000..da8d6a1a984f --- /dev/null +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* Copyright (c) 2013 Samsung Electronics Co., Ltd. | ||
2 | * http://www.samsung.com/ | ||
3 | * | ||
4 | * Author: Jacek Anaszewski <j.anaszewski@samsung.com> | ||
5 | * | ||
6 | * Register interface file for JPEG driver on Exynos4x12. | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/delay.h> | ||
14 | |||
15 | #include "jpeg-core.h" | ||
16 | #include "jpeg-hw-exynos4.h" | ||
17 | #include "jpeg-regs.h" | ||
18 | |||
19 | void exynos4_jpeg_sw_reset(void __iomem *base) | ||
20 | { | ||
21 | unsigned int reg; | ||
22 | |||
23 | reg = readl(base + EXYNOS4_JPEG_CNTL_REG); | ||
24 | writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG); | ||
25 | |||
26 | ndelay(100000); | ||
27 | |||
28 | writel(reg | EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG); | ||
29 | } | ||
30 | |||
31 | void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode) | ||
32 | { | ||
33 | unsigned int reg; | ||
34 | |||
35 | reg = readl(base + EXYNOS4_JPEG_CNTL_REG); | ||
36 | /* set exynos4_jpeg mod register */ | ||
37 | if (mode == S5P_JPEG_DECODE) { | ||
38 | writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) | | ||
39 | EXYNOS4_DEC_MODE, | ||
40 | base + EXYNOS4_JPEG_CNTL_REG); | ||
41 | } else {/* encode */ | ||
42 | writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) | | ||
43 | EXYNOS4_ENC_MODE, | ||
44 | base + EXYNOS4_JPEG_CNTL_REG); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt) | ||
49 | { | ||
50 | unsigned int reg; | ||
51 | |||
52 | reg = readl(base + EXYNOS4_IMG_FMT_REG) & | ||
53 | EXYNOS4_ENC_IN_FMT_MASK; /* clear except enc format */ | ||
54 | |||
55 | switch (img_fmt) { | ||
56 | case V4L2_PIX_FMT_GREY: | ||
57 | reg = reg | EXYNOS4_ENC_GRAY_IMG | EXYNOS4_GRAY_IMG_IP; | ||
58 | break; | ||
59 | case V4L2_PIX_FMT_RGB32: | ||
60 | reg = reg | EXYNOS4_ENC_RGB_IMG | | ||
61 | EXYNOS4_RGB_IP_RGB_32BIT_IMG; | ||
62 | break; | ||
63 | case V4L2_PIX_FMT_RGB565: | ||
64 | reg = reg | EXYNOS4_ENC_RGB_IMG | | ||
65 | EXYNOS4_RGB_IP_RGB_16BIT_IMG; | ||
66 | break; | ||
67 | case V4L2_PIX_FMT_NV24: | ||
68 | reg = reg | EXYNOS4_ENC_YUV_444_IMG | | ||
69 | EXYNOS4_YUV_444_IP_YUV_444_2P_IMG | | ||
70 | EXYNOS4_SWAP_CHROMA_CBCR; | ||
71 | break; | ||
72 | case V4L2_PIX_FMT_NV42: | ||
73 | reg = reg | EXYNOS4_ENC_YUV_444_IMG | | ||
74 | EXYNOS4_YUV_444_IP_YUV_444_2P_IMG | | ||
75 | EXYNOS4_SWAP_CHROMA_CRCB; | ||
76 | break; | ||
77 | case V4L2_PIX_FMT_YUYV: | ||
78 | reg = reg | EXYNOS4_DEC_YUV_422_IMG | | ||
79 | EXYNOS4_YUV_422_IP_YUV_422_1P_IMG | | ||
80 | EXYNOS4_SWAP_CHROMA_CBCR; | ||
81 | break; | ||
82 | |||
83 | case V4L2_PIX_FMT_YVYU: | ||
84 | reg = reg | EXYNOS4_DEC_YUV_422_IMG | | ||
85 | EXYNOS4_YUV_422_IP_YUV_422_1P_IMG | | ||
86 | EXYNOS4_SWAP_CHROMA_CRCB; | ||
87 | break; | ||
88 | case V4L2_PIX_FMT_NV16: | ||
89 | reg = reg | EXYNOS4_DEC_YUV_422_IMG | | ||
90 | EXYNOS4_YUV_422_IP_YUV_422_2P_IMG | | ||
91 | EXYNOS4_SWAP_CHROMA_CBCR; | ||
92 | break; | ||
93 | case V4L2_PIX_FMT_NV61: | ||
94 | reg = reg | EXYNOS4_DEC_YUV_422_IMG | | ||
95 | EXYNOS4_YUV_422_IP_YUV_422_2P_IMG | | ||
96 | EXYNOS4_SWAP_CHROMA_CRCB; | ||
97 | break; | ||
98 | case V4L2_PIX_FMT_NV12: | ||
99 | reg = reg | EXYNOS4_DEC_YUV_420_IMG | | ||
100 | EXYNOS4_YUV_420_IP_YUV_420_2P_IMG | | ||
101 | EXYNOS4_SWAP_CHROMA_CBCR; | ||
102 | break; | ||
103 | case V4L2_PIX_FMT_NV21: | ||
104 | reg = reg | EXYNOS4_DEC_YUV_420_IMG | | ||
105 | EXYNOS4_YUV_420_IP_YUV_420_2P_IMG | | ||
106 | EXYNOS4_SWAP_CHROMA_CRCB; | ||
107 | break; | ||
108 | case V4L2_PIX_FMT_YUV420: | ||
109 | reg = reg | EXYNOS4_DEC_YUV_420_IMG | | ||
110 | EXYNOS4_YUV_420_IP_YUV_420_3P_IMG | | ||
111 | EXYNOS4_SWAP_CHROMA_CBCR; | ||
112 | break; | ||
113 | default: | ||
114 | break; | ||
115 | |||
116 | } | ||
117 | |||
118 | writel(reg, base + EXYNOS4_IMG_FMT_REG); | ||
119 | } | ||
120 | |||
121 | void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt) | ||
122 | { | ||
123 | unsigned int reg; | ||
124 | |||
125 | reg = readl(base + EXYNOS4_IMG_FMT_REG) & | ||
126 | ~EXYNOS4_ENC_FMT_MASK; /* clear enc format */ | ||
127 | |||
128 | switch (out_fmt) { | ||
129 | case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY: | ||
130 | reg = reg | EXYNOS4_ENC_FMT_GRAY; | ||
131 | break; | ||
132 | |||
133 | case V4L2_JPEG_CHROMA_SUBSAMPLING_444: | ||
134 | reg = reg | EXYNOS4_ENC_FMT_YUV_444; | ||
135 | break; | ||
136 | |||
137 | case V4L2_JPEG_CHROMA_SUBSAMPLING_422: | ||
138 | reg = reg | EXYNOS4_ENC_FMT_YUV_422; | ||
139 | break; | ||
140 | |||
141 | case V4L2_JPEG_CHROMA_SUBSAMPLING_420: | ||
142 | reg = reg | EXYNOS4_ENC_FMT_YUV_420; | ||
143 | break; | ||
144 | |||
145 | default: | ||
146 | break; | ||
147 | } | ||
148 | |||
149 | writel(reg, base + EXYNOS4_IMG_FMT_REG); | ||
150 | } | ||
151 | |||
152 | void exynos4_jpeg_set_interrupt(void __iomem *base) | ||
153 | { | ||
154 | unsigned int reg; | ||
155 | |||
156 | reg = readl(base + EXYNOS4_INT_EN_REG) & ~EXYNOS4_INT_EN_MASK; | ||
157 | writel(EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG); | ||
158 | } | ||
159 | |||
160 | unsigned int exynos4_jpeg_get_int_status(void __iomem *base) | ||
161 | { | ||
162 | unsigned int int_status; | ||
163 | |||
164 | int_status = readl(base + EXYNOS4_INT_STATUS_REG); | ||
165 | |||
166 | return int_status; | ||
167 | } | ||
168 | |||
169 | unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base) | ||
170 | { | ||
171 | unsigned int fifo_status; | ||
172 | |||
173 | fifo_status = readl(base + EXYNOS4_FIFO_STATUS_REG); | ||
174 | |||
175 | return fifo_status; | ||
176 | } | ||
177 | |||
178 | void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value) | ||
179 | { | ||
180 | unsigned int reg; | ||
181 | |||
182 | reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~EXYNOS4_HUF_TBL_EN; | ||
183 | |||
184 | if (value == 1) | ||
185 | writel(reg | EXYNOS4_HUF_TBL_EN, | ||
186 | base + EXYNOS4_JPEG_CNTL_REG); | ||
187 | else | ||
188 | writel(reg | ~EXYNOS4_HUF_TBL_EN, | ||
189 | base + EXYNOS4_JPEG_CNTL_REG); | ||
190 | } | ||
191 | |||
192 | void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value) | ||
193 | { | ||
194 | unsigned int reg; | ||
195 | |||
196 | reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~(EXYNOS4_SYS_INT_EN); | ||
197 | |||
198 | if (value == 1) | ||
199 | writel(EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG); | ||
200 | else | ||
201 | writel(~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG); | ||
202 | } | ||
203 | |||
204 | void exynos4_jpeg_set_stream_buf_address(void __iomem *base, | ||
205 | unsigned int address) | ||
206 | { | ||
207 | writel(address, base + EXYNOS4_OUT_MEM_BASE_REG); | ||
208 | } | ||
209 | |||
210 | void exynos4_jpeg_set_stream_size(void __iomem *base, | ||
211 | unsigned int x_value, unsigned int y_value) | ||
212 | { | ||
213 | writel(0x0, base + EXYNOS4_JPEG_IMG_SIZE_REG); /* clear */ | ||
214 | writel(EXYNOS4_X_SIZE(x_value) | EXYNOS4_Y_SIZE(y_value), | ||
215 | base + EXYNOS4_JPEG_IMG_SIZE_REG); | ||
216 | } | ||
217 | |||
218 | void exynos4_jpeg_set_frame_buf_address(void __iomem *base, | ||
219 | struct s5p_jpeg_addr *exynos4_jpeg_addr) | ||
220 | { | ||
221 | writel(exynos4_jpeg_addr->y, base + EXYNOS4_IMG_BA_PLANE_1_REG); | ||
222 | writel(exynos4_jpeg_addr->cb, base + EXYNOS4_IMG_BA_PLANE_2_REG); | ||
223 | writel(exynos4_jpeg_addr->cr, base + EXYNOS4_IMG_BA_PLANE_3_REG); | ||
224 | } | ||
225 | |||
226 | void exynos4_jpeg_set_encode_tbl_select(void __iomem *base, | ||
227 | enum exynos4_jpeg_img_quality_level level) | ||
228 | { | ||
229 | unsigned int reg; | ||
230 | |||
231 | reg = EXYNOS4_Q_TBL_COMP1_0 | EXYNOS4_Q_TBL_COMP2_1 | | ||
232 | EXYNOS4_Q_TBL_COMP3_1 | | ||
233 | EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_1 | | ||
234 | EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_0 | | ||
235 | EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_1; | ||
236 | |||
237 | writel(reg, base + EXYNOS4_TBL_SEL_REG); | ||
238 | } | ||
239 | |||
240 | void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt) | ||
241 | { | ||
242 | if (fmt == V4L2_PIX_FMT_GREY) | ||
243 | writel(0xd2, base + EXYNOS4_HUFF_CNT_REG); | ||
244 | else | ||
245 | writel(0x1a2, base + EXYNOS4_HUFF_CNT_REG); | ||
246 | } | ||
247 | |||
248 | unsigned int exynos4_jpeg_get_stream_size(void __iomem *base) | ||
249 | { | ||
250 | unsigned int size; | ||
251 | |||
252 | size = readl(base + EXYNOS4_BITSTREAM_SIZE_REG); | ||
253 | return size; | ||
254 | } | ||
255 | |||
256 | void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size) | ||
257 | { | ||
258 | writel(size, base + EXYNOS4_BITSTREAM_SIZE_REG); | ||
259 | } | ||
260 | |||
261 | void exynos4_jpeg_get_frame_size(void __iomem *base, | ||
262 | unsigned int *width, unsigned int *height) | ||
263 | { | ||
264 | *width = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) & | ||
265 | EXYNOS4_DECODED_SIZE_MASK); | ||
266 | *height = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) >> 16) & | ||
267 | EXYNOS4_DECODED_SIZE_MASK; | ||
268 | } | ||
269 | |||
270 | unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base) | ||
271 | { | ||
272 | return readl(base + EXYNOS4_DECODE_IMG_FMT_REG) & | ||
273 | EXYNOS4_JPEG_DECODED_IMG_FMT_MASK; | ||
274 | } | ||
275 | |||
276 | void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size) | ||
277 | { | ||
278 | writel(size, base + EXYNOS4_INT_TIMER_COUNT_REG); | ||
279 | } | ||
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h new file mode 100644 index 000000000000..c228d28a4bc7 --- /dev/null +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* Copyright (c) 2013 Samsung Electronics Co., Ltd. | ||
2 | * http://www.samsung.com/ | ||
3 | * | ||
4 | * Author: Jacek Anaszewski <j.anaszewski@samsung.com> | ||
5 | * | ||
6 | * Header file of the register interface for JPEG driver on Exynos4x12. | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef JPEG_HW_EXYNOS4_H_ | ||
14 | #define JPEG_HW_EXYNOS4_H_ | ||
15 | |||
16 | void exynos4_jpeg_sw_reset(void __iomem *base); | ||
17 | void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode); | ||
18 | void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt); | ||
19 | void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt); | ||
20 | void exynos4_jpeg_set_enc_tbl(void __iomem *base); | ||
21 | void exynos4_jpeg_set_interrupt(void __iomem *base); | ||
22 | unsigned int exynos4_jpeg_get_int_status(void __iomem *base); | ||
23 | void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value); | ||
24 | void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value); | ||
25 | void exynos4_jpeg_set_stream_buf_address(void __iomem *base, | ||
26 | unsigned int address); | ||
27 | void exynos4_jpeg_set_stream_size(void __iomem *base, | ||
28 | unsigned int x_value, unsigned int y_value); | ||
29 | void exynos4_jpeg_set_frame_buf_address(void __iomem *base, | ||
30 | struct s5p_jpeg_addr *jpeg_addr); | ||
31 | void exynos4_jpeg_set_encode_tbl_select(void __iomem *base, | ||
32 | enum exynos4_jpeg_img_quality_level level); | ||
33 | void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt); | ||
34 | void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size); | ||
35 | unsigned int exynos4_jpeg_get_stream_size(void __iomem *base); | ||
36 | void exynos4_jpeg_get_frame_size(void __iomem *base, | ||
37 | unsigned int *width, unsigned int *height); | ||
38 | unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base); | ||
39 | unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base); | ||
40 | void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size); | ||
41 | |||
42 | #endif /* JPEG_HW_EXYNOS4_H_ */ | ||
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index b47e887b6138..52407d790726 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c | |||
@@ -9,27 +9,15 @@ | |||
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | #ifndef JPEG_HW_H_ | ||
13 | #define JPEG_HW_H_ | ||
14 | 12 | ||
15 | #include <linux/io.h> | 13 | #include <linux/io.h> |
16 | #include <linux/videodev2.h> | 14 | #include <linux/videodev2.h> |
17 | 15 | ||
18 | #include "jpeg-hw.h" | 16 | #include "jpeg-core.h" |
19 | #include "jpeg-regs.h" | 17 | #include "jpeg-regs.h" |
18 | #include "jpeg-hw-s5p.h" | ||
20 | 19 | ||
21 | #define S5P_JPEG_MIN_WIDTH 32 | 20 | void s5p_jpeg_reset(void __iomem *regs) |
22 | #define S5P_JPEG_MIN_HEIGHT 32 | ||
23 | #define S5P_JPEG_MAX_WIDTH 8192 | ||
24 | #define S5P_JPEG_MAX_HEIGHT 8192 | ||
25 | #define S5P_JPEG_ENCODE 0 | ||
26 | #define S5P_JPEG_DECODE 1 | ||
27 | #define S5P_JPEG_RAW_IN_565 0 | ||
28 | #define S5P_JPEG_RAW_IN_422 1 | ||
29 | #define S5P_JPEG_RAW_OUT_422 0 | ||
30 | #define S5P_JPEG_RAW_OUT_420 1 | ||
31 | |||
32 | static inline void jpeg_reset(void __iomem *regs) | ||
33 | { | 21 | { |
34 | unsigned long reg; | 22 | unsigned long reg; |
35 | 23 | ||
@@ -42,12 +30,12 @@ static inline void jpeg_reset(void __iomem *regs) | |||
42 | } | 30 | } |
43 | } | 31 | } |
44 | 32 | ||
45 | static inline void jpeg_poweron(void __iomem *regs) | 33 | void s5p_jpeg_poweron(void __iomem *regs) |
46 | { | 34 | { |
47 | writel(S5P_POWER_ON, regs + S5P_JPGCLKCON); | 35 | writel(S5P_POWER_ON, regs + S5P_JPGCLKCON); |
48 | } | 36 | } |
49 | 37 | ||
50 | static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) | 38 | void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) |
51 | { | 39 | { |
52 | unsigned long reg, m; | 40 | unsigned long reg, m; |
53 | 41 | ||
@@ -63,7 +51,7 @@ static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) | |||
63 | writel(reg, regs + S5P_JPGCMOD); | 51 | writel(reg, regs + S5P_JPGCMOD); |
64 | } | 52 | } |
65 | 53 | ||
66 | static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16) | 54 | void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16) |
67 | { | 55 | { |
68 | unsigned long reg; | 56 | unsigned long reg; |
69 | 57 | ||
@@ -75,7 +63,7 @@ static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16) | |||
75 | writel(reg, regs + S5P_JPGCMOD); | 63 | writel(reg, regs + S5P_JPGCMOD); |
76 | } | 64 | } |
77 | 65 | ||
78 | static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode) | 66 | void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode) |
79 | { | 67 | { |
80 | unsigned long reg, m; | 68 | unsigned long reg, m; |
81 | 69 | ||
@@ -90,7 +78,7 @@ static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode) | |||
90 | writel(reg, regs + S5P_JPGMOD); | 78 | writel(reg, regs + S5P_JPGMOD); |
91 | } | 79 | } |
92 | 80 | ||
93 | static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode) | 81 | void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode) |
94 | { | 82 | { |
95 | unsigned long reg, m; | 83 | unsigned long reg, m; |
96 | 84 | ||
@@ -105,12 +93,12 @@ static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode) | |||
105 | writel(reg, regs + S5P_JPGMOD); | 93 | writel(reg, regs + S5P_JPGMOD); |
106 | } | 94 | } |
107 | 95 | ||
108 | static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs) | 96 | unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs) |
109 | { | 97 | { |
110 | return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK; | 98 | return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK; |
111 | } | 99 | } |
112 | 100 | ||
113 | static inline void jpeg_dri(void __iomem *regs, unsigned int dri) | 101 | void s5p_jpeg_dri(void __iomem *regs, unsigned int dri) |
114 | { | 102 | { |
115 | unsigned long reg; | 103 | unsigned long reg; |
116 | 104 | ||
@@ -125,7 +113,7 @@ static inline void jpeg_dri(void __iomem *regs, unsigned int dri) | |||
125 | writel(reg, regs + S5P_JPGDRI_L); | 113 | writel(reg, regs + S5P_JPGDRI_L); |
126 | } | 114 | } |
127 | 115 | ||
128 | static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n) | 116 | void s5p_jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n) |
129 | { | 117 | { |
130 | unsigned long reg; | 118 | unsigned long reg; |
131 | 119 | ||
@@ -135,7 +123,7 @@ static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n) | |||
135 | writel(reg, regs + S5P_JPG_QTBL); | 123 | writel(reg, regs + S5P_JPG_QTBL); |
136 | } | 124 | } |
137 | 125 | ||
138 | static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t) | 126 | void s5p_jpeg_htbl_ac(void __iomem *regs, unsigned int t) |
139 | { | 127 | { |
140 | unsigned long reg; | 128 | unsigned long reg; |
141 | 129 | ||
@@ -146,7 +134,7 @@ static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t) | |||
146 | writel(reg, regs + S5P_JPG_HTBL); | 134 | writel(reg, regs + S5P_JPG_HTBL); |
147 | } | 135 | } |
148 | 136 | ||
149 | static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t) | 137 | void s5p_jpeg_htbl_dc(void __iomem *regs, unsigned int t) |
150 | { | 138 | { |
151 | unsigned long reg; | 139 | unsigned long reg; |
152 | 140 | ||
@@ -157,7 +145,7 @@ static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t) | |||
157 | writel(reg, regs + S5P_JPG_HTBL); | 145 | writel(reg, regs + S5P_JPG_HTBL); |
158 | } | 146 | } |
159 | 147 | ||
160 | static inline void jpeg_y(void __iomem *regs, unsigned int y) | 148 | void s5p_jpeg_y(void __iomem *regs, unsigned int y) |
161 | { | 149 | { |
162 | unsigned long reg; | 150 | unsigned long reg; |
163 | 151 | ||
@@ -172,7 +160,7 @@ static inline void jpeg_y(void __iomem *regs, unsigned int y) | |||
172 | writel(reg, regs + S5P_JPGY_L); | 160 | writel(reg, regs + S5P_JPGY_L); |
173 | } | 161 | } |
174 | 162 | ||
175 | static inline void jpeg_x(void __iomem *regs, unsigned int x) | 163 | void s5p_jpeg_x(void __iomem *regs, unsigned int x) |
176 | { | 164 | { |
177 | unsigned long reg; | 165 | unsigned long reg; |
178 | 166 | ||
@@ -187,7 +175,7 @@ static inline void jpeg_x(void __iomem *regs, unsigned int x) | |||
187 | writel(reg, regs + S5P_JPGX_L); | 175 | writel(reg, regs + S5P_JPGX_L); |
188 | } | 176 | } |
189 | 177 | ||
190 | static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable) | 178 | void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable) |
191 | { | 179 | { |
192 | unsigned long reg; | 180 | unsigned long reg; |
193 | 181 | ||
@@ -198,7 +186,7 @@ static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable) | |||
198 | writel(reg, regs + S5P_JPGINTSE); | 186 | writel(reg, regs + S5P_JPGINTSE); |
199 | } | 187 | } |
200 | 188 | ||
201 | static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable) | 189 | void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable) |
202 | { | 190 | { |
203 | unsigned long reg; | 191 | unsigned long reg; |
204 | 192 | ||
@@ -209,7 +197,7 @@ static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable) | |||
209 | writel(reg, regs + S5P_JPGINTSE); | 197 | writel(reg, regs + S5P_JPGINTSE); |
210 | } | 198 | } |
211 | 199 | ||
212 | static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl) | 200 | void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl) |
213 | { | 201 | { |
214 | unsigned long reg; | 202 | unsigned long reg; |
215 | 203 | ||
@@ -220,7 +208,7 @@ static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl) | |||
220 | writel(reg, regs + S5P_JPGINTSE); | 208 | writel(reg, regs + S5P_JPGINTSE); |
221 | } | 209 | } |
222 | 210 | ||
223 | static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val) | 211 | void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val) |
224 | { | 212 | { |
225 | unsigned long reg; | 213 | unsigned long reg; |
226 | 214 | ||
@@ -231,7 +219,7 @@ static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val) | |||
231 | writel(reg, regs + S5P_JPG_TIMER_SE); | 219 | writel(reg, regs + S5P_JPG_TIMER_SE); |
232 | } | 220 | } |
233 | 221 | ||
234 | static inline void jpeg_timer_disable(void __iomem *regs) | 222 | void s5p_jpeg_timer_disable(void __iomem *regs) |
235 | { | 223 | { |
236 | unsigned long reg; | 224 | unsigned long reg; |
237 | 225 | ||
@@ -240,13 +228,13 @@ static inline void jpeg_timer_disable(void __iomem *regs) | |||
240 | writel(reg, regs + S5P_JPG_TIMER_SE); | 228 | writel(reg, regs + S5P_JPG_TIMER_SE); |
241 | } | 229 | } |
242 | 230 | ||
243 | static inline int jpeg_timer_stat(void __iomem *regs) | 231 | int s5p_jpeg_timer_stat(void __iomem *regs) |
244 | { | 232 | { |
245 | return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK) | 233 | return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK) |
246 | >> S5P_TIMER_INT_STAT_SHIFT); | 234 | >> S5P_TIMER_INT_STAT_SHIFT); |
247 | } | 235 | } |
248 | 236 | ||
249 | static inline void jpeg_clear_timer_stat(void __iomem *regs) | 237 | void s5p_jpeg_clear_timer_stat(void __iomem *regs) |
250 | { | 238 | { |
251 | unsigned long reg; | 239 | unsigned long reg; |
252 | 240 | ||
@@ -255,7 +243,7 @@ static inline void jpeg_clear_timer_stat(void __iomem *regs) | |||
255 | writel(reg, regs + S5P_JPG_TIMER_SE); | 243 | writel(reg, regs + S5P_JPG_TIMER_SE); |
256 | } | 244 | } |
257 | 245 | ||
258 | static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size) | 246 | void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size) |
259 | { | 247 | { |
260 | unsigned long reg; | 248 | unsigned long reg; |
261 | 249 | ||
@@ -266,13 +254,13 @@ static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size) | |||
266 | writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); | 254 | writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); |
267 | } | 255 | } |
268 | 256 | ||
269 | static inline int jpeg_enc_stream_stat(void __iomem *regs) | 257 | int s5p_jpeg_enc_stream_stat(void __iomem *regs) |
270 | { | 258 | { |
271 | return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) & | 259 | return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) & |
272 | S5P_ENC_STREAM_INT_STAT_MASK); | 260 | S5P_ENC_STREAM_INT_STAT_MASK); |
273 | } | 261 | } |
274 | 262 | ||
275 | static inline void jpeg_clear_enc_stream_stat(void __iomem *regs) | 263 | void s5p_jpeg_clear_enc_stream_stat(void __iomem *regs) |
276 | { | 264 | { |
277 | unsigned long reg; | 265 | unsigned long reg; |
278 | 266 | ||
@@ -281,7 +269,7 @@ static inline void jpeg_clear_enc_stream_stat(void __iomem *regs) | |||
281 | writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); | 269 | writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); |
282 | } | 270 | } |
283 | 271 | ||
284 | static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format) | 272 | void s5p_jpeg_outform_raw(void __iomem *regs, unsigned long format) |
285 | { | 273 | { |
286 | unsigned long reg, f; | 274 | unsigned long reg, f; |
287 | 275 | ||
@@ -296,17 +284,17 @@ static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format) | |||
296 | writel(reg, regs + S5P_JPG_OUTFORM); | 284 | writel(reg, regs + S5P_JPG_OUTFORM); |
297 | } | 285 | } |
298 | 286 | ||
299 | static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr) | 287 | void s5p_jpeg_jpgadr(void __iomem *regs, unsigned long addr) |
300 | { | 288 | { |
301 | writel(addr, regs + S5P_JPG_JPGADR); | 289 | writel(addr, regs + S5P_JPG_JPGADR); |
302 | } | 290 | } |
303 | 291 | ||
304 | static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr) | 292 | void s5p_jpeg_imgadr(void __iomem *regs, unsigned long addr) |
305 | { | 293 | { |
306 | writel(addr, regs + S5P_JPG_IMGADR); | 294 | writel(addr, regs + S5P_JPG_IMGADR); |
307 | } | 295 | } |
308 | 296 | ||
309 | static inline void jpeg_coef(void __iomem *regs, unsigned int i, | 297 | void s5p_jpeg_coef(void __iomem *regs, unsigned int i, |
310 | unsigned int j, unsigned int coef) | 298 | unsigned int j, unsigned int coef) |
311 | { | 299 | { |
312 | unsigned long reg; | 300 | unsigned long reg; |
@@ -317,24 +305,24 @@ static inline void jpeg_coef(void __iomem *regs, unsigned int i, | |||
317 | writel(reg, regs + S5P_JPG_COEF(i)); | 305 | writel(reg, regs + S5P_JPG_COEF(i)); |
318 | } | 306 | } |
319 | 307 | ||
320 | static inline void jpeg_start(void __iomem *regs) | 308 | void s5p_jpeg_start(void __iomem *regs) |
321 | { | 309 | { |
322 | writel(1, regs + S5P_JSTART); | 310 | writel(1, regs + S5P_JSTART); |
323 | } | 311 | } |
324 | 312 | ||
325 | static inline int jpeg_result_stat_ok(void __iomem *regs) | 313 | int s5p_jpeg_result_stat_ok(void __iomem *regs) |
326 | { | 314 | { |
327 | return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK) | 315 | return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK) |
328 | >> S5P_RESULT_STAT_SHIFT); | 316 | >> S5P_RESULT_STAT_SHIFT); |
329 | } | 317 | } |
330 | 318 | ||
331 | static inline int jpeg_stream_stat_ok(void __iomem *regs) | 319 | int s5p_jpeg_stream_stat_ok(void __iomem *regs) |
332 | { | 320 | { |
333 | return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK) | 321 | return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK) |
334 | >> S5P_STREAM_STAT_SHIFT); | 322 | >> S5P_STREAM_STAT_SHIFT); |
335 | } | 323 | } |
336 | 324 | ||
337 | static inline void jpeg_clear_int(void __iomem *regs) | 325 | void s5p_jpeg_clear_int(void __iomem *regs) |
338 | { | 326 | { |
339 | unsigned long reg; | 327 | unsigned long reg; |
340 | 328 | ||
@@ -343,7 +331,7 @@ static inline void jpeg_clear_int(void __iomem *regs) | |||
343 | reg = readl(regs + S5P_JPGOPR); | 331 | reg = readl(regs + S5P_JPGOPR); |
344 | } | 332 | } |
345 | 333 | ||
346 | static inline unsigned int jpeg_compressed_size(void __iomem *regs) | 334 | unsigned int s5p_jpeg_compressed_size(void __iomem *regs) |
347 | { | 335 | { |
348 | unsigned long jpeg_size = 0; | 336 | unsigned long jpeg_size = 0; |
349 | 337 | ||
@@ -353,5 +341,3 @@ static inline unsigned int jpeg_compressed_size(void __iomem *regs) | |||
353 | 341 | ||
354 | return (unsigned int)jpeg_size; | 342 | return (unsigned int)jpeg_size; |
355 | } | 343 | } |
356 | |||
357 | #endif /* JPEG_HW_H_ */ | ||
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h new file mode 100644 index 000000000000..c11ebe86b9c9 --- /dev/null +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef JPEG_HW_S5P_H_ | ||
13 | #define JPEG_HW_S5P_H_ | ||
14 | |||
15 | #include <linux/io.h> | ||
16 | #include <linux/videodev2.h> | ||
17 | |||
18 | #include "jpeg-regs.h" | ||
19 | |||
20 | #define S5P_JPEG_MIN_WIDTH 32 | ||
21 | #define S5P_JPEG_MIN_HEIGHT 32 | ||
22 | #define S5P_JPEG_MAX_WIDTH 8192 | ||
23 | #define S5P_JPEG_MAX_HEIGHT 8192 | ||
24 | #define S5P_JPEG_RAW_IN_565 0 | ||
25 | #define S5P_JPEG_RAW_IN_422 1 | ||
26 | #define S5P_JPEG_RAW_OUT_422 0 | ||
27 | #define S5P_JPEG_RAW_OUT_420 1 | ||
28 | |||
29 | void s5p_jpeg_reset(void __iomem *regs); | ||
30 | void s5p_jpeg_poweron(void __iomem *regs); | ||
31 | void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode); | ||
32 | void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16); | ||
33 | void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode); | ||
34 | void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode); | ||
35 | unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs); | ||
36 | void s5p_jpeg_dri(void __iomem *regs, unsigned int dri); | ||
37 | void s5p_jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n); | ||
38 | void s5p_jpeg_htbl_ac(void __iomem *regs, unsigned int t); | ||
39 | void s5p_jpeg_htbl_dc(void __iomem *regs, unsigned int t); | ||
40 | void s5p_jpeg_y(void __iomem *regs, unsigned int y); | ||
41 | void s5p_jpeg_x(void __iomem *regs, unsigned int x); | ||
42 | void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable); | ||
43 | void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable); | ||
44 | void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl); | ||
45 | void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val); | ||
46 | void s5p_jpeg_timer_disable(void __iomem *regs); | ||
47 | int s5p_jpeg_timer_stat(void __iomem *regs); | ||
48 | void s5p_jpeg_clear_timer_stat(void __iomem *regs); | ||
49 | void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size); | ||
50 | int s5p_jpeg_enc_stream_stat(void __iomem *regs); | ||
51 | void s5p_jpeg_clear_enc_stream_stat(void __iomem *regs); | ||
52 | void s5p_jpeg_outform_raw(void __iomem *regs, unsigned long format); | ||
53 | void s5p_jpeg_jpgadr(void __iomem *regs, unsigned long addr); | ||
54 | void s5p_jpeg_imgadr(void __iomem *regs, unsigned long addr); | ||
55 | void s5p_jpeg_coef(void __iomem *regs, unsigned int i, | ||
56 | unsigned int j, unsigned int coef); | ||
57 | void s5p_jpeg_start(void __iomem *regs); | ||
58 | int s5p_jpeg_result_stat_ok(void __iomem *regs); | ||
59 | int s5p_jpeg_stream_stat_ok(void __iomem *regs); | ||
60 | void s5p_jpeg_clear_int(void __iomem *regs); | ||
61 | unsigned int s5p_jpeg_compressed_size(void __iomem *regs); | ||
62 | |||
63 | #endif /* JPEG_HW_S5P_H_ */ | ||
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h index 38e50815668c..33f2c7374cfd 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h | |||
@@ -2,10 +2,11 @@ | |||
2 | * | 2 | * |
3 | * Register definition file for Samsung JPEG codec driver | 3 | * Register definition file for Samsung JPEG codec driver |
4 | * | 4 | * |
5 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | 5 | * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd. |
6 | * http://www.samsung.com | 6 | * http://www.samsung.com |
7 | * | 7 | * |
8 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 8 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> |
9 | * Author: Jacek Anaszewski <j.anaszewski@samsung.com> | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -15,6 +16,8 @@ | |||
15 | #ifndef JPEG_REGS_H_ | 16 | #ifndef JPEG_REGS_H_ |
16 | #define JPEG_REGS_H_ | 17 | #define JPEG_REGS_H_ |
17 | 18 | ||
19 | /* Register and bit definitions for S5PC210 */ | ||
20 | |||
18 | /* JPEG mode register */ | 21 | /* JPEG mode register */ |
19 | #define S5P_JPGMOD 0x00 | 22 | #define S5P_JPGMOD 0x00 |
20 | #define S5P_PROC_MODE_MASK (0x1 << 3) | 23 | #define S5P_PROC_MODE_MASK (0x1 << 3) |
@@ -166,5 +169,209 @@ | |||
166 | /* JPEG AC Huffman table register */ | 169 | /* JPEG AC Huffman table register */ |
167 | #define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400) | 170 | #define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400) |
168 | 171 | ||
172 | |||
173 | /* Register and bit definitions for Exynos 4x12 */ | ||
174 | |||
175 | /* JPEG Codec Control Registers */ | ||
176 | #define EXYNOS4_JPEG_CNTL_REG 0x00 | ||
177 | #define EXYNOS4_INT_EN_REG 0x04 | ||
178 | #define EXYNOS4_INT_TIMER_COUNT_REG 0x08 | ||
179 | #define EXYNOS4_INT_STATUS_REG 0x0c | ||
180 | #define EXYNOS4_OUT_MEM_BASE_REG 0x10 | ||
181 | #define EXYNOS4_JPEG_IMG_SIZE_REG 0x14 | ||
182 | #define EXYNOS4_IMG_BA_PLANE_1_REG 0x18 | ||
183 | #define EXYNOS4_IMG_SO_PLANE_1_REG 0x1c | ||
184 | #define EXYNOS4_IMG_PO_PLANE_1_REG 0x20 | ||
185 | #define EXYNOS4_IMG_BA_PLANE_2_REG 0x24 | ||
186 | #define EXYNOS4_IMG_SO_PLANE_2_REG 0x28 | ||
187 | #define EXYNOS4_IMG_PO_PLANE_2_REG 0x2c | ||
188 | #define EXYNOS4_IMG_BA_PLANE_3_REG 0x30 | ||
189 | #define EXYNOS4_IMG_SO_PLANE_3_REG 0x34 | ||
190 | #define EXYNOS4_IMG_PO_PLANE_3_REG 0x38 | ||
191 | |||
192 | #define EXYNOS4_TBL_SEL_REG 0x3c | ||
193 | |||
194 | #define EXYNOS4_IMG_FMT_REG 0x40 | ||
195 | |||
196 | #define EXYNOS4_BITSTREAM_SIZE_REG 0x44 | ||
197 | #define EXYNOS4_PADDING_REG 0x48 | ||
198 | #define EXYNOS4_HUFF_CNT_REG 0x4c | ||
199 | #define EXYNOS4_FIFO_STATUS_REG 0x50 | ||
200 | #define EXYNOS4_DECODE_XY_SIZE_REG 0x54 | ||
201 | #define EXYNOS4_DECODE_IMG_FMT_REG 0x58 | ||
202 | |||
203 | #define EXYNOS4_QUAN_TBL_ENTRY_REG 0x100 | ||
204 | #define EXYNOS4_HUFF_TBL_ENTRY_REG 0x200 | ||
205 | |||
206 | |||
207 | /****************************************************************/ | ||
208 | /* Bit definition part */ | ||
209 | /****************************************************************/ | ||
210 | |||
211 | /* JPEG CNTL Register bit */ | ||
212 | #define EXYNOS4_ENC_DEC_MODE_MASK (0xfffffffc << 0) | ||
213 | #define EXYNOS4_DEC_MODE (1 << 0) | ||
214 | #define EXYNOS4_ENC_MODE (1 << 1) | ||
215 | #define EXYNOS4_AUTO_RST_MARKER (1 << 2) | ||
216 | #define EXYNOS4_RST_INTERVAL_SHIFT 3 | ||
217 | #define EXYNOS4_RST_INTERVAL(x) (((x) & 0xffff) \ | ||
218 | << EXYNOS4_RST_INTERVAL_SHIFT) | ||
219 | #define EXYNOS4_HUF_TBL_EN (1 << 19) | ||
220 | #define EXYNOS4_HOR_SCALING_SHIFT 20 | ||
221 | #define EXYNOS4_HOR_SCALING_MASK (3 << EXYNOS4_HOR_SCALING_SHIFT) | ||
222 | #define EXYNOS4_HOR_SCALING(x) (((x) & 0x3) \ | ||
223 | << EXYNOS4_HOR_SCALING_SHIFT) | ||
224 | #define EXYNOS4_VER_SCALING_SHIFT 22 | ||
225 | #define EXYNOS4_VER_SCALING_MASK (3 << EXYNOS4_VER_SCALING_SHIFT) | ||
226 | #define EXYNOS4_VER_SCALING(x) (((x) & 0x3) \ | ||
227 | << EXYNOS4_VER_SCALING_SHIFT) | ||
228 | #define EXYNOS4_PADDING (1 << 27) | ||
229 | #define EXYNOS4_SYS_INT_EN (1 << 28) | ||
230 | #define EXYNOS4_SOFT_RESET_HI (1 << 29) | ||
231 | |||
232 | /* JPEG INT Register bit */ | ||
233 | #define EXYNOS4_INT_EN_MASK (0x1f << 0) | ||
234 | #define EXYNOS4_PROT_ERR_INT_EN (1 << 0) | ||
235 | #define EXYNOS4_IMG_COMPLETION_INT_EN (1 << 1) | ||
236 | #define EXYNOS4_DEC_INVALID_FORMAT_EN (1 << 2) | ||
237 | #define EXYNOS4_MULTI_SCAN_ERROR_EN (1 << 3) | ||
238 | #define EXYNOS4_FRAME_ERR_EN (1 << 4) | ||
239 | #define EXYNOS4_INT_EN_ALL (0x1f << 0) | ||
240 | |||
241 | #define EXYNOS4_MOD_REG_PROC_ENC (0 << 3) | ||
242 | #define EXYNOS4_MOD_REG_PROC_DEC (1 << 3) | ||
243 | |||
244 | #define EXYNOS4_MOD_REG_SUBSAMPLE_444 (0 << 0) | ||
245 | #define EXYNOS4_MOD_REG_SUBSAMPLE_422 (1 << 0) | ||
246 | #define EXYNOS4_MOD_REG_SUBSAMPLE_420 (2 << 0) | ||
247 | #define EXYNOS4_MOD_REG_SUBSAMPLE_GRAY (3 << 0) | ||
248 | |||
249 | |||
250 | /* JPEG IMAGE SIZE Register bit */ | ||
251 | #define EXYNOS4_X_SIZE_SHIFT 0 | ||
252 | #define EXYNOS4_X_SIZE_MASK (0xffff << EXYNOS4_X_SIZE_SHIFT) | ||
253 | #define EXYNOS4_X_SIZE(x) (((x) & 0xffff) << EXYNOS4_X_SIZE_SHIFT) | ||
254 | #define EXYNOS4_Y_SIZE_SHIFT 16 | ||
255 | #define EXYNOS4_Y_SIZE_MASK (0xffff << EXYNOS4_Y_SIZE_SHIFT) | ||
256 | #define EXYNOS4_Y_SIZE(x) (((x) & 0xffff) << EXYNOS4_Y_SIZE_SHIFT) | ||
257 | |||
258 | /* JPEG IMAGE FORMAT Register bit */ | ||
259 | #define EXYNOS4_ENC_IN_FMT_MASK 0xffff0000 | ||
260 | #define EXYNOS4_ENC_GRAY_IMG (0 << 0) | ||
261 | #define EXYNOS4_ENC_RGB_IMG (1 << 0) | ||
262 | #define EXYNOS4_ENC_YUV_444_IMG (2 << 0) | ||
263 | #define EXYNOS4_ENC_YUV_422_IMG (3 << 0) | ||
264 | #define EXYNOS4_ENC_YUV_440_IMG (4 << 0) | ||
265 | |||
266 | #define EXYNOS4_DEC_GRAY_IMG (0 << 0) | ||
267 | #define EXYNOS4_DEC_RGB_IMG (1 << 0) | ||
268 | #define EXYNOS4_DEC_YUV_444_IMG (2 << 0) | ||
269 | #define EXYNOS4_DEC_YUV_422_IMG (3 << 0) | ||
270 | #define EXYNOS4_DEC_YUV_420_IMG (4 << 0) | ||
271 | |||
272 | #define EXYNOS4_GRAY_IMG_IP_SHIFT 3 | ||
273 | #define EXYNOS4_GRAY_IMG_IP_MASK (7 << EXYNOS4_GRAY_IMG_IP_SHIFT) | ||
274 | #define EXYNOS4_GRAY_IMG_IP (4 << EXYNOS4_GRAY_IMG_IP_SHIFT) | ||
275 | |||
276 | #define EXYNOS4_RGB_IP_SHIFT 6 | ||
277 | #define EXYNOS4_RGB_IP_MASK (7 << EXYNOS4_RGB_IP_SHIFT) | ||
278 | #define EXYNOS4_RGB_IP_RGB_16BIT_IMG (4 << EXYNOS4_RGB_IP_SHIFT) | ||
279 | #define EXYNOS4_RGB_IP_RGB_32BIT_IMG (5 << EXYNOS4_RGB_IP_SHIFT) | ||
280 | |||
281 | #define EXYNOS4_YUV_444_IP_SHIFT 9 | ||
282 | #define EXYNOS4_YUV_444_IP_MASK (7 << EXYNOS4_YUV_444_IP_SHIFT) | ||
283 | #define EXYNOS4_YUV_444_IP_YUV_444_2P_IMG (4 << EXYNOS4_YUV_444_IP_SHIFT) | ||
284 | #define EXYNOS4_YUV_444_IP_YUV_444_3P_IMG (5 << EXYNOS4_YUV_444_IP_SHIFT) | ||
285 | |||
286 | #define EXYNOS4_YUV_422_IP_SHIFT 12 | ||
287 | #define EXYNOS4_YUV_422_IP_MASK (7 << EXYNOS4_YUV_422_IP_SHIFT) | ||
288 | #define EXYNOS4_YUV_422_IP_YUV_422_1P_IMG (4 << EXYNOS4_YUV_422_IP_SHIFT) | ||
289 | #define EXYNOS4_YUV_422_IP_YUV_422_2P_IMG (5 << EXYNOS4_YUV_422_IP_SHIFT) | ||
290 | #define EXYNOS4_YUV_422_IP_YUV_422_3P_IMG (6 << EXYNOS4_YUV_422_IP_SHIFT) | ||
291 | |||
292 | #define EXYNOS4_YUV_420_IP_SHIFT 15 | ||
293 | #define EXYNOS4_YUV_420_IP_MASK (7 << EXYNOS4_YUV_420_IP_SHIFT) | ||
294 | #define EXYNOS4_YUV_420_IP_YUV_420_2P_IMG (4 << EXYNOS4_YUV_420_IP_SHIFT) | ||
295 | #define EXYNOS4_YUV_420_IP_YUV_420_3P_IMG (5 << EXYNOS4_YUV_420_IP_SHIFT) | ||
296 | |||
297 | #define EXYNOS4_ENC_FMT_SHIFT 24 | ||
298 | #define EXYNOS4_ENC_FMT_MASK (3 << EXYNOS4_ENC_FMT_SHIFT) | ||
299 | #define EXYNOS4_ENC_FMT_GRAY (0 << EXYNOS4_ENC_FMT_SHIFT) | ||
300 | #define EXYNOS4_ENC_FMT_YUV_444 (1 << EXYNOS4_ENC_FMT_SHIFT) | ||
301 | #define EXYNOS4_ENC_FMT_YUV_422 (2 << EXYNOS4_ENC_FMT_SHIFT) | ||
302 | #define EXYNOS4_ENC_FMT_YUV_420 (3 << EXYNOS4_ENC_FMT_SHIFT) | ||
303 | |||
304 | #define EXYNOS4_JPEG_DECODED_IMG_FMT_MASK 0x03 | ||
305 | |||
306 | #define EXYNOS4_SWAP_CHROMA_CRCB (1 << 26) | ||
307 | #define EXYNOS4_SWAP_CHROMA_CBCR (0 << 26) | ||
308 | |||
309 | /* JPEG HUFF count Register bit */ | ||
310 | #define EXYNOS4_HUFF_COUNT_MASK 0xffff | ||
311 | |||
312 | /* JPEG Decoded_img_x_y_size Register bit */ | ||
313 | #define EXYNOS4_DECODED_SIZE_MASK 0x0000ffff | ||
314 | |||
315 | /* JPEG Decoded image format Register bit */ | ||
316 | #define EXYNOS4_DECODED_IMG_FMT_MASK 0x3 | ||
317 | |||
318 | /* JPEG TBL SEL Register bit */ | ||
319 | #define EXYNOS4_Q_TBL_COMP1_0 (0 << 0) | ||
320 | #define EXYNOS4_Q_TBL_COMP1_1 (1 << 0) | ||
321 | #define EXYNOS4_Q_TBL_COMP1_2 (2 << 0) | ||
322 | #define EXYNOS4_Q_TBL_COMP1_3 (3 << 0) | ||
323 | |||
324 | #define EXYNOS4_Q_TBL_COMP2_0 (0 << 2) | ||
325 | #define EXYNOS4_Q_TBL_COMP2_1 (1 << 2) | ||
326 | #define EXYNOS4_Q_TBL_COMP2_2 (2 << 2) | ||
327 | #define EXYNOS4_Q_TBL_COMP2_3 (3 << 2) | ||
328 | |||
329 | #define EXYNOS4_Q_TBL_COMP3_0 (0 << 4) | ||
330 | #define EXYNOS4_Q_TBL_COMP3_1 (1 << 4) | ||
331 | #define EXYNOS4_Q_TBL_COMP3_2 (2 << 4) | ||
332 | #define EXYNOS4_Q_TBL_COMP3_3 (3 << 4) | ||
333 | |||
334 | #define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_0 (0 << 6) | ||
335 | #define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_1 (1 << 6) | ||
336 | #define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_0 (2 << 6) | ||
337 | #define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_1 (3 << 6) | ||
338 | |||
339 | #define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_0 (0 << 8) | ||
340 | #define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_1 (1 << 8) | ||
341 | #define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_0 (2 << 8) | ||
342 | #define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_1 (3 << 8) | ||
343 | |||
344 | #define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_0 (0 << 10) | ||
345 | #define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_1 (1 << 10) | ||
346 | #define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_0 (2 << 10) | ||
347 | #define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_1 (3 << 10) | ||
348 | |||
349 | /* JPEG quantizer table register */ | ||
350 | #define EXYNOS4_QTBL_CONTENT(n) (0x100 + (n) * 0x40) | ||
351 | |||
352 | /* JPEG DC luminance (code length) Huffman table register */ | ||
353 | #define EXYNOS4_HUFF_TBL_HDCLL 0x200 | ||
354 | |||
355 | /* JPEG DC luminance (values) Huffman table register */ | ||
356 | #define EXYNOS4_HUFF_TBL_HDCLV 0x210 | ||
357 | |||
358 | /* JPEG DC chrominance (code length) Huffman table register */ | ||
359 | #define EXYNOS4_HUFF_TBL_HDCCL 0x220 | ||
360 | |||
361 | /* JPEG DC chrominance (values) Huffman table register */ | ||
362 | #define EXYNOS4_HUFF_TBL_HDCCV 0x230 | ||
363 | |||
364 | /* JPEG AC luminance (code length) Huffman table register */ | ||
365 | #define EXYNOS4_HUFF_TBL_HACLL 0x240 | ||
366 | |||
367 | /* JPEG AC luminance (values) Huffman table register */ | ||
368 | #define EXYNOS4_HUFF_TBL_HACLV 0x250 | ||
369 | |||
370 | /* JPEG AC chrominance (code length) Huffman table register */ | ||
371 | #define EXYNOS4_HUFF_TBL_HACCL 0x300 | ||
372 | |||
373 | /* JPEG AC chrominance (values) Huffman table register */ | ||
374 | #define EXYNOS4_HUFF_TBL_HACCV 0x310 | ||
375 | |||
169 | #endif /* JPEG_REGS_H_ */ | 376 | #endif /* JPEG_REGS_H_ */ |
170 | 377 | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e46067a57853..e2aac592d29f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -177,21 +177,6 @@ unlock: | |||
177 | mutex_unlock(&dev->mfc_mutex); | 177 | mutex_unlock(&dev->mfc_mutex); |
178 | } | 178 | } |
179 | 179 | ||
180 | static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file) | ||
181 | { | ||
182 | struct video_device *vdev = video_devdata(file); | ||
183 | |||
184 | if (!vdev) { | ||
185 | mfc_err("failed to get video_device"); | ||
186 | return MFCNODE_INVALID; | ||
187 | } | ||
188 | if (vdev->index == 0) | ||
189 | return MFCNODE_DECODER; | ||
190 | else if (vdev->index == 1) | ||
191 | return MFCNODE_ENCODER; | ||
192 | return MFCNODE_INVALID; | ||
193 | } | ||
194 | |||
195 | static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) | 180 | static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) |
196 | { | 181 | { |
197 | mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); | 182 | mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); |
@@ -705,6 +690,7 @@ irq_cleanup_hw: | |||
705 | /* Open an MFC node */ | 690 | /* Open an MFC node */ |
706 | static int s5p_mfc_open(struct file *file) | 691 | static int s5p_mfc_open(struct file *file) |
707 | { | 692 | { |
693 | struct video_device *vdev = video_devdata(file); | ||
708 | struct s5p_mfc_dev *dev = video_drvdata(file); | 694 | struct s5p_mfc_dev *dev = video_drvdata(file); |
709 | struct s5p_mfc_ctx *ctx = NULL; | 695 | struct s5p_mfc_ctx *ctx = NULL; |
710 | struct vb2_queue *q; | 696 | struct vb2_queue *q; |
@@ -742,7 +728,7 @@ static int s5p_mfc_open(struct file *file) | |||
742 | /* Mark context as idle */ | 728 | /* Mark context as idle */ |
743 | clear_work_bit_irqsave(ctx); | 729 | clear_work_bit_irqsave(ctx); |
744 | dev->ctx[ctx->num] = ctx; | 730 | dev->ctx[ctx->num] = ctx; |
745 | if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { | 731 | if (vdev == dev->vfd_dec) { |
746 | ctx->type = MFCINST_DECODER; | 732 | ctx->type = MFCINST_DECODER; |
747 | ctx->c_ops = get_dec_codec_ops(); | 733 | ctx->c_ops = get_dec_codec_ops(); |
748 | s5p_mfc_dec_init(ctx); | 734 | s5p_mfc_dec_init(ctx); |
@@ -752,7 +738,7 @@ static int s5p_mfc_open(struct file *file) | |||
752 | mfc_err("Failed to setup mfc controls\n"); | 738 | mfc_err("Failed to setup mfc controls\n"); |
753 | goto err_ctrls_setup; | 739 | goto err_ctrls_setup; |
754 | } | 740 | } |
755 | } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { | 741 | } else if (vdev == dev->vfd_enc) { |
756 | ctx->type = MFCINST_ENCODER; | 742 | ctx->type = MFCINST_ENCODER; |
757 | ctx->c_ops = get_enc_codec_ops(); | 743 | ctx->c_ops = get_enc_codec_ops(); |
758 | /* only for encoder */ | 744 | /* only for encoder */ |
@@ -797,10 +783,10 @@ static int s5p_mfc_open(struct file *file) | |||
797 | q = &ctx->vq_dst; | 783 | q = &ctx->vq_dst; |
798 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 784 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
799 | q->drv_priv = &ctx->fh; | 785 | q->drv_priv = &ctx->fh; |
800 | if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { | 786 | if (vdev == dev->vfd_dec) { |
801 | q->io_modes = VB2_MMAP; | 787 | q->io_modes = VB2_MMAP; |
802 | q->ops = get_dec_queue_ops(); | 788 | q->ops = get_dec_queue_ops(); |
803 | } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { | 789 | } else if (vdev == dev->vfd_enc) { |
804 | q->io_modes = VB2_MMAP | VB2_USERPTR; | 790 | q->io_modes = VB2_MMAP | VB2_USERPTR; |
805 | q->ops = get_enc_queue_ops(); | 791 | q->ops = get_enc_queue_ops(); |
806 | } else { | 792 | } else { |
@@ -819,10 +805,10 @@ static int s5p_mfc_open(struct file *file) | |||
819 | q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 805 | q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
820 | q->io_modes = VB2_MMAP; | 806 | q->io_modes = VB2_MMAP; |
821 | q->drv_priv = &ctx->fh; | 807 | q->drv_priv = &ctx->fh; |
822 | if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { | 808 | if (vdev == dev->vfd_dec) { |
823 | q->io_modes = VB2_MMAP; | 809 | q->io_modes = VB2_MMAP; |
824 | q->ops = get_dec_queue_ops(); | 810 | q->ops = get_dec_queue_ops(); |
825 | } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { | 811 | } else if (vdev == dev->vfd_enc) { |
826 | q->io_modes = VB2_MMAP | VB2_USERPTR; | 812 | q->io_modes = VB2_MMAP | VB2_USERPTR; |
827 | q->ops = get_enc_queue_ops(); | 813 | q->ops = get_enc_queue_ops(); |
828 | } else { | 814 | } else { |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 6920b546181a..f723f1f2f578 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h | |||
@@ -115,15 +115,6 @@ enum s5p_mfc_fmt_type { | |||
115 | }; | 115 | }; |
116 | 116 | ||
117 | /** | 117 | /** |
118 | * enum s5p_mfc_node_type - The type of an MFC device node. | ||
119 | */ | ||
120 | enum s5p_mfc_node_type { | ||
121 | MFCNODE_INVALID = -1, | ||
122 | MFCNODE_DECODER = 0, | ||
123 | MFCNODE_ENCODER = 1, | ||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * enum s5p_mfc_inst_type - The type of an MFC instance. | 118 | * enum s5p_mfc_inst_type - The type of an MFC instance. |
128 | */ | 119 | */ |
129 | enum s5p_mfc_inst_type { | 120 | enum s5p_mfc_inst_type { |
@@ -422,6 +413,11 @@ struct s5p_mfc_vp8_enc_params { | |||
422 | enum v4l2_vp8_golden_frame_sel golden_frame_sel; | 413 | enum v4l2_vp8_golden_frame_sel golden_frame_sel; |
423 | u8 hier_layer; | 414 | u8 hier_layer; |
424 | u8 hier_layer_qp[3]; | 415 | u8 hier_layer_qp[3]; |
416 | u8 rc_min_qp; | ||
417 | u8 rc_max_qp; | ||
418 | u8 rc_frame_qp; | ||
419 | u8 rc_p_frame_qp; | ||
420 | u8 profile; | ||
425 | }; | 421 | }; |
426 | 422 | ||
427 | /** | 423 | /** |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 4ff3b6cd6842..91b6e020ddf3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | |||
@@ -618,6 +618,46 @@ static struct mfc_control controls[] = { | |||
618 | .default_value = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV, | 618 | .default_value = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV, |
619 | .menu_skip_mask = 0, | 619 | .menu_skip_mask = 0, |
620 | }, | 620 | }, |
621 | { | ||
622 | .id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, | ||
623 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
624 | .minimum = 0, | ||
625 | .maximum = 127, | ||
626 | .step = 1, | ||
627 | .default_value = 127, | ||
628 | }, | ||
629 | { | ||
630 | .id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, | ||
631 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
632 | .minimum = 0, | ||
633 | .maximum = 11, | ||
634 | .step = 1, | ||
635 | .default_value = 0, | ||
636 | }, | ||
637 | { | ||
638 | .id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP, | ||
639 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
640 | .minimum = 0, | ||
641 | .maximum = 127, | ||
642 | .step = 1, | ||
643 | .default_value = 10, | ||
644 | }, | ||
645 | { | ||
646 | .id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP, | ||
647 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
648 | .minimum = 0, | ||
649 | .maximum = 127, | ||
650 | .step = 1, | ||
651 | .default_value = 10, | ||
652 | }, | ||
653 | { | ||
654 | .id = V4L2_CID_MPEG_VIDEO_VPX_PROFILE, | ||
655 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
656 | .minimum = 0, | ||
657 | .maximum = 3, | ||
658 | .step = 1, | ||
659 | .default_value = 0, | ||
660 | }, | ||
621 | }; | 661 | }; |
622 | 662 | ||
623 | #define NUM_CTRLS ARRAY_SIZE(controls) | 663 | #define NUM_CTRLS ARRAY_SIZE(controls) |
@@ -1557,6 +1597,21 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) | |||
1557 | case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: | 1597 | case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: |
1558 | p->codec.vp8.golden_frame_sel = ctrl->val; | 1598 | p->codec.vp8.golden_frame_sel = ctrl->val; |
1559 | break; | 1599 | break; |
1600 | case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: | ||
1601 | p->codec.vp8.rc_min_qp = ctrl->val; | ||
1602 | break; | ||
1603 | case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: | ||
1604 | p->codec.vp8.rc_max_qp = ctrl->val; | ||
1605 | break; | ||
1606 | case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: | ||
1607 | p->codec.vp8.rc_frame_qp = ctrl->val; | ||
1608 | break; | ||
1609 | case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: | ||
1610 | p->codec.vp8.rc_p_frame_qp = ctrl->val; | ||
1611 | break; | ||
1612 | case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: | ||
1613 | p->codec.vp8.profile = ctrl->val; | ||
1614 | break; | ||
1560 | default: | 1615 | default: |
1561 | v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", | 1616 | v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", |
1562 | ctrl->id, ctrl->val); | 1617 | ctrl->id, ctrl->val); |
@@ -1863,7 +1918,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) | |||
1863 | if (ctx->src_bufs_cnt < ctx->pb_count) { | 1918 | if (ctx->src_bufs_cnt < ctx->pb_count) { |
1864 | mfc_err("Need minimum %d OUTPUT buffers\n", | 1919 | mfc_err("Need minimum %d OUTPUT buffers\n", |
1865 | ctx->pb_count); | 1920 | ctx->pb_count); |
1866 | return -EINVAL; | 1921 | return -ENOBUFS; |
1867 | } | 1922 | } |
1868 | } | 1923 | } |
1869 | 1924 | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 461358c4a790..f6ff2dbf3a1d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | |||
@@ -1197,10 +1197,8 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) | |||
1197 | reg |= ((p->num_b_frame & 0x3) << 16); | 1197 | reg |= ((p->num_b_frame & 0x3) << 16); |
1198 | WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); | 1198 | WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); |
1199 | 1199 | ||
1200 | /* profile & level */ | 1200 | /* profile - 0 ~ 3 */ |
1201 | reg = 0; | 1201 | reg = p_vp8->profile & 0x3; |
1202 | /** profile */ | ||
1203 | reg |= (0x1 << 4); | ||
1204 | WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); | 1202 | WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); |
1205 | 1203 | ||
1206 | /* rate control config. */ | 1204 | /* rate control config. */ |
@@ -1218,6 +1216,26 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) | |||
1218 | WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); | 1216 | WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); |
1219 | } | 1217 | } |
1220 | 1218 | ||
1219 | /* frame QP */ | ||
1220 | reg &= ~(0x7F); | ||
1221 | reg |= p_vp8->rc_frame_qp & 0x7F; | ||
1222 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
1223 | |||
1224 | /* other QPs */ | ||
1225 | WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
1226 | if (!p->rc_frame && !p->rc_mb) { | ||
1227 | reg = 0; | ||
1228 | reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8); | ||
1229 | reg |= p_vp8->rc_frame_qp & 0x7F; | ||
1230 | WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
1231 | } | ||
1232 | |||
1233 | /* max QP */ | ||
1234 | reg = ((p_vp8->rc_max_qp & 0x7F) << 8); | ||
1235 | /* min QP */ | ||
1236 | reg |= p_vp8->rc_min_qp & 0x7F; | ||
1237 | WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); | ||
1238 | |||
1221 | /* vbv buffer size */ | 1239 | /* vbv buffer size */ |
1222 | if (p->frame_skip_mode == | 1240 | if (p->frame_skip_mode == |
1223 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { | 1241 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { |
diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c index 51805a5e2beb..bc08b5f28e44 100644 --- a/drivers/media/platform/s5p-tv/mixer_drv.c +++ b/drivers/media/platform/s5p-tv/mixer_drv.c | |||
@@ -347,19 +347,41 @@ static int mxr_runtime_resume(struct device *dev) | |||
347 | { | 347 | { |
348 | struct mxr_device *mdev = to_mdev(dev); | 348 | struct mxr_device *mdev = to_mdev(dev); |
349 | struct mxr_resources *res = &mdev->res; | 349 | struct mxr_resources *res = &mdev->res; |
350 | int ret; | ||
350 | 351 | ||
351 | mxr_dbg(mdev, "resume - start\n"); | 352 | mxr_dbg(mdev, "resume - start\n"); |
352 | mutex_lock(&mdev->mutex); | 353 | mutex_lock(&mdev->mutex); |
353 | /* turn clocks on */ | 354 | /* turn clocks on */ |
354 | clk_enable(res->mixer); | 355 | ret = clk_prepare_enable(res->mixer); |
355 | clk_enable(res->vp); | 356 | if (ret < 0) { |
356 | clk_enable(res->sclk_mixer); | 357 | dev_err(mdev->dev, "clk_prepare_enable(mixer) failed\n"); |
358 | goto fail; | ||
359 | } | ||
360 | ret = clk_prepare_enable(res->vp); | ||
361 | if (ret < 0) { | ||
362 | dev_err(mdev->dev, "clk_prepare_enable(vp) failed\n"); | ||
363 | goto fail_mixer; | ||
364 | } | ||
365 | ret = clk_prepare_enable(res->sclk_mixer); | ||
366 | if (ret < 0) { | ||
367 | dev_err(mdev->dev, "clk_prepare_enable(sclk_mixer) failed\n"); | ||
368 | goto fail_vp; | ||
369 | } | ||
357 | /* apply default configuration */ | 370 | /* apply default configuration */ |
358 | mxr_reg_reset(mdev); | 371 | mxr_reg_reset(mdev); |
359 | mxr_dbg(mdev, "resume - finished\n"); | 372 | mxr_dbg(mdev, "resume - finished\n"); |
360 | 373 | ||
361 | mutex_unlock(&mdev->mutex); | 374 | mutex_unlock(&mdev->mutex); |
362 | return 0; | 375 | return 0; |
376 | |||
377 | fail_vp: | ||
378 | clk_disable_unprepare(res->vp); | ||
379 | fail_mixer: | ||
380 | clk_disable_unprepare(res->mixer); | ||
381 | fail: | ||
382 | mutex_unlock(&mdev->mutex); | ||
383 | dev_err(mdev->dev, "resume failed\n"); | ||
384 | return ret; | ||
363 | } | 385 | } |
364 | 386 | ||
365 | static int mxr_runtime_suspend(struct device *dev) | 387 | static int mxr_runtime_suspend(struct device *dev) |
@@ -369,9 +391,9 @@ static int mxr_runtime_suspend(struct device *dev) | |||
369 | mxr_dbg(mdev, "suspend - start\n"); | 391 | mxr_dbg(mdev, "suspend - start\n"); |
370 | mutex_lock(&mdev->mutex); | 392 | mutex_lock(&mdev->mutex); |
371 | /* turn clocks off */ | 393 | /* turn clocks off */ |
372 | clk_disable(res->sclk_mixer); | 394 | clk_disable_unprepare(res->sclk_mixer); |
373 | clk_disable(res->vp); | 395 | clk_disable_unprepare(res->vp); |
374 | clk_disable(res->mixer); | 396 | clk_disable_unprepare(res->mixer); |
375 | mutex_unlock(&mdev->mutex); | 397 | mutex_unlock(&mdev->mutex); |
376 | mxr_dbg(mdev, "suspend - finished\n"); | 398 | mxr_dbg(mdev, "suspend - finished\n"); |
377 | return 0; | 399 | return 0; |
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 81b97db111d8..c5059ba0d733 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c | |||
@@ -948,7 +948,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) | |||
948 | 948 | ||
949 | if (count == 0) { | 949 | if (count == 0) { |
950 | mxr_dbg(mdev, "no output buffers queued\n"); | 950 | mxr_dbg(mdev, "no output buffers queued\n"); |
951 | return -EINVAL; | 951 | return -ENOBUFS; |
952 | } | 952 | } |
953 | 953 | ||
954 | /* block any changes in output configuration */ | 954 | /* block any changes in output configuration */ |
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c index 0afa90f0f6ab..5a7c3796f22e 100644 --- a/drivers/media/platform/s5p-tv/sdo_drv.c +++ b/drivers/media/platform/s5p-tv/sdo_drv.c | |||
@@ -55,6 +55,8 @@ struct sdo_device { | |||
55 | struct clk *dacphy; | 55 | struct clk *dacphy; |
56 | /** clock for control of VPLL */ | 56 | /** clock for control of VPLL */ |
57 | struct clk *fout_vpll; | 57 | struct clk *fout_vpll; |
58 | /** vpll rate before sdo stream was on */ | ||
59 | unsigned long vpll_rate; | ||
58 | /** regulator for SDO IP power */ | 60 | /** regulator for SDO IP power */ |
59 | struct regulator *vdac; | 61 | struct regulator *vdac; |
60 | /** regulator for SDO plug detection */ | 62 | /** regulator for SDO plug detection */ |
@@ -193,17 +195,33 @@ static int sdo_s_power(struct v4l2_subdev *sd, int on) | |||
193 | 195 | ||
194 | static int sdo_streamon(struct sdo_device *sdev) | 196 | static int sdo_streamon(struct sdo_device *sdev) |
195 | { | 197 | { |
198 | int ret; | ||
199 | |||
196 | /* set proper clock for Timing Generator */ | 200 | /* set proper clock for Timing Generator */ |
197 | clk_set_rate(sdev->fout_vpll, 54000000); | 201 | sdev->vpll_rate = clk_get_rate(sdev->fout_vpll); |
202 | ret = clk_set_rate(sdev->fout_vpll, 54000000); | ||
203 | if (ret < 0) { | ||
204 | dev_err(sdev->dev, "Failed to set vpll rate\n"); | ||
205 | return ret; | ||
206 | } | ||
198 | dev_info(sdev->dev, "fout_vpll.rate = %lu\n", | 207 | dev_info(sdev->dev, "fout_vpll.rate = %lu\n", |
199 | clk_get_rate(sdev->fout_vpll)); | 208 | clk_get_rate(sdev->fout_vpll)); |
200 | /* enable clock in SDO */ | 209 | /* enable clock in SDO */ |
201 | sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON); | 210 | sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON); |
202 | clk_enable(sdev->dacphy); | 211 | ret = clk_prepare_enable(sdev->dacphy); |
212 | if (ret < 0) { | ||
213 | dev_err(sdev->dev, "clk_prepare_enable(dacphy) failed\n"); | ||
214 | goto fail; | ||
215 | } | ||
203 | /* enable DAC */ | 216 | /* enable DAC */ |
204 | sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC); | 217 | sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC); |
205 | sdo_reg_debug(sdev); | 218 | sdo_reg_debug(sdev); |
206 | return 0; | 219 | return 0; |
220 | |||
221 | fail: | ||
222 | sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON); | ||
223 | clk_set_rate(sdev->fout_vpll, sdev->vpll_rate); | ||
224 | return ret; | ||
207 | } | 225 | } |
208 | 226 | ||
209 | static int sdo_streamoff(struct sdo_device *sdev) | 227 | static int sdo_streamoff(struct sdo_device *sdev) |
@@ -211,7 +229,7 @@ static int sdo_streamoff(struct sdo_device *sdev) | |||
211 | int tries; | 229 | int tries; |
212 | 230 | ||
213 | sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC); | 231 | sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC); |
214 | clk_disable(sdev->dacphy); | 232 | clk_disable_unprepare(sdev->dacphy); |
215 | sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON); | 233 | sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON); |
216 | for (tries = 100; tries; --tries) { | 234 | for (tries = 100; tries; --tries) { |
217 | if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY) | 235 | if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY) |
@@ -220,6 +238,7 @@ static int sdo_streamoff(struct sdo_device *sdev) | |||
220 | } | 238 | } |
221 | if (tries == 0) | 239 | if (tries == 0) |
222 | dev_err(sdev->dev, "failed to stop streaming\n"); | 240 | dev_err(sdev->dev, "failed to stop streaming\n"); |
241 | clk_set_rate(sdev->fout_vpll, sdev->vpll_rate); | ||
223 | return tries ? 0 : -EIO; | 242 | return tries ? 0 : -EIO; |
224 | } | 243 | } |
225 | 244 | ||
@@ -254,7 +273,7 @@ static int sdo_runtime_suspend(struct device *dev) | |||
254 | dev_info(dev, "suspend\n"); | 273 | dev_info(dev, "suspend\n"); |
255 | regulator_disable(sdev->vdet); | 274 | regulator_disable(sdev->vdet); |
256 | regulator_disable(sdev->vdac); | 275 | regulator_disable(sdev->vdac); |
257 | clk_disable(sdev->sclk_dac); | 276 | clk_disable_unprepare(sdev->sclk_dac); |
258 | return 0; | 277 | return 0; |
259 | } | 278 | } |
260 | 279 | ||
@@ -266,7 +285,7 @@ static int sdo_runtime_resume(struct device *dev) | |||
266 | 285 | ||
267 | dev_info(dev, "resume\n"); | 286 | dev_info(dev, "resume\n"); |
268 | 287 | ||
269 | ret = clk_enable(sdev->sclk_dac); | 288 | ret = clk_prepare_enable(sdev->sclk_dac); |
270 | if (ret < 0) | 289 | if (ret < 0) |
271 | return ret; | 290 | return ret; |
272 | 291 | ||
@@ -299,7 +318,7 @@ static int sdo_runtime_resume(struct device *dev) | |||
299 | vdac_r_dis: | 318 | vdac_r_dis: |
300 | regulator_disable(sdev->vdac); | 319 | regulator_disable(sdev->vdac); |
301 | dac_clk_dis: | 320 | dac_clk_dis: |
302 | clk_disable(sdev->sclk_dac); | 321 | clk_disable_unprepare(sdev->sclk_dac); |
303 | return ret; | 322 | return ret; |
304 | } | 323 | } |
305 | 324 | ||
@@ -405,7 +424,11 @@ static int sdo_probe(struct platform_device *pdev) | |||
405 | } | 424 | } |
406 | 425 | ||
407 | /* enable gate for dac clock, because mixer uses it */ | 426 | /* enable gate for dac clock, because mixer uses it */ |
408 | clk_enable(sdev->dac); | 427 | ret = clk_prepare_enable(sdev->dac); |
428 | if (ret < 0) { | ||
429 | dev_err(dev, "clk_prepare_enable(dac) failed\n"); | ||
430 | goto fail_fout_vpll; | ||
431 | } | ||
409 | 432 | ||
410 | /* configure power management */ | 433 | /* configure power management */ |
411 | pm_runtime_enable(dev); | 434 | pm_runtime_enable(dev); |
@@ -444,7 +467,7 @@ static int sdo_remove(struct platform_device *pdev) | |||
444 | struct sdo_device *sdev = sd_to_sdev(sd); | 467 | struct sdo_device *sdev = sd_to_sdev(sd); |
445 | 468 | ||
446 | pm_runtime_disable(&pdev->dev); | 469 | pm_runtime_disable(&pdev->dev); |
447 | clk_disable(sdev->dac); | 470 | clk_disable_unprepare(sdev->dac); |
448 | clk_put(sdev->fout_vpll); | 471 | clk_put(sdev->fout_vpll); |
449 | clk_put(sdev->dacphy); | 472 | clk_put(sdev->dacphy); |
450 | clk_put(sdev->dac); | 473 | clk_put(sdev->dac); |
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 4f30341dc2ab..e5f1d4c14f2c 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c | |||
@@ -286,7 +286,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq, | |||
286 | vb->size = vb->height * bytes_per_line; | 286 | vb->size = vb->height * bytes_per_line; |
287 | if (vb->baddr && vb->bsize < vb->size) { | 287 | if (vb->baddr && vb->bsize < vb->size) { |
288 | /* User buffer too small */ | 288 | /* User buffer too small */ |
289 | dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n", | 289 | dev_warn(vq->dev, "User buffer too small: [%zu] @ %lx\n", |
290 | vb->bsize, vb->baddr); | 290 | vb->bsize, vb->baddr); |
291 | return -EINVAL; | 291 | return -EINVAL; |
292 | } | 292 | } |
@@ -302,9 +302,10 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq, | |||
302 | } | 302 | } |
303 | 303 | ||
304 | dev_dbg(vou_dev->v4l2_dev.dev, | 304 | dev_dbg(vou_dev->v4l2_dev.dev, |
305 | "%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n", | 305 | "%s(): fmt #%d, %u bytes per line, phys %pad, type %d, state %d\n", |
306 | __func__, vou_dev->pix_idx, bytes_per_line, | 306 | __func__, vou_dev->pix_idx, bytes_per_line, |
307 | videobuf_to_dma_contig(vb), vb->memory, vb->state); | 307 | ({ dma_addr_t addr = videobuf_to_dma_contig(vb); &addr; }), |
308 | vb->memory, vb->state); | ||
308 | 309 | ||
309 | return 0; | 310 | return 0; |
310 | } | 311 | } |
@@ -442,7 +443,7 @@ static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev, | |||
442 | int pix_idx, int w_idx, int h_idx) | 443 | int pix_idx, int w_idx, int h_idx) |
443 | { | 444 | { |
444 | struct sh_vou_fmt *fmt = vou_fmt + pix_idx; | 445 | struct sh_vou_fmt *fmt = vou_fmt + pix_idx; |
445 | unsigned int black_left, black_top, width_max, height_max, | 446 | unsigned int black_left, black_top, width_max, |
446 | frame_in_height, frame_out_height, frame_out_top; | 447 | frame_in_height, frame_out_height, frame_out_top; |
447 | struct v4l2_rect *rect = &vou_dev->rect; | 448 | struct v4l2_rect *rect = &vou_dev->rect; |
448 | struct v4l2_pix_format *pix = &vou_dev->pix; | 449 | struct v4l2_pix_format *pix = &vou_dev->pix; |
@@ -450,10 +451,10 @@ static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev, | |||
450 | 451 | ||
451 | if (vou_dev->std & V4L2_STD_525_60) { | 452 | if (vou_dev->std & V4L2_STD_525_60) { |
452 | width_max = 858; | 453 | width_max = 858; |
453 | height_max = 262; | 454 | /* height_max = 262; */ |
454 | } else { | 455 | } else { |
455 | width_max = 864; | 456 | width_max = 864; |
456 | height_max = 312; | 457 | /* height_max = 312; */ |
457 | } | 458 | } |
458 | 459 | ||
459 | frame_in_height = pix->height / 2; | 460 | frame_in_height = pix->height / 2; |
@@ -1052,7 +1053,6 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) | |||
1052 | static unsigned long j; | 1053 | static unsigned long j; |
1053 | struct videobuf_buffer *vb; | 1054 | struct videobuf_buffer *vb; |
1054 | static int cnt; | 1055 | static int cnt; |
1055 | static int side; | ||
1056 | u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked; | 1056 | u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked; |
1057 | u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR); | 1057 | u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR); |
1058 | 1058 | ||
@@ -1080,7 +1080,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) | |||
1080 | irq_status, masked, vou_status, cnt); | 1080 | irq_status, masked, vou_status, cnt); |
1081 | 1081 | ||
1082 | cnt++; | 1082 | cnt++; |
1083 | side = vou_status & 0x10000; | 1083 | /* side = vou_status & 0x10000; */ |
1084 | 1084 | ||
1085 | /* Clear only set interrupts */ | 1085 | /* Clear only set interrupts */ |
1086 | sh_vou_reg_a_write(vou_dev, VOUIR, masked); | 1086 | sh_vou_reg_a_write(vou_dev, VOUIR, masked); |
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 104485632501..4835173d7f80 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c | |||
@@ -34,13 +34,6 @@ | |||
34 | #define MIN_FRAME_RATE 15 | 34 | #define MIN_FRAME_RATE 15 |
35 | #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) | 35 | #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) |
36 | 36 | ||
37 | /* ISI states */ | ||
38 | enum { | ||
39 | ISI_STATE_IDLE = 0, | ||
40 | ISI_STATE_READY, | ||
41 | ISI_STATE_WAIT_SOF, | ||
42 | }; | ||
43 | |||
44 | /* Frame buffer descriptor */ | 37 | /* Frame buffer descriptor */ |
45 | struct fbd { | 38 | struct fbd { |
46 | /* Physical address of the frame buffer */ | 39 | /* Physical address of the frame buffer */ |
@@ -75,11 +68,6 @@ struct atmel_isi { | |||
75 | void __iomem *regs; | 68 | void __iomem *regs; |
76 | 69 | ||
77 | int sequence; | 70 | int sequence; |
78 | /* State of the ISI module in capturing mode */ | ||
79 | int state; | ||
80 | |||
81 | /* Wait queue for waiting for SOF */ | ||
82 | wait_queue_head_t vsync_wq; | ||
83 | 71 | ||
84 | struct vb2_alloc_ctx *alloc_ctx; | 72 | struct vb2_alloc_ctx *alloc_ctx; |
85 | 73 | ||
@@ -124,16 +112,16 @@ static int configure_geometry(struct atmel_isi *isi, u32 width, | |||
124 | case V4L2_MBUS_FMT_Y8_1X8: | 112 | case V4L2_MBUS_FMT_Y8_1X8: |
125 | cr = ISI_CFG2_GRAYSCALE; | 113 | cr = ISI_CFG2_GRAYSCALE; |
126 | break; | 114 | break; |
127 | case V4L2_MBUS_FMT_UYVY8_2X8: | 115 | case V4L2_MBUS_FMT_VYUY8_2X8: |
128 | cr = ISI_CFG2_YCC_SWAP_MODE_3; | 116 | cr = ISI_CFG2_YCC_SWAP_MODE_3; |
129 | break; | 117 | break; |
130 | case V4L2_MBUS_FMT_VYUY8_2X8: | 118 | case V4L2_MBUS_FMT_UYVY8_2X8: |
131 | cr = ISI_CFG2_YCC_SWAP_MODE_2; | 119 | cr = ISI_CFG2_YCC_SWAP_MODE_2; |
132 | break; | 120 | break; |
133 | case V4L2_MBUS_FMT_YUYV8_2X8: | 121 | case V4L2_MBUS_FMT_YVYU8_2X8: |
134 | cr = ISI_CFG2_YCC_SWAP_MODE_1; | 122 | cr = ISI_CFG2_YCC_SWAP_MODE_1; |
135 | break; | 123 | break; |
136 | case V4L2_MBUS_FMT_YVYU8_2X8: | 124 | case V4L2_MBUS_FMT_YUYV8_2X8: |
137 | cr = ISI_CFG2_YCC_SWAP_DEFAULT; | 125 | cr = ISI_CFG2_YCC_SWAP_DEFAULT; |
138 | break; | 126 | break; |
139 | /* RGB, TODO */ | 127 | /* RGB, TODO */ |
@@ -144,6 +132,8 @@ static int configure_geometry(struct atmel_isi *isi, u32 width, | |||
144 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | 132 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); |
145 | 133 | ||
146 | cfg2 = isi_readl(isi, ISI_CFG2); | 134 | cfg2 = isi_readl(isi, ISI_CFG2); |
135 | /* Set YCC swap mode */ | ||
136 | cfg2 &= ~ISI_CFG2_YCC_SWAP_MODE_MASK; | ||
147 | cfg2 |= cr; | 137 | cfg2 |= cr; |
148 | /* Set width */ | 138 | /* Set width */ |
149 | cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK); | 139 | cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK); |
@@ -207,12 +197,6 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id) | |||
207 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); | 197 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); |
208 | ret = IRQ_HANDLED; | 198 | ret = IRQ_HANDLED; |
209 | } else { | 199 | } else { |
210 | if ((pending & ISI_SR_VSYNC) && | ||
211 | (isi->state == ISI_STATE_IDLE)) { | ||
212 | isi->state = ISI_STATE_READY; | ||
213 | wake_up_interruptible(&isi->vsync_wq); | ||
214 | ret = IRQ_HANDLED; | ||
215 | } | ||
216 | if (likely(pending & ISI_SR_CXFR_DONE)) | 200 | if (likely(pending & ISI_SR_CXFR_DONE)) |
217 | ret = atmel_isi_handle_streaming(isi); | 201 | ret = atmel_isi_handle_streaming(isi); |
218 | } | 202 | } |
@@ -259,16 +243,6 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, | |||
259 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 243 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
260 | struct atmel_isi *isi = ici->priv; | 244 | struct atmel_isi *isi = ici->priv; |
261 | unsigned long size; | 245 | unsigned long size; |
262 | int ret; | ||
263 | |||
264 | /* Reset ISI */ | ||
265 | ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); | ||
266 | if (ret < 0) { | ||
267 | dev_err(icd->parent, "Reset ISI timed out\n"); | ||
268 | return ret; | ||
269 | } | ||
270 | /* Disable all interrupts */ | ||
271 | isi_writel(isi, ISI_INTDIS, ~0UL); | ||
272 | 246 | ||
273 | size = icd->sizeimage; | 247 | size = icd->sizeimage; |
274 | 248 | ||
@@ -374,6 +348,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) | |||
374 | isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | 348 | isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); |
375 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); | 349 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); |
376 | 350 | ||
351 | cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK; | ||
377 | /* Enable linked list */ | 352 | /* Enable linked list */ |
378 | cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR; | 353 | cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR; |
379 | 354 | ||
@@ -407,43 +382,27 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) | |||
407 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | 382 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); |
408 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 383 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
409 | struct atmel_isi *isi = ici->priv; | 384 | struct atmel_isi *isi = ici->priv; |
410 | |||
411 | u32 sr = 0; | 385 | u32 sr = 0; |
412 | int ret; | 386 | int ret; |
413 | 387 | ||
414 | spin_lock_irq(&isi->lock); | 388 | /* Reset ISI */ |
415 | isi->state = ISI_STATE_IDLE; | 389 | ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); |
416 | /* Clear any pending SOF interrupt */ | 390 | if (ret < 0) { |
417 | sr = isi_readl(isi, ISI_STATUS); | 391 | dev_err(icd->parent, "Reset ISI timed out\n"); |
418 | /* Enable VSYNC interrupt for SOF */ | 392 | return ret; |
419 | isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC); | ||
420 | isi_writel(isi, ISI_CTRL, ISI_CTRL_EN); | ||
421 | spin_unlock_irq(&isi->lock); | ||
422 | |||
423 | dev_dbg(icd->parent, "Waiting for SOF\n"); | ||
424 | ret = wait_event_interruptible(isi->vsync_wq, | ||
425 | isi->state != ISI_STATE_IDLE); | ||
426 | if (ret) | ||
427 | goto err; | ||
428 | |||
429 | if (isi->state != ISI_STATE_READY) { | ||
430 | ret = -EIO; | ||
431 | goto err; | ||
432 | } | 393 | } |
394 | /* Disable all interrupts */ | ||
395 | isi_writel(isi, ISI_INTDIS, ~0UL); | ||
433 | 396 | ||
434 | spin_lock_irq(&isi->lock); | 397 | spin_lock_irq(&isi->lock); |
435 | isi->state = ISI_STATE_WAIT_SOF; | 398 | /* Clear any pending interrupt */ |
436 | isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC); | 399 | sr = isi_readl(isi, ISI_STATUS); |
400 | |||
437 | if (count) | 401 | if (count) |
438 | start_dma(isi, isi->active); | 402 | start_dma(isi, isi->active); |
439 | spin_unlock_irq(&isi->lock); | 403 | spin_unlock_irq(&isi->lock); |
440 | 404 | ||
441 | return 0; | 405 | return 0; |
442 | err: | ||
443 | isi->active = NULL; | ||
444 | isi->sequence = 0; | ||
445 | INIT_LIST_HEAD(&isi->video_buffer_list); | ||
446 | return ret; | ||
447 | } | 406 | } |
448 | 407 | ||
449 | /* abort streaming and wait for last buffer */ | 408 | /* abort streaming and wait for last buffer */ |
@@ -765,14 +724,16 @@ static int isi_camera_clock_start(struct soc_camera_host *ici) | |||
765 | struct atmel_isi *isi = ici->priv; | 724 | struct atmel_isi *isi = ici->priv; |
766 | int ret; | 725 | int ret; |
767 | 726 | ||
768 | ret = clk_enable(isi->pclk); | 727 | ret = clk_prepare_enable(isi->pclk); |
769 | if (ret) | 728 | if (ret) |
770 | return ret; | 729 | return ret; |
771 | 730 | ||
772 | ret = clk_enable(isi->mck); | 731 | if (!IS_ERR(isi->mck)) { |
773 | if (ret) { | 732 | ret = clk_prepare_enable(isi->mck); |
774 | clk_disable(isi->pclk); | 733 | if (ret) { |
775 | return ret; | 734 | clk_disable_unprepare(isi->pclk); |
735 | return ret; | ||
736 | } | ||
776 | } | 737 | } |
777 | 738 | ||
778 | return 0; | 739 | return 0; |
@@ -783,8 +744,9 @@ static void isi_camera_clock_stop(struct soc_camera_host *ici) | |||
783 | { | 744 | { |
784 | struct atmel_isi *isi = ici->priv; | 745 | struct atmel_isi *isi = ici->priv; |
785 | 746 | ||
786 | clk_disable(isi->mck); | 747 | if (!IS_ERR(isi->mck)) |
787 | clk_disable(isi->pclk); | 748 | clk_disable_unprepare(isi->mck); |
749 | clk_disable_unprepare(isi->pclk); | ||
788 | } | 750 | } |
789 | 751 | ||
790 | static unsigned int isi_camera_poll(struct file *file, poll_table *pt) | 752 | static unsigned int isi_camera_poll(struct file *file, poll_table *pt) |
@@ -906,7 +868,6 @@ static int atmel_isi_remove(struct platform_device *pdev) | |||
906 | struct atmel_isi *isi = container_of(soc_host, | 868 | struct atmel_isi *isi = container_of(soc_host, |
907 | struct atmel_isi, soc_host); | 869 | struct atmel_isi, soc_host); |
908 | 870 | ||
909 | free_irq(isi->irq, isi); | ||
910 | soc_camera_host_unregister(soc_host); | 871 | soc_camera_host_unregister(soc_host); |
911 | vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); | 872 | vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); |
912 | dma_free_coherent(&pdev->dev, | 873 | dma_free_coherent(&pdev->dev, |
@@ -914,13 +875,6 @@ static int atmel_isi_remove(struct platform_device *pdev) | |||
914 | isi->p_fb_descriptors, | 875 | isi->p_fb_descriptors, |
915 | isi->fb_descriptors_phys); | 876 | isi->fb_descriptors_phys); |
916 | 877 | ||
917 | iounmap(isi->regs); | ||
918 | clk_unprepare(isi->mck); | ||
919 | clk_put(isi->mck); | ||
920 | clk_unprepare(isi->pclk); | ||
921 | clk_put(isi->pclk); | ||
922 | kfree(isi); | ||
923 | |||
924 | return 0; | 878 | return 0; |
925 | } | 879 | } |
926 | 880 | ||
@@ -928,7 +882,6 @@ static int atmel_isi_probe(struct platform_device *pdev) | |||
928 | { | 882 | { |
929 | unsigned int irq; | 883 | unsigned int irq; |
930 | struct atmel_isi *isi; | 884 | struct atmel_isi *isi; |
931 | struct clk *pclk; | ||
932 | struct resource *regs; | 885 | struct resource *regs; |
933 | int ret, i; | 886 | int ret, i; |
934 | struct device *dev = &pdev->dev; | 887 | struct device *dev = &pdev->dev; |
@@ -936,64 +889,50 @@ static int atmel_isi_probe(struct platform_device *pdev) | |||
936 | struct isi_platform_data *pdata; | 889 | struct isi_platform_data *pdata; |
937 | 890 | ||
938 | pdata = dev->platform_data; | 891 | pdata = dev->platform_data; |
939 | if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) { | 892 | if (!pdata || !pdata->data_width_flags) { |
940 | dev_err(&pdev->dev, | 893 | dev_err(&pdev->dev, |
941 | "No config available for Atmel ISI\n"); | 894 | "No config available for Atmel ISI\n"); |
942 | return -EINVAL; | 895 | return -EINVAL; |
943 | } | 896 | } |
944 | 897 | ||
945 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 898 | isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL); |
946 | if (!regs) | ||
947 | return -ENXIO; | ||
948 | |||
949 | pclk = clk_get(&pdev->dev, "isi_clk"); | ||
950 | if (IS_ERR(pclk)) | ||
951 | return PTR_ERR(pclk); | ||
952 | |||
953 | ret = clk_prepare(pclk); | ||
954 | if (ret) | ||
955 | goto err_clk_prepare_pclk; | ||
956 | |||
957 | isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL); | ||
958 | if (!isi) { | 899 | if (!isi) { |
959 | ret = -ENOMEM; | ||
960 | dev_err(&pdev->dev, "Can't allocate interface!\n"); | 900 | dev_err(&pdev->dev, "Can't allocate interface!\n"); |
961 | goto err_alloc_isi; | 901 | return -ENOMEM; |
962 | } | 902 | } |
963 | 903 | ||
964 | isi->pclk = pclk; | 904 | isi->pclk = devm_clk_get(&pdev->dev, "isi_clk"); |
905 | if (IS_ERR(isi->pclk)) | ||
906 | return PTR_ERR(isi->pclk); | ||
907 | |||
965 | isi->pdata = pdata; | 908 | isi->pdata = pdata; |
966 | isi->active = NULL; | 909 | isi->active = NULL; |
967 | spin_lock_init(&isi->lock); | 910 | spin_lock_init(&isi->lock); |
968 | init_waitqueue_head(&isi->vsync_wq); | ||
969 | INIT_LIST_HEAD(&isi->video_buffer_list); | 911 | INIT_LIST_HEAD(&isi->video_buffer_list); |
970 | INIT_LIST_HEAD(&isi->dma_desc_head); | 912 | INIT_LIST_HEAD(&isi->dma_desc_head); |
971 | 913 | ||
972 | /* Get ISI_MCK, provided by programmable clock or external clock */ | 914 | /* ISI_MCK is the sensor master clock. It should be handled by the |
973 | isi->mck = clk_get(dev, "isi_mck"); | 915 | * sensor driver directly, as the ISI has no use for that clock. Make |
974 | if (IS_ERR(isi->mck)) { | 916 | * the clock optional here while platforms transition to the correct |
975 | dev_err(dev, "Failed to get isi_mck\n"); | 917 | * model. |
976 | ret = PTR_ERR(isi->mck); | 918 | */ |
977 | goto err_clk_get; | 919 | isi->mck = devm_clk_get(dev, "isi_mck"); |
920 | if (!IS_ERR(isi->mck)) { | ||
921 | /* Set ISI_MCK's frequency, it should be faster than pixel | ||
922 | * clock. | ||
923 | */ | ||
924 | ret = clk_set_rate(isi->mck, pdata->mck_hz); | ||
925 | if (ret < 0) | ||
926 | return ret; | ||
978 | } | 927 | } |
979 | 928 | ||
980 | ret = clk_prepare(isi->mck); | ||
981 | if (ret) | ||
982 | goto err_clk_prepare_mck; | ||
983 | |||
984 | /* Set ISI_MCK's frequency, it should be faster than pixel clock */ | ||
985 | ret = clk_set_rate(isi->mck, pdata->mck_hz); | ||
986 | if (ret < 0) | ||
987 | goto err_set_mck_rate; | ||
988 | |||
989 | isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, | 929 | isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, |
990 | sizeof(struct fbd) * MAX_BUFFER_NUM, | 930 | sizeof(struct fbd) * MAX_BUFFER_NUM, |
991 | &isi->fb_descriptors_phys, | 931 | &isi->fb_descriptors_phys, |
992 | GFP_KERNEL); | 932 | GFP_KERNEL); |
993 | if (!isi->p_fb_descriptors) { | 933 | if (!isi->p_fb_descriptors) { |
994 | ret = -ENOMEM; | ||
995 | dev_err(&pdev->dev, "Can't allocate descriptors!\n"); | 934 | dev_err(&pdev->dev, "Can't allocate descriptors!\n"); |
996 | goto err_alloc_descriptors; | 935 | return -ENOMEM; |
997 | } | 936 | } |
998 | 937 | ||
999 | for (i = 0; i < MAX_BUFFER_NUM; i++) { | 938 | for (i = 0; i < MAX_BUFFER_NUM; i++) { |
@@ -1009,9 +948,10 @@ static int atmel_isi_probe(struct platform_device *pdev) | |||
1009 | goto err_alloc_ctx; | 948 | goto err_alloc_ctx; |
1010 | } | 949 | } |
1011 | 950 | ||
1012 | isi->regs = ioremap(regs->start, resource_size(regs)); | 951 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1013 | if (!isi->regs) { | 952 | isi->regs = devm_ioremap_resource(&pdev->dev, regs); |
1014 | ret = -ENOMEM; | 953 | if (IS_ERR(isi->regs)) { |
954 | ret = PTR_ERR(isi->regs); | ||
1015 | goto err_ioremap; | 955 | goto err_ioremap; |
1016 | } | 956 | } |
1017 | 957 | ||
@@ -1028,7 +968,7 @@ static int atmel_isi_probe(struct platform_device *pdev) | |||
1028 | goto err_req_irq; | 968 | goto err_req_irq; |
1029 | } | 969 | } |
1030 | 970 | ||
1031 | ret = request_irq(irq, isi_interrupt, 0, "isi", isi); | 971 | ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi); |
1032 | if (ret) { | 972 | if (ret) { |
1033 | dev_err(&pdev->dev, "Unable to request irq %d\n", irq); | 973 | dev_err(&pdev->dev, "Unable to request irq %d\n", irq); |
1034 | goto err_req_irq; | 974 | goto err_req_irq; |
@@ -1050,9 +990,7 @@ static int atmel_isi_probe(struct platform_device *pdev) | |||
1050 | return 0; | 990 | return 0; |
1051 | 991 | ||
1052 | err_register_soc_camera_host: | 992 | err_register_soc_camera_host: |
1053 | free_irq(isi->irq, isi); | ||
1054 | err_req_irq: | 993 | err_req_irq: |
1055 | iounmap(isi->regs); | ||
1056 | err_ioremap: | 994 | err_ioremap: |
1057 | vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); | 995 | vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); |
1058 | err_alloc_ctx: | 996 | err_alloc_ctx: |
@@ -1060,17 +998,6 @@ err_alloc_ctx: | |||
1060 | sizeof(struct fbd) * MAX_BUFFER_NUM, | 998 | sizeof(struct fbd) * MAX_BUFFER_NUM, |
1061 | isi->p_fb_descriptors, | 999 | isi->p_fb_descriptors, |
1062 | isi->fb_descriptors_phys); | 1000 | isi->fb_descriptors_phys); |
1063 | err_alloc_descriptors: | ||
1064 | err_set_mck_rate: | ||
1065 | clk_unprepare(isi->mck); | ||
1066 | err_clk_prepare_mck: | ||
1067 | clk_put(isi->mck); | ||
1068 | err_clk_get: | ||
1069 | kfree(isi); | ||
1070 | err_alloc_isi: | ||
1071 | clk_unprepare(pclk); | ||
1072 | err_clk_prepare_pclk: | ||
1073 | clk_put(pclk); | ||
1074 | 1001 | ||
1075 | return ret; | 1002 | return ret; |
1076 | } | 1003 | } |
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 45a0276be4e5..d73abca9c6ee 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c | |||
@@ -659,7 +659,7 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) | |||
659 | unsigned long flags; | 659 | unsigned long flags; |
660 | 660 | ||
661 | if (count < 2) | 661 | if (count < 2) |
662 | return -EINVAL; | 662 | return -ENOBUFS; |
663 | 663 | ||
664 | spin_lock_irqsave(&pcdev->lock, flags); | 664 | spin_lock_irqsave(&pcdev->lock, flags); |
665 | 665 | ||
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 6866bb4fbebc..3b1c05a72d00 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c | |||
@@ -106,7 +106,7 @@ | |||
106 | #define VIN_MAX_HEIGHT 2048 | 106 | #define VIN_MAX_HEIGHT 2048 |
107 | 107 | ||
108 | enum chip_id { | 108 | enum chip_id { |
109 | RCAR_H2, | 109 | RCAR_GEN2, |
110 | RCAR_H1, | 110 | RCAR_H1, |
111 | RCAR_M1, | 111 | RCAR_M1, |
112 | RCAR_E1, | 112 | RCAR_E1, |
@@ -302,7 +302,7 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv) | |||
302 | dmr = 0; | 302 | dmr = 0; |
303 | break; | 303 | break; |
304 | case V4L2_PIX_FMT_RGB32: | 304 | case V4L2_PIX_FMT_RGB32: |
305 | if (priv->chip == RCAR_H2 || priv->chip == RCAR_H1 || | 305 | if (priv->chip == RCAR_GEN2 || priv->chip == RCAR_H1 || |
306 | priv->chip == RCAR_E1) { | 306 | priv->chip == RCAR_E1) { |
307 | dmr = VNDMR_EXRGB; | 307 | dmr = VNDMR_EXRGB; |
308 | break; | 308 | break; |
@@ -1384,7 +1384,8 @@ static struct soc_camera_host_ops rcar_vin_host_ops = { | |||
1384 | }; | 1384 | }; |
1385 | 1385 | ||
1386 | static struct platform_device_id rcar_vin_id_table[] = { | 1386 | static struct platform_device_id rcar_vin_id_table[] = { |
1387 | { "r8a7790-vin", RCAR_H2 }, | 1387 | { "r8a7791-vin", RCAR_GEN2 }, |
1388 | { "r8a7790-vin", RCAR_GEN2 }, | ||
1388 | { "r8a7779-vin", RCAR_H1 }, | 1389 | { "r8a7779-vin", RCAR_H1 }, |
1389 | { "r8a7778-vin", RCAR_M1 }, | 1390 | { "r8a7778-vin", RCAR_M1 }, |
1390 | { "uPD35004-vin", RCAR_E1 }, | 1391 | { "uPD35004-vin", RCAR_E1 }, |
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c index cbd3a34f4f3f..8e74fb7f2a07 100644 --- a/drivers/media/platform/soc_camera/soc_scale_crop.c +++ b/drivers/media/platform/soc_camera/soc_scale_crop.c | |||
@@ -141,8 +141,8 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd, | |||
141 | * Popular special case - some cameras can only handle fixed sizes like | 141 | * Popular special case - some cameras can only handle fixed sizes like |
142 | * QVGA, VGA,... Take care to avoid infinite loop. | 142 | * QVGA, VGA,... Take care to avoid infinite loop. |
143 | */ | 143 | */ |
144 | width = max(cam_rect->width, 2); | 144 | width = max_t(unsigned int, cam_rect->width, 2); |
145 | height = max(cam_rect->height, 2); | 145 | height = max_t(unsigned int, cam_rect->height, 2); |
146 | 146 | ||
147 | /* | 147 | /* |
148 | * Loop as long as sensor is not covering the requested rectangle and | 148 | * Loop as long as sensor is not covering the requested rectangle and |
diff --git a/drivers/media/platform/ti-vpe/Makefile b/drivers/media/platform/ti-vpe/Makefile index cbf0a806ba1d..be680f839e77 100644 --- a/drivers/media/platform/ti-vpe/Makefile +++ b/drivers/media/platform/ti-vpe/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o | 1 | obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o |
2 | 2 | ||
3 | ti-vpe-y := vpe.o vpdma.o | 3 | ti-vpe-y := vpe.o sc.o csc.o vpdma.o |
4 | 4 | ||
5 | ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG | 5 | ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG |
diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c new file mode 100644 index 000000000000..acfea500710e --- /dev/null +++ b/drivers/media/platform/ti-vpe/csc.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Color space converter library | ||
3 | * | ||
4 | * Copyright (c) 2013 Texas Instruments Inc. | ||
5 | * | ||
6 | * David Griego, <dagriego@biglakesoftware.com> | ||
7 | * Dale Farnsworth, <dale@farnsworth.org> | ||
8 | * Archit Taneja, <archit@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/err.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/videodev2.h> | ||
20 | |||
21 | #include "csc.h" | ||
22 | |||
23 | /* | ||
24 | * 16 coefficients in the order: | ||
25 | * a0, b0, c0, a1, b1, c1, a2, b2, c2, d0, d1, d2 | ||
26 | * (we may need to pass non-default values from user space later on, we might | ||
27 | * need to make the coefficient struct more easy to populate) | ||
28 | */ | ||
29 | struct colorspace_coeffs { | ||
30 | u16 sd[12]; | ||
31 | u16 hd[12]; | ||
32 | }; | ||
33 | |||
34 | /* VIDEO_RANGE: limited range, GRAPHICS_RANGE: full range */ | ||
35 | #define CSC_COEFFS_VIDEO_RANGE_Y2R 0 | ||
36 | #define CSC_COEFFS_GRAPHICS_RANGE_Y2R 1 | ||
37 | #define CSC_COEFFS_VIDEO_RANGE_R2Y 2 | ||
38 | #define CSC_COEFFS_GRAPHICS_RANGE_R2Y 3 | ||
39 | |||
40 | /* default colorspace coefficients */ | ||
41 | static struct colorspace_coeffs colorspace_coeffs[4] = { | ||
42 | [CSC_COEFFS_VIDEO_RANGE_Y2R] = { | ||
43 | { | ||
44 | /* SDTV */ | ||
45 | 0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35, | ||
46 | 0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88, | ||
47 | }, | ||
48 | { | ||
49 | /* HDTV */ | ||
50 | 0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B, | ||
51 | 0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60, | ||
52 | }, | ||
53 | }, | ||
54 | [CSC_COEFFS_GRAPHICS_RANGE_Y2R] = { | ||
55 | { | ||
56 | /* SDTV */ | ||
57 | 0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF, | ||
58 | 0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC, | ||
59 | }, | ||
60 | { | ||
61 | /* HDTV */ | ||
62 | 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE, | ||
63 | 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C, | ||
64 | }, | ||
65 | }, | ||
66 | [CSC_COEFFS_VIDEO_RANGE_R2Y] = { | ||
67 | { | ||
68 | /* SDTV */ | ||
69 | 0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B, | ||
70 | 0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200, | ||
71 | }, | ||
72 | { | ||
73 | /* HDTV */ | ||
74 | 0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C, | ||
75 | 0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200, | ||
76 | }, | ||
77 | }, | ||
78 | [CSC_COEFFS_GRAPHICS_RANGE_R2Y] = { | ||
79 | { | ||
80 | /* SDTV */ | ||
81 | 0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2, | ||
82 | 0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200, | ||
83 | }, | ||
84 | { | ||
85 | /* HDTV */ | ||
86 | 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE, | ||
87 | 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C, | ||
88 | }, | ||
89 | }, | ||
90 | }; | ||
91 | |||
92 | void csc_dump_regs(struct csc_data *csc) | ||
93 | { | ||
94 | struct device *dev = &csc->pdev->dev; | ||
95 | |||
96 | u32 read_reg(struct csc_data *csc, int offset) | ||
97 | { | ||
98 | return ioread32(csc->base + offset); | ||
99 | } | ||
100 | |||
101 | #define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(csc, CSC_##r)) | ||
102 | |||
103 | DUMPREG(CSC00); | ||
104 | DUMPREG(CSC01); | ||
105 | DUMPREG(CSC02); | ||
106 | DUMPREG(CSC03); | ||
107 | DUMPREG(CSC04); | ||
108 | DUMPREG(CSC05); | ||
109 | |||
110 | #undef DUMPREG | ||
111 | } | ||
112 | |||
113 | void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5) | ||
114 | { | ||
115 | *csc_reg5 |= CSC_BYPASS; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * set the color space converter coefficient shadow register values | ||
120 | */ | ||
121 | void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, | ||
122 | enum v4l2_colorspace src_colorspace, | ||
123 | enum v4l2_colorspace dst_colorspace) | ||
124 | { | ||
125 | u32 *csc_reg5 = csc_reg0 + 5; | ||
126 | u32 *shadow_csc = csc_reg0; | ||
127 | struct colorspace_coeffs *sd_hd_coeffs; | ||
128 | u16 *coeff, *end_coeff; | ||
129 | enum v4l2_colorspace yuv_colorspace; | ||
130 | int sel = 0; | ||
131 | |||
132 | /* | ||
133 | * support only graphics data range(full range) for now, a control ioctl | ||
134 | * would be nice here | ||
135 | */ | ||
136 | /* Y2R */ | ||
137 | if (dst_colorspace == V4L2_COLORSPACE_SRGB && | ||
138 | (src_colorspace == V4L2_COLORSPACE_SMPTE170M || | ||
139 | src_colorspace == V4L2_COLORSPACE_REC709)) { | ||
140 | /* Y2R */ | ||
141 | sel = 1; | ||
142 | yuv_colorspace = src_colorspace; | ||
143 | } else if ((dst_colorspace == V4L2_COLORSPACE_SMPTE170M || | ||
144 | dst_colorspace == V4L2_COLORSPACE_REC709) && | ||
145 | src_colorspace == V4L2_COLORSPACE_SRGB) { | ||
146 | /* R2Y */ | ||
147 | sel = 3; | ||
148 | yuv_colorspace = dst_colorspace; | ||
149 | } else { | ||
150 | *csc_reg5 |= CSC_BYPASS; | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | sd_hd_coeffs = &colorspace_coeffs[sel]; | ||
155 | |||
156 | /* select between SD or HD coefficients */ | ||
157 | if (yuv_colorspace == V4L2_COLORSPACE_SMPTE170M) | ||
158 | coeff = sd_hd_coeffs->sd; | ||
159 | else | ||
160 | coeff = sd_hd_coeffs->hd; | ||
161 | |||
162 | end_coeff = coeff + 12; | ||
163 | |||
164 | for (; coeff < end_coeff; coeff += 2) | ||
165 | *shadow_csc++ = (*(coeff + 1) << 16) | *coeff; | ||
166 | } | ||
167 | |||
168 | struct csc_data *csc_create(struct platform_device *pdev) | ||
169 | { | ||
170 | struct csc_data *csc; | ||
171 | |||
172 | dev_dbg(&pdev->dev, "csc_create\n"); | ||
173 | |||
174 | csc = devm_kzalloc(&pdev->dev, sizeof(*csc), GFP_KERNEL); | ||
175 | if (!csc) { | ||
176 | dev_err(&pdev->dev, "couldn't alloc csc_data\n"); | ||
177 | return ERR_PTR(-ENOMEM); | ||
178 | } | ||
179 | |||
180 | csc->pdev = pdev; | ||
181 | |||
182 | csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
183 | "vpe_csc"); | ||
184 | if (csc->res == NULL) { | ||
185 | dev_err(&pdev->dev, "missing platform resources data\n"); | ||
186 | return ERR_PTR(-ENODEV); | ||
187 | } | ||
188 | |||
189 | csc->base = devm_ioremap_resource(&pdev->dev, csc->res); | ||
190 | if (!csc->base) { | ||
191 | dev_err(&pdev->dev, "failed to ioremap\n"); | ||
192 | return ERR_PTR(-ENOMEM); | ||
193 | } | ||
194 | |||
195 | return csc; | ||
196 | } | ||
diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h new file mode 100644 index 000000000000..1ad2b6dad561 --- /dev/null +++ b/drivers/media/platform/ti-vpe/csc.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Texas Instruments Inc. | ||
3 | * | ||
4 | * David Griego, <dagriego@biglakesoftware.com> | ||
5 | * Dale Farnsworth, <dale@farnsworth.org> | ||
6 | * Archit Taneja, <archit@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef TI_CSC_H | ||
13 | #define TI_CSC_H | ||
14 | |||
15 | /* VPE color space converter regs */ | ||
16 | #define CSC_CSC00 0x00 | ||
17 | #define CSC_A0_MASK 0x1fff | ||
18 | #define CSC_A0_SHIFT 0 | ||
19 | #define CSC_B0_MASK 0x1fff | ||
20 | #define CSC_B0_SHIFT 16 | ||
21 | |||
22 | #define CSC_CSC01 0x04 | ||
23 | #define CSC_C0_MASK 0x1fff | ||
24 | #define CSC_C0_SHIFT 0 | ||
25 | #define CSC_A1_MASK 0x1fff | ||
26 | #define CSC_A1_SHIFT 16 | ||
27 | |||
28 | #define CSC_CSC02 0x08 | ||
29 | #define CSC_B1_MASK 0x1fff | ||
30 | #define CSC_B1_SHIFT 0 | ||
31 | #define CSC_C1_MASK 0x1fff | ||
32 | #define CSC_C1_SHIFT 16 | ||
33 | |||
34 | #define CSC_CSC03 0x0c | ||
35 | #define CSC_A2_MASK 0x1fff | ||
36 | #define CSC_A2_SHIFT 0 | ||
37 | #define CSC_B2_MASK 0x1fff | ||
38 | #define CSC_B2_SHIFT 16 | ||
39 | |||
40 | #define CSC_CSC04 0x10 | ||
41 | #define CSC_C2_MASK 0x1fff | ||
42 | #define CSC_C2_SHIFT 0 | ||
43 | #define CSC_D0_MASK 0x0fff | ||
44 | #define CSC_D0_SHIFT 16 | ||
45 | |||
46 | #define CSC_CSC05 0x14 | ||
47 | #define CSC_D1_MASK 0x0fff | ||
48 | #define CSC_D1_SHIFT 0 | ||
49 | #define CSC_D2_MASK 0x0fff | ||
50 | #define CSC_D2_SHIFT 16 | ||
51 | |||
52 | #define CSC_BYPASS (1 << 28) | ||
53 | |||
54 | struct csc_data { | ||
55 | void __iomem *base; | ||
56 | struct resource *res; | ||
57 | |||
58 | struct platform_device *pdev; | ||
59 | }; | ||
60 | |||
61 | void csc_dump_regs(struct csc_data *csc); | ||
62 | void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5); | ||
63 | void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, | ||
64 | enum v4l2_colorspace src_colorspace, | ||
65 | enum v4l2_colorspace dst_colorspace); | ||
66 | struct csc_data *csc_create(struct platform_device *pdev); | ||
67 | |||
68 | #endif | ||
diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c new file mode 100644 index 000000000000..93f0af546b76 --- /dev/null +++ b/drivers/media/platform/ti-vpe/sc.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * Scaler library | ||
3 | * | ||
4 | * Copyright (c) 2013 Texas Instruments Inc. | ||
5 | * | ||
6 | * David Griego, <dagriego@biglakesoftware.com> | ||
7 | * Dale Farnsworth, <dale@farnsworth.org> | ||
8 | * Archit Taneja, <archit@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/err.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | |||
20 | #include "sc.h" | ||
21 | #include "sc_coeff.h" | ||
22 | |||
23 | void sc_dump_regs(struct sc_data *sc) | ||
24 | { | ||
25 | struct device *dev = &sc->pdev->dev; | ||
26 | |||
27 | u32 read_reg(struct sc_data *sc, int offset) | ||
28 | { | ||
29 | return ioread32(sc->base + offset); | ||
30 | } | ||
31 | |||
32 | #define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(sc, CFG_##r)) | ||
33 | |||
34 | DUMPREG(SC0); | ||
35 | DUMPREG(SC1); | ||
36 | DUMPREG(SC2); | ||
37 | DUMPREG(SC3); | ||
38 | DUMPREG(SC4); | ||
39 | DUMPREG(SC5); | ||
40 | DUMPREG(SC6); | ||
41 | DUMPREG(SC8); | ||
42 | DUMPREG(SC9); | ||
43 | DUMPREG(SC10); | ||
44 | DUMPREG(SC11); | ||
45 | DUMPREG(SC12); | ||
46 | DUMPREG(SC13); | ||
47 | DUMPREG(SC17); | ||
48 | DUMPREG(SC18); | ||
49 | DUMPREG(SC19); | ||
50 | DUMPREG(SC20); | ||
51 | DUMPREG(SC21); | ||
52 | DUMPREG(SC22); | ||
53 | DUMPREG(SC23); | ||
54 | DUMPREG(SC24); | ||
55 | DUMPREG(SC25); | ||
56 | |||
57 | #undef DUMPREG | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * set the horizontal scaler coefficients according to the ratio of output to | ||
62 | * input widths, after accounting for up to two levels of decimation | ||
63 | */ | ||
64 | void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, | ||
65 | unsigned int dst_w) | ||
66 | { | ||
67 | int sixteenths; | ||
68 | int idx; | ||
69 | int i, j; | ||
70 | u16 *coeff_h = addr; | ||
71 | const u16 *cp; | ||
72 | |||
73 | if (dst_w > src_w) { | ||
74 | idx = HS_UP_SCALE; | ||
75 | } else { | ||
76 | if ((dst_w << 1) < src_w) | ||
77 | dst_w <<= 1; /* first level decimation */ | ||
78 | if ((dst_w << 1) < src_w) | ||
79 | dst_w <<= 1; /* second level decimation */ | ||
80 | |||
81 | if (dst_w == src_w) { | ||
82 | idx = HS_LE_16_16_SCALE; | ||
83 | } else { | ||
84 | sixteenths = (dst_w << 4) / src_w; | ||
85 | if (sixteenths < 8) | ||
86 | sixteenths = 8; | ||
87 | idx = HS_LT_9_16_SCALE + sixteenths - 8; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | if (idx == sc->hs_index) | ||
92 | return; | ||
93 | |||
94 | cp = scaler_hs_coeffs[idx]; | ||
95 | |||
96 | for (i = 0; i < SC_NUM_PHASES * 2; i++) { | ||
97 | for (j = 0; j < SC_H_NUM_TAPS; j++) | ||
98 | *coeff_h++ = *cp++; | ||
99 | /* | ||
100 | * for each phase, the scaler expects space for 8 coefficients | ||
101 | * in it's memory. For the horizontal scaler, we copy the first | ||
102 | * 7 coefficients and skip the last slot to move to the next | ||
103 | * row to hold coefficients for the next phase | ||
104 | */ | ||
105 | coeff_h += SC_NUM_TAPS_MEM_ALIGN - SC_H_NUM_TAPS; | ||
106 | } | ||
107 | |||
108 | sc->hs_index = idx; | ||
109 | |||
110 | sc->load_coeff_h = true; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * set the vertical scaler coefficients according to the ratio of output to | ||
115 | * input heights | ||
116 | */ | ||
117 | void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, | ||
118 | unsigned int dst_h) | ||
119 | { | ||
120 | int sixteenths; | ||
121 | int idx; | ||
122 | int i, j; | ||
123 | u16 *coeff_v = addr; | ||
124 | const u16 *cp; | ||
125 | |||
126 | if (dst_h > src_h) { | ||
127 | idx = VS_UP_SCALE; | ||
128 | } else if (dst_h == src_h) { | ||
129 | idx = VS_1_TO_1_SCALE; | ||
130 | } else { | ||
131 | sixteenths = (dst_h << 4) / src_h; | ||
132 | if (sixteenths < 8) | ||
133 | sixteenths = 8; | ||
134 | idx = VS_LT_9_16_SCALE + sixteenths - 8; | ||
135 | } | ||
136 | |||
137 | if (idx == sc->vs_index) | ||
138 | return; | ||
139 | |||
140 | cp = scaler_vs_coeffs[idx]; | ||
141 | |||
142 | for (i = 0; i < SC_NUM_PHASES * 2; i++) { | ||
143 | for (j = 0; j < SC_V_NUM_TAPS; j++) | ||
144 | *coeff_v++ = *cp++; | ||
145 | /* | ||
146 | * for the vertical scaler, we copy the first 5 coefficients and | ||
147 | * skip the last 3 slots to move to the next row to hold | ||
148 | * coefficients for the next phase | ||
149 | */ | ||
150 | coeff_v += SC_NUM_TAPS_MEM_ALIGN - SC_V_NUM_TAPS; | ||
151 | } | ||
152 | |||
153 | sc->vs_index = idx; | ||
154 | sc->load_coeff_v = true; | ||
155 | } | ||
156 | |||
157 | void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, | ||
158 | u32 *sc_reg17, unsigned int src_w, unsigned int src_h, | ||
159 | unsigned int dst_w, unsigned int dst_h) | ||
160 | { | ||
161 | struct device *dev = &sc->pdev->dev; | ||
162 | u32 val; | ||
163 | int dcm_x, dcm_shift; | ||
164 | bool use_rav; | ||
165 | unsigned long lltmp; | ||
166 | u32 lin_acc_inc, lin_acc_inc_u; | ||
167 | u32 col_acc_offset; | ||
168 | u16 factor = 0; | ||
169 | int row_acc_init_rav = 0, row_acc_init_rav_b = 0; | ||
170 | u32 row_acc_inc = 0, row_acc_offset = 0, row_acc_offset_b = 0; | ||
171 | /* | ||
172 | * location of SC register in payload memory with respect to the first | ||
173 | * register in the mmr address data block | ||
174 | */ | ||
175 | u32 *sc_reg9 = sc_reg8 + 1; | ||
176 | u32 *sc_reg12 = sc_reg8 + 4; | ||
177 | u32 *sc_reg13 = sc_reg8 + 5; | ||
178 | u32 *sc_reg24 = sc_reg17 + 7; | ||
179 | |||
180 | val = sc_reg0[0]; | ||
181 | |||
182 | /* clear all the features(they may get enabled elsewhere later) */ | ||
183 | val &= ~(CFG_SELFGEN_FID | CFG_TRIM | CFG_ENABLE_SIN2_VER_INTP | | ||
184 | CFG_INTERLACE_I | CFG_DCM_4X | CFG_DCM_2X | CFG_AUTO_HS | | ||
185 | CFG_ENABLE_EV | CFG_USE_RAV | CFG_INVT_FID | CFG_SC_BYPASS | | ||
186 | CFG_INTERLACE_O | CFG_Y_PK_EN | CFG_HP_BYPASS | CFG_LINEAR); | ||
187 | |||
188 | if (src_w == dst_w && src_h == dst_h) { | ||
189 | val |= CFG_SC_BYPASS; | ||
190 | sc_reg0[0] = val; | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | /* we only support linear scaling for now */ | ||
195 | val |= CFG_LINEAR; | ||
196 | |||
197 | /* configure horizontal scaler */ | ||
198 | |||
199 | /* enable 2X or 4X decimation */ | ||
200 | dcm_x = src_w / dst_w; | ||
201 | if (dcm_x > 4) { | ||
202 | val |= CFG_DCM_4X; | ||
203 | dcm_shift = 2; | ||
204 | } else if (dcm_x > 2) { | ||
205 | val |= CFG_DCM_2X; | ||
206 | dcm_shift = 1; | ||
207 | } else { | ||
208 | dcm_shift = 0; | ||
209 | } | ||
210 | |||
211 | lltmp = dst_w - 1; | ||
212 | lin_acc_inc = div64_u64(((u64)(src_w >> dcm_shift) - 1) << 24, lltmp); | ||
213 | lin_acc_inc_u = 0; | ||
214 | col_acc_offset = 0; | ||
215 | |||
216 | dev_dbg(dev, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n", | ||
217 | src_w, dst_w, dcm_shift == 2 ? "4x" : | ||
218 | (dcm_shift == 1 ? "2x" : "none"), lin_acc_inc); | ||
219 | |||
220 | /* configure vertical scaler */ | ||
221 | |||
222 | /* use RAV for vertical scaler if vertical downscaling is > 4x */ | ||
223 | if (dst_h < (src_h >> 2)) { | ||
224 | use_rav = true; | ||
225 | val |= CFG_USE_RAV; | ||
226 | } else { | ||
227 | use_rav = false; | ||
228 | } | ||
229 | |||
230 | if (use_rav) { | ||
231 | /* use RAV */ | ||
232 | factor = (u16) ((dst_h << 10) / src_h); | ||
233 | |||
234 | row_acc_init_rav = factor + ((1 + factor) >> 1); | ||
235 | if (row_acc_init_rav >= 1024) | ||
236 | row_acc_init_rav -= 1024; | ||
237 | |||
238 | row_acc_init_rav_b = row_acc_init_rav + | ||
239 | (1 + (row_acc_init_rav >> 1)) - | ||
240 | (1024 >> 1); | ||
241 | |||
242 | if (row_acc_init_rav_b < 0) { | ||
243 | row_acc_init_rav_b += row_acc_init_rav; | ||
244 | row_acc_init_rav *= 2; | ||
245 | } | ||
246 | |||
247 | dev_dbg(dev, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n", | ||
248 | src_h, dst_h, factor, row_acc_init_rav, | ||
249 | row_acc_init_rav_b); | ||
250 | } else { | ||
251 | /* use polyphase */ | ||
252 | row_acc_inc = ((src_h - 1) << 16) / (dst_h - 1); | ||
253 | row_acc_offset = 0; | ||
254 | row_acc_offset_b = 0; | ||
255 | |||
256 | dev_dbg(dev, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n", | ||
257 | src_h, dst_h, row_acc_inc); | ||
258 | } | ||
259 | |||
260 | |||
261 | sc_reg0[0] = val; | ||
262 | sc_reg0[1] = row_acc_inc; | ||
263 | sc_reg0[2] = row_acc_offset; | ||
264 | sc_reg0[3] = row_acc_offset_b; | ||
265 | |||
266 | sc_reg0[4] = ((lin_acc_inc_u & CFG_LIN_ACC_INC_U_MASK) << | ||
267 | CFG_LIN_ACC_INC_U_SHIFT) | (dst_w << CFG_TAR_W_SHIFT) | | ||
268 | (dst_h << CFG_TAR_H_SHIFT); | ||
269 | |||
270 | sc_reg0[5] = (src_w << CFG_SRC_W_SHIFT) | (src_h << CFG_SRC_H_SHIFT); | ||
271 | |||
272 | sc_reg0[6] = (row_acc_init_rav_b << CFG_ROW_ACC_INIT_RAV_B_SHIFT) | | ||
273 | (row_acc_init_rav << CFG_ROW_ACC_INIT_RAV_SHIFT); | ||
274 | |||
275 | *sc_reg9 = lin_acc_inc; | ||
276 | |||
277 | *sc_reg12 = col_acc_offset << CFG_COL_ACC_OFFSET_SHIFT; | ||
278 | |||
279 | *sc_reg13 = factor; | ||
280 | |||
281 | *sc_reg24 = (src_w << CFG_ORG_W_SHIFT) | (src_h << CFG_ORG_H_SHIFT); | ||
282 | } | ||
283 | |||
284 | struct sc_data *sc_create(struct platform_device *pdev) | ||
285 | { | ||
286 | struct sc_data *sc; | ||
287 | |||
288 | dev_dbg(&pdev->dev, "sc_create\n"); | ||
289 | |||
290 | sc = devm_kzalloc(&pdev->dev, sizeof(*sc), GFP_KERNEL); | ||
291 | if (!sc) { | ||
292 | dev_err(&pdev->dev, "couldn't alloc sc_data\n"); | ||
293 | return ERR_PTR(-ENOMEM); | ||
294 | } | ||
295 | |||
296 | sc->pdev = pdev; | ||
297 | |||
298 | sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sc"); | ||
299 | if (!sc->res) { | ||
300 | dev_err(&pdev->dev, "missing platform resources data\n"); | ||
301 | return ERR_PTR(-ENODEV); | ||
302 | } | ||
303 | |||
304 | sc->base = devm_ioremap_resource(&pdev->dev, sc->res); | ||
305 | if (!sc->base) { | ||
306 | dev_err(&pdev->dev, "failed to ioremap\n"); | ||
307 | return ERR_PTR(-ENOMEM); | ||
308 | } | ||
309 | |||
310 | return sc; | ||
311 | } | ||
diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h new file mode 100644 index 000000000000..60e411e05c30 --- /dev/null +++ b/drivers/media/platform/ti-vpe/sc.h | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Texas Instruments Inc. | ||
3 | * | ||
4 | * David Griego, <dagriego@biglakesoftware.com> | ||
5 | * Dale Farnsworth, <dale@farnsworth.org> | ||
6 | * Archit Taneja, <archit@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef TI_SC_H | ||
13 | #define TI_SC_H | ||
14 | |||
15 | /* Scaler regs */ | ||
16 | #define CFG_SC0 0x0 | ||
17 | #define CFG_INTERLACE_O (1 << 0) | ||
18 | #define CFG_LINEAR (1 << 1) | ||
19 | #define CFG_SC_BYPASS (1 << 2) | ||
20 | #define CFG_INVT_FID (1 << 3) | ||
21 | #define CFG_USE_RAV (1 << 4) | ||
22 | #define CFG_ENABLE_EV (1 << 5) | ||
23 | #define CFG_AUTO_HS (1 << 6) | ||
24 | #define CFG_DCM_2X (1 << 7) | ||
25 | #define CFG_DCM_4X (1 << 8) | ||
26 | #define CFG_HP_BYPASS (1 << 9) | ||
27 | #define CFG_INTERLACE_I (1 << 10) | ||
28 | #define CFG_ENABLE_SIN2_VER_INTP (1 << 11) | ||
29 | #define CFG_Y_PK_EN (1 << 14) | ||
30 | #define CFG_TRIM (1 << 15) | ||
31 | #define CFG_SELFGEN_FID (1 << 16) | ||
32 | |||
33 | #define CFG_SC1 0x4 | ||
34 | #define CFG_ROW_ACC_INC_MASK 0x07ffffff | ||
35 | #define CFG_ROW_ACC_INC_SHIFT 0 | ||
36 | |||
37 | #define CFG_SC2 0x08 | ||
38 | #define CFG_ROW_ACC_OFFSET_MASK 0x0fffffff | ||
39 | #define CFG_ROW_ACC_OFFSET_SHIFT 0 | ||
40 | |||
41 | #define CFG_SC3 0x0c | ||
42 | #define CFG_ROW_ACC_OFFSET_B_MASK 0x0fffffff | ||
43 | #define CFG_ROW_ACC_OFFSET_B_SHIFT 0 | ||
44 | |||
45 | #define CFG_SC4 0x10 | ||
46 | #define CFG_TAR_H_MASK 0x07ff | ||
47 | #define CFG_TAR_H_SHIFT 0 | ||
48 | #define CFG_TAR_W_MASK 0x07ff | ||
49 | #define CFG_TAR_W_SHIFT 12 | ||
50 | #define CFG_LIN_ACC_INC_U_MASK 0x07 | ||
51 | #define CFG_LIN_ACC_INC_U_SHIFT 24 | ||
52 | #define CFG_NLIN_ACC_INIT_U_MASK 0x07 | ||
53 | #define CFG_NLIN_ACC_INIT_U_SHIFT 28 | ||
54 | |||
55 | #define CFG_SC5 0x14 | ||
56 | #define CFG_SRC_H_MASK 0x07ff | ||
57 | #define CFG_SRC_H_SHIFT 0 | ||
58 | #define CFG_SRC_W_MASK 0x07ff | ||
59 | #define CFG_SRC_W_SHIFT 12 | ||
60 | #define CFG_NLIN_ACC_INC_U_MASK 0x07 | ||
61 | #define CFG_NLIN_ACC_INC_U_SHIFT 24 | ||
62 | |||
63 | #define CFG_SC6 0x18 | ||
64 | #define CFG_ROW_ACC_INIT_RAV_MASK 0x03ff | ||
65 | #define CFG_ROW_ACC_INIT_RAV_SHIFT 0 | ||
66 | #define CFG_ROW_ACC_INIT_RAV_B_MASK 0x03ff | ||
67 | #define CFG_ROW_ACC_INIT_RAV_B_SHIFT 10 | ||
68 | |||
69 | #define CFG_SC8 0x20 | ||
70 | #define CFG_NLIN_LEFT_MASK 0x07ff | ||
71 | #define CFG_NLIN_LEFT_SHIFT 0 | ||
72 | #define CFG_NLIN_RIGHT_MASK 0x07ff | ||
73 | #define CFG_NLIN_RIGHT_SHIFT 12 | ||
74 | |||
75 | #define CFG_SC9 0x24 | ||
76 | #define CFG_LIN_ACC_INC CFG_SC9 | ||
77 | |||
78 | #define CFG_SC10 0x28 | ||
79 | #define CFG_NLIN_ACC_INIT CFG_SC10 | ||
80 | |||
81 | #define CFG_SC11 0x2c | ||
82 | #define CFG_NLIN_ACC_INC CFG_SC11 | ||
83 | |||
84 | #define CFG_SC12 0x30 | ||
85 | #define CFG_COL_ACC_OFFSET_MASK 0x01ffffff | ||
86 | #define CFG_COL_ACC_OFFSET_SHIFT 0 | ||
87 | |||
88 | #define CFG_SC13 0x34 | ||
89 | #define CFG_SC_FACTOR_RAV_MASK 0xff | ||
90 | #define CFG_SC_FACTOR_RAV_SHIFT 0 | ||
91 | #define CFG_CHROMA_INTP_THR_MASK 0x03ff | ||
92 | #define CFG_CHROMA_INTP_THR_SHIFT 12 | ||
93 | #define CFG_DELTA_CHROMA_THR_MASK 0x0f | ||
94 | #define CFG_DELTA_CHROMA_THR_SHIFT 24 | ||
95 | |||
96 | #define CFG_SC17 0x44 | ||
97 | #define CFG_EV_THR_MASK 0x03ff | ||
98 | #define CFG_EV_THR_SHIFT 12 | ||
99 | #define CFG_DELTA_LUMA_THR_MASK 0x0f | ||
100 | #define CFG_DELTA_LUMA_THR_SHIFT 24 | ||
101 | #define CFG_DELTA_EV_THR_MASK 0x0f | ||
102 | #define CFG_DELTA_EV_THR_SHIFT 28 | ||
103 | |||
104 | #define CFG_SC18 0x48 | ||
105 | #define CFG_HS_FACTOR_MASK 0x03ff | ||
106 | #define CFG_HS_FACTOR_SHIFT 0 | ||
107 | #define CFG_CONF_DEFAULT_MASK 0x01ff | ||
108 | #define CFG_CONF_DEFAULT_SHIFT 16 | ||
109 | |||
110 | #define CFG_SC19 0x4c | ||
111 | #define CFG_HPF_COEFF0_MASK 0xff | ||
112 | #define CFG_HPF_COEFF0_SHIFT 0 | ||
113 | #define CFG_HPF_COEFF1_MASK 0xff | ||
114 | #define CFG_HPF_COEFF1_SHIFT 8 | ||
115 | #define CFG_HPF_COEFF2_MASK 0xff | ||
116 | #define CFG_HPF_COEFF2_SHIFT 16 | ||
117 | #define CFG_HPF_COEFF3_MASK 0xff | ||
118 | #define CFG_HPF_COEFF3_SHIFT 23 | ||
119 | |||
120 | #define CFG_SC20 0x50 | ||
121 | #define CFG_HPF_COEFF4_MASK 0xff | ||
122 | #define CFG_HPF_COEFF4_SHIFT 0 | ||
123 | #define CFG_HPF_COEFF5_MASK 0xff | ||
124 | #define CFG_HPF_COEFF5_SHIFT 8 | ||
125 | #define CFG_HPF_NORM_SHIFT_MASK 0x07 | ||
126 | #define CFG_HPF_NORM_SHIFT_SHIFT 16 | ||
127 | #define CFG_NL_LIMIT_MASK 0x1ff | ||
128 | #define CFG_NL_LIMIT_SHIFT 20 | ||
129 | |||
130 | #define CFG_SC21 0x54 | ||
131 | #define CFG_NL_LO_THR_MASK 0x01ff | ||
132 | #define CFG_NL_LO_THR_SHIFT 0 | ||
133 | #define CFG_NL_LO_SLOPE_MASK 0xff | ||
134 | #define CFG_NL_LO_SLOPE_SHIFT 16 | ||
135 | |||
136 | #define CFG_SC22 0x58 | ||
137 | #define CFG_NL_HI_THR_MASK 0x01ff | ||
138 | #define CFG_NL_HI_THR_SHIFT 0 | ||
139 | #define CFG_NL_HI_SLOPE_SH_MASK 0x07 | ||
140 | #define CFG_NL_HI_SLOPE_SH_SHIFT 16 | ||
141 | |||
142 | #define CFG_SC23 0x5c | ||
143 | #define CFG_GRADIENT_THR_MASK 0x07ff | ||
144 | #define CFG_GRADIENT_THR_SHIFT 0 | ||
145 | #define CFG_GRADIENT_THR_RANGE_MASK 0x0f | ||
146 | #define CFG_GRADIENT_THR_RANGE_SHIFT 12 | ||
147 | #define CFG_MIN_GY_THR_MASK 0xff | ||
148 | #define CFG_MIN_GY_THR_SHIFT 16 | ||
149 | #define CFG_MIN_GY_THR_RANGE_MASK 0x0f | ||
150 | #define CFG_MIN_GY_THR_RANGE_SHIFT 28 | ||
151 | |||
152 | #define CFG_SC24 0x60 | ||
153 | #define CFG_ORG_H_MASK 0x07ff | ||
154 | #define CFG_ORG_H_SHIFT 0 | ||
155 | #define CFG_ORG_W_MASK 0x07ff | ||
156 | #define CFG_ORG_W_SHIFT 16 | ||
157 | |||
158 | #define CFG_SC25 0x64 | ||
159 | #define CFG_OFF_H_MASK 0x07ff | ||
160 | #define CFG_OFF_H_SHIFT 0 | ||
161 | #define CFG_OFF_W_MASK 0x07ff | ||
162 | #define CFG_OFF_W_SHIFT 16 | ||
163 | |||
164 | /* number of phases supported by the polyphase scalers */ | ||
165 | #define SC_NUM_PHASES 32 | ||
166 | |||
167 | /* number of taps used by horizontal polyphase scaler */ | ||
168 | #define SC_H_NUM_TAPS 7 | ||
169 | |||
170 | /* number of taps used by vertical polyphase scaler */ | ||
171 | #define SC_V_NUM_TAPS 5 | ||
172 | |||
173 | /* number of taps expected by the scaler in it's coefficient memory */ | ||
174 | #define SC_NUM_TAPS_MEM_ALIGN 8 | ||
175 | |||
176 | /* | ||
177 | * coefficient memory size in bytes: | ||
178 | * num phases x num sets(luma and chroma) x num taps(aligned) x coeff size | ||
179 | */ | ||
180 | #define SC_COEF_SRAM_SIZE (SC_NUM_PHASES * 2 * SC_NUM_TAPS_MEM_ALIGN * 2) | ||
181 | |||
182 | struct sc_data { | ||
183 | void __iomem *base; | ||
184 | struct resource *res; | ||
185 | |||
186 | dma_addr_t loaded_coeff_h; /* loaded h coeffs in SC */ | ||
187 | dma_addr_t loaded_coeff_v; /* loaded v coeffs in SC */ | ||
188 | |||
189 | bool load_coeff_h; /* have new h SC coeffs */ | ||
190 | bool load_coeff_v; /* have new v SC coeffs */ | ||
191 | |||
192 | unsigned int hs_index; /* h SC coeffs selector */ | ||
193 | unsigned int vs_index; /* v SC coeffs selector */ | ||
194 | |||
195 | struct platform_device *pdev; | ||
196 | }; | ||
197 | |||
198 | void sc_dump_regs(struct sc_data *sc); | ||
199 | void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, | ||
200 | unsigned int dst_w); | ||
201 | void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, | ||
202 | unsigned int dst_h); | ||
203 | void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, | ||
204 | u32 *sc_reg17, unsigned int src_w, unsigned int src_h, | ||
205 | unsigned int dst_w, unsigned int dst_h); | ||
206 | struct sc_data *sc_create(struct platform_device *pdev); | ||
207 | |||
208 | #endif | ||
diff --git a/drivers/media/platform/ti-vpe/sc_coeff.h b/drivers/media/platform/ti-vpe/sc_coeff.h new file mode 100644 index 000000000000..5bfa5c03aec6 --- /dev/null +++ b/drivers/media/platform/ti-vpe/sc_coeff.h | |||
@@ -0,0 +1,1342 @@ | |||
1 | /* | ||
2 | * VPE SC coefs | ||
3 | * | ||
4 | * Copyright (c) 2013 Texas Instruments Inc. | ||
5 | * | ||
6 | * David Griego, <dagriego@biglakesoftware.com> | ||
7 | * Dale Farnsworth, <dale@farnsworth.org> | ||
8 | * Archit Taneja, <archit@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __TI_SC_COEFF_H | ||
16 | #define __TI_SC_COEFF_H | ||
17 | |||
18 | /* horizontal scaler coefficients */ | ||
19 | enum { | ||
20 | HS_UP_SCALE = 0, | ||
21 | HS_LT_9_16_SCALE, | ||
22 | HS_LT_10_16_SCALE, | ||
23 | HS_LT_11_16_SCALE, | ||
24 | HS_LT_12_16_SCALE, | ||
25 | HS_LT_13_16_SCALE, | ||
26 | HS_LT_14_16_SCALE, | ||
27 | HS_LT_15_16_SCALE, | ||
28 | HS_LE_16_16_SCALE, | ||
29 | }; | ||
30 | |||
31 | static const u16 scaler_hs_coeffs[13][SC_NUM_PHASES * 2 * SC_H_NUM_TAPS] = { | ||
32 | [HS_UP_SCALE] = { | ||
33 | /* Luma */ | ||
34 | 0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F, | ||
35 | 0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022, | ||
36 | 0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025, | ||
37 | 0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028, | ||
38 | 0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B, | ||
39 | 0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D, | ||
40 | 0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F, | ||
41 | 0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031, | ||
42 | 0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033, | ||
43 | 0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034, | ||
44 | 0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035, | ||
45 | 0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035, | ||
46 | 0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034, | ||
47 | 0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033, | ||
48 | 0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032, | ||
49 | 0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F, | ||
50 | 0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000, | ||
51 | 0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF, | ||
52 | 0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000, | ||
53 | 0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001, | ||
54 | 0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002, | ||
55 | 0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003, | ||
56 | 0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005, | ||
57 | 0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007, | ||
58 | 0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009, | ||
59 | 0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B, | ||
60 | 0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E, | ||
61 | 0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010, | ||
62 | 0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013, | ||
63 | 0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016, | ||
64 | 0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019, | ||
65 | 0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C, | ||
66 | /* Chroma */ | ||
67 | 0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F, | ||
68 | 0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022, | ||
69 | 0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025, | ||
70 | 0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028, | ||
71 | 0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B, | ||
72 | 0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D, | ||
73 | 0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F, | ||
74 | 0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031, | ||
75 | 0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033, | ||
76 | 0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034, | ||
77 | 0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035, | ||
78 | 0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035, | ||
79 | 0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034, | ||
80 | 0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033, | ||
81 | 0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032, | ||
82 | 0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F, | ||
83 | 0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000, | ||
84 | 0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF, | ||
85 | 0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000, | ||
86 | 0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001, | ||
87 | 0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002, | ||
88 | 0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003, | ||
89 | 0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005, | ||
90 | 0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007, | ||
91 | 0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009, | ||
92 | 0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B, | ||
93 | 0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E, | ||
94 | 0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010, | ||
95 | 0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013, | ||
96 | 0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016, | ||
97 | 0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019, | ||
98 | 0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C, | ||
99 | }, | ||
100 | [HS_LT_9_16_SCALE] = { | ||
101 | /* Luma */ | ||
102 | 0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3, | ||
103 | 0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4, | ||
104 | 0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4, | ||
105 | 0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5, | ||
106 | 0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6, | ||
107 | 0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8, | ||
108 | 0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA, | ||
109 | 0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC, | ||
110 | 0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF, | ||
111 | 0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2, | ||
112 | 0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5, | ||
113 | 0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9, | ||
114 | 0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD, | ||
115 | 0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1, | ||
116 | 0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6, | ||
117 | 0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB, | ||
118 | 0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000, | ||
119 | 0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7, | ||
120 | 0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4, | ||
121 | 0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2, | ||
122 | 0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0, | ||
123 | 0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE, | ||
124 | 0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC, | ||
125 | 0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA, | ||
126 | 0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9, | ||
127 | 0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7, | ||
128 | 0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6, | ||
129 | 0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5, | ||
130 | 0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4, | ||
131 | 0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3, | ||
132 | 0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3, | ||
133 | 0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3, | ||
134 | /* Chroma */ | ||
135 | 0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3, | ||
136 | 0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4, | ||
137 | 0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4, | ||
138 | 0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5, | ||
139 | 0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6, | ||
140 | 0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8, | ||
141 | 0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA, | ||
142 | 0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC, | ||
143 | 0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF, | ||
144 | 0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2, | ||
145 | 0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5, | ||
146 | 0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9, | ||
147 | 0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD, | ||
148 | 0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1, | ||
149 | 0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6, | ||
150 | 0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB, | ||
151 | 0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000, | ||
152 | 0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7, | ||
153 | 0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4, | ||
154 | 0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2, | ||
155 | 0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0, | ||
156 | 0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE, | ||
157 | 0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC, | ||
158 | 0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA, | ||
159 | 0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9, | ||
160 | 0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7, | ||
161 | 0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6, | ||
162 | 0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5, | ||
163 | 0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4, | ||
164 | 0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3, | ||
165 | 0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3, | ||
166 | 0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3, | ||
167 | }, | ||
168 | [HS_LT_10_16_SCALE] = { | ||
169 | /* Luma */ | ||
170 | 0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D, | ||
171 | 0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A, | ||
172 | 0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88, | ||
173 | 0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86, | ||
174 | 0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85, | ||
175 | 0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83, | ||
176 | 0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83, | ||
177 | 0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82, | ||
178 | 0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82, | ||
179 | 0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82, | ||
180 | 0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83, | ||
181 | 0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84, | ||
182 | 0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85, | ||
183 | 0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87, | ||
184 | 0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A, | ||
185 | 0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D, | ||
186 | 0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000, | ||
187 | 0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4, | ||
188 | 0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0, | ||
189 | 0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC, | ||
190 | 0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8, | ||
191 | 0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3, | ||
192 | 0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF, | ||
193 | 0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB, | ||
194 | 0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7, | ||
195 | 0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4, | ||
196 | 0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0, | ||
197 | 0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C, | ||
198 | 0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99, | ||
199 | 0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95, | ||
200 | 0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92, | ||
201 | 0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F, | ||
202 | /* Chroma */ | ||
203 | 0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D, | ||
204 | 0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A, | ||
205 | 0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88, | ||
206 | 0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86, | ||
207 | 0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85, | ||
208 | 0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83, | ||
209 | 0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83, | ||
210 | 0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82, | ||
211 | 0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82, | ||
212 | 0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82, | ||
213 | 0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83, | ||
214 | 0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84, | ||
215 | 0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85, | ||
216 | 0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87, | ||
217 | 0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A, | ||
218 | 0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D, | ||
219 | 0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000, | ||
220 | 0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4, | ||
221 | 0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0, | ||
222 | 0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC, | ||
223 | 0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8, | ||
224 | 0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3, | ||
225 | 0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF, | ||
226 | 0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB, | ||
227 | 0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7, | ||
228 | 0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4, | ||
229 | 0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0, | ||
230 | 0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C, | ||
231 | 0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99, | ||
232 | 0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95, | ||
233 | 0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92, | ||
234 | 0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F, | ||
235 | }, | ||
236 | [HS_LT_11_16_SCALE] = { | ||
237 | /* Luma */ | ||
238 | 0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95, | ||
239 | 0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90, | ||
240 | 0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A, | ||
241 | 0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85, | ||
242 | 0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80, | ||
243 | 0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C, | ||
244 | 0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77, | ||
245 | 0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73, | ||
246 | 0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70, | ||
247 | 0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D, | ||
248 | 0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A, | ||
249 | 0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67, | ||
250 | 0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65, | ||
251 | 0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64, | ||
252 | 0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62, | ||
253 | 0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62, | ||
254 | 0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000, | ||
255 | 0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7, | ||
256 | 0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3, | ||
257 | 0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE, | ||
258 | 0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8, | ||
259 | 0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3, | ||
260 | 0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE, | ||
261 | 0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8, | ||
262 | 0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3, | ||
263 | 0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD, | ||
264 | 0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7, | ||
265 | 0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1, | ||
266 | 0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC, | ||
267 | 0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6, | ||
268 | 0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0, | ||
269 | 0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B, | ||
270 | /* Chroma */ | ||
271 | 0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95, | ||
272 | 0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90, | ||
273 | 0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A, | ||
274 | 0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85, | ||
275 | 0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80, | ||
276 | 0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C, | ||
277 | 0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77, | ||
278 | 0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73, | ||
279 | 0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70, | ||
280 | 0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D, | ||
281 | 0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A, | ||
282 | 0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67, | ||
283 | 0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65, | ||
284 | 0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64, | ||
285 | 0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62, | ||
286 | 0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62, | ||
287 | 0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000, | ||
288 | 0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7, | ||
289 | 0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3, | ||
290 | 0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE, | ||
291 | 0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8, | ||
292 | 0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3, | ||
293 | 0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE, | ||
294 | 0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8, | ||
295 | 0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3, | ||
296 | 0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD, | ||
297 | 0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7, | ||
298 | 0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1, | ||
299 | 0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC, | ||
300 | 0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6, | ||
301 | 0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0, | ||
302 | 0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B, | ||
303 | }, | ||
304 | [HS_LT_12_16_SCALE] = { | ||
305 | /* Luma */ | ||
306 | 0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB, | ||
307 | 0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4, | ||
308 | 0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC, | ||
309 | 0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5, | ||
310 | 0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D, | ||
311 | 0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95, | ||
312 | 0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E, | ||
313 | 0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86, | ||
314 | 0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F, | ||
315 | 0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78, | ||
316 | 0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72, | ||
317 | 0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B, | ||
318 | 0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65, | ||
319 | 0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F, | ||
320 | 0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A, | ||
321 | 0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55, | ||
322 | 0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000, | ||
323 | 0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015, | ||
324 | 0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011, | ||
325 | 0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D, | ||
326 | 0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008, | ||
327 | 0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003, | ||
328 | 0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE, | ||
329 | 0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8, | ||
330 | 0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2, | ||
331 | 0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC, | ||
332 | 0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6, | ||
333 | 0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF, | ||
334 | 0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8, | ||
335 | 0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1, | ||
336 | 0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA, | ||
337 | 0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3, | ||
338 | /* Chroma */ | ||
339 | 0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB, | ||
340 | 0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4, | ||
341 | 0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC, | ||
342 | 0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5, | ||
343 | 0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D, | ||
344 | 0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95, | ||
345 | 0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E, | ||
346 | 0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86, | ||
347 | 0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F, | ||
348 | 0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78, | ||
349 | 0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72, | ||
350 | 0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B, | ||
351 | 0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65, | ||
352 | 0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F, | ||
353 | 0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A, | ||
354 | 0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55, | ||
355 | 0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000, | ||
356 | 0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015, | ||
357 | 0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011, | ||
358 | 0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D, | ||
359 | 0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008, | ||
360 | 0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003, | ||
361 | 0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE, | ||
362 | 0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8, | ||
363 | 0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2, | ||
364 | 0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC, | ||
365 | 0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6, | ||
366 | 0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF, | ||
367 | 0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8, | ||
368 | 0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1, | ||
369 | 0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA, | ||
370 | 0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3, | ||
371 | }, | ||
372 | [HS_LT_13_16_SCALE] = { | ||
373 | /* Luma */ | ||
374 | 0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4, | ||
375 | 0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC, | ||
376 | 0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4, | ||
377 | 0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB, | ||
378 | 0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2, | ||
379 | 0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9, | ||
380 | 0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0, | ||
381 | 0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6, | ||
382 | 0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD, | ||
383 | 0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3, | ||
384 | 0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99, | ||
385 | 0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90, | ||
386 | 0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86, | ||
387 | 0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D, | ||
388 | 0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73, | ||
389 | 0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A, | ||
390 | 0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000, | ||
391 | 0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C, | ||
392 | 0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A, | ||
393 | 0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038, | ||
394 | 0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035, | ||
395 | 0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032, | ||
396 | 0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F, | ||
397 | 0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B, | ||
398 | 0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027, | ||
399 | 0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022, | ||
400 | 0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D, | ||
401 | 0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017, | ||
402 | 0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011, | ||
403 | 0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A, | ||
404 | 0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003, | ||
405 | 0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC, | ||
406 | /* Chroma */ | ||
407 | 0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4, | ||
408 | 0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC, | ||
409 | 0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4, | ||
410 | 0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB, | ||
411 | 0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2, | ||
412 | 0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9, | ||
413 | 0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0, | ||
414 | 0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6, | ||
415 | 0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD, | ||
416 | 0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3, | ||
417 | 0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99, | ||
418 | 0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90, | ||
419 | 0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86, | ||
420 | 0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D, | ||
421 | 0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73, | ||
422 | 0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A, | ||
423 | 0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000, | ||
424 | 0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C, | ||
425 | 0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A, | ||
426 | 0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038, | ||
427 | 0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035, | ||
428 | 0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032, | ||
429 | 0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F, | ||
430 | 0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B, | ||
431 | 0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027, | ||
432 | 0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022, | ||
433 | 0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D, | ||
434 | 0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017, | ||
435 | 0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011, | ||
436 | 0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A, | ||
437 | 0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003, | ||
438 | 0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC, | ||
439 | }, | ||
440 | [HS_LT_14_16_SCALE] = { | ||
441 | /* Luma */ | ||
442 | 0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F, | ||
443 | 0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028, | ||
444 | 0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021, | ||
445 | 0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A, | ||
446 | 0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012, | ||
447 | 0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009, | ||
448 | 0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000, | ||
449 | 0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6, | ||
450 | 0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC, | ||
451 | 0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2, | ||
452 | 0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7, | ||
453 | 0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB, | ||
454 | 0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0, | ||
455 | 0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4, | ||
456 | 0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8, | ||
457 | 0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C, | ||
458 | 0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000, | ||
459 | 0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D, | ||
460 | 0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E, | ||
461 | 0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F, | ||
462 | 0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050, | ||
463 | 0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050, | ||
464 | 0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050, | ||
465 | 0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F, | ||
466 | 0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E, | ||
467 | 0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C, | ||
468 | 0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049, | ||
469 | 0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046, | ||
470 | 0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043, | ||
471 | 0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F, | ||
472 | 0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A, | ||
473 | 0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035, | ||
474 | /* Chroma */ | ||
475 | 0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F, | ||
476 | 0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028, | ||
477 | 0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021, | ||
478 | 0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A, | ||
479 | 0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012, | ||
480 | 0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009, | ||
481 | 0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000, | ||
482 | 0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6, | ||
483 | 0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC, | ||
484 | 0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2, | ||
485 | 0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7, | ||
486 | 0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB, | ||
487 | 0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0, | ||
488 | 0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4, | ||
489 | 0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8, | ||
490 | 0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C, | ||
491 | 0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000, | ||
492 | 0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D, | ||
493 | 0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E, | ||
494 | 0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F, | ||
495 | 0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050, | ||
496 | 0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050, | ||
497 | 0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050, | ||
498 | 0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F, | ||
499 | 0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E, | ||
500 | 0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C, | ||
501 | 0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049, | ||
502 | 0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046, | ||
503 | 0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043, | ||
504 | 0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F, | ||
505 | 0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A, | ||
506 | 0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035, | ||
507 | }, | ||
508 | [HS_LT_15_16_SCALE] = { | ||
509 | /* Luma */ | ||
510 | 0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B, | ||
511 | 0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058, | ||
512 | 0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054, | ||
513 | 0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F, | ||
514 | 0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A, | ||
515 | 0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044, | ||
516 | 0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D, | ||
517 | 0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036, | ||
518 | 0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D, | ||
519 | 0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024, | ||
520 | 0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A, | ||
521 | 0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010, | ||
522 | 0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005, | ||
523 | 0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9, | ||
524 | 0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED, | ||
525 | 0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0, | ||
526 | 0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000, | ||
527 | 0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043, | ||
528 | 0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048, | ||
529 | 0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C, | ||
530 | 0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050, | ||
531 | 0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053, | ||
532 | 0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057, | ||
533 | 0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059, | ||
534 | 0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C, | ||
535 | 0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E, | ||
536 | 0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F, | ||
537 | 0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060, | ||
538 | 0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060, | ||
539 | 0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060, | ||
540 | 0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F, | ||
541 | 0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D, | ||
542 | /* Chroma */ | ||
543 | 0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B, | ||
544 | 0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058, | ||
545 | 0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054, | ||
546 | 0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F, | ||
547 | 0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A, | ||
548 | 0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044, | ||
549 | 0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D, | ||
550 | 0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036, | ||
551 | 0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D, | ||
552 | 0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024, | ||
553 | 0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A, | ||
554 | 0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010, | ||
555 | 0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005, | ||
556 | 0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9, | ||
557 | 0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED, | ||
558 | 0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0, | ||
559 | 0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000, | ||
560 | 0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043, | ||
561 | 0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048, | ||
562 | 0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C, | ||
563 | 0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050, | ||
564 | 0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053, | ||
565 | 0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057, | ||
566 | 0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059, | ||
567 | 0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C, | ||
568 | 0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E, | ||
569 | 0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F, | ||
570 | 0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060, | ||
571 | 0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060, | ||
572 | 0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060, | ||
573 | 0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F, | ||
574 | 0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D, | ||
575 | }, | ||
576 | [HS_LE_16_16_SCALE] = { | ||
577 | /* Luma */ | ||
578 | 0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E, | ||
579 | 0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070, | ||
580 | 0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070, | ||
581 | 0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070, | ||
582 | 0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F, | ||
583 | 0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D, | ||
584 | 0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B, | ||
585 | 0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067, | ||
586 | 0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063, | ||
587 | 0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D, | ||
588 | 0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057, | ||
589 | 0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F, | ||
590 | 0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047, | ||
591 | 0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D, | ||
592 | 0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033, | ||
593 | 0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027, | ||
594 | 0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000, | ||
595 | 0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023, | ||
596 | 0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A, | ||
597 | 0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030, | ||
598 | 0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036, | ||
599 | 0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D, | ||
600 | 0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043, | ||
601 | 0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049, | ||
602 | 0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E, | ||
603 | 0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054, | ||
604 | 0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059, | ||
605 | 0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E, | ||
606 | 0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062, | ||
607 | 0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066, | ||
608 | 0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069, | ||
609 | 0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C, | ||
610 | /* Chroma */ | ||
611 | 0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E, | ||
612 | 0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070, | ||
613 | 0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070, | ||
614 | 0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070, | ||
615 | 0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F, | ||
616 | 0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D, | ||
617 | 0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B, | ||
618 | 0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067, | ||
619 | 0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063, | ||
620 | 0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D, | ||
621 | 0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057, | ||
622 | 0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F, | ||
623 | 0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047, | ||
624 | 0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D, | ||
625 | 0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033, | ||
626 | 0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027, | ||
627 | 0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000, | ||
628 | 0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023, | ||
629 | 0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A, | ||
630 | 0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030, | ||
631 | 0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036, | ||
632 | 0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D, | ||
633 | 0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043, | ||
634 | 0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049, | ||
635 | 0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E, | ||
636 | 0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054, | ||
637 | 0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059, | ||
638 | 0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E, | ||
639 | 0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062, | ||
640 | 0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066, | ||
641 | 0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069, | ||
642 | 0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C, | ||
643 | }, | ||
644 | }; | ||
645 | |||
646 | /* vertical scaler coefficients */ | ||
647 | enum { | ||
648 | VS_UP_SCALE = 0, | ||
649 | VS_LT_9_16_SCALE, | ||
650 | VS_LT_10_16_SCALE, | ||
651 | VS_LT_11_16_SCALE, | ||
652 | VS_LT_12_16_SCALE, | ||
653 | VS_LT_13_16_SCALE, | ||
654 | VS_LT_14_16_SCALE, | ||
655 | VS_LT_15_16_SCALE, | ||
656 | VS_LT_16_16_SCALE, | ||
657 | VS_1_TO_1_SCALE, | ||
658 | }; | ||
659 | |||
660 | static const u16 scaler_vs_coeffs[15][SC_NUM_PHASES * 2 * SC_V_NUM_TAPS] = { | ||
661 | [VS_UP_SCALE] = { | ||
662 | /* Luma */ | ||
663 | 0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1, | ||
664 | 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, | ||
665 | 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, | ||
666 | 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, | ||
667 | 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, | ||
668 | 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, | ||
669 | 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, | ||
670 | 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, | ||
671 | 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, | ||
672 | 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, | ||
673 | 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, | ||
674 | 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, | ||
675 | 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, | ||
676 | 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, | ||
677 | 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, | ||
678 | 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, | ||
679 | 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, | ||
680 | 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, | ||
681 | 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, | ||
682 | 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, | ||
683 | 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, | ||
684 | 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, | ||
685 | 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, | ||
686 | 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, | ||
687 | 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, | ||
688 | 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, | ||
689 | 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, | ||
690 | 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, | ||
691 | 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, | ||
692 | 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, | ||
693 | 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, | ||
694 | 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, | ||
695 | /* Chroma */ | ||
696 | 0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1, | ||
697 | 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, | ||
698 | 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, | ||
699 | 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, | ||
700 | 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, | ||
701 | 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, | ||
702 | 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, | ||
703 | 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, | ||
704 | 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, | ||
705 | 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, | ||
706 | 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, | ||
707 | 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, | ||
708 | 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, | ||
709 | 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, | ||
710 | 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, | ||
711 | 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, | ||
712 | 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, | ||
713 | 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, | ||
714 | 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, | ||
715 | 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, | ||
716 | 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, | ||
717 | 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, | ||
718 | 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, | ||
719 | 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, | ||
720 | 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, | ||
721 | 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, | ||
722 | 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, | ||
723 | 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, | ||
724 | 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, | ||
725 | 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, | ||
726 | 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, | ||
727 | 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, | ||
728 | }, | ||
729 | [VS_LT_9_16_SCALE] = { | ||
730 | /* Luma */ | ||
731 | 0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C, | ||
732 | 0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022, | ||
733 | 0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028, | ||
734 | 0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E, | ||
735 | 0x000C, 0x019D, 0x03D2, 0x0250, 0x0035, | ||
736 | 0x0009, 0x0188, 0x03CC, 0x0266, 0x003D, | ||
737 | 0x0006, 0x0173, 0x03C5, 0x027D, 0x0045, | ||
738 | 0x0004, 0x015E, 0x03BD, 0x0293, 0x004E, | ||
739 | 0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058, | ||
740 | 0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062, | ||
741 | 0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D, | ||
742 | 0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078, | ||
743 | 0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085, | ||
744 | 0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091, | ||
745 | 0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F, | ||
746 | 0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD, | ||
747 | 0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000, | ||
748 | 0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC, | ||
749 | 0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC, | ||
750 | 0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD, | ||
751 | 0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD, | ||
752 | 0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE, | ||
753 | 0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF, | ||
754 | 0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000, | ||
755 | 0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002, | ||
756 | 0x004E, 0x0293, 0x03BD, 0x015E, 0x0004, | ||
757 | 0x0045, 0x027D, 0x03C5, 0x0173, 0x0006, | ||
758 | 0x003D, 0x0266, 0x03CC, 0x0188, 0x0009, | ||
759 | 0x0035, 0x0250, 0x03D2, 0x019D, 0x000C, | ||
760 | 0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F, | ||
761 | 0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013, | ||
762 | 0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018, | ||
763 | /* Chroma */ | ||
764 | 0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C, | ||
765 | 0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022, | ||
766 | 0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028, | ||
767 | 0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E, | ||
768 | 0x000C, 0x019D, 0x03D2, 0x0250, 0x0035, | ||
769 | 0x0009, 0x0188, 0x03CC, 0x0266, 0x003D, | ||
770 | 0x0006, 0x0173, 0x03C5, 0x027D, 0x0045, | ||
771 | 0x0004, 0x015E, 0x03BD, 0x0293, 0x004E, | ||
772 | 0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058, | ||
773 | 0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062, | ||
774 | 0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D, | ||
775 | 0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078, | ||
776 | 0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085, | ||
777 | 0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091, | ||
778 | 0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F, | ||
779 | 0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD, | ||
780 | 0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000, | ||
781 | 0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC, | ||
782 | 0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC, | ||
783 | 0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD, | ||
784 | 0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD, | ||
785 | 0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE, | ||
786 | 0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF, | ||
787 | 0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000, | ||
788 | 0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002, | ||
789 | 0x004E, 0x0293, 0x03BD, 0x015E, 0x0004, | ||
790 | 0x0045, 0x027D, 0x03C5, 0x0173, 0x0006, | ||
791 | 0x003D, 0x0266, 0x03CC, 0x0188, 0x0009, | ||
792 | 0x0035, 0x0250, 0x03D2, 0x019D, 0x000C, | ||
793 | 0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F, | ||
794 | 0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013, | ||
795 | 0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018, | ||
796 | }, | ||
797 | [VS_LT_10_16_SCALE] = { | ||
798 | /* Luma */ | ||
799 | 0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003, | ||
800 | 0x0000, 0x01D0, 0x0426, 0x0203, 0x0007, | ||
801 | 0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C, | ||
802 | 0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011, | ||
803 | 0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017, | ||
804 | 0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D, | ||
805 | 0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024, | ||
806 | 0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C, | ||
807 | 0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035, | ||
808 | 0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E, | ||
809 | 0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048, | ||
810 | 0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053, | ||
811 | 0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F, | ||
812 | 0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B, | ||
813 | 0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078, | ||
814 | 0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086, | ||
815 | 0x0094, 0x036C, 0x036C, 0x0094, 0x0000, | ||
816 | 0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6, | ||
817 | 0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6, | ||
818 | 0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5, | ||
819 | 0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4, | ||
820 | 0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4, | ||
821 | 0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4, | ||
822 | 0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4, | ||
823 | 0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4, | ||
824 | 0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5, | ||
825 | 0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6, | ||
826 | 0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7, | ||
827 | 0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9, | ||
828 | 0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB, | ||
829 | 0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD, | ||
830 | 0x0007, 0x0203, 0x0426, 0x01D0, 0x0000, | ||
831 | /* Chroma */ | ||
832 | 0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003, | ||
833 | 0x0000, 0x01D0, 0x0426, 0x0203, 0x0007, | ||
834 | 0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C, | ||
835 | 0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011, | ||
836 | 0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017, | ||
837 | 0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D, | ||
838 | 0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024, | ||
839 | 0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C, | ||
840 | 0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035, | ||
841 | 0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E, | ||
842 | 0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048, | ||
843 | 0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053, | ||
844 | 0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F, | ||
845 | 0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B, | ||
846 | 0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078, | ||
847 | 0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086, | ||
848 | 0x0094, 0x036C, 0x036C, 0x0094, 0x0000, | ||
849 | 0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6, | ||
850 | 0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6, | ||
851 | 0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5, | ||
852 | 0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4, | ||
853 | 0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4, | ||
854 | 0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4, | ||
855 | 0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4, | ||
856 | 0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4, | ||
857 | 0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5, | ||
858 | 0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6, | ||
859 | 0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7, | ||
860 | 0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9, | ||
861 | 0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB, | ||
862 | 0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD, | ||
863 | 0x0007, 0x0203, 0x0426, 0x01D0, 0x0000, | ||
864 | }, | ||
865 | [VS_LT_11_16_SCALE] = { | ||
866 | /* Luma */ | ||
867 | 0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC, | ||
868 | 0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE, | ||
869 | 0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1, | ||
870 | 0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5, | ||
871 | 0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9, | ||
872 | 0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD, | ||
873 | 0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003, | ||
874 | 0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009, | ||
875 | 0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010, | ||
876 | 0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018, | ||
877 | 0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021, | ||
878 | 0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B, | ||
879 | 0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035, | ||
880 | 0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041, | ||
881 | 0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D, | ||
882 | 0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B, | ||
883 | 0x0069, 0x0397, 0x0397, 0x0069, 0x0000, | ||
884 | 0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3, | ||
885 | 0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1, | ||
886 | 0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0, | ||
887 | 0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE, | ||
888 | 0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED, | ||
889 | 0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB, | ||
890 | 0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA, | ||
891 | 0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9, | ||
892 | 0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9, | ||
893 | 0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8, | ||
894 | 0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8, | ||
895 | 0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8, | ||
896 | 0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8, | ||
897 | 0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9, | ||
898 | 0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA, | ||
899 | /* Chroma */ | ||
900 | 0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC, | ||
901 | 0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE, | ||
902 | 0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1, | ||
903 | 0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5, | ||
904 | 0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9, | ||
905 | 0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD, | ||
906 | 0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003, | ||
907 | 0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009, | ||
908 | 0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010, | ||
909 | 0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018, | ||
910 | 0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021, | ||
911 | 0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B, | ||
912 | 0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035, | ||
913 | 0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041, | ||
914 | 0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D, | ||
915 | 0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B, | ||
916 | 0x0069, 0x0397, 0x0397, 0x0069, 0x0000, | ||
917 | 0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3, | ||
918 | 0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1, | ||
919 | 0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0, | ||
920 | 0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE, | ||
921 | 0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED, | ||
922 | 0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB, | ||
923 | 0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA, | ||
924 | 0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9, | ||
925 | 0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9, | ||
926 | 0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8, | ||
927 | 0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8, | ||
928 | 0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8, | ||
929 | 0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8, | ||
930 | 0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9, | ||
931 | 0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA, | ||
932 | }, | ||
933 | [VS_LT_12_16_SCALE] = { | ||
934 | /* Luma */ | ||
935 | 0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8, | ||
936 | 0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8, | ||
937 | 0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9, | ||
938 | 0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA, | ||
939 | 0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC, | ||
940 | 0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF, | ||
941 | 0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3, | ||
942 | 0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7, | ||
943 | 0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC, | ||
944 | 0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2, | ||
945 | 0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA, | ||
946 | 0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002, | ||
947 | 0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B, | ||
948 | 0x1FED, 0x006B, 0x0421, 0x0372, 0x0015, | ||
949 | 0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020, | ||
950 | 0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D, | ||
951 | 0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000, | ||
952 | 0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1, | ||
953 | 0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF, | ||
954 | 0x0015, 0x0372, 0x0421, 0x006B, 0x1FED, | ||
955 | 0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB, | ||
956 | 0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9, | ||
957 | 0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6, | ||
958 | 0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4, | ||
959 | 0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2, | ||
960 | 0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0, | ||
961 | 0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE, | ||
962 | 0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC, | ||
963 | 0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB, | ||
964 | 0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9, | ||
965 | 0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8, | ||
966 | 0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8, | ||
967 | /* Chroma */ | ||
968 | 0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8, | ||
969 | 0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8, | ||
970 | 0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9, | ||
971 | 0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA, | ||
972 | 0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC, | ||
973 | 0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF, | ||
974 | 0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3, | ||
975 | 0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7, | ||
976 | 0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC, | ||
977 | 0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2, | ||
978 | 0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA, | ||
979 | 0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002, | ||
980 | 0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B, | ||
981 | 0x1FED, 0x006B, 0x0421, 0x0372, 0x0015, | ||
982 | 0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020, | ||
983 | 0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D, | ||
984 | 0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000, | ||
985 | 0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1, | ||
986 | 0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF, | ||
987 | 0x0015, 0x0372, 0x0421, 0x006B, 0x1FED, | ||
988 | 0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB, | ||
989 | 0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9, | ||
990 | 0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6, | ||
991 | 0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4, | ||
992 | 0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2, | ||
993 | 0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0, | ||
994 | 0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE, | ||
995 | 0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC, | ||
996 | 0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB, | ||
997 | 0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9, | ||
998 | 0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8, | ||
999 | 0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8, | ||
1000 | }, | ||
1001 | [VS_LT_13_16_SCALE] = { | ||
1002 | /* Luma */ | ||
1003 | 0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8, | ||
1004 | 0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6, | ||
1005 | 0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5, | ||
1006 | 0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4, | ||
1007 | 0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4, | ||
1008 | 0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5, | ||
1009 | 0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6, | ||
1010 | 0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8, | ||
1011 | 0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB, | ||
1012 | 0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF, | ||
1013 | 0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4, | ||
1014 | 0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9, | ||
1015 | 0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1, | ||
1016 | 0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9, | ||
1017 | 0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2, | ||
1018 | 0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD, | ||
1019 | 0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000, | ||
1020 | 0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2, | ||
1021 | 0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0, | ||
1022 | 0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE, | ||
1023 | 0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB, | ||
1024 | 0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8, | ||
1025 | 0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5, | ||
1026 | 0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2, | ||
1027 | 0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF, | ||
1028 | 0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC, | ||
1029 | 0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8, | ||
1030 | 0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5, | ||
1031 | 0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2, | ||
1032 | 0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF, | ||
1033 | 0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD, | ||
1034 | 0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA, | ||
1035 | /* Chroma */ | ||
1036 | 0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8, | ||
1037 | 0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6, | ||
1038 | 0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5, | ||
1039 | 0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4, | ||
1040 | 0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4, | ||
1041 | 0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5, | ||
1042 | 0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6, | ||
1043 | 0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8, | ||
1044 | 0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB, | ||
1045 | 0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF, | ||
1046 | 0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4, | ||
1047 | 0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9, | ||
1048 | 0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1, | ||
1049 | 0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9, | ||
1050 | 0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2, | ||
1051 | 0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD, | ||
1052 | 0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000, | ||
1053 | 0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2, | ||
1054 | 0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0, | ||
1055 | 0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE, | ||
1056 | 0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB, | ||
1057 | 0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8, | ||
1058 | 0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5, | ||
1059 | 0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2, | ||
1060 | 0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF, | ||
1061 | 0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC, | ||
1062 | 0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8, | ||
1063 | 0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5, | ||
1064 | 0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2, | ||
1065 | 0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF, | ||
1066 | 0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD, | ||
1067 | 0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA, | ||
1068 | }, | ||
1069 | [VS_LT_14_16_SCALE] = { | ||
1070 | /* Luma */ | ||
1071 | 0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF, | ||
1072 | 0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB, | ||
1073 | 0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8, | ||
1074 | 0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5, | ||
1075 | 0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2, | ||
1076 | 0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0, | ||
1077 | 0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF, | ||
1078 | 0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE, | ||
1079 | 0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE, | ||
1080 | 0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF, | ||
1081 | 0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1, | ||
1082 | 0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4, | ||
1083 | 0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9, | ||
1084 | 0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF, | ||
1085 | 0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6, | ||
1086 | 0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE, | ||
1087 | 0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000, | ||
1088 | 0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6, | ||
1089 | 0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4, | ||
1090 | 0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1, | ||
1091 | 0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE, | ||
1092 | 0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB, | ||
1093 | 0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8, | ||
1094 | 0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4, | ||
1095 | 0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0, | ||
1096 | 0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC, | ||
1097 | 0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8, | ||
1098 | 0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4, | ||
1099 | 0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0, | ||
1100 | 0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB, | ||
1101 | 0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7, | ||
1102 | 0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3, | ||
1103 | /* Chroma */ | ||
1104 | 0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF, | ||
1105 | 0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB, | ||
1106 | 0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8, | ||
1107 | 0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5, | ||
1108 | 0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2, | ||
1109 | 0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0, | ||
1110 | 0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF, | ||
1111 | 0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE, | ||
1112 | 0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE, | ||
1113 | 0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF, | ||
1114 | 0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1, | ||
1115 | 0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4, | ||
1116 | 0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9, | ||
1117 | 0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF, | ||
1118 | 0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6, | ||
1119 | 0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE, | ||
1120 | 0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000, | ||
1121 | 0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6, | ||
1122 | 0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4, | ||
1123 | 0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1, | ||
1124 | 0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE, | ||
1125 | 0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB, | ||
1126 | 0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8, | ||
1127 | 0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4, | ||
1128 | 0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0, | ||
1129 | 0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC, | ||
1130 | 0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8, | ||
1131 | 0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4, | ||
1132 | 0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0, | ||
1133 | 0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB, | ||
1134 | 0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7, | ||
1135 | 0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3, | ||
1136 | }, | ||
1137 | [VS_LT_15_16_SCALE] = { | ||
1138 | /* Luma */ | ||
1139 | 0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD, | ||
1140 | 0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8, | ||
1141 | 0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2, | ||
1142 | 0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD, | ||
1143 | 0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8, | ||
1144 | 0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3, | ||
1145 | 0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F, | ||
1146 | 0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B, | ||
1147 | 0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98, | ||
1148 | 0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96, | ||
1149 | 0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95, | ||
1150 | 0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95, | ||
1151 | 0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96, | ||
1152 | 0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99, | ||
1153 | 0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D, | ||
1154 | 0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2, | ||
1155 | 0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000, | ||
1156 | 0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB, | ||
1157 | 0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9, | ||
1158 | 0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7, | ||
1159 | 0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4, | ||
1160 | 0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1, | ||
1161 | 0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE, | ||
1162 | 0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA, | ||
1163 | 0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7, | ||
1164 | 0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2, | ||
1165 | 0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE, | ||
1166 | 0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9, | ||
1167 | 0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4, | ||
1168 | 0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE, | ||
1169 | 0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9, | ||
1170 | 0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3, | ||
1171 | /* Chroma */ | ||
1172 | 0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD, | ||
1173 | 0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8, | ||
1174 | 0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2, | ||
1175 | 0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD, | ||
1176 | 0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8, | ||
1177 | 0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3, | ||
1178 | 0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F, | ||
1179 | 0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B, | ||
1180 | 0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98, | ||
1181 | 0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96, | ||
1182 | 0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95, | ||
1183 | 0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95, | ||
1184 | 0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96, | ||
1185 | 0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99, | ||
1186 | 0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D, | ||
1187 | 0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2, | ||
1188 | 0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000, | ||
1189 | 0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB, | ||
1190 | 0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9, | ||
1191 | 0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7, | ||
1192 | 0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4, | ||
1193 | 0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1, | ||
1194 | 0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE, | ||
1195 | 0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA, | ||
1196 | 0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7, | ||
1197 | 0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2, | ||
1198 | 0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE, | ||
1199 | 0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9, | ||
1200 | 0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4, | ||
1201 | 0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE, | ||
1202 | 0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9, | ||
1203 | 0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3, | ||
1204 | }, | ||
1205 | [VS_LT_16_16_SCALE] = { | ||
1206 | /* Luma */ | ||
1207 | 0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3, | ||
1208 | 0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC, | ||
1209 | 0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5, | ||
1210 | 0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE, | ||
1211 | 0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6, | ||
1212 | 0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F, | ||
1213 | 0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98, | ||
1214 | 0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92, | ||
1215 | 0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C, | ||
1216 | 0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87, | ||
1217 | 0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82, | ||
1218 | 0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E, | ||
1219 | 0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C, | ||
1220 | 0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B, | ||
1221 | 0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B, | ||
1222 | 0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C, | ||
1223 | 0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000, | ||
1224 | 0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001, | ||
1225 | 0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000, | ||
1226 | 0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE, | ||
1227 | 0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC, | ||
1228 | 0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA, | ||
1229 | 0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7, | ||
1230 | 0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4, | ||
1231 | 0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0, | ||
1232 | 0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC, | ||
1233 | 0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8, | ||
1234 | 0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3, | ||
1235 | 0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD, | ||
1236 | 0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7, | ||
1237 | 0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1, | ||
1238 | 0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA, | ||
1239 | /* Chroma */ | ||
1240 | 0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3, | ||
1241 | 0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC, | ||
1242 | 0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5, | ||
1243 | 0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE, | ||
1244 | 0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6, | ||
1245 | 0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F, | ||
1246 | 0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98, | ||
1247 | 0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92, | ||
1248 | 0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C, | ||
1249 | 0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87, | ||
1250 | 0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82, | ||
1251 | 0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E, | ||
1252 | 0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C, | ||
1253 | 0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B, | ||
1254 | 0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B, | ||
1255 | 0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C, | ||
1256 | 0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000, | ||
1257 | 0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001, | ||
1258 | 0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000, | ||
1259 | 0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE, | ||
1260 | 0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC, | ||
1261 | 0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA, | ||
1262 | 0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7, | ||
1263 | 0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4, | ||
1264 | 0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0, | ||
1265 | 0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC, | ||
1266 | 0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8, | ||
1267 | 0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3, | ||
1268 | 0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD, | ||
1269 | 0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7, | ||
1270 | 0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1, | ||
1271 | 0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA, | ||
1272 | }, | ||
1273 | [VS_1_TO_1_SCALE] = { | ||
1274 | /* Luma */ | ||
1275 | 0x0000, 0x0000, 0x0800, 0x0000, 0x0000, | ||
1276 | 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, | ||
1277 | 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, | ||
1278 | 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, | ||
1279 | 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, | ||
1280 | 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, | ||
1281 | 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, | ||
1282 | 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, | ||
1283 | 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, | ||
1284 | 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, | ||
1285 | 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, | ||
1286 | 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, | ||
1287 | 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, | ||
1288 | 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, | ||
1289 | 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, | ||
1290 | 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, | ||
1291 | 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, | ||
1292 | 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, | ||
1293 | 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, | ||
1294 | 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, | ||
1295 | 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, | ||
1296 | 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, | ||
1297 | 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, | ||
1298 | 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, | ||
1299 | 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, | ||
1300 | 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, | ||
1301 | 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, | ||
1302 | 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, | ||
1303 | 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, | ||
1304 | 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, | ||
1305 | 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, | ||
1306 | 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, | ||
1307 | /* Chroma */ | ||
1308 | 0x0000, 0x0000, 0x0800, 0x0000, 0x0000, | ||
1309 | 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, | ||
1310 | 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, | ||
1311 | 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, | ||
1312 | 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, | ||
1313 | 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, | ||
1314 | 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, | ||
1315 | 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, | ||
1316 | 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, | ||
1317 | 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, | ||
1318 | 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, | ||
1319 | 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, | ||
1320 | 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, | ||
1321 | 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, | ||
1322 | 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, | ||
1323 | 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, | ||
1324 | 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, | ||
1325 | 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, | ||
1326 | 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, | ||
1327 | 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, | ||
1328 | 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, | ||
1329 | 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, | ||
1330 | 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, | ||
1331 | 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, | ||
1332 | 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, | ||
1333 | 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, | ||
1334 | 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, | ||
1335 | 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, | ||
1336 | 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, | ||
1337 | 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, | ||
1338 | 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, | ||
1339 | 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, | ||
1340 | }, | ||
1341 | }; | ||
1342 | #endif | ||
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index fcbe48a09cf8..e8175e7938ed 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c | |||
@@ -30,38 +30,47 @@ | |||
30 | 30 | ||
31 | const struct vpdma_data_format vpdma_yuv_fmts[] = { | 31 | const struct vpdma_data_format vpdma_yuv_fmts[] = { |
32 | [VPDMA_DATA_FMT_Y444] = { | 32 | [VPDMA_DATA_FMT_Y444] = { |
33 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
33 | .data_type = DATA_TYPE_Y444, | 34 | .data_type = DATA_TYPE_Y444, |
34 | .depth = 8, | 35 | .depth = 8, |
35 | }, | 36 | }, |
36 | [VPDMA_DATA_FMT_Y422] = { | 37 | [VPDMA_DATA_FMT_Y422] = { |
38 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
37 | .data_type = DATA_TYPE_Y422, | 39 | .data_type = DATA_TYPE_Y422, |
38 | .depth = 8, | 40 | .depth = 8, |
39 | }, | 41 | }, |
40 | [VPDMA_DATA_FMT_Y420] = { | 42 | [VPDMA_DATA_FMT_Y420] = { |
43 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
41 | .data_type = DATA_TYPE_Y420, | 44 | .data_type = DATA_TYPE_Y420, |
42 | .depth = 8, | 45 | .depth = 8, |
43 | }, | 46 | }, |
44 | [VPDMA_DATA_FMT_C444] = { | 47 | [VPDMA_DATA_FMT_C444] = { |
48 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
45 | .data_type = DATA_TYPE_C444, | 49 | .data_type = DATA_TYPE_C444, |
46 | .depth = 8, | 50 | .depth = 8, |
47 | }, | 51 | }, |
48 | [VPDMA_DATA_FMT_C422] = { | 52 | [VPDMA_DATA_FMT_C422] = { |
53 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
49 | .data_type = DATA_TYPE_C422, | 54 | .data_type = DATA_TYPE_C422, |
50 | .depth = 8, | 55 | .depth = 8, |
51 | }, | 56 | }, |
52 | [VPDMA_DATA_FMT_C420] = { | 57 | [VPDMA_DATA_FMT_C420] = { |
58 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
53 | .data_type = DATA_TYPE_C420, | 59 | .data_type = DATA_TYPE_C420, |
54 | .depth = 4, | 60 | .depth = 4, |
55 | }, | 61 | }, |
56 | [VPDMA_DATA_FMT_YC422] = { | 62 | [VPDMA_DATA_FMT_YC422] = { |
63 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
57 | .data_type = DATA_TYPE_YC422, | 64 | .data_type = DATA_TYPE_YC422, |
58 | .depth = 16, | 65 | .depth = 16, |
59 | }, | 66 | }, |
60 | [VPDMA_DATA_FMT_YC444] = { | 67 | [VPDMA_DATA_FMT_YC444] = { |
68 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
61 | .data_type = DATA_TYPE_YC444, | 69 | .data_type = DATA_TYPE_YC444, |
62 | .depth = 24, | 70 | .depth = 24, |
63 | }, | 71 | }, |
64 | [VPDMA_DATA_FMT_CY422] = { | 72 | [VPDMA_DATA_FMT_CY422] = { |
73 | .type = VPDMA_DATA_FMT_TYPE_YUV, | ||
65 | .data_type = DATA_TYPE_CY422, | 74 | .data_type = DATA_TYPE_CY422, |
66 | .depth = 16, | 75 | .depth = 16, |
67 | }, | 76 | }, |
@@ -69,82 +78,102 @@ const struct vpdma_data_format vpdma_yuv_fmts[] = { | |||
69 | 78 | ||
70 | const struct vpdma_data_format vpdma_rgb_fmts[] = { | 79 | const struct vpdma_data_format vpdma_rgb_fmts[] = { |
71 | [VPDMA_DATA_FMT_RGB565] = { | 80 | [VPDMA_DATA_FMT_RGB565] = { |
81 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
72 | .data_type = DATA_TYPE_RGB16_565, | 82 | .data_type = DATA_TYPE_RGB16_565, |
73 | .depth = 16, | 83 | .depth = 16, |
74 | }, | 84 | }, |
75 | [VPDMA_DATA_FMT_ARGB16_1555] = { | 85 | [VPDMA_DATA_FMT_ARGB16_1555] = { |
86 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
76 | .data_type = DATA_TYPE_ARGB_1555, | 87 | .data_type = DATA_TYPE_ARGB_1555, |
77 | .depth = 16, | 88 | .depth = 16, |
78 | }, | 89 | }, |
79 | [VPDMA_DATA_FMT_ARGB16] = { | 90 | [VPDMA_DATA_FMT_ARGB16] = { |
91 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
80 | .data_type = DATA_TYPE_ARGB_4444, | 92 | .data_type = DATA_TYPE_ARGB_4444, |
81 | .depth = 16, | 93 | .depth = 16, |
82 | }, | 94 | }, |
83 | [VPDMA_DATA_FMT_RGBA16_5551] = { | 95 | [VPDMA_DATA_FMT_RGBA16_5551] = { |
96 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
84 | .data_type = DATA_TYPE_RGBA_5551, | 97 | .data_type = DATA_TYPE_RGBA_5551, |
85 | .depth = 16, | 98 | .depth = 16, |
86 | }, | 99 | }, |
87 | [VPDMA_DATA_FMT_RGBA16] = { | 100 | [VPDMA_DATA_FMT_RGBA16] = { |
101 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
88 | .data_type = DATA_TYPE_RGBA_4444, | 102 | .data_type = DATA_TYPE_RGBA_4444, |
89 | .depth = 16, | 103 | .depth = 16, |
90 | }, | 104 | }, |
91 | [VPDMA_DATA_FMT_ARGB24] = { | 105 | [VPDMA_DATA_FMT_ARGB24] = { |
106 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
92 | .data_type = DATA_TYPE_ARGB24_6666, | 107 | .data_type = DATA_TYPE_ARGB24_6666, |
93 | .depth = 24, | 108 | .depth = 24, |
94 | }, | 109 | }, |
95 | [VPDMA_DATA_FMT_RGB24] = { | 110 | [VPDMA_DATA_FMT_RGB24] = { |
111 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
96 | .data_type = DATA_TYPE_RGB24_888, | 112 | .data_type = DATA_TYPE_RGB24_888, |
97 | .depth = 24, | 113 | .depth = 24, |
98 | }, | 114 | }, |
99 | [VPDMA_DATA_FMT_ARGB32] = { | 115 | [VPDMA_DATA_FMT_ARGB32] = { |
116 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
100 | .data_type = DATA_TYPE_ARGB32_8888, | 117 | .data_type = DATA_TYPE_ARGB32_8888, |
101 | .depth = 32, | 118 | .depth = 32, |
102 | }, | 119 | }, |
103 | [VPDMA_DATA_FMT_RGBA24] = { | 120 | [VPDMA_DATA_FMT_RGBA24] = { |
121 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
104 | .data_type = DATA_TYPE_RGBA24_6666, | 122 | .data_type = DATA_TYPE_RGBA24_6666, |
105 | .depth = 24, | 123 | .depth = 24, |
106 | }, | 124 | }, |
107 | [VPDMA_DATA_FMT_RGBA32] = { | 125 | [VPDMA_DATA_FMT_RGBA32] = { |
126 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
108 | .data_type = DATA_TYPE_RGBA32_8888, | 127 | .data_type = DATA_TYPE_RGBA32_8888, |
109 | .depth = 32, | 128 | .depth = 32, |
110 | }, | 129 | }, |
111 | [VPDMA_DATA_FMT_BGR565] = { | 130 | [VPDMA_DATA_FMT_BGR565] = { |
131 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
112 | .data_type = DATA_TYPE_BGR16_565, | 132 | .data_type = DATA_TYPE_BGR16_565, |
113 | .depth = 16, | 133 | .depth = 16, |
114 | }, | 134 | }, |
115 | [VPDMA_DATA_FMT_ABGR16_1555] = { | 135 | [VPDMA_DATA_FMT_ABGR16_1555] = { |
136 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
116 | .data_type = DATA_TYPE_ABGR_1555, | 137 | .data_type = DATA_TYPE_ABGR_1555, |
117 | .depth = 16, | 138 | .depth = 16, |
118 | }, | 139 | }, |
119 | [VPDMA_DATA_FMT_ABGR16] = { | 140 | [VPDMA_DATA_FMT_ABGR16] = { |
141 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
120 | .data_type = DATA_TYPE_ABGR_4444, | 142 | .data_type = DATA_TYPE_ABGR_4444, |
121 | .depth = 16, | 143 | .depth = 16, |
122 | }, | 144 | }, |
123 | [VPDMA_DATA_FMT_BGRA16_5551] = { | 145 | [VPDMA_DATA_FMT_BGRA16_5551] = { |
146 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
124 | .data_type = DATA_TYPE_BGRA_5551, | 147 | .data_type = DATA_TYPE_BGRA_5551, |
125 | .depth = 16, | 148 | .depth = 16, |
126 | }, | 149 | }, |
127 | [VPDMA_DATA_FMT_BGRA16] = { | 150 | [VPDMA_DATA_FMT_BGRA16] = { |
151 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
128 | .data_type = DATA_TYPE_BGRA_4444, | 152 | .data_type = DATA_TYPE_BGRA_4444, |
129 | .depth = 16, | 153 | .depth = 16, |
130 | }, | 154 | }, |
131 | [VPDMA_DATA_FMT_ABGR24] = { | 155 | [VPDMA_DATA_FMT_ABGR24] = { |
156 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
132 | .data_type = DATA_TYPE_ABGR24_6666, | 157 | .data_type = DATA_TYPE_ABGR24_6666, |
133 | .depth = 24, | 158 | .depth = 24, |
134 | }, | 159 | }, |
135 | [VPDMA_DATA_FMT_BGR24] = { | 160 | [VPDMA_DATA_FMT_BGR24] = { |
161 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
136 | .data_type = DATA_TYPE_BGR24_888, | 162 | .data_type = DATA_TYPE_BGR24_888, |
137 | .depth = 24, | 163 | .depth = 24, |
138 | }, | 164 | }, |
139 | [VPDMA_DATA_FMT_ABGR32] = { | 165 | [VPDMA_DATA_FMT_ABGR32] = { |
166 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
140 | .data_type = DATA_TYPE_ABGR32_8888, | 167 | .data_type = DATA_TYPE_ABGR32_8888, |
141 | .depth = 32, | 168 | .depth = 32, |
142 | }, | 169 | }, |
143 | [VPDMA_DATA_FMT_BGRA24] = { | 170 | [VPDMA_DATA_FMT_BGRA24] = { |
171 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
144 | .data_type = DATA_TYPE_BGRA24_6666, | 172 | .data_type = DATA_TYPE_BGRA24_6666, |
145 | .depth = 24, | 173 | .depth = 24, |
146 | }, | 174 | }, |
147 | [VPDMA_DATA_FMT_BGRA32] = { | 175 | [VPDMA_DATA_FMT_BGRA32] = { |
176 | .type = VPDMA_DATA_FMT_TYPE_RGB, | ||
148 | .data_type = DATA_TYPE_BGRA32_8888, | 177 | .data_type = DATA_TYPE_BGRA32_8888, |
149 | .depth = 32, | 178 | .depth = 32, |
150 | }, | 179 | }, |
@@ -152,6 +181,7 @@ const struct vpdma_data_format vpdma_rgb_fmts[] = { | |||
152 | 181 | ||
153 | const struct vpdma_data_format vpdma_misc_fmts[] = { | 182 | const struct vpdma_data_format vpdma_misc_fmts[] = { |
154 | [VPDMA_DATA_FMT_MV] = { | 183 | [VPDMA_DATA_FMT_MV] = { |
184 | .type = VPDMA_DATA_FMT_TYPE_MISC, | ||
155 | .data_type = DATA_TYPE_MV, | 185 | .data_type = DATA_TYPE_MV, |
156 | .depth = 4, | 186 | .depth = 4, |
157 | }, | 187 | }, |
@@ -599,10 +629,11 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect, | |||
599 | 629 | ||
600 | channel = next_chan = chan_info[chan].num; | 630 | channel = next_chan = chan_info[chan].num; |
601 | 631 | ||
602 | if (fmt->data_type == DATA_TYPE_C420) | 632 | if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && |
633 | fmt->data_type == DATA_TYPE_C420) | ||
603 | depth = 8; | 634 | depth = 8; |
604 | 635 | ||
605 | stride = (depth * c_rect->width) >> 3; | 636 | stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN); |
606 | dma_addr += (c_rect->left * depth) >> 3; | 637 | dma_addr += (c_rect->left * depth) >> 3; |
607 | 638 | ||
608 | dtd = list->next; | 639 | dtd = list->next; |
@@ -649,13 +680,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width, | |||
649 | 680 | ||
650 | channel = next_chan = chan_info[chan].num; | 681 | channel = next_chan = chan_info[chan].num; |
651 | 682 | ||
652 | if (fmt->data_type == DATA_TYPE_C420) { | 683 | if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && |
684 | fmt->data_type == DATA_TYPE_C420) { | ||
653 | height >>= 1; | 685 | height >>= 1; |
654 | frame_height >>= 1; | 686 | frame_height >>= 1; |
655 | depth = 8; | 687 | depth = 8; |
656 | } | 688 | } |
657 | 689 | ||
658 | stride = (depth * c_rect->width) >> 3; | 690 | stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN); |
659 | dma_addr += (c_rect->left * depth) >> 3; | 691 | dma_addr += (c_rect->left * depth) >> 3; |
660 | 692 | ||
661 | dtd = list->next; | 693 | dtd = list->next; |
diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index eaa2a71a5db9..cf40f11b3c8f 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h | |||
@@ -39,13 +39,23 @@ struct vpdma_data { | |||
39 | bool ready; | 39 | bool ready; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | enum vpdma_data_format_type { | ||
43 | VPDMA_DATA_FMT_TYPE_YUV, | ||
44 | VPDMA_DATA_FMT_TYPE_RGB, | ||
45 | VPDMA_DATA_FMT_TYPE_MISC, | ||
46 | }; | ||
47 | |||
42 | struct vpdma_data_format { | 48 | struct vpdma_data_format { |
49 | enum vpdma_data_format_type type; | ||
43 | int data_type; | 50 | int data_type; |
44 | u8 depth; | 51 | u8 depth; |
45 | }; | 52 | }; |
46 | 53 | ||
47 | #define VPDMA_DESC_ALIGN 16 /* 16-byte descriptor alignment */ | 54 | #define VPDMA_DESC_ALIGN 16 /* 16-byte descriptor alignment */ |
48 | 55 | #define VPDMA_STRIDE_ALIGN 16 /* | |
56 | * line stride of source and dest | ||
57 | * buffers should be 16 byte aligned | ||
58 | */ | ||
49 | #define VPDMA_DTD_DESC_SIZE 32 /* 8 words */ | 59 | #define VPDMA_DTD_DESC_SIZE 32 /* 8 words */ |
50 | #define VPDMA_CFD_CTD_DESC_SIZE 16 /* 4 words */ | 60 | #define VPDMA_CFD_CTD_DESC_SIZE 16 /* 4 words */ |
51 | 61 | ||
diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index f0e9a8038c1b..c1a6ce1884f3 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h | |||
@@ -78,7 +78,7 @@ | |||
78 | #define DATA_TYPE_C420 0x6 | 78 | #define DATA_TYPE_C420 0x6 |
79 | #define DATA_TYPE_YC422 0x7 | 79 | #define DATA_TYPE_YC422 0x7 |
80 | #define DATA_TYPE_YC444 0x8 | 80 | #define DATA_TYPE_YC444 0x8 |
81 | #define DATA_TYPE_CY422 0x23 | 81 | #define DATA_TYPE_CY422 0x27 |
82 | 82 | ||
83 | #define DATA_TYPE_RGB16_565 0x0 | 83 | #define DATA_TYPE_RGB16_565 0x0 |
84 | #define DATA_TYPE_ARGB_1555 0x1 | 84 | #define DATA_TYPE_ARGB_1555 0x1 |
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 4e58069e24ff..1296c5386231 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/sched.h> | 30 | #include <linux/sched.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/videodev2.h> | 32 | #include <linux/videodev2.h> |
33 | #include <linux/log2.h> | ||
33 | 34 | ||
34 | #include <media/v4l2-common.h> | 35 | #include <media/v4l2-common.h> |
35 | #include <media/v4l2-ctrls.h> | 36 | #include <media/v4l2-ctrls.h> |
@@ -42,6 +43,8 @@ | |||
42 | 43 | ||
43 | #include "vpdma.h" | 44 | #include "vpdma.h" |
44 | #include "vpe_regs.h" | 45 | #include "vpe_regs.h" |
46 | #include "sc.h" | ||
47 | #include "csc.h" | ||
45 | 48 | ||
46 | #define VPE_MODULE_NAME "vpe" | 49 | #define VPE_MODULE_NAME "vpe" |
47 | 50 | ||
@@ -54,10 +57,6 @@ | |||
54 | /* required alignments */ | 57 | /* required alignments */ |
55 | #define S_ALIGN 0 /* multiple of 1 */ | 58 | #define S_ALIGN 0 /* multiple of 1 */ |
56 | #define H_ALIGN 1 /* multiple of 2 */ | 59 | #define H_ALIGN 1 /* multiple of 2 */ |
57 | #define W_ALIGN 1 /* multiple of 2 */ | ||
58 | |||
59 | /* multiple of 128 bits, line stride, 16 bytes */ | ||
60 | #define L_ALIGN 4 | ||
61 | 60 | ||
62 | /* flags that indicate a format can be used for capture/output */ | 61 | /* flags that indicate a format can be used for capture/output */ |
63 | #define VPE_FMT_TYPE_CAPTURE (1 << 0) | 62 | #define VPE_FMT_TYPE_CAPTURE (1 << 0) |
@@ -268,6 +267,38 @@ static struct vpe_fmt vpe_formats[] = { | |||
268 | .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CY422], | 267 | .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CY422], |
269 | }, | 268 | }, |
270 | }, | 269 | }, |
270 | { | ||
271 | .name = "RGB888 packed", | ||
272 | .fourcc = V4L2_PIX_FMT_RGB24, | ||
273 | .types = VPE_FMT_TYPE_CAPTURE, | ||
274 | .coplanar = 0, | ||
275 | .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB24], | ||
276 | }, | ||
277 | }, | ||
278 | { | ||
279 | .name = "ARGB32", | ||
280 | .fourcc = V4L2_PIX_FMT_RGB32, | ||
281 | .types = VPE_FMT_TYPE_CAPTURE, | ||
282 | .coplanar = 0, | ||
283 | .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ARGB32], | ||
284 | }, | ||
285 | }, | ||
286 | { | ||
287 | .name = "BGR888 packed", | ||
288 | .fourcc = V4L2_PIX_FMT_BGR24, | ||
289 | .types = VPE_FMT_TYPE_CAPTURE, | ||
290 | .coplanar = 0, | ||
291 | .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_BGR24], | ||
292 | }, | ||
293 | }, | ||
294 | { | ||
295 | .name = "ABGR32", | ||
296 | .fourcc = V4L2_PIX_FMT_BGR32, | ||
297 | .types = VPE_FMT_TYPE_CAPTURE, | ||
298 | .coplanar = 0, | ||
299 | .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ABGR32], | ||
300 | }, | ||
301 | }, | ||
271 | }; | 302 | }; |
272 | 303 | ||
273 | /* | 304 | /* |
@@ -327,9 +358,12 @@ struct vpe_dev { | |||
327 | 358 | ||
328 | int irq; | 359 | int irq; |
329 | void __iomem *base; | 360 | void __iomem *base; |
361 | struct resource *res; | ||
330 | 362 | ||
331 | struct vb2_alloc_ctx *alloc_ctx; | 363 | struct vb2_alloc_ctx *alloc_ctx; |
332 | struct vpdma_data *vpdma; /* vpdma data handle */ | 364 | struct vpdma_data *vpdma; /* vpdma data handle */ |
365 | struct sc_data *sc; /* scaler data handle */ | ||
366 | struct csc_data *csc; /* csc data handle */ | ||
333 | }; | 367 | }; |
334 | 368 | ||
335 | /* | 369 | /* |
@@ -356,6 +390,8 @@ struct vpe_ctx { | |||
356 | void *mv_buf[2]; /* virtual addrs of motion vector bufs */ | 390 | void *mv_buf[2]; /* virtual addrs of motion vector bufs */ |
357 | size_t mv_buf_size; /* current motion vector buffer size */ | 391 | size_t mv_buf_size; /* current motion vector buffer size */ |
358 | struct vpdma_buf mmr_adb; /* shadow reg addr/data block */ | 392 | struct vpdma_buf mmr_adb; /* shadow reg addr/data block */ |
393 | struct vpdma_buf sc_coeff_h; /* h coeff buffer */ | ||
394 | struct vpdma_buf sc_coeff_v; /* v coeff buffer */ | ||
359 | struct vpdma_desc_list desc_list; /* DMA descriptor list */ | 395 | struct vpdma_desc_list desc_list; /* DMA descriptor list */ |
360 | 396 | ||
361 | bool deinterlacing; /* using de-interlacer */ | 397 | bool deinterlacing; /* using de-interlacer */ |
@@ -438,14 +474,23 @@ struct vpe_mmr_adb { | |||
438 | u32 us3_regs[8]; | 474 | u32 us3_regs[8]; |
439 | struct vpdma_adb_hdr dei_hdr; | 475 | struct vpdma_adb_hdr dei_hdr; |
440 | u32 dei_regs[8]; | 476 | u32 dei_regs[8]; |
441 | struct vpdma_adb_hdr sc_hdr; | 477 | struct vpdma_adb_hdr sc_hdr0; |
442 | u32 sc_regs[1]; | 478 | u32 sc_regs0[7]; |
443 | u32 sc_pad[3]; | 479 | u32 sc_pad0[1]; |
480 | struct vpdma_adb_hdr sc_hdr8; | ||
481 | u32 sc_regs8[6]; | ||
482 | u32 sc_pad8[2]; | ||
483 | struct vpdma_adb_hdr sc_hdr17; | ||
484 | u32 sc_regs17[9]; | ||
485 | u32 sc_pad17[3]; | ||
444 | struct vpdma_adb_hdr csc_hdr; | 486 | struct vpdma_adb_hdr csc_hdr; |
445 | u32 csc_regs[6]; | 487 | u32 csc_regs[6]; |
446 | u32 csc_pad[2]; | 488 | u32 csc_pad[2]; |
447 | }; | 489 | }; |
448 | 490 | ||
491 | #define GET_OFFSET_TOP(ctx, obj, reg) \ | ||
492 | ((obj)->res->start - ctx->dev->res->start + reg) | ||
493 | |||
449 | #define VPE_SET_MMR_ADB_HDR(ctx, hdr, regs, offset_a) \ | 494 | #define VPE_SET_MMR_ADB_HDR(ctx, hdr, regs, offset_a) \ |
450 | VPDMA_SET_MMR_ADB_HDR(ctx->mmr_adb, vpe_mmr_adb, hdr, regs, offset_a) | 495 | VPDMA_SET_MMR_ADB_HDR(ctx->mmr_adb, vpe_mmr_adb, hdr, regs, offset_a) |
451 | /* | 496 | /* |
@@ -458,8 +503,14 @@ static void init_adb_hdrs(struct vpe_ctx *ctx) | |||
458 | VPE_SET_MMR_ADB_HDR(ctx, us2_hdr, us2_regs, VPE_US2_R0); | 503 | VPE_SET_MMR_ADB_HDR(ctx, us2_hdr, us2_regs, VPE_US2_R0); |
459 | VPE_SET_MMR_ADB_HDR(ctx, us3_hdr, us3_regs, VPE_US3_R0); | 504 | VPE_SET_MMR_ADB_HDR(ctx, us3_hdr, us3_regs, VPE_US3_R0); |
460 | VPE_SET_MMR_ADB_HDR(ctx, dei_hdr, dei_regs, VPE_DEI_FRAME_SIZE); | 505 | VPE_SET_MMR_ADB_HDR(ctx, dei_hdr, dei_regs, VPE_DEI_FRAME_SIZE); |
461 | VPE_SET_MMR_ADB_HDR(ctx, sc_hdr, sc_regs, VPE_SC_MP_SC0); | 506 | VPE_SET_MMR_ADB_HDR(ctx, sc_hdr0, sc_regs0, |
462 | VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs, VPE_CSC_CSC00); | 507 | GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC0)); |
508 | VPE_SET_MMR_ADB_HDR(ctx, sc_hdr8, sc_regs8, | ||
509 | GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC8)); | ||
510 | VPE_SET_MMR_ADB_HDR(ctx, sc_hdr17, sc_regs17, | ||
511 | GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC17)); | ||
512 | VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs, | ||
513 | GET_OFFSET_TOP(ctx, ctx->dev->csc, CSC_CSC00)); | ||
463 | }; | 514 | }; |
464 | 515 | ||
465 | /* | 516 | /* |
@@ -670,17 +721,20 @@ static void set_src_registers(struct vpe_ctx *ctx) | |||
670 | static void set_dst_registers(struct vpe_ctx *ctx) | 721 | static void set_dst_registers(struct vpe_ctx *ctx) |
671 | { | 722 | { |
672 | struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; | 723 | struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; |
724 | enum v4l2_colorspace clrspc = ctx->q_data[Q_DATA_DST].colorspace; | ||
673 | struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt; | 725 | struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt; |
674 | u32 val = 0; | 726 | u32 val = 0; |
675 | 727 | ||
676 | /* select RGB path when color space conversion is supported in future */ | 728 | if (clrspc == V4L2_COLORSPACE_SRGB) |
677 | if (fmt->fourcc == V4L2_PIX_FMT_RGB24) | 729 | val |= VPE_RGB_OUT_SELECT; |
678 | val |= VPE_RGB_OUT_SELECT | VPE_CSC_SRC_DEI_SCALER; | ||
679 | else if (fmt->fourcc == V4L2_PIX_FMT_NV16) | 730 | else if (fmt->fourcc == V4L2_PIX_FMT_NV16) |
680 | val |= VPE_COLOR_SEPARATE_422; | 731 | val |= VPE_COLOR_SEPARATE_422; |
681 | 732 | ||
682 | /* The source of CHR_DS is always the scaler, whether it's used or not */ | 733 | /* |
683 | val |= VPE_DS_SRC_DEI_SCALER; | 734 | * the source of CHR_DS and CSC is always the scaler, irrespective of |
735 | * whether it's used or not | ||
736 | */ | ||
737 | val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER; | ||
684 | 738 | ||
685 | if (fmt->fourcc != V4L2_PIX_FMT_NV12) | 739 | if (fmt->fourcc != V4L2_PIX_FMT_NV12) |
686 | val |= VPE_DS_BYPASS; | 740 | val |= VPE_DS_BYPASS; |
@@ -742,28 +796,6 @@ static void set_dei_shadow_registers(struct vpe_ctx *ctx) | |||
742 | ctx->load_mmrs = true; | 796 | ctx->load_mmrs = true; |
743 | } | 797 | } |
744 | 798 | ||
745 | static void set_csc_coeff_bypass(struct vpe_ctx *ctx) | ||
746 | { | ||
747 | struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; | ||
748 | u32 *shadow_csc_reg5 = &mmr_adb->csc_regs[5]; | ||
749 | |||
750 | *shadow_csc_reg5 |= VPE_CSC_BYPASS; | ||
751 | |||
752 | ctx->load_mmrs = true; | ||
753 | } | ||
754 | |||
755 | static void set_sc_regs_bypass(struct vpe_ctx *ctx) | ||
756 | { | ||
757 | struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; | ||
758 | u32 *sc_reg0 = &mmr_adb->sc_regs[0]; | ||
759 | u32 val = 0; | ||
760 | |||
761 | val |= VPE_SC_BYPASS; | ||
762 | *sc_reg0 = val; | ||
763 | |||
764 | ctx->load_mmrs = true; | ||
765 | } | ||
766 | |||
767 | /* | 799 | /* |
768 | * Set the shadow registers whose values are modified when either the | 800 | * Set the shadow registers whose values are modified when either the |
769 | * source or destination format is changed. | 801 | * source or destination format is changed. |
@@ -772,6 +804,11 @@ static int set_srcdst_params(struct vpe_ctx *ctx) | |||
772 | { | 804 | { |
773 | struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; | 805 | struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; |
774 | struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; | 806 | struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; |
807 | struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; | ||
808 | unsigned int src_w = s_q_data->c_rect.width; | ||
809 | unsigned int src_h = s_q_data->c_rect.height; | ||
810 | unsigned int dst_w = d_q_data->c_rect.width; | ||
811 | unsigned int dst_h = d_q_data->c_rect.height; | ||
775 | size_t mv_buf_size; | 812 | size_t mv_buf_size; |
776 | int ret; | 813 | int ret; |
777 | 814 | ||
@@ -780,12 +817,23 @@ static int set_srcdst_params(struct vpe_ctx *ctx) | |||
780 | 817 | ||
781 | if ((s_q_data->flags & Q_DATA_INTERLACED) && | 818 | if ((s_q_data->flags & Q_DATA_INTERLACED) && |
782 | !(d_q_data->flags & Q_DATA_INTERLACED)) { | 819 | !(d_q_data->flags & Q_DATA_INTERLACED)) { |
820 | int bytes_per_line; | ||
783 | const struct vpdma_data_format *mv = | 821 | const struct vpdma_data_format *mv = |
784 | &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; | 822 | &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; |
785 | 823 | ||
824 | /* | ||
825 | * we make sure that the source image has a 16 byte aligned | ||
826 | * stride, we need to do the same for the motion vector buffer | ||
827 | * by aligning it's stride to the next 16 byte boundry. this | ||
828 | * extra space will not be used by the de-interlacer, but will | ||
829 | * ensure that vpdma operates correctly | ||
830 | */ | ||
831 | bytes_per_line = ALIGN((s_q_data->width * mv->depth) >> 3, | ||
832 | VPDMA_STRIDE_ALIGN); | ||
833 | mv_buf_size = bytes_per_line * s_q_data->height; | ||
834 | |||
786 | ctx->deinterlacing = 1; | 835 | ctx->deinterlacing = 1; |
787 | mv_buf_size = | 836 | src_h <<= 1; |
788 | (s_q_data->width * s_q_data->height * mv->depth) >> 3; | ||
789 | } else { | 837 | } else { |
790 | ctx->deinterlacing = 0; | 838 | ctx->deinterlacing = 0; |
791 | mv_buf_size = 0; | 839 | mv_buf_size = 0; |
@@ -799,8 +847,16 @@ static int set_srcdst_params(struct vpe_ctx *ctx) | |||
799 | 847 | ||
800 | set_cfg_and_line_modes(ctx); | 848 | set_cfg_and_line_modes(ctx); |
801 | set_dei_regs(ctx); | 849 | set_dei_regs(ctx); |
802 | set_csc_coeff_bypass(ctx); | 850 | |
803 | set_sc_regs_bypass(ctx); | 851 | csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0], |
852 | s_q_data->colorspace, d_q_data->colorspace); | ||
853 | |||
854 | sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w); | ||
855 | sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h); | ||
856 | |||
857 | sc_config_scaler(ctx->dev->sc, &mmr_adb->sc_regs0[0], | ||
858 | &mmr_adb->sc_regs8[0], &mmr_adb->sc_regs17[0], | ||
859 | src_w, src_h, dst_w, dst_h); | ||
804 | 860 | ||
805 | return 0; | 861 | return 0; |
806 | } | 862 | } |
@@ -916,35 +972,10 @@ static void vpe_dump_regs(struct vpe_dev *dev) | |||
916 | DUMPREG(DEI_FMD_STATUS_R0); | 972 | DUMPREG(DEI_FMD_STATUS_R0); |
917 | DUMPREG(DEI_FMD_STATUS_R1); | 973 | DUMPREG(DEI_FMD_STATUS_R1); |
918 | DUMPREG(DEI_FMD_STATUS_R2); | 974 | DUMPREG(DEI_FMD_STATUS_R2); |
919 | DUMPREG(SC_MP_SC0); | ||
920 | DUMPREG(SC_MP_SC1); | ||
921 | DUMPREG(SC_MP_SC2); | ||
922 | DUMPREG(SC_MP_SC3); | ||
923 | DUMPREG(SC_MP_SC4); | ||
924 | DUMPREG(SC_MP_SC5); | ||
925 | DUMPREG(SC_MP_SC6); | ||
926 | DUMPREG(SC_MP_SC8); | ||
927 | DUMPREG(SC_MP_SC9); | ||
928 | DUMPREG(SC_MP_SC10); | ||
929 | DUMPREG(SC_MP_SC11); | ||
930 | DUMPREG(SC_MP_SC12); | ||
931 | DUMPREG(SC_MP_SC13); | ||
932 | DUMPREG(SC_MP_SC17); | ||
933 | DUMPREG(SC_MP_SC18); | ||
934 | DUMPREG(SC_MP_SC19); | ||
935 | DUMPREG(SC_MP_SC20); | ||
936 | DUMPREG(SC_MP_SC21); | ||
937 | DUMPREG(SC_MP_SC22); | ||
938 | DUMPREG(SC_MP_SC23); | ||
939 | DUMPREG(SC_MP_SC24); | ||
940 | DUMPREG(SC_MP_SC25); | ||
941 | DUMPREG(CSC_CSC00); | ||
942 | DUMPREG(CSC_CSC01); | ||
943 | DUMPREG(CSC_CSC02); | ||
944 | DUMPREG(CSC_CSC03); | ||
945 | DUMPREG(CSC_CSC04); | ||
946 | DUMPREG(CSC_CSC05); | ||
947 | #undef DUMPREG | 975 | #undef DUMPREG |
976 | |||
977 | sc_dump_regs(dev->sc); | ||
978 | csc_dump_regs(dev->csc); | ||
948 | } | 979 | } |
949 | 980 | ||
950 | static void add_out_dtd(struct vpe_ctx *ctx, int port) | 981 | static void add_out_dtd(struct vpe_ctx *ctx, int port) |
@@ -1053,6 +1084,7 @@ static void disable_irqs(struct vpe_ctx *ctx) | |||
1053 | static void device_run(void *priv) | 1084 | static void device_run(void *priv) |
1054 | { | 1085 | { |
1055 | struct vpe_ctx *ctx = priv; | 1086 | struct vpe_ctx *ctx = priv; |
1087 | struct sc_data *sc = ctx->dev->sc; | ||
1056 | struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; | 1088 | struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; |
1057 | 1089 | ||
1058 | if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) { | 1090 | if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) { |
@@ -1075,13 +1107,37 @@ static void device_run(void *priv) | |||
1075 | ctx->load_mmrs = false; | 1107 | ctx->load_mmrs = false; |
1076 | } | 1108 | } |
1077 | 1109 | ||
1110 | if (sc->loaded_coeff_h != ctx->sc_coeff_h.dma_addr || | ||
1111 | sc->load_coeff_h) { | ||
1112 | vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_h); | ||
1113 | vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT, | ||
1114 | &ctx->sc_coeff_h, 0); | ||
1115 | |||
1116 | sc->loaded_coeff_h = ctx->sc_coeff_h.dma_addr; | ||
1117 | sc->load_coeff_h = false; | ||
1118 | } | ||
1119 | |||
1120 | if (sc->loaded_coeff_v != ctx->sc_coeff_v.dma_addr || | ||
1121 | sc->load_coeff_v) { | ||
1122 | vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_v); | ||
1123 | vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT, | ||
1124 | &ctx->sc_coeff_v, SC_COEF_SRAM_SIZE >> 4); | ||
1125 | |||
1126 | sc->loaded_coeff_v = ctx->sc_coeff_v.dma_addr; | ||
1127 | sc->load_coeff_v = false; | ||
1128 | } | ||
1129 | |||
1078 | /* output data descriptors */ | 1130 | /* output data descriptors */ |
1079 | if (ctx->deinterlacing) | 1131 | if (ctx->deinterlacing) |
1080 | add_out_dtd(ctx, VPE_PORT_MV_OUT); | 1132 | add_out_dtd(ctx, VPE_PORT_MV_OUT); |
1081 | 1133 | ||
1082 | add_out_dtd(ctx, VPE_PORT_LUMA_OUT); | 1134 | if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) { |
1083 | if (d_q_data->fmt->coplanar) | 1135 | add_out_dtd(ctx, VPE_PORT_RGB_OUT); |
1084 | add_out_dtd(ctx, VPE_PORT_CHROMA_OUT); | 1136 | } else { |
1137 | add_out_dtd(ctx, VPE_PORT_LUMA_OUT); | ||
1138 | if (d_q_data->fmt->coplanar) | ||
1139 | add_out_dtd(ctx, VPE_PORT_CHROMA_OUT); | ||
1140 | } | ||
1085 | 1141 | ||
1086 | /* input data descriptors */ | 1142 | /* input data descriptors */ |
1087 | if (ctx->deinterlacing) { | 1143 | if (ctx->deinterlacing) { |
@@ -1117,9 +1173,16 @@ static void device_run(void *priv) | |||
1117 | } | 1173 | } |
1118 | 1174 | ||
1119 | /* sync on channel control descriptors for output ports */ | 1175 | /* sync on channel control descriptors for output ports */ |
1120 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_LUMA_OUT); | 1176 | if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) { |
1121 | if (d_q_data->fmt->coplanar) | 1177 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, |
1122 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_CHROMA_OUT); | 1178 | VPE_CHAN_RGB_OUT); |
1179 | } else { | ||
1180 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, | ||
1181 | VPE_CHAN_LUMA_OUT); | ||
1182 | if (d_q_data->fmt->coplanar) | ||
1183 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, | ||
1184 | VPE_CHAN_CHROMA_OUT); | ||
1185 | } | ||
1123 | 1186 | ||
1124 | if (ctx->deinterlacing) | 1187 | if (ctx->deinterlacing) |
1125 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_OUT); | 1188 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_OUT); |
@@ -1198,6 +1261,8 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) | |||
1198 | 1261 | ||
1199 | vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); | 1262 | vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); |
1200 | vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb); | 1263 | vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb); |
1264 | vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h); | ||
1265 | vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v); | ||
1201 | 1266 | ||
1202 | vpdma_reset_desc_list(&ctx->desc_list); | 1267 | vpdma_reset_desc_list(&ctx->desc_list); |
1203 | 1268 | ||
@@ -1352,7 +1417,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, | |||
1352 | { | 1417 | { |
1353 | struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; | 1418 | struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; |
1354 | struct v4l2_plane_pix_format *plane_fmt; | 1419 | struct v4l2_plane_pix_format *plane_fmt; |
1355 | int i; | 1420 | unsigned int w_align; |
1421 | int i, depth, depth_bytes; | ||
1356 | 1422 | ||
1357 | if (!fmt || !(fmt->types & type)) { | 1423 | if (!fmt || !(fmt->types & type)) { |
1358 | vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n", | 1424 | vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n", |
@@ -1363,35 +1429,57 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, | |||
1363 | if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE) | 1429 | if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE) |
1364 | pix->field = V4L2_FIELD_NONE; | 1430 | pix->field = V4L2_FIELD_NONE; |
1365 | 1431 | ||
1366 | v4l_bound_align_image(&pix->width, MIN_W, MAX_W, W_ALIGN, | 1432 | depth = fmt->vpdma_fmt[VPE_LUMA]->depth; |
1433 | |||
1434 | /* | ||
1435 | * the line stride should 16 byte aligned for VPDMA to work, based on | ||
1436 | * the bytes per pixel, figure out how much the width should be aligned | ||
1437 | * to make sure line stride is 16 byte aligned | ||
1438 | */ | ||
1439 | depth_bytes = depth >> 3; | ||
1440 | |||
1441 | if (depth_bytes == 3) | ||
1442 | /* | ||
1443 | * if bpp is 3(as in some RGB formats), the pixel width doesn't | ||
1444 | * really help in ensuring line stride is 16 byte aligned | ||
1445 | */ | ||
1446 | w_align = 4; | ||
1447 | else | ||
1448 | /* | ||
1449 | * for the remainder bpp(4, 2 and 1), the pixel width alignment | ||
1450 | * can ensure a line stride alignment of 16 bytes. For example, | ||
1451 | * if bpp is 2, then the line stride can be 16 byte aligned if | ||
1452 | * the width is 8 byte aligned | ||
1453 | */ | ||
1454 | w_align = order_base_2(VPDMA_DESC_ALIGN / depth_bytes); | ||
1455 | |||
1456 | v4l_bound_align_image(&pix->width, MIN_W, MAX_W, w_align, | ||
1367 | &pix->height, MIN_H, MAX_H, H_ALIGN, | 1457 | &pix->height, MIN_H, MAX_H, H_ALIGN, |
1368 | S_ALIGN); | 1458 | S_ALIGN); |
1369 | 1459 | ||
1370 | pix->num_planes = fmt->coplanar ? 2 : 1; | 1460 | pix->num_planes = fmt->coplanar ? 2 : 1; |
1371 | pix->pixelformat = fmt->fourcc; | 1461 | pix->pixelformat = fmt->fourcc; |
1372 | 1462 | ||
1373 | if (type == VPE_FMT_TYPE_CAPTURE) { | 1463 | if (!pix->colorspace) { |
1374 | struct vpe_q_data *s_q_data; | 1464 | if (fmt->fourcc == V4L2_PIX_FMT_RGB24 || |
1375 | 1465 | fmt->fourcc == V4L2_PIX_FMT_BGR24 || | |
1376 | /* get colorspace from the source queue */ | 1466 | fmt->fourcc == V4L2_PIX_FMT_RGB32 || |
1377 | s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | 1467 | fmt->fourcc == V4L2_PIX_FMT_BGR32) { |
1378 | 1468 | pix->colorspace = V4L2_COLORSPACE_SRGB; | |
1379 | pix->colorspace = s_q_data->colorspace; | 1469 | } else { |
1380 | } else { | 1470 | if (pix->height > 1280) /* HD */ |
1381 | if (!pix->colorspace) | 1471 | pix->colorspace = V4L2_COLORSPACE_REC709; |
1382 | pix->colorspace = V4L2_COLORSPACE_SMPTE240M; | 1472 | else /* SD */ |
1473 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
1474 | } | ||
1383 | } | 1475 | } |
1384 | 1476 | ||
1385 | for (i = 0; i < pix->num_planes; i++) { | 1477 | for (i = 0; i < pix->num_planes; i++) { |
1386 | int depth; | ||
1387 | |||
1388 | plane_fmt = &pix->plane_fmt[i]; | 1478 | plane_fmt = &pix->plane_fmt[i]; |
1389 | depth = fmt->vpdma_fmt[i]->depth; | 1479 | depth = fmt->vpdma_fmt[i]->depth; |
1390 | 1480 | ||
1391 | if (i == VPE_LUMA) | 1481 | if (i == VPE_LUMA) |
1392 | plane_fmt->bytesperline = | 1482 | plane_fmt->bytesperline = (pix->width * depth) >> 3; |
1393 | round_up((pix->width * depth) >> 3, | ||
1394 | 1 << L_ALIGN); | ||
1395 | else | 1483 | else |
1396 | plane_fmt->bytesperline = pix->width; | 1484 | plane_fmt->bytesperline = pix->width; |
1397 | 1485 | ||
@@ -1749,6 +1837,14 @@ static int vpe_open(struct file *file) | |||
1749 | if (ret != 0) | 1837 | if (ret != 0) |
1750 | goto free_desc_list; | 1838 | goto free_desc_list; |
1751 | 1839 | ||
1840 | ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_h, SC_COEF_SRAM_SIZE); | ||
1841 | if (ret != 0) | ||
1842 | goto free_mmr_adb; | ||
1843 | |||
1844 | ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_v, SC_COEF_SRAM_SIZE); | ||
1845 | if (ret != 0) | ||
1846 | goto free_sc_h; | ||
1847 | |||
1752 | init_adb_hdrs(ctx); | 1848 | init_adb_hdrs(ctx); |
1753 | 1849 | ||
1754 | v4l2_fh_init(&ctx->fh, video_devdata(file)); | 1850 | v4l2_fh_init(&ctx->fh, video_devdata(file)); |
@@ -1770,7 +1866,7 @@ static int vpe_open(struct file *file) | |||
1770 | s_q_data->height = 1080; | 1866 | s_q_data->height = 1080; |
1771 | s_q_data->sizeimage[VPE_LUMA] = (s_q_data->width * s_q_data->height * | 1867 | s_q_data->sizeimage[VPE_LUMA] = (s_q_data->width * s_q_data->height * |
1772 | s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; | 1868 | s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; |
1773 | s_q_data->colorspace = V4L2_COLORSPACE_SMPTE240M; | 1869 | s_q_data->colorspace = V4L2_COLORSPACE_SMPTE170M; |
1774 | s_q_data->field = V4L2_FIELD_NONE; | 1870 | s_q_data->field = V4L2_FIELD_NONE; |
1775 | s_q_data->c_rect.left = 0; | 1871 | s_q_data->c_rect.left = 0; |
1776 | s_q_data->c_rect.top = 0; | 1872 | s_q_data->c_rect.top = 0; |
@@ -1817,6 +1913,10 @@ static int vpe_open(struct file *file) | |||
1817 | exit_fh: | 1913 | exit_fh: |
1818 | v4l2_ctrl_handler_free(hdl); | 1914 | v4l2_ctrl_handler_free(hdl); |
1819 | v4l2_fh_exit(&ctx->fh); | 1915 | v4l2_fh_exit(&ctx->fh); |
1916 | vpdma_free_desc_buf(&ctx->sc_coeff_v); | ||
1917 | free_sc_h: | ||
1918 | vpdma_free_desc_buf(&ctx->sc_coeff_h); | ||
1919 | free_mmr_adb: | ||
1820 | vpdma_free_desc_buf(&ctx->mmr_adb); | 1920 | vpdma_free_desc_buf(&ctx->mmr_adb); |
1821 | free_desc_list: | 1921 | free_desc_list: |
1822 | vpdma_free_desc_list(&ctx->desc_list); | 1922 | vpdma_free_desc_list(&ctx->desc_list); |
@@ -1938,12 +2038,11 @@ static int vpe_probe(struct platform_device *pdev) | |||
1938 | { | 2038 | { |
1939 | struct vpe_dev *dev; | 2039 | struct vpe_dev *dev; |
1940 | struct video_device *vfd; | 2040 | struct video_device *vfd; |
1941 | struct resource *res; | ||
1942 | int ret, irq, func; | 2041 | int ret, irq, func; |
1943 | 2042 | ||
1944 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | 2043 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); |
1945 | if (IS_ERR(dev)) | 2044 | if (!dev) |
1946 | return PTR_ERR(dev); | 2045 | return -ENOMEM; |
1947 | 2046 | ||
1948 | spin_lock_init(&dev->lock); | 2047 | spin_lock_init(&dev->lock); |
1949 | 2048 | ||
@@ -1954,16 +2053,17 @@ static int vpe_probe(struct platform_device *pdev) | |||
1954 | atomic_set(&dev->num_instances, 0); | 2053 | atomic_set(&dev->num_instances, 0); |
1955 | mutex_init(&dev->dev_mutex); | 2054 | mutex_init(&dev->dev_mutex); |
1956 | 2055 | ||
1957 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpe_top"); | 2056 | dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
2057 | "vpe_top"); | ||
1958 | /* | 2058 | /* |
1959 | * HACK: we get resource info from device tree in the form of a list of | 2059 | * HACK: we get resource info from device tree in the form of a list of |
1960 | * VPE sub blocks, the driver currently uses only the base of vpe_top | 2060 | * VPE sub blocks, the driver currently uses only the base of vpe_top |
1961 | * for register access, the driver should be changed later to access | 2061 | * for register access, the driver should be changed later to access |
1962 | * registers based on the sub block base addresses | 2062 | * registers based on the sub block base addresses |
1963 | */ | 2063 | */ |
1964 | dev->base = devm_ioremap(&pdev->dev, res->start, SZ_32K); | 2064 | dev->base = devm_ioremap(&pdev->dev, dev->res->start, SZ_32K); |
1965 | if (IS_ERR(dev->base)) { | 2065 | if (!dev->base) { |
1966 | ret = PTR_ERR(dev->base); | 2066 | ret = -ENOMEM; |
1967 | goto v4l2_dev_unreg; | 2067 | goto v4l2_dev_unreg; |
1968 | } | 2068 | } |
1969 | 2069 | ||
@@ -2006,9 +2106,23 @@ static int vpe_probe(struct platform_device *pdev) | |||
2006 | 2106 | ||
2007 | vpe_top_vpdma_reset(dev); | 2107 | vpe_top_vpdma_reset(dev); |
2008 | 2108 | ||
2109 | dev->sc = sc_create(pdev); | ||
2110 | if (IS_ERR(dev->sc)) { | ||
2111 | ret = PTR_ERR(dev->sc); | ||
2112 | goto runtime_put; | ||
2113 | } | ||
2114 | |||
2115 | dev->csc = csc_create(pdev); | ||
2116 | if (IS_ERR(dev->csc)) { | ||
2117 | ret = PTR_ERR(dev->csc); | ||
2118 | goto runtime_put; | ||
2119 | } | ||
2120 | |||
2009 | dev->vpdma = vpdma_create(pdev); | 2121 | dev->vpdma = vpdma_create(pdev); |
2010 | if (IS_ERR(dev->vpdma)) | 2122 | if (IS_ERR(dev->vpdma)) { |
2123 | ret = PTR_ERR(dev->vpdma); | ||
2011 | goto runtime_put; | 2124 | goto runtime_put; |
2125 | } | ||
2012 | 2126 | ||
2013 | vfd = &dev->vfd; | 2127 | vfd = &dev->vfd; |
2014 | *vfd = vpe_videodev; | 2128 | *vfd = vpe_videodev; |
@@ -2081,18 +2195,7 @@ static struct platform_driver vpe_pdrv = { | |||
2081 | }, | 2195 | }, |
2082 | }; | 2196 | }; |
2083 | 2197 | ||
2084 | static void __exit vpe_exit(void) | 2198 | module_platform_driver(vpe_pdrv); |
2085 | { | ||
2086 | platform_driver_unregister(&vpe_pdrv); | ||
2087 | } | ||
2088 | |||
2089 | static int __init vpe_init(void) | ||
2090 | { | ||
2091 | return platform_driver_register(&vpe_pdrv); | ||
2092 | } | ||
2093 | |||
2094 | module_init(vpe_init); | ||
2095 | module_exit(vpe_exit); | ||
2096 | 2199 | ||
2097 | MODULE_DESCRIPTION("TI VPE driver"); | 2200 | MODULE_DESCRIPTION("TI VPE driver"); |
2098 | MODULE_AUTHOR("Dale Farnsworth, <dale@farnsworth.org>"); | 2201 | MODULE_AUTHOR("Dale Farnsworth, <dale@farnsworth.org>"); |
diff --git a/drivers/media/platform/ti-vpe/vpe_regs.h b/drivers/media/platform/ti-vpe/vpe_regs.h index ed214e828398..74283d79eae1 100644 --- a/drivers/media/platform/ti-vpe/vpe_regs.h +++ b/drivers/media/platform/ti-vpe/vpe_regs.h | |||
@@ -306,191 +306,4 @@ | |||
306 | #define VPE_FMD_FRAME_DIFF_MASK 0x000fffff | 306 | #define VPE_FMD_FRAME_DIFF_MASK 0x000fffff |
307 | #define VPE_FMD_FRAME_DIFF_SHIFT 0 | 307 | #define VPE_FMD_FRAME_DIFF_SHIFT 0 |
308 | 308 | ||
309 | /* VPE scaler regs */ | ||
310 | #define VPE_SC_MP_SC0 0x0700 | ||
311 | #define VPE_INTERLACE_O (1 << 0) | ||
312 | #define VPE_LINEAR (1 << 1) | ||
313 | #define VPE_SC_BYPASS (1 << 2) | ||
314 | #define VPE_INVT_FID (1 << 3) | ||
315 | #define VPE_USE_RAV (1 << 4) | ||
316 | #define VPE_ENABLE_EV (1 << 5) | ||
317 | #define VPE_AUTO_HS (1 << 6) | ||
318 | #define VPE_DCM_2X (1 << 7) | ||
319 | #define VPE_DCM_4X (1 << 8) | ||
320 | #define VPE_HP_BYPASS (1 << 9) | ||
321 | #define VPE_INTERLACE_I (1 << 10) | ||
322 | #define VPE_ENABLE_SIN2_VER_INTP (1 << 11) | ||
323 | #define VPE_Y_PK_EN (1 << 14) | ||
324 | #define VPE_TRIM (1 << 15) | ||
325 | #define VPE_SELFGEN_FID (1 << 16) | ||
326 | |||
327 | #define VPE_SC_MP_SC1 0x0704 | ||
328 | #define VPE_ROW_ACC_INC_MASK 0x07ffffff | ||
329 | #define VPE_ROW_ACC_INC_SHIFT 0 | ||
330 | |||
331 | #define VPE_SC_MP_SC2 0x0708 | ||
332 | #define VPE_ROW_ACC_OFFSET_MASK 0x0fffffff | ||
333 | #define VPE_ROW_ACC_OFFSET_SHIFT 0 | ||
334 | |||
335 | #define VPE_SC_MP_SC3 0x070c | ||
336 | #define VPE_ROW_ACC_OFFSET_B_MASK 0x0fffffff | ||
337 | #define VPE_ROW_ACC_OFFSET_B_SHIFT 0 | ||
338 | |||
339 | #define VPE_SC_MP_SC4 0x0710 | ||
340 | #define VPE_TAR_H_MASK 0x07ff | ||
341 | #define VPE_TAR_H_SHIFT 0 | ||
342 | #define VPE_TAR_W_MASK 0x07ff | ||
343 | #define VPE_TAR_W_SHIFT 12 | ||
344 | #define VPE_LIN_ACC_INC_U_MASK 0x07 | ||
345 | #define VPE_LIN_ACC_INC_U_SHIFT 24 | ||
346 | #define VPE_NLIN_ACC_INIT_U_MASK 0x07 | ||
347 | #define VPE_NLIN_ACC_INIT_U_SHIFT 28 | ||
348 | |||
349 | #define VPE_SC_MP_SC5 0x0714 | ||
350 | #define VPE_SRC_H_MASK 0x07ff | ||
351 | #define VPE_SRC_H_SHIFT 0 | ||
352 | #define VPE_SRC_W_MASK 0x07ff | ||
353 | #define VPE_SRC_W_SHIFT 12 | ||
354 | #define VPE_NLIN_ACC_INC_U_MASK 0x07 | ||
355 | #define VPE_NLIN_ACC_INC_U_SHIFT 24 | ||
356 | |||
357 | #define VPE_SC_MP_SC6 0x0718 | ||
358 | #define VPE_ROW_ACC_INIT_RAV_MASK 0x03ff | ||
359 | #define VPE_ROW_ACC_INIT_RAV_SHIFT 0 | ||
360 | #define VPE_ROW_ACC_INIT_RAV_B_MASK 0x03ff | ||
361 | #define VPE_ROW_ACC_INIT_RAV_B_SHIFT 10 | ||
362 | |||
363 | #define VPE_SC_MP_SC8 0x0720 | ||
364 | #define VPE_NLIN_LEFT_MASK 0x07ff | ||
365 | #define VPE_NLIN_LEFT_SHIFT 0 | ||
366 | #define VPE_NLIN_RIGHT_MASK 0x07ff | ||
367 | #define VPE_NLIN_RIGHT_SHIFT 12 | ||
368 | |||
369 | #define VPE_SC_MP_SC9 0x0724 | ||
370 | #define VPE_LIN_ACC_INC VPE_SC_MP_SC9 | ||
371 | |||
372 | #define VPE_SC_MP_SC10 0x0728 | ||
373 | #define VPE_NLIN_ACC_INIT VPE_SC_MP_SC10 | ||
374 | |||
375 | #define VPE_SC_MP_SC11 0x072c | ||
376 | #define VPE_NLIN_ACC_INC VPE_SC_MP_SC11 | ||
377 | |||
378 | #define VPE_SC_MP_SC12 0x0730 | ||
379 | #define VPE_COL_ACC_OFFSET_MASK 0x01ffffff | ||
380 | #define VPE_COL_ACC_OFFSET_SHIFT 0 | ||
381 | |||
382 | #define VPE_SC_MP_SC13 0x0734 | ||
383 | #define VPE_SC_FACTOR_RAV_MASK 0x03ff | ||
384 | #define VPE_SC_FACTOR_RAV_SHIFT 0 | ||
385 | #define VPE_CHROMA_INTP_THR_MASK 0x03ff | ||
386 | #define VPE_CHROMA_INTP_THR_SHIFT 12 | ||
387 | #define VPE_DELTA_CHROMA_THR_MASK 0x0f | ||
388 | #define VPE_DELTA_CHROMA_THR_SHIFT 24 | ||
389 | |||
390 | #define VPE_SC_MP_SC17 0x0744 | ||
391 | #define VPE_EV_THR_MASK 0x03ff | ||
392 | #define VPE_EV_THR_SHIFT 12 | ||
393 | #define VPE_DELTA_LUMA_THR_MASK 0x0f | ||
394 | #define VPE_DELTA_LUMA_THR_SHIFT 24 | ||
395 | #define VPE_DELTA_EV_THR_MASK 0x0f | ||
396 | #define VPE_DELTA_EV_THR_SHIFT 28 | ||
397 | |||
398 | #define VPE_SC_MP_SC18 0x0748 | ||
399 | #define VPE_HS_FACTOR_MASK 0x03ff | ||
400 | #define VPE_HS_FACTOR_SHIFT 0 | ||
401 | #define VPE_CONF_DEFAULT_MASK 0x01ff | ||
402 | #define VPE_CONF_DEFAULT_SHIFT 16 | ||
403 | |||
404 | #define VPE_SC_MP_SC19 0x074c | ||
405 | #define VPE_HPF_COEFF0_MASK 0xff | ||
406 | #define VPE_HPF_COEFF0_SHIFT 0 | ||
407 | #define VPE_HPF_COEFF1_MASK 0xff | ||
408 | #define VPE_HPF_COEFF1_SHIFT 8 | ||
409 | #define VPE_HPF_COEFF2_MASK 0xff | ||
410 | #define VPE_HPF_COEFF2_SHIFT 16 | ||
411 | #define VPE_HPF_COEFF3_MASK 0xff | ||
412 | #define VPE_HPF_COEFF3_SHIFT 23 | ||
413 | |||
414 | #define VPE_SC_MP_SC20 0x0750 | ||
415 | #define VPE_HPF_COEFF4_MASK 0xff | ||
416 | #define VPE_HPF_COEFF4_SHIFT 0 | ||
417 | #define VPE_HPF_COEFF5_MASK 0xff | ||
418 | #define VPE_HPF_COEFF5_SHIFT 8 | ||
419 | #define VPE_HPF_NORM_SHIFT_MASK 0x07 | ||
420 | #define VPE_HPF_NORM_SHIFT_SHIFT 16 | ||
421 | #define VPE_NL_LIMIT_MASK 0x1ff | ||
422 | #define VPE_NL_LIMIT_SHIFT 20 | ||
423 | |||
424 | #define VPE_SC_MP_SC21 0x0754 | ||
425 | #define VPE_NL_LO_THR_MASK 0x01ff | ||
426 | #define VPE_NL_LO_THR_SHIFT 0 | ||
427 | #define VPE_NL_LO_SLOPE_MASK 0xff | ||
428 | #define VPE_NL_LO_SLOPE_SHIFT 16 | ||
429 | |||
430 | #define VPE_SC_MP_SC22 0x0758 | ||
431 | #define VPE_NL_HI_THR_MASK 0x01ff | ||
432 | #define VPE_NL_HI_THR_SHIFT 0 | ||
433 | #define VPE_NL_HI_SLOPE_SH_MASK 0x07 | ||
434 | #define VPE_NL_HI_SLOPE_SH_SHIFT 16 | ||
435 | |||
436 | #define VPE_SC_MP_SC23 0x075c | ||
437 | #define VPE_GRADIENT_THR_MASK 0x07ff | ||
438 | #define VPE_GRADIENT_THR_SHIFT 0 | ||
439 | #define VPE_GRADIENT_THR_RANGE_MASK 0x0f | ||
440 | #define VPE_GRADIENT_THR_RANGE_SHIFT 12 | ||
441 | #define VPE_MIN_GY_THR_MASK 0xff | ||
442 | #define VPE_MIN_GY_THR_SHIFT 16 | ||
443 | #define VPE_MIN_GY_THR_RANGE_MASK 0x0f | ||
444 | #define VPE_MIN_GY_THR_RANGE_SHIFT 28 | ||
445 | |||
446 | #define VPE_SC_MP_SC24 0x0760 | ||
447 | #define VPE_ORG_H_MASK 0x07ff | ||
448 | #define VPE_ORG_H_SHIFT 0 | ||
449 | #define VPE_ORG_W_MASK 0x07ff | ||
450 | #define VPE_ORG_W_SHIFT 16 | ||
451 | |||
452 | #define VPE_SC_MP_SC25 0x0764 | ||
453 | #define VPE_OFF_H_MASK 0x07ff | ||
454 | #define VPE_OFF_H_SHIFT 0 | ||
455 | #define VPE_OFF_W_MASK 0x07ff | ||
456 | #define VPE_OFF_W_SHIFT 16 | ||
457 | |||
458 | /* VPE color space converter regs */ | ||
459 | #define VPE_CSC_CSC00 0x5700 | ||
460 | #define VPE_CSC_A0_MASK 0x1fff | ||
461 | #define VPE_CSC_A0_SHIFT 0 | ||
462 | #define VPE_CSC_B0_MASK 0x1fff | ||
463 | #define VPE_CSC_B0_SHIFT 16 | ||
464 | |||
465 | #define VPE_CSC_CSC01 0x5704 | ||
466 | #define VPE_CSC_C0_MASK 0x1fff | ||
467 | #define VPE_CSC_C0_SHIFT 0 | ||
468 | #define VPE_CSC_A1_MASK 0x1fff | ||
469 | #define VPE_CSC_A1_SHIFT 16 | ||
470 | |||
471 | #define VPE_CSC_CSC02 0x5708 | ||
472 | #define VPE_CSC_B1_MASK 0x1fff | ||
473 | #define VPE_CSC_B1_SHIFT 0 | ||
474 | #define VPE_CSC_C1_MASK 0x1fff | ||
475 | #define VPE_CSC_C1_SHIFT 16 | ||
476 | |||
477 | #define VPE_CSC_CSC03 0x570c | ||
478 | #define VPE_CSC_A2_MASK 0x1fff | ||
479 | #define VPE_CSC_A2_SHIFT 0 | ||
480 | #define VPE_CSC_B2_MASK 0x1fff | ||
481 | #define VPE_CSC_B2_SHIFT 16 | ||
482 | |||
483 | #define VPE_CSC_CSC04 0x5710 | ||
484 | #define VPE_CSC_C2_MASK 0x1fff | ||
485 | #define VPE_CSC_C2_SHIFT 0 | ||
486 | #define VPE_CSC_D0_MASK 0x0fff | ||
487 | #define VPE_CSC_D0_SHIFT 16 | ||
488 | |||
489 | #define VPE_CSC_CSC05 0x5714 | ||
490 | #define VPE_CSC_D1_MASK 0x0fff | ||
491 | #define VPE_CSC_D1_SHIFT 0 | ||
492 | #define VPE_CSC_D2_MASK 0x0fff | ||
493 | #define VPE_CSC_D2_SHIFT 16 | ||
494 | #define VPE_CSC_BYPASS (1 << 28) | ||
495 | |||
496 | #endif | 309 | #endif |
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 4da226169e15..151cecd0ea25 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o | 1 | vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o |
2 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o | 2 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o |
3 | vsp1-y += vsp1_lif.o vsp1_uds.o | 3 | vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o |
4 | vsp1-y += vsp1_sru.o vsp1_uds.o | ||
4 | 5 | ||
5 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o | 6 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o |
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index d6c6ecd039ff..94d1b02680c5 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h | |||
@@ -28,8 +28,11 @@ struct clk; | |||
28 | struct device; | 28 | struct device; |
29 | 29 | ||
30 | struct vsp1_platform_data; | 30 | struct vsp1_platform_data; |
31 | struct vsp1_hsit; | ||
31 | struct vsp1_lif; | 32 | struct vsp1_lif; |
33 | struct vsp1_lut; | ||
32 | struct vsp1_rwpf; | 34 | struct vsp1_rwpf; |
35 | struct vsp1_sru; | ||
33 | struct vsp1_uds; | 36 | struct vsp1_uds; |
34 | 37 | ||
35 | #define VPS1_MAX_RPF 5 | 38 | #define VPS1_MAX_RPF 5 |
@@ -47,8 +50,12 @@ struct vsp1_device { | |||
47 | struct mutex lock; | 50 | struct mutex lock; |
48 | int ref_count; | 51 | int ref_count; |
49 | 52 | ||
53 | struct vsp1_hsit *hsi; | ||
54 | struct vsp1_hsit *hst; | ||
50 | struct vsp1_lif *lif; | 55 | struct vsp1_lif *lif; |
56 | struct vsp1_lut *lut; | ||
51 | struct vsp1_rwpf *rpf[VPS1_MAX_RPF]; | 57 | struct vsp1_rwpf *rpf[VPS1_MAX_RPF]; |
58 | struct vsp1_sru *sru; | ||
52 | struct vsp1_uds *uds[VPS1_MAX_UDS]; | 59 | struct vsp1_uds *uds[VPS1_MAX_UDS]; |
53 | struct vsp1_rwpf *wpf[VPS1_MAX_WPF]; | 60 | struct vsp1_rwpf *wpf[VPS1_MAX_WPF]; |
54 | 61 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index d16bf0f41e24..0df0a994e575 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c | |||
@@ -20,8 +20,11 @@ | |||
20 | #include <linux/videodev2.h> | 20 | #include <linux/videodev2.h> |
21 | 21 | ||
22 | #include "vsp1.h" | 22 | #include "vsp1.h" |
23 | #include "vsp1_hsit.h" | ||
23 | #include "vsp1_lif.h" | 24 | #include "vsp1_lif.h" |
25 | #include "vsp1_lut.h" | ||
24 | #include "vsp1_rwpf.h" | 26 | #include "vsp1_rwpf.h" |
27 | #include "vsp1_sru.h" | ||
25 | #include "vsp1_uds.h" | 28 | #include "vsp1_uds.h" |
26 | 29 | ||
27 | /* ----------------------------------------------------------------------------- | 30 | /* ----------------------------------------------------------------------------- |
@@ -152,6 +155,22 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
152 | } | 155 | } |
153 | 156 | ||
154 | /* Instantiate all the entities. */ | 157 | /* Instantiate all the entities. */ |
158 | vsp1->hsi = vsp1_hsit_create(vsp1, true); | ||
159 | if (IS_ERR(vsp1->hsi)) { | ||
160 | ret = PTR_ERR(vsp1->hsi); | ||
161 | goto done; | ||
162 | } | ||
163 | |||
164 | list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities); | ||
165 | |||
166 | vsp1->hst = vsp1_hsit_create(vsp1, false); | ||
167 | if (IS_ERR(vsp1->hst)) { | ||
168 | ret = PTR_ERR(vsp1->hst); | ||
169 | goto done; | ||
170 | } | ||
171 | |||
172 | list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); | ||
173 | |||
155 | if (vsp1->pdata->features & VSP1_HAS_LIF) { | 174 | if (vsp1->pdata->features & VSP1_HAS_LIF) { |
156 | vsp1->lif = vsp1_lif_create(vsp1); | 175 | vsp1->lif = vsp1_lif_create(vsp1); |
157 | if (IS_ERR(vsp1->lif)) { | 176 | if (IS_ERR(vsp1->lif)) { |
@@ -162,6 +181,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
162 | list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); | 181 | list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); |
163 | } | 182 | } |
164 | 183 | ||
184 | if (vsp1->pdata->features & VSP1_HAS_LUT) { | ||
185 | vsp1->lut = vsp1_lut_create(vsp1); | ||
186 | if (IS_ERR(vsp1->lut)) { | ||
187 | ret = PTR_ERR(vsp1->lut); | ||
188 | goto done; | ||
189 | } | ||
190 | |||
191 | list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); | ||
192 | } | ||
193 | |||
165 | for (i = 0; i < vsp1->pdata->rpf_count; ++i) { | 194 | for (i = 0; i < vsp1->pdata->rpf_count; ++i) { |
166 | struct vsp1_rwpf *rpf; | 195 | struct vsp1_rwpf *rpf; |
167 | 196 | ||
@@ -175,6 +204,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
175 | list_add_tail(&rpf->entity.list_dev, &vsp1->entities); | 204 | list_add_tail(&rpf->entity.list_dev, &vsp1->entities); |
176 | } | 205 | } |
177 | 206 | ||
207 | if (vsp1->pdata->features & VSP1_HAS_SRU) { | ||
208 | vsp1->sru = vsp1_sru_create(vsp1); | ||
209 | if (IS_ERR(vsp1->sru)) { | ||
210 | ret = PTR_ERR(vsp1->sru); | ||
211 | goto done; | ||
212 | } | ||
213 | |||
214 | list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); | ||
215 | } | ||
216 | |||
178 | for (i = 0; i < vsp1->pdata->uds_count; ++i) { | 217 | for (i = 0; i < vsp1->pdata->uds_count; ++i) { |
179 | struct vsp1_uds *uds; | 218 | struct vsp1_uds *uds; |
180 | 219 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 9028f9d524f4..0226e47df6d9 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/gfp.h> | 15 | #include <linux/gfp.h> |
16 | 16 | ||
17 | #include <media/media-entity.h> | 17 | #include <media/media-entity.h> |
18 | #include <media/v4l2-ctrls.h> | ||
18 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
19 | 20 | ||
20 | #include "vsp1.h" | 21 | #include "vsp1.h" |
@@ -122,12 +123,16 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | |||
122 | unsigned int id; | 123 | unsigned int id; |
123 | unsigned int reg; | 124 | unsigned int reg; |
124 | } routes[] = { | 125 | } routes[] = { |
126 | { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE }, | ||
127 | { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE }, | ||
125 | { VI6_DPR_NODE_LIF, 0 }, | 128 | { VI6_DPR_NODE_LIF, 0 }, |
129 | { VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE }, | ||
126 | { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) }, | 130 | { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) }, |
127 | { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) }, | 131 | { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) }, |
128 | { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, | 132 | { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, |
129 | { VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) }, | 133 | { VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) }, |
130 | { VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) }, | 134 | { VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) }, |
135 | { VI6_DPR_NODE_SRU, VI6_DPR_SRU_ROUTE }, | ||
131 | { VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) }, | 136 | { VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) }, |
132 | { VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) }, | 137 | { VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) }, |
133 | { VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) }, | 138 | { VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) }, |
@@ -177,5 +182,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | |||
177 | 182 | ||
178 | void vsp1_entity_destroy(struct vsp1_entity *entity) | 183 | void vsp1_entity_destroy(struct vsp1_entity *entity) |
179 | { | 184 | { |
185 | if (entity->subdev.ctrl_handler) | ||
186 | v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); | ||
180 | media_entity_cleanup(&entity->subdev.entity); | 187 | media_entity_cleanup(&entity->subdev.entity); |
181 | } | 188 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index c4feab2cbb81..e152798d7f38 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h | |||
@@ -20,8 +20,12 @@ | |||
20 | struct vsp1_device; | 20 | struct vsp1_device; |
21 | 21 | ||
22 | enum vsp1_entity_type { | 22 | enum vsp1_entity_type { |
23 | VSP1_ENTITY_HSI, | ||
24 | VSP1_ENTITY_HST, | ||
23 | VSP1_ENTITY_LIF, | 25 | VSP1_ENTITY_LIF, |
26 | VSP1_ENTITY_LUT, | ||
24 | VSP1_ENTITY_RPF, | 27 | VSP1_ENTITY_RPF, |
28 | VSP1_ENTITY_SRU, | ||
25 | VSP1_ENTITY_UDS, | 29 | VSP1_ENTITY_UDS, |
26 | VSP1_ENTITY_WPF, | 30 | VSP1_ENTITY_WPF, |
27 | }; | 31 | }; |
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c new file mode 100644 index 000000000000..285485350d82 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_hsit.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * vsp1_hsit.c -- R-Car VSP1 Hue Saturation value (Inverse) Transform | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
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 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/gfp.h> | ||
16 | |||
17 | #include <media/v4l2-subdev.h> | ||
18 | |||
19 | #include "vsp1.h" | ||
20 | #include "vsp1_hsit.h" | ||
21 | |||
22 | #define HSIT_MIN_SIZE 4U | ||
23 | #define HSIT_MAX_SIZE 8190U | ||
24 | |||
25 | /* ----------------------------------------------------------------------------- | ||
26 | * Device Access | ||
27 | */ | ||
28 | |||
29 | static inline u32 vsp1_hsit_read(struct vsp1_hsit *hsit, u32 reg) | ||
30 | { | ||
31 | return vsp1_read(hsit->entity.vsp1, reg); | ||
32 | } | ||
33 | |||
34 | static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data) | ||
35 | { | ||
36 | vsp1_write(hsit->entity.vsp1, reg, data); | ||
37 | } | ||
38 | |||
39 | /* ----------------------------------------------------------------------------- | ||
40 | * V4L2 Subdevice Core Operations | ||
41 | */ | ||
42 | |||
43 | static int hsit_s_stream(struct v4l2_subdev *subdev, int enable) | ||
44 | { | ||
45 | struct vsp1_hsit *hsit = to_hsit(subdev); | ||
46 | |||
47 | if (!enable) | ||
48 | return 0; | ||
49 | |||
50 | if (hsit->inverse) | ||
51 | vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); | ||
52 | else | ||
53 | vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | /* ----------------------------------------------------------------------------- | ||
59 | * V4L2 Subdevice Pad Operations | ||
60 | */ | ||
61 | |||
62 | static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, | ||
63 | struct v4l2_subdev_fh *fh, | ||
64 | struct v4l2_subdev_mbus_code_enum *code) | ||
65 | { | ||
66 | struct vsp1_hsit *hsit = to_hsit(subdev); | ||
67 | |||
68 | if (code->index > 0) | ||
69 | return -EINVAL; | ||
70 | |||
71 | if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) | | ||
72 | (code->pad == HSIT_PAD_SOURCE && hsit->inverse)) | ||
73 | code->code = V4L2_MBUS_FMT_ARGB8888_1X32; | ||
74 | else | ||
75 | code->code = V4L2_MBUS_FMT_AHSV8888_1X32; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int hsit_enum_frame_size(struct v4l2_subdev *subdev, | ||
81 | struct v4l2_subdev_fh *fh, | ||
82 | struct v4l2_subdev_frame_size_enum *fse) | ||
83 | { | ||
84 | struct v4l2_mbus_framefmt *format; | ||
85 | |||
86 | format = v4l2_subdev_get_try_format(fh, fse->pad); | ||
87 | |||
88 | if (fse->index || fse->code != format->code) | ||
89 | return -EINVAL; | ||
90 | |||
91 | if (fse->pad == HSIT_PAD_SINK) { | ||
92 | fse->min_width = HSIT_MIN_SIZE; | ||
93 | fse->max_width = HSIT_MAX_SIZE; | ||
94 | fse->min_height = HSIT_MIN_SIZE; | ||
95 | fse->max_height = HSIT_MAX_SIZE; | ||
96 | } else { | ||
97 | /* The size on the source pad are fixed and always identical to | ||
98 | * the size on the sink pad. | ||
99 | */ | ||
100 | fse->min_width = format->width; | ||
101 | fse->max_width = format->width; | ||
102 | fse->min_height = format->height; | ||
103 | fse->max_height = format->height; | ||
104 | } | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int hsit_get_format(struct v4l2_subdev *subdev, | ||
110 | struct v4l2_subdev_fh *fh, | ||
111 | struct v4l2_subdev_format *fmt) | ||
112 | { | ||
113 | struct vsp1_hsit *hsit = to_hsit(subdev); | ||
114 | |||
115 | fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, | ||
116 | fmt->which); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int hsit_set_format(struct v4l2_subdev *subdev, | ||
122 | struct v4l2_subdev_fh *fh, | ||
123 | struct v4l2_subdev_format *fmt) | ||
124 | { | ||
125 | struct vsp1_hsit *hsit = to_hsit(subdev); | ||
126 | struct v4l2_mbus_framefmt *format; | ||
127 | |||
128 | format = vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, | ||
129 | fmt->which); | ||
130 | |||
131 | if (fmt->pad == HSIT_PAD_SOURCE) { | ||
132 | /* The HST and HSI output format code and resolution can't be | ||
133 | * modified. | ||
134 | */ | ||
135 | fmt->format = *format; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | format->code = hsit->inverse ? V4L2_MBUS_FMT_AHSV8888_1X32 | ||
140 | : V4L2_MBUS_FMT_ARGB8888_1X32; | ||
141 | format->width = clamp_t(unsigned int, fmt->format.width, | ||
142 | HSIT_MIN_SIZE, HSIT_MAX_SIZE); | ||
143 | format->height = clamp_t(unsigned int, fmt->format.height, | ||
144 | HSIT_MIN_SIZE, HSIT_MAX_SIZE); | ||
145 | format->field = V4L2_FIELD_NONE; | ||
146 | format->colorspace = V4L2_COLORSPACE_SRGB; | ||
147 | |||
148 | fmt->format = *format; | ||
149 | |||
150 | /* Propagate the format to the source pad. */ | ||
151 | format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE, | ||
152 | fmt->which); | ||
153 | *format = fmt->format; | ||
154 | format->code = hsit->inverse ? V4L2_MBUS_FMT_ARGB8888_1X32 | ||
155 | : V4L2_MBUS_FMT_AHSV8888_1X32; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | /* ----------------------------------------------------------------------------- | ||
161 | * V4L2 Subdevice Operations | ||
162 | */ | ||
163 | |||
164 | static struct v4l2_subdev_video_ops hsit_video_ops = { | ||
165 | .s_stream = hsit_s_stream, | ||
166 | }; | ||
167 | |||
168 | static struct v4l2_subdev_pad_ops hsit_pad_ops = { | ||
169 | .enum_mbus_code = hsit_enum_mbus_code, | ||
170 | .enum_frame_size = hsit_enum_frame_size, | ||
171 | .get_fmt = hsit_get_format, | ||
172 | .set_fmt = hsit_set_format, | ||
173 | }; | ||
174 | |||
175 | static struct v4l2_subdev_ops hsit_ops = { | ||
176 | .video = &hsit_video_ops, | ||
177 | .pad = &hsit_pad_ops, | ||
178 | }; | ||
179 | |||
180 | /* ----------------------------------------------------------------------------- | ||
181 | * Initialization and Cleanup | ||
182 | */ | ||
183 | |||
184 | struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) | ||
185 | { | ||
186 | struct v4l2_subdev *subdev; | ||
187 | struct vsp1_hsit *hsit; | ||
188 | int ret; | ||
189 | |||
190 | hsit = devm_kzalloc(vsp1->dev, sizeof(*hsit), GFP_KERNEL); | ||
191 | if (hsit == NULL) | ||
192 | return ERR_PTR(-ENOMEM); | ||
193 | |||
194 | hsit->inverse = inverse; | ||
195 | |||
196 | if (inverse) { | ||
197 | hsit->entity.type = VSP1_ENTITY_HSI; | ||
198 | hsit->entity.id = VI6_DPR_NODE_HSI; | ||
199 | } else { | ||
200 | hsit->entity.type = VSP1_ENTITY_HST; | ||
201 | hsit->entity.id = VI6_DPR_NODE_HST; | ||
202 | } | ||
203 | |||
204 | ret = vsp1_entity_init(vsp1, &hsit->entity, 2); | ||
205 | if (ret < 0) | ||
206 | return ERR_PTR(ret); | ||
207 | |||
208 | /* Initialize the V4L2 subdev. */ | ||
209 | subdev = &hsit->entity.subdev; | ||
210 | v4l2_subdev_init(subdev, &hsit_ops); | ||
211 | |||
212 | subdev->entity.ops = &vsp1_media_ops; | ||
213 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
214 | snprintf(subdev->name, sizeof(subdev->name), "%s %s", | ||
215 | dev_name(vsp1->dev), inverse ? "hsi" : "hst"); | ||
216 | v4l2_set_subdevdata(subdev, hsit); | ||
217 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
218 | |||
219 | vsp1_entity_init_formats(subdev, NULL); | ||
220 | |||
221 | return hsit; | ||
222 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.h b/drivers/media/platform/vsp1/vsp1_hsit.h new file mode 100644 index 000000000000..82f1c8426900 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_hsit.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * vsp1_hsit.h -- R-Car VSP1 Hue Saturation value (Inverse) Transform | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
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 | #ifndef __VSP1_HSIT_H__ | ||
14 | #define __VSP1_HSIT_H__ | ||
15 | |||
16 | #include <media/media-entity.h> | ||
17 | #include <media/v4l2-subdev.h> | ||
18 | |||
19 | #include "vsp1_entity.h" | ||
20 | |||
21 | struct vsp1_device; | ||
22 | |||
23 | #define HSIT_PAD_SINK 0 | ||
24 | #define HSIT_PAD_SOURCE 1 | ||
25 | |||
26 | struct vsp1_hsit { | ||
27 | struct vsp1_entity entity; | ||
28 | bool inverse; | ||
29 | }; | ||
30 | |||
31 | static inline struct vsp1_hsit *to_hsit(struct v4l2_subdev *subdev) | ||
32 | { | ||
33 | return container_of(subdev, struct vsp1_hsit, entity.subdev); | ||
34 | } | ||
35 | |||
36 | struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse); | ||
37 | |||
38 | #endif /* __VSP1_HSIT_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c new file mode 100644 index 000000000000..4e9dc7c86ef8 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_lut.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * vsp1_lut.c -- R-Car VSP1 Look-Up Table | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
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 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/gfp.h> | ||
16 | #include <linux/vsp1.h> | ||
17 | |||
18 | #include <media/v4l2-subdev.h> | ||
19 | |||
20 | #include "vsp1.h" | ||
21 | #include "vsp1_lut.h" | ||
22 | |||
23 | #define LUT_MIN_SIZE 4U | ||
24 | #define LUT_MAX_SIZE 8190U | ||
25 | |||
26 | /* ----------------------------------------------------------------------------- | ||
27 | * Device Access | ||
28 | */ | ||
29 | |||
30 | static inline u32 vsp1_lut_read(struct vsp1_lut *lut, u32 reg) | ||
31 | { | ||
32 | return vsp1_read(lut->entity.vsp1, reg); | ||
33 | } | ||
34 | |||
35 | static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data) | ||
36 | { | ||
37 | vsp1_write(lut->entity.vsp1, reg, data); | ||
38 | } | ||
39 | |||
40 | /* ----------------------------------------------------------------------------- | ||
41 | * V4L2 Subdevice Core Operations | ||
42 | */ | ||
43 | |||
44 | static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config) | ||
45 | { | ||
46 | memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut, | ||
47 | sizeof(config->lut)); | ||
48 | } | ||
49 | |||
50 | static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) | ||
51 | { | ||
52 | struct vsp1_lut *lut = to_lut(subdev); | ||
53 | |||
54 | switch (cmd) { | ||
55 | case VIDIOC_VSP1_LUT_CONFIG: | ||
56 | lut_configure(lut, arg); | ||
57 | return 0; | ||
58 | |||
59 | default: | ||
60 | return -ENOIOCTLCMD; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /* ----------------------------------------------------------------------------- | ||
65 | * V4L2 Subdevice Video Operations | ||
66 | */ | ||
67 | |||
68 | static int lut_s_stream(struct v4l2_subdev *subdev, int enable) | ||
69 | { | ||
70 | struct vsp1_lut *lut = to_lut(subdev); | ||
71 | |||
72 | if (!enable) | ||
73 | return 0; | ||
74 | |||
75 | vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* ----------------------------------------------------------------------------- | ||
81 | * V4L2 Subdevice Pad Operations | ||
82 | */ | ||
83 | |||
84 | static int lut_enum_mbus_code(struct v4l2_subdev *subdev, | ||
85 | struct v4l2_subdev_fh *fh, | ||
86 | struct v4l2_subdev_mbus_code_enum *code) | ||
87 | { | ||
88 | static const unsigned int codes[] = { | ||
89 | V4L2_MBUS_FMT_ARGB8888_1X32, | ||
90 | V4L2_MBUS_FMT_AHSV8888_1X32, | ||
91 | V4L2_MBUS_FMT_AYUV8_1X32, | ||
92 | }; | ||
93 | struct v4l2_mbus_framefmt *format; | ||
94 | |||
95 | if (code->pad == LUT_PAD_SINK) { | ||
96 | if (code->index >= ARRAY_SIZE(codes)) | ||
97 | return -EINVAL; | ||
98 | |||
99 | code->code = codes[code->index]; | ||
100 | } else { | ||
101 | /* The LUT can't perform format conversion, the sink format is | ||
102 | * always identical to the source format. | ||
103 | */ | ||
104 | if (code->index) | ||
105 | return -EINVAL; | ||
106 | |||
107 | format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK); | ||
108 | code->code = format->code; | ||
109 | } | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int lut_enum_frame_size(struct v4l2_subdev *subdev, | ||
115 | struct v4l2_subdev_fh *fh, | ||
116 | struct v4l2_subdev_frame_size_enum *fse) | ||
117 | { | ||
118 | struct v4l2_mbus_framefmt *format; | ||
119 | |||
120 | format = v4l2_subdev_get_try_format(fh, fse->pad); | ||
121 | |||
122 | if (fse->index || fse->code != format->code) | ||
123 | return -EINVAL; | ||
124 | |||
125 | if (fse->pad == LUT_PAD_SINK) { | ||
126 | fse->min_width = LUT_MIN_SIZE; | ||
127 | fse->max_width = LUT_MAX_SIZE; | ||
128 | fse->min_height = LUT_MIN_SIZE; | ||
129 | fse->max_height = LUT_MAX_SIZE; | ||
130 | } else { | ||
131 | /* The size on the source pad are fixed and always identical to | ||
132 | * the size on the sink pad. | ||
133 | */ | ||
134 | fse->min_width = format->width; | ||
135 | fse->max_width = format->width; | ||
136 | fse->min_height = format->height; | ||
137 | fse->max_height = format->height; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | ||
144 | struct v4l2_subdev_format *fmt) | ||
145 | { | ||
146 | struct vsp1_lut *lut = to_lut(subdev); | ||
147 | |||
148 | fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, | ||
149 | fmt->which); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | ||
155 | struct v4l2_subdev_format *fmt) | ||
156 | { | ||
157 | struct vsp1_lut *lut = to_lut(subdev); | ||
158 | struct v4l2_mbus_framefmt *format; | ||
159 | |||
160 | /* Default to YUV if the requested format is not supported. */ | ||
161 | if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 && | ||
162 | fmt->format.code != V4L2_MBUS_FMT_AHSV8888_1X32 && | ||
163 | fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32) | ||
164 | fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32; | ||
165 | |||
166 | format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, | ||
167 | fmt->which); | ||
168 | |||
169 | if (fmt->pad == LUT_PAD_SOURCE) { | ||
170 | /* The LUT output format can't be modified. */ | ||
171 | fmt->format = *format; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | format->width = clamp_t(unsigned int, fmt->format.width, | ||
176 | LUT_MIN_SIZE, LUT_MAX_SIZE); | ||
177 | format->height = clamp_t(unsigned int, fmt->format.height, | ||
178 | LUT_MIN_SIZE, LUT_MAX_SIZE); | ||
179 | format->field = V4L2_FIELD_NONE; | ||
180 | format->colorspace = V4L2_COLORSPACE_SRGB; | ||
181 | |||
182 | fmt->format = *format; | ||
183 | |||
184 | /* Propagate the format to the source pad. */ | ||
185 | format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE, | ||
186 | fmt->which); | ||
187 | *format = fmt->format; | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /* ----------------------------------------------------------------------------- | ||
193 | * V4L2 Subdevice Operations | ||
194 | */ | ||
195 | |||
196 | static struct v4l2_subdev_core_ops lut_core_ops = { | ||
197 | .ioctl = lut_ioctl, | ||
198 | }; | ||
199 | |||
200 | static struct v4l2_subdev_video_ops lut_video_ops = { | ||
201 | .s_stream = lut_s_stream, | ||
202 | }; | ||
203 | |||
204 | static struct v4l2_subdev_pad_ops lut_pad_ops = { | ||
205 | .enum_mbus_code = lut_enum_mbus_code, | ||
206 | .enum_frame_size = lut_enum_frame_size, | ||
207 | .get_fmt = lut_get_format, | ||
208 | .set_fmt = lut_set_format, | ||
209 | }; | ||
210 | |||
211 | static struct v4l2_subdev_ops lut_ops = { | ||
212 | .core = &lut_core_ops, | ||
213 | .video = &lut_video_ops, | ||
214 | .pad = &lut_pad_ops, | ||
215 | }; | ||
216 | |||
217 | /* ----------------------------------------------------------------------------- | ||
218 | * Initialization and Cleanup | ||
219 | */ | ||
220 | |||
221 | struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) | ||
222 | { | ||
223 | struct v4l2_subdev *subdev; | ||
224 | struct vsp1_lut *lut; | ||
225 | int ret; | ||
226 | |||
227 | lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL); | ||
228 | if (lut == NULL) | ||
229 | return ERR_PTR(-ENOMEM); | ||
230 | |||
231 | lut->entity.type = VSP1_ENTITY_LUT; | ||
232 | lut->entity.id = VI6_DPR_NODE_LUT; | ||
233 | |||
234 | ret = vsp1_entity_init(vsp1, &lut->entity, 2); | ||
235 | if (ret < 0) | ||
236 | return ERR_PTR(ret); | ||
237 | |||
238 | /* Initialize the V4L2 subdev. */ | ||
239 | subdev = &lut->entity.subdev; | ||
240 | v4l2_subdev_init(subdev, &lut_ops); | ||
241 | |||
242 | subdev->entity.ops = &vsp1_media_ops; | ||
243 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
244 | snprintf(subdev->name, sizeof(subdev->name), "%s lut", | ||
245 | dev_name(vsp1->dev)); | ||
246 | v4l2_set_subdevdata(subdev, lut); | ||
247 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
248 | |||
249 | vsp1_entity_init_formats(subdev, NULL); | ||
250 | |||
251 | return lut; | ||
252 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h new file mode 100644 index 000000000000..f92ffb867350 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_lut.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * vsp1_lut.h -- R-Car VSP1 Look-Up Table | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
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 | #ifndef __VSP1_LUT_H__ | ||
14 | #define __VSP1_LUT_H__ | ||
15 | |||
16 | #include <media/media-entity.h> | ||
17 | #include <media/v4l2-subdev.h> | ||
18 | |||
19 | #include "vsp1_entity.h" | ||
20 | |||
21 | struct vsp1_device; | ||
22 | |||
23 | #define LUT_PAD_SINK 0 | ||
24 | #define LUT_PAD_SOURCE 1 | ||
25 | |||
26 | struct vsp1_lut { | ||
27 | struct vsp1_entity entity; | ||
28 | u32 lut[256]; | ||
29 | }; | ||
30 | |||
31 | static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev) | ||
32 | { | ||
33 | return container_of(subdev, struct vsp1_lut, entity.subdev); | ||
34 | } | ||
35 | |||
36 | struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1); | ||
37 | |||
38 | #endif /* __VSP1_LUT_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 1d3304f1365b..28650806c20f 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h | |||
@@ -336,8 +336,21 @@ | |||
336 | */ | 336 | */ |
337 | 337 | ||
338 | #define VI6_SRU_CTRL0 0x2200 | 338 | #define VI6_SRU_CTRL0 0x2200 |
339 | #define VI6_SRU_CTRL0_PARAM0_SHIFT 16 | ||
340 | #define VI6_SRU_CTRL0_PARAM1_SHIFT 8 | ||
341 | #define VI6_SRU_CTRL0_MODE_UPSCALE (4 << 4) | ||
342 | #define VI6_SRU_CTRL0_PARAM2 (1 << 3) | ||
343 | #define VI6_SRU_CTRL0_PARAM3 (1 << 2) | ||
344 | #define VI6_SRU_CTRL0_PARAM4 (1 << 1) | ||
345 | #define VI6_SRU_CTRL0_EN (1 << 0) | ||
346 | |||
339 | #define VI6_SRU_CTRL1 0x2204 | 347 | #define VI6_SRU_CTRL1 0x2204 |
348 | #define VI6_SRU_CTRL1_PARAM5 0x7ff | ||
349 | |||
340 | #define VI6_SRU_CTRL2 0x2208 | 350 | #define VI6_SRU_CTRL2 0x2208 |
351 | #define VI6_SRU_CTRL2_PARAM6_SHIFT 16 | ||
352 | #define VI6_SRU_CTRL2_PARAM7_SHIFT 8 | ||
353 | #define VI6_SRU_CTRL2_PARAM8_SHIFT 0 | ||
341 | 354 | ||
342 | /* ----------------------------------------------------------------------------- | 355 | /* ----------------------------------------------------------------------------- |
343 | * UDS Control Registers | 356 | * UDS Control Registers |
@@ -412,6 +425,7 @@ | |||
412 | */ | 425 | */ |
413 | 426 | ||
414 | #define VI6_LUT_CTRL 0x2800 | 427 | #define VI6_LUT_CTRL 0x2800 |
428 | #define VI6_LUT_CTRL_EN (1 << 0) | ||
415 | 429 | ||
416 | /* ----------------------------------------------------------------------------- | 430 | /* ----------------------------------------------------------------------------- |
417 | * CLU Control Registers | 431 | * CLU Control Registers |
@@ -424,12 +438,14 @@ | |||
424 | */ | 438 | */ |
425 | 439 | ||
426 | #define VI6_HST_CTRL 0x2a00 | 440 | #define VI6_HST_CTRL 0x2a00 |
441 | #define VI6_HST_CTRL_EN (1 << 0) | ||
427 | 442 | ||
428 | /* ----------------------------------------------------------------------------- | 443 | /* ----------------------------------------------------------------------------- |
429 | * HSI Control Registers | 444 | * HSI Control Registers |
430 | */ | 445 | */ |
431 | 446 | ||
432 | #define VI6_HSI_CTRL 0x2b00 | 447 | #define VI6_HSI_CTRL 0x2b00 |
448 | #define VI6_HSI_CTRL_EN (1 << 0) | ||
433 | 449 | ||
434 | /* ----------------------------------------------------------------------------- | 450 | /* ----------------------------------------------------------------------------- |
435 | * BRU Control Registers | 451 | * BRU Control Registers |
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 254871d3423e..bce2be5466b9 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c | |||
@@ -47,25 +47,36 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
47 | struct vsp1_rwpf *rpf = to_rwpf(subdev); | 47 | struct vsp1_rwpf *rpf = to_rwpf(subdev); |
48 | const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo; | 48 | const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo; |
49 | const struct v4l2_pix_format_mplane *format = &rpf->video.format; | 49 | const struct v4l2_pix_format_mplane *format = &rpf->video.format; |
50 | const struct v4l2_rect *crop = &rpf->crop; | ||
50 | u32 pstride; | 51 | u32 pstride; |
51 | u32 infmt; | 52 | u32 infmt; |
52 | 53 | ||
53 | if (!enable) | 54 | if (!enable) |
54 | return 0; | 55 | return 0; |
55 | 56 | ||
56 | /* Source size and stride. Cropping isn't supported yet. */ | 57 | /* Source size, stride and crop offsets. |
58 | * | ||
59 | * The crop offsets correspond to the location of the crop rectangle top | ||
60 | * left corner in the plane buffer. Only two offsets are needed, as | ||
61 | * planes 2 and 3 always have identical strides. | ||
62 | */ | ||
57 | vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE, | 63 | vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE, |
58 | (format->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | | 64 | (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | |
59 | (format->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); | 65 | (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); |
60 | vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE, | 66 | vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE, |
61 | (format->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | | 67 | (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | |
62 | (format->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); | 68 | (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); |
63 | 69 | ||
70 | rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline | ||
71 | + crop->left * fmtinfo->bpp[0] / 8; | ||
64 | pstride = format->plane_fmt[0].bytesperline | 72 | pstride = format->plane_fmt[0].bytesperline |
65 | << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; | 73 | << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; |
66 | if (format->num_planes > 1) | 74 | if (format->num_planes > 1) { |
75 | rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline | ||
76 | + crop->left * fmtinfo->bpp[1] / 8; | ||
67 | pstride |= format->plane_fmt[1].bytesperline | 77 | pstride |= format->plane_fmt[1].bytesperline |
68 | << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; | 78 | << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; |
79 | } | ||
69 | 80 | ||
70 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride); | 81 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride); |
71 | 82 | ||
@@ -113,6 +124,8 @@ static struct v4l2_subdev_pad_ops rpf_pad_ops = { | |||
113 | .enum_frame_size = vsp1_rwpf_enum_frame_size, | 124 | .enum_frame_size = vsp1_rwpf_enum_frame_size, |
114 | .get_fmt = vsp1_rwpf_get_format, | 125 | .get_fmt = vsp1_rwpf_get_format, |
115 | .set_fmt = vsp1_rwpf_set_format, | 126 | .set_fmt = vsp1_rwpf_set_format, |
127 | .get_selection = vsp1_rwpf_get_selection, | ||
128 | .set_selection = vsp1_rwpf_set_selection, | ||
116 | }; | 129 | }; |
117 | 130 | ||
118 | static struct v4l2_subdev_ops rpf_ops = { | 131 | static struct v4l2_subdev_ops rpf_ops = { |
@@ -129,11 +142,14 @@ static void rpf_vdev_queue(struct vsp1_video *video, | |||
129 | { | 142 | { |
130 | struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video); | 143 | struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video); |
131 | 144 | ||
132 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, buf->addr[0]); | 145 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, |
146 | buf->addr[0] + rpf->offsets[0]); | ||
133 | if (buf->buf.num_planes > 1) | 147 | if (buf->buf.num_planes > 1) |
134 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, buf->addr[1]); | 148 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, |
149 | buf->addr[1] + rpf->offsets[1]); | ||
135 | if (buf->buf.num_planes > 2) | 150 | if (buf->buf.num_planes > 2) |
136 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, buf->addr[2]); | 151 | vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, |
152 | buf->addr[2] + rpf->offsets[1]); | ||
137 | } | 153 | } |
138 | 154 | ||
139 | static const struct vsp1_video_operations rpf_vdev_ops = { | 155 | static const struct vsp1_video_operations rpf_vdev_ops = { |
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 9752d5516ceb..782f770daee5 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c | |||
@@ -71,6 +71,19 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, | |||
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
73 | 73 | ||
74 | static struct v4l2_rect * | ||
75 | vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which) | ||
76 | { | ||
77 | switch (which) { | ||
78 | case V4L2_SUBDEV_FORMAT_TRY: | ||
79 | return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK); | ||
80 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
81 | return &rwpf->crop; | ||
82 | default: | ||
83 | return NULL; | ||
84 | } | ||
85 | } | ||
86 | |||
74 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 87 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, |
75 | struct v4l2_subdev_format *fmt) | 88 | struct v4l2_subdev_format *fmt) |
76 | { | 89 | { |
@@ -87,6 +100,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
87 | { | 100 | { |
88 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 101 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
89 | struct v4l2_mbus_framefmt *format; | 102 | struct v4l2_mbus_framefmt *format; |
103 | struct v4l2_rect *crop; | ||
90 | 104 | ||
91 | /* Default to YUV if the requested format is not supported. */ | 105 | /* Default to YUV if the requested format is not supported. */ |
92 | if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 && | 106 | if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 && |
@@ -115,6 +129,13 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
115 | 129 | ||
116 | fmt->format = *format; | 130 | fmt->format = *format; |
117 | 131 | ||
132 | /* Update the sink crop rectangle. */ | ||
133 | crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which); | ||
134 | crop->left = 0; | ||
135 | crop->top = 0; | ||
136 | crop->width = fmt->format.width; | ||
137 | crop->height = fmt->format.height; | ||
138 | |||
118 | /* Propagate the format to the source pad. */ | 139 | /* Propagate the format to the source pad. */ |
119 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, | 140 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, |
120 | fmt->which); | 141 | fmt->which); |
@@ -122,3 +143,78 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
122 | 143 | ||
123 | return 0; | 144 | return 0; |
124 | } | 145 | } |
146 | |||
147 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | ||
148 | struct v4l2_subdev_fh *fh, | ||
149 | struct v4l2_subdev_selection *sel) | ||
150 | { | ||
151 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | ||
152 | struct v4l2_mbus_framefmt *format; | ||
153 | |||
154 | /* Cropping is implemented on the sink pad. */ | ||
155 | if (sel->pad != RWPF_PAD_SINK) | ||
156 | return -EINVAL; | ||
157 | |||
158 | switch (sel->target) { | ||
159 | case V4L2_SEL_TGT_CROP: | ||
160 | sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which); | ||
161 | break; | ||
162 | |||
163 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
164 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, | ||
165 | RWPF_PAD_SINK, sel->which); | ||
166 | sel->r.left = 0; | ||
167 | sel->r.top = 0; | ||
168 | sel->r.width = format->width; | ||
169 | sel->r.height = format->height; | ||
170 | break; | ||
171 | |||
172 | default: | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | ||
180 | struct v4l2_subdev_fh *fh, | ||
181 | struct v4l2_subdev_selection *sel) | ||
182 | { | ||
183 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | ||
184 | struct v4l2_mbus_framefmt *format; | ||
185 | struct v4l2_rect *crop; | ||
186 | |||
187 | /* Cropping is implemented on the sink pad. */ | ||
188 | if (sel->pad != RWPF_PAD_SINK) | ||
189 | return -EINVAL; | ||
190 | |||
191 | if (sel->target != V4L2_SEL_TGT_CROP) | ||
192 | return -EINVAL; | ||
193 | |||
194 | /* Make sure the crop rectangle is entirely contained in the image. The | ||
195 | * WPF top and left offsets are limited to 255. | ||
196 | */ | ||
197 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK, | ||
198 | sel->which); | ||
199 | sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); | ||
200 | sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); | ||
201 | if (rwpf->entity.type == VSP1_ENTITY_WPF) { | ||
202 | sel->r.left = min_t(unsigned int, sel->r.left, 255); | ||
203 | sel->r.top = min_t(unsigned int, sel->r.top, 255); | ||
204 | } | ||
205 | sel->r.width = min_t(unsigned int, sel->r.width, | ||
206 | format->width - sel->r.left); | ||
207 | sel->r.height = min_t(unsigned int, sel->r.height, | ||
208 | format->height - sel->r.top); | ||
209 | |||
210 | crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which); | ||
211 | *crop = sel->r; | ||
212 | |||
213 | /* Propagate the format to the source pad. */ | ||
214 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, | ||
215 | sel->which); | ||
216 | format->width = crop->width; | ||
217 | format->height = crop->height; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index c182d85f36b3..6cbdb547470b 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h | |||
@@ -29,6 +29,10 @@ struct vsp1_rwpf { | |||
29 | 29 | ||
30 | unsigned int max_width; | 30 | unsigned int max_width; |
31 | unsigned int max_height; | 31 | unsigned int max_height; |
32 | |||
33 | struct v4l2_rect crop; | ||
34 | |||
35 | unsigned int offsets[2]; | ||
32 | }; | 36 | }; |
33 | 37 | ||
34 | static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) | 38 | static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) |
@@ -49,5 +53,11 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
49 | struct v4l2_subdev_format *fmt); | 53 | struct v4l2_subdev_format *fmt); |
50 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 54 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, |
51 | struct v4l2_subdev_format *fmt); | 55 | struct v4l2_subdev_format *fmt); |
56 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | ||
57 | struct v4l2_subdev_fh *fh, | ||
58 | struct v4l2_subdev_selection *sel); | ||
59 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | ||
60 | struct v4l2_subdev_fh *fh, | ||
61 | struct v4l2_subdev_selection *sel); | ||
52 | 62 | ||
53 | #endif /* __VSP1_RWPF_H__ */ | 63 | #endif /* __VSP1_RWPF_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c new file mode 100644 index 000000000000..7ab1a0b2d656 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_sru.c | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * vsp1_sru.c -- R-Car VSP1 Super Resolution Unit | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
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 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/gfp.h> | ||
16 | |||
17 | #include <media/v4l2-subdev.h> | ||
18 | |||
19 | #include "vsp1.h" | ||
20 | #include "vsp1_sru.h" | ||
21 | |||
22 | #define SRU_MIN_SIZE 4U | ||
23 | #define SRU_MAX_SIZE 8190U | ||
24 | |||
25 | /* ----------------------------------------------------------------------------- | ||
26 | * Device Access | ||
27 | */ | ||
28 | |||
29 | static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg) | ||
30 | { | ||
31 | return vsp1_read(sru->entity.vsp1, reg); | ||
32 | } | ||
33 | |||
34 | static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data) | ||
35 | { | ||
36 | vsp1_write(sru->entity.vsp1, reg, data); | ||
37 | } | ||
38 | |||
39 | /* ----------------------------------------------------------------------------- | ||
40 | * Controls | ||
41 | */ | ||
42 | |||
43 | #define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE + 1) | ||
44 | |||
45 | static int sru_s_ctrl(struct v4l2_ctrl *ctrl) | ||
46 | { | ||
47 | struct vsp1_sru *sru = | ||
48 | container_of(ctrl->handler, struct vsp1_sru, ctrls); | ||
49 | |||
50 | switch (ctrl->id) { | ||
51 | case V4L2_CID_VSP1_SRU_INTENSITY: | ||
52 | sru->intensity = ctrl->val; | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static const struct v4l2_ctrl_ops sru_ctrl_ops = { | ||
60 | .s_ctrl = sru_s_ctrl, | ||
61 | }; | ||
62 | |||
63 | static const struct v4l2_ctrl_config sru_intensity_control = { | ||
64 | .ops = &sru_ctrl_ops, | ||
65 | .id = V4L2_CID_VSP1_SRU_INTENSITY, | ||
66 | .name = "Intensity", | ||
67 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
68 | .min = 1, | ||
69 | .max = 6, | ||
70 | .step = 1, | ||
71 | }; | ||
72 | |||
73 | /* ----------------------------------------------------------------------------- | ||
74 | * V4L2 Subdevice Core Operations | ||
75 | */ | ||
76 | |||
77 | struct vsp1_sru_param { | ||
78 | u32 ctrl0; | ||
79 | u32 ctrl2; | ||
80 | }; | ||
81 | |||
82 | #define VI6_SRU_CTRL0_PARAMS(p0, p1) \ | ||
83 | (((p0) << VI6_SRU_CTRL0_PARAM0_SHIFT) | \ | ||
84 | ((p1) << VI6_SRU_CTRL0_PARAM1_SHIFT)) | ||
85 | |||
86 | #define VI6_SRU_CTRL2_PARAMS(p6, p7, p8) \ | ||
87 | (((p6) << VI6_SRU_CTRL2_PARAM6_SHIFT) | \ | ||
88 | ((p7) << VI6_SRU_CTRL2_PARAM7_SHIFT) | \ | ||
89 | ((p8) << VI6_SRU_CTRL2_PARAM8_SHIFT)) | ||
90 | |||
91 | static const struct vsp1_sru_param vsp1_sru_params[] = { | ||
92 | { | ||
93 | .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN, | ||
94 | .ctrl2 = VI6_SRU_CTRL2_PARAMS(24, 40, 255), | ||
95 | }, { | ||
96 | .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN, | ||
97 | .ctrl2 = VI6_SRU_CTRL2_PARAMS(8, 16, 255), | ||
98 | }, { | ||
99 | .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN, | ||
100 | .ctrl2 = VI6_SRU_CTRL2_PARAMS(36, 60, 255), | ||
101 | }, { | ||
102 | .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN, | ||
103 | .ctrl2 = VI6_SRU_CTRL2_PARAMS(12, 27, 255), | ||
104 | }, { | ||
105 | .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN, | ||
106 | .ctrl2 = VI6_SRU_CTRL2_PARAMS(48, 80, 255), | ||
107 | }, { | ||
108 | .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN, | ||
109 | .ctrl2 = VI6_SRU_CTRL2_PARAMS(16, 36, 255), | ||
110 | }, | ||
111 | }; | ||
112 | |||
113 | static int sru_s_stream(struct v4l2_subdev *subdev, int enable) | ||
114 | { | ||
115 | struct vsp1_sru *sru = to_sru(subdev); | ||
116 | const struct vsp1_sru_param *param; | ||
117 | struct v4l2_mbus_framefmt *input; | ||
118 | struct v4l2_mbus_framefmt *output; | ||
119 | bool upscale; | ||
120 | u32 ctrl0; | ||
121 | |||
122 | if (!enable) | ||
123 | return 0; | ||
124 | |||
125 | input = &sru->entity.formats[SRU_PAD_SINK]; | ||
126 | output = &sru->entity.formats[SRU_PAD_SOURCE]; | ||
127 | upscale = input->width != output->width; | ||
128 | param = &vsp1_sru_params[sru->intensity]; | ||
129 | |||
130 | if (input->code == V4L2_MBUS_FMT_ARGB8888_1X32) | ||
131 | ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 | ||
132 | | VI6_SRU_CTRL0_PARAM4; | ||
133 | else | ||
134 | ctrl0 = VI6_SRU_CTRL0_PARAM3; | ||
135 | |||
136 | vsp1_sru_write(sru, VI6_SRU_CTRL0, param->ctrl0 | ctrl0 | | ||
137 | (upscale ? VI6_SRU_CTRL0_MODE_UPSCALE : 0)); | ||
138 | vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5); | ||
139 | vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /* ----------------------------------------------------------------------------- | ||
145 | * V4L2 Subdevice Pad Operations | ||
146 | */ | ||
147 | |||
148 | static int sru_enum_mbus_code(struct v4l2_subdev *subdev, | ||
149 | struct v4l2_subdev_fh *fh, | ||
150 | struct v4l2_subdev_mbus_code_enum *code) | ||
151 | { | ||
152 | static const unsigned int codes[] = { | ||
153 | V4L2_MBUS_FMT_ARGB8888_1X32, | ||
154 | V4L2_MBUS_FMT_AYUV8_1X32, | ||
155 | }; | ||
156 | struct v4l2_mbus_framefmt *format; | ||
157 | |||
158 | if (code->pad == SRU_PAD_SINK) { | ||
159 | if (code->index >= ARRAY_SIZE(codes)) | ||
160 | return -EINVAL; | ||
161 | |||
162 | code->code = codes[code->index]; | ||
163 | } else { | ||
164 | /* The SRU can't perform format conversion, the sink format is | ||
165 | * always identical to the source format. | ||
166 | */ | ||
167 | if (code->index) | ||
168 | return -EINVAL; | ||
169 | |||
170 | format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); | ||
171 | code->code = format->code; | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int sru_enum_frame_size(struct v4l2_subdev *subdev, | ||
178 | struct v4l2_subdev_fh *fh, | ||
179 | struct v4l2_subdev_frame_size_enum *fse) | ||
180 | { | ||
181 | struct v4l2_mbus_framefmt *format; | ||
182 | |||
183 | format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); | ||
184 | |||
185 | if (fse->index || fse->code != format->code) | ||
186 | return -EINVAL; | ||
187 | |||
188 | if (fse->pad == SRU_PAD_SINK) { | ||
189 | fse->min_width = SRU_MIN_SIZE; | ||
190 | fse->max_width = SRU_MAX_SIZE; | ||
191 | fse->min_height = SRU_MIN_SIZE; | ||
192 | fse->max_height = SRU_MAX_SIZE; | ||
193 | } else { | ||
194 | fse->min_width = format->width; | ||
195 | fse->min_height = format->height; | ||
196 | if (format->width <= SRU_MAX_SIZE / 2 && | ||
197 | format->height <= SRU_MAX_SIZE / 2) { | ||
198 | fse->max_width = format->width * 2; | ||
199 | fse->max_height = format->height * 2; | ||
200 | } else { | ||
201 | fse->max_width = format->width; | ||
202 | fse->max_height = format->height; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | ||
210 | struct v4l2_subdev_format *fmt) | ||
211 | { | ||
212 | struct vsp1_sru *sru = to_sru(subdev); | ||
213 | |||
214 | fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, | ||
215 | fmt->which); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, | ||
221 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | ||
222 | enum v4l2_subdev_format_whence which) | ||
223 | { | ||
224 | struct v4l2_mbus_framefmt *format; | ||
225 | unsigned int input_area; | ||
226 | unsigned int output_area; | ||
227 | |||
228 | switch (pad) { | ||
229 | case SRU_PAD_SINK: | ||
230 | /* Default to YUV if the requested format is not supported. */ | ||
231 | if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && | ||
232 | fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) | ||
233 | fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; | ||
234 | |||
235 | fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE); | ||
236 | fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE); | ||
237 | break; | ||
238 | |||
239 | case SRU_PAD_SOURCE: | ||
240 | /* The SRU can't perform format conversion. */ | ||
241 | format = vsp1_entity_get_pad_format(&sru->entity, fh, | ||
242 | SRU_PAD_SINK, which); | ||
243 | fmt->code = format->code; | ||
244 | |||
245 | /* We can upscale by 2 in both direction, but not independently. | ||
246 | * Compare the input and output rectangles areas (avoiding | ||
247 | * integer overflows on the output): if the requested output | ||
248 | * area is larger than 1.5^2 the input area upscale by two, | ||
249 | * otherwise don't scale. | ||
250 | */ | ||
251 | input_area = format->width * format->height; | ||
252 | output_area = min(fmt->width, SRU_MAX_SIZE) | ||
253 | * min(fmt->height, SRU_MAX_SIZE); | ||
254 | |||
255 | if (fmt->width <= SRU_MAX_SIZE / 2 && | ||
256 | fmt->height <= SRU_MAX_SIZE / 2 && | ||
257 | output_area > input_area * 9 / 4) { | ||
258 | fmt->width = format->width * 2; | ||
259 | fmt->height = format->height * 2; | ||
260 | } else { | ||
261 | fmt->width = format->width; | ||
262 | fmt->height = format->height; | ||
263 | } | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | fmt->field = V4L2_FIELD_NONE; | ||
268 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | ||
269 | } | ||
270 | |||
271 | static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | ||
272 | struct v4l2_subdev_format *fmt) | ||
273 | { | ||
274 | struct vsp1_sru *sru = to_sru(subdev); | ||
275 | struct v4l2_mbus_framefmt *format; | ||
276 | |||
277 | sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which); | ||
278 | |||
279 | format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, | ||
280 | fmt->which); | ||
281 | *format = fmt->format; | ||
282 | |||
283 | if (fmt->pad == SRU_PAD_SINK) { | ||
284 | /* Propagate the format to the source pad. */ | ||
285 | format = vsp1_entity_get_pad_format(&sru->entity, fh, | ||
286 | SRU_PAD_SOURCE, fmt->which); | ||
287 | *format = fmt->format; | ||
288 | |||
289 | sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which); | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /* ----------------------------------------------------------------------------- | ||
296 | * V4L2 Subdevice Operations | ||
297 | */ | ||
298 | |||
299 | static struct v4l2_subdev_video_ops sru_video_ops = { | ||
300 | .s_stream = sru_s_stream, | ||
301 | }; | ||
302 | |||
303 | static struct v4l2_subdev_pad_ops sru_pad_ops = { | ||
304 | .enum_mbus_code = sru_enum_mbus_code, | ||
305 | .enum_frame_size = sru_enum_frame_size, | ||
306 | .get_fmt = sru_get_format, | ||
307 | .set_fmt = sru_set_format, | ||
308 | }; | ||
309 | |||
310 | static struct v4l2_subdev_ops sru_ops = { | ||
311 | .video = &sru_video_ops, | ||
312 | .pad = &sru_pad_ops, | ||
313 | }; | ||
314 | |||
315 | /* ----------------------------------------------------------------------------- | ||
316 | * Initialization and Cleanup | ||
317 | */ | ||
318 | |||
319 | struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) | ||
320 | { | ||
321 | struct v4l2_subdev *subdev; | ||
322 | struct vsp1_sru *sru; | ||
323 | int ret; | ||
324 | |||
325 | sru = devm_kzalloc(vsp1->dev, sizeof(*sru), GFP_KERNEL); | ||
326 | if (sru == NULL) | ||
327 | return ERR_PTR(-ENOMEM); | ||
328 | |||
329 | sru->entity.type = VSP1_ENTITY_SRU; | ||
330 | sru->entity.id = VI6_DPR_NODE_SRU; | ||
331 | |||
332 | ret = vsp1_entity_init(vsp1, &sru->entity, 2); | ||
333 | if (ret < 0) | ||
334 | return ERR_PTR(ret); | ||
335 | |||
336 | /* Initialize the V4L2 subdev. */ | ||
337 | subdev = &sru->entity.subdev; | ||
338 | v4l2_subdev_init(subdev, &sru_ops); | ||
339 | |||
340 | subdev->entity.ops = &vsp1_media_ops; | ||
341 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
342 | snprintf(subdev->name, sizeof(subdev->name), "%s sru", | ||
343 | dev_name(vsp1->dev)); | ||
344 | v4l2_set_subdevdata(subdev, sru); | ||
345 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
346 | |||
347 | vsp1_entity_init_formats(subdev, NULL); | ||
348 | |||
349 | /* Initialize the control handler. */ | ||
350 | v4l2_ctrl_handler_init(&sru->ctrls, 1); | ||
351 | v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL); | ||
352 | v4l2_ctrl_handler_setup(&sru->ctrls); | ||
353 | sru->entity.subdev.ctrl_handler = &sru->ctrls; | ||
354 | |||
355 | return sru; | ||
356 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_sru.h b/drivers/media/platform/vsp1/vsp1_sru.h new file mode 100644 index 000000000000..381870b74780 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_sru.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * vsp1_sru.h -- R-Car VSP1 Super Resolution Unit | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
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 | #ifndef __VSP1_SRU_H__ | ||
14 | #define __VSP1_SRU_H__ | ||
15 | |||
16 | #include <media/media-entity.h> | ||
17 | #include <media/v4l2-ctrls.h> | ||
18 | #include <media/v4l2-subdev.h> | ||
19 | |||
20 | #include "vsp1_entity.h" | ||
21 | |||
22 | struct vsp1_device; | ||
23 | |||
24 | #define SRU_PAD_SINK 0 | ||
25 | #define SRU_PAD_SOURCE 1 | ||
26 | |||
27 | struct vsp1_sru { | ||
28 | struct vsp1_entity entity; | ||
29 | |||
30 | struct v4l2_ctrl_handler ctrls; | ||
31 | unsigned int intensity; | ||
32 | }; | ||
33 | |||
34 | static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev) | ||
35 | { | ||
36 | return container_of(subdev, struct vsp1_sru, entity.subdev); | ||
37 | } | ||
38 | |||
39 | struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1); | ||
40 | |||
41 | #endif /* __VSP1_SRU_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 4b0ac07af662..b4687a834f85 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c | |||
@@ -488,11 +488,17 @@ static bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe) | |||
488 | * This function completes the current buffer by filling its sequence number, | 488 | * This function completes the current buffer by filling its sequence number, |
489 | * time stamp and payload size, and hands it back to the videobuf core. | 489 | * time stamp and payload size, and hands it back to the videobuf core. |
490 | * | 490 | * |
491 | * When operating in DU output mode (deep pipeline to the DU through the LIF), | ||
492 | * the VSP1 needs to constantly supply frames to the display. In that case, if | ||
493 | * no other buffer is queued, reuse the one that has just been processed instead | ||
494 | * of handing it back to the videobuf core. | ||
495 | * | ||
491 | * Return the next queued buffer or NULL if the queue is empty. | 496 | * Return the next queued buffer or NULL if the queue is empty. |
492 | */ | 497 | */ |
493 | static struct vsp1_video_buffer * | 498 | static struct vsp1_video_buffer * |
494 | vsp1_video_complete_buffer(struct vsp1_video *video) | 499 | vsp1_video_complete_buffer(struct vsp1_video *video) |
495 | { | 500 | { |
501 | struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); | ||
496 | struct vsp1_video_buffer *next = NULL; | 502 | struct vsp1_video_buffer *next = NULL; |
497 | struct vsp1_video_buffer *done; | 503 | struct vsp1_video_buffer *done; |
498 | unsigned long flags; | 504 | unsigned long flags; |
@@ -507,6 +513,13 @@ vsp1_video_complete_buffer(struct vsp1_video *video) | |||
507 | 513 | ||
508 | done = list_first_entry(&video->irqqueue, | 514 | done = list_first_entry(&video->irqqueue, |
509 | struct vsp1_video_buffer, queue); | 515 | struct vsp1_video_buffer, queue); |
516 | |||
517 | /* In DU output mode reuse the buffer if the list is singular. */ | ||
518 | if (pipe->lif && list_is_singular(&video->irqqueue)) { | ||
519 | spin_unlock_irqrestore(&video->irqlock, flags); | ||
520 | return done; | ||
521 | } | ||
522 | |||
510 | list_del(&done->queue); | 523 | list_del(&done->queue); |
511 | 524 | ||
512 | if (!list_empty(&video->irqqueue)) | 525 | if (!list_empty(&video->irqqueue)) |
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index db4b85ee05fc..7baed81ff005 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c | |||
@@ -48,8 +48,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
48 | struct vsp1_pipeline *pipe = | 48 | struct vsp1_pipeline *pipe = |
49 | to_vsp1_pipeline(&wpf->entity.subdev.entity); | 49 | to_vsp1_pipeline(&wpf->entity.subdev.entity); |
50 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | 50 | struct vsp1_device *vsp1 = wpf->entity.vsp1; |
51 | const struct v4l2_mbus_framefmt *format = | 51 | const struct v4l2_rect *crop = &wpf->crop; |
52 | &wpf->entity.formats[RWPF_PAD_SOURCE]; | ||
53 | unsigned int i; | 52 | unsigned int i; |
54 | u32 srcrpf = 0; | 53 | u32 srcrpf = 0; |
55 | u32 outfmt = 0; | 54 | u32 outfmt = 0; |
@@ -68,7 +67,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
68 | 67 | ||
69 | vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); | 68 | vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); |
70 | 69 | ||
71 | /* Destination stride. Cropping isn't supported yet. */ | 70 | /* Destination stride. */ |
72 | if (!pipe->lif) { | 71 | if (!pipe->lif) { |
73 | struct v4l2_pix_format_mplane *format = &wpf->video.format; | 72 | struct v4l2_pix_format_mplane *format = &wpf->video.format; |
74 | 73 | ||
@@ -79,10 +78,12 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
79 | format->plane_fmt[1].bytesperline); | 78 | format->plane_fmt[1].bytesperline); |
80 | } | 79 | } |
81 | 80 | ||
82 | vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, | 81 | vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | |
83 | format->width << VI6_WPF_SZCLIP_SIZE_SHIFT); | 82 | (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) | |
84 | vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, | 83 | (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT)); |
85 | format->height << VI6_WPF_SZCLIP_SIZE_SHIFT); | 84 | vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | |
85 | (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
86 | (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
86 | 87 | ||
87 | /* Format */ | 88 | /* Format */ |
88 | if (!pipe->lif) { | 89 | if (!pipe->lif) { |
@@ -130,6 +131,8 @@ static struct v4l2_subdev_pad_ops wpf_pad_ops = { | |||
130 | .enum_frame_size = vsp1_rwpf_enum_frame_size, | 131 | .enum_frame_size = vsp1_rwpf_enum_frame_size, |
131 | .get_fmt = vsp1_rwpf_get_format, | 132 | .get_fmt = vsp1_rwpf_get_format, |
132 | .set_fmt = vsp1_rwpf_set_format, | 133 | .set_fmt = vsp1_rwpf_set_format, |
134 | .get_selection = vsp1_rwpf_get_selection, | ||
135 | .set_selection = vsp1_rwpf_set_selection, | ||
133 | }; | 136 | }; |
134 | 137 | ||
135 | static struct v4l2_subdev_ops wpf_ops = { | 138 | static struct v4l2_subdev_ops wpf_ops = { |
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 6ecdc39bb366..192f36f2f4aa 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig | |||
@@ -21,6 +21,12 @@ config RADIO_SI470X | |||
21 | 21 | ||
22 | source "drivers/media/radio/si470x/Kconfig" | 22 | source "drivers/media/radio/si470x/Kconfig" |
23 | 23 | ||
24 | config RADIO_SI4713 | ||
25 | tristate "Silicon Labs Si4713 FM Radio with RDS Transmitter support" | ||
26 | depends on VIDEO_V4L2 | ||
27 | |||
28 | source "drivers/media/radio/si4713/Kconfig" | ||
29 | |||
24 | config RADIO_SI476X | 30 | config RADIO_SI476X |
25 | tristate "Silicon Laboratories Si476x I2C FM Radio" | 31 | tristate "Silicon Laboratories Si476x I2C FM Radio" |
26 | depends on I2C && VIDEO_V4L2 | 32 | depends on I2C && VIDEO_V4L2 |
@@ -113,29 +119,6 @@ config RADIO_SHARK2 | |||
113 | To compile this driver as a module, choose M here: the | 119 | To compile this driver as a module, choose M here: the |
114 | module will be called radio-shark2. | 120 | module will be called radio-shark2. |
115 | 121 | ||
116 | config I2C_SI4713 | ||
117 | tristate "I2C driver for Silicon Labs Si4713 device" | ||
118 | depends on I2C && VIDEO_V4L2 | ||
119 | ---help--- | ||
120 | Say Y here if you want support to Si4713 I2C device. | ||
121 | This device driver supports only i2c bus. | ||
122 | |||
123 | To compile this driver as a module, choose M here: the | ||
124 | module will be called si4713. | ||
125 | |||
126 | config RADIO_SI4713 | ||
127 | tristate "Silicon Labs Si4713 FM Radio Transmitter support" | ||
128 | depends on I2C && VIDEO_V4L2 | ||
129 | select I2C_SI4713 | ||
130 | ---help--- | ||
131 | Say Y here if you want support to Si4713 FM Radio Transmitter. | ||
132 | This device can transmit audio through FM. It can transmit | ||
133 | RDS and RBDS signals as well. This module is the v4l2 radio | ||
134 | interface for the i2c driver of this device. | ||
135 | |||
136 | To compile this driver as a module, choose M here: the | ||
137 | module will be called radio-si4713. | ||
138 | |||
139 | config USB_KEENE | 122 | config USB_KEENE |
140 | tristate "Keene FM Transmitter USB support" | 123 | tristate "Keene FM Transmitter USB support" |
141 | depends on USB && VIDEO_V4L2 | 124 | depends on USB && VIDEO_V4L2 |
@@ -146,6 +129,20 @@ config USB_KEENE | |||
146 | To compile this driver as a module, choose M here: the | 129 | To compile this driver as a module, choose M here: the |
147 | module will be called radio-keene. | 130 | module will be called radio-keene. |
148 | 131 | ||
132 | config USB_RAREMONO | ||
133 | tristate "Thanko's Raremono AM/FM/SW radio support" | ||
134 | depends on USB && VIDEO_V4L2 | ||
135 | ---help--- | ||
136 | The 'Thanko's Raremono' device contains the Si4734 chip from Silicon Labs Inc. | ||
137 | It is one of the very few or perhaps the only consumer USB radio device | ||
138 | to receive the AM/FM/SW bands. | ||
139 | |||
140 | Say Y here if you want to connect this type of AM/FM/SW receiver | ||
141 | to your computer's USB port. | ||
142 | |||
143 | To compile this driver as a module, choose M here: the | ||
144 | module will be called radio-raremono. | ||
145 | |||
149 | config USB_MA901 | 146 | config USB_MA901 |
150 | tristate "Masterkit MA901 USB FM radio support" | 147 | tristate "Masterkit MA901 USB FM radio support" |
151 | depends on USB && VIDEO_V4L2 | 148 | depends on USB && VIDEO_V4L2 |
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 3b645601800d..120e791199b2 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile | |||
@@ -17,12 +17,11 @@ obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o | |||
17 | obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o | 17 | obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o |
18 | obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o | 18 | obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o |
19 | obj-$(CONFIG_RADIO_TRUST) += radio-trust.o | 19 | obj-$(CONFIG_RADIO_TRUST) += radio-trust.o |
20 | obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o | ||
21 | obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o | ||
22 | obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o | 20 | obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o |
23 | obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o | 21 | obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o |
24 | obj-$(CONFIG_USB_DSBR) += dsbr100.o | 22 | obj-$(CONFIG_USB_DSBR) += dsbr100.o |
25 | obj-$(CONFIG_RADIO_SI470X) += si470x/ | 23 | obj-$(CONFIG_RADIO_SI470X) += si470x/ |
24 | obj-$(CONFIG_RADIO_SI4713) += si4713/ | ||
26 | obj-$(CONFIG_USB_MR800) += radio-mr800.o | 25 | obj-$(CONFIG_USB_MR800) += radio-mr800.o |
27 | obj-$(CONFIG_USB_KEENE) += radio-keene.o | 26 | obj-$(CONFIG_USB_KEENE) += radio-keene.o |
28 | obj-$(CONFIG_USB_MA901) += radio-ma901.o | 27 | obj-$(CONFIG_USB_MA901) += radio-ma901.o |
@@ -33,6 +32,7 @@ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o | |||
33 | obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o | 32 | obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o |
34 | obj-$(CONFIG_RADIO_WL128X) += wl128x/ | 33 | obj-$(CONFIG_RADIO_WL128X) += wl128x/ |
35 | obj-$(CONFIG_RADIO_TEA575X) += tea575x.o | 34 | obj-$(CONFIG_RADIO_TEA575X) += tea575x.o |
35 | obj-$(CONFIG_USB_RAREMONO) += radio-raremono.o | ||
36 | 36 | ||
37 | shark2-objs := radio-shark2.o radio-tea5777.o | 37 | shark2-objs := radio-shark2.o radio-tea5777.o |
38 | 38 | ||
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c new file mode 100644 index 000000000000..7b3bdbb1be73 --- /dev/null +++ b/drivers/media/radio/radio-raremono.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you may redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2 of the License. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
11 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
12 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
15 | * SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/input.h> | ||
23 | #include <linux/usb.h> | ||
24 | #include <linux/hid.h> | ||
25 | #include <linux/mutex.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <asm/unaligned.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/v4l2-ioctl.h> | ||
30 | #include <media/v4l2-ctrls.h> | ||
31 | #include <media/v4l2-event.h> | ||
32 | |||
33 | /* | ||
34 | * 'Thanko's Raremono' is a Japanese si4734-based AM/FM/SW USB receiver: | ||
35 | * | ||
36 | * http://www.raremono.jp/product/484.html/ | ||
37 | * | ||
38 | * The USB protocol has been reversed engineered using wireshark, initially | ||
39 | * by Dinesh Ram <dinesh.ram@cern.ch> and finished by Hans Verkuil | ||
40 | * <hverkuil@xs4all.nl>. | ||
41 | * | ||
42 | * Sadly the firmware used in this product hides lots of goodies since the | ||
43 | * si4734 has more features than are supported by the firmware. Oh well... | ||
44 | */ | ||
45 | |||
46 | /* driver and module definitions */ | ||
47 | MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); | ||
48 | MODULE_DESCRIPTION("Thanko's Raremono AM/FM/SW Receiver USB driver"); | ||
49 | MODULE_LICENSE("GPL v2"); | ||
50 | |||
51 | /* | ||
52 | * The Device announces itself as Cygnal Integrated Products, Inc. | ||
53 | * | ||
54 | * The vendor and product IDs (and in fact all other lsusb information as | ||
55 | * well) are identical to the si470x Silicon Labs USB FM Radio Reference | ||
56 | * Design board, even though this card has a si4734 device. Clearly the | ||
57 | * designer of this product never bothered to change the USB IDs. | ||
58 | */ | ||
59 | |||
60 | /* USB Device ID List */ | ||
61 | static struct usb_device_id usb_raremono_device_table[] = { | ||
62 | {USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, | ||
63 | { } /* Terminating entry */ | ||
64 | }; | ||
65 | |||
66 | MODULE_DEVICE_TABLE(usb, usb_raremono_device_table); | ||
67 | |||
68 | #define BUFFER_LENGTH 64 | ||
69 | |||
70 | /* Timeout is set to a high value, could probably be reduced. Need more tests */ | ||
71 | #define USB_TIMEOUT 10000 | ||
72 | |||
73 | /* Frequency limits in KHz */ | ||
74 | #define FM_FREQ_RANGE_LOW 64000 | ||
75 | #define FM_FREQ_RANGE_HIGH 108000 | ||
76 | |||
77 | #define AM_FREQ_RANGE_LOW 520 | ||
78 | #define AM_FREQ_RANGE_HIGH 1710 | ||
79 | |||
80 | #define SW_FREQ_RANGE_LOW 2300 | ||
81 | #define SW_FREQ_RANGE_HIGH 26100 | ||
82 | |||
83 | enum { BAND_FM, BAND_AM, BAND_SW }; | ||
84 | |||
85 | static const struct v4l2_frequency_band bands[] = { | ||
86 | /* Band FM */ | ||
87 | { | ||
88 | .type = V4L2_TUNER_RADIO, | ||
89 | .index = 0, | ||
90 | .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | | ||
91 | V4L2_TUNER_CAP_FREQ_BANDS, | ||
92 | .rangelow = FM_FREQ_RANGE_LOW * 16, | ||
93 | .rangehigh = FM_FREQ_RANGE_HIGH * 16, | ||
94 | .modulation = V4L2_BAND_MODULATION_FM, | ||
95 | }, | ||
96 | /* Band AM */ | ||
97 | { | ||
98 | .type = V4L2_TUNER_RADIO, | ||
99 | .index = 1, | ||
100 | .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, | ||
101 | .rangelow = AM_FREQ_RANGE_LOW * 16, | ||
102 | .rangehigh = AM_FREQ_RANGE_HIGH * 16, | ||
103 | .modulation = V4L2_BAND_MODULATION_AM, | ||
104 | }, | ||
105 | /* Band SW */ | ||
106 | { | ||
107 | .type = V4L2_TUNER_RADIO, | ||
108 | .index = 2, | ||
109 | .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, | ||
110 | .rangelow = SW_FREQ_RANGE_LOW * 16, | ||
111 | .rangehigh = SW_FREQ_RANGE_HIGH * 16, | ||
112 | .modulation = V4L2_BAND_MODULATION_AM, | ||
113 | }, | ||
114 | }; | ||
115 | |||
116 | struct raremono_device { | ||
117 | struct usb_device *usbdev; | ||
118 | struct usb_interface *intf; | ||
119 | struct video_device vdev; | ||
120 | struct v4l2_device v4l2_dev; | ||
121 | struct mutex lock; | ||
122 | |||
123 | u8 *buffer; | ||
124 | u32 band; | ||
125 | unsigned curfreq; | ||
126 | }; | ||
127 | |||
128 | static inline struct raremono_device *to_raremono_dev(struct v4l2_device *v4l2_dev) | ||
129 | { | ||
130 | return container_of(v4l2_dev, struct raremono_device, v4l2_dev); | ||
131 | } | ||
132 | |||
133 | /* Set frequency. */ | ||
134 | static int raremono_cmd_main(struct raremono_device *radio, unsigned band, unsigned freq) | ||
135 | { | ||
136 | unsigned band_offset; | ||
137 | int ret; | ||
138 | |||
139 | switch (band) { | ||
140 | case BAND_FM: | ||
141 | band_offset = 1; | ||
142 | freq /= 10; | ||
143 | break; | ||
144 | case BAND_AM: | ||
145 | band_offset = 0; | ||
146 | break; | ||
147 | default: | ||
148 | band_offset = 2; | ||
149 | break; | ||
150 | } | ||
151 | radio->buffer[0] = 0x04 + band_offset; | ||
152 | radio->buffer[1] = freq >> 8; | ||
153 | radio->buffer[2] = freq & 0xff; | ||
154 | |||
155 | ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | ||
156 | HID_REQ_SET_REPORT, | ||
157 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
158 | 0x0300 + radio->buffer[0], 2, | ||
159 | radio->buffer, 3, USB_TIMEOUT); | ||
160 | |||
161 | if (ret < 0) { | ||
162 | dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret); | ||
163 | return ret; | ||
164 | } | ||
165 | radio->curfreq = (band == BAND_FM) ? freq * 10 : freq; | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* Handle unplugging the device. | ||
170 | * We call video_unregister_device in any case. | ||
171 | * The last function called in this procedure is | ||
172 | * usb_raremono_device_release. | ||
173 | */ | ||
174 | static void usb_raremono_disconnect(struct usb_interface *intf) | ||
175 | { | ||
176 | struct raremono_device *radio = to_raremono_dev(usb_get_intfdata(intf)); | ||
177 | |||
178 | dev_info(&intf->dev, "Thanko's Raremono disconnected\n"); | ||
179 | |||
180 | mutex_lock(&radio->lock); | ||
181 | usb_set_intfdata(intf, NULL); | ||
182 | video_unregister_device(&radio->vdev); | ||
183 | v4l2_device_disconnect(&radio->v4l2_dev); | ||
184 | mutex_unlock(&radio->lock); | ||
185 | v4l2_device_put(&radio->v4l2_dev); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Linux Video interface | ||
190 | */ | ||
191 | static int vidioc_querycap(struct file *file, void *priv, | ||
192 | struct v4l2_capability *v) | ||
193 | { | ||
194 | struct raremono_device *radio = video_drvdata(file); | ||
195 | |||
196 | strlcpy(v->driver, "radio-raremono", sizeof(v->driver)); | ||
197 | strlcpy(v->card, "Thanko's Raremono", sizeof(v->card)); | ||
198 | usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); | ||
199 | v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
200 | v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int vidioc_enum_freq_bands(struct file *file, void *priv, | ||
205 | struct v4l2_frequency_band *band) | ||
206 | { | ||
207 | if (band->tuner != 0) | ||
208 | return -EINVAL; | ||
209 | |||
210 | if (band->index >= ARRAY_SIZE(bands)) | ||
211 | return -EINVAL; | ||
212 | |||
213 | *band = bands[band->index]; | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
219 | struct v4l2_tuner *v) | ||
220 | { | ||
221 | struct raremono_device *radio = video_drvdata(file); | ||
222 | int ret; | ||
223 | |||
224 | if (v->index > 0) | ||
225 | return -EINVAL; | ||
226 | |||
227 | strlcpy(v->name, "AM/FM/SW", sizeof(v->name)); | ||
228 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | | ||
229 | V4L2_TUNER_CAP_FREQ_BANDS; | ||
230 | v->rangelow = AM_FREQ_RANGE_LOW * 16; | ||
231 | v->rangehigh = FM_FREQ_RANGE_HIGH * 16; | ||
232 | v->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; | ||
233 | v->audmode = (radio->curfreq < FM_FREQ_RANGE_LOW) ? | ||
234 | V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO; | ||
235 | memset(radio->buffer, 1, BUFFER_LENGTH); | ||
236 | ret = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
237 | 1, 0xa1, 0x030d, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); | ||
238 | |||
239 | if (ret < 0) { | ||
240 | dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret); | ||
241 | return ret; | ||
242 | } | ||
243 | v->signal = ((radio->buffer[1] & 0xf) << 8 | radio->buffer[2]) << 4; | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
248 | const struct v4l2_tuner *v) | ||
249 | { | ||
250 | return v->index ? -EINVAL : 0; | ||
251 | } | ||
252 | |||
253 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
254 | const struct v4l2_frequency *f) | ||
255 | { | ||
256 | struct raremono_device *radio = video_drvdata(file); | ||
257 | u32 freq = f->frequency; | ||
258 | unsigned band; | ||
259 | |||
260 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
261 | return -EINVAL; | ||
262 | |||
263 | if (f->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) * 8) | ||
264 | band = BAND_FM; | ||
265 | else if (f->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) * 8) | ||
266 | band = BAND_AM; | ||
267 | else | ||
268 | band = BAND_SW; | ||
269 | |||
270 | freq = clamp_t(u32, f->frequency, bands[band].rangelow, bands[band].rangehigh); | ||
271 | return raremono_cmd_main(radio, band, freq / 16); | ||
272 | } | ||
273 | |||
274 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
275 | struct v4l2_frequency *f) | ||
276 | { | ||
277 | struct raremono_device *radio = video_drvdata(file); | ||
278 | |||
279 | if (f->tuner != 0) | ||
280 | return -EINVAL; | ||
281 | f->type = V4L2_TUNER_RADIO; | ||
282 | f->frequency = radio->curfreq * 16; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* File system interface */ | ||
287 | static const struct v4l2_file_operations usb_raremono_fops = { | ||
288 | .owner = THIS_MODULE, | ||
289 | .open = v4l2_fh_open, | ||
290 | .release = v4l2_fh_release, | ||
291 | .unlocked_ioctl = video_ioctl2, | ||
292 | }; | ||
293 | |||
294 | static const struct v4l2_ioctl_ops usb_raremono_ioctl_ops = { | ||
295 | .vidioc_querycap = vidioc_querycap, | ||
296 | .vidioc_g_tuner = vidioc_g_tuner, | ||
297 | .vidioc_s_tuner = vidioc_s_tuner, | ||
298 | .vidioc_g_frequency = vidioc_g_frequency, | ||
299 | .vidioc_s_frequency = vidioc_s_frequency, | ||
300 | .vidioc_enum_freq_bands = vidioc_enum_freq_bands, | ||
301 | }; | ||
302 | |||
303 | /* check if the device is present and register with v4l and usb if it is */ | ||
304 | static int usb_raremono_probe(struct usb_interface *intf, | ||
305 | const struct usb_device_id *id) | ||
306 | { | ||
307 | struct raremono_device *radio; | ||
308 | int retval = 0; | ||
309 | |||
310 | radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL); | ||
311 | if (radio) | ||
312 | radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL); | ||
313 | |||
314 | if (!radio || !radio->buffer) | ||
315 | return -ENOMEM; | ||
316 | |||
317 | radio->usbdev = interface_to_usbdev(intf); | ||
318 | radio->intf = intf; | ||
319 | |||
320 | /* | ||
321 | * This device uses the same USB IDs as the si470x SiLabs reference | ||
322 | * design. So do an additional check: attempt to read the device ID | ||
323 | * from the si470x: the lower 12 bits are 0x0242 for the si470x. The | ||
324 | * Raremono always returns 0x0800 (the meaning of that is unknown, but | ||
325 | * at least it works). | ||
326 | * | ||
327 | * We use this check to determine which device we are dealing with. | ||
328 | */ | ||
329 | msleep(20); | ||
330 | retval = usb_control_msg(radio->usbdev, | ||
331 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
332 | HID_REQ_GET_REPORT, | ||
333 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
334 | 1, 2, | ||
335 | radio->buffer, 3, 500); | ||
336 | if (retval != 3 || | ||
337 | (get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) { | ||
338 | dev_info(&intf->dev, "this is not Thanko's Raremono.\n"); | ||
339 | return -ENODEV; | ||
340 | } | ||
341 | |||
342 | dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n", | ||
343 | id->idVendor, id->idProduct); | ||
344 | |||
345 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); | ||
346 | if (retval < 0) { | ||
347 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); | ||
348 | return retval; | ||
349 | } | ||
350 | |||
351 | mutex_init(&radio->lock); | ||
352 | |||
353 | strlcpy(radio->vdev.name, radio->v4l2_dev.name, | ||
354 | sizeof(radio->vdev.name)); | ||
355 | radio->vdev.v4l2_dev = &radio->v4l2_dev; | ||
356 | radio->vdev.fops = &usb_raremono_fops; | ||
357 | radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops; | ||
358 | radio->vdev.lock = &radio->lock; | ||
359 | radio->vdev.release = video_device_release_empty; | ||
360 | |||
361 | usb_set_intfdata(intf, &radio->v4l2_dev); | ||
362 | |||
363 | video_set_drvdata(&radio->vdev, radio); | ||
364 | set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags); | ||
365 | |||
366 | raremono_cmd_main(radio, BAND_FM, 95160); | ||
367 | |||
368 | retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1); | ||
369 | if (retval == 0) { | ||
370 | dev_info(&intf->dev, "V4L2 device registered as %s\n", | ||
371 | video_device_node_name(&radio->vdev)); | ||
372 | return 0; | ||
373 | } | ||
374 | dev_err(&intf->dev, "could not register video device\n"); | ||
375 | v4l2_device_unregister(&radio->v4l2_dev); | ||
376 | return retval; | ||
377 | } | ||
378 | |||
379 | /* USB subsystem interface */ | ||
380 | static struct usb_driver usb_raremono_driver = { | ||
381 | .name = "radio-raremono", | ||
382 | .probe = usb_raremono_probe, | ||
383 | .disconnect = usb_raremono_disconnect, | ||
384 | .id_table = usb_raremono_device_table, | ||
385 | }; | ||
386 | |||
387 | module_usb_driver(usb_raremono_driver); | ||
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index d6d4d60261d5..07ef40595efd 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c | |||
@@ -137,6 +137,8 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); | |||
137 | /* interrupt out endpoint 2 every 1 millisecond */ | 137 | /* interrupt out endpoint 2 every 1 millisecond */ |
138 | #define UNUSED_REPORT 23 | 138 | #define UNUSED_REPORT 23 |
139 | 139 | ||
140 | #define MAX_REPORT_SIZE 64 | ||
141 | |||
140 | 142 | ||
141 | 143 | ||
142 | /************************************************************************** | 144 | /************************************************************************** |
@@ -208,7 +210,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); | |||
208 | */ | 210 | */ |
209 | static int si470x_get_report(struct si470x_device *radio, void *buf, int size) | 211 | static int si470x_get_report(struct si470x_device *radio, void *buf, int size) |
210 | { | 212 | { |
211 | unsigned char *report = (unsigned char *) buf; | 213 | unsigned char *report = buf; |
212 | int retval; | 214 | int retval; |
213 | 215 | ||
214 | retval = usb_control_msg(radio->usbdev, | 216 | retval = usb_control_msg(radio->usbdev, |
@@ -231,7 +233,7 @@ static int si470x_get_report(struct si470x_device *radio, void *buf, int size) | |||
231 | */ | 233 | */ |
232 | static int si470x_set_report(struct si470x_device *radio, void *buf, int size) | 234 | static int si470x_set_report(struct si470x_device *radio, void *buf, int size) |
233 | { | 235 | { |
234 | unsigned char *report = (unsigned char *) buf; | 236 | unsigned char *report = buf; |
235 | int retval; | 237 | int retval; |
236 | 238 | ||
237 | retval = usb_control_msg(radio->usbdev, | 239 | retval = usb_control_msg(radio->usbdev, |
@@ -254,15 +256,14 @@ static int si470x_set_report(struct si470x_device *radio, void *buf, int size) | |||
254 | */ | 256 | */ |
255 | int si470x_get_register(struct si470x_device *radio, int regnr) | 257 | int si470x_get_register(struct si470x_device *radio, int regnr) |
256 | { | 258 | { |
257 | unsigned char buf[REGISTER_REPORT_SIZE]; | ||
258 | int retval; | 259 | int retval; |
259 | 260 | ||
260 | buf[0] = REGISTER_REPORT(regnr); | 261 | radio->usb_buf[0] = REGISTER_REPORT(regnr); |
261 | 262 | ||
262 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); | 263 | retval = si470x_get_report(radio, radio->usb_buf, REGISTER_REPORT_SIZE); |
263 | 264 | ||
264 | if (retval >= 0) | 265 | if (retval >= 0) |
265 | radio->registers[regnr] = get_unaligned_be16(&buf[1]); | 266 | radio->registers[regnr] = get_unaligned_be16(&radio->usb_buf[1]); |
266 | 267 | ||
267 | return (retval < 0) ? -EINVAL : 0; | 268 | return (retval < 0) ? -EINVAL : 0; |
268 | } | 269 | } |
@@ -273,13 +274,12 @@ int si470x_get_register(struct si470x_device *radio, int regnr) | |||
273 | */ | 274 | */ |
274 | int si470x_set_register(struct si470x_device *radio, int regnr) | 275 | int si470x_set_register(struct si470x_device *radio, int regnr) |
275 | { | 276 | { |
276 | unsigned char buf[REGISTER_REPORT_SIZE]; | ||
277 | int retval; | 277 | int retval; |
278 | 278 | ||
279 | buf[0] = REGISTER_REPORT(regnr); | 279 | radio->usb_buf[0] = REGISTER_REPORT(regnr); |
280 | put_unaligned_be16(radio->registers[regnr], &buf[1]); | 280 | put_unaligned_be16(radio->registers[regnr], &radio->usb_buf[1]); |
281 | 281 | ||
282 | retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); | 282 | retval = si470x_set_report(radio, radio->usb_buf, REGISTER_REPORT_SIZE); |
283 | 283 | ||
284 | return (retval < 0) ? -EINVAL : 0; | 284 | return (retval < 0) ? -EINVAL : 0; |
285 | } | 285 | } |
@@ -295,18 +295,17 @@ int si470x_set_register(struct si470x_device *radio, int regnr) | |||
295 | */ | 295 | */ |
296 | static int si470x_get_all_registers(struct si470x_device *radio) | 296 | static int si470x_get_all_registers(struct si470x_device *radio) |
297 | { | 297 | { |
298 | unsigned char buf[ENTIRE_REPORT_SIZE]; | ||
299 | int retval; | 298 | int retval; |
300 | unsigned char regnr; | 299 | unsigned char regnr; |
301 | 300 | ||
302 | buf[0] = ENTIRE_REPORT; | 301 | radio->usb_buf[0] = ENTIRE_REPORT; |
303 | 302 | ||
304 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); | 303 | retval = si470x_get_report(radio, radio->usb_buf, ENTIRE_REPORT_SIZE); |
305 | 304 | ||
306 | if (retval >= 0) | 305 | if (retval >= 0) |
307 | for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) | 306 | for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) |
308 | radio->registers[regnr] = get_unaligned_be16( | 307 | radio->registers[regnr] = get_unaligned_be16( |
309 | &buf[regnr * RADIO_REGISTER_SIZE + 1]); | 308 | &radio->usb_buf[regnr * RADIO_REGISTER_SIZE + 1]); |
310 | 309 | ||
311 | return (retval < 0) ? -EINVAL : 0; | 310 | return (retval < 0) ? -EINVAL : 0; |
312 | } | 311 | } |
@@ -323,14 +322,13 @@ static int si470x_get_all_registers(struct si470x_device *radio) | |||
323 | static int si470x_set_led_state(struct si470x_device *radio, | 322 | static int si470x_set_led_state(struct si470x_device *radio, |
324 | unsigned char led_state) | 323 | unsigned char led_state) |
325 | { | 324 | { |
326 | unsigned char buf[LED_REPORT_SIZE]; | ||
327 | int retval; | 325 | int retval; |
328 | 326 | ||
329 | buf[0] = LED_REPORT; | 327 | radio->usb_buf[0] = LED_REPORT; |
330 | buf[1] = LED_COMMAND; | 328 | radio->usb_buf[1] = LED_COMMAND; |
331 | buf[2] = led_state; | 329 | radio->usb_buf[2] = led_state; |
332 | 330 | ||
333 | retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); | 331 | retval = si470x_set_report(radio, radio->usb_buf, LED_REPORT_SIZE); |
334 | 332 | ||
335 | return (retval < 0) ? -EINVAL : 0; | 333 | return (retval < 0) ? -EINVAL : 0; |
336 | } | 334 | } |
@@ -346,19 +344,18 @@ static int si470x_set_led_state(struct si470x_device *radio, | |||
346 | */ | 344 | */ |
347 | static int si470x_get_scratch_page_versions(struct si470x_device *radio) | 345 | static int si470x_get_scratch_page_versions(struct si470x_device *radio) |
348 | { | 346 | { |
349 | unsigned char buf[SCRATCH_REPORT_SIZE]; | ||
350 | int retval; | 347 | int retval; |
351 | 348 | ||
352 | buf[0] = SCRATCH_REPORT; | 349 | radio->usb_buf[0] = SCRATCH_REPORT; |
353 | 350 | ||
354 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); | 351 | retval = si470x_get_report(radio, radio->usb_buf, SCRATCH_REPORT_SIZE); |
355 | 352 | ||
356 | if (retval < 0) | 353 | if (retval < 0) |
357 | dev_warn(&radio->intf->dev, "si470x_get_scratch: " | 354 | dev_warn(&radio->intf->dev, "si470x_get_scratch: " |
358 | "si470x_get_report returned %d\n", retval); | 355 | "si470x_get_report returned %d\n", retval); |
359 | else { | 356 | else { |
360 | radio->software_version = buf[1]; | 357 | radio->software_version = radio->usb_buf[1]; |
361 | radio->hardware_version = buf[2]; | 358 | radio->hardware_version = radio->usb_buf[2]; |
362 | } | 359 | } |
363 | 360 | ||
364 | return (retval < 0) ? -EINVAL : 0; | 361 | return (retval < 0) ? -EINVAL : 0; |
@@ -509,6 +506,7 @@ static void si470x_usb_release(struct v4l2_device *v4l2_dev) | |||
509 | v4l2_device_unregister(&radio->v4l2_dev); | 506 | v4l2_device_unregister(&radio->v4l2_dev); |
510 | kfree(radio->int_in_buffer); | 507 | kfree(radio->int_in_buffer); |
511 | kfree(radio->buffer); | 508 | kfree(radio->buffer); |
509 | kfree(radio->usb_buf); | ||
512 | kfree(radio); | 510 | kfree(radio); |
513 | } | 511 | } |
514 | 512 | ||
@@ -593,6 +591,11 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
593 | retval = -ENOMEM; | 591 | retval = -ENOMEM; |
594 | goto err_initial; | 592 | goto err_initial; |
595 | } | 593 | } |
594 | radio->usb_buf = kmalloc(MAX_REPORT_SIZE, GFP_KERNEL); | ||
595 | if (radio->usb_buf == NULL) { | ||
596 | retval = -ENOMEM; | ||
597 | goto err_radio; | ||
598 | } | ||
596 | radio->usbdev = interface_to_usbdev(intf); | 599 | radio->usbdev = interface_to_usbdev(intf); |
597 | radio->intf = intf; | 600 | radio->intf = intf; |
598 | radio->band = 1; /* Default to 76 - 108 MHz */ | 601 | radio->band = 1; /* Default to 76 - 108 MHz */ |
@@ -612,7 +615,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
612 | if (!radio->int_in_endpoint) { | 615 | if (!radio->int_in_endpoint) { |
613 | dev_info(&intf->dev, "could not find interrupt in endpoint\n"); | 616 | dev_info(&intf->dev, "could not find interrupt in endpoint\n"); |
614 | retval = -EIO; | 617 | retval = -EIO; |
615 | goto err_radio; | 618 | goto err_usbbuf; |
616 | } | 619 | } |
617 | 620 | ||
618 | int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize); | 621 | int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize); |
@@ -621,7 +624,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
621 | if (!radio->int_in_buffer) { | 624 | if (!radio->int_in_buffer) { |
622 | dev_info(&intf->dev, "could not allocate int_in_buffer"); | 625 | dev_info(&intf->dev, "could not allocate int_in_buffer"); |
623 | retval = -ENOMEM; | 626 | retval = -ENOMEM; |
624 | goto err_radio; | 627 | goto err_usbbuf; |
625 | } | 628 | } |
626 | 629 | ||
627 | radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); | 630 | radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); |
@@ -632,6 +635,30 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
632 | } | 635 | } |
633 | 636 | ||
634 | radio->v4l2_dev.release = si470x_usb_release; | 637 | radio->v4l2_dev.release = si470x_usb_release; |
638 | |||
639 | /* | ||
640 | * The si470x SiLabs reference design uses the same USB IDs as | ||
641 | * 'Thanko's Raremono' si4734 based receiver. So check here which we | ||
642 | * have: attempt to read the device ID from the si470x: the lower 12 | ||
643 | * bits should be 0x0242 for the si470x. | ||
644 | * | ||
645 | * We use this check to determine which device we are dealing with. | ||
646 | */ | ||
647 | if (id->idVendor == 0x10c4 && id->idProduct == 0x818a) { | ||
648 | retval = usb_control_msg(radio->usbdev, | ||
649 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
650 | HID_REQ_GET_REPORT, | ||
651 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
652 | 1, 2, | ||
653 | radio->usb_buf, 3, 500); | ||
654 | if (retval != 3 || | ||
655 | (get_unaligned_be16(&radio->usb_buf[1]) & 0xfff) != 0x0242) { | ||
656 | dev_info(&intf->dev, "this is not a si470x device.\n"); | ||
657 | retval = -ENODEV; | ||
658 | goto err_urb; | ||
659 | } | ||
660 | } | ||
661 | |||
635 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); | 662 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); |
636 | if (retval < 0) { | 663 | if (retval < 0) { |
637 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); | 664 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); |
@@ -743,6 +770,8 @@ err_urb: | |||
743 | usb_free_urb(radio->int_in_urb); | 770 | usb_free_urb(radio->int_in_urb); |
744 | err_intbuffer: | 771 | err_intbuffer: |
745 | kfree(radio->int_in_buffer); | 772 | kfree(radio->int_in_buffer); |
773 | err_usbbuf: | ||
774 | kfree(radio->usb_buf); | ||
746 | err_radio: | 775 | err_radio: |
747 | kfree(radio); | 776 | kfree(radio); |
748 | err_initial: | 777 | err_initial: |
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index 467e95575488..4b7660470e2f 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h | |||
@@ -167,6 +167,7 @@ struct si470x_device { | |||
167 | /* reference to USB and video device */ | 167 | /* reference to USB and video device */ |
168 | struct usb_device *usbdev; | 168 | struct usb_device *usbdev; |
169 | struct usb_interface *intf; | 169 | struct usb_interface *intf; |
170 | char *usb_buf; | ||
170 | 171 | ||
171 | /* Interrupt endpoint handling */ | 172 | /* Interrupt endpoint handling */ |
172 | char *int_in_buffer; | 173 | char *int_in_buffer; |
diff --git a/drivers/media/radio/si4713/Kconfig b/drivers/media/radio/si4713/Kconfig new file mode 100644 index 000000000000..a7c3ba85d12b --- /dev/null +++ b/drivers/media/radio/si4713/Kconfig | |||
@@ -0,0 +1,40 @@ | |||
1 | config USB_SI4713 | ||
2 | tristate "Silicon Labs Si4713 FM Radio Transmitter support with USB" | ||
3 | depends on USB && RADIO_SI4713 | ||
4 | select SI4713 | ||
5 | ---help--- | ||
6 | This is a driver for USB devices with the Silicon Labs SI4713 | ||
7 | chip. Currently these devices are known to work. | ||
8 | - 10c4:8244: Silicon Labs FM Transmitter USB device. | ||
9 | |||
10 | Say Y here if you want to connect this type of radio to your | ||
11 | computer's USB port. | ||
12 | |||
13 | To compile this driver as a module, choose M here: the | ||
14 | module will be called radio-usb-si4713. | ||
15 | |||
16 | config PLATFORM_SI4713 | ||
17 | tristate "Silicon Labs Si4713 FM Radio Transmitter support with I2C" | ||
18 | depends on I2C && RADIO_SI4713 | ||
19 | select SI4713 | ||
20 | ---help--- | ||
21 | This is a driver for I2C devices with the Silicon Labs SI4713 | ||
22 | chip. | ||
23 | |||
24 | Say Y here if you want to connect this type of radio to your | ||
25 | computer's I2C port. | ||
26 | |||
27 | To compile this driver as a module, choose M here: the | ||
28 | module will be called radio-platform-si4713. | ||
29 | |||
30 | config I2C_SI4713 | ||
31 | tristate "Silicon Labs Si4713 FM Radio Transmitter support" | ||
32 | depends on I2C && RADIO_SI4713 | ||
33 | ---help--- | ||
34 | Say Y here if you want support to Si4713 FM Radio Transmitter. | ||
35 | This device can transmit audio through FM. It can transmit | ||
36 | RDS and RBDS signals as well. This module is the v4l2 radio | ||
37 | interface for the i2c driver of this device. | ||
38 | |||
39 | To compile this driver as a module, choose M here: the | ||
40 | module will be called si4713. | ||
diff --git a/drivers/media/radio/si4713/Makefile b/drivers/media/radio/si4713/Makefile new file mode 100644 index 000000000000..ddaaf925e883 --- /dev/null +++ b/drivers/media/radio/si4713/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for radios with Silicon Labs Si4713 FM Radio Transmitters | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_I2C_SI4713) += si4713.o | ||
6 | obj-$(CONFIG_USB_SI4713) += radio-usb-si4713.o | ||
7 | obj-$(CONFIG_PLATFORM_SI4713) += radio-platform-si4713.o | ||
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index ba4cfc946868..ba4cfc946868 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c | |||
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c new file mode 100644 index 000000000000..779855b74bcd --- /dev/null +++ b/drivers/media/radio/si4713/radio-usb-si4713.c | |||
@@ -0,0 +1,540 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | /* kernel includes */ | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/usb.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/input.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include <linux/i2c.h> | ||
28 | /* V4l includes */ | ||
29 | #include <linux/videodev2.h> | ||
30 | #include <media/v4l2-common.h> | ||
31 | #include <media/v4l2-device.h> | ||
32 | #include <media/v4l2-ioctl.h> | ||
33 | #include <media/v4l2-event.h> | ||
34 | #include <media/si4713.h> | ||
35 | |||
36 | #include "si4713.h" | ||
37 | |||
38 | /* driver and module definitions */ | ||
39 | MODULE_AUTHOR("Dinesh Ram <dinesh.ram@cern.ch>"); | ||
40 | MODULE_DESCRIPTION("Si4713 FM Transmitter USB driver"); | ||
41 | MODULE_LICENSE("GPL v2"); | ||
42 | |||
43 | /* The Device announces itself as Cygnal Integrated Products, Inc. */ | ||
44 | #define USB_SI4713_VENDOR 0x10c4 | ||
45 | #define USB_SI4713_PRODUCT 0x8244 | ||
46 | |||
47 | #define BUFFER_LENGTH 64 | ||
48 | #define USB_TIMEOUT 1000 | ||
49 | #define USB_RESP_TIMEOUT 50000 | ||
50 | |||
51 | /* USB Device ID List */ | ||
52 | static struct usb_device_id usb_si4713_usb_device_table[] = { | ||
53 | {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT, | ||
54 | USB_CLASS_HID, 0, 0) }, | ||
55 | { } /* Terminating entry */ | ||
56 | }; | ||
57 | |||
58 | MODULE_DEVICE_TABLE(usb, usb_si4713_usb_device_table); | ||
59 | |||
60 | struct si4713_usb_device { | ||
61 | struct usb_device *usbdev; | ||
62 | struct usb_interface *intf; | ||
63 | struct video_device vdev; | ||
64 | struct v4l2_device v4l2_dev; | ||
65 | struct v4l2_subdev *v4l2_subdev; | ||
66 | struct mutex lock; | ||
67 | struct i2c_adapter i2c_adapter; | ||
68 | |||
69 | u8 *buffer; | ||
70 | }; | ||
71 | |||
72 | static inline struct si4713_usb_device *to_si4713_dev(struct v4l2_device *v4l2_dev) | ||
73 | { | ||
74 | return container_of(v4l2_dev, struct si4713_usb_device, v4l2_dev); | ||
75 | } | ||
76 | |||
77 | static int vidioc_querycap(struct file *file, void *priv, | ||
78 | struct v4l2_capability *v) | ||
79 | { | ||
80 | struct si4713_usb_device *radio = video_drvdata(file); | ||
81 | |||
82 | strlcpy(v->driver, "radio-usb-si4713", sizeof(v->driver)); | ||
83 | strlcpy(v->card, "Si4713 FM Transmitter", sizeof(v->card)); | ||
84 | usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); | ||
85 | v->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; | ||
86 | v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int vidioc_g_modulator(struct file *file, void *priv, | ||
92 | struct v4l2_modulator *vm) | ||
93 | { | ||
94 | struct si4713_usb_device *radio = video_drvdata(file); | ||
95 | |||
96 | return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_modulator, vm); | ||
97 | } | ||
98 | |||
99 | static int vidioc_s_modulator(struct file *file, void *priv, | ||
100 | const struct v4l2_modulator *vm) | ||
101 | { | ||
102 | struct si4713_usb_device *radio = video_drvdata(file); | ||
103 | |||
104 | return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_modulator, vm); | ||
105 | } | ||
106 | |||
107 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
108 | const struct v4l2_frequency *vf) | ||
109 | { | ||
110 | struct si4713_usb_device *radio = video_drvdata(file); | ||
111 | |||
112 | return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_frequency, vf); | ||
113 | } | ||
114 | |||
115 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
116 | struct v4l2_frequency *vf) | ||
117 | { | ||
118 | struct si4713_usb_device *radio = video_drvdata(file); | ||
119 | |||
120 | return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_frequency, vf); | ||
121 | } | ||
122 | |||
123 | static const struct v4l2_ioctl_ops usb_si4713_ioctl_ops = { | ||
124 | .vidioc_querycap = vidioc_querycap, | ||
125 | .vidioc_g_modulator = vidioc_g_modulator, | ||
126 | .vidioc_s_modulator = vidioc_s_modulator, | ||
127 | .vidioc_g_frequency = vidioc_g_frequency, | ||
128 | .vidioc_s_frequency = vidioc_s_frequency, | ||
129 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
130 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
131 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
132 | }; | ||
133 | |||
134 | /* File system interface */ | ||
135 | static const struct v4l2_file_operations usb_si4713_fops = { | ||
136 | .owner = THIS_MODULE, | ||
137 | .open = v4l2_fh_open, | ||
138 | .release = v4l2_fh_release, | ||
139 | .poll = v4l2_ctrl_poll, | ||
140 | .unlocked_ioctl = video_ioctl2, | ||
141 | }; | ||
142 | |||
143 | static void usb_si4713_video_device_release(struct v4l2_device *v4l2_dev) | ||
144 | { | ||
145 | struct si4713_usb_device *radio = to_si4713_dev(v4l2_dev); | ||
146 | struct i2c_adapter *adapter = &radio->i2c_adapter; | ||
147 | |||
148 | i2c_del_adapter(adapter); | ||
149 | v4l2_device_unregister(&radio->v4l2_dev); | ||
150 | kfree(radio->buffer); | ||
151 | kfree(radio); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * This command sequence emulates the behaviour of the Windows driver. | ||
156 | * The structure of these commands was determined by sniffing the | ||
157 | * usb traffic of the device during startup. | ||
158 | * Most likely, these commands make some queries to the device. | ||
159 | * Commands are sent to enquire parameters like the bus mode, | ||
160 | * component revision, boot mode, the device serial number etc. | ||
161 | * | ||
162 | * These commands are necessary to be sent in this order during startup. | ||
163 | * The device fails to powerup if these commands are not sent. | ||
164 | * | ||
165 | * The complete list of startup commands is given in the start_seq table below. | ||
166 | */ | ||
167 | static int si4713_send_startup_command(struct si4713_usb_device *radio) | ||
168 | { | ||
169 | unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1; | ||
170 | u8 *buffer = radio->buffer; | ||
171 | int retval; | ||
172 | |||
173 | /* send the command */ | ||
174 | retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | ||
175 | 0x09, 0x21, 0x033f, 0, radio->buffer, | ||
176 | BUFFER_LENGTH, USB_TIMEOUT); | ||
177 | if (retval < 0) | ||
178 | return retval; | ||
179 | |||
180 | for (;;) { | ||
181 | /* receive the response */ | ||
182 | retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
183 | 0x01, 0xa1, 0x033f, 0, radio->buffer, | ||
184 | BUFFER_LENGTH, USB_TIMEOUT); | ||
185 | if (retval < 0) | ||
186 | return retval; | ||
187 | if (!radio->buffer[1]) { | ||
188 | /* USB traffic sniffing showed that some commands require | ||
189 | * additional checks. */ | ||
190 | switch (buffer[1]) { | ||
191 | case 0x32: | ||
192 | if (radio->buffer[2] == 0) | ||
193 | return 0; | ||
194 | break; | ||
195 | case 0x14: | ||
196 | case 0x12: | ||
197 | if (radio->buffer[2] & SI4713_CTS) | ||
198 | return 0; | ||
199 | break; | ||
200 | case 0x06: | ||
201 | if ((radio->buffer[2] & SI4713_CTS) && radio->buffer[9] == 0x08) | ||
202 | return 0; | ||
203 | break; | ||
204 | default: | ||
205 | return 0; | ||
206 | } | ||
207 | } | ||
208 | if (time_is_before_jiffies(until_jiffies)) | ||
209 | return -EIO; | ||
210 | msleep(3); | ||
211 | } | ||
212 | |||
213 | return retval; | ||
214 | } | ||
215 | |||
216 | struct si4713_start_seq_table { | ||
217 | int len; | ||
218 | u8 payload[8]; | ||
219 | }; | ||
220 | |||
221 | /* | ||
222 | * Some of the startup commands that could be recognized are : | ||
223 | * (0x03): Get serial number of the board (Response : CB000-00-00) | ||
224 | * (0x06, 0x03, 0x03, 0x08, 0x01, 0x0f) : Get Component revision | ||
225 | */ | ||
226 | static struct si4713_start_seq_table start_seq[] = { | ||
227 | |||
228 | { 1, { 0x03 } }, | ||
229 | { 2, { 0x32, 0x7f } }, | ||
230 | { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } }, | ||
231 | { 2, { 0x14, 0x02 } }, | ||
232 | { 2, { 0x09, 0x90 } }, | ||
233 | { 3, { 0x08, 0x90, 0xfa } }, | ||
234 | { 2, { 0x36, 0x01 } }, | ||
235 | { 2, { 0x05, 0x03 } }, | ||
236 | { 7, { 0x06, 0x00, 0x06, 0x0e, 0x01, 0x0f, 0x05 } }, | ||
237 | { 1, { 0x12 } }, | ||
238 | /* Commands that are sent after pressing the 'Initialize' | ||
239 | button in the windows application */ | ||
240 | { 1, { 0x03 } }, | ||
241 | { 1, { 0x01 } }, | ||
242 | { 2, { 0x09, 0x90 } }, | ||
243 | { 3, { 0x08, 0x90, 0xfa } }, | ||
244 | { 1, { 0x34 } }, | ||
245 | { 2, { 0x35, 0x01 } }, | ||
246 | { 2, { 0x36, 0x01 } }, | ||
247 | { 2, { 0x30, 0x09 } }, | ||
248 | { 4, { 0x30, 0x06, 0x00, 0xe2 } }, | ||
249 | { 3, { 0x31, 0x01, 0x30 } }, | ||
250 | { 3, { 0x31, 0x04, 0x09 } }, | ||
251 | { 2, { 0x05, 0x02 } }, | ||
252 | { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } }, | ||
253 | }; | ||
254 | |||
255 | static int si4713_start_seq(struct si4713_usb_device *radio) | ||
256 | { | ||
257 | int retval = 0; | ||
258 | int i; | ||
259 | |||
260 | radio->buffer[0] = 0x3f; | ||
261 | |||
262 | for (i = 0; i < ARRAY_SIZE(start_seq); i++) { | ||
263 | int len = start_seq[i].len; | ||
264 | u8 *payload = start_seq[i].payload; | ||
265 | |||
266 | memcpy(radio->buffer + 1, payload, len); | ||
267 | memset(radio->buffer + len + 1, 0, BUFFER_LENGTH - 1 - len); | ||
268 | retval = si4713_send_startup_command(radio); | ||
269 | } | ||
270 | |||
271 | return retval; | ||
272 | } | ||
273 | |||
274 | static struct i2c_board_info si4713_board_info = { | ||
275 | I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH), | ||
276 | }; | ||
277 | |||
278 | struct si4713_command_table { | ||
279 | int command_id; | ||
280 | u8 payload[8]; | ||
281 | }; | ||
282 | |||
283 | /* | ||
284 | * Structure of a command : | ||
285 | * Byte 1 : 0x3f (always) | ||
286 | * Byte 2 : 0x06 (send a command) | ||
287 | * Byte 3 : Unknown | ||
288 | * Byte 4 : Number of arguments + 1 (for the command byte) | ||
289 | * Byte 5 : Number of response bytes | ||
290 | */ | ||
291 | static struct si4713_command_table command_table[] = { | ||
292 | |||
293 | { SI4713_CMD_POWER_UP, { 0x00, SI4713_PWUP_NARGS + 1, SI4713_PWUP_NRESP} }, | ||
294 | { SI4713_CMD_GET_REV, { 0x03, 0x01, SI4713_GETREV_NRESP } }, | ||
295 | { SI4713_CMD_POWER_DOWN, { 0x00, 0x01, SI4713_PWDN_NRESP} }, | ||
296 | { SI4713_CMD_SET_PROPERTY, { 0x00, SI4713_SET_PROP_NARGS + 1, SI4713_SET_PROP_NRESP } }, | ||
297 | { SI4713_CMD_GET_PROPERTY, { 0x00, SI4713_GET_PROP_NARGS + 1, SI4713_GET_PROP_NRESP } }, | ||
298 | { SI4713_CMD_TX_TUNE_FREQ, { 0x03, SI4713_TXFREQ_NARGS + 1, SI4713_TXFREQ_NRESP } }, | ||
299 | { SI4713_CMD_TX_TUNE_POWER, { 0x03, SI4713_TXPWR_NARGS + 1, SI4713_TXPWR_NRESP } }, | ||
300 | { SI4713_CMD_TX_TUNE_MEASURE, { 0x03, SI4713_TXMEA_NARGS + 1, SI4713_TXMEA_NRESP } }, | ||
301 | { SI4713_CMD_TX_TUNE_STATUS, { 0x00, SI4713_TXSTATUS_NARGS + 1, SI4713_TXSTATUS_NRESP } }, | ||
302 | { SI4713_CMD_TX_ASQ_STATUS, { 0x03, SI4713_ASQSTATUS_NARGS + 1, SI4713_ASQSTATUS_NRESP } }, | ||
303 | { SI4713_CMD_GET_INT_STATUS, { 0x03, 0x01, SI4713_GET_STATUS_NRESP } }, | ||
304 | { SI4713_CMD_TX_RDS_BUFF, { 0x03, SI4713_RDSBUFF_NARGS + 1, SI4713_RDSBUFF_NRESP } }, | ||
305 | { SI4713_CMD_TX_RDS_PS, { 0x00, SI4713_RDSPS_NARGS + 1, SI4713_RDSPS_NRESP } }, | ||
306 | }; | ||
307 | |||
308 | static int send_command(struct si4713_usb_device *radio, u8 *payload, char *data, int len) | ||
309 | { | ||
310 | int retval; | ||
311 | |||
312 | radio->buffer[0] = 0x3f; | ||
313 | radio->buffer[1] = 0x06; | ||
314 | |||
315 | memcpy(radio->buffer + 2, payload, 3); | ||
316 | memcpy(radio->buffer + 5, data, len); | ||
317 | memset(radio->buffer + 5 + len, 0, BUFFER_LENGTH - 5 - len); | ||
318 | |||
319 | /* send the command */ | ||
320 | retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), | ||
321 | 0x09, 0x21, 0x033f, 0, radio->buffer, | ||
322 | BUFFER_LENGTH, USB_TIMEOUT); | ||
323 | |||
324 | return retval < 0 ? retval : 0; | ||
325 | } | ||
326 | |||
327 | static int si4713_i2c_read(struct si4713_usb_device *radio, char *data, int len) | ||
328 | { | ||
329 | unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1; | ||
330 | int retval; | ||
331 | |||
332 | /* receive the response */ | ||
333 | for (;;) { | ||
334 | retval = usb_control_msg(radio->usbdev, | ||
335 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
336 | 0x01, 0xa1, 0x033f, 0, radio->buffer, | ||
337 | BUFFER_LENGTH, USB_TIMEOUT); | ||
338 | if (retval < 0) | ||
339 | return retval; | ||
340 | |||
341 | /* | ||
342 | * Check that we get a valid reply back (buffer[1] == 0) and | ||
343 | * that CTS is set before returning, otherwise we wait and try | ||
344 | * again. The i2c driver also does the CTS check, but the timeouts | ||
345 | * used there are much too small for this USB driver, so we wait | ||
346 | * for it here. | ||
347 | */ | ||
348 | if (radio->buffer[1] == 0 && (radio->buffer[2] & SI4713_CTS)) { | ||
349 | memcpy(data, radio->buffer + 2, len); | ||
350 | return 0; | ||
351 | } | ||
352 | if (time_is_before_jiffies(until_jiffies)) { | ||
353 | /* Zero the status value, ensuring CTS isn't set */ | ||
354 | data[0] = 0; | ||
355 | return 0; | ||
356 | } | ||
357 | msleep(3); | ||
358 | } | ||
359 | } | ||
360 | |||
361 | static int si4713_i2c_write(struct si4713_usb_device *radio, char *data, int len) | ||
362 | { | ||
363 | int retval = -EINVAL; | ||
364 | int i; | ||
365 | |||
366 | if (len > BUFFER_LENGTH - 5) | ||
367 | return -EINVAL; | ||
368 | |||
369 | for (i = 0; i < ARRAY_SIZE(command_table); i++) { | ||
370 | if (data[0] == command_table[i].command_id) | ||
371 | retval = send_command(radio, command_table[i].payload, | ||
372 | data, len); | ||
373 | } | ||
374 | |||
375 | return retval < 0 ? retval : 0; | ||
376 | } | ||
377 | |||
378 | static int si4713_transfer(struct i2c_adapter *i2c_adapter, | ||
379 | struct i2c_msg *msgs, int num) | ||
380 | { | ||
381 | struct si4713_usb_device *radio = i2c_get_adapdata(i2c_adapter); | ||
382 | int retval = -EINVAL; | ||
383 | int i; | ||
384 | |||
385 | if (num <= 0) | ||
386 | return 0; | ||
387 | |||
388 | for (i = 0; i < num; i++) { | ||
389 | if (msgs[i].flags & I2C_M_RD) | ||
390 | retval = si4713_i2c_read(radio, msgs[i].buf, msgs[i].len); | ||
391 | else | ||
392 | retval = si4713_i2c_write(radio, msgs[i].buf, msgs[i].len); | ||
393 | if (retval) | ||
394 | break; | ||
395 | } | ||
396 | |||
397 | return retval ? retval : num; | ||
398 | } | ||
399 | |||
400 | static u32 si4713_functionality(struct i2c_adapter *adapter) | ||
401 | { | ||
402 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
403 | } | ||
404 | |||
405 | static struct i2c_algorithm si4713_algo = { | ||
406 | .master_xfer = si4713_transfer, | ||
407 | .functionality = si4713_functionality, | ||
408 | }; | ||
409 | |||
410 | /* This name value shows up in the sysfs filename associated | ||
411 | with this I2C adapter */ | ||
412 | static struct i2c_adapter si4713_i2c_adapter_template = { | ||
413 | .name = "si4713-i2c", | ||
414 | .owner = THIS_MODULE, | ||
415 | .algo = &si4713_algo, | ||
416 | }; | ||
417 | |||
418 | static int si4713_register_i2c_adapter(struct si4713_usb_device *radio) | ||
419 | { | ||
420 | radio->i2c_adapter = si4713_i2c_adapter_template; | ||
421 | /* set up sysfs linkage to our parent device */ | ||
422 | radio->i2c_adapter.dev.parent = &radio->usbdev->dev; | ||
423 | i2c_set_adapdata(&radio->i2c_adapter, radio); | ||
424 | |||
425 | return i2c_add_adapter(&radio->i2c_adapter); | ||
426 | } | ||
427 | |||
428 | /* check if the device is present and register with v4l and usb if it is */ | ||
429 | static int usb_si4713_probe(struct usb_interface *intf, | ||
430 | const struct usb_device_id *id) | ||
431 | { | ||
432 | struct si4713_usb_device *radio; | ||
433 | struct i2c_adapter *adapter; | ||
434 | struct v4l2_subdev *sd; | ||
435 | int retval = -ENOMEM; | ||
436 | |||
437 | dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n", | ||
438 | id->idVendor, id->idProduct); | ||
439 | |||
440 | /* Initialize local device structure */ | ||
441 | radio = kzalloc(sizeof(struct si4713_usb_device), GFP_KERNEL); | ||
442 | if (radio) | ||
443 | radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); | ||
444 | |||
445 | if (!radio || !radio->buffer) { | ||
446 | dev_err(&intf->dev, "kmalloc for si4713_usb_device failed\n"); | ||
447 | kfree(radio); | ||
448 | return -ENOMEM; | ||
449 | } | ||
450 | |||
451 | mutex_init(&radio->lock); | ||
452 | |||
453 | radio->usbdev = interface_to_usbdev(intf); | ||
454 | radio->intf = intf; | ||
455 | usb_set_intfdata(intf, &radio->v4l2_dev); | ||
456 | |||
457 | retval = si4713_start_seq(radio); | ||
458 | if (retval < 0) | ||
459 | goto err_v4l2; | ||
460 | |||
461 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); | ||
462 | if (retval < 0) { | ||
463 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); | ||
464 | goto err_v4l2; | ||
465 | } | ||
466 | |||
467 | retval = si4713_register_i2c_adapter(radio); | ||
468 | if (retval < 0) { | ||
469 | dev_err(&intf->dev, "could not register i2c device\n"); | ||
470 | goto err_i2cdev; | ||
471 | } | ||
472 | |||
473 | adapter = &radio->i2c_adapter; | ||
474 | sd = v4l2_i2c_new_subdev_board(&radio->v4l2_dev, adapter, | ||
475 | &si4713_board_info, NULL); | ||
476 | radio->v4l2_subdev = sd; | ||
477 | if (!sd) { | ||
478 | dev_err(&intf->dev, "cannot get v4l2 subdevice\n"); | ||
479 | retval = -ENODEV; | ||
480 | goto del_adapter; | ||
481 | } | ||
482 | |||
483 | radio->vdev.ctrl_handler = sd->ctrl_handler; | ||
484 | radio->v4l2_dev.release = usb_si4713_video_device_release; | ||
485 | strlcpy(radio->vdev.name, radio->v4l2_dev.name, | ||
486 | sizeof(radio->vdev.name)); | ||
487 | radio->vdev.v4l2_dev = &radio->v4l2_dev; | ||
488 | radio->vdev.fops = &usb_si4713_fops; | ||
489 | radio->vdev.ioctl_ops = &usb_si4713_ioctl_ops; | ||
490 | radio->vdev.lock = &radio->lock; | ||
491 | radio->vdev.release = video_device_release_empty; | ||
492 | radio->vdev.vfl_dir = VFL_DIR_TX; | ||
493 | |||
494 | video_set_drvdata(&radio->vdev, radio); | ||
495 | set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags); | ||
496 | |||
497 | retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1); | ||
498 | if (retval < 0) { | ||
499 | dev_err(&intf->dev, "could not register video device\n"); | ||
500 | goto del_adapter; | ||
501 | } | ||
502 | |||
503 | dev_info(&intf->dev, "V4L2 device registered as %s\n", | ||
504 | video_device_node_name(&radio->vdev)); | ||
505 | |||
506 | return 0; | ||
507 | |||
508 | del_adapter: | ||
509 | i2c_del_adapter(adapter); | ||
510 | err_i2cdev: | ||
511 | v4l2_device_unregister(&radio->v4l2_dev); | ||
512 | err_v4l2: | ||
513 | kfree(radio->buffer); | ||
514 | kfree(radio); | ||
515 | return retval; | ||
516 | } | ||
517 | |||
518 | static void usb_si4713_disconnect(struct usb_interface *intf) | ||
519 | { | ||
520 | struct si4713_usb_device *radio = to_si4713_dev(usb_get_intfdata(intf)); | ||
521 | |||
522 | dev_info(&intf->dev, "Si4713 development board now disconnected\n"); | ||
523 | |||
524 | mutex_lock(&radio->lock); | ||
525 | usb_set_intfdata(intf, NULL); | ||
526 | video_unregister_device(&radio->vdev); | ||
527 | v4l2_device_disconnect(&radio->v4l2_dev); | ||
528 | mutex_unlock(&radio->lock); | ||
529 | v4l2_device_put(&radio->v4l2_dev); | ||
530 | } | ||
531 | |||
532 | /* USB subsystem interface */ | ||
533 | static struct usb_driver usb_si4713_driver = { | ||
534 | .name = "radio-usb-si4713", | ||
535 | .probe = usb_si4713_probe, | ||
536 | .disconnect = usb_si4713_disconnect, | ||
537 | .id_table = usb_si4713_usb_device_table, | ||
538 | }; | ||
539 | |||
540 | module_usb_driver(usb_si4713_driver); | ||
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713/si4713.c index 9ec48ccbcf0b..07d5153811e8 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713/si4713.c | |||
@@ -27,13 +27,12 @@ | |||
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/gpio.h> | 29 | #include <linux/gpio.h> |
30 | #include <linux/regulator/consumer.h> | ||
31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
32 | #include <media/v4l2-device.h> | 31 | #include <media/v4l2-device.h> |
33 | #include <media/v4l2-ioctl.h> | 32 | #include <media/v4l2-ioctl.h> |
34 | #include <media/v4l2-common.h> | 33 | #include <media/v4l2-common.h> |
35 | 34 | ||
36 | #include "si4713-i2c.h" | 35 | #include "si4713.h" |
37 | 36 | ||
38 | /* module parameters */ | 37 | /* module parameters */ |
39 | static int debug; | 38 | static int debug; |
@@ -45,23 +44,18 @@ MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>"); | |||
45 | MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter"); | 44 | MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter"); |
46 | MODULE_VERSION("0.0.1"); | 45 | MODULE_VERSION("0.0.1"); |
47 | 46 | ||
48 | static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = { | ||
49 | "vio", | ||
50 | "vdd", | ||
51 | }; | ||
52 | |||
53 | #define DEFAULT_RDS_PI 0x00 | 47 | #define DEFAULT_RDS_PI 0x00 |
54 | #define DEFAULT_RDS_PTY 0x00 | 48 | #define DEFAULT_RDS_PTY 0x00 |
55 | #define DEFAULT_RDS_DEVIATION 0x00C8 | 49 | #define DEFAULT_RDS_DEVIATION 0x00C8 |
56 | #define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003 | 50 | #define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003 |
57 | #define DEFAULT_LIMITER_RTIME 0x1392 | 51 | #define DEFAULT_LIMITER_RTIME 0x1392 |
58 | #define DEFAULT_LIMITER_DEV 0x102CA | 52 | #define DEFAULT_LIMITER_DEV 0x102CA |
59 | #define DEFAULT_PILOT_FREQUENCY 0x4A38 | 53 | #define DEFAULT_PILOT_FREQUENCY 0x4A38 |
60 | #define DEFAULT_PILOT_DEVIATION 0x1A5E | 54 | #define DEFAULT_PILOT_DEVIATION 0x1A5E |
61 | #define DEFAULT_ACOMP_ATIME 0x0000 | 55 | #define DEFAULT_ACOMP_ATIME 0x0000 |
62 | #define DEFAULT_ACOMP_RTIME 0xF4240L | 56 | #define DEFAULT_ACOMP_RTIME 0xF4240L |
63 | #define DEFAULT_ACOMP_GAIN 0x0F | 57 | #define DEFAULT_ACOMP_GAIN 0x0F |
64 | #define DEFAULT_ACOMP_THRESHOLD (-0x28) | 58 | #define DEFAULT_ACOMP_THRESHOLD (-0x28) |
65 | #define DEFAULT_MUTE 0x01 | 59 | #define DEFAULT_MUTE 0x01 |
66 | #define DEFAULT_POWER_LEVEL 88 | 60 | #define DEFAULT_POWER_LEVEL 88 |
67 | #define DEFAULT_FREQUENCY 8800 | 61 | #define DEFAULT_FREQUENCY 8800 |
@@ -213,6 +207,7 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command, | |||
213 | u8 response[], const int respn, const int usecs) | 207 | u8 response[], const int respn, const int usecs) |
214 | { | 208 | { |
215 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); | 209 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); |
210 | unsigned long until_jiffies; | ||
216 | u8 data1[MAX_ARGS + 1]; | 211 | u8 data1[MAX_ARGS + 1]; |
217 | int err; | 212 | int err; |
218 | 213 | ||
@@ -228,30 +223,42 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command, | |||
228 | if (err != argn + 1) { | 223 | if (err != argn + 1) { |
229 | v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n", | 224 | v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n", |
230 | command); | 225 | command); |
231 | return (err > 0) ? -EIO : err; | 226 | return err < 0 ? err : -EIO; |
232 | } | 227 | } |
233 | 228 | ||
229 | until_jiffies = jiffies + usecs_to_jiffies(usecs) + 1; | ||
230 | |||
234 | /* Wait response from interrupt */ | 231 | /* Wait response from interrupt */ |
235 | if (!wait_for_completion_timeout(&sdev->work, | 232 | if (client->irq) { |
233 | if (!wait_for_completion_timeout(&sdev->work, | ||
236 | usecs_to_jiffies(usecs) + 1)) | 234 | usecs_to_jiffies(usecs) + 1)) |
237 | v4l2_warn(&sdev->sd, | 235 | v4l2_warn(&sdev->sd, |
238 | "(%s) Device took too much time to answer.\n", | 236 | "(%s) Device took too much time to answer.\n", |
239 | __func__); | 237 | __func__); |
240 | |||
241 | /* Then get the response */ | ||
242 | err = i2c_master_recv(client, response, respn); | ||
243 | if (err != respn) { | ||
244 | v4l2_err(&sdev->sd, | ||
245 | "Error while reading response for command 0x%02x\n", | ||
246 | command); | ||
247 | return (err > 0) ? -EIO : err; | ||
248 | } | 238 | } |
249 | 239 | ||
250 | DBG_BUFFER(&sdev->sd, "Response", response, respn); | 240 | do { |
251 | if (check_command_failed(response[0])) | 241 | err = i2c_master_recv(client, response, respn); |
252 | return -EBUSY; | 242 | if (err != respn) { |
243 | v4l2_err(&sdev->sd, | ||
244 | "Error %d while reading response for command 0x%02x\n", | ||
245 | err, command); | ||
246 | return err < 0 ? err : -EIO; | ||
247 | } | ||
253 | 248 | ||
254 | return 0; | 249 | DBG_BUFFER(&sdev->sd, "Response", response, respn); |
250 | if (!check_command_failed(response[0])) | ||
251 | return 0; | ||
252 | |||
253 | if (client->irq) | ||
254 | return -EBUSY; | ||
255 | if (usecs <= 1000) | ||
256 | usleep_range(usecs, 1000); | ||
257 | else | ||
258 | usleep_range(1000, 2000); | ||
259 | } while (time_is_after_jiffies(until_jiffies)); | ||
260 | |||
261 | return -EBUSY; | ||
255 | } | 262 | } |
256 | 263 | ||
257 | /* | 264 | /* |
@@ -265,9 +272,9 @@ static int si4713_read_property(struct si4713_device *sdev, u16 prop, u32 *pv) | |||
265 | int err; | 272 | int err; |
266 | u8 val[SI4713_GET_PROP_NRESP]; | 273 | u8 val[SI4713_GET_PROP_NRESP]; |
267 | /* | 274 | /* |
268 | * .First byte = 0 | 275 | * .First byte = 0 |
269 | * .Second byte = property's MSB | 276 | * .Second byte = property's MSB |
270 | * .Third byte = property's LSB | 277 | * .Third byte = property's LSB |
271 | */ | 278 | */ |
272 | const u8 args[SI4713_GET_PROP_NARGS] = { | 279 | const u8 args[SI4713_GET_PROP_NARGS] = { |
273 | 0x00, | 280 | 0x00, |
@@ -302,11 +309,11 @@ static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val) | |||
302 | int rval; | 309 | int rval; |
303 | u8 resp[SI4713_SET_PROP_NRESP]; | 310 | u8 resp[SI4713_SET_PROP_NRESP]; |
304 | /* | 311 | /* |
305 | * .First byte = 0 | 312 | * .First byte = 0 |
306 | * .Second byte = property's MSB | 313 | * .Second byte = property's MSB |
307 | * .Third byte = property's LSB | 314 | * .Third byte = property's LSB |
308 | * .Fourth byte = value's MSB | 315 | * .Fourth byte = value's MSB |
309 | * .Fifth byte = value's LSB | 316 | * .Fifth byte = value's LSB |
310 | */ | 317 | */ |
311 | const u8 args[SI4713_SET_PROP_NARGS] = { | 318 | const u8 args[SI4713_SET_PROP_NARGS] = { |
312 | 0x00, | 319 | 0x00, |
@@ -344,31 +351,36 @@ static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val) | |||
344 | */ | 351 | */ |
345 | static int si4713_powerup(struct si4713_device *sdev) | 352 | static int si4713_powerup(struct si4713_device *sdev) |
346 | { | 353 | { |
354 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); | ||
347 | int err; | 355 | int err; |
348 | u8 resp[SI4713_PWUP_NRESP]; | 356 | u8 resp[SI4713_PWUP_NRESP]; |
349 | /* | 357 | /* |
350 | * .First byte = Enabled interrupts and boot function | 358 | * .First byte = Enabled interrupts and boot function |
351 | * .Second byte = Input operation mode | 359 | * .Second byte = Input operation mode |
352 | */ | 360 | */ |
353 | const u8 args[SI4713_PWUP_NARGS] = { | 361 | u8 args[SI4713_PWUP_NARGS] = { |
354 | SI4713_PWUP_CTSIEN | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX, | 362 | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX, |
355 | SI4713_PWUP_OPMOD_ANALOG, | 363 | SI4713_PWUP_OPMOD_ANALOG, |
356 | }; | 364 | }; |
357 | 365 | ||
358 | if (sdev->power_state) | 366 | if (sdev->power_state) |
359 | return 0; | 367 | return 0; |
360 | 368 | ||
361 | err = regulator_bulk_enable(ARRAY_SIZE(sdev->supplies), | 369 | if (sdev->supplies) { |
362 | sdev->supplies); | 370 | err = regulator_bulk_enable(sdev->supplies, sdev->supply_data); |
363 | if (err) { | 371 | if (err) { |
364 | v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err); | 372 | v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err); |
365 | return err; | 373 | return err; |
374 | } | ||
366 | } | 375 | } |
367 | if (gpio_is_valid(sdev->gpio_reset)) { | 376 | if (gpio_is_valid(sdev->gpio_reset)) { |
368 | udelay(50); | 377 | udelay(50); |
369 | gpio_set_value(sdev->gpio_reset, 1); | 378 | gpio_set_value(sdev->gpio_reset, 1); |
370 | } | 379 | } |
371 | 380 | ||
381 | if (client->irq) | ||
382 | args[0] |= SI4713_PWUP_CTSIEN; | ||
383 | |||
372 | err = si4713_send_command(sdev, SI4713_CMD_POWER_UP, | 384 | err = si4713_send_command(sdev, SI4713_CMD_POWER_UP, |
373 | args, ARRAY_SIZE(args), | 385 | args, ARRAY_SIZE(args), |
374 | resp, ARRAY_SIZE(resp), | 386 | resp, ARRAY_SIZE(resp), |
@@ -380,13 +392,15 @@ static int si4713_powerup(struct si4713_device *sdev) | |||
380 | v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n"); | 392 | v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n"); |
381 | sdev->power_state = POWER_ON; | 393 | sdev->power_state = POWER_ON; |
382 | 394 | ||
383 | err = si4713_write_property(sdev, SI4713_GPO_IEN, | 395 | if (client->irq) |
396 | err = si4713_write_property(sdev, SI4713_GPO_IEN, | ||
384 | SI4713_STC_INT | SI4713_CTS); | 397 | SI4713_STC_INT | SI4713_CTS); |
385 | } else { | 398 | return err; |
386 | if (gpio_is_valid(sdev->gpio_reset)) | 399 | } |
387 | gpio_set_value(sdev->gpio_reset, 0); | 400 | if (gpio_is_valid(sdev->gpio_reset)) |
388 | err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies), | 401 | gpio_set_value(sdev->gpio_reset, 0); |
389 | sdev->supplies); | 402 | if (sdev->supplies) { |
403 | err = regulator_bulk_disable(sdev->supplies, sdev->supply_data); | ||
390 | if (err) | 404 | if (err) |
391 | v4l2_err(&sdev->sd, | 405 | v4l2_err(&sdev->sd, |
392 | "Failed to disable supplies: %d\n", err); | 406 | "Failed to disable supplies: %d\n", err); |
@@ -418,11 +432,13 @@ static int si4713_powerdown(struct si4713_device *sdev) | |||
418 | v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n"); | 432 | v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n"); |
419 | if (gpio_is_valid(sdev->gpio_reset)) | 433 | if (gpio_is_valid(sdev->gpio_reset)) |
420 | gpio_set_value(sdev->gpio_reset, 0); | 434 | gpio_set_value(sdev->gpio_reset, 0); |
421 | err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies), | 435 | if (sdev->supplies) { |
422 | sdev->supplies); | 436 | err = regulator_bulk_disable(sdev->supplies, |
423 | if (err) | 437 | sdev->supply_data); |
424 | v4l2_err(&sdev->sd, | 438 | if (err) |
425 | "Failed to disable supplies: %d\n", err); | 439 | v4l2_err(&sdev->sd, |
440 | "Failed to disable supplies: %d\n", err); | ||
441 | } | ||
426 | sdev->power_state = POWER_OFF; | 442 | sdev->power_state = POWER_OFF; |
427 | } | 443 | } |
428 | 444 | ||
@@ -451,7 +467,7 @@ static int si4713_checkrev(struct si4713_device *sdev) | |||
451 | v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n", | 467 | v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n", |
452 | client->addr << 1, client->adapter->name); | 468 | client->addr << 1, client->adapter->name); |
453 | } else { | 469 | } else { |
454 | v4l2_err(&sdev->sd, "Invalid product number\n"); | 470 | v4l2_err(&sdev->sd, "Invalid product number 0x%X\n", resp[1]); |
455 | rval = -EINVAL; | 471 | rval = -EINVAL; |
456 | } | 472 | } |
457 | return rval; | 473 | return rval; |
@@ -465,39 +481,45 @@ static int si4713_checkrev(struct si4713_device *sdev) | |||
465 | */ | 481 | */ |
466 | static int si4713_wait_stc(struct si4713_device *sdev, const int usecs) | 482 | static int si4713_wait_stc(struct si4713_device *sdev, const int usecs) |
467 | { | 483 | { |
468 | int err; | 484 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); |
469 | u8 resp[SI4713_GET_STATUS_NRESP]; | 485 | u8 resp[SI4713_GET_STATUS_NRESP]; |
486 | unsigned long start_jiffies = jiffies; | ||
487 | int err; | ||
470 | 488 | ||
471 | /* Wait response from STC interrupt */ | 489 | if (client->irq && |
472 | if (!wait_for_completion_timeout(&sdev->work, | 490 | !wait_for_completion_timeout(&sdev->work, usecs_to_jiffies(usecs) + 1)) |
473 | usecs_to_jiffies(usecs) + 1)) | ||
474 | v4l2_warn(&sdev->sd, | 491 | v4l2_warn(&sdev->sd, |
475 | "%s: device took too much time to answer (%d usec).\n", | 492 | "(%s) Device took too much time to answer.\n", __func__); |
476 | __func__, usecs); | 493 | |
477 | 494 | for (;;) { | |
478 | /* Clear status bits */ | 495 | /* Clear status bits */ |
479 | err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS, | 496 | err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS, |
480 | NULL, 0, | 497 | NULL, 0, |
481 | resp, ARRAY_SIZE(resp), | 498 | resp, ARRAY_SIZE(resp), |
482 | DEFAULT_TIMEOUT); | 499 | DEFAULT_TIMEOUT); |
483 | 500 | /* The USB device returns errors when it waits for the | |
484 | if (err < 0) | 501 | * STC bit to be set. Hence polling */ |
485 | goto exit; | 502 | if (err >= 0) { |
486 | 503 | v4l2_dbg(1, debug, &sdev->sd, | |
487 | v4l2_dbg(1, debug, &sdev->sd, | 504 | "%s: status bits: 0x%02x\n", __func__, resp[0]); |
488 | "%s: status bits: 0x%02x\n", __func__, resp[0]); | 505 | |
489 | 506 | if (resp[0] & SI4713_STC_INT) | |
490 | if (!(resp[0] & SI4713_STC_INT)) | 507 | return 0; |
491 | err = -EIO; | 508 | } |
492 | 509 | if (jiffies_to_usecs(jiffies - start_jiffies) > usecs) | |
493 | exit: | 510 | return err < 0 ? err : -EIO; |
494 | return err; | 511 | /* We sleep here for 3-4 ms in order to avoid flooding the device |
512 | * with USB requests. The si4713 USB driver was developed | ||
513 | * by reverse engineering the Windows USB driver. The windows | ||
514 | * driver also has a ~2.5 ms delay between responses. */ | ||
515 | usleep_range(3000, 4000); | ||
516 | } | ||
495 | } | 517 | } |
496 | 518 | ||
497 | /* | 519 | /* |
498 | * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning | 520 | * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning |
499 | * frequency between 76 and 108 MHz in 10 kHz units and | 521 | * frequency between 76 and 108 MHz in 10 kHz units and |
500 | * steps of 50 kHz. | 522 | * steps of 50 kHz. |
501 | * @sdev: si4713_device structure for the device we are communicating | 523 | * @sdev: si4713_device structure for the device we are communicating |
502 | * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) | 524 | * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) |
503 | */ | 525 | */ |
@@ -506,9 +528,9 @@ static int si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency) | |||
506 | int err; | 528 | int err; |
507 | u8 val[SI4713_TXFREQ_NRESP]; | 529 | u8 val[SI4713_TXFREQ_NRESP]; |
508 | /* | 530 | /* |
509 | * .First byte = 0 | 531 | * .First byte = 0 |
510 | * .Second byte = frequency's MSB | 532 | * .Second byte = frequency's MSB |
511 | * .Third byte = frequency's LSB | 533 | * .Third byte = frequency's LSB |
512 | */ | 534 | */ |
513 | const u8 args[SI4713_TXFREQ_NARGS] = { | 535 | const u8 args[SI4713_TXFREQ_NARGS] = { |
514 | 0x00, | 536 | 0x00, |
@@ -535,14 +557,14 @@ static int si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency) | |||
535 | } | 557 | } |
536 | 558 | ||
537 | /* | 559 | /* |
538 | * si4713_tx_tune_power - Sets the RF voltage level between 88 and 115 dBuV in | 560 | * si4713_tx_tune_power - Sets the RF voltage level between 88 and 120 dBuV in |
539 | * 1 dB units. A value of 0x00 indicates off. The command | 561 | * 1 dB units. A value of 0x00 indicates off. The command |
540 | * also sets the antenna tuning capacitance. A value of 0 | 562 | * also sets the antenna tuning capacitance. A value of 0 |
541 | * indicates autotuning, and a value of 1 - 191 indicates | 563 | * indicates autotuning, and a value of 1 - 191 indicates |
542 | * a manual override, which results in a tuning | 564 | * a manual override, which results in a tuning |
543 | * capacitance of 0.25 pF x @antcap. | 565 | * capacitance of 0.25 pF x @antcap. |
544 | * @sdev: si4713_device structure for the device we are communicating | 566 | * @sdev: si4713_device structure for the device we are communicating |
545 | * @power: tuning power (88 - 115 dBuV, unit/step 1 dB) | 567 | * @power: tuning power (88 - 120 dBuV, unit/step 1 dB) |
546 | * @antcap: value of antenna tuning capacitor (0 - 191) | 568 | * @antcap: value of antenna tuning capacitor (0 - 191) |
547 | */ | 569 | */ |
548 | static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power, | 570 | static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power, |
@@ -551,21 +573,21 @@ static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power, | |||
551 | int err; | 573 | int err; |
552 | u8 val[SI4713_TXPWR_NRESP]; | 574 | u8 val[SI4713_TXPWR_NRESP]; |
553 | /* | 575 | /* |
554 | * .First byte = 0 | 576 | * .First byte = 0 |
555 | * .Second byte = 0 | 577 | * .Second byte = 0 |
556 | * .Third byte = power | 578 | * .Third byte = power |
557 | * .Fourth byte = antcap | 579 | * .Fourth byte = antcap |
558 | */ | 580 | */ |
559 | const u8 args[SI4713_TXPWR_NARGS] = { | 581 | u8 args[SI4713_TXPWR_NARGS] = { |
560 | 0x00, | 582 | 0x00, |
561 | 0x00, | 583 | 0x00, |
562 | power, | 584 | power, |
563 | antcap, | 585 | antcap, |
564 | }; | 586 | }; |
565 | 587 | ||
566 | if (((power > 0) && (power < SI4713_MIN_POWER)) || | 588 | /* Map power values 1-87 to MIN_POWER (88) */ |
567 | power > SI4713_MAX_POWER || antcap > SI4713_MAX_ANTCAP) | 589 | if (power > 0 && power < SI4713_MIN_POWER) |
568 | return -EDOM; | 590 | args[2] = power = SI4713_MIN_POWER; |
569 | 591 | ||
570 | err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_POWER, | 592 | err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_POWER, |
571 | args, ARRAY_SIZE(args), val, | 593 | args, ARRAY_SIZE(args), val, |
@@ -583,12 +605,12 @@ static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power, | |||
583 | 605 | ||
584 | /* | 606 | /* |
585 | * si4713_tx_tune_measure - Enters receive mode and measures the received noise | 607 | * si4713_tx_tune_measure - Enters receive mode and measures the received noise |
586 | * level in units of dBuV on the selected frequency. | 608 | * level in units of dBuV on the selected frequency. |
587 | * The Frequency must be between 76 and 108 MHz in 10 kHz | 609 | * The Frequency must be between 76 and 108 MHz in 10 kHz |
588 | * units and steps of 50 kHz. The command also sets the | 610 | * units and steps of 50 kHz. The command also sets the |
589 | * antenna tuning capacitance. A value of 0 means | 611 | * antenna tuning capacitance. A value of 0 means |
590 | * autotuning, and a value of 1 to 191 indicates manual | 612 | * autotuning, and a value of 1 to 191 indicates manual |
591 | * override. | 613 | * override. |
592 | * @sdev: si4713_device structure for the device we are communicating | 614 | * @sdev: si4713_device structure for the device we are communicating |
593 | * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) | 615 | * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) |
594 | * @antcap: value of antenna tuning capacitor (0 - 191) | 616 | * @antcap: value of antenna tuning capacitor (0 - 191) |
@@ -599,10 +621,10 @@ static int si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency, | |||
599 | int err; | 621 | int err; |
600 | u8 val[SI4713_TXMEA_NRESP]; | 622 | u8 val[SI4713_TXMEA_NRESP]; |
601 | /* | 623 | /* |
602 | * .First byte = 0 | 624 | * .First byte = 0 |
603 | * .Second byte = frequency's MSB | 625 | * .Second byte = frequency's MSB |
604 | * .Third byte = frequency's LSB | 626 | * .Third byte = frequency's LSB |
605 | * .Fourth byte = antcap | 627 | * .Fourth byte = antcap |
606 | */ | 628 | */ |
607 | const u8 args[SI4713_TXMEA_NARGS] = { | 629 | const u8 args[SI4713_TXMEA_NARGS] = { |
608 | 0x00, | 630 | 0x00, |
@@ -632,11 +654,11 @@ static int si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency, | |||
632 | 654 | ||
633 | /* | 655 | /* |
634 | * si4713_tx_tune_status- Returns the status of the tx_tune_freq, tx_tune_mea or | 656 | * si4713_tx_tune_status- Returns the status of the tx_tune_freq, tx_tune_mea or |
635 | * tx_tune_power commands. This command return the current | 657 | * tx_tune_power commands. This command return the current |
636 | * frequency, output voltage in dBuV, the antenna tunning | 658 | * frequency, output voltage in dBuV, the antenna tunning |
637 | * capacitance value and the received noise level. The | 659 | * capacitance value and the received noise level. The |
638 | * command also clears the stcint interrupt bit when the | 660 | * command also clears the stcint interrupt bit when the |
639 | * first bit of its arguments is high. | 661 | * first bit of its arguments is high. |
640 | * @sdev: si4713_device structure for the device we are communicating | 662 | * @sdev: si4713_device structure for the device we are communicating |
641 | * @intack: 0x01 to clear the seek/tune complete interrupt status indicator. | 663 | * @intack: 0x01 to clear the seek/tune complete interrupt status indicator. |
642 | * @frequency: returned frequency | 664 | * @frequency: returned frequency |
@@ -651,7 +673,7 @@ static int si4713_tx_tune_status(struct si4713_device *sdev, u8 intack, | |||
651 | int err; | 673 | int err; |
652 | u8 val[SI4713_TXSTATUS_NRESP]; | 674 | u8 val[SI4713_TXSTATUS_NRESP]; |
653 | /* | 675 | /* |
654 | * .First byte = intack bit | 676 | * .First byte = intack bit |
655 | */ | 677 | */ |
656 | const u8 args[SI4713_TXSTATUS_NARGS] = { | 678 | const u8 args[SI4713_TXSTATUS_NARGS] = { |
657 | intack & SI4713_INTACK_MASK, | 679 | intack & SI4713_INTACK_MASK, |
@@ -812,8 +834,9 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name) | |||
812 | return rval; | 834 | return rval; |
813 | } | 835 | } |
814 | 836 | ||
815 | static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) | 837 | static int si4713_set_rds_radio_text(struct si4713_device *sdev, const char *rt) |
816 | { | 838 | { |
839 | static const char cr[RDS_RADIOTEXT_BLK_SIZE] = { RDS_CARRIAGE_RETURN, 0 }; | ||
817 | int rval = 0, i; | 840 | int rval = 0, i; |
818 | u16 t_index = 0; | 841 | u16 t_index = 0; |
819 | u8 b_index = 0, cr_inserted = 0; | 842 | u8 b_index = 0, cr_inserted = 0; |
@@ -837,7 +860,7 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) | |||
837 | for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) { | 860 | for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) { |
838 | if (!rt[t_index + i] || | 861 | if (!rt[t_index + i] || |
839 | rt[t_index + i] == RDS_CARRIAGE_RETURN) { | 862 | rt[t_index + i] == RDS_CARRIAGE_RETURN) { |
840 | rt[t_index + i] = RDS_CARRIAGE_RETURN; | 863 | rt = cr; |
841 | cr_inserted = 1; | 864 | cr_inserted = 1; |
842 | break; | 865 | break; |
843 | } | 866 | } |
@@ -1024,7 +1047,6 @@ static int si4713_initialize(struct si4713_device *sdev) | |||
1024 | if (rval < 0) | 1047 | if (rval < 0) |
1025 | return rval; | 1048 | return rval; |
1026 | 1049 | ||
1027 | |||
1028 | sdev->frequency = DEFAULT_FREQUENCY; | 1050 | sdev->frequency = DEFAULT_FREQUENCY; |
1029 | sdev->stereo = 1; | 1051 | sdev->stereo = 1; |
1030 | sdev->tune_rnl = DEFAULT_TUNE_RNL; | 1052 | sdev->tune_rnl = DEFAULT_TUNE_RNL; |
@@ -1345,7 +1367,7 @@ static int si4713_probe(struct i2c_client *client, | |||
1345 | struct v4l2_ctrl_handler *hdl; | 1367 | struct v4l2_ctrl_handler *hdl; |
1346 | int rval, i; | 1368 | int rval, i; |
1347 | 1369 | ||
1348 | sdev = kzalloc(sizeof *sdev, GFP_KERNEL); | 1370 | sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); |
1349 | if (!sdev) { | 1371 | if (!sdev) { |
1350 | dev_err(&client->dev, "Failed to alloc video device.\n"); | 1372 | dev_err(&client->dev, "Failed to alloc video device.\n"); |
1351 | rval = -ENOMEM; | 1373 | rval = -ENOMEM; |
@@ -1362,13 +1384,14 @@ static int si4713_probe(struct i2c_client *client, | |||
1362 | } | 1384 | } |
1363 | sdev->gpio_reset = pdata->gpio_reset; | 1385 | sdev->gpio_reset = pdata->gpio_reset; |
1364 | gpio_direction_output(sdev->gpio_reset, 0); | 1386 | gpio_direction_output(sdev->gpio_reset, 0); |
1387 | sdev->supplies = pdata->supplies; | ||
1365 | } | 1388 | } |
1366 | 1389 | ||
1367 | for (i = 0; i < ARRAY_SIZE(sdev->supplies); i++) | 1390 | for (i = 0; i < sdev->supplies; i++) |
1368 | sdev->supplies[i].supply = si4713_supply_names[i]; | 1391 | sdev->supply_data[i].supply = pdata->supply_names[i]; |
1369 | 1392 | ||
1370 | rval = regulator_bulk_get(&client->dev, ARRAY_SIZE(sdev->supplies), | 1393 | rval = regulator_bulk_get(&client->dev, sdev->supplies, |
1371 | sdev->supplies); | 1394 | sdev->supply_data); |
1372 | if (rval) { | 1395 | if (rval) { |
1373 | dev_err(&client->dev, "Cannot get regulators: %d\n", rval); | 1396 | dev_err(&client->dev, "Cannot get regulators: %d\n", rval); |
1374 | goto free_gpio; | 1397 | goto free_gpio; |
@@ -1420,8 +1443,8 @@ static int si4713_probe(struct i2c_client *client, | |||
1420 | V4L2_CID_AUDIO_COMPRESSION_GAIN, 0, MAX_ACOMP_GAIN, 1, | 1443 | V4L2_CID_AUDIO_COMPRESSION_GAIN, 0, MAX_ACOMP_GAIN, 1, |
1421 | DEFAULT_ACOMP_GAIN); | 1444 | DEFAULT_ACOMP_GAIN); |
1422 | sdev->compression_threshold = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, | 1445 | sdev->compression_threshold = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, |
1423 | V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, MIN_ACOMP_THRESHOLD, | 1446 | V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, |
1424 | MAX_ACOMP_THRESHOLD, 1, | 1447 | MIN_ACOMP_THRESHOLD, MAX_ACOMP_THRESHOLD, 1, |
1425 | DEFAULT_ACOMP_THRESHOLD); | 1448 | DEFAULT_ACOMP_THRESHOLD); |
1426 | sdev->compression_attack_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, | 1449 | sdev->compression_attack_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, |
1427 | V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, 0, | 1450 | V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, 0, |
@@ -1443,9 +1466,11 @@ static int si4713_probe(struct i2c_client *client, | |||
1443 | V4L2_CID_TUNE_PREEMPHASIS, | 1466 | V4L2_CID_TUNE_PREEMPHASIS, |
1444 | V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS); | 1467 | V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS); |
1445 | sdev->tune_pwr_level = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, | 1468 | sdev->tune_pwr_level = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, |
1446 | V4L2_CID_TUNE_POWER_LEVEL, 0, 120, 1, DEFAULT_POWER_LEVEL); | 1469 | V4L2_CID_TUNE_POWER_LEVEL, 0, SI4713_MAX_POWER, |
1470 | 1, DEFAULT_POWER_LEVEL); | ||
1447 | sdev->tune_ant_cap = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, | 1471 | sdev->tune_ant_cap = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, |
1448 | V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, 191, 1, 0); | 1472 | V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, SI4713_MAX_ANTCAP, |
1473 | 1, 0); | ||
1449 | 1474 | ||
1450 | if (hdl->error) { | 1475 | if (hdl->error) { |
1451 | rval = hdl->error; | 1476 | rval = hdl->error; |
@@ -1481,7 +1506,7 @@ free_irq: | |||
1481 | free_ctrls: | 1506 | free_ctrls: |
1482 | v4l2_ctrl_handler_free(hdl); | 1507 | v4l2_ctrl_handler_free(hdl); |
1483 | put_reg: | 1508 | put_reg: |
1484 | regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); | 1509 | regulator_bulk_free(sdev->supplies, sdev->supply_data); |
1485 | free_gpio: | 1510 | free_gpio: |
1486 | if (gpio_is_valid(sdev->gpio_reset)) | 1511 | if (gpio_is_valid(sdev->gpio_reset)) |
1487 | gpio_free(sdev->gpio_reset); | 1512 | gpio_free(sdev->gpio_reset); |
@@ -1505,7 +1530,7 @@ static int si4713_remove(struct i2c_client *client) | |||
1505 | 1530 | ||
1506 | v4l2_device_unregister_subdev(sd); | 1531 | v4l2_device_unregister_subdev(sd); |
1507 | v4l2_ctrl_handler_free(sd->ctrl_handler); | 1532 | v4l2_ctrl_handler_free(sd->ctrl_handler); |
1508 | regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); | 1533 | regulator_bulk_free(sdev->supplies, sdev->supply_data); |
1509 | if (gpio_is_valid(sdev->gpio_reset)) | 1534 | if (gpio_is_valid(sdev->gpio_reset)) |
1510 | gpio_free(sdev->gpio_reset); | 1535 | gpio_free(sdev->gpio_reset); |
1511 | kfree(sdev); | 1536 | kfree(sdev); |
diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713/si4713.h index 25cdea26343b..4837cf6e0e1b 100644 --- a/drivers/media/radio/si4713-i2c.h +++ b/drivers/media/radio/si4713/si4713.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #ifndef SI4713_I2C_H | 15 | #ifndef SI4713_I2C_H |
16 | #define SI4713_I2C_H | 16 | #define SI4713_I2C_H |
17 | 17 | ||
18 | #include <linux/regulator/consumer.h> | ||
18 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
19 | #include <media/v4l2-ctrls.h> | 20 | #include <media/v4l2-ctrls.h> |
20 | #include <media/si4713.h> | 21 | #include <media/si4713.h> |
@@ -226,7 +227,8 @@ struct si4713_device { | |||
226 | struct v4l2_ctrl *tune_ant_cap; | 227 | struct v4l2_ctrl *tune_ant_cap; |
227 | }; | 228 | }; |
228 | struct completion work; | 229 | struct completion work; |
229 | struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES]; | 230 | unsigned supplies; |
231 | struct regulator_bulk_data supply_data[SI4713_NUM_SUPPLIES]; | ||
230 | int gpio_reset; | 232 | int gpio_reset; |
231 | u32 power_state; | 233 | u32 power_state; |
232 | u32 rds_enabled; | 234 | u32 rds_enabled; |
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c index cef06981b7c9..7c14060a40b8 100644 --- a/drivers/media/radio/tea575x.c +++ b/drivers/media/radio/tea575x.c | |||
@@ -20,12 +20,12 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <asm/io.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/module.h> | 24 | #include <linux/module.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
28 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <asm/io.h> | ||
29 | #include <media/v4l2-device.h> | 29 | #include <media/v4l2-device.h> |
30 | #include <media/v4l2-dev.h> | 30 | #include <media/v4l2-dev.h> |
31 | #include <media/v4l2-fh.h> | 31 | #include <media/v4l2-fh.h> |
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index f329485c6629..822b9f47ca72 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c | |||
@@ -1909,10 +1909,8 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) | |||
1909 | int ret, i; | 1909 | int ret, i; |
1910 | 1910 | ||
1911 | idev = input_allocate_device(); | 1911 | idev = input_allocate_device(); |
1912 | if (!idev) { | 1912 | if (!idev) |
1913 | dev_err(ictx->dev, "input dev allocation failed\n"); | ||
1914 | goto out; | 1913 | goto out; |
1915 | } | ||
1916 | 1914 | ||
1917 | snprintf(ictx->name_idev, sizeof(ictx->name_idev), | 1915 | snprintf(ictx->name_idev, sizeof(ictx->name_idev), |
1918 | "iMON Panel, Knob and Mouse(%04x:%04x)", | 1916 | "iMON Panel, Knob and Mouse(%04x:%04x)", |
@@ -1960,10 +1958,8 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx) | |||
1960 | int ret; | 1958 | int ret; |
1961 | 1959 | ||
1962 | touch = input_allocate_device(); | 1960 | touch = input_allocate_device(); |
1963 | if (!touch) { | 1961 | if (!touch) |
1964 | dev_err(ictx->dev, "touchscreen input dev allocation failed\n"); | ||
1965 | goto touch_alloc_failed; | 1962 | goto touch_alloc_failed; |
1966 | } | ||
1967 | 1963 | ||
1968 | snprintf(ictx->name_touch, sizeof(ictx->name_touch), | 1964 | snprintf(ictx->name_touch, sizeof(ictx->name_touch), |
1969 | "iMON USB Touchscreen (%04x:%04x)", | 1965 | "iMON USB Touchscreen (%04x:%04x)", |
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index b1cde8c0422b..0b8c54919010 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile | |||
@@ -98,4 +98,5 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | |||
98 | rc-videomate-s350.o \ | 98 | rc-videomate-s350.o \ |
99 | rc-videomate-tv-pvr.o \ | 99 | rc-videomate-tv-pvr.o \ |
100 | rc-winfast.o \ | 100 | rc-winfast.o \ |
101 | rc-winfast-usbii-deluxe.o | 101 | rc-winfast-usbii-deluxe.o \ |
102 | rc-su3000.o | ||
diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c new file mode 100644 index 000000000000..8dbd3e9bc951 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-su3000.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* rc-su3000.h - Keytable for Geniatech HDStar Remote Controller | ||
2 | * | ||
3 | * Copyright (c) 2013 by Evgeny Plehov <Evgeny Plehov@ukr.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <media/rc-map.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | static struct rc_map_table su3000[] = { | ||
15 | { 0x25, KEY_POWER }, /* right-bottom Red */ | ||
16 | { 0x0a, KEY_MUTE }, /* -/-- */ | ||
17 | { 0x01, KEY_1 }, | ||
18 | { 0x02, KEY_2 }, | ||
19 | { 0x03, KEY_3 }, | ||
20 | { 0x04, KEY_4 }, | ||
21 | { 0x05, KEY_5 }, | ||
22 | { 0x06, KEY_6 }, | ||
23 | { 0x07, KEY_7 }, | ||
24 | { 0x08, KEY_8 }, | ||
25 | { 0x09, KEY_9 }, | ||
26 | { 0x00, KEY_0 }, | ||
27 | { 0x20, KEY_UP }, /* CH+ */ | ||
28 | { 0x21, KEY_DOWN }, /* CH+ */ | ||
29 | { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ | ||
30 | { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ | ||
31 | { 0x1f, KEY_RECORD }, | ||
32 | { 0x17, KEY_PLAY }, | ||
33 | { 0x16, KEY_PAUSE }, | ||
34 | { 0x0b, KEY_STOP }, | ||
35 | { 0x27, KEY_FASTFORWARD },/* >> */ | ||
36 | { 0x26, KEY_REWIND }, /* << */ | ||
37 | { 0x0d, KEY_OK }, /* Mute */ | ||
38 | { 0x11, KEY_LEFT }, /* VOL- */ | ||
39 | { 0x10, KEY_RIGHT }, /* VOL+ */ | ||
40 | { 0x29, KEY_BACK }, /* button under 9 */ | ||
41 | { 0x2c, KEY_MENU }, /* TTX */ | ||
42 | { 0x2b, KEY_EPG }, /* EPG */ | ||
43 | { 0x1e, KEY_RED }, /* OSD */ | ||
44 | { 0x0e, KEY_GREEN }, /* Window */ | ||
45 | { 0x2d, KEY_YELLOW }, /* button under << */ | ||
46 | { 0x0f, KEY_BLUE }, /* bottom yellow button */ | ||
47 | { 0x14, KEY_AUDIO }, /* Snapshot */ | ||
48 | { 0x38, KEY_TV }, /* TV/Radio */ | ||
49 | { 0x0c, KEY_ESC } /* upper Red button */ | ||
50 | }; | ||
51 | |||
52 | static struct rc_map_list su3000_map = { | ||
53 | .map = { | ||
54 | .scan = su3000, | ||
55 | .size = ARRAY_SIZE(su3000), | ||
56 | .rc_type = RC_TYPE_RC5, | ||
57 | .name = RC_MAP_SU3000, | ||
58 | } | ||
59 | }; | ||
60 | |||
61 | static int __init init_rc_map_su3000(void) | ||
62 | { | ||
63 | return rc_map_register(&su3000_map); | ||
64 | } | ||
65 | |||
66 | static void __exit exit_rc_map_su3000(void) | ||
67 | { | ||
68 | rc_map_unregister(&su3000_map); | ||
69 | } | ||
70 | |||
71 | module_init(init_rc_map_su3000) | ||
72 | module_exit(exit_rc_map_su3000) | ||
73 | |||
74 | MODULE_LICENSE("GPL"); | ||
75 | MODULE_AUTHOR("Evgeny Plehov <Evgeny Plehov@ukr.net>"); | ||
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 3c761014d3ce..a25bb1581e46 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c | |||
@@ -199,6 +199,7 @@ static bool debug; | |||
199 | #define VENDOR_TIVO 0x105a | 199 | #define VENDOR_TIVO 0x105a |
200 | #define VENDOR_CONEXANT 0x0572 | 200 | #define VENDOR_CONEXANT 0x0572 |
201 | #define VENDOR_TWISTEDMELON 0x2596 | 201 | #define VENDOR_TWISTEDMELON 0x2596 |
202 | #define VENDOR_HAUPPAUGE 0x2040 | ||
202 | 203 | ||
203 | enum mceusb_model_type { | 204 | enum mceusb_model_type { |
204 | MCE_GEN2 = 0, /* Most boards */ | 205 | MCE_GEN2 = 0, /* Most boards */ |
@@ -210,6 +211,7 @@ enum mceusb_model_type { | |||
210 | MULTIFUNCTION, | 211 | MULTIFUNCTION, |
211 | TIVO_KIT, | 212 | TIVO_KIT, |
212 | MCE_GEN2_NO_TX, | 213 | MCE_GEN2_NO_TX, |
214 | HAUPPAUGE_CX_HYBRID_TV, | ||
213 | }; | 215 | }; |
214 | 216 | ||
215 | struct mceusb_model { | 217 | struct mceusb_model { |
@@ -258,6 +260,11 @@ static const struct mceusb_model mceusb_model[] = { | |||
258 | .no_tx = 1, /* tx isn't wired up at all */ | 260 | .no_tx = 1, /* tx isn't wired up at all */ |
259 | .name = "Conexant Hybrid TV (cx231xx) MCE IR", | 261 | .name = "Conexant Hybrid TV (cx231xx) MCE IR", |
260 | }, | 262 | }, |
263 | [HAUPPAUGE_CX_HYBRID_TV] = { | ||
264 | .rc_map = RC_MAP_HAUPPAUGE, | ||
265 | .no_tx = 1, /* eeprom says it has no tx */ | ||
266 | .name = "Conexant Hybrid TV (cx231xx) MCE IR no TX", | ||
267 | }, | ||
261 | [MULTIFUNCTION] = { | 268 | [MULTIFUNCTION] = { |
262 | .mce_gen2 = 1, | 269 | .mce_gen2 = 1, |
263 | .ir_intfnum = 2, | 270 | .ir_intfnum = 2, |
@@ -399,6 +406,9 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
399 | { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8016) }, | 406 | { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8016) }, |
400 | /* Twisted Melon Inc. - Manta Transceiver */ | 407 | /* Twisted Melon Inc. - Manta Transceiver */ |
401 | { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8042) }, | 408 | { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8042) }, |
409 | /* Hauppauge WINTV-HVR-HVR 930C-HD - based on cx231xx */ | ||
410 | { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb130), | ||
411 | .driver_info = HAUPPAUGE_CX_HYBRID_TV }, | ||
402 | /* Terminating entry */ | 412 | /* Terminating entry */ |
403 | { } | 413 | { } |
404 | }; | 414 | }; |
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 46da365c9c84..02e2f38c9c85 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c | |||
@@ -22,6 +22,10 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include "rc-core-priv.h" | 23 | #include "rc-core-priv.h" |
24 | 24 | ||
25 | /* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */ | ||
26 | #define IRRCV_NUM_DEVICES 256 | ||
27 | DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES); | ||
28 | |||
25 | /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ | 29 | /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ |
26 | #define IR_TAB_MIN_SIZE 256 | 30 | #define IR_TAB_MIN_SIZE 256 |
27 | #define IR_TAB_MAX_SIZE 8192 | 31 | #define IR_TAB_MAX_SIZE 8192 |
@@ -1065,10 +1069,9 @@ EXPORT_SYMBOL_GPL(rc_free_device); | |||
1065 | int rc_register_device(struct rc_dev *dev) | 1069 | int rc_register_device(struct rc_dev *dev) |
1066 | { | 1070 | { |
1067 | static bool raw_init = false; /* raw decoders loaded? */ | 1071 | static bool raw_init = false; /* raw decoders loaded? */ |
1068 | static atomic_t devno = ATOMIC_INIT(0); | ||
1069 | struct rc_map *rc_map; | 1072 | struct rc_map *rc_map; |
1070 | const char *path; | 1073 | const char *path; |
1071 | int rc; | 1074 | int rc, devno; |
1072 | 1075 | ||
1073 | if (!dev || !dev->map_name) | 1076 | if (!dev || !dev->map_name) |
1074 | return -EINVAL; | 1077 | return -EINVAL; |
@@ -1096,7 +1099,15 @@ int rc_register_device(struct rc_dev *dev) | |||
1096 | */ | 1099 | */ |
1097 | mutex_lock(&dev->lock); | 1100 | mutex_lock(&dev->lock); |
1098 | 1101 | ||
1099 | dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1); | 1102 | do { |
1103 | devno = find_first_zero_bit(ir_core_dev_number, | ||
1104 | IRRCV_NUM_DEVICES); | ||
1105 | /* No free device slots */ | ||
1106 | if (devno >= IRRCV_NUM_DEVICES) | ||
1107 | return -ENOMEM; | ||
1108 | } while (test_and_set_bit(devno, ir_core_dev_number)); | ||
1109 | |||
1110 | dev->devno = devno; | ||
1100 | dev_set_name(&dev->dev, "rc%ld", dev->devno); | 1111 | dev_set_name(&dev->dev, "rc%ld", dev->devno); |
1101 | dev_set_drvdata(&dev->dev, dev); | 1112 | dev_set_drvdata(&dev->dev, dev); |
1102 | rc = device_add(&dev->dev); | 1113 | rc = device_add(&dev->dev); |
@@ -1186,6 +1197,7 @@ out_dev: | |||
1186 | device_del(&dev->dev); | 1197 | device_del(&dev->dev); |
1187 | out_unlock: | 1198 | out_unlock: |
1188 | mutex_unlock(&dev->lock); | 1199 | mutex_unlock(&dev->lock); |
1200 | clear_bit(dev->devno, ir_core_dev_number); | ||
1189 | return rc; | 1201 | return rc; |
1190 | } | 1202 | } |
1191 | EXPORT_SYMBOL_GPL(rc_register_device); | 1203 | EXPORT_SYMBOL_GPL(rc_register_device); |
@@ -1197,6 +1209,8 @@ void rc_unregister_device(struct rc_dev *dev) | |||
1197 | 1209 | ||
1198 | del_timer_sync(&dev->timer_keyup); | 1210 | del_timer_sync(&dev->timer_keyup); |
1199 | 1211 | ||
1212 | clear_bit(dev->devno, ir_core_dev_number); | ||
1213 | |||
1200 | if (dev->driver_type == RC_DRIVER_IR_RAW) | 1214 | if (dev->driver_type == RC_DRIVER_IR_RAW) |
1201 | ir_raw_event_unregister(dev); | 1215 | ir_raw_event_unregister(dev); |
1202 | 1216 | ||
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 65120c2d47ad..8f0cddb9e8f2 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/reset.h> | ||
16 | #include <media/rc-core.h> | 17 | #include <media/rc-core.h> |
17 | #include <linux/pinctrl/consumer.h> | 18 | #include <linux/pinctrl/consumer.h> |
18 | 19 | ||
@@ -28,6 +29,7 @@ struct st_rc_device { | |||
28 | int sample_mult; | 29 | int sample_mult; |
29 | int sample_div; | 30 | int sample_div; |
30 | bool rxuhfmode; | 31 | bool rxuhfmode; |
32 | struct reset_control *rstc; | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | /* Registers */ | 35 | /* Registers */ |
@@ -161,6 +163,10 @@ static void st_rc_hardware_init(struct st_rc_device *dev) | |||
161 | unsigned int rx_max_symbol_per = MAX_SYMB_TIME; | 163 | unsigned int rx_max_symbol_per = MAX_SYMB_TIME; |
162 | unsigned int rx_sampling_freq_div; | 164 | unsigned int rx_sampling_freq_div; |
163 | 165 | ||
166 | /* Enable the IP */ | ||
167 | if (dev->rstc) | ||
168 | reset_control_deassert(dev->rstc); | ||
169 | |||
164 | clk_prepare_enable(dev->sys_clock); | 170 | clk_prepare_enable(dev->sys_clock); |
165 | baseclock = clk_get_rate(dev->sys_clock); | 171 | baseclock = clk_get_rate(dev->sys_clock); |
166 | 172 | ||
@@ -271,6 +277,11 @@ static int st_rc_probe(struct platform_device *pdev) | |||
271 | else | 277 | else |
272 | rc_dev->rx_base = rc_dev->base; | 278 | rc_dev->rx_base = rc_dev->base; |
273 | 279 | ||
280 | |||
281 | rc_dev->rstc = reset_control_get(dev, NULL); | ||
282 | if (IS_ERR(rc_dev->rstc)) | ||
283 | rc_dev->rstc = NULL; | ||
284 | |||
274 | rc_dev->dev = dev; | 285 | rc_dev->dev = dev; |
275 | platform_set_drvdata(pdev, rc_dev); | 286 | platform_set_drvdata(pdev, rc_dev); |
276 | st_rc_hardware_init(rc_dev); | 287 | st_rc_hardware_init(rc_dev); |
@@ -338,6 +349,8 @@ static int st_rc_suspend(struct device *dev) | |||
338 | writel(0x00, rc_dev->rx_base + IRB_RX_EN); | 349 | writel(0x00, rc_dev->rx_base + IRB_RX_EN); |
339 | writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN); | 350 | writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN); |
340 | clk_disable_unprepare(rc_dev->sys_clock); | 351 | clk_disable_unprepare(rc_dev->sys_clock); |
352 | if (rc_dev->rstc) | ||
353 | reset_control_assert(rc_dev->rstc); | ||
341 | } | 354 | } |
342 | 355 | ||
343 | return 0; | 356 | return 0; |
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 15665debc572..ba2e365296cf 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig | |||
@@ -215,6 +215,13 @@ config MEDIA_TUNER_FC2580 | |||
215 | help | 215 | help |
216 | FCI FC2580 silicon tuner driver. | 216 | FCI FC2580 silicon tuner driver. |
217 | 217 | ||
218 | config MEDIA_TUNER_M88TS2022 | ||
219 | tristate "Montage M88TS2022 silicon tuner" | ||
220 | depends on MEDIA_SUPPORT && I2C | ||
221 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
222 | help | ||
223 | Montage M88TS2022 silicon tuner driver. | ||
224 | |||
218 | config MEDIA_TUNER_TUA9001 | 225 | config MEDIA_TUNER_TUA9001 |
219 | tristate "Infineon TUA 9001 silicon tuner" | 226 | tristate "Infineon TUA 9001 silicon tuner" |
220 | depends on MEDIA_SUPPORT && I2C | 227 | depends on MEDIA_SUPPORT && I2C |
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 308f108eadba..efe82a904b12 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o | |||
31 | obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o | 31 | obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o |
32 | obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o | 32 | obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o |
33 | obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o | 33 | obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o |
34 | obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o | ||
34 | obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o | 35 | obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o |
35 | obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o | 36 | obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o |
36 | obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o | 37 | obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o |
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 72971a8d3c37..40c1da707d15 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c | |||
@@ -243,8 +243,10 @@ static int e4000_set_params(struct dvb_frontend *fe) | |||
243 | break; | 243 | break; |
244 | } | 244 | } |
245 | 245 | ||
246 | if (i == ARRAY_SIZE(e4000_pll_lut)) | 246 | if (i == ARRAY_SIZE(e4000_pll_lut)) { |
247 | ret = -EINVAL; | ||
247 | goto err; | 248 | goto err; |
249 | } | ||
248 | 250 | ||
249 | /* | 251 | /* |
250 | * Note: Currently f_vco overflows when c->frequency is 1 073 741 824 Hz | 252 | * Note: Currently f_vco overflows when c->frequency is 1 073 741 824 Hz |
@@ -271,8 +273,10 @@ static int e4000_set_params(struct dvb_frontend *fe) | |||
271 | break; | 273 | break; |
272 | } | 274 | } |
273 | 275 | ||
274 | if (i == ARRAY_SIZE(e400_lna_filter_lut)) | 276 | if (i == ARRAY_SIZE(e400_lna_filter_lut)) { |
277 | ret = -EINVAL; | ||
275 | goto err; | 278 | goto err; |
279 | } | ||
276 | 280 | ||
277 | ret = e4000_wr_reg(priv, 0x10, e400_lna_filter_lut[i].val); | 281 | ret = e4000_wr_reg(priv, 0x10, e400_lna_filter_lut[i].val); |
278 | if (ret < 0) | 282 | if (ret < 0) |
@@ -284,8 +288,10 @@ static int e4000_set_params(struct dvb_frontend *fe) | |||
284 | break; | 288 | break; |
285 | } | 289 | } |
286 | 290 | ||
287 | if (i == ARRAY_SIZE(e4000_if_filter_lut)) | 291 | if (i == ARRAY_SIZE(e4000_if_filter_lut)) { |
292 | ret = -EINVAL; | ||
288 | goto err; | 293 | goto err; |
294 | } | ||
289 | 295 | ||
290 | buf[0] = e4000_if_filter_lut[i].reg11_val; | 296 | buf[0] = e4000_if_filter_lut[i].reg11_val; |
291 | buf[1] = e4000_if_filter_lut[i].reg12_val; | 297 | buf[1] = e4000_if_filter_lut[i].reg12_val; |
@@ -300,8 +306,10 @@ static int e4000_set_params(struct dvb_frontend *fe) | |||
300 | break; | 306 | break; |
301 | } | 307 | } |
302 | 308 | ||
303 | if (i == ARRAY_SIZE(e4000_band_lut)) | 309 | if (i == ARRAY_SIZE(e4000_band_lut)) { |
310 | ret = -EINVAL; | ||
304 | goto err; | 311 | goto err; |
312 | } | ||
305 | 313 | ||
306 | ret = e4000_wr_reg(priv, 0x07, e4000_band_lut[i].reg07_val); | 314 | ret = e4000_wr_reg(priv, 0x07, e4000_band_lut[i].reg07_val); |
307 | if (ret < 0) | 315 | if (ret < 0) |
diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c new file mode 100644 index 000000000000..40c42dec721b --- /dev/null +++ b/drivers/media/tuners/m88ts2022.c | |||
@@ -0,0 +1,674 @@ | |||
1 | /* | ||
2 | * Montage M88TS2022 silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * Some calculations are taken from existing TS2020 driver. | ||
17 | */ | ||
18 | |||
19 | #include "m88ts2022_priv.h" | ||
20 | |||
21 | /* write multiple registers */ | ||
22 | static int m88ts2022_wr_regs(struct m88ts2022_priv *priv, | ||
23 | u8 reg, const u8 *val, int len) | ||
24 | { | ||
25 | #define MAX_WR_LEN 3 | ||
26 | #define MAX_WR_XFER_LEN (MAX_WR_LEN + 1) | ||
27 | int ret; | ||
28 | u8 buf[MAX_WR_XFER_LEN]; | ||
29 | struct i2c_msg msg[1] = { | ||
30 | { | ||
31 | .addr = priv->client->addr, | ||
32 | .flags = 0, | ||
33 | .len = 1 + len, | ||
34 | .buf = buf, | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | if (WARN_ON(len > MAX_WR_LEN)) | ||
39 | return -EINVAL; | ||
40 | |||
41 | buf[0] = reg; | ||
42 | memcpy(&buf[1], val, len); | ||
43 | |||
44 | ret = i2c_transfer(priv->client->adapter, msg, 1); | ||
45 | if (ret == 1) { | ||
46 | ret = 0; | ||
47 | } else { | ||
48 | dev_warn(&priv->client->dev, | ||
49 | "%s: i2c wr failed=%d reg=%02x len=%d\n", | ||
50 | KBUILD_MODNAME, ret, reg, len); | ||
51 | ret = -EREMOTEIO; | ||
52 | } | ||
53 | |||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | /* read multiple registers */ | ||
58 | static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg, | ||
59 | u8 *val, int len) | ||
60 | { | ||
61 | #define MAX_RD_LEN 1 | ||
62 | #define MAX_RD_XFER_LEN (MAX_RD_LEN) | ||
63 | int ret; | ||
64 | u8 buf[MAX_RD_XFER_LEN]; | ||
65 | struct i2c_msg msg[2] = { | ||
66 | { | ||
67 | .addr = priv->client->addr, | ||
68 | .flags = 0, | ||
69 | .len = 1, | ||
70 | .buf = ®, | ||
71 | }, { | ||
72 | .addr = priv->client->addr, | ||
73 | .flags = I2C_M_RD, | ||
74 | .len = len, | ||
75 | .buf = buf, | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | if (WARN_ON(len > MAX_RD_LEN)) | ||
80 | return -EINVAL; | ||
81 | |||
82 | ret = i2c_transfer(priv->client->adapter, msg, 2); | ||
83 | if (ret == 2) { | ||
84 | memcpy(val, buf, len); | ||
85 | ret = 0; | ||
86 | } else { | ||
87 | dev_warn(&priv->client->dev, | ||
88 | "%s: i2c rd failed=%d reg=%02x len=%d\n", | ||
89 | KBUILD_MODNAME, ret, reg, len); | ||
90 | ret = -EREMOTEIO; | ||
91 | } | ||
92 | |||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | /* write single register */ | ||
97 | static int m88ts2022_wr_reg(struct m88ts2022_priv *priv, u8 reg, u8 val) | ||
98 | { | ||
99 | return m88ts2022_wr_regs(priv, reg, &val, 1); | ||
100 | } | ||
101 | |||
102 | /* read single register */ | ||
103 | static int m88ts2022_rd_reg(struct m88ts2022_priv *priv, u8 reg, u8 *val) | ||
104 | { | ||
105 | return m88ts2022_rd_regs(priv, reg, val, 1); | ||
106 | } | ||
107 | |||
108 | /* write single register with mask */ | ||
109 | static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv, | ||
110 | u8 reg, u8 val, u8 mask) | ||
111 | { | ||
112 | int ret; | ||
113 | u8 u8tmp; | ||
114 | |||
115 | /* no need for read if whole reg is written */ | ||
116 | if (mask != 0xff) { | ||
117 | ret = m88ts2022_rd_regs(priv, reg, &u8tmp, 1); | ||
118 | if (ret) | ||
119 | return ret; | ||
120 | |||
121 | val &= mask; | ||
122 | u8tmp &= ~mask; | ||
123 | val |= u8tmp; | ||
124 | } | ||
125 | |||
126 | return m88ts2022_wr_regs(priv, reg, &val, 1); | ||
127 | } | ||
128 | |||
129 | static int m88ts2022_cmd(struct dvb_frontend *fe, | ||
130 | int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val) | ||
131 | { | ||
132 | struct m88ts2022_priv *priv = fe->tuner_priv; | ||
133 | int ret, i; | ||
134 | u8 u8tmp; | ||
135 | struct m88ts2022_reg_val reg_vals[] = { | ||
136 | {0x51, 0x1f - op}, | ||
137 | {0x51, 0x1f}, | ||
138 | {0x50, 0x00 + op}, | ||
139 | {0x50, 0x00}, | ||
140 | }; | ||
141 | |||
142 | for (i = 0; i < 2; i++) { | ||
143 | dev_dbg(&priv->client->dev, | ||
144 | "%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n", | ||
145 | __func__, i, op, reg, mask, val); | ||
146 | |||
147 | for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { | ||
148 | ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, | ||
149 | reg_vals[i].val); | ||
150 | if (ret) | ||
151 | goto err; | ||
152 | } | ||
153 | |||
154 | usleep_range(sleep * 1000, sleep * 10000); | ||
155 | |||
156 | ret = m88ts2022_rd_reg(priv, reg, &u8tmp); | ||
157 | if (ret) | ||
158 | goto err; | ||
159 | |||
160 | if ((u8tmp & mask) != val) | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | if (reg_val) | ||
165 | *reg_val = u8tmp; | ||
166 | err: | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int m88ts2022_set_params(struct dvb_frontend *fe) | ||
171 | { | ||
172 | struct m88ts2022_priv *priv = fe->tuner_priv; | ||
173 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
174 | int ret; | ||
175 | unsigned int frequency_khz, frequency_offset_khz, f_3db_hz; | ||
176 | unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28; | ||
177 | u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min; | ||
178 | u16 u16tmp; | ||
179 | dev_dbg(&priv->client->dev, | ||
180 | "%s: frequency=%d symbol_rate=%d rolloff=%d\n", | ||
181 | __func__, c->frequency, c->symbol_rate, c->rolloff); | ||
182 | /* | ||
183 | * Integer-N PLL synthesizer | ||
184 | * kHz is used for all calculations to keep calculations within 32-bit | ||
185 | */ | ||
186 | f_ref_khz = DIV_ROUND_CLOSEST(priv->cfg.clock, 1000); | ||
187 | div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000); | ||
188 | |||
189 | if (c->symbol_rate < 5000000) | ||
190 | frequency_offset_khz = 3000; /* 3 MHz */ | ||
191 | else | ||
192 | frequency_offset_khz = 0; | ||
193 | |||
194 | frequency_khz = c->frequency + frequency_offset_khz; | ||
195 | |||
196 | if (frequency_khz < 1103000) { | ||
197 | div_out = 4; | ||
198 | u8tmp = 0x1b; | ||
199 | } else { | ||
200 | div_out = 2; | ||
201 | u8tmp = 0x0b; | ||
202 | } | ||
203 | |||
204 | buf[0] = u8tmp; | ||
205 | buf[1] = 0x40; | ||
206 | ret = m88ts2022_wr_regs(priv, 0x10, buf, 2); | ||
207 | if (ret) | ||
208 | goto err; | ||
209 | |||
210 | f_vco_khz = frequency_khz * div_out; | ||
211 | pll_n = f_vco_khz * div_ref / f_ref_khz; | ||
212 | pll_n += pll_n % 2; | ||
213 | priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out; | ||
214 | |||
215 | if (pll_n < 4095) | ||
216 | u16tmp = pll_n - 1024; | ||
217 | else if (pll_n < 6143) | ||
218 | u16tmp = pll_n + 1024; | ||
219 | else | ||
220 | u16tmp = pll_n + 3072; | ||
221 | |||
222 | buf[0] = (u16tmp >> 8) & 0x3f; | ||
223 | buf[1] = (u16tmp >> 0) & 0xff; | ||
224 | buf[2] = div_ref - 8; | ||
225 | ret = m88ts2022_wr_regs(priv, 0x01, buf, 3); | ||
226 | if (ret) | ||
227 | goto err; | ||
228 | |||
229 | dev_dbg(&priv->client->dev, | ||
230 | "%s: frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", | ||
231 | __func__, priv->frequency_khz, | ||
232 | priv->frequency_khz - c->frequency, f_vco_khz, pll_n, | ||
233 | div_ref, div_out); | ||
234 | |||
235 | ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); | ||
236 | if (ret) | ||
237 | goto err; | ||
238 | |||
239 | ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp); | ||
240 | if (ret) | ||
241 | goto err; | ||
242 | |||
243 | u8tmp &= 0x7f; | ||
244 | if (u8tmp < 64) { | ||
245 | ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80); | ||
246 | if (ret) | ||
247 | goto err; | ||
248 | |||
249 | ret = m88ts2022_wr_reg(priv, 0x11, 0x6f); | ||
250 | if (ret) | ||
251 | goto err; | ||
252 | |||
253 | ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); | ||
254 | if (ret) | ||
255 | goto err; | ||
256 | } | ||
257 | |||
258 | ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp); | ||
259 | if (ret) | ||
260 | goto err; | ||
261 | |||
262 | u8tmp &= 0x1f; | ||
263 | if (u8tmp > 19) { | ||
264 | ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02); | ||
265 | if (ret) | ||
266 | goto err; | ||
267 | } | ||
268 | |||
269 | ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL); | ||
270 | if (ret) | ||
271 | goto err; | ||
272 | |||
273 | ret = m88ts2022_wr_reg(priv, 0x25, 0x00); | ||
274 | if (ret) | ||
275 | goto err; | ||
276 | |||
277 | ret = m88ts2022_wr_reg(priv, 0x27, 0x70); | ||
278 | if (ret) | ||
279 | goto err; | ||
280 | |||
281 | ret = m88ts2022_wr_reg(priv, 0x41, 0x09); | ||
282 | if (ret) | ||
283 | goto err; | ||
284 | |||
285 | ret = m88ts2022_wr_reg(priv, 0x08, 0x0b); | ||
286 | if (ret) | ||
287 | goto err; | ||
288 | |||
289 | /* filters */ | ||
290 | gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U); | ||
291 | |||
292 | ret = m88ts2022_wr_reg(priv, 0x04, gdiv28); | ||
293 | if (ret) | ||
294 | goto err; | ||
295 | |||
296 | ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); | ||
297 | if (ret) | ||
298 | goto err; | ||
299 | |||
300 | cap_code = u8tmp & 0x3f; | ||
301 | |||
302 | ret = m88ts2022_wr_reg(priv, 0x41, 0x0d); | ||
303 | if (ret) | ||
304 | goto err; | ||
305 | |||
306 | ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); | ||
307 | if (ret) | ||
308 | goto err; | ||
309 | |||
310 | u8tmp &= 0x3f; | ||
311 | cap_code = (cap_code + u8tmp) / 2; | ||
312 | gdiv28 = gdiv28 * 207 / (cap_code * 2 + 151); | ||
313 | div_max = gdiv28 * 135 / 100; | ||
314 | div_min = gdiv28 * 78 / 100; | ||
315 | div_max = clamp_val(div_max, 0U, 63U); | ||
316 | |||
317 | f_3db_hz = c->symbol_rate * 135UL / 200UL; | ||
318 | f_3db_hz += 2000000U + (frequency_offset_khz * 1000U); | ||
319 | f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U); | ||
320 | |||
321 | #define LPF_COEFF 3200U | ||
322 | lpf_gm = DIV_ROUND_CLOSEST(f_3db_hz * gdiv28, LPF_COEFF * f_ref_khz); | ||
323 | lpf_gm = clamp_val(lpf_gm, 1U, 23U); | ||
324 | |||
325 | lpf_mxdiv = DIV_ROUND_CLOSEST(lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz); | ||
326 | if (lpf_mxdiv < div_min) | ||
327 | lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz); | ||
328 | lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max); | ||
329 | |||
330 | ret = m88ts2022_wr_reg(priv, 0x04, lpf_mxdiv); | ||
331 | if (ret) | ||
332 | goto err; | ||
333 | |||
334 | ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm); | ||
335 | if (ret) | ||
336 | goto err; | ||
337 | |||
338 | ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); | ||
339 | if (ret) | ||
340 | goto err; | ||
341 | |||
342 | cap_code = u8tmp & 0x3f; | ||
343 | |||
344 | ret = m88ts2022_wr_reg(priv, 0x41, 0x09); | ||
345 | if (ret) | ||
346 | goto err; | ||
347 | |||
348 | ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); | ||
349 | if (ret) | ||
350 | goto err; | ||
351 | |||
352 | u8tmp &= 0x3f; | ||
353 | cap_code = (cap_code + u8tmp) / 2; | ||
354 | |||
355 | u8tmp = cap_code | 0x80; | ||
356 | ret = m88ts2022_wr_reg(priv, 0x25, u8tmp); | ||
357 | if (ret) | ||
358 | goto err; | ||
359 | |||
360 | ret = m88ts2022_wr_reg(priv, 0x27, 0x30); | ||
361 | if (ret) | ||
362 | goto err; | ||
363 | |||
364 | ret = m88ts2022_wr_reg(priv, 0x08, 0x09); | ||
365 | if (ret) | ||
366 | goto err; | ||
367 | |||
368 | ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL); | ||
369 | if (ret) | ||
370 | goto err; | ||
371 | err: | ||
372 | if (ret) | ||
373 | dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); | ||
374 | |||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | static int m88ts2022_init(struct dvb_frontend *fe) | ||
379 | { | ||
380 | struct m88ts2022_priv *priv = fe->tuner_priv; | ||
381 | int ret, i; | ||
382 | u8 u8tmp; | ||
383 | static const struct m88ts2022_reg_val reg_vals[] = { | ||
384 | {0x7d, 0x9d}, | ||
385 | {0x7c, 0x9a}, | ||
386 | {0x7a, 0x76}, | ||
387 | {0x3b, 0x01}, | ||
388 | {0x63, 0x88}, | ||
389 | {0x61, 0x85}, | ||
390 | {0x22, 0x30}, | ||
391 | {0x30, 0x40}, | ||
392 | {0x20, 0x23}, | ||
393 | {0x24, 0x02}, | ||
394 | {0x12, 0xa0}, | ||
395 | }; | ||
396 | dev_dbg(&priv->client->dev, "%s:\n", __func__); | ||
397 | |||
398 | ret = m88ts2022_wr_reg(priv, 0x00, 0x01); | ||
399 | if (ret) | ||
400 | goto err; | ||
401 | |||
402 | ret = m88ts2022_wr_reg(priv, 0x00, 0x03); | ||
403 | if (ret) | ||
404 | goto err; | ||
405 | |||
406 | switch (priv->cfg.clock_out) { | ||
407 | case M88TS2022_CLOCK_OUT_DISABLED: | ||
408 | u8tmp = 0x60; | ||
409 | break; | ||
410 | case M88TS2022_CLOCK_OUT_ENABLED: | ||
411 | u8tmp = 0x70; | ||
412 | ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div); | ||
413 | if (ret) | ||
414 | goto err; | ||
415 | break; | ||
416 | case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT: | ||
417 | u8tmp = 0x6c; | ||
418 | break; | ||
419 | default: | ||
420 | goto err; | ||
421 | } | ||
422 | |||
423 | ret = m88ts2022_wr_reg(priv, 0x42, u8tmp); | ||
424 | if (ret) | ||
425 | goto err; | ||
426 | |||
427 | if (priv->cfg.loop_through) | ||
428 | u8tmp = 0xec; | ||
429 | else | ||
430 | u8tmp = 0x6c; | ||
431 | |||
432 | ret = m88ts2022_wr_reg(priv, 0x62, u8tmp); | ||
433 | if (ret) | ||
434 | goto err; | ||
435 | |||
436 | for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { | ||
437 | ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, reg_vals[i].val); | ||
438 | if (ret) | ||
439 | goto err; | ||
440 | } | ||
441 | err: | ||
442 | if (ret) | ||
443 | dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | static int m88ts2022_sleep(struct dvb_frontend *fe) | ||
448 | { | ||
449 | struct m88ts2022_priv *priv = fe->tuner_priv; | ||
450 | int ret; | ||
451 | dev_dbg(&priv->client->dev, "%s:\n", __func__); | ||
452 | |||
453 | ret = m88ts2022_wr_reg(priv, 0x00, 0x00); | ||
454 | if (ret) | ||
455 | goto err; | ||
456 | err: | ||
457 | if (ret) | ||
458 | dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
463 | { | ||
464 | struct m88ts2022_priv *priv = fe->tuner_priv; | ||
465 | dev_dbg(&priv->client->dev, "%s:\n", __func__); | ||
466 | |||
467 | *frequency = priv->frequency_khz; | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
472 | { | ||
473 | struct m88ts2022_priv *priv = fe->tuner_priv; | ||
474 | dev_dbg(&priv->client->dev, "%s:\n", __func__); | ||
475 | |||
476 | *frequency = 0; /* Zero-IF */ | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
481 | { | ||
482 | struct m88ts2022_priv *priv = fe->tuner_priv; | ||
483 | int ret; | ||
484 | u8 u8tmp; | ||
485 | u16 gain, u16tmp; | ||
486 | unsigned int gain1, gain2, gain3; | ||
487 | |||
488 | ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp); | ||
489 | if (ret) | ||
490 | goto err; | ||
491 | |||
492 | gain1 = (u8tmp >> 0) & 0x1f; | ||
493 | gain1 = clamp(gain1, 0U, 15U); | ||
494 | |||
495 | ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp); | ||
496 | if (ret) | ||
497 | goto err; | ||
498 | |||
499 | gain2 = (u8tmp >> 0) & 0x1f; | ||
500 | gain2 = clamp(gain2, 2U, 16U); | ||
501 | |||
502 | ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp); | ||
503 | if (ret) | ||
504 | goto err; | ||
505 | |||
506 | gain3 = (u8tmp >> 3) & 0x07; | ||
507 | gain3 = clamp(gain3, 0U, 6U); | ||
508 | |||
509 | gain = gain1 * 265 + gain2 * 338 + gain3 * 285; | ||
510 | |||
511 | /* scale value to 0x0000-0xffff */ | ||
512 | u16tmp = (0xffff - gain); | ||
513 | u16tmp = clamp_val(u16tmp, 59000U, 61500U); | ||
514 | |||
515 | *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000); | ||
516 | err: | ||
517 | if (ret) | ||
518 | dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); | ||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | static const struct dvb_tuner_ops m88ts2022_tuner_ops = { | ||
523 | .info = { | ||
524 | .name = "Montage M88TS2022", | ||
525 | .frequency_min = 950000, | ||
526 | .frequency_max = 2150000, | ||
527 | }, | ||
528 | |||
529 | .init = m88ts2022_init, | ||
530 | .sleep = m88ts2022_sleep, | ||
531 | .set_params = m88ts2022_set_params, | ||
532 | |||
533 | .get_frequency = m88ts2022_get_frequency, | ||
534 | .get_if_frequency = m88ts2022_get_if_frequency, | ||
535 | .get_rf_strength = m88ts2022_get_rf_strength, | ||
536 | }; | ||
537 | |||
538 | static int m88ts2022_probe(struct i2c_client *client, | ||
539 | const struct i2c_device_id *id) | ||
540 | { | ||
541 | struct m88ts2022_config *cfg = client->dev.platform_data; | ||
542 | struct dvb_frontend *fe = cfg->fe; | ||
543 | struct m88ts2022_priv *priv; | ||
544 | int ret; | ||
545 | u8 chip_id, u8tmp; | ||
546 | |||
547 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
548 | if (!priv) { | ||
549 | ret = -ENOMEM; | ||
550 | dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); | ||
551 | goto err; | ||
552 | } | ||
553 | |||
554 | memcpy(&priv->cfg, cfg, sizeof(struct m88ts2022_config)); | ||
555 | priv->client = client; | ||
556 | |||
557 | /* check if the tuner is there */ | ||
558 | ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp); | ||
559 | if (ret) | ||
560 | goto err; | ||
561 | |||
562 | if ((u8tmp & 0x03) == 0x00) { | ||
563 | ret = m88ts2022_wr_reg(priv, 0x00, 0x01); | ||
564 | if (ret < 0) | ||
565 | goto err; | ||
566 | |||
567 | usleep_range(2000, 50000); | ||
568 | } | ||
569 | |||
570 | ret = m88ts2022_wr_reg(priv, 0x00, 0x03); | ||
571 | if (ret) | ||
572 | goto err; | ||
573 | |||
574 | usleep_range(2000, 50000); | ||
575 | |||
576 | ret = m88ts2022_rd_reg(priv, 0x00, &chip_id); | ||
577 | if (ret) | ||
578 | goto err; | ||
579 | |||
580 | dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id); | ||
581 | |||
582 | switch (chip_id) { | ||
583 | case 0xc3: | ||
584 | case 0x83: | ||
585 | break; | ||
586 | default: | ||
587 | goto err; | ||
588 | } | ||
589 | |||
590 | switch (priv->cfg.clock_out) { | ||
591 | case M88TS2022_CLOCK_OUT_DISABLED: | ||
592 | u8tmp = 0x60; | ||
593 | break; | ||
594 | case M88TS2022_CLOCK_OUT_ENABLED: | ||
595 | u8tmp = 0x70; | ||
596 | ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div); | ||
597 | if (ret) | ||
598 | goto err; | ||
599 | break; | ||
600 | case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT: | ||
601 | u8tmp = 0x6c; | ||
602 | break; | ||
603 | default: | ||
604 | goto err; | ||
605 | } | ||
606 | |||
607 | ret = m88ts2022_wr_reg(priv, 0x42, u8tmp); | ||
608 | if (ret) | ||
609 | goto err; | ||
610 | |||
611 | if (priv->cfg.loop_through) | ||
612 | u8tmp = 0xec; | ||
613 | else | ||
614 | u8tmp = 0x6c; | ||
615 | |||
616 | ret = m88ts2022_wr_reg(priv, 0x62, u8tmp); | ||
617 | if (ret) | ||
618 | goto err; | ||
619 | |||
620 | /* sleep */ | ||
621 | ret = m88ts2022_wr_reg(priv, 0x00, 0x00); | ||
622 | if (ret) | ||
623 | goto err; | ||
624 | |||
625 | dev_info(&priv->client->dev, | ||
626 | "%s: Montage M88TS2022 successfully identified\n", | ||
627 | KBUILD_MODNAME); | ||
628 | |||
629 | fe->tuner_priv = priv; | ||
630 | memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops, | ||
631 | sizeof(struct dvb_tuner_ops)); | ||
632 | |||
633 | i2c_set_clientdata(client, priv); | ||
634 | return 0; | ||
635 | err: | ||
636 | dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); | ||
637 | kfree(priv); | ||
638 | return ret; | ||
639 | } | ||
640 | |||
641 | static int m88ts2022_remove(struct i2c_client *client) | ||
642 | { | ||
643 | struct m88ts2022_priv *priv = i2c_get_clientdata(client); | ||
644 | struct dvb_frontend *fe = priv->cfg.fe; | ||
645 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
646 | |||
647 | memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); | ||
648 | fe->tuner_priv = NULL; | ||
649 | kfree(priv); | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static const struct i2c_device_id m88ts2022_id[] = { | ||
655 | {"m88ts2022", 0}, | ||
656 | {} | ||
657 | }; | ||
658 | MODULE_DEVICE_TABLE(i2c, m88ts2022_id); | ||
659 | |||
660 | static struct i2c_driver m88ts2022_driver = { | ||
661 | .driver = { | ||
662 | .owner = THIS_MODULE, | ||
663 | .name = "m88ts2022", | ||
664 | }, | ||
665 | .probe = m88ts2022_probe, | ||
666 | .remove = m88ts2022_remove, | ||
667 | .id_table = m88ts2022_id, | ||
668 | }; | ||
669 | |||
670 | module_i2c_driver(m88ts2022_driver); | ||
671 | |||
672 | MODULE_DESCRIPTION("Montage M88TS2022 silicon tuner driver"); | ||
673 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
674 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/m88ts2022.h b/drivers/media/tuners/m88ts2022.h new file mode 100644 index 000000000000..659fa1b1633a --- /dev/null +++ b/drivers/media/tuners/m88ts2022.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Montage M88TS2022 silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef M88TS2022_H | ||
18 | #define M88TS2022_H | ||
19 | |||
20 | #include "dvb_frontend.h" | ||
21 | |||
22 | struct m88ts2022_config { | ||
23 | /* | ||
24 | * clock | ||
25 | * 16000000 - 32000000 | ||
26 | */ | ||
27 | u32 clock; | ||
28 | |||
29 | /* | ||
30 | * RF loop-through | ||
31 | */ | ||
32 | u8 loop_through:1; | ||
33 | |||
34 | /* | ||
35 | * clock output | ||
36 | */ | ||
37 | #define M88TS2022_CLOCK_OUT_DISABLED 0 | ||
38 | #define M88TS2022_CLOCK_OUT_ENABLED 1 | ||
39 | #define M88TS2022_CLOCK_OUT_ENABLED_XTALOUT 2 | ||
40 | u8 clock_out:2; | ||
41 | |||
42 | /* | ||
43 | * clock output divider | ||
44 | * 1 - 31 | ||
45 | */ | ||
46 | u8 clock_out_div:5; | ||
47 | |||
48 | /* | ||
49 | * pointer to DVB frontend | ||
50 | */ | ||
51 | struct dvb_frontend *fe; | ||
52 | }; | ||
53 | |||
54 | #endif | ||
diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h new file mode 100644 index 000000000000..0363dd866a2d --- /dev/null +++ b/drivers/media/tuners/m88ts2022_priv.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Montage M88TS2022 silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef M88TS2022_PRIV_H | ||
18 | #define M88TS2022_PRIV_H | ||
19 | |||
20 | #include "m88ts2022.h" | ||
21 | |||
22 | struct m88ts2022_priv { | ||
23 | struct m88ts2022_config cfg; | ||
24 | struct i2c_client *client; | ||
25 | struct dvb_frontend *fe; | ||
26 | u32 frequency_khz; | ||
27 | }; | ||
28 | |||
29 | struct m88ts2022_reg_val { | ||
30 | u8 reg; | ||
31 | u8 val; | ||
32 | }; | ||
33 | |||
34 | #endif | ||
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 4be5cf808a40..cca508d4aafb 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c | |||
@@ -134,15 +134,6 @@ struct xc2028_data { | |||
134 | _rc; \ | 134 | _rc; \ |
135 | }) | 135 | }) |
136 | 136 | ||
137 | #define i2c_rcv(priv, buf, size) ({ \ | ||
138 | int _rc; \ | ||
139 | _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ | ||
140 | if (size != _rc) \ | ||
141 | tuner_err("i2c input error: rc = %d (should be %d)\n", \ | ||
142 | _rc, (int)size); \ | ||
143 | _rc; \ | ||
144 | }) | ||
145 | |||
146 | #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ | 137 | #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ |
147 | int _rc; \ | 138 | int _rc; \ |
148 | _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ | 139 | _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ |
@@ -276,6 +267,7 @@ static int check_device_status(struct xc2028_data *priv) | |||
276 | case XC2028_WAITING_FIRMWARE: | 267 | case XC2028_WAITING_FIRMWARE: |
277 | return -EAGAIN; | 268 | return -EAGAIN; |
278 | case XC2028_ACTIVE: | 269 | case XC2028_ACTIVE: |
270 | return 1; | ||
279 | case XC2028_SLEEP: | 271 | case XC2028_SLEEP: |
280 | return 0; | 272 | return 0; |
281 | case XC2028_NODEV: | 273 | case XC2028_NODEV: |
@@ -718,6 +710,8 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, | |||
718 | return 0; | 710 | return 0; |
719 | } | 711 | } |
720 | 712 | ||
713 | static int xc2028_sleep(struct dvb_frontend *fe); | ||
714 | |||
721 | static int check_firmware(struct dvb_frontend *fe, unsigned int type, | 715 | static int check_firmware(struct dvb_frontend *fe, unsigned int type, |
722 | v4l2_std_id std, __u16 int_freq) | 716 | v4l2_std_id std, __u16 int_freq) |
723 | { | 717 | { |
@@ -890,7 +884,7 @@ read_not_reliable: | |||
890 | return 0; | 884 | return 0; |
891 | 885 | ||
892 | fail: | 886 | fail: |
893 | priv->state = XC2028_SLEEP; | 887 | priv->state = XC2028_NO_FIRMWARE; |
894 | 888 | ||
895 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | 889 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); |
896 | if (retry_count < 8) { | 890 | if (retry_count < 8) { |
@@ -900,6 +894,9 @@ fail: | |||
900 | goto retry; | 894 | goto retry; |
901 | } | 895 | } |
902 | 896 | ||
897 | /* Firmware didn't load. Put the device to sleep */ | ||
898 | xc2028_sleep(fe); | ||
899 | |||
903 | if (rc == -ENOENT) | 900 | if (rc == -ENOENT) |
904 | rc = -EINVAL; | 901 | rc = -EINVAL; |
905 | return rc; | 902 | return rc; |
@@ -917,6 +914,12 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) | |||
917 | if (rc < 0) | 914 | if (rc < 0) |
918 | return rc; | 915 | return rc; |
919 | 916 | ||
917 | /* If the device is sleeping, no channel is tuned */ | ||
918 | if (!rc) { | ||
919 | *strength = 0; | ||
920 | return 0; | ||
921 | } | ||
922 | |||
920 | mutex_lock(&priv->lock); | 923 | mutex_lock(&priv->lock); |
921 | 924 | ||
922 | /* Sync Lock Indicator */ | 925 | /* Sync Lock Indicator */ |
@@ -964,6 +967,12 @@ static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc) | |||
964 | if (rc < 0) | 967 | if (rc < 0) |
965 | return rc; | 968 | return rc; |
966 | 969 | ||
970 | /* If the device is sleeping, no channel is tuned */ | ||
971 | if (!rc) { | ||
972 | *afc = 0; | ||
973 | return 0; | ||
974 | } | ||
975 | |||
967 | mutex_lock(&priv->lock); | 976 | mutex_lock(&priv->lock); |
968 | 977 | ||
969 | /* Sync Lock Indicator */ | 978 | /* Sync Lock Indicator */ |
@@ -1281,6 +1290,10 @@ static int xc2028_sleep(struct dvb_frontend *fe) | |||
1281 | if (rc < 0) | 1290 | if (rc < 0) |
1282 | return rc; | 1291 | return rc; |
1283 | 1292 | ||
1293 | /* Device is already in sleep mode */ | ||
1294 | if (!rc) | ||
1295 | return 0; | ||
1296 | |||
1284 | /* Avoid firmware reload on slow devices or if PM disabled */ | 1297 | /* Avoid firmware reload on slow devices or if PM disabled */ |
1285 | if (no_poweroff || priv->ctrl.disable_power_mgmt) | 1298 | if (no_poweroff || priv->ctrl.disable_power_mgmt) |
1286 | return 0; | 1299 | return 0; |
@@ -1298,7 +1311,8 @@ static int xc2028_sleep(struct dvb_frontend *fe) | |||
1298 | else | 1311 | else |
1299 | rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); | 1312 | rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); |
1300 | 1313 | ||
1301 | priv->state = XC2028_SLEEP; | 1314 | if (rc >= 0) |
1315 | priv->state = XC2028_SLEEP; | ||
1302 | 1316 | ||
1303 | mutex_unlock(&priv->lock); | 1317 | mutex_unlock(&priv->lock); |
1304 | 1318 | ||
@@ -1366,7 +1380,7 @@ static void load_firmware_cb(const struct firmware *fw, | |||
1366 | 1380 | ||
1367 | if (rc < 0) | 1381 | if (rc < 0) |
1368 | return; | 1382 | return; |
1369 | priv->state = XC2028_SLEEP; | 1383 | priv->state = XC2028_ACTIVE; |
1370 | } | 1384 | } |
1371 | 1385 | ||
1372 | static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) | 1386 | static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) |
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index cfe8056b91aa..39d824e2bb69 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig | |||
@@ -17,7 +17,6 @@ source "drivers/media/usb/cpia2/Kconfig" | |||
17 | source "drivers/media/usb/zr364xx/Kconfig" | 17 | source "drivers/media/usb/zr364xx/Kconfig" |
18 | source "drivers/media/usb/stkwebcam/Kconfig" | 18 | source "drivers/media/usb/stkwebcam/Kconfig" |
19 | source "drivers/media/usb/s2255/Kconfig" | 19 | source "drivers/media/usb/s2255/Kconfig" |
20 | source "drivers/media/usb/sn9c102/Kconfig" | ||
21 | source "drivers/media/usb/usbtv/Kconfig" | 20 | source "drivers/media/usb/usbtv/Kconfig" |
22 | endif | 21 | endif |
23 | 22 | ||
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index 0935f47497a6..7ac4b143dce8 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile | |||
@@ -10,7 +10,6 @@ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ | |||
10 | obj-$(CONFIG_USB_GSPCA) += gspca/ | 10 | obj-$(CONFIG_USB_GSPCA) += gspca/ |
11 | obj-$(CONFIG_USB_PWC) += pwc/ | 11 | obj-$(CONFIG_USB_PWC) += pwc/ |
12 | obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ | 12 | obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ |
13 | obj-$(CONFIG_USB_SN9C102) += sn9c102/ | ||
14 | obj-$(CONFIG_VIDEO_AU0828) += au0828/ | 13 | obj-$(CONFIG_VIDEO_AU0828) += au0828/ |
15 | obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ | 14 | obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ |
16 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ | 15 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ |
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index bd9d19a73efd..ab45a6f9dcc9 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c | |||
@@ -173,9 +173,8 @@ static int au0828_usb_probe(struct usb_interface *interface, | |||
173 | const struct usb_device_id *id) | 173 | const struct usb_device_id *id) |
174 | { | 174 | { |
175 | int ifnum; | 175 | int ifnum; |
176 | #ifdef CONFIG_VIDEO_AU0828_V4L2 | 176 | int retval = 0; |
177 | int retval; | 177 | |
178 | #endif | ||
179 | struct au0828_dev *dev; | 178 | struct au0828_dev *dev; |
180 | struct usb_device *usbdev = interface_to_usbdev(interface); | 179 | struct usb_device *usbdev = interface_to_usbdev(interface); |
181 | 180 | ||
@@ -257,7 +256,11 @@ static int au0828_usb_probe(struct usb_interface *interface, | |||
257 | #endif | 256 | #endif |
258 | 257 | ||
259 | /* Digital TV */ | 258 | /* Digital TV */ |
260 | au0828_dvb_register(dev); | 259 | retval = au0828_dvb_register(dev); |
260 | if (retval) | ||
261 | pr_err("%s() au0282_dev_register failed\n", | ||
262 | __func__); | ||
263 | |||
261 | 264 | ||
262 | /* Store the pointer to the au0828_dev so it can be accessed in | 265 | /* Store the pointer to the au0828_dev so it can be accessed in |
263 | au0828_usb_disconnect */ | 266 | au0828_usb_disconnect */ |
@@ -268,7 +271,7 @@ static int au0828_usb_probe(struct usb_interface *interface, | |||
268 | 271 | ||
269 | mutex_unlock(&dev->lock); | 272 | mutex_unlock(&dev->lock); |
270 | 273 | ||
271 | return 0; | 274 | return retval; |
272 | } | 275 | } |
273 | 276 | ||
274 | static struct usb_driver au0828_usb_driver = { | 277 | static struct usb_driver au0828_usb_driver = { |
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 9a6f15613a38..4ae8b1074649 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c | |||
@@ -33,6 +33,10 @@ | |||
33 | #include "mxl5007t.h" | 33 | #include "mxl5007t.h" |
34 | #include "tda18271.h" | 34 | #include "tda18271.h" |
35 | 35 | ||
36 | static int preallocate_big_buffers; | ||
37 | module_param_named(preallocate_big_buffers, preallocate_big_buffers, int, 0644); | ||
38 | MODULE_PARM_DESC(preallocate_big_buffers, "Preallocate the larger transfer buffers at module load time"); | ||
39 | |||
36 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 40 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
37 | 41 | ||
38 | #define _AU0828_BULKPIPE 0x83 | 42 | #define _AU0828_BULKPIPE 0x83 |
@@ -153,9 +157,13 @@ static int stop_urb_transfer(struct au0828_dev *dev) | |||
153 | 157 | ||
154 | dev->urb_streaming = 0; | 158 | dev->urb_streaming = 0; |
155 | for (i = 0; i < URB_COUNT; i++) { | 159 | for (i = 0; i < URB_COUNT; i++) { |
156 | usb_kill_urb(dev->urbs[i]); | 160 | if (dev->urbs[i]) { |
157 | kfree(dev->urbs[i]->transfer_buffer); | 161 | usb_kill_urb(dev->urbs[i]); |
158 | usb_free_urb(dev->urbs[i]); | 162 | if (!preallocate_big_buffers) |
163 | kfree(dev->urbs[i]->transfer_buffer); | ||
164 | |||
165 | usb_free_urb(dev->urbs[i]); | ||
166 | } | ||
159 | } | 167 | } |
160 | 168 | ||
161 | return 0; | 169 | return 0; |
@@ -181,10 +189,18 @@ static int start_urb_transfer(struct au0828_dev *dev) | |||
181 | 189 | ||
182 | purb = dev->urbs[i]; | 190 | purb = dev->urbs[i]; |
183 | 191 | ||
184 | purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); | 192 | if (preallocate_big_buffers) |
193 | purb->transfer_buffer = dev->dig_transfer_buffer[i]; | ||
194 | else | ||
195 | purb->transfer_buffer = kzalloc(URB_BUFSIZE, | ||
196 | GFP_KERNEL); | ||
197 | |||
185 | if (!purb->transfer_buffer) { | 198 | if (!purb->transfer_buffer) { |
186 | usb_free_urb(purb); | 199 | usb_free_urb(purb); |
187 | dev->urbs[i] = NULL; | 200 | dev->urbs[i] = NULL; |
201 | printk(KERN_ERR | ||
202 | "%s: failed big buffer allocation, err = %d\n", | ||
203 | __func__, ret); | ||
188 | goto err; | 204 | goto err; |
189 | } | 205 | } |
190 | 206 | ||
@@ -217,6 +233,27 @@ err: | |||
217 | return ret; | 233 | return ret; |
218 | } | 234 | } |
219 | 235 | ||
236 | static void au0828_start_transport(struct au0828_dev *dev) | ||
237 | { | ||
238 | au0828_write(dev, 0x608, 0x90); | ||
239 | au0828_write(dev, 0x609, 0x72); | ||
240 | au0828_write(dev, 0x60a, 0x71); | ||
241 | au0828_write(dev, 0x60b, 0x01); | ||
242 | |||
243 | } | ||
244 | |||
245 | static void au0828_stop_transport(struct au0828_dev *dev, int full_stop) | ||
246 | { | ||
247 | if (full_stop) { | ||
248 | au0828_write(dev, 0x608, 0x00); | ||
249 | au0828_write(dev, 0x609, 0x00); | ||
250 | au0828_write(dev, 0x60a, 0x00); | ||
251 | } | ||
252 | au0828_write(dev, 0x60b, 0x00); | ||
253 | } | ||
254 | |||
255 | |||
256 | |||
220 | static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) | 257 | static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) |
221 | { | 258 | { |
222 | struct dvb_demux *demux = feed->demux; | 259 | struct dvb_demux *demux = feed->demux; |
@@ -231,13 +268,17 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) | |||
231 | 268 | ||
232 | if (dvb) { | 269 | if (dvb) { |
233 | mutex_lock(&dvb->lock); | 270 | mutex_lock(&dvb->lock); |
271 | dvb->start_count++; | ||
272 | dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__, | ||
273 | dvb->start_count, dvb->stop_count); | ||
234 | if (dvb->feeding++ == 0) { | 274 | if (dvb->feeding++ == 0) { |
235 | /* Start transport */ | 275 | /* Start transport */ |
236 | au0828_write(dev, 0x608, 0x90); | 276 | au0828_start_transport(dev); |
237 | au0828_write(dev, 0x609, 0x72); | ||
238 | au0828_write(dev, 0x60a, 0x71); | ||
239 | au0828_write(dev, 0x60b, 0x01); | ||
240 | ret = start_urb_transfer(dev); | 277 | ret = start_urb_transfer(dev); |
278 | if (ret < 0) { | ||
279 | au0828_stop_transport(dev, 0); | ||
280 | dvb->feeding--; /* We ran out of memory... */ | ||
281 | } | ||
241 | } | 282 | } |
242 | mutex_unlock(&dvb->lock); | 283 | mutex_unlock(&dvb->lock); |
243 | } | 284 | } |
@@ -256,10 +297,16 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) | |||
256 | 297 | ||
257 | if (dvb) { | 298 | if (dvb) { |
258 | mutex_lock(&dvb->lock); | 299 | mutex_lock(&dvb->lock); |
259 | if (--dvb->feeding == 0) { | 300 | dvb->stop_count++; |
260 | /* Stop transport */ | 301 | dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__, |
261 | ret = stop_urb_transfer(dev); | 302 | dvb->start_count, dvb->stop_count); |
262 | au0828_write(dev, 0x60b, 0x00); | 303 | if (dvb->feeding > 0) { |
304 | dvb->feeding--; | ||
305 | if (dvb->feeding == 0) { | ||
306 | /* Stop transport */ | ||
307 | ret = stop_urb_transfer(dev); | ||
308 | au0828_stop_transport(dev, 0); | ||
309 | } | ||
263 | } | 310 | } |
264 | mutex_unlock(&dvb->lock); | 311 | mutex_unlock(&dvb->lock); |
265 | } | 312 | } |
@@ -282,16 +329,10 @@ static void au0828_restart_dvb_streaming(struct work_struct *work) | |||
282 | 329 | ||
283 | /* Stop transport */ | 330 | /* Stop transport */ |
284 | stop_urb_transfer(dev); | 331 | stop_urb_transfer(dev); |
285 | au0828_write(dev, 0x608, 0x00); | 332 | au0828_stop_transport(dev, 1); |
286 | au0828_write(dev, 0x609, 0x00); | ||
287 | au0828_write(dev, 0x60a, 0x00); | ||
288 | au0828_write(dev, 0x60b, 0x00); | ||
289 | 333 | ||
290 | /* Start transport */ | 334 | /* Start transport */ |
291 | au0828_write(dev, 0x608, 0x90); | 335 | au0828_start_transport(dev); |
292 | au0828_write(dev, 0x609, 0x72); | ||
293 | au0828_write(dev, 0x60a, 0x71); | ||
294 | au0828_write(dev, 0x60b, 0x01); | ||
295 | start_urb_transfer(dev); | 336 | start_urb_transfer(dev); |
296 | 337 | ||
297 | mutex_unlock(&dvb->lock); | 338 | mutex_unlock(&dvb->lock); |
@@ -304,6 +345,23 @@ static int dvb_register(struct au0828_dev *dev) | |||
304 | 345 | ||
305 | dprintk(1, "%s()\n", __func__); | 346 | dprintk(1, "%s()\n", __func__); |
306 | 347 | ||
348 | if (preallocate_big_buffers) { | ||
349 | int i; | ||
350 | for (i = 0; i < URB_COUNT; i++) { | ||
351 | dev->dig_transfer_buffer[i] = kzalloc(URB_BUFSIZE, | ||
352 | GFP_KERNEL); | ||
353 | |||
354 | if (!dev->dig_transfer_buffer[i]) { | ||
355 | result = -ENOMEM; | ||
356 | |||
357 | printk(KERN_ERR | ||
358 | "%s: failed buffer allocation (errno = %d)\n", | ||
359 | DRIVER_NAME, result); | ||
360 | goto fail_adapter; | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
307 | INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming); | 365 | INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming); |
308 | 366 | ||
309 | /* register adapter */ | 367 | /* register adapter */ |
@@ -375,6 +433,9 @@ static int dvb_register(struct au0828_dev *dev) | |||
375 | 433 | ||
376 | /* register network adapter */ | 434 | /* register network adapter */ |
377 | dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); | 435 | dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); |
436 | |||
437 | dvb->start_count = 0; | ||
438 | dvb->stop_count = 0; | ||
378 | return 0; | 439 | return 0; |
379 | 440 | ||
380 | fail_fe_conn: | 441 | fail_fe_conn: |
@@ -391,6 +452,13 @@ fail_frontend: | |||
391 | dvb_frontend_detach(dvb->frontend); | 452 | dvb_frontend_detach(dvb->frontend); |
392 | dvb_unregister_adapter(&dvb->adapter); | 453 | dvb_unregister_adapter(&dvb->adapter); |
393 | fail_adapter: | 454 | fail_adapter: |
455 | |||
456 | if (preallocate_big_buffers) { | ||
457 | int i; | ||
458 | for (i = 0; i < URB_COUNT; i++) | ||
459 | kfree(dev->dig_transfer_buffer[i]); | ||
460 | } | ||
461 | |||
394 | return result; | 462 | return result; |
395 | } | 463 | } |
396 | 464 | ||
@@ -411,6 +479,14 @@ void au0828_dvb_unregister(struct au0828_dev *dev) | |||
411 | dvb_unregister_frontend(dvb->frontend); | 479 | dvb_unregister_frontend(dvb->frontend); |
412 | dvb_frontend_detach(dvb->frontend); | 480 | dvb_frontend_detach(dvb->frontend); |
413 | dvb_unregister_adapter(&dvb->adapter); | 481 | dvb_unregister_adapter(&dvb->adapter); |
482 | |||
483 | if (preallocate_big_buffers) { | ||
484 | int i; | ||
485 | for (i = 0; i < URB_COUNT; i++) | ||
486 | kfree(dev->dig_transfer_buffer[i]); | ||
487 | } | ||
488 | |||
489 | |||
414 | } | 490 | } |
415 | 491 | ||
416 | /* All the DVB attach calls go here, this function get's modified | 492 | /* All the DVB attach calls go here, this function get's modified |
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index ef1f57f22be7..5439772c1551 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h | |||
@@ -102,6 +102,8 @@ struct au0828_dvb { | |||
102 | struct dmx_frontend fe_mem; | 102 | struct dmx_frontend fe_mem; |
103 | struct dvb_net net; | 103 | struct dvb_net net; |
104 | int feeding; | 104 | int feeding; |
105 | int start_count; | ||
106 | int stop_count; | ||
105 | }; | 107 | }; |
106 | 108 | ||
107 | enum au0828_stream_state { | 109 | enum au0828_stream_state { |
@@ -260,6 +262,10 @@ struct au0828_dev { | |||
260 | /* USB / URB Related */ | 262 | /* USB / URB Related */ |
261 | int urb_streaming; | 263 | int urb_streaming; |
262 | struct urb *urbs[URB_COUNT]; | 264 | struct urb *urbs[URB_COUNT]; |
265 | |||
266 | /* Preallocated transfer digital transfer buffers */ | ||
267 | |||
268 | char *dig_transfer_buffer[URB_COUNT]; | ||
263 | }; | 269 | }; |
264 | 270 | ||
265 | /* ----------------------------------------------------------- */ | 271 | /* ----------------------------------------------------------- */ |
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 86feeeaf61c2..f14c5e89a567 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig | |||
@@ -45,6 +45,8 @@ config VIDEO_CX231XX_DVB | |||
45 | select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT | 45 | select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT |
46 | select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT | 46 | select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT |
47 | select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT | 47 | select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT |
48 | select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT | ||
49 | select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT | ||
48 | 50 | ||
49 | ---help--- | 51 | ---help--- |
50 | This adds support for DVB cards based on the | 52 | This adds support for DVB cards based on the |
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 528cce958a82..2ee03e4ddd86 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c | |||
@@ -709,6 +709,8 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); | |||
709 | 709 | ||
710 | /* table of devices that work with this driver */ | 710 | /* table of devices that work with this driver */ |
711 | struct usb_device_id cx231xx_id_table[] = { | 711 | struct usb_device_id cx231xx_id_table[] = { |
712 | {USB_DEVICE(0x1D19, 0x6109), | ||
713 | .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, | ||
712 | {USB_DEVICE(0x0572, 0x5A3C), | 714 | {USB_DEVICE(0x0572, 0x5A3C), |
713 | .driver_info = CX231XX_BOARD_UNKNOWN}, | 715 | .driver_info = CX231XX_BOARD_UNKNOWN}, |
714 | {USB_DEVICE(0x0572, 0x58A2), | 716 | {USB_DEVICE(0x0572, 0x58A2), |
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 96a5a0965399..7c0f797f1057 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c | |||
@@ -371,9 +371,9 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
371 | mutex_lock(&dev->i2c_lock); | 371 | mutex_lock(&dev->i2c_lock); |
372 | for (i = 0; i < num; i++) { | 372 | for (i = 0; i < num; i++) { |
373 | 373 | ||
374 | addr = msgs[i].addr >> 1; | 374 | addr = msgs[i].addr; |
375 | 375 | ||
376 | dprintk2(2, "%s %s addr=%x len=%d:", | 376 | dprintk2(2, "%s %s addr=0x%x len=%d:", |
377 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", | 377 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", |
378 | i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); | 378 | i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); |
379 | if (!msgs[i].len) { | 379 | if (!msgs[i].len) { |
@@ -390,32 +390,41 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
390 | rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]); | 390 | rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]); |
391 | if (i2c_debug >= 2) { | 391 | if (i2c_debug >= 2) { |
392 | for (byte = 0; byte < msgs[i].len; byte++) | 392 | for (byte = 0; byte < msgs[i].len; byte++) |
393 | printk(" %02x", msgs[i].buf[byte]); | 393 | printk(KERN_CONT " %02x", msgs[i].buf[byte]); |
394 | } | 394 | } |
395 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && | 395 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && |
396 | msgs[i].addr == msgs[i + 1].addr | 396 | msgs[i].addr == msgs[i + 1].addr |
397 | && (msgs[i].len <= 2) && (bus->nr < 3)) { | 397 | && (msgs[i].len <= 2) && (bus->nr < 3)) { |
398 | /* write bytes */ | ||
399 | if (i2c_debug >= 2) { | ||
400 | for (byte = 0; byte < msgs[i].len; byte++) | ||
401 | printk(KERN_CONT " %02x", msgs[i].buf[byte]); | ||
402 | printk(KERN_CONT "\n"); | ||
403 | } | ||
398 | /* read bytes */ | 404 | /* read bytes */ |
405 | dprintk2(2, "plus %s %s addr=0x%x len=%d:", | ||
406 | (msgs[i+1].flags & I2C_M_RD) ? "read" : "write", | ||
407 | i+1 == num - 1 ? "stop" : "nonstop", addr, msgs[i+1].len); | ||
399 | rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, | 408 | rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, |
400 | &msgs[i], | 409 | &msgs[i], |
401 | &msgs[i + 1]); | 410 | &msgs[i + 1]); |
402 | if (i2c_debug >= 2) { | 411 | if (i2c_debug >= 2) { |
403 | for (byte = 0; byte < msgs[i].len; byte++) | 412 | for (byte = 0; byte < msgs[i+1].len; byte++) |
404 | printk(" %02x", msgs[i].buf[byte]); | 413 | printk(KERN_CONT " %02x", msgs[i+1].buf[byte]); |
405 | } | 414 | } |
406 | i++; | 415 | i++; |
407 | } else { | 416 | } else { |
408 | /* write bytes */ | 417 | /* write bytes */ |
409 | if (i2c_debug >= 2) { | 418 | if (i2c_debug >= 2) { |
410 | for (byte = 0; byte < msgs[i].len; byte++) | 419 | for (byte = 0; byte < msgs[i].len; byte++) |
411 | printk(" %02x", msgs[i].buf[byte]); | 420 | printk(KERN_CONT " %02x", msgs[i].buf[byte]); |
412 | } | 421 | } |
413 | rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]); | 422 | rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]); |
414 | } | 423 | } |
415 | if (rc < 0) | 424 | if (rc < 0) |
416 | goto err; | 425 | goto err; |
417 | if (i2c_debug >= 2) | 426 | if (i2c_debug >= 2) |
418 | printk("\n"); | 427 | printk(KERN_CONT "\n"); |
419 | } | 428 | } |
420 | mutex_unlock(&dev->i2c_lock); | 429 | mutex_unlock(&dev->i2c_lock); |
421 | return num; | 430 | return num; |
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 90cfa35ef6e6..eeab79bdd2aa 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c | |||
@@ -442,6 +442,7 @@ static struct cxd2820r_config anysee_cxd2820r_config = { | |||
442 | * IOD[0] ZL10353 1=enabled | 442 | * IOD[0] ZL10353 1=enabled |
443 | * IOE[0] tuner 0=enabled | 443 | * IOE[0] tuner 0=enabled |
444 | * tuner is behind ZL10353 I2C-gate | 444 | * tuner is behind ZL10353 I2C-gate |
445 | * tuner is behind TDA10023 I2C-gate | ||
445 | * | 446 | * |
446 | * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" | 447 | * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" |
447 | * PCB: 508TC (rev0.6) | 448 | * PCB: 508TC (rev0.6) |
@@ -956,7 +957,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) | |||
956 | 957 | ||
957 | if (fe && adap->fe[1]) { | 958 | if (fe && adap->fe[1]) { |
958 | /* attach tuner for 2nd FE */ | 959 | /* attach tuner for 2nd FE */ |
959 | fe = dvb_attach(dvb_pll_attach, adap->fe[0], | 960 | fe = dvb_attach(dvb_pll_attach, adap->fe[1], |
960 | (0xc0 >> 1), &d->i2c_adap, | 961 | (0xc0 >> 1), &d->i2c_adap, |
961 | DVB_PLL_SAMSUNG_DTOS403IH102A); | 962 | DVB_PLL_SAMSUNG_DTOS403IH102A); |
962 | } | 963 | } |
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 44c64ef361bf..c1051c347744 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c | |||
@@ -68,6 +68,19 @@ static struct drxk_config terratec_h7_drxk = { | |||
68 | .microcode_name = "dvb-usb-terratec-h7-drxk.fw", | 68 | .microcode_name = "dvb-usb-terratec-h7-drxk.fw", |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static struct drxk_config cablestar_hdci_drxk = { | ||
72 | .adr = 0x29, | ||
73 | .parallel_ts = true, | ||
74 | .dynamic_clk = true, | ||
75 | .single_master = true, | ||
76 | .enable_merr_cfg = true, | ||
77 | .no_i2c_bridge = false, | ||
78 | .chunk_size = 64, | ||
79 | .mpeg_out_clk_strength = 0x02, | ||
80 | .qam_demod_parameter_count = 2, | ||
81 | .microcode_name = "dvb-usb-technisat-cablestar-hdci-drxk.fw", | ||
82 | }; | ||
83 | |||
71 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) | 84 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) |
72 | { | 85 | { |
73 | struct az6007_device_state *st = fe_to_priv(fe); | 86 | struct az6007_device_state *st = fe_to_priv(fe); |
@@ -630,6 +643,27 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap) | |||
630 | return 0; | 643 | return 0; |
631 | } | 644 | } |
632 | 645 | ||
646 | static int az6007_cablestar_hdci_frontend_attach(struct dvb_usb_adapter *adap) | ||
647 | { | ||
648 | struct az6007_device_state *st = adap_to_priv(adap); | ||
649 | struct dvb_usb_device *d = adap_to_d(adap); | ||
650 | |||
651 | pr_debug("attaching demod drxk\n"); | ||
652 | |||
653 | adap->fe[0] = dvb_attach(drxk_attach, &cablestar_hdci_drxk, | ||
654 | &d->i2c_adap); | ||
655 | if (!adap->fe[0]) | ||
656 | return -EINVAL; | ||
657 | |||
658 | adap->fe[0]->sec_priv = adap; | ||
659 | st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl; | ||
660 | adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; | ||
661 | |||
662 | az6007_ci_init(adap); | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
633 | static int az6007_tuner_attach(struct dvb_usb_adapter *adap) | 667 | static int az6007_tuner_attach(struct dvb_usb_adapter *adap) |
634 | { | 668 | { |
635 | struct dvb_usb_device *d = adap_to_d(adap); | 669 | struct dvb_usb_device *d = adap_to_d(adap); |
@@ -868,6 +902,29 @@ static struct dvb_usb_device_properties az6007_props = { | |||
868 | } | 902 | } |
869 | }; | 903 | }; |
870 | 904 | ||
905 | static struct dvb_usb_device_properties az6007_cablestar_hdci_props = { | ||
906 | .driver_name = KBUILD_MODNAME, | ||
907 | .owner = THIS_MODULE, | ||
908 | .firmware = AZ6007_FIRMWARE, | ||
909 | |||
910 | .adapter_nr = adapter_nr, | ||
911 | .size_of_priv = sizeof(struct az6007_device_state), | ||
912 | .i2c_algo = &az6007_i2c_algo, | ||
913 | .tuner_attach = az6007_tuner_attach, | ||
914 | .frontend_attach = az6007_cablestar_hdci_frontend_attach, | ||
915 | .streaming_ctrl = az6007_streaming_ctrl, | ||
916 | /* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */ | ||
917 | .get_rc_config = NULL, | ||
918 | .read_mac_address = az6007_read_mac_addr, | ||
919 | .download_firmware = az6007_download_firmware, | ||
920 | .identify_state = az6007_identify_state, | ||
921 | .power_ctrl = az6007_power_ctrl, | ||
922 | .num_adapters = 1, | ||
923 | .adapter = { | ||
924 | { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), } | ||
925 | } | ||
926 | }; | ||
927 | |||
871 | static struct usb_device_id az6007_usb_table[] = { | 928 | static struct usb_device_id az6007_usb_table[] = { |
872 | {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007, | 929 | {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007, |
873 | &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)}, | 930 | &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)}, |
@@ -875,6 +932,8 @@ static struct usb_device_id az6007_usb_table[] = { | |||
875 | &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, | 932 | &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, |
876 | {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2, | 933 | {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2, |
877 | &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, | 934 | &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, |
935 | {DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI, | ||
936 | &az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)}, | ||
878 | {0}, | 937 | {0}, |
879 | }; | 938 | }; |
880 | 939 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c index 5c68f3918bc8..0c2b377704ff 100644 --- a/drivers/media/usb/dvb-usb-v2/ec168.c +++ b/drivers/media/usb/dvb-usb-v2/ec168.c | |||
@@ -170,7 +170,7 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
170 | 170 | ||
171 | error: | 171 | error: |
172 | mutex_unlock(&d->i2c_mutex); | 172 | mutex_unlock(&d->i2c_mutex); |
173 | return i; | 173 | return ret; |
174 | } | 174 | } |
175 | 175 | ||
176 | static u32 ec168_i2c_func(struct i2c_adapter *adapter) | 176 | static u32 ec168_i2c_func(struct i2c_adapter *adapter) |
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c index 1cb6899cf797..fe95a586dd5d 100644 --- a/drivers/media/usb/dvb-usb-v2/it913x.c +++ b/drivers/media/usb/dvb-usb-v2/it913x.c | |||
@@ -799,6 +799,9 @@ static const struct usb_device_id it913x_id_table[] = { | |||
799 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, | 799 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, |
800 | &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2", | 800 | &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2", |
801 | RC_MAP_IT913X_V1) }, | 801 | RC_MAP_IT913X_V1) }, |
802 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335, | ||
803 | &it913x_properties, "Avermedia H335", | ||
804 | RC_MAP_IT913X_V2) }, | ||
802 | {} /* Terminating entry */ | 805 | {} /* Terminating entry */ |
803 | }; | 806 | }; |
804 | 807 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index ecca03667f98..fda5c64ba0e8 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c | |||
@@ -1407,6 +1407,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { | |||
1407 | &rtl2832u_props, "Dexatek DK DVB-T Dongle", NULL) }, | 1407 | &rtl2832u_props, "Dexatek DK DVB-T Dongle", NULL) }, |
1408 | { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680, | 1408 | { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680, |
1409 | &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) }, | 1409 | &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) }, |
1410 | { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID, | ||
1411 | &rtl2832u_props, "Leadtek Winfast DTV Dongle Mini D", NULL) }, | ||
1410 | { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3, | 1412 | { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3, |
1411 | &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, | 1413 | &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, |
1412 | { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102, | 1414 | { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102, |
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 20e345d9fe8f..a1c641e18362 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c | |||
@@ -149,6 +149,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
149 | int num) | 149 | int num) |
150 | { | 150 | { |
151 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 151 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
152 | int ret; | ||
152 | int i; | 153 | int i; |
153 | 154 | ||
154 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 155 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) |
@@ -173,7 +174,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
173 | if (1 + msg[i].len > sizeof(ibuf)) { | 174 | if (1 + msg[i].len > sizeof(ibuf)) { |
174 | warn("i2c rd: len=%d is too big!\n", | 175 | warn("i2c rd: len=%d is too big!\n", |
175 | msg[i].len); | 176 | msg[i].len); |
176 | return -EOPNOTSUPP; | 177 | ret = -EOPNOTSUPP; |
178 | goto unlock; | ||
177 | } | 179 | } |
178 | obuf[0] = 0; | 180 | obuf[0] = 0; |
179 | obuf[1] = msg[i].len; | 181 | obuf[1] = msg[i].len; |
@@ -193,12 +195,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
193 | if (3 + msg[i].len > sizeof(obuf)) { | 195 | if (3 + msg[i].len > sizeof(obuf)) { |
194 | warn("i2c wr: len=%d is too big!\n", | 196 | warn("i2c wr: len=%d is too big!\n", |
195 | msg[i].len); | 197 | msg[i].len); |
196 | return -EOPNOTSUPP; | 198 | ret = -EOPNOTSUPP; |
199 | goto unlock; | ||
197 | } | 200 | } |
198 | if (1 + msg[i + 1].len > sizeof(ibuf)) { | 201 | if (1 + msg[i + 1].len > sizeof(ibuf)) { |
199 | warn("i2c rd: len=%d is too big!\n", | 202 | warn("i2c rd: len=%d is too big!\n", |
200 | msg[i + 1].len); | 203 | msg[i + 1].len); |
201 | return -EOPNOTSUPP; | 204 | ret = -EOPNOTSUPP; |
205 | goto unlock; | ||
202 | } | 206 | } |
203 | obuf[0] = msg[i].len; | 207 | obuf[0] = msg[i].len; |
204 | obuf[1] = msg[i+1].len; | 208 | obuf[1] = msg[i+1].len; |
@@ -223,7 +227,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
223 | if (2 + msg[i].len > sizeof(obuf)) { | 227 | if (2 + msg[i].len > sizeof(obuf)) { |
224 | warn("i2c wr: len=%d is too big!\n", | 228 | warn("i2c wr: len=%d is too big!\n", |
225 | msg[i].len); | 229 | msg[i].len); |
226 | return -EOPNOTSUPP; | 230 | ret = -EOPNOTSUPP; |
231 | goto unlock; | ||
227 | } | 232 | } |
228 | obuf[0] = msg[i].addr; | 233 | obuf[0] = msg[i].addr; |
229 | obuf[1] = msg[i].len; | 234 | obuf[1] = msg[i].len; |
@@ -237,8 +242,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
237 | } | 242 | } |
238 | } | 243 | } |
239 | 244 | ||
245 | if (i == num) | ||
246 | ret = num; | ||
247 | else | ||
248 | ret = -EREMOTEIO; | ||
249 | |||
250 | unlock: | ||
240 | mutex_unlock(&d->i2c_mutex); | 251 | mutex_unlock(&d->i2c_mutex); |
241 | return i == num ? num : -EREMOTEIO; | 252 | return ret; |
242 | } | 253 | } |
243 | 254 | ||
244 | static u32 cxusb_i2c_func(struct i2c_adapter *adapter) | 255 | static u32 cxusb_i2c_func(struct i2c_adapter *adapter) |
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index c1a63b2a6baa..ae0f56a32e4d 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, | 2 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, |
3 | * TeVii S600, S630, S650, S660, S480, S421, S632 | 3 | * TeVii S600, S630, S650, S660, S480, S421, S632 |
4 | * Prof 1100, 7500, | 4 | * Prof 1100, 7500, |
5 | * Geniatech SU3000 Cards | 5 | * Geniatech SU3000, T220 Cards |
6 | * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by) | 6 | * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
@@ -29,6 +29,8 @@ | |||
29 | #include "stb6100.h" | 29 | #include "stb6100.h" |
30 | #include "stb6100_proc.h" | 30 | #include "stb6100_proc.h" |
31 | #include "m88rs2000.h" | 31 | #include "m88rs2000.h" |
32 | #include "tda18271.h" | ||
33 | #include "cxd2820r.h" | ||
32 | 34 | ||
33 | /* Max transfer size done by I2C transfer functions */ | 35 | /* Max transfer size done by I2C transfer functions */ |
34 | #define MAX_XFER_SIZE 64 | 36 | #define MAX_XFER_SIZE 64 |
@@ -110,11 +112,6 @@ | |||
110 | "Please see linux/Documentation/dvb/ for more details " \ | 112 | "Please see linux/Documentation/dvb/ for more details " \ |
111 | "on firmware-problems." | 113 | "on firmware-problems." |
112 | 114 | ||
113 | struct rc_map_dvb_usb_table_table { | ||
114 | struct rc_map_table *rc_keys; | ||
115 | int rc_keys_size; | ||
116 | }; | ||
117 | |||
118 | struct su3000_state { | 115 | struct su3000_state { |
119 | u8 initialized; | 116 | u8 initialized; |
120 | }; | 117 | }; |
@@ -129,12 +126,6 @@ module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); | |||
129 | MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." | 126 | MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." |
130 | DVB_USB_DEBUG_STATUS); | 127 | DVB_USB_DEBUG_STATUS); |
131 | 128 | ||
132 | /* keymaps */ | ||
133 | static int ir_keymap; | ||
134 | module_param_named(keymap, ir_keymap, int, 0644); | ||
135 | MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..." | ||
136 | " 256=none"); | ||
137 | |||
138 | /* demod probe */ | 129 | /* demod probe */ |
139 | static int demod_probe = 1; | 130 | static int demod_probe = 1; |
140 | module_param_named(demod, demod_probe, int, 0644); | 131 | module_param_named(demod, demod_probe, int, 0644); |
@@ -301,6 +292,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, | |||
301 | static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | 292 | static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) |
302 | { | 293 | { |
303 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 294 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
295 | int ret; | ||
304 | 296 | ||
305 | if (!d) | 297 | if (!d) |
306 | return -ENODEV; | 298 | return -ENODEV; |
@@ -316,7 +308,8 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
316 | if (2 + msg[1].len > sizeof(ibuf)) { | 308 | if (2 + msg[1].len > sizeof(ibuf)) { |
317 | warn("i2c rd: len=%d is too big!\n", | 309 | warn("i2c rd: len=%d is too big!\n", |
318 | msg[1].len); | 310 | msg[1].len); |
319 | return -EOPNOTSUPP; | 311 | ret = -EOPNOTSUPP; |
312 | goto unlock; | ||
320 | } | 313 | } |
321 | 314 | ||
322 | obuf[0] = msg[0].addr << 1; | 315 | obuf[0] = msg[0].addr << 1; |
@@ -340,7 +333,8 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
340 | if (2 + msg[0].len > sizeof(obuf)) { | 333 | if (2 + msg[0].len > sizeof(obuf)) { |
341 | warn("i2c wr: len=%d is too big!\n", | 334 | warn("i2c wr: len=%d is too big!\n", |
342 | msg[1].len); | 335 | msg[1].len); |
343 | return -EOPNOTSUPP; | 336 | ret = -EOPNOTSUPP; |
337 | goto unlock; | ||
344 | } | 338 | } |
345 | 339 | ||
346 | obuf[0] = msg[0].addr << 1; | 340 | obuf[0] = msg[0].addr << 1; |
@@ -357,7 +351,8 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
357 | if (2 + msg[0].len > sizeof(obuf)) { | 351 | if (2 + msg[0].len > sizeof(obuf)) { |
358 | warn("i2c wr: len=%d is too big!\n", | 352 | warn("i2c wr: len=%d is too big!\n", |
359 | msg[1].len); | 353 | msg[1].len); |
360 | return -EOPNOTSUPP; | 354 | ret = -EOPNOTSUPP; |
355 | goto unlock; | ||
361 | } | 356 | } |
362 | 357 | ||
363 | obuf[0] = msg[0].addr << 1; | 358 | obuf[0] = msg[0].addr << 1; |
@@ -386,15 +381,17 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
386 | 381 | ||
387 | break; | 382 | break; |
388 | } | 383 | } |
384 | ret = num; | ||
389 | 385 | ||
386 | unlock: | ||
390 | mutex_unlock(&d->i2c_mutex); | 387 | mutex_unlock(&d->i2c_mutex); |
391 | return num; | 388 | return ret; |
392 | } | 389 | } |
393 | 390 | ||
394 | static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | 391 | static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) |
395 | { | 392 | { |
396 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 393 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
397 | int len, i, j; | 394 | int len, i, j, ret; |
398 | 395 | ||
399 | if (!d) | 396 | if (!d) |
400 | return -ENODEV; | 397 | return -ENODEV; |
@@ -430,7 +427,8 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i | |||
430 | if (2 + msg[j].len > sizeof(ibuf)) { | 427 | if (2 + msg[j].len > sizeof(ibuf)) { |
431 | warn("i2c rd: len=%d is too big!\n", | 428 | warn("i2c rd: len=%d is too big!\n", |
432 | msg[j].len); | 429 | msg[j].len); |
433 | return -EOPNOTSUPP; | 430 | ret = -EOPNOTSUPP; |
431 | goto unlock; | ||
434 | } | 432 | } |
435 | 433 | ||
436 | dw210x_op_rw(d->udev, 0xc3, | 434 | dw210x_op_rw(d->udev, 0xc3, |
@@ -466,7 +464,8 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i | |||
466 | if (2 + msg[j].len > sizeof(obuf)) { | 464 | if (2 + msg[j].len > sizeof(obuf)) { |
467 | warn("i2c wr: len=%d is too big!\n", | 465 | warn("i2c wr: len=%d is too big!\n", |
468 | msg[j].len); | 466 | msg[j].len); |
469 | return -EOPNOTSUPP; | 467 | ret = -EOPNOTSUPP; |
468 | goto unlock; | ||
470 | } | 469 | } |
471 | 470 | ||
472 | obuf[0] = msg[j].addr << 1; | 471 | obuf[0] = msg[j].addr << 1; |
@@ -481,15 +480,18 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i | |||
481 | } | 480 | } |
482 | 481 | ||
483 | } | 482 | } |
483 | ret = num; | ||
484 | 484 | ||
485 | unlock: | ||
485 | mutex_unlock(&d->i2c_mutex); | 486 | mutex_unlock(&d->i2c_mutex); |
486 | return num; | 487 | return ret; |
487 | } | 488 | } |
488 | 489 | ||
489 | static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 490 | static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
490 | int num) | 491 | int num) |
491 | { | 492 | { |
492 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 493 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
494 | int ret; | ||
493 | int i; | 495 | int i; |
494 | 496 | ||
495 | if (!d) | 497 | if (!d) |
@@ -506,7 +508,8 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
506 | if (2 + msg[1].len > sizeof(ibuf)) { | 508 | if (2 + msg[1].len > sizeof(ibuf)) { |
507 | warn("i2c rd: len=%d is too big!\n", | 509 | warn("i2c rd: len=%d is too big!\n", |
508 | msg[1].len); | 510 | msg[1].len); |
509 | return -EOPNOTSUPP; | 511 | ret = -EOPNOTSUPP; |
512 | goto unlock; | ||
510 | } | 513 | } |
511 | obuf[0] = msg[0].addr << 1; | 514 | obuf[0] = msg[0].addr << 1; |
512 | obuf[1] = msg[0].len; | 515 | obuf[1] = msg[0].len; |
@@ -530,7 +533,8 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
530 | if (2 + msg[0].len > sizeof(obuf)) { | 533 | if (2 + msg[0].len > sizeof(obuf)) { |
531 | warn("i2c wr: len=%d is too big!\n", | 534 | warn("i2c wr: len=%d is too big!\n", |
532 | msg[0].len); | 535 | msg[0].len); |
533 | return -EOPNOTSUPP; | 536 | ret = -EOPNOTSUPP; |
537 | goto unlock; | ||
534 | } | 538 | } |
535 | obuf[0] = msg[0].addr << 1; | 539 | obuf[0] = msg[0].addr << 1; |
536 | obuf[1] = msg[0].len; | 540 | obuf[1] = msg[0].len; |
@@ -556,9 +560,11 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
556 | msg[i].flags == 0 ? ">>>" : "<<<"); | 560 | msg[i].flags == 0 ? ">>>" : "<<<"); |
557 | debug_dump(msg[i].buf, msg[i].len, deb_xfer); | 561 | debug_dump(msg[i].buf, msg[i].len, deb_xfer); |
558 | } | 562 | } |
563 | ret = num; | ||
559 | 564 | ||
565 | unlock: | ||
560 | mutex_unlock(&d->i2c_mutex); | 566 | mutex_unlock(&d->i2c_mutex); |
561 | return num; | 567 | return ret; |
562 | } | 568 | } |
563 | 569 | ||
564 | static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 570 | static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
@@ -566,7 +572,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
566 | { | 572 | { |
567 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 573 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
568 | struct usb_device *udev; | 574 | struct usb_device *udev; |
569 | int len, i, j; | 575 | int len, i, j, ret; |
570 | 576 | ||
571 | if (!d) | 577 | if (!d) |
572 | return -ENODEV; | 578 | return -ENODEV; |
@@ -618,7 +624,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
618 | if (msg[j].len > sizeof(ibuf)) { | 624 | if (msg[j].len > sizeof(ibuf)) { |
619 | warn("i2c rd: len=%d is too big!\n", | 625 | warn("i2c rd: len=%d is too big!\n", |
620 | msg[j].len); | 626 | msg[j].len); |
621 | return -EOPNOTSUPP; | 627 | ret = -EOPNOTSUPP; |
628 | goto unlock; | ||
622 | } | 629 | } |
623 | 630 | ||
624 | dw210x_op_rw(d->udev, 0x91, 0, 0, | 631 | dw210x_op_rw(d->udev, 0x91, 0, 0, |
@@ -652,7 +659,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
652 | if (2 + msg[j].len > sizeof(obuf)) { | 659 | if (2 + msg[j].len > sizeof(obuf)) { |
653 | warn("i2c wr: len=%d is too big!\n", | 660 | warn("i2c wr: len=%d is too big!\n", |
654 | msg[j].len); | 661 | msg[j].len); |
655 | return -EOPNOTSUPP; | 662 | ret = -EOPNOTSUPP; |
663 | goto unlock; | ||
656 | } | 664 | } |
657 | 665 | ||
658 | obuf[0] = msg[j + 1].len; | 666 | obuf[0] = msg[j + 1].len; |
@@ -671,7 +679,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
671 | if (2 + msg[j].len > sizeof(obuf)) { | 679 | if (2 + msg[j].len > sizeof(obuf)) { |
672 | warn("i2c wr: len=%d is too big!\n", | 680 | warn("i2c wr: len=%d is too big!\n", |
673 | msg[j].len); | 681 | msg[j].len); |
674 | return -EOPNOTSUPP; | 682 | ret = -EOPNOTSUPP; |
683 | goto unlock; | ||
675 | } | 684 | } |
676 | obuf[0] = msg[j].len + 1; | 685 | obuf[0] = msg[j].len + 1; |
677 | obuf[1] = (msg[j].addr << 1); | 686 | obuf[1] = (msg[j].addr << 1); |
@@ -685,9 +694,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
685 | } | 694 | } |
686 | } | 695 | } |
687 | } | 696 | } |
697 | ret = num; | ||
688 | 698 | ||
699 | unlock: | ||
689 | mutex_unlock(&d->i2c_mutex); | 700 | mutex_unlock(&d->i2c_mutex); |
690 | return num; | 701 | return ret; |
691 | } | 702 | } |
692 | 703 | ||
693 | static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 704 | static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
@@ -1095,6 +1106,16 @@ static struct ds3000_config su3000_ds3000_config = { | |||
1095 | .set_lock_led = dw210x_led_ctrl, | 1106 | .set_lock_led = dw210x_led_ctrl, |
1096 | }; | 1107 | }; |
1097 | 1108 | ||
1109 | static struct cxd2820r_config cxd2820r_config = { | ||
1110 | .i2c_address = 0x6c, /* (0xd8 >> 1) */ | ||
1111 | .ts_mode = 0x38, | ||
1112 | }; | ||
1113 | |||
1114 | static struct tda18271_config tda18271_config = { | ||
1115 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
1116 | .gate = TDA18271_GATE_DIGITAL, | ||
1117 | }; | ||
1118 | |||
1098 | static u8 m88rs2000_inittab[] = { | 1119 | static u8 m88rs2000_inittab[] = { |
1099 | DEMOD_WRITE, 0x9a, 0x30, | 1120 | DEMOD_WRITE, 0x9a, 0x30, |
1100 | DEMOD_WRITE, 0x00, 0x01, | 1121 | DEMOD_WRITE, 0x00, 0x01, |
@@ -1364,6 +1385,49 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) | |||
1364 | return -EIO; | 1385 | return -EIO; |
1365 | } | 1386 | } |
1366 | 1387 | ||
1388 | static int t220_frontend_attach(struct dvb_usb_adapter *d) | ||
1389 | { | ||
1390 | u8 obuf[3] = { 0xe, 0x80, 0 }; | ||
1391 | u8 ibuf[] = { 0 }; | ||
1392 | |||
1393 | if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) | ||
1394 | err("command 0x0e transfer failed."); | ||
1395 | |||
1396 | obuf[0] = 0xe; | ||
1397 | obuf[1] = 0x83; | ||
1398 | obuf[2] = 0; | ||
1399 | |||
1400 | if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) | ||
1401 | err("command 0x0e transfer failed."); | ||
1402 | |||
1403 | msleep(100); | ||
1404 | |||
1405 | obuf[0] = 0xe; | ||
1406 | obuf[1] = 0x80; | ||
1407 | obuf[2] = 1; | ||
1408 | |||
1409 | if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) | ||
1410 | err("command 0x0e transfer failed."); | ||
1411 | |||
1412 | obuf[0] = 0x51; | ||
1413 | |||
1414 | if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) | ||
1415 | err("command 0x51 transfer failed."); | ||
1416 | |||
1417 | d->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config, | ||
1418 | &d->dev->i2c_adap, NULL); | ||
1419 | if (d->fe_adap[0].fe != NULL) { | ||
1420 | if (dvb_attach(tda18271_attach, d->fe_adap[0].fe, 0x60, | ||
1421 | &d->dev->i2c_adap, &tda18271_config)) { | ||
1422 | info("Attached TDA18271HD/CXD2820R!\n"); | ||
1423 | return 0; | ||
1424 | } | ||
1425 | } | ||
1426 | |||
1427 | info("Failed to attach TDA18271HD/CXD2820R!\n"); | ||
1428 | return -EIO; | ||
1429 | } | ||
1430 | |||
1367 | static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d) | 1431 | static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d) |
1368 | { | 1432 | { |
1369 | u8 obuf[] = { 0x51 }; | 1433 | u8 obuf[] = { 0x51 }; |
@@ -1404,174 +1468,29 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) | |||
1404 | return 0; | 1468 | return 0; |
1405 | } | 1469 | } |
1406 | 1470 | ||
1407 | static struct rc_map_table rc_map_dw210x_table[] = { | 1471 | static int dw2102_rc_query(struct dvb_usb_device *d) |
1408 | { 0xf80a, KEY_POWER2 }, /*power*/ | 1472 | { |
1409 | { 0xf80c, KEY_MUTE }, /*mute*/ | 1473 | u8 key[2]; |
1410 | { 0xf811, KEY_1 }, | 1474 | struct i2c_msg msg = { |
1411 | { 0xf812, KEY_2 }, | 1475 | .addr = DW2102_RC_QUERY, |
1412 | { 0xf813, KEY_3 }, | 1476 | .flags = I2C_M_RD, |
1413 | { 0xf814, KEY_4 }, | 1477 | .buf = key, |
1414 | { 0xf815, KEY_5 }, | 1478 | .len = 2 |
1415 | { 0xf816, KEY_6 }, | 1479 | }; |
1416 | { 0xf817, KEY_7 }, | ||
1417 | { 0xf818, KEY_8 }, | ||
1418 | { 0xf819, KEY_9 }, | ||
1419 | { 0xf810, KEY_0 }, | ||
1420 | { 0xf81c, KEY_CHANNELUP }, /*ch+*/ | ||
1421 | { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/ | ||
1422 | { 0xf81a, KEY_VOLUMEUP }, /*vol+*/ | ||
1423 | { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/ | ||
1424 | { 0xf804, KEY_RECORD }, /*rec*/ | ||
1425 | { 0xf809, KEY_FAVORITES }, /*fav*/ | ||
1426 | { 0xf808, KEY_REWIND }, /*rewind*/ | ||
1427 | { 0xf807, KEY_FASTFORWARD }, /*fast*/ | ||
1428 | { 0xf80b, KEY_PAUSE }, /*pause*/ | ||
1429 | { 0xf802, KEY_ESC }, /*cancel*/ | ||
1430 | { 0xf803, KEY_TAB }, /*tab*/ | ||
1431 | { 0xf800, KEY_UP }, /*up*/ | ||
1432 | { 0xf81f, KEY_OK }, /*ok*/ | ||
1433 | { 0xf801, KEY_DOWN }, /*down*/ | ||
1434 | { 0xf805, KEY_CAMERA }, /*cap*/ | ||
1435 | { 0xf806, KEY_STOP }, /*stop*/ | ||
1436 | { 0xf840, KEY_ZOOM }, /*full*/ | ||
1437 | { 0xf81e, KEY_TV }, /*tvmode*/ | ||
1438 | { 0xf81b, KEY_LAST }, /*recall*/ | ||
1439 | }; | ||
1440 | |||
1441 | static struct rc_map_table rc_map_tevii_table[] = { | ||
1442 | { 0xf80a, KEY_POWER }, | ||
1443 | { 0xf80c, KEY_MUTE }, | ||
1444 | { 0xf811, KEY_1 }, | ||
1445 | { 0xf812, KEY_2 }, | ||
1446 | { 0xf813, KEY_3 }, | ||
1447 | { 0xf814, KEY_4 }, | ||
1448 | { 0xf815, KEY_5 }, | ||
1449 | { 0xf816, KEY_6 }, | ||
1450 | { 0xf817, KEY_7 }, | ||
1451 | { 0xf818, KEY_8 }, | ||
1452 | { 0xf819, KEY_9 }, | ||
1453 | { 0xf810, KEY_0 }, | ||
1454 | { 0xf81c, KEY_MENU }, | ||
1455 | { 0xf80f, KEY_VOLUMEDOWN }, | ||
1456 | { 0xf81a, KEY_LAST }, | ||
1457 | { 0xf80e, KEY_OPEN }, | ||
1458 | { 0xf804, KEY_RECORD }, | ||
1459 | { 0xf809, KEY_VOLUMEUP }, | ||
1460 | { 0xf808, KEY_CHANNELUP }, | ||
1461 | { 0xf807, KEY_PVR }, | ||
1462 | { 0xf80b, KEY_TIME }, | ||
1463 | { 0xf802, KEY_RIGHT }, | ||
1464 | { 0xf803, KEY_LEFT }, | ||
1465 | { 0xf800, KEY_UP }, | ||
1466 | { 0xf81f, KEY_OK }, | ||
1467 | { 0xf801, KEY_DOWN }, | ||
1468 | { 0xf805, KEY_TUNER }, | ||
1469 | { 0xf806, KEY_CHANNELDOWN }, | ||
1470 | { 0xf840, KEY_PLAYPAUSE }, | ||
1471 | { 0xf81e, KEY_REWIND }, | ||
1472 | { 0xf81b, KEY_FAVORITES }, | ||
1473 | { 0xf81d, KEY_BACK }, | ||
1474 | { 0xf84d, KEY_FASTFORWARD }, | ||
1475 | { 0xf844, KEY_EPG }, | ||
1476 | { 0xf84c, KEY_INFO }, | ||
1477 | { 0xf841, KEY_AB }, | ||
1478 | { 0xf843, KEY_AUDIO }, | ||
1479 | { 0xf845, KEY_SUBTITLE }, | ||
1480 | { 0xf84a, KEY_LIST }, | ||
1481 | { 0xf846, KEY_F1 }, | ||
1482 | { 0xf847, KEY_F2 }, | ||
1483 | { 0xf85e, KEY_F3 }, | ||
1484 | { 0xf85c, KEY_F4 }, | ||
1485 | { 0xf852, KEY_F5 }, | ||
1486 | { 0xf85a, KEY_F6 }, | ||
1487 | { 0xf856, KEY_MODE }, | ||
1488 | { 0xf858, KEY_SWITCHVIDEOMODE }, | ||
1489 | }; | ||
1490 | |||
1491 | static struct rc_map_table rc_map_tbs_table[] = { | ||
1492 | { 0xf884, KEY_POWER }, | ||
1493 | { 0xf894, KEY_MUTE }, | ||
1494 | { 0xf887, KEY_1 }, | ||
1495 | { 0xf886, KEY_2 }, | ||
1496 | { 0xf885, KEY_3 }, | ||
1497 | { 0xf88b, KEY_4 }, | ||
1498 | { 0xf88a, KEY_5 }, | ||
1499 | { 0xf889, KEY_6 }, | ||
1500 | { 0xf88f, KEY_7 }, | ||
1501 | { 0xf88e, KEY_8 }, | ||
1502 | { 0xf88d, KEY_9 }, | ||
1503 | { 0xf892, KEY_0 }, | ||
1504 | { 0xf896, KEY_CHANNELUP }, | ||
1505 | { 0xf891, KEY_CHANNELDOWN }, | ||
1506 | { 0xf893, KEY_VOLUMEUP }, | ||
1507 | { 0xf88c, KEY_VOLUMEDOWN }, | ||
1508 | { 0xf883, KEY_RECORD }, | ||
1509 | { 0xf898, KEY_PAUSE }, | ||
1510 | { 0xf899, KEY_OK }, | ||
1511 | { 0xf89a, KEY_SHUFFLE }, | ||
1512 | { 0xf881, KEY_UP }, | ||
1513 | { 0xf890, KEY_LEFT }, | ||
1514 | { 0xf882, KEY_RIGHT }, | ||
1515 | { 0xf888, KEY_DOWN }, | ||
1516 | { 0xf895, KEY_FAVORITES }, | ||
1517 | { 0xf897, KEY_SUBTITLE }, | ||
1518 | { 0xf89d, KEY_ZOOM }, | ||
1519 | { 0xf89f, KEY_EXIT }, | ||
1520 | { 0xf89e, KEY_MENU }, | ||
1521 | { 0xf89c, KEY_EPG }, | ||
1522 | { 0xf880, KEY_PREVIOUS }, | ||
1523 | { 0xf89b, KEY_MODE } | ||
1524 | }; | ||
1525 | 1480 | ||
1526 | static struct rc_map_table rc_map_su3000_table[] = { | 1481 | if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { |
1527 | { 0x25, KEY_POWER }, /* right-bottom Red */ | 1482 | if (msg.buf[0] != 0xff) { |
1528 | { 0x0a, KEY_MUTE }, /* -/-- */ | 1483 | deb_rc("%s: rc code: %x, %x\n", |
1529 | { 0x01, KEY_1 }, | 1484 | __func__, key[0], key[1]); |
1530 | { 0x02, KEY_2 }, | 1485 | rc_keydown(d->rc_dev, key[0], 1); |
1531 | { 0x03, KEY_3 }, | 1486 | } |
1532 | { 0x04, KEY_4 }, | 1487 | } |
1533 | { 0x05, KEY_5 }, | ||
1534 | { 0x06, KEY_6 }, | ||
1535 | { 0x07, KEY_7 }, | ||
1536 | { 0x08, KEY_8 }, | ||
1537 | { 0x09, KEY_9 }, | ||
1538 | { 0x00, KEY_0 }, | ||
1539 | { 0x20, KEY_UP }, /* CH+ */ | ||
1540 | { 0x21, KEY_DOWN }, /* CH+ */ | ||
1541 | { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ | ||
1542 | { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ | ||
1543 | { 0x1f, KEY_RECORD }, | ||
1544 | { 0x17, KEY_PLAY }, | ||
1545 | { 0x16, KEY_PAUSE }, | ||
1546 | { 0x0b, KEY_STOP }, | ||
1547 | { 0x27, KEY_FASTFORWARD },/* >> */ | ||
1548 | { 0x26, KEY_REWIND }, /* << */ | ||
1549 | { 0x0d, KEY_OK }, /* Mute */ | ||
1550 | { 0x11, KEY_LEFT }, /* VOL- */ | ||
1551 | { 0x10, KEY_RIGHT }, /* VOL+ */ | ||
1552 | { 0x29, KEY_BACK }, /* button under 9 */ | ||
1553 | { 0x2c, KEY_MENU }, /* TTX */ | ||
1554 | { 0x2b, KEY_EPG }, /* EPG */ | ||
1555 | { 0x1e, KEY_RED }, /* OSD */ | ||
1556 | { 0x0e, KEY_GREEN }, /* Window */ | ||
1557 | { 0x2d, KEY_YELLOW }, /* button under << */ | ||
1558 | { 0x0f, KEY_BLUE }, /* bottom yellow button */ | ||
1559 | { 0x14, KEY_AUDIO }, /* Snapshot */ | ||
1560 | { 0x38, KEY_TV }, /* TV/Radio */ | ||
1561 | { 0x0c, KEY_ESC } /* upper Red button */ | ||
1562 | }; | ||
1563 | 1488 | ||
1564 | static struct rc_map_dvb_usb_table_table keys_tables[] = { | 1489 | return 0; |
1565 | { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) }, | 1490 | } |
1566 | { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) }, | ||
1567 | { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) }, | ||
1568 | { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) }, | ||
1569 | }; | ||
1570 | 1491 | ||
1571 | static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | 1492 | static int prof_rc_query(struct dvb_usb_device *d) |
1572 | { | 1493 | { |
1573 | struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; | ||
1574 | int keymap_size = d->props.rc.legacy.rc_map_size; | ||
1575 | u8 key[2]; | 1494 | u8 key[2]; |
1576 | struct i2c_msg msg = { | 1495 | struct i2c_msg msg = { |
1577 | .addr = DW2102_RC_QUERY, | 1496 | .addr = DW2102_RC_QUERY, |
@@ -1579,32 +1498,34 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
1579 | .buf = key, | 1498 | .buf = key, |
1580 | .len = 2 | 1499 | .len = 2 |
1581 | }; | 1500 | }; |
1582 | int i; | ||
1583 | /* override keymap */ | ||
1584 | if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { | ||
1585 | keymap = keys_tables[ir_keymap - 1].rc_keys ; | ||
1586 | keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; | ||
1587 | } else if (ir_keymap > ARRAY_SIZE(keys_tables)) | ||
1588 | return 0; /* none */ | ||
1589 | |||
1590 | *state = REMOTE_NO_KEY_PRESSED; | ||
1591 | if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { | ||
1592 | for (i = 0; i < keymap_size ; i++) { | ||
1593 | if (rc5_data(&keymap[i]) == msg.buf[0]) { | ||
1594 | *state = REMOTE_KEY_PRESSED; | ||
1595 | *event = keymap[i].keycode; | ||
1596 | break; | ||
1597 | } | ||
1598 | 1501 | ||
1502 | if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { | ||
1503 | if (msg.buf[0] != 0xff) { | ||
1504 | deb_rc("%s: rc code: %x, %x\n", | ||
1505 | __func__, key[0], key[1]); | ||
1506 | rc_keydown(d->rc_dev, key[0]^0xff, 1); | ||
1599 | } | 1507 | } |
1508 | } | ||
1600 | 1509 | ||
1601 | if ((*state) == REMOTE_KEY_PRESSED) | 1510 | return 0; |
1602 | deb_rc("%s: found rc key: %x, %x, event: %x\n", | 1511 | } |
1603 | __func__, key[0], key[1], (*event)); | ||
1604 | else if (key[0] != 0xff) | ||
1605 | deb_rc("%s: unknown rc key: %x, %x\n", | ||
1606 | __func__, key[0], key[1]); | ||
1607 | 1512 | ||
1513 | static int su3000_rc_query(struct dvb_usb_device *d) | ||
1514 | { | ||
1515 | u8 key[2]; | ||
1516 | struct i2c_msg msg = { | ||
1517 | .addr = DW2102_RC_QUERY, | ||
1518 | .flags = I2C_M_RD, | ||
1519 | .buf = key, | ||
1520 | .len = 2 | ||
1521 | }; | ||
1522 | |||
1523 | if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { | ||
1524 | if (msg.buf[0] != 0xff) { | ||
1525 | deb_rc("%s: rc code: %x, %x\n", | ||
1526 | __func__, key[0], key[1]); | ||
1527 | rc_keydown(d->rc_dev, key[1] << 8 | key[0], 1); | ||
1528 | } | ||
1608 | } | 1529 | } |
1609 | 1530 | ||
1610 | return 0; | 1531 | return 0; |
@@ -1630,6 +1551,7 @@ enum dw2102_table_entry { | |||
1630 | TEVII_S632, | 1551 | TEVII_S632, |
1631 | TERRATEC_CINERGY_S2_R2, | 1552 | TERRATEC_CINERGY_S2_R2, |
1632 | GOTVIEW_SAT_HD, | 1553 | GOTVIEW_SAT_HD, |
1554 | GENIATECH_T220, | ||
1633 | }; | 1555 | }; |
1634 | 1556 | ||
1635 | static struct usb_device_id dw2102_table[] = { | 1557 | static struct usb_device_id dw2102_table[] = { |
@@ -1652,6 +1574,7 @@ static struct usb_device_id dw2102_table[] = { | |||
1652 | [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, | 1574 | [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, |
1653 | [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)}, | 1575 | [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)}, |
1654 | [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, | 1576 | [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, |
1577 | [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, | ||
1655 | { } | 1578 | { } |
1656 | }; | 1579 | }; |
1657 | 1580 | ||
@@ -1711,9 +1634,7 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
1711 | /* init registers */ | 1634 | /* init registers */ |
1712 | switch (dev->descriptor.idProduct) { | 1635 | switch (dev->descriptor.idProduct) { |
1713 | case USB_PID_TEVII_S650: | 1636 | case USB_PID_TEVII_S650: |
1714 | dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table; | 1637 | dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC; |
1715 | dw2104_properties.rc.legacy.rc_map_size = | ||
1716 | ARRAY_SIZE(rc_map_tevii_table); | ||
1717 | case USB_PID_DW2104: | 1638 | case USB_PID_DW2104: |
1718 | reset = 1; | 1639 | reset = 1; |
1719 | dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, | 1640 | dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, |
@@ -1777,10 +1698,11 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
1777 | 1698 | ||
1778 | .i2c_algo = &dw2102_serit_i2c_algo, | 1699 | .i2c_algo = &dw2102_serit_i2c_algo, |
1779 | 1700 | ||
1780 | .rc.legacy = { | 1701 | .rc.core = { |
1781 | .rc_map_table = rc_map_dw210x_table, | ||
1782 | .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), | ||
1783 | .rc_interval = 150, | 1702 | .rc_interval = 150, |
1703 | .rc_codes = RC_MAP_DM1105_NEC, | ||
1704 | .module_name = "dw2102", | ||
1705 | .allowed_protos = RC_BIT_NEC, | ||
1784 | .rc_query = dw2102_rc_query, | 1706 | .rc_query = dw2102_rc_query, |
1785 | }, | 1707 | }, |
1786 | 1708 | ||
@@ -1831,10 +1753,11 @@ static struct dvb_usb_device_properties dw2104_properties = { | |||
1831 | .no_reconnect = 1, | 1753 | .no_reconnect = 1, |
1832 | 1754 | ||
1833 | .i2c_algo = &dw2104_i2c_algo, | 1755 | .i2c_algo = &dw2104_i2c_algo, |
1834 | .rc.legacy = { | 1756 | .rc.core = { |
1835 | .rc_map_table = rc_map_dw210x_table, | ||
1836 | .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), | ||
1837 | .rc_interval = 150, | 1757 | .rc_interval = 150, |
1758 | .rc_codes = RC_MAP_DM1105_NEC, | ||
1759 | .module_name = "dw2102", | ||
1760 | .allowed_protos = RC_BIT_NEC, | ||
1838 | .rc_query = dw2102_rc_query, | 1761 | .rc_query = dw2102_rc_query, |
1839 | }, | 1762 | }, |
1840 | 1763 | ||
@@ -1881,10 +1804,11 @@ static struct dvb_usb_device_properties dw3101_properties = { | |||
1881 | .no_reconnect = 1, | 1804 | .no_reconnect = 1, |
1882 | 1805 | ||
1883 | .i2c_algo = &dw3101_i2c_algo, | 1806 | .i2c_algo = &dw3101_i2c_algo, |
1884 | .rc.legacy = { | 1807 | .rc.core = { |
1885 | .rc_map_table = rc_map_dw210x_table, | ||
1886 | .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), | ||
1887 | .rc_interval = 150, | 1808 | .rc_interval = 150, |
1809 | .rc_codes = RC_MAP_DM1105_NEC, | ||
1810 | .module_name = "dw2102", | ||
1811 | .allowed_protos = RC_BIT_NEC, | ||
1888 | .rc_query = dw2102_rc_query, | 1812 | .rc_query = dw2102_rc_query, |
1889 | }, | 1813 | }, |
1890 | 1814 | ||
@@ -1929,10 +1853,11 @@ static struct dvb_usb_device_properties s6x0_properties = { | |||
1929 | .no_reconnect = 1, | 1853 | .no_reconnect = 1, |
1930 | 1854 | ||
1931 | .i2c_algo = &s6x0_i2c_algo, | 1855 | .i2c_algo = &s6x0_i2c_algo, |
1932 | .rc.legacy = { | 1856 | .rc.core = { |
1933 | .rc_map_table = rc_map_tevii_table, | ||
1934 | .rc_map_size = ARRAY_SIZE(rc_map_tevii_table), | ||
1935 | .rc_interval = 150, | 1857 | .rc_interval = 150, |
1858 | .rc_codes = RC_MAP_TEVII_NEC, | ||
1859 | .module_name = "dw2102", | ||
1860 | .allowed_protos = RC_BIT_NEC, | ||
1936 | .rc_query = dw2102_rc_query, | 1861 | .rc_query = dw2102_rc_query, |
1937 | }, | 1862 | }, |
1938 | 1863 | ||
@@ -2022,11 +1947,12 @@ static struct dvb_usb_device_properties su3000_properties = { | |||
2022 | .identify_state = su3000_identify_state, | 1947 | .identify_state = su3000_identify_state, |
2023 | .i2c_algo = &su3000_i2c_algo, | 1948 | .i2c_algo = &su3000_i2c_algo, |
2024 | 1949 | ||
2025 | .rc.legacy = { | 1950 | .rc.core = { |
2026 | .rc_map_table = rc_map_su3000_table, | ||
2027 | .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), | ||
2028 | .rc_interval = 150, | 1951 | .rc_interval = 150, |
2029 | .rc_query = dw2102_rc_query, | 1952 | .rc_codes = RC_MAP_SU3000, |
1953 | .module_name = "dw2102", | ||
1954 | .allowed_protos = RC_BIT_RC5, | ||
1955 | .rc_query = su3000_rc_query, | ||
2030 | }, | 1956 | }, |
2031 | 1957 | ||
2032 | .read_mac_address = su3000_read_mac_address, | 1958 | .read_mac_address = su3000_read_mac_address, |
@@ -2077,6 +2003,55 @@ static struct dvb_usb_device_properties su3000_properties = { | |||
2077 | } | 2003 | } |
2078 | }; | 2004 | }; |
2079 | 2005 | ||
2006 | static struct dvb_usb_device_properties t220_properties = { | ||
2007 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
2008 | .usb_ctrl = DEVICE_SPECIFIC, | ||
2009 | .size_of_priv = sizeof(struct su3000_state), | ||
2010 | .power_ctrl = su3000_power_ctrl, | ||
2011 | .num_adapters = 1, | ||
2012 | .identify_state = su3000_identify_state, | ||
2013 | .i2c_algo = &su3000_i2c_algo, | ||
2014 | |||
2015 | .rc.core = { | ||
2016 | .rc_interval = 150, | ||
2017 | .rc_codes = RC_MAP_SU3000, | ||
2018 | .module_name = "dw2102", | ||
2019 | .allowed_protos = RC_BIT_RC5, | ||
2020 | .rc_query = su3000_rc_query, | ||
2021 | }, | ||
2022 | |||
2023 | .read_mac_address = su3000_read_mac_address, | ||
2024 | |||
2025 | .generic_bulk_ctrl_endpoint = 0x01, | ||
2026 | |||
2027 | .adapter = { | ||
2028 | { | ||
2029 | .num_frontends = 1, | ||
2030 | .fe = { { | ||
2031 | .streaming_ctrl = su3000_streaming_ctrl, | ||
2032 | .frontend_attach = t220_frontend_attach, | ||
2033 | .stream = { | ||
2034 | .type = USB_BULK, | ||
2035 | .count = 8, | ||
2036 | .endpoint = 0x82, | ||
2037 | .u = { | ||
2038 | .bulk = { | ||
2039 | .buffersize = 4096, | ||
2040 | } | ||
2041 | } | ||
2042 | } | ||
2043 | } }, | ||
2044 | } | ||
2045 | }, | ||
2046 | .num_device_descs = 1, | ||
2047 | .devices = { | ||
2048 | { "Geniatech T220 DVB-T/T2 USB2.0", | ||
2049 | { &dw2102_table[GENIATECH_T220], NULL }, | ||
2050 | { NULL }, | ||
2051 | }, | ||
2052 | } | ||
2053 | }; | ||
2054 | |||
2080 | static int dw2102_probe(struct usb_interface *intf, | 2055 | static int dw2102_probe(struct usb_interface *intf, |
2081 | const struct usb_device_id *id) | 2056 | const struct usb_device_id *id) |
2082 | { | 2057 | { |
@@ -2088,8 +2063,8 @@ static int dw2102_probe(struct usb_interface *intf, | |||
2088 | /* fill only different fields */ | 2063 | /* fill only different fields */ |
2089 | p1100->firmware = P1100_FIRMWARE; | 2064 | p1100->firmware = P1100_FIRMWARE; |
2090 | p1100->devices[0] = d1100; | 2065 | p1100->devices[0] = d1100; |
2091 | p1100->rc.legacy.rc_map_table = rc_map_tbs_table; | 2066 | p1100->rc.core.rc_query = prof_rc_query; |
2092 | p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); | 2067 | p1100->rc.core.rc_codes = RC_MAP_TBS_NEC; |
2093 | p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; | 2068 | p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; |
2094 | 2069 | ||
2095 | s660 = kmemdup(&s6x0_properties, | 2070 | s660 = kmemdup(&s6x0_properties, |
@@ -2114,8 +2089,8 @@ static int dw2102_probe(struct usb_interface *intf, | |||
2114 | } | 2089 | } |
2115 | p7500->firmware = P7500_FIRMWARE; | 2090 | p7500->firmware = P7500_FIRMWARE; |
2116 | p7500->devices[0] = d7500; | 2091 | p7500->devices[0] = d7500; |
2117 | p7500->rc.legacy.rc_map_table = rc_map_tbs_table; | 2092 | p7500->rc.core.rc_query = prof_rc_query; |
2118 | p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); | 2093 | p7500->rc.core.rc_codes = RC_MAP_TBS_NEC; |
2119 | p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach; | 2094 | p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach; |
2120 | 2095 | ||
2121 | 2096 | ||
@@ -2149,7 +2124,9 @@ static int dw2102_probe(struct usb_interface *intf, | |||
2149 | 0 == dvb_usb_device_init(intf, s421, | 2124 | 0 == dvb_usb_device_init(intf, s421, |
2150 | THIS_MODULE, NULL, adapter_nr) || | 2125 | THIS_MODULE, NULL, adapter_nr) || |
2151 | 0 == dvb_usb_device_init(intf, &su3000_properties, | 2126 | 0 == dvb_usb_device_init(intf, &su3000_properties, |
2152 | THIS_MODULE, NULL, adapter_nr)) | 2127 | THIS_MODULE, NULL, adapter_nr) || |
2128 | 0 == dvb_usb_device_init(intf, &t220_properties, | ||
2129 | THIS_MODULE, NULL, adapter_nr)) | ||
2153 | return 0; | 2130 | return 0; |
2154 | 2131 | ||
2155 | return -ENODEV; | 2132 | return -ENODEV; |
@@ -2169,7 +2146,7 @@ MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," | |||
2169 | " DVB-C 3101 USB2.0," | 2146 | " DVB-C 3101 USB2.0," |
2170 | " TeVii S600, S630, S650, S660, S480, S421, S632" | 2147 | " TeVii S600, S630, S650, S660, S480, S421, S632" |
2171 | " Prof 1100, 7500 USB2.0," | 2148 | " Prof 1100, 7500 USB2.0," |
2172 | " Geniatech SU3000 devices"); | 2149 | " Geniatech SU3000, T220 devices"); |
2173 | MODULE_VERSION("0.1"); | 2150 | MODULE_VERSION("0.1"); |
2174 | MODULE_LICENSE("GPL"); | 2151 | MODULE_LICENSE("GPL"); |
2175 | MODULE_FIRMWARE(DW2101_FIRMWARE); | 2152 | MODULE_FIRMWARE(DW2101_FIRMWARE); |
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index ca5ee6aceb62..a1fccf3096de 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig | |||
@@ -1,8 +1,12 @@ | |||
1 | config VIDEO_EM28XX | 1 | config VIDEO_EM28XX |
2 | tristate "Empia EM28xx USB video capture support" | 2 | tristate "Empia EM28xx USB devices support" |
3 | depends on VIDEO_DEV && I2C | 3 | depends on VIDEO_DEV && I2C |
4 | select VIDEO_TUNER | 4 | select VIDEO_TUNER |
5 | select VIDEO_TVEEPROM | 5 | select VIDEO_TVEEPROM |
6 | |||
7 | config VIDEO_EM28XX_V4L2 | ||
8 | tristate "Empia EM28xx analog TV, video capture and/or webcam support" | ||
9 | depends on VIDEO_EM28XX | ||
6 | select VIDEOBUF2_VMALLOC | 10 | select VIDEOBUF2_VMALLOC |
7 | select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT | 11 | select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT |
8 | select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT | 12 | select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT |
@@ -49,6 +53,8 @@ config VIDEO_EM28XX_DVB | |||
49 | select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT | 53 | select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT |
50 | select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT | 54 | select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT |
51 | select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT | 55 | select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT |
56 | select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT | ||
57 | select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT | ||
52 | ---help--- | 58 | ---help--- |
53 | This adds support for DVB cards based on the | 59 | This adds support for DVB cards based on the |
54 | Empiatech em28xx chips. | 60 | Empiatech em28xx chips. |
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile index ad6d48557940..3f850d5063d0 100644 --- a/drivers/media/usb/em28xx/Makefile +++ b/drivers/media/usb/em28xx/Makefile | |||
@@ -1,10 +1,11 @@ | |||
1 | em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o | 1 | em28xx-y += em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o |
2 | em28xx-y += em28xx-core.o em28xx-vbi.o em28xx-camera.o | ||
3 | 2 | ||
3 | em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o | ||
4 | em28xx-alsa-objs := em28xx-audio.o | 4 | em28xx-alsa-objs := em28xx-audio.o |
5 | em28xx-rc-objs := em28xx-input.o | 5 | em28xx-rc-objs := em28xx-input.o |
6 | 6 | ||
7 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o | 7 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o |
8 | obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o | ||
8 | obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o | 9 | obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o |
9 | obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o | 10 | obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o |
10 | obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o | 11 | obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o |
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 2fdb66ee44ab..05e9bd11a3ff 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> | 4 | * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> |
5 | * | 5 | * |
6 | * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com> | 6 | * Copyright (C) 2007-2014 Mauro Carvalho Chehab |
7 | * - Port to work with the in-kernel driver | 7 | * - Port to work with the in-kernel driver |
8 | * - Cleanups, fixes, alsa-controls, etc. | 8 | * - Cleanups, fixes, alsa-controls, etc. |
9 | * | 9 | * |
@@ -50,6 +50,9 @@ static int debug; | |||
50 | module_param(debug, int, 0644); | 50 | module_param(debug, int, 0644); |
51 | MODULE_PARM_DESC(debug, "activates debug info"); | 51 | MODULE_PARM_DESC(debug, "activates debug info"); |
52 | 52 | ||
53 | #define EM28XX_MAX_AUDIO_BUFS 5 | ||
54 | #define EM28XX_MIN_AUDIO_PACKETS 64 | ||
55 | |||
53 | #define dprintk(fmt, arg...) do { \ | 56 | #define dprintk(fmt, arg...) do { \ |
54 | if (debug) \ | 57 | if (debug) \ |
55 | printk(KERN_INFO "em28xx-audio %s: " fmt, \ | 58 | printk(KERN_INFO "em28xx-audio %s: " fmt, \ |
@@ -63,17 +66,13 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev) | |||
63 | int i; | 66 | int i; |
64 | 67 | ||
65 | dprintk("Stopping isoc\n"); | 68 | dprintk("Stopping isoc\n"); |
66 | for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { | 69 | for (i = 0; i < dev->adev.num_urb; i++) { |
70 | struct urb *urb = dev->adev.urb[i]; | ||
71 | |||
67 | if (!irqs_disabled()) | 72 | if (!irqs_disabled()) |
68 | usb_kill_urb(dev->adev.urb[i]); | 73 | usb_kill_urb(urb); |
69 | else | 74 | else |
70 | usb_unlink_urb(dev->adev.urb[i]); | 75 | usb_unlink_urb(urb); |
71 | |||
72 | usb_free_urb(dev->adev.urb[i]); | ||
73 | dev->adev.urb[i] = NULL; | ||
74 | |||
75 | kfree(dev->adev.transfer_buffer[i]); | ||
76 | dev->adev.transfer_buffer[i] = NULL; | ||
77 | } | 76 | } |
78 | 77 | ||
79 | return 0; | 78 | return 0; |
@@ -91,6 +90,12 @@ static void em28xx_audio_isocirq(struct urb *urb) | |||
91 | struct snd_pcm_substream *substream; | 90 | struct snd_pcm_substream *substream; |
92 | struct snd_pcm_runtime *runtime; | 91 | struct snd_pcm_runtime *runtime; |
93 | 92 | ||
93 | if (dev->disconnected) { | ||
94 | dprintk("device disconnected while streaming. URB status=%d.\n", urb->status); | ||
95 | atomic_set(&dev->stream_started, 0); | ||
96 | return; | ||
97 | } | ||
98 | |||
94 | switch (urb->status) { | 99 | switch (urb->status) { |
95 | case 0: /* success */ | 100 | case 0: /* success */ |
96 | case -ETIMEDOUT: /* NAK */ | 101 | case -ETIMEDOUT: /* NAK */ |
@@ -158,63 +163,27 @@ static void em28xx_audio_isocirq(struct urb *urb) | |||
158 | urb->status = 0; | 163 | urb->status = 0; |
159 | 164 | ||
160 | status = usb_submit_urb(urb, GFP_ATOMIC); | 165 | status = usb_submit_urb(urb, GFP_ATOMIC); |
161 | if (status < 0) { | 166 | if (status < 0) |
162 | em28xx_errdev("resubmit of audio urb failed (error=%i)\n", | 167 | em28xx_errdev("resubmit of audio urb failed (error=%i)\n", |
163 | status); | 168 | status); |
164 | } | ||
165 | return; | 169 | return; |
166 | } | 170 | } |
167 | 171 | ||
168 | static int em28xx_init_audio_isoc(struct em28xx *dev) | 172 | static int em28xx_init_audio_isoc(struct em28xx *dev) |
169 | { | 173 | { |
170 | int i, errCode; | 174 | int i, errCode; |
171 | const int sb_size = EM28XX_NUM_AUDIO_PACKETS * | ||
172 | EM28XX_AUDIO_MAX_PACKET_SIZE; | ||
173 | 175 | ||
174 | dprintk("Starting isoc transfers\n"); | 176 | dprintk("Starting isoc transfers\n"); |
175 | 177 | ||
176 | for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { | 178 | /* Start streaming */ |
177 | struct urb *urb; | 179 | for (i = 0; i < dev->adev.num_urb; i++) { |
178 | int j, k; | 180 | memset(dev->adev.transfer_buffer[i], 0x80, |
179 | 181 | dev->adev.urb[i]->transfer_buffer_length); | |
180 | dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); | ||
181 | if (!dev->adev.transfer_buffer[i]) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | memset(dev->adev.transfer_buffer[i], 0x80, sb_size); | ||
185 | urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); | ||
186 | if (!urb) { | ||
187 | em28xx_errdev("usb_alloc_urb failed!\n"); | ||
188 | for (j = 0; j < i; j++) { | ||
189 | usb_free_urb(dev->adev.urb[j]); | ||
190 | kfree(dev->adev.transfer_buffer[j]); | ||
191 | } | ||
192 | return -ENOMEM; | ||
193 | } | ||
194 | |||
195 | urb->dev = dev->udev; | ||
196 | urb->context = dev; | ||
197 | urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO); | ||
198 | urb->transfer_flags = URB_ISO_ASAP; | ||
199 | urb->transfer_buffer = dev->adev.transfer_buffer[i]; | ||
200 | urb->interval = 1; | ||
201 | urb->complete = em28xx_audio_isocirq; | ||
202 | urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; | ||
203 | urb->transfer_buffer_length = sb_size; | ||
204 | |||
205 | for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; | ||
206 | j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { | ||
207 | urb->iso_frame_desc[j].offset = k; | ||
208 | urb->iso_frame_desc[j].length = | ||
209 | EM28XX_AUDIO_MAX_PACKET_SIZE; | ||
210 | } | ||
211 | dev->adev.urb[i] = urb; | ||
212 | } | ||
213 | 182 | ||
214 | for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { | ||
215 | errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); | 183 | errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); |
216 | if (errCode) { | 184 | if (errCode) { |
217 | em28xx_errdev("submit of audio urb failed\n"); | 185 | em28xx_errdev("submit of audio urb failed (error=%i)\n", |
186 | errCode); | ||
218 | em28xx_deinit_isoc_audio(dev); | 187 | em28xx_deinit_isoc_audio(dev); |
219 | atomic_set(&dev->stream_started, 0); | 188 | atomic_set(&dev->stream_started, 0); |
220 | return errCode; | 189 | return errCode; |
@@ -255,15 +224,26 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = { | |||
255 | 224 | ||
256 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 225 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
257 | 226 | ||
258 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, | 227 | .rates = SNDRV_PCM_RATE_48000, |
259 | 228 | ||
260 | .rate_min = 48000, | 229 | .rate_min = 48000, |
261 | .rate_max = 48000, | 230 | .rate_max = 48000, |
262 | .channels_min = 2, | 231 | .channels_min = 2, |
263 | .channels_max = 2, | 232 | .channels_max = 2, |
264 | .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ | 233 | .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ |
265 | .period_bytes_min = 64, /* 12544/2, */ | 234 | |
266 | .period_bytes_max = 12544, | 235 | |
236 | /* | ||
237 | * The period is 12.288 bytes. Allow a 10% of variation along its | ||
238 | * value, in order to avoid overruns/underruns due to some clock | ||
239 | * drift. | ||
240 | * | ||
241 | * FIXME: This period assumes 64 packets, and a 48000 PCM rate. | ||
242 | * Calculate it dynamically. | ||
243 | */ | ||
244 | .period_bytes_min = 11059, | ||
245 | .period_bytes_max = 13516, | ||
246 | |||
267 | .periods_min = 2, | 247 | .periods_min = 2, |
268 | .periods_max = 98, /* 12544, */ | 248 | .periods_max = 98, /* 12544, */ |
269 | }; | 249 | }; |
@@ -274,28 +254,48 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) | |||
274 | struct snd_pcm_runtime *runtime = substream->runtime; | 254 | struct snd_pcm_runtime *runtime = substream->runtime; |
275 | int ret = 0; | 255 | int ret = 0; |
276 | 256 | ||
277 | dprintk("opening device and trying to acquire exclusive lock\n"); | ||
278 | |||
279 | if (!dev) { | 257 | if (!dev) { |
280 | em28xx_err("BUG: em28xx can't find device struct." | 258 | em28xx_err("BUG: em28xx can't find device struct." |
281 | " Can't proceed with open\n"); | 259 | " Can't proceed with open\n"); |
282 | return -ENODEV; | 260 | return -ENODEV; |
283 | } | 261 | } |
284 | 262 | ||
263 | if (dev->disconnected) | ||
264 | return -ENODEV; | ||
265 | |||
266 | dprintk("opening device and trying to acquire exclusive lock\n"); | ||
267 | |||
285 | runtime->hw = snd_em28xx_hw_capture; | 268 | runtime->hw = snd_em28xx_hw_capture; |
286 | if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) { | 269 | if ((dev->alt == 0 || dev->is_audio_only) && dev->adev.users == 0) { |
287 | if (dev->audio_ifnum) | 270 | int nonblock = !!(substream->f_flags & O_NONBLOCK); |
271 | |||
272 | if (nonblock) { | ||
273 | if (!mutex_trylock(&dev->lock)) | ||
274 | return -EAGAIN; | ||
275 | } else | ||
276 | mutex_lock(&dev->lock); | ||
277 | if (dev->is_audio_only) | ||
278 | /* vendor audio is on a separate interface */ | ||
288 | dev->alt = 1; | 279 | dev->alt = 1; |
289 | else | 280 | else |
281 | /* vendor audio is on the same interface as video */ | ||
290 | dev->alt = 7; | 282 | dev->alt = 7; |
283 | /* | ||
284 | * FIXME: The intention seems to be to select the alt | ||
285 | * setting with the largest wMaxPacketSize for the video | ||
286 | * endpoint. | ||
287 | * At least dev->alt should be used instead, but we | ||
288 | * should probably not touch it at all if it is | ||
289 | * already >0, because wMaxPacketSize of the audio | ||
290 | * endpoints seems to be the same for all. | ||
291 | */ | ||
291 | 292 | ||
292 | dprintk("changing alternate number on interface %d to %d\n", | 293 | dprintk("changing alternate number on interface %d to %d\n", |
293 | dev->audio_ifnum, dev->alt); | 294 | dev->ifnum, dev->alt); |
294 | usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt); | 295 | usb_set_interface(dev->udev, dev->ifnum, dev->alt); |
295 | 296 | ||
296 | /* Sets volume, mute, etc */ | 297 | /* Sets volume, mute, etc */ |
297 | dev->mute = 0; | 298 | dev->mute = 0; |
298 | mutex_lock(&dev->lock); | ||
299 | ret = em28xx_audio_analog_set(dev); | 299 | ret = em28xx_audio_analog_set(dev); |
300 | if (ret < 0) | 300 | if (ret < 0) |
301 | goto err; | 301 | goto err; |
@@ -304,7 +304,12 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) | |||
304 | mutex_unlock(&dev->lock); | 304 | mutex_unlock(&dev->lock); |
305 | } | 305 | } |
306 | 306 | ||
307 | /* Dynamically adjust the period size */ | ||
307 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | 308 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); |
309 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
310 | dev->adev.period * 95 / 100, | ||
311 | dev->adev.period * 105 / 100); | ||
312 | |||
308 | dev->adev.capture_pcm_substream = substream; | 313 | dev->adev.capture_pcm_substream = substream; |
309 | 314 | ||
310 | return 0; | 315 | return 0; |
@@ -344,6 +349,10 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, | |||
344 | struct snd_pcm_hw_params *hw_params) | 349 | struct snd_pcm_hw_params *hw_params) |
345 | { | 350 | { |
346 | int ret; | 351 | int ret; |
352 | struct em28xx *dev = snd_pcm_substream_chip(substream); | ||
353 | |||
354 | if (dev->disconnected) | ||
355 | return -ENODEV; | ||
347 | 356 | ||
348 | dprintk("Setting capture parameters\n"); | 357 | dprintk("Setting capture parameters\n"); |
349 | 358 | ||
@@ -383,6 +392,9 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream) | |||
383 | { | 392 | { |
384 | struct em28xx *dev = snd_pcm_substream_chip(substream); | 393 | struct em28xx *dev = snd_pcm_substream_chip(substream); |
385 | 394 | ||
395 | if (dev->disconnected) | ||
396 | return -ENODEV; | ||
397 | |||
386 | dev->adev.hwptr_done_capture = 0; | 398 | dev->adev.hwptr_done_capture = 0; |
387 | dev->adev.capture_transfer_done = 0; | 399 | dev->adev.capture_transfer_done = 0; |
388 | 400 | ||
@@ -408,6 +420,9 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, | |||
408 | struct em28xx *dev = snd_pcm_substream_chip(substream); | 420 | struct em28xx *dev = snd_pcm_substream_chip(substream); |
409 | int retval = 0; | 421 | int retval = 0; |
410 | 422 | ||
423 | if (dev->disconnected) | ||
424 | return -ENODEV; | ||
425 | |||
411 | switch (cmd) { | 426 | switch (cmd) { |
412 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ | 427 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ |
413 | case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ | 428 | case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ |
@@ -434,6 +449,9 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream | |||
434 | snd_pcm_uframes_t hwptr_done; | 449 | snd_pcm_uframes_t hwptr_done; |
435 | 450 | ||
436 | dev = snd_pcm_substream_chip(substream); | 451 | dev = snd_pcm_substream_chip(substream); |
452 | if (dev->disconnected) | ||
453 | return SNDRV_PCM_POS_XRUN; | ||
454 | |||
437 | spin_lock_irqsave(&dev->adev.slock, flags); | 455 | spin_lock_irqsave(&dev->adev.slock, flags); |
438 | hwptr_done = dev->adev.hwptr_done_capture; | 456 | hwptr_done = dev->adev.hwptr_done_capture; |
439 | spin_unlock_irqrestore(&dev->adev.slock, flags); | 457 | spin_unlock_irqrestore(&dev->adev.slock, flags); |
@@ -455,6 +473,11 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | |||
455 | static int em28xx_vol_info(struct snd_kcontrol *kcontrol, | 473 | static int em28xx_vol_info(struct snd_kcontrol *kcontrol, |
456 | struct snd_ctl_elem_info *info) | 474 | struct snd_ctl_elem_info *info) |
457 | { | 475 | { |
476 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); | ||
477 | |||
478 | if (dev->disconnected) | ||
479 | return -ENODEV; | ||
480 | |||
458 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 481 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
459 | info->count = 2; | 482 | info->count = 2; |
460 | info->value.integer.min = 0; | 483 | info->value.integer.min = 0; |
@@ -467,11 +490,22 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol, | |||
467 | struct snd_ctl_elem_value *value) | 490 | struct snd_ctl_elem_value *value) |
468 | { | 491 | { |
469 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); | 492 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); |
493 | struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; | ||
470 | u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) | | 494 | u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) | |
471 | (0x1f - (value->value.integer.value[1] & 0x1f)) << 8; | 495 | (0x1f - (value->value.integer.value[1] & 0x1f)) << 8; |
496 | int nonblock = 0; | ||
472 | int rc; | 497 | int rc; |
473 | 498 | ||
474 | mutex_lock(&dev->lock); | 499 | if (dev->disconnected) |
500 | return -ENODEV; | ||
501 | |||
502 | if (substream) | ||
503 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
504 | if (nonblock) { | ||
505 | if (!mutex_trylock(&dev->lock)) | ||
506 | return -EAGAIN; | ||
507 | } else | ||
508 | mutex_lock(&dev->lock); | ||
475 | rc = em28xx_read_ac97(dev, kcontrol->private_value); | 509 | rc = em28xx_read_ac97(dev, kcontrol->private_value); |
476 | if (rc < 0) | 510 | if (rc < 0) |
477 | goto err; | 511 | goto err; |
@@ -496,9 +530,20 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol, | |||
496 | struct snd_ctl_elem_value *value) | 530 | struct snd_ctl_elem_value *value) |
497 | { | 531 | { |
498 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); | 532 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); |
533 | struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; | ||
534 | int nonblock = 0; | ||
499 | int val; | 535 | int val; |
500 | 536 | ||
501 | mutex_lock(&dev->lock); | 537 | if (dev->disconnected) |
538 | return -ENODEV; | ||
539 | |||
540 | if (substream) | ||
541 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
542 | if (nonblock) { | ||
543 | if (!mutex_trylock(&dev->lock)) | ||
544 | return -EAGAIN; | ||
545 | } else | ||
546 | mutex_lock(&dev->lock); | ||
502 | val = em28xx_read_ac97(dev, kcontrol->private_value); | 547 | val = em28xx_read_ac97(dev, kcontrol->private_value); |
503 | mutex_unlock(&dev->lock); | 548 | mutex_unlock(&dev->lock); |
504 | if (val < 0) | 549 | if (val < 0) |
@@ -520,9 +565,20 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, | |||
520 | { | 565 | { |
521 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); | 566 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); |
522 | u16 val = value->value.integer.value[0]; | 567 | u16 val = value->value.integer.value[0]; |
568 | struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; | ||
569 | int nonblock = 0; | ||
523 | int rc; | 570 | int rc; |
524 | 571 | ||
525 | mutex_lock(&dev->lock); | 572 | if (dev->disconnected) |
573 | return -ENODEV; | ||
574 | |||
575 | if (substream) | ||
576 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
577 | if (nonblock) { | ||
578 | if (!mutex_trylock(&dev->lock)) | ||
579 | return -EAGAIN; | ||
580 | } else | ||
581 | mutex_lock(&dev->lock); | ||
526 | rc = em28xx_read_ac97(dev, kcontrol->private_value); | 582 | rc = em28xx_read_ac97(dev, kcontrol->private_value); |
527 | if (rc < 0) | 583 | if (rc < 0) |
528 | goto err; | 584 | goto err; |
@@ -550,9 +606,20 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, | |||
550 | struct snd_ctl_elem_value *value) | 606 | struct snd_ctl_elem_value *value) |
551 | { | 607 | { |
552 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); | 608 | struct em28xx *dev = snd_kcontrol_chip(kcontrol); |
609 | struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; | ||
610 | int nonblock = 0; | ||
553 | int val; | 611 | int val; |
554 | 612 | ||
555 | mutex_lock(&dev->lock); | 613 | if (dev->disconnected) |
614 | return -ENODEV; | ||
615 | |||
616 | if (substream) | ||
617 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
618 | if (nonblock) { | ||
619 | if (!mutex_trylock(&dev->lock)) | ||
620 | return -EAGAIN; | ||
621 | } else | ||
622 | mutex_lock(&dev->lock); | ||
556 | val = em28xx_read_ac97(dev, kcontrol->private_value); | 623 | val = em28xx_read_ac97(dev, kcontrol->private_value); |
557 | mutex_unlock(&dev->lock); | 624 | mutex_unlock(&dev->lock); |
558 | if (val < 0) | 625 | if (val < 0) |
@@ -634,25 +701,204 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = { | |||
634 | .page = snd_pcm_get_vmalloc_page, | 701 | .page = snd_pcm_get_vmalloc_page, |
635 | }; | 702 | }; |
636 | 703 | ||
704 | static void em28xx_audio_free_urb(struct em28xx *dev) | ||
705 | { | ||
706 | int i; | ||
707 | |||
708 | for (i = 0; i < dev->adev.num_urb; i++) { | ||
709 | struct urb *urb = dev->adev.urb[i]; | ||
710 | |||
711 | if (!urb) | ||
712 | continue; | ||
713 | |||
714 | usb_free_coherent(dev->udev, urb->transfer_buffer_length, | ||
715 | dev->adev.transfer_buffer[i], | ||
716 | urb->transfer_dma); | ||
717 | |||
718 | usb_free_urb(urb); | ||
719 | } | ||
720 | kfree(dev->adev.urb); | ||
721 | kfree(dev->adev.transfer_buffer); | ||
722 | dev->adev.num_urb = 0; | ||
723 | } | ||
724 | |||
725 | /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ | ||
726 | static int em28xx_audio_ep_packet_size(struct usb_device *udev, | ||
727 | struct usb_endpoint_descriptor *e) | ||
728 | { | ||
729 | int size = le16_to_cpu(e->wMaxPacketSize); | ||
730 | |||
731 | if (udev->speed == USB_SPEED_HIGH) | ||
732 | return (size & 0x7ff) * (1 + (((size) >> 11) & 0x03)); | ||
733 | |||
734 | return size & 0x7ff; | ||
735 | } | ||
736 | |||
737 | static int em28xx_audio_urb_init(struct em28xx *dev) | ||
738 | { | ||
739 | struct usb_interface *intf; | ||
740 | struct usb_endpoint_descriptor *e, *ep = NULL; | ||
741 | int i, ep_size, interval, num_urb, npackets; | ||
742 | int urb_size, bytes_per_transfer; | ||
743 | u8 alt; | ||
744 | |||
745 | if (dev->ifnum) | ||
746 | alt = 1; | ||
747 | else | ||
748 | alt = 7; | ||
749 | |||
750 | intf = usb_ifnum_to_if(dev->udev, dev->ifnum); | ||
751 | |||
752 | if (intf->num_altsetting <= alt) { | ||
753 | em28xx_errdev("alt %d doesn't exist on interface %d\n", | ||
754 | dev->ifnum, alt); | ||
755 | return -ENODEV; | ||
756 | } | ||
757 | |||
758 | for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) { | ||
759 | e = &intf->altsetting[alt].endpoint[i].desc; | ||
760 | if (!usb_endpoint_dir_in(e)) | ||
761 | continue; | ||
762 | if (e->bEndpointAddress == EM28XX_EP_AUDIO) { | ||
763 | ep = e; | ||
764 | break; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | if (!ep) { | ||
769 | em28xx_errdev("Couldn't find an audio endpoint"); | ||
770 | return -ENODEV; | ||
771 | } | ||
772 | |||
773 | ep_size = em28xx_audio_ep_packet_size(dev->udev, ep); | ||
774 | interval = 1 << (ep->bInterval - 1); | ||
775 | |||
776 | em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", | ||
777 | EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed), | ||
778 | dev->ifnum, alt, | ||
779 | interval, | ||
780 | ep_size); | ||
781 | |||
782 | /* Calculate the number and size of URBs to better fit the audio samples */ | ||
783 | |||
784 | /* | ||
785 | * Estimate the number of bytes per DMA transfer. | ||
786 | * | ||
787 | * This is given by the bit rate (for now, only 48000 Hz) multiplied | ||
788 | * by 2 channels and 2 bytes/sample divided by the number of microframe | ||
789 | * intervals and by the microframe rate (125 us) | ||
790 | */ | ||
791 | bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval); | ||
792 | |||
793 | /* | ||
794 | * Estimate the number of transfer URBs. Don't let it go past the | ||
795 | * maximum number of URBs that is known to be supported by the device. | ||
796 | */ | ||
797 | num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size); | ||
798 | if (num_urb > EM28XX_MAX_AUDIO_BUFS) | ||
799 | num_urb = EM28XX_MAX_AUDIO_BUFS; | ||
800 | |||
801 | /* | ||
802 | * Now that we know the number of bytes per transfer and the number of | ||
803 | * URBs, estimate the typical size of an URB, in order to adjust the | ||
804 | * minimal number of packets. | ||
805 | */ | ||
806 | urb_size = bytes_per_transfer / num_urb; | ||
807 | |||
808 | /* | ||
809 | * Now, calculate the amount of audio packets to be filled on each | ||
810 | * URB. In order to preserve the old behaviour, use a minimal | ||
811 | * threshold for this value. | ||
812 | */ | ||
813 | npackets = EM28XX_MIN_AUDIO_PACKETS; | ||
814 | if (urb_size > ep_size * npackets) | ||
815 | npackets = DIV_ROUND_UP(urb_size, ep_size); | ||
816 | |||
817 | em28xx_info("Number of URBs: %d, with %d packets and %d size", | ||
818 | num_urb, npackets, urb_size); | ||
819 | |||
820 | /* Estimate the bytes per period */ | ||
821 | dev->adev.period = urb_size * npackets; | ||
822 | |||
823 | /* Allocate space to store the number of URBs to be used */ | ||
824 | |||
825 | dev->adev.transfer_buffer = kcalloc(num_urb, | ||
826 | sizeof(*dev->adev.transfer_buffer), | ||
827 | GFP_ATOMIC); | ||
828 | if (!dev->adev.transfer_buffer) { | ||
829 | return -ENOMEM; | ||
830 | } | ||
831 | |||
832 | dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC); | ||
833 | if (!dev->adev.urb) { | ||
834 | kfree(dev->adev.transfer_buffer); | ||
835 | return -ENOMEM; | ||
836 | } | ||
837 | |||
838 | /* Alloc memory for each URB and for each transfer buffer */ | ||
839 | dev->adev.num_urb = num_urb; | ||
840 | for (i = 0; i < num_urb; i++) { | ||
841 | struct urb *urb; | ||
842 | int j, k; | ||
843 | void *buf; | ||
844 | |||
845 | urb = usb_alloc_urb(npackets, GFP_ATOMIC); | ||
846 | if (!urb) { | ||
847 | em28xx_errdev("usb_alloc_urb failed!\n"); | ||
848 | em28xx_audio_free_urb(dev); | ||
849 | return -ENOMEM; | ||
850 | } | ||
851 | dev->adev.urb[i] = urb; | ||
852 | |||
853 | buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC, | ||
854 | &urb->transfer_dma); | ||
855 | if (!buf) { | ||
856 | em28xx_errdev("usb_alloc_coherent failed!\n"); | ||
857 | em28xx_audio_free_urb(dev); | ||
858 | return -ENOMEM; | ||
859 | } | ||
860 | dev->adev.transfer_buffer[i] = buf; | ||
861 | |||
862 | urb->dev = dev->udev; | ||
863 | urb->context = dev; | ||
864 | urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO); | ||
865 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | ||
866 | urb->transfer_buffer = buf; | ||
867 | urb->interval = interval; | ||
868 | urb->complete = em28xx_audio_isocirq; | ||
869 | urb->number_of_packets = npackets; | ||
870 | urb->transfer_buffer_length = ep_size * npackets; | ||
871 | |||
872 | for (j = k = 0; j < npackets; j++, k += ep_size) { | ||
873 | urb->iso_frame_desc[j].offset = k; | ||
874 | urb->iso_frame_desc[j].length = ep_size; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
637 | static int em28xx_audio_init(struct em28xx *dev) | 881 | static int em28xx_audio_init(struct em28xx *dev) |
638 | { | 882 | { |
639 | struct em28xx_audio *adev = &dev->adev; | 883 | struct em28xx_audio *adev = &dev->adev; |
640 | struct snd_pcm *pcm; | 884 | struct snd_pcm *pcm; |
641 | struct snd_card *card; | 885 | struct snd_card *card; |
642 | static int devnr; | 886 | static int devnr; |
643 | int err; | 887 | int err; |
644 | 888 | ||
645 | if (!dev->has_alsa_audio || dev->audio_ifnum < 0) { | 889 | if (!dev->has_alsa_audio) { |
646 | /* This device does not support the extension (in this case | 890 | /* This device does not support the extension (in this case |
647 | the device is expecting the snd-usb-audio module or | 891 | the device is expecting the snd-usb-audio module or |
648 | doesn't have analog audio support at all) */ | 892 | doesn't have analog audio support at all) */ |
649 | return 0; | 893 | return 0; |
650 | } | 894 | } |
651 | 895 | ||
652 | printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n"); | 896 | em28xx_info("Binding audio extension\n"); |
897 | |||
653 | printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " | 898 | printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " |
654 | "Rechberger\n"); | 899 | "Rechberger\n"); |
655 | printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n"); | 900 | printk(KERN_INFO |
901 | "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n"); | ||
656 | 902 | ||
657 | err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, | 903 | err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, |
658 | &card); | 904 | &card); |
@@ -660,11 +906,12 @@ static int em28xx_audio_init(struct em28xx *dev) | |||
660 | return err; | 906 | return err; |
661 | 907 | ||
662 | spin_lock_init(&adev->slock); | 908 | spin_lock_init(&adev->slock); |
909 | adev->sndcard = card; | ||
910 | adev->udev = dev->udev; | ||
911 | |||
663 | err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); | 912 | err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); |
664 | if (err < 0) { | 913 | if (err < 0) |
665 | snd_card_free(card); | 914 | goto card_free; |
666 | return err; | ||
667 | } | ||
668 | 915 | ||
669 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); | 916 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); |
670 | pcm->info_flags = 0; | 917 | pcm->info_flags = 0; |
@@ -694,15 +941,25 @@ static int em28xx_audio_init(struct em28xx *dev) | |||
694 | em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER); | 941 | em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER); |
695 | } | 942 | } |
696 | 943 | ||
944 | err = em28xx_audio_urb_init(dev); | ||
945 | if (err) | ||
946 | goto card_free; | ||
947 | |||
697 | err = snd_card_register(card); | 948 | err = snd_card_register(card); |
698 | if (err < 0) { | 949 | if (err < 0) |
699 | snd_card_free(card); | 950 | goto urb_free; |
700 | return err; | ||
701 | } | ||
702 | adev->sndcard = card; | ||
703 | adev->udev = dev->udev; | ||
704 | 951 | ||
952 | em28xx_info("Audio extension successfully initialized\n"); | ||
705 | return 0; | 953 | return 0; |
954 | |||
955 | urb_free: | ||
956 | em28xx_audio_free_urb(dev); | ||
957 | |||
958 | card_free: | ||
959 | snd_card_free(card); | ||
960 | adev->sndcard = NULL; | ||
961 | |||
962 | return err; | ||
706 | } | 963 | } |
707 | 964 | ||
708 | static int em28xx_audio_fini(struct em28xx *dev) | 965 | static int em28xx_audio_fini(struct em28xx *dev) |
@@ -717,7 +974,14 @@ static int em28xx_audio_fini(struct em28xx *dev) | |||
717 | return 0; | 974 | return 0; |
718 | } | 975 | } |
719 | 976 | ||
977 | em28xx_info("Closing audio extension"); | ||
978 | |||
720 | if (dev->adev.sndcard) { | 979 | if (dev->adev.sndcard) { |
980 | snd_card_disconnect(dev->adev.sndcard); | ||
981 | flush_work(&dev->wq_trigger); | ||
982 | |||
983 | em28xx_audio_free_urb(dev); | ||
984 | |||
721 | snd_card_free(dev->adev.sndcard); | 985 | snd_card_free(dev->adev.sndcard); |
722 | dev->adev.sndcard = NULL; | 986 | dev->adev.sndcard = NULL; |
723 | } | 987 | } |
@@ -745,7 +1009,8 @@ static void __exit em28xx_alsa_unregister(void) | |||
745 | MODULE_LICENSE("GPL"); | 1009 | MODULE_LICENSE("GPL"); |
746 | MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); | 1010 | MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); |
747 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | 1011 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); |
748 | MODULE_DESCRIPTION("Em28xx Audio driver"); | 1012 | MODULE_DESCRIPTION(DRIVER_DESC " - audio interface"); |
1013 | MODULE_VERSION(EM28XX_VERSION); | ||
749 | 1014 | ||
750 | module_init(em28xx_alsa_register); | 1015 | module_init(em28xx_alsa_register); |
751 | module_exit(em28xx_alsa_unregister); | 1016 | module_exit(em28xx_alsa_unregister); |
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index d666741797d4..c29f5c4e7b40 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c | |||
@@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev) | |||
454 | 454 | ||
455 | return ret; | 455 | return ret; |
456 | } | 456 | } |
457 | EXPORT_SYMBOL_GPL(em28xx_init_camera); | ||
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index a5196697627f..4d97a76cc3b0 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <media/tvaudio.h> | 36 | #include <media/tvaudio.h> |
37 | #include <media/i2c-addr.h> | 37 | #include <media/i2c-addr.h> |
38 | #include <media/tveeprom.h> | 38 | #include <media/tveeprom.h> |
39 | #include <media/v4l2-clk.h> | ||
40 | #include <media/v4l2-common.h> | 39 | #include <media/v4l2-common.h> |
41 | 40 | ||
42 | #include "em28xx.h" | 41 | #include "em28xx.h" |
@@ -67,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode, | |||
67 | 66 | ||
68 | 67 | ||
69 | /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */ | 68 | /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */ |
70 | static unsigned long em28xx_devused; | 69 | DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS); |
71 | 70 | ||
72 | struct em28xx_hash_table { | 71 | struct em28xx_hash_table { |
73 | unsigned long hash; | 72 | unsigned long hash; |
@@ -356,6 +355,28 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { | |||
356 | { -1, -1, -1, -1}, | 355 | { -1, -1, -1, -1}, |
357 | }; | 356 | }; |
358 | 357 | ||
358 | /* | ||
359 | * 2013:0258 PCTV DVB-S2 Stick (461e) | ||
360 | * GPIO 0 = POWER_ON | ||
361 | * GPIO 1 = BOOST | ||
362 | * GPIO 2 = VUV_LNB (red LED) | ||
363 | * GPIO 3 = #EXT_12V | ||
364 | * GPIO 4 = INT_DEM | ||
365 | * GPIO 5 = INT_LNB | ||
366 | * GPIO 6 = #RESET_DEM | ||
367 | * GPIO 7 = P07_LED (green LED) | ||
368 | */ | ||
369 | static struct em28xx_reg_seq pctv_461e[] = { | ||
370 | {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 0}, | ||
371 | {0x0d, 0xff, 0xff, 0}, | ||
372 | {EM2874_R80_GPIO_P0_CTRL, 0x3f, 0xff, 100}, /* reset demod */ | ||
373 | {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 200}, /* reset demod */ | ||
374 | {0x0d, 0x42, 0xff, 0}, | ||
375 | {EM2874_R80_GPIO_P0_CTRL, 0xeb, 0xff, 0}, | ||
376 | {EM2874_R5F_TS_ENABLE, 0x84, 0x84, 0}, /* parallel? | null discard */ | ||
377 | { -1, -1, -1, -1}, | ||
378 | }; | ||
379 | |||
359 | #if 0 | 380 | #if 0 |
360 | static struct em28xx_reg_seq hauppauge_930c_gpio[] = { | 381 | static struct em28xx_reg_seq hauppauge_930c_gpio[] = { |
361 | {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10}, | 382 | {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10}, |
@@ -412,6 +433,70 @@ static struct em28xx_reg_seq pctv_520e[] = { | |||
412 | { -1, -1, -1, -1}, | 433 | { -1, -1, -1, -1}, |
413 | }; | 434 | }; |
414 | 435 | ||
436 | /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam | ||
437 | * reg 0x80/0x84: | ||
438 | * GPIO_0: capturing LED, 0=on, 1=off | ||
439 | * GPIO_2: AV mute button, 0=pressed, 1=unpressed | ||
440 | * GPIO 3: illumination button, 0=pressed, 1=unpressed | ||
441 | * GPIO_6: illumination/flash LED, 0=on, 1=off | ||
442 | * reg 0x81/0x85: | ||
443 | * GPIO_7: snapshot button, 0=pressed, 1=unpressed | ||
444 | */ | ||
445 | static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = { | ||
446 | {EM2820_R08_GPIO_CTRL, 0xf7, 0xff, 10}, | ||
447 | {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xb2, 10}, | ||
448 | { -1, -1, -1, -1}, | ||
449 | }; | ||
450 | |||
451 | /* | ||
452 | * Button definitions | ||
453 | */ | ||
454 | static struct em28xx_button std_snapshot_button[] = { | ||
455 | { | ||
456 | .role = EM28XX_BUTTON_SNAPSHOT, | ||
457 | .reg_r = EM28XX_R0C_USBSUSP, | ||
458 | .reg_clearing = EM28XX_R0C_USBSUSP, | ||
459 | .mask = EM28XX_R0C_USBSUSP_SNAPSHOT, | ||
460 | .inverted = 0, | ||
461 | }, | ||
462 | {-1, 0, 0, 0, 0}, | ||
463 | }; | ||
464 | |||
465 | static struct em28xx_button speedlink_vad_laplace_buttons[] = { | ||
466 | { | ||
467 | .role = EM28XX_BUTTON_SNAPSHOT, | ||
468 | .reg_r = EM2874_R85_GPIO_P1_STATE, | ||
469 | .mask = 0x80, | ||
470 | .inverted = 1, | ||
471 | }, | ||
472 | { | ||
473 | .role = EM28XX_BUTTON_ILLUMINATION, | ||
474 | .reg_r = EM2874_R84_GPIO_P0_STATE, | ||
475 | .mask = 0x08, | ||
476 | .inverted = 1, | ||
477 | }, | ||
478 | {-1, 0, 0, 0, 0}, | ||
479 | }; | ||
480 | |||
481 | /* | ||
482 | * LED definitions | ||
483 | */ | ||
484 | static struct em28xx_led speedlink_vad_laplace_leds[] = { | ||
485 | { | ||
486 | .role = EM28XX_LED_ANALOG_CAPTURING, | ||
487 | .gpio_reg = EM2874_R80_GPIO_P0_CTRL, | ||
488 | .gpio_mask = 0x01, | ||
489 | .inverted = 1, | ||
490 | }, | ||
491 | { | ||
492 | .role = EM28XX_LED_ILLUMINATION, | ||
493 | .gpio_reg = EM2874_R80_GPIO_P0_CTRL, | ||
494 | .gpio_mask = 0x40, | ||
495 | .inverted = 1, | ||
496 | }, | ||
497 | {-1, 0, 0, 0}, | ||
498 | }; | ||
499 | |||
415 | /* | 500 | /* |
416 | * Board definitions | 501 | * Board definitions |
417 | */ | 502 | */ |
@@ -1391,7 +1476,7 @@ struct em28xx_board em28xx_boards[] = { | |||
1391 | }, | 1476 | }, |
1392 | [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { | 1477 | [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { |
1393 | .name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0", | 1478 | .name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0", |
1394 | .has_snapshot_button = 1, | 1479 | .buttons = std_snapshot_button, |
1395 | .tda9887_conf = TDA9887_PRESENT, | 1480 | .tda9887_conf = TDA9887_PRESENT, |
1396 | .tuner_type = TUNER_YMEC_TVF_5533MF, | 1481 | .tuner_type = TUNER_YMEC_TVF_5533MF, |
1397 | .decoder = EM28XX_SAA711X, | 1482 | .decoder = EM28XX_SAA711X, |
@@ -1413,7 +1498,7 @@ struct em28xx_board em28xx_boards[] = { | |||
1413 | }, | 1498 | }, |
1414 | [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = { | 1499 | [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = { |
1415 | .name = "EM2860/SAA711X Reference Design", | 1500 | .name = "EM2860/SAA711X Reference Design", |
1416 | .has_snapshot_button = 1, | 1501 | .buttons = std_snapshot_button, |
1417 | .tuner_type = TUNER_ABSENT, | 1502 | .tuner_type = TUNER_ABSENT, |
1418 | .decoder = EM28XX_SAA711X, | 1503 | .decoder = EM28XX_SAA711X, |
1419 | .input = { { | 1504 | .input = { { |
@@ -2020,7 +2105,7 @@ struct em28xx_board em28xx_boards[] = { | |||
2020 | }, | 2105 | }, |
2021 | /* 1b80:e1cc Delock 61959 | 2106 | /* 1b80:e1cc Delock 61959 |
2022 | * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 | 2107 | * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 |
2023 | * mostly the same as MaxMedia UB-425-TC but different remote */ | 2108 | * mostly the same as MaxMedia UB-425-TC but different remote */ |
2024 | [EM2874_BOARD_DELOCK_61959] = { | 2109 | [EM2874_BOARD_DELOCK_61959] = { |
2025 | .name = "Delock 61959", | 2110 | .name = "Delock 61959", |
2026 | .tuner_type = TUNER_ABSENT, | 2111 | .tuner_type = TUNER_ABSENT, |
@@ -2043,7 +2128,38 @@ struct em28xx_board em28xx_boards[] = { | |||
2043 | .tuner_gpio = default_tuner_gpio, | 2128 | .tuner_gpio = default_tuner_gpio, |
2044 | .def_i2c_bus = 1, | 2129 | .def_i2c_bus = 1, |
2045 | }, | 2130 | }, |
2131 | /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam | ||
2132 | * Empia EM2765 + OmniVision OV2640 */ | ||
2133 | [EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = { | ||
2134 | .name = "SpeedLink Vicious And Devine Laplace webcam", | ||
2135 | .xclk = EM28XX_XCLK_FREQUENCY_24MHZ, | ||
2136 | .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | | ||
2137 | EM28XX_I2C_FREQ_100_KHZ, | ||
2138 | .def_i2c_bus = 1, | ||
2139 | .tuner_type = TUNER_ABSENT, | ||
2140 | .is_webcam = 1, | ||
2141 | .input = { { | ||
2142 | .type = EM28XX_VMUX_COMPOSITE1, | ||
2143 | .amux = EM28XX_AMUX_VIDEO, | ||
2144 | .gpio = speedlink_vad_laplace_reg_seq, | ||
2145 | } }, | ||
2146 | .buttons = speedlink_vad_laplace_buttons, | ||
2147 | .leds = speedlink_vad_laplace_leds, | ||
2148 | }, | ||
2149 | /* 2013:0258 PCTV DVB-S2 Stick (461e) | ||
2150 | * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */ | ||
2151 | [EM28178_BOARD_PCTV_461E] = { | ||
2152 | .def_i2c_bus = 1, | ||
2153 | .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, | ||
2154 | .name = "PCTV DVB-S2 Stick (461e)", | ||
2155 | .tuner_type = TUNER_ABSENT, | ||
2156 | .tuner_gpio = pctv_461e, | ||
2157 | .has_dvb = 1, | ||
2158 | .ir_codes = RC_MAP_PINNACLE_PCTV_HD, | ||
2159 | }, | ||
2046 | }; | 2160 | }; |
2161 | EXPORT_SYMBOL_GPL(em28xx_boards); | ||
2162 | |||
2047 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); | 2163 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); |
2048 | 2164 | ||
2049 | /* table of devices that work with this driver */ | 2165 | /* table of devices that work with this driver */ |
@@ -2208,6 +2324,12 @@ struct usb_device_id em28xx_id_table[] = { | |||
2208 | .driver_info = EM2884_BOARD_PCTV_520E }, | 2324 | .driver_info = EM2884_BOARD_PCTV_520E }, |
2209 | { USB_DEVICE(0x1b80, 0xe1cc), | 2325 | { USB_DEVICE(0x1b80, 0xe1cc), |
2210 | .driver_info = EM2874_BOARD_DELOCK_61959 }, | 2326 | .driver_info = EM2874_BOARD_DELOCK_61959 }, |
2327 | { USB_DEVICE(0x1ae7, 0x9003), | ||
2328 | .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, | ||
2329 | { USB_DEVICE(0x1ae7, 0x9004), | ||
2330 | .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, | ||
2331 | { USB_DEVICE(0x2013, 0x0258), | ||
2332 | .driver_info = EM28178_BOARD_PCTV_461E }, | ||
2211 | { }, | 2333 | { }, |
2212 | }; | 2334 | }; |
2213 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); | 2335 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); |
@@ -2239,24 +2361,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { | |||
2239 | }; | 2361 | }; |
2240 | /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */ | 2362 | /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */ |
2241 | 2363 | ||
2242 | /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ | ||
2243 | static unsigned short saa711x_addrs[] = { | ||
2244 | 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ | ||
2245 | 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ | ||
2246 | I2C_CLIENT_END }; | ||
2247 | |||
2248 | static unsigned short tvp5150_addrs[] = { | ||
2249 | 0xb8 >> 1, | ||
2250 | 0xba >> 1, | ||
2251 | I2C_CLIENT_END | ||
2252 | }; | ||
2253 | |||
2254 | static unsigned short msp3400_addrs[] = { | ||
2255 | 0x80 >> 1, | ||
2256 | 0x88 >> 1, | ||
2257 | I2C_CLIENT_END | ||
2258 | }; | ||
2259 | |||
2260 | int em28xx_tuner_callback(void *ptr, int component, int command, int arg) | 2364 | int em28xx_tuner_callback(void *ptr, int component, int command, int arg) |
2261 | { | 2365 | { |
2262 | struct em28xx_i2c_bus *i2c_bus = ptr; | 2366 | struct em28xx_i2c_bus *i2c_bus = ptr; |
@@ -2408,113 +2512,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev) | |||
2408 | em28xx_set_mode(dev, EM28XX_SUSPEND); | 2512 | em28xx_set_mode(dev, EM28XX_SUSPEND); |
2409 | } | 2513 | } |
2410 | 2514 | ||
2411 | static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) | ||
2412 | { | ||
2413 | memset(ctl, 0, sizeof(*ctl)); | ||
2414 | |||
2415 | ctl->fname = XC2028_DEFAULT_FIRMWARE; | ||
2416 | ctl->max_len = 64; | ||
2417 | ctl->mts = em28xx_boards[dev->model].mts_firmware; | ||
2418 | |||
2419 | switch (dev->model) { | ||
2420 | case EM2880_BOARD_EMPIRE_DUAL_TV: | ||
2421 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | ||
2422 | case EM2882_BOARD_TERRATEC_HYBRID_XS: | ||
2423 | ctl->demod = XC3028_FE_ZARLINK456; | ||
2424 | break; | ||
2425 | case EM2880_BOARD_TERRATEC_HYBRID_XS: | ||
2426 | case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: | ||
2427 | case EM2881_BOARD_PINNACLE_HYBRID_PRO: | ||
2428 | ctl->demod = XC3028_FE_ZARLINK456; | ||
2429 | break; | ||
2430 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: | ||
2431 | case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: | ||
2432 | ctl->demod = XC3028_FE_DEFAULT; | ||
2433 | break; | ||
2434 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: | ||
2435 | ctl->demod = XC3028_FE_DEFAULT; | ||
2436 | ctl->fname = XC3028L_DEFAULT_FIRMWARE; | ||
2437 | break; | ||
2438 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: | ||
2439 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | ||
2440 | case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: | ||
2441 | /* FIXME: Better to specify the needed IF */ | ||
2442 | ctl->demod = XC3028_FE_DEFAULT; | ||
2443 | break; | ||
2444 | case EM2883_BOARD_KWORLD_HYBRID_330U: | ||
2445 | case EM2882_BOARD_DIKOM_DK300: | ||
2446 | case EM2882_BOARD_KWORLD_VS_DVBT: | ||
2447 | ctl->demod = XC3028_FE_CHINA; | ||
2448 | ctl->fname = XC2028_DEFAULT_FIRMWARE; | ||
2449 | break; | ||
2450 | case EM2882_BOARD_EVGA_INDTUBE: | ||
2451 | ctl->demod = XC3028_FE_CHINA; | ||
2452 | ctl->fname = XC3028L_DEFAULT_FIRMWARE; | ||
2453 | break; | ||
2454 | default: | ||
2455 | ctl->demod = XC3028_FE_OREN538; | ||
2456 | } | ||
2457 | } | ||
2458 | |||
2459 | static void em28xx_tuner_setup(struct em28xx *dev) | ||
2460 | { | ||
2461 | struct tuner_setup tun_setup; | ||
2462 | struct v4l2_frequency f; | ||
2463 | |||
2464 | if (dev->tuner_type == TUNER_ABSENT) | ||
2465 | return; | ||
2466 | |||
2467 | memset(&tun_setup, 0, sizeof(tun_setup)); | ||
2468 | |||
2469 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
2470 | tun_setup.tuner_callback = em28xx_tuner_callback; | ||
2471 | |||
2472 | if (dev->board.radio.type) { | ||
2473 | tun_setup.type = dev->board.radio.type; | ||
2474 | tun_setup.addr = dev->board.radio_addr; | ||
2475 | |||
2476 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2477 | } | ||
2478 | |||
2479 | if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { | ||
2480 | tun_setup.type = dev->tuner_type; | ||
2481 | tun_setup.addr = dev->tuner_addr; | ||
2482 | |||
2483 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2484 | } | ||
2485 | |||
2486 | if (dev->tda9887_conf) { | ||
2487 | struct v4l2_priv_tun_config tda9887_cfg; | ||
2488 | |||
2489 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
2490 | tda9887_cfg.priv = &dev->tda9887_conf; | ||
2491 | |||
2492 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg); | ||
2493 | } | ||
2494 | |||
2495 | if (dev->tuner_type == TUNER_XC2028) { | ||
2496 | struct v4l2_priv_tun_config xc2028_cfg; | ||
2497 | struct xc2028_ctrl ctl; | ||
2498 | |||
2499 | memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); | ||
2500 | memset(&ctl, 0, sizeof(ctl)); | ||
2501 | |||
2502 | em28xx_setup_xc3028(dev, &ctl); | ||
2503 | |||
2504 | xc2028_cfg.tuner = TUNER_XC2028; | ||
2505 | xc2028_cfg.priv = &ctl; | ||
2506 | |||
2507 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg); | ||
2508 | } | ||
2509 | |||
2510 | /* configure tuner */ | ||
2511 | f.tuner = 0; | ||
2512 | f.type = V4L2_TUNER_ANALOG_TV; | ||
2513 | f.frequency = 9076; /* just a magic number */ | ||
2514 | dev->ctl_freq = f.frequency; | ||
2515 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); | ||
2516 | } | ||
2517 | |||
2518 | static int em28xx_hint_board(struct em28xx *dev) | 2515 | static int em28xx_hint_board(struct em28xx *dev) |
2519 | { | 2516 | { |
2520 | int i; | 2517 | int i; |
@@ -2768,57 +2765,56 @@ static void em28xx_card_setup(struct em28xx *dev) | |||
2768 | /* Allow override tuner type by a module parameter */ | 2765 | /* Allow override tuner type by a module parameter */ |
2769 | if (tuner >= 0) | 2766 | if (tuner >= 0) |
2770 | dev->tuner_type = tuner; | 2767 | dev->tuner_type = tuner; |
2768 | } | ||
2771 | 2769 | ||
2772 | /* request some modules */ | 2770 | void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) |
2773 | if (dev->board.has_msp34xx) | 2771 | { |
2774 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | 2772 | memset(ctl, 0, sizeof(*ctl)); |
2775 | "msp3400", 0, msp3400_addrs); | ||
2776 | |||
2777 | if (dev->board.decoder == EM28XX_SAA711X) | ||
2778 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2779 | "saa7115_auto", 0, saa711x_addrs); | ||
2780 | |||
2781 | if (dev->board.decoder == EM28XX_TVP5150) | ||
2782 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2783 | "tvp5150", 0, tvp5150_addrs); | ||
2784 | |||
2785 | if (dev->board.adecoder == EM28XX_TVAUDIO) | ||
2786 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2787 | "tvaudio", dev->board.tvaudio_addr, NULL); | ||
2788 | |||
2789 | if (dev->board.tuner_type != TUNER_ABSENT) { | ||
2790 | int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); | ||
2791 | |||
2792 | if (dev->board.radio.type) | ||
2793 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2794 | "tuner", dev->board.radio_addr, NULL); | ||
2795 | |||
2796 | if (has_demod) | ||
2797 | v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
2798 | &dev->i2c_adap[dev->def_i2c_bus], "tuner", | ||
2799 | 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | ||
2800 | if (dev->tuner_addr == 0) { | ||
2801 | enum v4l2_i2c_tuner_type type = | ||
2802 | has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; | ||
2803 | struct v4l2_subdev *sd; | ||
2804 | |||
2805 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
2806 | &dev->i2c_adap[dev->def_i2c_bus], "tuner", | ||
2807 | 0, v4l2_i2c_tuner_addrs(type)); | ||
2808 | |||
2809 | if (sd) | ||
2810 | dev->tuner_addr = v4l2_i2c_subdev_addr(sd); | ||
2811 | } else { | ||
2812 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2813 | "tuner", dev->tuner_addr, NULL); | ||
2814 | } | ||
2815 | } | ||
2816 | 2773 | ||
2817 | em28xx_tuner_setup(dev); | 2774 | ctl->fname = XC2028_DEFAULT_FIRMWARE; |
2775 | ctl->max_len = 64; | ||
2776 | ctl->mts = em28xx_boards[dev->model].mts_firmware; | ||
2818 | 2777 | ||
2819 | em28xx_init_camera(dev); | 2778 | switch (dev->model) { |
2779 | case EM2880_BOARD_EMPIRE_DUAL_TV: | ||
2780 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | ||
2781 | case EM2882_BOARD_TERRATEC_HYBRID_XS: | ||
2782 | ctl->demod = XC3028_FE_ZARLINK456; | ||
2783 | break; | ||
2784 | case EM2880_BOARD_TERRATEC_HYBRID_XS: | ||
2785 | case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: | ||
2786 | case EM2881_BOARD_PINNACLE_HYBRID_PRO: | ||
2787 | ctl->demod = XC3028_FE_ZARLINK456; | ||
2788 | break; | ||
2789 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: | ||
2790 | case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: | ||
2791 | ctl->demod = XC3028_FE_DEFAULT; | ||
2792 | break; | ||
2793 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: | ||
2794 | ctl->demod = XC3028_FE_DEFAULT; | ||
2795 | ctl->fname = XC3028L_DEFAULT_FIRMWARE; | ||
2796 | break; | ||
2797 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: | ||
2798 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | ||
2799 | case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: | ||
2800 | /* FIXME: Better to specify the needed IF */ | ||
2801 | ctl->demod = XC3028_FE_DEFAULT; | ||
2802 | break; | ||
2803 | case EM2883_BOARD_KWORLD_HYBRID_330U: | ||
2804 | case EM2882_BOARD_DIKOM_DK300: | ||
2805 | case EM2882_BOARD_KWORLD_VS_DVBT: | ||
2806 | ctl->demod = XC3028_FE_CHINA; | ||
2807 | ctl->fname = XC2028_DEFAULT_FIRMWARE; | ||
2808 | break; | ||
2809 | case EM2882_BOARD_EVGA_INDTUBE: | ||
2810 | ctl->demod = XC3028_FE_CHINA; | ||
2811 | ctl->fname = XC3028L_DEFAULT_FIRMWARE; | ||
2812 | break; | ||
2813 | default: | ||
2814 | ctl->demod = XC3028_FE_OREN538; | ||
2815 | } | ||
2820 | } | 2816 | } |
2821 | 2817 | EXPORT_SYMBOL_GPL(em28xx_setup_xc3028); | |
2822 | 2818 | ||
2823 | static void request_module_async(struct work_struct *work) | 2819 | static void request_module_async(struct work_struct *work) |
2824 | { | 2820 | { |
@@ -2831,17 +2827,30 @@ static void request_module_async(struct work_struct *work) | |||
2831 | * can be initialised right now. Otherwise, the module init | 2827 | * can be initialised right now. Otherwise, the module init |
2832 | * code will do it. | 2828 | * code will do it. |
2833 | */ | 2829 | */ |
2830 | |||
2831 | /* | ||
2832 | * Devicdes with an audio-only interface also have a V4L/DVB/RC | ||
2833 | * interface. Don't register extensions twice on those devices. | ||
2834 | */ | ||
2835 | if (dev->is_audio_only) { | ||
2836 | #if defined(CONFIG_MODULES) && defined(MODULE) | ||
2837 | request_module("em28xx-alsa"); | ||
2838 | #endif | ||
2839 | return; | ||
2840 | } | ||
2841 | |||
2834 | em28xx_init_extension(dev); | 2842 | em28xx_init_extension(dev); |
2835 | 2843 | ||
2836 | #if defined(CONFIG_MODULES) && defined(MODULE) | 2844 | #if defined(CONFIG_MODULES) && defined(MODULE) |
2845 | if (dev->has_video) | ||
2846 | request_module("em28xx-v4l"); | ||
2837 | if (dev->has_audio_class) | 2847 | if (dev->has_audio_class) |
2838 | request_module("snd-usb-audio"); | 2848 | request_module("snd-usb-audio"); |
2839 | else if (dev->has_alsa_audio) | 2849 | else if (dev->has_alsa_audio) |
2840 | request_module("em28xx-alsa"); | 2850 | request_module("em28xx-alsa"); |
2841 | |||
2842 | if (dev->board.has_dvb) | 2851 | if (dev->board.has_dvb) |
2843 | request_module("em28xx-dvb"); | 2852 | request_module("em28xx-dvb"); |
2844 | if (dev->board.has_snapshot_button || | 2853 | if (dev->board.buttons || |
2845 | ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir)) | 2854 | ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir)) |
2846 | request_module("em28xx-rc"); | 2855 | request_module("em28xx-rc"); |
2847 | #endif /* CONFIG_MODULES */ | 2856 | #endif /* CONFIG_MODULES */ |
@@ -2867,23 +2876,20 @@ void em28xx_release_resources(struct em28xx *dev) | |||
2867 | { | 2876 | { |
2868 | /*FIXME: I2C IR should be disconnected */ | 2877 | /*FIXME: I2C IR should be disconnected */ |
2869 | 2878 | ||
2870 | em28xx_release_analog_resources(dev); | 2879 | mutex_lock(&dev->lock); |
2871 | 2880 | ||
2872 | if (dev->def_i2c_bus) | 2881 | if (dev->def_i2c_bus) |
2873 | em28xx_i2c_unregister(dev, 1); | 2882 | em28xx_i2c_unregister(dev, 1); |
2874 | em28xx_i2c_unregister(dev, 0); | 2883 | em28xx_i2c_unregister(dev, 0); |
2875 | if (dev->clk) | ||
2876 | v4l2_clk_unregister_fixed(dev->clk); | ||
2877 | |||
2878 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
2879 | |||
2880 | v4l2_device_unregister(&dev->v4l2_dev); | ||
2881 | 2884 | ||
2882 | usb_put_dev(dev->udev); | 2885 | usb_put_dev(dev->udev); |
2883 | 2886 | ||
2884 | /* Mark device as unused */ | 2887 | /* Mark device as unused */ |
2885 | clear_bit(dev->devno, &em28xx_devused); | 2888 | clear_bit(dev->devno, em28xx_devused); |
2889 | |||
2890 | mutex_unlock(&dev->lock); | ||
2886 | }; | 2891 | }; |
2892 | EXPORT_SYMBOL_GPL(em28xx_release_resources); | ||
2887 | 2893 | ||
2888 | /* | 2894 | /* |
2889 | * em28xx_init_dev() | 2895 | * em28xx_init_dev() |
@@ -2893,7 +2899,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, | |||
2893 | struct usb_interface *interface, | 2899 | struct usb_interface *interface, |
2894 | int minor) | 2900 | int minor) |
2895 | { | 2901 | { |
2896 | struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; | ||
2897 | int retval; | 2902 | int retval; |
2898 | static const char *default_chip_name = "em28xx"; | 2903 | static const char *default_chip_name = "em28xx"; |
2899 | const char *chip_name = default_chip_name; | 2904 | const char *chip_name = default_chip_name; |
@@ -2968,6 +2973,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, | |||
2968 | dev->wait_after_write = 0; | 2973 | dev->wait_after_write = 0; |
2969 | dev->eeprom_addrwidth_16bit = 1; | 2974 | dev->eeprom_addrwidth_16bit = 1; |
2970 | break; | 2975 | break; |
2976 | case CHIP_ID_EM28178: | ||
2977 | chip_name = "em28178"; | ||
2978 | dev->wait_after_write = 0; | ||
2979 | dev->eeprom_addrwidth_16bit = 1; | ||
2980 | break; | ||
2971 | case CHIP_ID_EM2883: | 2981 | case CHIP_ID_EM2883: |
2972 | chip_name = "em2882/3"; | 2982 | chip_name = "em2882/3"; |
2973 | dev->wait_after_write = 0; | 2983 | dev->wait_after_write = 0; |
@@ -2983,6 +2993,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, | |||
2983 | } | 2993 | } |
2984 | } | 2994 | } |
2985 | 2995 | ||
2996 | if (dev->chip_id == CHIP_ID_EM2870 || | ||
2997 | dev->chip_id == CHIP_ID_EM2874 || | ||
2998 | dev->chip_id == CHIP_ID_EM28174 || | ||
2999 | dev->chip_id == CHIP_ID_EM28178) { | ||
3000 | /* Digital only device - don't load any alsa module */ | ||
3001 | dev->audio_mode.has_audio = false; | ||
3002 | dev->has_audio_class = false; | ||
3003 | dev->has_alsa_audio = false; | ||
3004 | } | ||
3005 | |||
2986 | if (chip_name != default_chip_name) | 3006 | if (chip_name != default_chip_name) |
2987 | printk(KERN_INFO DRIVER_NAME | 3007 | printk(KERN_INFO DRIVER_NAME |
2988 | ": chip ID is %s\n", chip_name); | 3008 | ": chip ID is %s\n", chip_name); |
@@ -3015,15 +3035,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, | |||
3015 | } | 3035 | } |
3016 | } | 3036 | } |
3017 | 3037 | ||
3018 | retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); | ||
3019 | if (retval < 0) { | ||
3020 | em28xx_errdev("Call to v4l2_device_register() failed!\n"); | ||
3021 | return retval; | ||
3022 | } | ||
3023 | |||
3024 | v4l2_ctrl_handler_init(hdl, 8); | ||
3025 | dev->v4l2_dev.ctrl_handler = hdl; | ||
3026 | |||
3027 | rt_mutex_init(&dev->i2c_bus_lock); | 3038 | rt_mutex_init(&dev->i2c_bus_lock); |
3028 | 3039 | ||
3029 | /* register i2c bus 0 */ | 3040 | /* register i2c bus 0 */ |
@@ -3034,7 +3045,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, | |||
3034 | if (retval < 0) { | 3045 | if (retval < 0) { |
3035 | em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n", | 3046 | em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n", |
3036 | __func__, retval); | 3047 | __func__, retval); |
3037 | goto unregister_dev; | 3048 | return retval; |
3038 | } | 3049 | } |
3039 | 3050 | ||
3040 | /* register i2c bus 1 */ | 3051 | /* register i2c bus 1 */ |
@@ -3048,88 +3059,17 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, | |||
3048 | if (retval < 0) { | 3059 | if (retval < 0) { |
3049 | em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n", | 3060 | em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n", |
3050 | __func__, retval); | 3061 | __func__, retval); |
3051 | goto unregister_dev; | ||
3052 | } | ||
3053 | } | ||
3054 | |||
3055 | /* | ||
3056 | * Default format, used for tvp5150 or saa711x output formats | ||
3057 | */ | ||
3058 | dev->vinmode = 0x10; | ||
3059 | dev->vinctl = EM28XX_VINCTRL_INTERLACED | | ||
3060 | EM28XX_VINCTRL_CCIR656_ENABLE; | ||
3061 | 3062 | ||
3062 | /* Do board specific init and eeprom reading */ | 3063 | em28xx_i2c_unregister(dev, 0); |
3063 | em28xx_card_setup(dev); | ||
3064 | 3064 | ||
3065 | /* Configure audio */ | 3065 | return retval; |
3066 | retval = em28xx_audio_setup(dev); | ||
3067 | if (retval < 0) { | ||
3068 | em28xx_errdev("%s: Error while setting audio - error [%d]!\n", | ||
3069 | __func__, retval); | ||
3070 | goto fail; | ||
3071 | } | ||
3072 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { | ||
3073 | v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, | ||
3074 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | ||
3075 | v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, | ||
3076 | V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f); | ||
3077 | } else { | ||
3078 | /* install the em28xx notify callback */ | ||
3079 | v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE), | ||
3080 | em28xx_ctrl_notify, dev); | ||
3081 | v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME), | ||
3082 | em28xx_ctrl_notify, dev); | ||
3083 | } | ||
3084 | |||
3085 | /* wake i2c devices */ | ||
3086 | em28xx_wake_i2c(dev); | ||
3087 | |||
3088 | /* init video dma queues */ | ||
3089 | INIT_LIST_HEAD(&dev->vidq.active); | ||
3090 | INIT_LIST_HEAD(&dev->vbiq.active); | ||
3091 | |||
3092 | if (dev->board.has_msp34xx) { | ||
3093 | /* Send a reset to other chips via gpio */ | ||
3094 | retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); | ||
3095 | if (retval < 0) { | ||
3096 | em28xx_errdev("%s: em28xx_write_reg - " | ||
3097 | "msp34xx(1) failed! error [%d]\n", | ||
3098 | __func__, retval); | ||
3099 | goto fail; | ||
3100 | } | ||
3101 | msleep(3); | ||
3102 | |||
3103 | retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); | ||
3104 | if (retval < 0) { | ||
3105 | em28xx_errdev("%s: em28xx_write_reg - " | ||
3106 | "msp34xx(2) failed! error [%d]\n", | ||
3107 | __func__, retval); | ||
3108 | goto fail; | ||
3109 | } | 3066 | } |
3110 | msleep(3); | ||
3111 | } | ||
3112 | |||
3113 | retval = em28xx_register_analog_devices(dev); | ||
3114 | if (retval < 0) { | ||
3115 | goto fail; | ||
3116 | } | 3067 | } |
3117 | 3068 | ||
3118 | /* Save some power by putting tuner to sleep */ | 3069 | /* Do board specific init and eeprom reading */ |
3119 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); | 3070 | em28xx_card_setup(dev); |
3120 | 3071 | ||
3121 | return 0; | 3072 | return 0; |
3122 | |||
3123 | fail: | ||
3124 | if (dev->def_i2c_bus) | ||
3125 | em28xx_i2c_unregister(dev, 1); | ||
3126 | em28xx_i2c_unregister(dev, 0); | ||
3127 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
3128 | |||
3129 | unregister_dev: | ||
3130 | v4l2_device_unregister(&dev->v4l2_dev); | ||
3131 | |||
3132 | return retval; | ||
3133 | } | 3073 | } |
3134 | 3074 | ||
3135 | /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ | 3075 | /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ |
@@ -3154,7 +3094,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3154 | 3094 | ||
3155 | /* Check to see next free device and mark as used */ | 3095 | /* Check to see next free device and mark as used */ |
3156 | do { | 3096 | do { |
3157 | nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); | 3097 | nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); |
3158 | if (nr >= EM28XX_MAXBOARDS) { | 3098 | if (nr >= EM28XX_MAXBOARDS) { |
3159 | /* No free device slots */ | 3099 | /* No free device slots */ |
3160 | printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", | 3100 | printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", |
@@ -3162,7 +3102,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3162 | retval = -ENOMEM; | 3102 | retval = -ENOMEM; |
3163 | goto err_no_slot; | 3103 | goto err_no_slot; |
3164 | } | 3104 | } |
3165 | } while (test_and_set_bit(nr, &em28xx_devused)); | 3105 | } while (test_and_set_bit(nr, em28xx_devused)); |
3166 | 3106 | ||
3167 | /* Don't register audio interfaces */ | 3107 | /* Don't register audio interfaces */ |
3168 | if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { | 3108 | if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { |
@@ -3332,7 +3272,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3332 | dev->alt = -1; | 3272 | dev->alt = -1; |
3333 | dev->is_audio_only = has_audio && !(has_video || has_dvb); | 3273 | dev->is_audio_only = has_audio && !(has_video || has_dvb); |
3334 | dev->has_alsa_audio = has_audio; | 3274 | dev->has_alsa_audio = has_audio; |
3335 | dev->audio_ifnum = ifnum; | 3275 | dev->audio_mode.has_audio = has_audio; |
3276 | dev->has_video = has_video; | ||
3277 | dev->ifnum = ifnum; | ||
3336 | 3278 | ||
3337 | /* Checks if audio is provided by some interface */ | 3279 | /* Checks if audio is provided by some interface */ |
3338 | for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { | 3280 | for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { |
@@ -3369,15 +3311,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3369 | /* save our data pointer in this interface device */ | 3311 | /* save our data pointer in this interface device */ |
3370 | usb_set_intfdata(interface, dev); | 3312 | usb_set_intfdata(interface, dev); |
3371 | 3313 | ||
3372 | /* initialize videobuf2 stuff */ | ||
3373 | em28xx_vb2_setup(dev); | ||
3374 | |||
3375 | /* allocate device struct */ | 3314 | /* allocate device struct */ |
3376 | mutex_init(&dev->lock); | 3315 | mutex_init(&dev->lock); |
3377 | mutex_lock(&dev->lock); | ||
3378 | retval = em28xx_init_dev(dev, udev, interface, nr); | 3316 | retval = em28xx_init_dev(dev, udev, interface, nr); |
3379 | if (retval) { | 3317 | if (retval) { |
3380 | goto unlock_and_free; | 3318 | goto err_free; |
3381 | } | 3319 | } |
3382 | 3320 | ||
3383 | if (usb_xfer_mode < 0) { | 3321 | if (usb_xfer_mode < 0) { |
@@ -3402,26 +3340,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3402 | 3340 | ||
3403 | em28xx_info("dvb set to %s mode.\n", | 3341 | em28xx_info("dvb set to %s mode.\n", |
3404 | dev->dvb_xfer_bulk ? "bulk" : "isoc"); | 3342 | dev->dvb_xfer_bulk ? "bulk" : "isoc"); |
3405 | |||
3406 | /* pre-allocate DVB usb transfer buffers */ | ||
3407 | if (dev->dvb_xfer_bulk) { | ||
3408 | retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, | ||
3409 | dev->dvb_xfer_bulk, | ||
3410 | EM28XX_DVB_NUM_BUFS, | ||
3411 | 512, | ||
3412 | EM28XX_DVB_BULK_PACKET_MULTIPLIER); | ||
3413 | } else { | ||
3414 | retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, | ||
3415 | dev->dvb_xfer_bulk, | ||
3416 | EM28XX_DVB_NUM_BUFS, | ||
3417 | dev->dvb_max_pkt_size_isoc, | ||
3418 | EM28XX_DVB_NUM_ISOC_PACKETS); | ||
3419 | } | ||
3420 | if (retval) { | ||
3421 | printk(DRIVER_NAME | ||
3422 | ": Failed to pre-allocate USB transfer buffers for DVB.\n"); | ||
3423 | goto unlock_and_free; | ||
3424 | } | ||
3425 | } | 3343 | } |
3426 | 3344 | ||
3427 | request_modules(dev); | 3345 | request_modules(dev); |
@@ -3429,19 +3347,15 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3429 | /* Should be the last thing to do, to avoid newer udev's to | 3347 | /* Should be the last thing to do, to avoid newer udev's to |
3430 | open the device before fully initializing it | 3348 | open the device before fully initializing it |
3431 | */ | 3349 | */ |
3432 | mutex_unlock(&dev->lock); | ||
3433 | 3350 | ||
3434 | return 0; | 3351 | return 0; |
3435 | 3352 | ||
3436 | unlock_and_free: | ||
3437 | mutex_unlock(&dev->lock); | ||
3438 | |||
3439 | err_free: | 3353 | err_free: |
3440 | kfree(dev->alt_max_pkt_size_isoc); | 3354 | kfree(dev->alt_max_pkt_size_isoc); |
3441 | kfree(dev); | 3355 | kfree(dev); |
3442 | 3356 | ||
3443 | err: | 3357 | err: |
3444 | clear_bit(nr, &em28xx_devused); | 3358 | clear_bit(nr, em28xx_devused); |
3445 | 3359 | ||
3446 | err_no_slot: | 3360 | err_no_slot: |
3447 | usb_put_dev(udev); | 3361 | usb_put_dev(udev); |
@@ -3465,36 +3379,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) | |||
3465 | 3379 | ||
3466 | dev->disconnected = 1; | 3380 | dev->disconnected = 1; |
3467 | 3381 | ||
3468 | if (dev->is_audio_only) { | 3382 | em28xx_info("Disconnecting %s\n", dev->name); |
3469 | mutex_lock(&dev->lock); | ||
3470 | em28xx_close_extension(dev); | ||
3471 | mutex_unlock(&dev->lock); | ||
3472 | return; | ||
3473 | } | ||
3474 | |||
3475 | em28xx_info("disconnecting %s\n", dev->vdev->name); | ||
3476 | 3383 | ||
3477 | flush_request_modules(dev); | 3384 | flush_request_modules(dev); |
3478 | 3385 | ||
3479 | mutex_lock(&dev->lock); | ||
3480 | |||
3481 | v4l2_device_disconnect(&dev->v4l2_dev); | ||
3482 | |||
3483 | if (dev->users) { | ||
3484 | em28xx_warn("device %s is open! Deregistration and memory deallocation are deferred on close.\n", | ||
3485 | video_device_node_name(dev->vdev)); | ||
3486 | |||
3487 | em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); | ||
3488 | em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); | ||
3489 | } | ||
3490 | |||
3491 | em28xx_close_extension(dev); | 3386 | em28xx_close_extension(dev); |
3492 | /* NOTE: must be called BEFORE the resources are released */ | ||
3493 | |||
3494 | if (!dev->users) | ||
3495 | em28xx_release_resources(dev); | ||
3496 | 3387 | ||
3497 | mutex_unlock(&dev->lock); | 3388 | em28xx_release_resources(dev); |
3498 | 3389 | ||
3499 | if (!dev->users) { | 3390 | if (!dev->users) { |
3500 | kfree(dev->alt_max_pkt_size_isoc); | 3391 | kfree(dev->alt_max_pkt_size_isoc); |
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index fc157af5234a..898fb9bd88a2 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c | |||
@@ -23,6 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/jiffies.h> | ||
26 | #include <linux/list.h> | 27 | #include <linux/list.h> |
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
@@ -33,6 +34,16 @@ | |||
33 | 34 | ||
34 | #include "em28xx.h" | 35 | #include "em28xx.h" |
35 | 36 | ||
37 | #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \ | ||
38 | "Markus Rechberger <mrechberger@gmail.com>, " \ | ||
39 | "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ | ||
40 | "Sascha Sommer <saschasommer@freenet.de>" | ||
41 | |||
42 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
43 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | MODULE_VERSION(EM28XX_VERSION); | ||
46 | |||
36 | /* #define ENABLE_DEBUG_ISOC_FRAMES */ | 47 | /* #define ENABLE_DEBUG_ISOC_FRAMES */ |
37 | 48 | ||
38 | static unsigned int core_debug; | 49 | static unsigned int core_debug; |
@@ -53,14 +64,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); | |||
53 | printk(KERN_INFO "%s %s :"fmt, \ | 64 | printk(KERN_INFO "%s %s :"fmt, \ |
54 | dev->name, __func__ , ##arg); } while (0) | 65 | dev->name, __func__ , ##arg); } while (0) |
55 | 66 | ||
56 | static int alt; | ||
57 | module_param(alt, int, 0644); | ||
58 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); | ||
59 | |||
60 | static unsigned int disable_vbi; | ||
61 | module_param(disable_vbi, int, 0644); | ||
62 | MODULE_PARM_DESC(disable_vbi, "disable vbi support"); | ||
63 | |||
64 | /* FIXME */ | 67 | /* FIXME */ |
65 | #define em28xx_isocdbg(fmt, arg...) do {\ | 68 | #define em28xx_isocdbg(fmt, arg...) do {\ |
66 | if (core_debug) \ | 69 | if (core_debug) \ |
@@ -226,21 +229,42 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, | |||
226 | EXPORT_SYMBOL_GPL(em28xx_write_reg_bits); | 229 | EXPORT_SYMBOL_GPL(em28xx_write_reg_bits); |
227 | 230 | ||
228 | /* | 231 | /* |
232 | * em28xx_toggle_reg_bits() | ||
233 | * toggles/inverts the bits (specified by bitmask) of a register | ||
234 | */ | ||
235 | int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask) | ||
236 | { | ||
237 | int oldval; | ||
238 | u8 newval; | ||
239 | |||
240 | oldval = em28xx_read_reg(dev, reg); | ||
241 | if (oldval < 0) | ||
242 | return oldval; | ||
243 | |||
244 | newval = (~oldval & bitmask) | (oldval & ~bitmask); | ||
245 | |||
246 | return em28xx_write_reg(dev, reg, newval); | ||
247 | } | ||
248 | EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits); | ||
249 | |||
250 | /* | ||
229 | * em28xx_is_ac97_ready() | 251 | * em28xx_is_ac97_ready() |
230 | * Checks if ac97 is ready | 252 | * Checks if ac97 is ready |
231 | */ | 253 | */ |
232 | static int em28xx_is_ac97_ready(struct em28xx *dev) | 254 | static int em28xx_is_ac97_ready(struct em28xx *dev) |
233 | { | 255 | { |
234 | int ret, i; | 256 | unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_AC97_XFER_TIMEOUT); |
257 | int ret; | ||
235 | 258 | ||
236 | /* Wait up to 50 ms for AC97 command to complete */ | 259 | /* Wait up to 50 ms for AC97 command to complete */ |
237 | for (i = 0; i < 10; i++, msleep(5)) { | 260 | while (time_is_after_jiffies(timeout)) { |
238 | ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); | 261 | ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); |
239 | if (ret < 0) | 262 | if (ret < 0) |
240 | return ret; | 263 | return ret; |
241 | 264 | ||
242 | if (!(ret & 0x01)) | 265 | if (!(ret & 0x01)) |
243 | return 0; | 266 | return 0; |
267 | msleep(5); | ||
244 | } | 268 | } |
245 | 269 | ||
246 | em28xx_warn("AC97 command still being executed: not handled properly!\n"); | 270 | em28xx_warn("AC97 command still being executed: not handled properly!\n"); |
@@ -482,16 +506,8 @@ int em28xx_audio_setup(struct em28xx *dev) | |||
482 | int vid1, vid2, feat, cfg; | 506 | int vid1, vid2, feat, cfg; |
483 | u32 vid; | 507 | u32 vid; |
484 | 508 | ||
485 | if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 | 509 | if (!dev->audio_mode.has_audio) |
486 | || dev->chip_id == CHIP_ID_EM28174) { | ||
487 | /* Digital only device - don't load any alsa module */ | ||
488 | dev->audio_mode.has_audio = false; | ||
489 | dev->has_audio_class = false; | ||
490 | dev->has_alsa_audio = false; | ||
491 | return 0; | 510 | return 0; |
492 | } | ||
493 | |||
494 | dev->audio_mode.has_audio = true; | ||
495 | 511 | ||
496 | /* See how this device is configured */ | 512 | /* See how this device is configured */ |
497 | cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); | 513 | cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); |
@@ -504,17 +520,19 @@ int em28xx_audio_setup(struct em28xx *dev) | |||
504 | dev->has_alsa_audio = false; | 520 | dev->has_alsa_audio = false; |
505 | dev->audio_mode.has_audio = false; | 521 | dev->audio_mode.has_audio = false; |
506 | return 0; | 522 | return 0; |
507 | } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == | 523 | } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { |
508 | EM28XX_CHIPCFG_I2S_3_SAMPRATES) { | 524 | if (dev->chip_id < CHIP_ID_EM2860 && |
509 | em28xx_info("I2S Audio (3 sample rates)\n"); | 525 | (cfg & EM28XX_CHIPCFG_AUDIOMASK) == |
510 | dev->audio_mode.i2s_3rates = 1; | 526 | EM2820_CHIPCFG_I2S_1_SAMPRATE) |
511 | } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == | 527 | dev->audio_mode.i2s_samplerates = 1; |
512 | EM28XX_CHIPCFG_I2S_5_SAMPRATES) { | 528 | else if (dev->chip_id >= CHIP_ID_EM2860 && |
513 | em28xx_info("I2S Audio (5 sample rates)\n"); | 529 | (cfg & EM28XX_CHIPCFG_AUDIOMASK) == |
514 | dev->audio_mode.i2s_5rates = 1; | 530 | EM2860_CHIPCFG_I2S_5_SAMPRATES) |
515 | } | 531 | dev->audio_mode.i2s_samplerates = 5; |
516 | 532 | else | |
517 | if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { | 533 | dev->audio_mode.i2s_samplerates = 3; |
534 | em28xx_info("I2S Audio (%d sample rate(s))\n", | ||
535 | dev->audio_mode.i2s_samplerates); | ||
518 | /* Skip the code that does AC97 vendor detection */ | 536 | /* Skip the code that does AC97 vendor detection */ |
519 | dev->audio_mode.ac97 = EM28XX_NO_AC97; | 537 | dev->audio_mode.ac97 = EM28XX_NO_AC97; |
520 | goto init_audio; | 538 | goto init_audio; |
@@ -582,23 +600,21 @@ init_audio: | |||
582 | } | 600 | } |
583 | EXPORT_SYMBOL_GPL(em28xx_audio_setup); | 601 | EXPORT_SYMBOL_GPL(em28xx_audio_setup); |
584 | 602 | ||
585 | int em28xx_colorlevels_set_default(struct em28xx *dev) | 603 | const struct em28xx_led *em28xx_find_led(struct em28xx *dev, |
604 | enum em28xx_led_role role) | ||
586 | { | 605 | { |
587 | em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT); | 606 | if (dev->board.leds) { |
588 | em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT); | 607 | u8 k = 0; |
589 | em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT); | 608 | while (dev->board.leds[k].role >= 0 && |
590 | em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT); | 609 | dev->board.leds[k].role < EM28XX_NUM_LED_ROLES) { |
591 | em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT); | 610 | if (dev->board.leds[k].role == role) |
592 | em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT); | 611 | return &dev->board.leds[k]; |
593 | 612 | k++; | |
594 | em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); | 613 | } |
595 | em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); | 614 | } |
596 | em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); | 615 | return NULL; |
597 | em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); | ||
598 | em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); | ||
599 | em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); | ||
600 | return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); | ||
601 | } | 616 | } |
617 | EXPORT_SYMBOL_GPL(em28xx_find_led); | ||
602 | 618 | ||
603 | int em28xx_capture_start(struct em28xx *dev, int start) | 619 | int em28xx_capture_start(struct em28xx *dev, int start) |
604 | { | 620 | { |
@@ -606,271 +622,57 @@ int em28xx_capture_start(struct em28xx *dev, int start) | |||
606 | 622 | ||
607 | if (dev->chip_id == CHIP_ID_EM2874 || | 623 | if (dev->chip_id == CHIP_ID_EM2874 || |
608 | dev->chip_id == CHIP_ID_EM2884 || | 624 | dev->chip_id == CHIP_ID_EM2884 || |
609 | dev->chip_id == CHIP_ID_EM28174) { | 625 | dev->chip_id == CHIP_ID_EM28174 || |
626 | dev->chip_id == CHIP_ID_EM28178) { | ||
610 | /* The Transport Stream Enable Register moved in em2874 */ | 627 | /* The Transport Stream Enable Register moved in em2874 */ |
611 | if (!start) { | ||
612 | rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, | ||
613 | 0x00, | ||
614 | EM2874_TS1_CAPTURE_ENABLE); | ||
615 | return rc; | ||
616 | } | ||
617 | |||
618 | /* Enable Transport Stream */ | ||
619 | rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, | 628 | rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, |
620 | EM2874_TS1_CAPTURE_ENABLE, | 629 | start ? |
630 | EM2874_TS1_CAPTURE_ENABLE : 0x00, | ||
621 | EM2874_TS1_CAPTURE_ENABLE); | 631 | EM2874_TS1_CAPTURE_ENABLE); |
622 | return rc; | ||
623 | } | ||
624 | |||
625 | |||
626 | /* FIXME: which is the best order? */ | ||
627 | /* video registers are sampled by VREF */ | ||
628 | rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, | ||
629 | start ? 0x10 : 0x00, 0x10); | ||
630 | if (rc < 0) | ||
631 | return rc; | ||
632 | |||
633 | if (!start) { | ||
634 | /* disable video capture */ | ||
635 | rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); | ||
636 | return rc; | ||
637 | } | ||
638 | |||
639 | if (dev->board.is_webcam) | ||
640 | rc = em28xx_write_reg(dev, 0x13, 0x0c); | ||
641 | |||
642 | /* enable video capture */ | ||
643 | rc = em28xx_write_reg(dev, 0x48, 0x00); | ||
644 | |||
645 | if (dev->mode == EM28XX_ANALOG_MODE) | ||
646 | rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); | ||
647 | else | ||
648 | rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); | ||
649 | |||
650 | msleep(6); | ||
651 | |||
652 | return rc; | ||
653 | } | ||
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->board.is_webcam) | ||
662 | return 0; | ||
663 | |||
664 | /* FIXME: check subdevices for VBI support */ | ||
665 | |||
666 | if (dev->chip_id == CHIP_ID_EM2860 || | ||
667 | dev->chip_id == CHIP_ID_EM2883) | ||
668 | return 1; | ||
669 | |||
670 | /* Version of em28xx that does not support VBI */ | ||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | int em28xx_set_outfmt(struct em28xx *dev) | ||
675 | { | ||
676 | int ret; | ||
677 | u8 fmt, vinctrl; | ||
678 | |||
679 | fmt = dev->format->reg; | ||
680 | if (!dev->is_em25xx) | ||
681 | fmt |= 0x20; | ||
682 | /* | ||
683 | * NOTE: it's not clear if this is really needed ! | ||
684 | * The datasheets say bit 5 is a reserved bit and devices seem to work | ||
685 | * fine without it. But the Windows driver sets it for em2710/50+em28xx | ||
686 | * devices and we've always been setting it, too. | ||
687 | * | ||
688 | * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set, | ||
689 | * it's likely used for an additional (compressed ?) format there. | ||
690 | */ | ||
691 | ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt); | ||
692 | if (ret < 0) | ||
693 | return ret; | ||
694 | |||
695 | ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); | ||
696 | if (ret < 0) | ||
697 | return ret; | ||
698 | |||
699 | vinctrl = dev->vinctl; | ||
700 | if (em28xx_vbi_supported(dev) == 1) { | ||
701 | vinctrl |= EM28XX_VINCTRL_VBI_RAW; | ||
702 | em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); | ||
703 | em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4); | ||
704 | em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height); | ||
705 | if (dev->norm & V4L2_STD_525_60) { | ||
706 | /* NTSC */ | ||
707 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); | ||
708 | } else if (dev->norm & V4L2_STD_625_50) { | ||
709 | /* PAL */ | ||
710 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); | ||
711 | } | ||
712 | } | ||
713 | |||
714 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); | ||
715 | } | ||
716 | |||
717 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, | ||
718 | u8 ymin, u8 ymax) | ||
719 | { | ||
720 | em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", | ||
721 | xmin, ymin, xmax, ymax); | ||
722 | |||
723 | em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); | ||
724 | em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); | ||
725 | em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); | ||
726 | return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); | ||
727 | } | ||
728 | |||
729 | static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, | ||
730 | u16 width, u16 height) | ||
731 | { | ||
732 | u8 cwidth = width >> 2; | ||
733 | u8 cheight = height >> 2; | ||
734 | u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01); | ||
735 | /* NOTE: size limit: 2047x1023 = 2MPix */ | ||
736 | |||
737 | em28xx_coredbg("capture area set to (%d,%d): %dx%d\n", | ||
738 | hstart, vstart, | ||
739 | ((overflow & 2) << 9 | cwidth << 2), | ||
740 | ((overflow & 1) << 10 | cheight << 2)); | ||
741 | |||
742 | em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); | ||
743 | em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); | ||
744 | em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); | ||
745 | em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); | ||
746 | em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); | ||
747 | |||
748 | /* FIXME: function/meaning of these registers ? */ | ||
749 | /* FIXME: align width+height to multiples of 4 ?! */ | ||
750 | if (dev->is_em25xx) { | ||
751 | em28xx_write_reg(dev, 0x34, width >> 4); | ||
752 | em28xx_write_reg(dev, 0x35, height >> 4); | ||
753 | } | ||
754 | } | ||
755 | |||
756 | static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) | ||
757 | { | ||
758 | u8 mode; | ||
759 | /* the em2800 scaler only supports scaling down to 50% */ | ||
760 | |||
761 | if (dev->board.is_em2800) { | ||
762 | mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); | ||
763 | } else { | 632 | } else { |
764 | u8 buf[2]; | 633 | /* FIXME: which is the best order? */ |
765 | 634 | /* video registers are sampled by VREF */ | |
766 | buf[0] = h; | 635 | rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, |
767 | buf[1] = h >> 8; | 636 | start ? 0x10 : 0x00, 0x10); |
768 | em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); | 637 | if (rc < 0) |
769 | 638 | return rc; | |
770 | buf[0] = v; | ||
771 | buf[1] = v >> 8; | ||
772 | em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); | ||
773 | /* it seems that both H and V scalers must be active | ||
774 | to work correctly */ | ||
775 | mode = (h || v) ? 0x30 : 0x00; | ||
776 | } | ||
777 | return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); | ||
778 | } | ||
779 | |||
780 | /* FIXME: this only function read values from dev */ | ||
781 | int em28xx_resolution_set(struct em28xx *dev) | ||
782 | { | ||
783 | int width, height; | ||
784 | width = norm_maxw(dev); | ||
785 | height = norm_maxh(dev); | ||
786 | |||
787 | /* Properly setup VBI */ | ||
788 | dev->vbi_width = 720; | ||
789 | if (dev->norm & V4L2_STD_525_60) | ||
790 | dev->vbi_height = 12; | ||
791 | else | ||
792 | dev->vbi_height = 18; | ||
793 | |||
794 | em28xx_set_outfmt(dev); | ||
795 | 639 | ||
796 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); | 640 | if (start) { |
641 | if (dev->board.is_webcam) | ||
642 | rc = em28xx_write_reg(dev, 0x13, 0x0c); | ||
797 | 643 | ||
798 | /* If we don't set the start position to 2 in VBI mode, we end up | 644 | /* Enable video capture */ |
799 | with line 20/21 being YUYV encoded instead of being in 8-bit | 645 | rc = em28xx_write_reg(dev, 0x48, 0x00); |
800 | greyscale. The core of the issue is that line 21 (and line 23 for | ||
801 | PAL WSS) are inside of active video region, and as a result they | ||
802 | get the pixelformatting associated with that area. So by cropping | ||
803 | it out, we end up with the same format as the rest of the VBI | ||
804 | region */ | ||
805 | if (em28xx_vbi_supported(dev) == 1) | ||
806 | em28xx_capture_area_set(dev, 0, 2, width, height); | ||
807 | else | ||
808 | em28xx_capture_area_set(dev, 0, 0, width, height); | ||
809 | 646 | ||
810 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); | 647 | if (dev->mode == EM28XX_ANALOG_MODE) |
811 | } | 648 | rc = em28xx_write_reg(dev, |
649 | EM28XX_R12_VINENABLE, 0x67); | ||
650 | else | ||
651 | rc = em28xx_write_reg(dev, | ||
652 | EM28XX_R12_VINENABLE, 0x37); | ||
812 | 653 | ||
813 | /* Set USB alternate setting for analog video */ | 654 | msleep(6); |
814 | int em28xx_set_alternate(struct em28xx *dev) | 655 | } else { |
815 | { | 656 | /* disable video capture */ |
816 | int errCode; | 657 | rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); |
817 | int i; | 658 | } |
818 | unsigned int min_pkt_size = dev->width * 2 + 4; | ||
819 | |||
820 | /* NOTE: for isoc transfers, only alt settings > 0 are allowed | ||
821 | bulk transfers seem to work only with alt=0 ! */ | ||
822 | dev->alt = 0; | ||
823 | if ((alt > 0) && (alt < dev->num_alt)) { | ||
824 | em28xx_coredbg("alternate forced to %d\n", dev->alt); | ||
825 | dev->alt = alt; | ||
826 | goto set_alt; | ||
827 | } | 659 | } |
828 | if (dev->analog_xfer_bulk) | ||
829 | goto set_alt; | ||
830 | 660 | ||
831 | /* When image size is bigger than a certain value, | 661 | if (rc < 0) |
832 | the frame size should be increased, otherwise, only | 662 | return rc; |
833 | green screen will be received. | ||
834 | */ | ||
835 | if (dev->width * 2 * dev->height > 720 * 240 * 2) | ||
836 | min_pkt_size *= 2; | ||
837 | 663 | ||
838 | for (i = 0; i < dev->num_alt; i++) { | 664 | /* Switch (explicitly controlled) analog capturing LED on/off */ |
839 | /* stop when the selected alt setting offers enough bandwidth */ | 665 | if (dev->mode == EM28XX_ANALOG_MODE) { |
840 | if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { | 666 | const struct em28xx_led *led; |
841 | dev->alt = i; | 667 | led = em28xx_find_led(dev, EM28XX_LED_ANALOG_CAPTURING); |
842 | break; | 668 | if (led) |
843 | /* otherwise make sure that we end up with the maximum bandwidth | 669 | em28xx_write_reg_bits(dev, led->gpio_reg, |
844 | because the min_pkt_size equation might be wrong... | 670 | (!start ^ led->inverted) ? |
845 | */ | 671 | ~led->gpio_mask : led->gpio_mask, |
846 | } else if (dev->alt_max_pkt_size_isoc[i] > | 672 | led->gpio_mask); |
847 | dev->alt_max_pkt_size_isoc[dev->alt]) | ||
848 | dev->alt = i; | ||
849 | } | 673 | } |
850 | 674 | ||
851 | set_alt: | 675 | return rc; |
852 | /* NOTE: for bulk transfers, we need to call usb_set_interface() | ||
853 | * even if the previous settings were the same. Otherwise streaming | ||
854 | * fails with all urbs having status = -EOVERFLOW ! */ | ||
855 | if (dev->analog_xfer_bulk) { | ||
856 | dev->max_pkt_size = 512; /* USB 2.0 spec */ | ||
857 | dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; | ||
858 | } else { /* isoc */ | ||
859 | em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", | ||
860 | min_pkt_size, dev->alt); | ||
861 | dev->max_pkt_size = | ||
862 | dev->alt_max_pkt_size_isoc[dev->alt]; | ||
863 | dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; | ||
864 | } | ||
865 | em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", | ||
866 | dev->alt, dev->max_pkt_size); | ||
867 | errCode = usb_set_interface(dev->udev, 0, dev->alt); | ||
868 | if (errCode < 0) { | ||
869 | em28xx_errdev("cannot change alternate number to %d (error=%i)\n", | ||
870 | dev->alt, errCode); | ||
871 | return errCode; | ||
872 | } | ||
873 | return 0; | ||
874 | } | 676 | } |
875 | 677 | ||
876 | int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) | 678 | int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) |
@@ -1238,18 +1040,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, | |||
1238 | EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer); | 1040 | EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer); |
1239 | 1041 | ||
1240 | /* | 1042 | /* |
1241 | * em28xx_wake_i2c() | ||
1242 | * configure i2c attached devices | ||
1243 | */ | ||
1244 | void em28xx_wake_i2c(struct em28xx *dev) | ||
1245 | { | ||
1246 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); | ||
1247 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, | ||
1248 | INPUT(dev->ctl_input)->vmux, 0, 0); | ||
1249 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); | ||
1250 | } | ||
1251 | |||
1252 | /* | ||
1253 | * Device control list | 1043 | * Device control list |
1254 | */ | 1044 | */ |
1255 | 1045 | ||
@@ -1272,7 +1062,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) | |||
1272 | ops->init(dev); | 1062 | ops->init(dev); |
1273 | } | 1063 | } |
1274 | mutex_unlock(&em28xx_devlist_mutex); | 1064 | mutex_unlock(&em28xx_devlist_mutex); |
1275 | printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); | 1065 | printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name); |
1276 | return 0; | 1066 | return 0; |
1277 | } | 1067 | } |
1278 | EXPORT_SYMBOL(em28xx_register_extension); | 1068 | EXPORT_SYMBOL(em28xx_register_extension); |
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 344042bb845c..a0a669e81362 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c | |||
@@ -51,10 +51,14 @@ | |||
51 | #include "a8293.h" | 51 | #include "a8293.h" |
52 | #include "qt1010.h" | 52 | #include "qt1010.h" |
53 | #include "mb86a20s.h" | 53 | #include "mb86a20s.h" |
54 | #include "m88ds3103.h" | ||
55 | #include "m88ts2022.h" | ||
54 | 56 | ||
55 | MODULE_DESCRIPTION("driver for em28xx based DVB cards"); | ||
56 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | 57 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); |
57 | MODULE_LICENSE("GPL"); | 58 | MODULE_LICENSE("GPL"); |
59 | MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface"); | ||
60 | MODULE_VERSION(EM28XX_VERSION); | ||
61 | |||
58 | 62 | ||
59 | static unsigned int debug; | 63 | static unsigned int debug; |
60 | module_param(debug, int, 0644); | 64 | module_param(debug, int, 0644); |
@@ -87,6 +91,7 @@ struct em28xx_dvb { | |||
87 | struct semaphore pll_mutex; | 91 | struct semaphore pll_mutex; |
88 | bool dont_attach_fe1; | 92 | bool dont_attach_fe1; |
89 | int lna_gpio; | 93 | int lna_gpio; |
94 | struct i2c_client *i2c_client_tuner; | ||
90 | }; | 95 | }; |
91 | 96 | ||
92 | 97 | ||
@@ -198,7 +203,7 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) | |||
198 | dvb_alt = dev->dvb_alt_isoc; | 203 | dvb_alt = dev->dvb_alt_isoc; |
199 | } | 204 | } |
200 | 205 | ||
201 | usb_set_interface(dev->udev, 0, dvb_alt); | 206 | usb_set_interface(dev->udev, dev->ifnum, dvb_alt); |
202 | rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); | 207 | rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); |
203 | if (rc < 0) | 208 | if (rc < 0) |
204 | return rc; | 209 | return rc; |
@@ -271,7 +276,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed) | |||
271 | static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) | 276 | static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) |
272 | { | 277 | { |
273 | struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; | 278 | struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; |
274 | struct em28xx *dev = i2c_bus->dev; | 279 | struct em28xx *dev = i2c_bus->dev; |
275 | 280 | ||
276 | if (acquire) | 281 | if (acquire) |
277 | return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); | 282 | return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); |
@@ -370,7 +375,6 @@ static struct drxk_config terratec_h5_drxk = { | |||
370 | .no_i2c_bridge = 1, | 375 | .no_i2c_bridge = 1, |
371 | .microcode_name = "dvb-usb-terratec-h5-drxk.fw", | 376 | .microcode_name = "dvb-usb-terratec-h5-drxk.fw", |
372 | .qam_demod_parameter_count = 2, | 377 | .qam_demod_parameter_count = 2, |
373 | .load_firmware_sync = true, | ||
374 | }; | 378 | }; |
375 | 379 | ||
376 | static struct drxk_config hauppauge_930c_drxk = { | 380 | static struct drxk_config hauppauge_930c_drxk = { |
@@ -380,7 +384,6 @@ static struct drxk_config hauppauge_930c_drxk = { | |||
380 | .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw", | 384 | .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw", |
381 | .chunk_size = 56, | 385 | .chunk_size = 56, |
382 | .qam_demod_parameter_count = 2, | 386 | .qam_demod_parameter_count = 2, |
383 | .load_firmware_sync = true, | ||
384 | }; | 387 | }; |
385 | 388 | ||
386 | static struct drxk_config terratec_htc_stick_drxk = { | 389 | static struct drxk_config terratec_htc_stick_drxk = { |
@@ -394,7 +397,6 @@ static struct drxk_config terratec_htc_stick_drxk = { | |||
394 | .antenna_dvbt = true, | 397 | .antenna_dvbt = true, |
395 | /* The windows driver uses the same. This will disable LNA. */ | 398 | /* The windows driver uses the same. This will disable LNA. */ |
396 | .antenna_gpio = 0x6, | 399 | .antenna_gpio = 0x6, |
397 | .load_firmware_sync = true, | ||
398 | }; | 400 | }; |
399 | 401 | ||
400 | static struct drxk_config maxmedia_ub425_tc_drxk = { | 402 | static struct drxk_config maxmedia_ub425_tc_drxk = { |
@@ -403,7 +405,6 @@ static struct drxk_config maxmedia_ub425_tc_drxk = { | |||
403 | .no_i2c_bridge = 1, | 405 | .no_i2c_bridge = 1, |
404 | .microcode_name = "dvb-demod-drxk-01.fw", | 406 | .microcode_name = "dvb-demod-drxk-01.fw", |
405 | .chunk_size = 62, | 407 | .chunk_size = 62, |
406 | .load_firmware_sync = true, | ||
407 | .qam_demod_parameter_count = 2, | 408 | .qam_demod_parameter_count = 2, |
408 | }; | 409 | }; |
409 | 410 | ||
@@ -415,7 +416,6 @@ static struct drxk_config pctv_520e_drxk = { | |||
415 | .chunk_size = 58, | 416 | .chunk_size = 58, |
416 | .antenna_dvbt = true, /* disable LNA */ | 417 | .antenna_dvbt = true, /* disable LNA */ |
417 | .antenna_gpio = (1 << 2), /* disable LNA */ | 418 | .antenna_gpio = (1 << 2), /* disable LNA */ |
418 | .load_firmware_sync = true, | ||
419 | }; | 419 | }; |
420 | 420 | ||
421 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) | 421 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) |
@@ -808,6 +808,14 @@ static struct tda18271_config c3tech_duo_tda18271_config = { | |||
808 | .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, | 808 | .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, |
809 | }; | 809 | }; |
810 | 810 | ||
811 | static const struct m88ds3103_config pctv_461e_m88ds3103_config = { | ||
812 | .i2c_addr = 0x68, | ||
813 | .clock = 27000000, | ||
814 | .i2c_wr_max = 33, | ||
815 | .clock_out = 0, | ||
816 | .ts_mode = M88DS3103_TS_PARALLEL_16, | ||
817 | .agc = 0x99, | ||
818 | }; | ||
811 | 819 | ||
812 | /* ------------------------------------------------------------------ */ | 820 | /* ------------------------------------------------------------------ */ |
813 | 821 | ||
@@ -815,11 +823,16 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) | |||
815 | { | 823 | { |
816 | struct dvb_frontend *fe; | 824 | struct dvb_frontend *fe; |
817 | struct xc2028_config cfg; | 825 | struct xc2028_config cfg; |
826 | struct xc2028_ctrl ctl; | ||
818 | 827 | ||
819 | memset(&cfg, 0, sizeof(cfg)); | 828 | memset(&cfg, 0, sizeof(cfg)); |
820 | cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus]; | 829 | cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus]; |
821 | cfg.i2c_addr = addr; | 830 | cfg.i2c_addr = addr; |
822 | 831 | ||
832 | memset(&ctl, 0, sizeof(ctl)); | ||
833 | em28xx_setup_xc3028(dev, &ctl); | ||
834 | cfg.ctrl = &ctl; | ||
835 | |||
823 | if (!dev->dvb->fe[0]) { | 836 | if (!dev->dvb->fe[0]) { |
824 | em28xx_errdev("/2: dvb frontend not attached. " | 837 | em28xx_errdev("/2: dvb frontend not attached. " |
825 | "Can't attach xc3028\n"); | 838 | "Can't attach xc3028\n"); |
@@ -979,12 +992,18 @@ static int em28xx_dvb_init(struct em28xx *dev) | |||
979 | int result = 0, mfe_shared = 0; | 992 | int result = 0, mfe_shared = 0; |
980 | struct em28xx_dvb *dvb; | 993 | struct em28xx_dvb *dvb; |
981 | 994 | ||
995 | if (dev->is_audio_only) { | ||
996 | /* Shouldn't initialize IR for this interface */ | ||
997 | return 0; | ||
998 | } | ||
999 | |||
982 | if (!dev->board.has_dvb) { | 1000 | if (!dev->board.has_dvb) { |
983 | /* This device does not support the extension */ | 1001 | /* This device does not support the extension */ |
984 | printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n"); | ||
985 | return 0; | 1002 | return 0; |
986 | } | 1003 | } |
987 | 1004 | ||
1005 | em28xx_info("Binding DVB extension\n"); | ||
1006 | |||
988 | dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); | 1007 | dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); |
989 | 1008 | ||
990 | if (dvb == NULL) { | 1009 | if (dvb == NULL) { |
@@ -994,6 +1013,27 @@ static int em28xx_dvb_init(struct em28xx *dev) | |||
994 | dev->dvb = dvb; | 1013 | dev->dvb = dvb; |
995 | dvb->fe[0] = dvb->fe[1] = NULL; | 1014 | dvb->fe[0] = dvb->fe[1] = NULL; |
996 | 1015 | ||
1016 | /* pre-allocate DVB usb transfer buffers */ | ||
1017 | if (dev->dvb_xfer_bulk) { | ||
1018 | result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, | ||
1019 | dev->dvb_xfer_bulk, | ||
1020 | EM28XX_DVB_NUM_BUFS, | ||
1021 | 512, | ||
1022 | EM28XX_DVB_BULK_PACKET_MULTIPLIER); | ||
1023 | } else { | ||
1024 | result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, | ||
1025 | dev->dvb_xfer_bulk, | ||
1026 | EM28XX_DVB_NUM_BUFS, | ||
1027 | dev->dvb_max_pkt_size_isoc, | ||
1028 | EM28XX_DVB_NUM_ISOC_PACKETS); | ||
1029 | } | ||
1030 | if (result) { | ||
1031 | em28xx_errdev("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n"); | ||
1032 | kfree(dvb); | ||
1033 | dev->dvb = NULL; | ||
1034 | return result; | ||
1035 | } | ||
1036 | |||
997 | mutex_lock(&dev->lock); | 1037 | mutex_lock(&dev->lock); |
998 | em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); | 1038 | em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); |
999 | /* init frontend */ | 1039 | /* init frontend */ |
@@ -1330,6 +1370,48 @@ static int em28xx_dvb_init(struct em28xx *dev) | |||
1330 | goto out_free; | 1370 | goto out_free; |
1331 | } | 1371 | } |
1332 | break; | 1372 | break; |
1373 | case EM28178_BOARD_PCTV_461E: | ||
1374 | { | ||
1375 | /* demod I2C adapter */ | ||
1376 | struct i2c_adapter *i2c_adapter; | ||
1377 | struct i2c_board_info info; | ||
1378 | struct m88ts2022_config m88ts2022_config = { | ||
1379 | .clock = 27000000, | ||
1380 | }; | ||
1381 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1382 | |||
1383 | /* attach demod */ | ||
1384 | dvb->fe[0] = dvb_attach(m88ds3103_attach, | ||
1385 | &pctv_461e_m88ds3103_config, | ||
1386 | &dev->i2c_adap[dev->def_i2c_bus], | ||
1387 | &i2c_adapter); | ||
1388 | if (dvb->fe[0] == NULL) { | ||
1389 | result = -ENODEV; | ||
1390 | goto out_free; | ||
1391 | } | ||
1392 | |||
1393 | /* attach tuner */ | ||
1394 | m88ts2022_config.fe = dvb->fe[0]; | ||
1395 | strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); | ||
1396 | info.addr = 0x60; | ||
1397 | info.platform_data = &m88ts2022_config; | ||
1398 | request_module("m88ts2022"); | ||
1399 | dvb->i2c_client_tuner = i2c_new_device(i2c_adapter, &info); | ||
1400 | |||
1401 | /* delegate signal strength measurement to tuner */ | ||
1402 | dvb->fe[0]->ops.read_signal_strength = | ||
1403 | dvb->fe[0]->ops.tuner_ops.get_rf_strength; | ||
1404 | |||
1405 | /* attach SEC */ | ||
1406 | if (!dvb_attach(a8293_attach, dvb->fe[0], | ||
1407 | &dev->i2c_adap[dev->def_i2c_bus], | ||
1408 | &em28xx_a8293_config)) { | ||
1409 | dvb_frontend_detach(dvb->fe[0]); | ||
1410 | result = -ENODEV; | ||
1411 | goto out_free; | ||
1412 | } | ||
1413 | } | ||
1414 | break; | ||
1333 | default: | 1415 | default: |
1334 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" | 1416 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" |
1335 | " isn't supported yet\n"); | 1417 | " isn't supported yet\n"); |
@@ -1354,7 +1436,7 @@ static int em28xx_dvb_init(struct em28xx *dev) | |||
1354 | /* MFE lock */ | 1436 | /* MFE lock */ |
1355 | dvb->adapter.mfe_shared = mfe_shared; | 1437 | dvb->adapter.mfe_shared = mfe_shared; |
1356 | 1438 | ||
1357 | em28xx_info("Successfully loaded em28xx-dvb\n"); | 1439 | em28xx_info("DVB extension successfully initialized\n"); |
1358 | ret: | 1440 | ret: |
1359 | em28xx_set_mode(dev, EM28XX_SUSPEND); | 1441 | em28xx_set_mode(dev, EM28XX_SUSPEND); |
1360 | mutex_unlock(&dev->lock); | 1442 | mutex_unlock(&dev->lock); |
@@ -1375,14 +1457,23 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops) | |||
1375 | 1457 | ||
1376 | static int em28xx_dvb_fini(struct em28xx *dev) | 1458 | static int em28xx_dvb_fini(struct em28xx *dev) |
1377 | { | 1459 | { |
1460 | if (dev->is_audio_only) { | ||
1461 | /* Shouldn't initialize IR for this interface */ | ||
1462 | return 0; | ||
1463 | } | ||
1464 | |||
1378 | if (!dev->board.has_dvb) { | 1465 | if (!dev->board.has_dvb) { |
1379 | /* This device does not support the extension */ | 1466 | /* This device does not support the extension */ |
1380 | return 0; | 1467 | return 0; |
1381 | } | 1468 | } |
1382 | 1469 | ||
1470 | em28xx_info("Closing DVB extension"); | ||
1471 | |||
1383 | if (dev->dvb) { | 1472 | if (dev->dvb) { |
1384 | struct em28xx_dvb *dvb = dev->dvb; | 1473 | struct em28xx_dvb *dvb = dev->dvb; |
1385 | 1474 | ||
1475 | em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); | ||
1476 | |||
1386 | if (dev->disconnected) { | 1477 | if (dev->disconnected) { |
1387 | /* We cannot tell the device to sleep | 1478 | /* We cannot tell the device to sleep |
1388 | * once it has been unplugged. */ | 1479 | * once it has been unplugged. */ |
@@ -1392,6 +1483,7 @@ static int em28xx_dvb_fini(struct em28xx *dev) | |||
1392 | prevent_sleep(&dvb->fe[1]->ops); | 1483 | prevent_sleep(&dvb->fe[1]->ops); |
1393 | } | 1484 | } |
1394 | 1485 | ||
1486 | i2c_release_client(dvb->i2c_client_tuner); | ||
1395 | em28xx_unregister_dvb(dvb); | 1487 | em28xx_unregister_dvb(dvb); |
1396 | kfree(dvb); | 1488 | kfree(dvb); |
1397 | dev->dvb = NULL; | 1489 | dev->dvb = NULL; |
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index c4ff9739a7ae..7e1724076ac4 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/usb.h> | 27 | #include <linux/usb.h> |
28 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
29 | #include <linux/jiffies.h> | ||
29 | 30 | ||
30 | #include "em28xx.h" | 31 | #include "em28xx.h" |
31 | #include "tuner-xc2028.h" | 32 | #include "tuner-xc2028.h" |
@@ -40,7 +41,7 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | |||
40 | 41 | ||
41 | static unsigned int i2c_debug; | 42 | static unsigned int i2c_debug; |
42 | module_param(i2c_debug, int, 0644); | 43 | module_param(i2c_debug, int, 0644); |
43 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | 44 | MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)"); |
44 | 45 | ||
45 | /* | 46 | /* |
46 | * em2800_i2c_send_bytes() | 47 | * em2800_i2c_send_bytes() |
@@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | |||
48 | */ | 49 | */ |
49 | static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) | 50 | static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) |
50 | { | 51 | { |
52 | unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); | ||
51 | int ret; | 53 | int ret; |
52 | int write_timeout; | ||
53 | u8 b2[6]; | 54 | u8 b2[6]; |
54 | 55 | ||
55 | if (len < 1 || len > 4) | 56 | if (len < 1 || len > 4) |
@@ -74,22 +75,26 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) | |||
74 | return (ret < 0) ? ret : -EIO; | 75 | return (ret < 0) ? ret : -EIO; |
75 | } | 76 | } |
76 | /* wait for completion */ | 77 | /* wait for completion */ |
77 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; | 78 | while (time_is_after_jiffies(timeout)) { |
78 | write_timeout -= 5) { | ||
79 | ret = dev->em28xx_read_reg(dev, 0x05); | 79 | ret = dev->em28xx_read_reg(dev, 0x05); |
80 | if (ret == 0x80 + len - 1) { | 80 | if (ret == 0x80 + len - 1) |
81 | return len; | 81 | return len; |
82 | } else if (ret == 0x94 + len - 1) { | 82 | if (ret == 0x94 + len - 1) { |
83 | return -ENODEV; | 83 | if (i2c_debug == 1) |
84 | } else if (ret < 0) { | 84 | em28xx_warn("R05 returned 0x%02x: I2C timeout", |
85 | ret); | ||
86 | return -ENXIO; | ||
87 | } | ||
88 | if (ret < 0) { | ||
85 | em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", | 89 | em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", |
86 | ret); | 90 | ret); |
87 | return ret; | 91 | return ret; |
88 | } | 92 | } |
89 | msleep(5); | 93 | msleep(5); |
90 | } | 94 | } |
91 | em28xx_warn("write to i2c device at 0x%x timed out\n", addr); | 95 | if (i2c_debug) |
92 | return -EIO; | 96 | em28xx_warn("write to i2c device at 0x%x timed out\n", addr); |
97 | return -ETIMEDOUT; | ||
93 | } | 98 | } |
94 | 99 | ||
95 | /* | 100 | /* |
@@ -98,9 +103,9 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) | |||
98 | */ | 103 | */ |
99 | static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) | 104 | static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) |
100 | { | 105 | { |
106 | unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); | ||
101 | u8 buf2[4]; | 107 | u8 buf2[4]; |
102 | int ret; | 108 | int ret; |
103 | int read_timeout; | ||
104 | int i; | 109 | int i; |
105 | 110 | ||
106 | if (len < 1 || len > 4) | 111 | if (len < 1 || len > 4) |
@@ -117,22 +122,28 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) | |||
117 | } | 122 | } |
118 | 123 | ||
119 | /* wait for completion */ | 124 | /* wait for completion */ |
120 | for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0; | 125 | while (time_is_after_jiffies(timeout)) { |
121 | read_timeout -= 5) { | ||
122 | ret = dev->em28xx_read_reg(dev, 0x05); | 126 | ret = dev->em28xx_read_reg(dev, 0x05); |
123 | if (ret == 0x84 + len - 1) { | 127 | if (ret == 0x84 + len - 1) |
124 | break; | 128 | break; |
125 | } else if (ret == 0x94 + len - 1) { | 129 | if (ret == 0x94 + len - 1) { |
126 | return -ENODEV; | 130 | if (i2c_debug == 1) |
127 | } else if (ret < 0) { | 131 | em28xx_warn("R05 returned 0x%02x: I2C timeout", |
132 | ret); | ||
133 | return -ENXIO; | ||
134 | } | ||
135 | if (ret < 0) { | ||
128 | em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", | 136 | em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", |
129 | ret); | 137 | ret); |
130 | return ret; | 138 | return ret; |
131 | } | 139 | } |
132 | msleep(5); | 140 | msleep(5); |
133 | } | 141 | } |
134 | if (ret != 0x84 + len - 1) | 142 | if (ret != 0x84 + len - 1) { |
135 | em28xx_warn("read from i2c device at 0x%x timed out\n", addr); | 143 | if (i2c_debug) |
144 | em28xx_warn("read from i2c device at 0x%x timed out\n", | ||
145 | addr); | ||
146 | } | ||
136 | 147 | ||
137 | /* get the received message */ | 148 | /* get the received message */ |
138 | ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); | 149 | ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); |
@@ -168,7 +179,8 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr) | |||
168 | static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, | 179 | static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, |
169 | u16 len, int stop) | 180 | u16 len, int stop) |
170 | { | 181 | { |
171 | int write_timeout, ret; | 182 | unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); |
183 | int ret; | ||
172 | 184 | ||
173 | if (len < 1 || len > 64) | 185 | if (len < 1 || len > 64) |
174 | return -EOPNOTSUPP; | 186 | return -EOPNOTSUPP; |
@@ -191,16 +203,19 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, | |||
191 | } | 203 | } |
192 | } | 204 | } |
193 | 205 | ||
194 | /* Check success of the i2c operation */ | 206 | /* wait for completion */ |
195 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; | 207 | while (time_is_after_jiffies(timeout)) { |
196 | write_timeout -= 5) { | ||
197 | ret = dev->em28xx_read_reg(dev, 0x05); | 208 | ret = dev->em28xx_read_reg(dev, 0x05); |
198 | if (ret == 0) { /* success */ | 209 | if (ret == 0) /* success */ |
199 | return len; | 210 | return len; |
200 | } else if (ret == 0x10) { | 211 | if (ret == 0x10) { |
201 | return -ENODEV; | 212 | if (i2c_debug == 1) |
202 | } else if (ret < 0) { | 213 | em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", |
203 | em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n", | 214 | addr); |
215 | return -ENXIO; | ||
216 | } | ||
217 | if (ret < 0) { | ||
218 | em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", | ||
204 | ret); | 219 | ret); |
205 | return ret; | 220 | return ret; |
206 | } | 221 | } |
@@ -211,8 +226,10 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, | |||
211 | * (even with high payload) ... | 226 | * (even with high payload) ... |
212 | */ | 227 | */ |
213 | } | 228 | } |
214 | em28xx_warn("write to i2c device at 0x%x timed out\n", addr); | 229 | if (i2c_debug) |
215 | return -EIO; | 230 | em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", |
231 | addr, ret); | ||
232 | return -ETIMEDOUT; | ||
216 | } | 233 | } |
217 | 234 | ||
218 | /* | 235 | /* |
@@ -242,26 +259,28 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) | |||
242 | * bytes if we are on bus B AND there was no write attempt to the | 259 | * bytes if we are on bus B AND there was no write attempt to the |
243 | * specified slave address before AND no device is present at the | 260 | * specified slave address before AND no device is present at the |
244 | * requested slave address. | 261 | * requested slave address. |
245 | * Anyway, the next check will fail with -ENODEV in this case, so avoid | 262 | * Anyway, the next check will fail with -ENXIO in this case, so avoid |
246 | * spamming the system log on device probing and do nothing here. | 263 | * spamming the system log on device probing and do nothing here. |
247 | */ | 264 | */ |
248 | 265 | ||
249 | /* Check success of the i2c operation */ | 266 | /* Check success of the i2c operation */ |
250 | ret = dev->em28xx_read_reg(dev, 0x05); | 267 | ret = dev->em28xx_read_reg(dev, 0x05); |
268 | if (ret == 0) /* success */ | ||
269 | return len; | ||
251 | if (ret < 0) { | 270 | if (ret < 0) { |
252 | em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n", | 271 | em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", |
253 | ret); | 272 | ret); |
254 | return ret; | 273 | return ret; |
255 | } | 274 | } |
256 | if (ret > 0) { | 275 | if (ret == 0x10) { |
257 | if (ret == 0x10) { | 276 | if (i2c_debug == 1) |
258 | return -ENODEV; | 277 | em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", |
259 | } else { | 278 | addr); |
260 | em28xx_warn("unknown i2c error (status=%i)\n", ret); | 279 | return -ENXIO; |
261 | return -EIO; | ||
262 | } | ||
263 | } | 280 | } |
264 | return len; | 281 | |
282 | em28xx_warn("unknown i2c error (status=%i)\n", ret); | ||
283 | return -ETIMEDOUT; | ||
265 | } | 284 | } |
266 | 285 | ||
267 | /* | 286 | /* |
@@ -316,8 +335,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, | |||
316 | */ | 335 | */ |
317 | if (!ret) | 336 | if (!ret) |
318 | return len; | 337 | return len; |
319 | else if (ret > 0) | 338 | else if (ret > 0) { |
320 | return -ENODEV; | 339 | if (i2c_debug == 1) |
340 | em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", | ||
341 | ret); | ||
342 | return -ENXIO; | ||
343 | } | ||
321 | 344 | ||
322 | return ret; | 345 | return ret; |
323 | /* | 346 | /* |
@@ -355,7 +378,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, | |||
355 | * bytes if we are on bus B AND there was no write attempt to the | 378 | * bytes if we are on bus B AND there was no write attempt to the |
356 | * specified slave address before AND no device is present at the | 379 | * specified slave address before AND no device is present at the |
357 | * requested slave address. | 380 | * requested slave address. |
358 | * Anyway, the next check will fail with -ENODEV in this case, so avoid | 381 | * Anyway, the next check will fail with -ENXIO in this case, so avoid |
359 | * spamming the system log on device probing and do nothing here. | 382 | * spamming the system log on device probing and do nothing here. |
360 | */ | 383 | */ |
361 | 384 | ||
@@ -367,8 +390,12 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, | |||
367 | */ | 390 | */ |
368 | if (!ret) | 391 | if (!ret) |
369 | return len; | 392 | return len; |
370 | else if (ret > 0) | 393 | else if (ret > 0) { |
371 | return -ENODEV; | 394 | if (i2c_debug == 1) |
395 | em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", | ||
396 | ret); | ||
397 | return -ENXIO; | ||
398 | } | ||
372 | 399 | ||
373 | return ret; | 400 | return ret; |
374 | /* | 401 | /* |
@@ -409,10 +436,6 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr) | |||
409 | rc = em2800_i2c_check_for_device(dev, addr); | 436 | rc = em2800_i2c_check_for_device(dev, addr); |
410 | else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) | 437 | else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) |
411 | rc = em25xx_bus_B_check_for_device(dev, addr); | 438 | rc = em25xx_bus_B_check_for_device(dev, addr); |
412 | if (rc == -ENODEV) { | ||
413 | if (i2c_debug) | ||
414 | printk(" no device\n"); | ||
415 | } | ||
416 | return rc; | 439 | return rc; |
417 | } | 440 | } |
418 | 441 | ||
@@ -421,7 +444,7 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus, | |||
421 | { | 444 | { |
422 | struct em28xx *dev = i2c_bus->dev; | 445 | struct em28xx *dev = i2c_bus->dev; |
423 | u16 addr = msg.addr << 1; | 446 | u16 addr = msg.addr << 1; |
424 | int byte, rc = -EOPNOTSUPP; | 447 | int rc = -EOPNOTSUPP; |
425 | 448 | ||
426 | if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) | 449 | if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) |
427 | rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len); | 450 | rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len); |
@@ -429,10 +452,6 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus, | |||
429 | rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len); | 452 | rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len); |
430 | else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) | 453 | else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) |
431 | rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len); | 454 | rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len); |
432 | if (i2c_debug) { | ||
433 | for (byte = 0; byte < msg.len; byte++) | ||
434 | printk(" %02x", msg.buf[byte]); | ||
435 | } | ||
436 | return rc; | 455 | return rc; |
437 | } | 456 | } |
438 | 457 | ||
@@ -441,12 +460,8 @@ static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus, | |||
441 | { | 460 | { |
442 | struct em28xx *dev = i2c_bus->dev; | 461 | struct em28xx *dev = i2c_bus->dev; |
443 | u16 addr = msg.addr << 1; | 462 | u16 addr = msg.addr << 1; |
444 | int byte, rc = -EOPNOTSUPP; | 463 | int rc = -EOPNOTSUPP; |
445 | 464 | ||
446 | if (i2c_debug) { | ||
447 | for (byte = 0; byte < msg.len; byte++) | ||
448 | printk(" %02x", msg.buf[byte]); | ||
449 | } | ||
450 | if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) | 465 | if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) |
451 | rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop); | 466 | rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop); |
452 | else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) | 467 | else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) |
@@ -491,33 +506,53 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
491 | } | 506 | } |
492 | for (i = 0; i < num; i++) { | 507 | for (i = 0; i < num; i++) { |
493 | addr = msgs[i].addr << 1; | 508 | addr = msgs[i].addr << 1; |
494 | if (i2c_debug) | 509 | if (i2c_debug > 1) |
495 | printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:", | 510 | printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:", |
496 | dev->name, __func__ , | 511 | dev->name, __func__ , |
497 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", | 512 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", |
498 | i == num - 1 ? "stop" : "nonstop", | 513 | i == num - 1 ? "stop" : "nonstop", |
499 | addr, msgs[i].len); | 514 | addr, msgs[i].len); |
500 | if (!msgs[i].len) { /* no len: check only for device presence */ | 515 | if (!msgs[i].len) { |
516 | /* | ||
517 | * no len: check only for device presence | ||
518 | * This code is only called during device probe. | ||
519 | */ | ||
501 | rc = i2c_check_for_device(i2c_bus, addr); | 520 | rc = i2c_check_for_device(i2c_bus, addr); |
502 | if (rc == -ENODEV) { | 521 | if (rc < 0) { |
522 | if (rc == -ENXIO) { | ||
523 | if (i2c_debug > 1) | ||
524 | printk(KERN_CONT " no device\n"); | ||
525 | rc = -ENODEV; | ||
526 | } else { | ||
527 | if (i2c_debug > 1) | ||
528 | printk(KERN_CONT " ERROR: %i\n", rc); | ||
529 | } | ||
503 | rt_mutex_unlock(&dev->i2c_bus_lock); | 530 | rt_mutex_unlock(&dev->i2c_bus_lock); |
504 | return rc; | 531 | return rc; |
505 | } | 532 | } |
506 | } else if (msgs[i].flags & I2C_M_RD) { | 533 | } else if (msgs[i].flags & I2C_M_RD) { |
507 | /* read bytes */ | 534 | /* read bytes */ |
508 | rc = i2c_recv_bytes(i2c_bus, msgs[i]); | 535 | rc = i2c_recv_bytes(i2c_bus, msgs[i]); |
536 | |||
537 | if (i2c_debug > 1 && rc >= 0) | ||
538 | printk(KERN_CONT " %*ph", | ||
539 | msgs[i].len, msgs[i].buf); | ||
509 | } else { | 540 | } else { |
541 | if (i2c_debug > 1) | ||
542 | printk(KERN_CONT " %*ph", | ||
543 | msgs[i].len, msgs[i].buf); | ||
544 | |||
510 | /* write bytes */ | 545 | /* write bytes */ |
511 | rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1); | 546 | rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1); |
512 | } | 547 | } |
513 | if (rc < 0) { | 548 | if (rc < 0) { |
514 | if (i2c_debug) | 549 | if (i2c_debug > 1) |
515 | printk(" ERROR: %i\n", rc); | 550 | printk(KERN_CONT " ERROR: %i\n", rc); |
516 | rt_mutex_unlock(&dev->i2c_bus_lock); | 551 | rt_mutex_unlock(&dev->i2c_bus_lock); |
517 | return rc; | 552 | return rc; |
518 | } | 553 | } |
519 | if (i2c_debug) | 554 | if (i2c_debug > 1) |
520 | printk("\n"); | 555 | printk(KERN_CONT "\n"); |
521 | } | 556 | } |
522 | 557 | ||
523 | rt_mutex_unlock(&dev->i2c_bus_lock); | 558 | rt_mutex_unlock(&dev->i2c_bus_lock); |
@@ -600,7 +635,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, | |||
600 | * calculation and returned device dataset. Simplifies the code a lot, | 635 | * calculation and returned device dataset. Simplifies the code a lot, |
601 | * but we might have to deal with multiple sizes in the future ! | 636 | * but we might have to deal with multiple sizes in the future ! |
602 | */ | 637 | */ |
603 | int i, err; | 638 | int err; |
604 | struct em28xx_eeprom *dev_config; | 639 | struct em28xx_eeprom *dev_config; |
605 | u8 buf, *data; | 640 | u8 buf, *data; |
606 | 641 | ||
@@ -631,20 +666,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, | |||
631 | goto error; | 666 | goto error; |
632 | } | 667 | } |
633 | 668 | ||
634 | /* Display eeprom content */ | 669 | if (i2c_debug) { |
635 | for (i = 0; i < len; i++) { | 670 | /* Display eeprom content */ |
636 | if (0 == (i % 16)) { | 671 | print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET, |
637 | if (dev->eeprom_addrwidth_16bit) | 672 | 16, 1, data, len, true); |
638 | em28xx_info("i2c eeprom %04x:", i); | 673 | |
639 | else | 674 | if (dev->eeprom_addrwidth_16bit) |
640 | em28xx_info("i2c eeprom %02x:", i); | 675 | em28xx_info("eeprom %06x: ... (skipped)\n", 256); |
641 | } | ||
642 | printk(" %02x", data[i]); | ||
643 | if (15 == (i % 16)) | ||
644 | printk("\n"); | ||
645 | } | 676 | } |
646 | if (dev->eeprom_addrwidth_16bit) | ||
647 | em28xx_info("i2c eeprom %04x: ... (skipped)\n", i); | ||
648 | 677 | ||
649 | if (dev->eeprom_addrwidth_16bit && | 678 | if (dev->eeprom_addrwidth_16bit && |
650 | data[0] == 0x26 && data[3] == 0x00) { | 679 | data[0] == 0x26 && data[3] == 0x00) { |
@@ -736,10 +765,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, | |||
736 | em28xx_info("\tAC97 audio (5 sample rates)\n"); | 765 | em28xx_info("\tAC97 audio (5 sample rates)\n"); |
737 | break; | 766 | break; |
738 | case 2: | 767 | case 2: |
739 | em28xx_info("\tI2S audio, sample rate=32k\n"); | 768 | if (dev->chip_id < CHIP_ID_EM2860) |
769 | em28xx_info("\tI2S audio, sample rate=32k\n"); | ||
770 | else | ||
771 | em28xx_info("\tI2S audio, 3 sample rates\n"); | ||
740 | break; | 772 | break; |
741 | case 3: | 773 | case 3: |
742 | em28xx_info("\tI2S audio, 3 sample rates\n"); | 774 | if (dev->chip_id < CHIP_ID_EM2860) |
775 | em28xx_info("\tI2S audio, 3 sample rates\n"); | ||
776 | else | ||
777 | em28xx_info("\tI2S audio, 5 sample rates\n"); | ||
743 | break; | 778 | break; |
744 | } | 779 | } |
745 | 780 | ||
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index ea181e4b68c5..18f65d89d4bc 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c | |||
@@ -30,8 +30,9 @@ | |||
30 | 30 | ||
31 | #include "em28xx.h" | 31 | #include "em28xx.h" |
32 | 32 | ||
33 | #define EM28XX_SNAPSHOT_KEY KEY_CAMERA | 33 | #define EM28XX_SNAPSHOT_KEY KEY_CAMERA |
34 | #define EM28XX_SBUTTON_QUERY_INTERVAL 500 | 34 | #define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL 500 /* [ms] */ |
35 | #define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL 100 /* [ms] */ | ||
35 | 36 | ||
36 | static unsigned int ir_debug; | 37 | static unsigned int ir_debug; |
37 | module_param(ir_debug, int, 0644); | 38 | module_param(ir_debug, int, 0644); |
@@ -442,6 +443,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) | |||
442 | case CHIP_ID_EM2884: | 443 | case CHIP_ID_EM2884: |
443 | case CHIP_ID_EM2874: | 444 | case CHIP_ID_EM2874: |
444 | case CHIP_ID_EM28174: | 445 | case CHIP_ID_EM28174: |
446 | case CHIP_ID_EM28178: | ||
445 | return em2874_ir_change_protocol(rc_dev, rc_type); | 447 | return em2874_ir_change_protocol(rc_dev, rc_type); |
446 | default: | 448 | default: |
447 | printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n", | 449 | printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n", |
@@ -470,54 +472,98 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev) | |||
470 | } | 472 | } |
471 | 473 | ||
472 | /********************************************************** | 474 | /********************************************************** |
473 | Handle Webcam snapshot button | 475 | Handle buttons |
474 | **********************************************************/ | 476 | **********************************************************/ |
475 | 477 | ||
476 | static void em28xx_query_sbutton(struct work_struct *work) | 478 | static void em28xx_query_buttons(struct work_struct *work) |
477 | { | 479 | { |
478 | /* Poll the register and see if the button is depressed */ | ||
479 | struct em28xx *dev = | 480 | struct em28xx *dev = |
480 | container_of(work, struct em28xx, sbutton_query_work.work); | 481 | container_of(work, struct em28xx, buttons_query_work.work); |
481 | int ret; | 482 | u8 i, j; |
482 | 483 | int regval; | |
483 | ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP); | 484 | bool is_pressed, was_pressed; |
484 | 485 | const struct em28xx_led *led; | |
485 | if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) { | 486 | |
486 | u8 cleared; | 487 | /* Poll and evaluate all addresses */ |
487 | /* Button is depressed, clear the register */ | 488 | for (i = 0; i < dev->num_button_polling_addresses; i++) { |
488 | cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT; | 489 | /* Read value from register */ |
489 | em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1); | 490 | regval = em28xx_read_reg(dev, dev->button_polling_addresses[i]); |
490 | 491 | if (regval < 0) | |
491 | /* Not emulate the keypress */ | 492 | continue; |
492 | input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, | 493 | /* Check states of the buttons and act */ |
493 | 1); | 494 | j = 0; |
494 | /* Now unpress the key */ | 495 | while (dev->board.buttons[j].role >= 0 && |
495 | input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, | 496 | dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) { |
496 | 0); | 497 | struct em28xx_button *button = &dev->board.buttons[j]; |
498 | /* Check if button uses the current address */ | ||
499 | if (button->reg_r != dev->button_polling_addresses[i]) { | ||
500 | j++; | ||
501 | continue; | ||
502 | } | ||
503 | /* Determine if button is and was pressed last time */ | ||
504 | is_pressed = regval & button->mask; | ||
505 | was_pressed = dev->button_polling_last_values[i] | ||
506 | & button->mask; | ||
507 | if (button->inverted) { | ||
508 | is_pressed = !is_pressed; | ||
509 | was_pressed = !was_pressed; | ||
510 | } | ||
511 | /* Clear button state (if needed) */ | ||
512 | if (is_pressed && button->reg_clearing) | ||
513 | em28xx_write_reg(dev, button->reg_clearing, | ||
514 | (~regval & button->mask) | ||
515 | | (regval & ~button->mask)); | ||
516 | /* Handle button state */ | ||
517 | if (!is_pressed || was_pressed) { | ||
518 | j++; | ||
519 | continue; | ||
520 | } | ||
521 | switch (button->role) { | ||
522 | case EM28XX_BUTTON_SNAPSHOT: | ||
523 | /* Emulate the keypress */ | ||
524 | input_report_key(dev->sbutton_input_dev, | ||
525 | EM28XX_SNAPSHOT_KEY, 1); | ||
526 | /* Unpress the key */ | ||
527 | input_report_key(dev->sbutton_input_dev, | ||
528 | EM28XX_SNAPSHOT_KEY, 0); | ||
529 | break; | ||
530 | case EM28XX_BUTTON_ILLUMINATION: | ||
531 | led = em28xx_find_led(dev, | ||
532 | EM28XX_LED_ILLUMINATION); | ||
533 | /* Switch illumination LED on/off */ | ||
534 | if (led) | ||
535 | em28xx_toggle_reg_bits(dev, | ||
536 | led->gpio_reg, | ||
537 | led->gpio_mask); | ||
538 | break; | ||
539 | default: | ||
540 | WARN_ONCE(1, "BUG: unhandled button role."); | ||
541 | } | ||
542 | /* Next button */ | ||
543 | j++; | ||
544 | } | ||
545 | /* Save current value for comparison during the next polling */ | ||
546 | dev->button_polling_last_values[i] = regval; | ||
497 | } | 547 | } |
498 | |||
499 | /* Schedule next poll */ | 548 | /* Schedule next poll */ |
500 | schedule_delayed_work(&dev->sbutton_query_work, | 549 | schedule_delayed_work(&dev->buttons_query_work, |
501 | msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); | 550 | msecs_to_jiffies(dev->button_polling_interval)); |
502 | } | 551 | } |
503 | 552 | ||
504 | static void em28xx_register_snapshot_button(struct em28xx *dev) | 553 | static int em28xx_register_snapshot_button(struct em28xx *dev) |
505 | { | 554 | { |
506 | struct input_dev *input_dev; | 555 | struct input_dev *input_dev; |
507 | int err; | 556 | int err; |
508 | 557 | ||
509 | em28xx_info("Registering snapshot button...\n"); | 558 | em28xx_info("Registering snapshot button...\n"); |
510 | input_dev = input_allocate_device(); | 559 | input_dev = input_allocate_device(); |
511 | if (!input_dev) { | 560 | if (!input_dev) |
512 | em28xx_errdev("input_allocate_device failed\n"); | 561 | return -ENOMEM; |
513 | return; | ||
514 | } | ||
515 | 562 | ||
516 | usb_make_path(dev->udev, dev->snapshot_button_path, | 563 | usb_make_path(dev->udev, dev->snapshot_button_path, |
517 | sizeof(dev->snapshot_button_path)); | 564 | sizeof(dev->snapshot_button_path)); |
518 | strlcat(dev->snapshot_button_path, "/sbutton", | 565 | strlcat(dev->snapshot_button_path, "/sbutton", |
519 | sizeof(dev->snapshot_button_path)); | 566 | sizeof(dev->snapshot_button_path)); |
520 | INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton); | ||
521 | 567 | ||
522 | input_dev->name = "em28xx snapshot button"; | 568 | input_dev->name = "em28xx snapshot button"; |
523 | input_dev->phys = dev->snapshot_button_path; | 569 | input_dev->phys = dev->snapshot_button_path; |
@@ -535,25 +581,86 @@ static void em28xx_register_snapshot_button(struct em28xx *dev) | |||
535 | if (err) { | 581 | if (err) { |
536 | em28xx_errdev("input_register_device failed\n"); | 582 | em28xx_errdev("input_register_device failed\n"); |
537 | input_free_device(input_dev); | 583 | input_free_device(input_dev); |
538 | return; | 584 | return err; |
539 | } | 585 | } |
540 | 586 | ||
541 | dev->sbutton_input_dev = input_dev; | 587 | dev->sbutton_input_dev = input_dev; |
542 | schedule_delayed_work(&dev->sbutton_query_work, | 588 | return 0; |
543 | msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); | 589 | } |
544 | return; | ||
545 | 590 | ||
591 | static void em28xx_init_buttons(struct em28xx *dev) | ||
592 | { | ||
593 | u8 i = 0, j = 0; | ||
594 | bool addr_new = 0; | ||
595 | |||
596 | dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL; | ||
597 | while (dev->board.buttons[i].role >= 0 && | ||
598 | dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) { | ||
599 | struct em28xx_button *button = &dev->board.buttons[i]; | ||
600 | /* Check if polling address is already on the list */ | ||
601 | addr_new = 1; | ||
602 | for (j = 0; j < dev->num_button_polling_addresses; j++) { | ||
603 | if (button->reg_r == dev->button_polling_addresses[j]) { | ||
604 | addr_new = 0; | ||
605 | break; | ||
606 | } | ||
607 | } | ||
608 | /* Check if max. number of polling addresses is exceeded */ | ||
609 | if (addr_new && dev->num_button_polling_addresses | ||
610 | >= EM28XX_NUM_BUTTON_ADDRESSES_MAX) { | ||
611 | WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded."); | ||
612 | goto next_button; | ||
613 | } | ||
614 | /* Button role specific checks and actions */ | ||
615 | if (button->role == EM28XX_BUTTON_SNAPSHOT) { | ||
616 | /* Register input device */ | ||
617 | if (em28xx_register_snapshot_button(dev) < 0) | ||
618 | goto next_button; | ||
619 | } else if (button->role == EM28XX_BUTTON_ILLUMINATION) { | ||
620 | /* Check sanity */ | ||
621 | if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) { | ||
622 | em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n"); | ||
623 | goto next_button; | ||
624 | } | ||
625 | } | ||
626 | /* Add read address to list of polling addresses */ | ||
627 | if (addr_new) { | ||
628 | unsigned int index = dev->num_button_polling_addresses; | ||
629 | dev->button_polling_addresses[index] = button->reg_r; | ||
630 | dev->num_button_polling_addresses++; | ||
631 | } | ||
632 | /* Reduce polling interval if necessary */ | ||
633 | if (!button->reg_clearing) | ||
634 | dev->button_polling_interval = | ||
635 | EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL; | ||
636 | next_button: | ||
637 | /* Next button */ | ||
638 | i++; | ||
639 | } | ||
640 | |||
641 | /* Start polling */ | ||
642 | if (dev->num_button_polling_addresses) { | ||
643 | memset(dev->button_polling_last_values, 0, | ||
644 | EM28XX_NUM_BUTTON_ADDRESSES_MAX); | ||
645 | INIT_DELAYED_WORK(&dev->buttons_query_work, | ||
646 | em28xx_query_buttons); | ||
647 | schedule_delayed_work(&dev->buttons_query_work, | ||
648 | msecs_to_jiffies(dev->button_polling_interval)); | ||
649 | } | ||
546 | } | 650 | } |
547 | 651 | ||
548 | static void em28xx_deregister_snapshot_button(struct em28xx *dev) | 652 | static void em28xx_shutdown_buttons(struct em28xx *dev) |
549 | { | 653 | { |
654 | /* Cancel polling */ | ||
655 | cancel_delayed_work_sync(&dev->buttons_query_work); | ||
656 | /* Clear polling addresses list */ | ||
657 | dev->num_button_polling_addresses = 0; | ||
658 | /* Deregister input devices */ | ||
550 | if (dev->sbutton_input_dev != NULL) { | 659 | if (dev->sbutton_input_dev != NULL) { |
551 | em28xx_info("Deregistering snapshot button\n"); | 660 | em28xx_info("Deregistering snapshot button\n"); |
552 | cancel_delayed_work_sync(&dev->sbutton_query_work); | ||
553 | input_unregister_device(dev->sbutton_input_dev); | 661 | input_unregister_device(dev->sbutton_input_dev); |
554 | dev->sbutton_input_dev = NULL; | 662 | dev->sbutton_input_dev = NULL; |
555 | } | 663 | } |
556 | return; | ||
557 | } | 664 | } |
558 | 665 | ||
559 | static int em28xx_ir_init(struct em28xx *dev) | 666 | static int em28xx_ir_init(struct em28xx *dev) |
@@ -564,8 +671,13 @@ static int em28xx_ir_init(struct em28xx *dev) | |||
564 | u64 rc_type; | 671 | u64 rc_type; |
565 | u16 i2c_rc_dev_addr = 0; | 672 | u16 i2c_rc_dev_addr = 0; |
566 | 673 | ||
567 | if (dev->board.has_snapshot_button) | 674 | if (dev->is_audio_only) { |
568 | em28xx_register_snapshot_button(dev); | 675 | /* Shouldn't initialize IR for this interface */ |
676 | return 0; | ||
677 | } | ||
678 | |||
679 | if (dev->board.buttons) | ||
680 | em28xx_init_buttons(dev); | ||
569 | 681 | ||
570 | if (dev->board.has_ir_i2c) { | 682 | if (dev->board.has_ir_i2c) { |
571 | i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev); | 683 | i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev); |
@@ -583,6 +695,8 @@ static int em28xx_ir_init(struct em28xx *dev) | |||
583 | return 0; | 695 | return 0; |
584 | } | 696 | } |
585 | 697 | ||
698 | em28xx_info("Registering input extension\n"); | ||
699 | |||
586 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); | 700 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); |
587 | rc = rc_allocate_device(); | 701 | rc = rc_allocate_device(); |
588 | if (!ir || !rc) | 702 | if (!ir || !rc) |
@@ -633,6 +747,7 @@ static int em28xx_ir_init(struct em28xx *dev) | |||
633 | case CHIP_ID_EM2884: | 747 | case CHIP_ID_EM2884: |
634 | case CHIP_ID_EM2874: | 748 | case CHIP_ID_EM2874: |
635 | case CHIP_ID_EM28174: | 749 | case CHIP_ID_EM28174: |
750 | case CHIP_ID_EM28178: | ||
636 | ir->get_key = em2874_polling_getkey; | 751 | ir->get_key = em2874_polling_getkey; |
637 | rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC | | 752 | rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC | |
638 | RC_BIT_RC6_0; | 753 | RC_BIT_RC6_0; |
@@ -675,6 +790,8 @@ static int em28xx_ir_init(struct em28xx *dev) | |||
675 | if (err) | 790 | if (err) |
676 | goto error; | 791 | goto error; |
677 | 792 | ||
793 | em28xx_info("Input extension successfully initalized\n"); | ||
794 | |||
678 | return 0; | 795 | return 0; |
679 | 796 | ||
680 | error: | 797 | error: |
@@ -688,7 +805,14 @@ static int em28xx_ir_fini(struct em28xx *dev) | |||
688 | { | 805 | { |
689 | struct em28xx_IR *ir = dev->ir; | 806 | struct em28xx_IR *ir = dev->ir; |
690 | 807 | ||
691 | em28xx_deregister_snapshot_button(dev); | 808 | if (dev->is_audio_only) { |
809 | /* Shouldn't initialize IR for this interface */ | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | em28xx_info("Closing input extension"); | ||
814 | |||
815 | em28xx_shutdown_buttons(dev); | ||
692 | 816 | ||
693 | /* skip detach on non attached boards */ | 817 | /* skip detach on non attached boards */ |
694 | if (!ir) | 818 | if (!ir) |
@@ -722,7 +846,8 @@ static void __exit em28xx_rc_unregister(void) | |||
722 | 846 | ||
723 | MODULE_LICENSE("GPL"); | 847 | MODULE_LICENSE("GPL"); |
724 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | 848 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); |
725 | MODULE_DESCRIPTION("Em28xx Input driver"); | 849 | MODULE_DESCRIPTION(DRIVER_DESC " - input interface"); |
850 | MODULE_VERSION(EM28XX_VERSION); | ||
726 | 851 | ||
727 | module_init(em28xx_rc_register); | 852 | module_init(em28xx_rc_register); |
728 | module_exit(em28xx_rc_unregister); | 853 | module_exit(em28xx_rc_unregister); |
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 0e0477847965..311fb349dafa 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h | |||
@@ -25,10 +25,12 @@ | |||
25 | #define EM28XX_R00_CHIPCFG 0x00 | 25 | #define EM28XX_R00_CHIPCFG 0x00 |
26 | 26 | ||
27 | /* em28xx Chip Configuration 0x00 */ | 27 | /* em28xx Chip Configuration 0x00 */ |
28 | #define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80 | 28 | #define EM2860_CHIPCFG_VENDOR_AUDIO 0x80 |
29 | #define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 | 29 | #define EM2860_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 |
30 | #define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30 | 30 | #define EM2820_CHIPCFG_I2S_3_SAMPRATES 0x30 |
31 | #define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20 | 31 | #define EM2860_CHIPCFG_I2S_5_SAMPRATES 0x30 |
32 | #define EM2820_CHIPCFG_I2S_1_SAMPRATE 0x20 | ||
33 | #define EM2860_CHIPCFG_I2S_3_SAMPRATES 0x20 | ||
32 | #define EM28XX_CHIPCFG_AC97 0x10 | 34 | #define EM28XX_CHIPCFG_AC97 0x10 |
33 | #define EM28XX_CHIPCFG_AUDIOMASK 0x30 | 35 | #define EM28XX_CHIPCFG_AUDIOMASK 0x30 |
34 | 36 | ||
@@ -245,6 +247,7 @@ enum em28xx_chip_id { | |||
245 | CHIP_ID_EM2874 = 65, | 247 | CHIP_ID_EM2874 = 65, |
246 | CHIP_ID_EM2884 = 68, | 248 | CHIP_ID_EM2884 = 68, |
247 | CHIP_ID_EM28174 = 113, | 249 | CHIP_ID_EM28174 = 113, |
250 | CHIP_ID_EM28178 = 114, | ||
248 | }; | 251 | }; |
249 | 252 | ||
250 | /* | 253 | /* |
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h new file mode 100644 index 000000000000..bce438691e0e --- /dev/null +++ b/drivers/media/usb/em28xx/em28xx-v4l.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB | ||
3 | video capture devices | ||
4 | |||
5 | Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation version 2 of the License. | ||
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 | |||
17 | |||
18 | int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); | ||
19 | int em28xx_stop_vbi_streaming(struct vb2_queue *vq); | ||
20 | extern struct vb2_ops em28xx_vbi_qops; | ||
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 39f39c527c13..db3d655600df 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | 28 | ||
29 | #include "em28xx.h" | 29 | #include "em28xx.h" |
30 | #include "em28xx-v4l.h" | ||
30 | 31 | ||
31 | static unsigned int vbibufs = 5; | 32 | static unsigned int vbibufs = 5; |
32 | module_param(vbibufs, int, 0644); | 33 | module_param(vbibufs, int, 0644); |
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index dd19c9ff76e0..c3c928937dcd 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c | |||
@@ -38,9 +38,11 @@ | |||
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | 39 | ||
40 | #include "em28xx.h" | 40 | #include "em28xx.h" |
41 | #include "em28xx-v4l.h" | ||
41 | #include <media/v4l2-common.h> | 42 | #include <media/v4l2-common.h> |
42 | #include <media/v4l2-ioctl.h> | 43 | #include <media/v4l2-ioctl.h> |
43 | #include <media/v4l2-event.h> | 44 | #include <media/v4l2-event.h> |
45 | #include <media/v4l2-clk.h> | ||
44 | #include <media/msp3400.h> | 46 | #include <media/msp3400.h> |
45 | #include <media/tuner.h> | 47 | #include <media/tuner.h> |
46 | 48 | ||
@@ -49,19 +51,23 @@ | |||
49 | "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ | 51 | "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ |
50 | "Sascha Sommer <saschasommer@freenet.de>" | 52 | "Sascha Sommer <saschasommer@freenet.de>" |
51 | 53 | ||
52 | #define DRIVER_DESC "Empia em28xx based USB video device driver" | 54 | static unsigned int isoc_debug; |
55 | module_param(isoc_debug, int, 0644); | ||
56 | MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); | ||
57 | |||
58 | static unsigned int disable_vbi; | ||
59 | module_param(disable_vbi, int, 0644); | ||
60 | MODULE_PARM_DESC(disable_vbi, "disable vbi support"); | ||
53 | 61 | ||
54 | #define EM28XX_VERSION "0.2.0" | 62 | static int alt; |
63 | module_param(alt, int, 0644); | ||
64 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); | ||
55 | 65 | ||
56 | #define em28xx_videodbg(fmt, arg...) do {\ | 66 | #define em28xx_videodbg(fmt, arg...) do {\ |
57 | if (video_debug) \ | 67 | if (video_debug) \ |
58 | printk(KERN_INFO "%s %s :"fmt, \ | 68 | printk(KERN_INFO "%s %s :"fmt, \ |
59 | dev->name, __func__ , ##arg); } while (0) | 69 | dev->name, __func__ , ##arg); } while (0) |
60 | 70 | ||
61 | static unsigned int isoc_debug; | ||
62 | module_param(isoc_debug, int, 0644); | ||
63 | MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); | ||
64 | |||
65 | #define em28xx_isocdbg(fmt, arg...) \ | 71 | #define em28xx_isocdbg(fmt, arg...) \ |
66 | do {\ | 72 | do {\ |
67 | if (isoc_debug) { \ | 73 | if (isoc_debug) { \ |
@@ -71,7 +77,7 @@ do {\ | |||
71 | } while (0) | 77 | } while (0) |
72 | 78 | ||
73 | MODULE_AUTHOR(DRIVER_AUTHOR); | 79 | MODULE_AUTHOR(DRIVER_AUTHOR); |
74 | MODULE_DESCRIPTION(DRIVER_DESC); | 80 | MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface"); |
75 | MODULE_LICENSE("GPL"); | 81 | MODULE_LICENSE("GPL"); |
76 | MODULE_VERSION(EM28XX_VERSION); | 82 | MODULE_VERSION(EM28XX_VERSION); |
77 | 83 | ||
@@ -135,6 +141,257 @@ static struct em28xx_fmt format[] = { | |||
135 | }, | 141 | }, |
136 | }; | 142 | }; |
137 | 143 | ||
144 | static int em28xx_vbi_supported(struct em28xx *dev) | ||
145 | { | ||
146 | /* Modprobe option to manually disable */ | ||
147 | if (disable_vbi == 1) | ||
148 | return 0; | ||
149 | |||
150 | if (dev->board.is_webcam) | ||
151 | return 0; | ||
152 | |||
153 | /* FIXME: check subdevices for VBI support */ | ||
154 | |||
155 | if (dev->chip_id == CHIP_ID_EM2860 || | ||
156 | dev->chip_id == CHIP_ID_EM2883) | ||
157 | return 1; | ||
158 | |||
159 | /* Version of em28xx that does not support VBI */ | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * em28xx_wake_i2c() | ||
165 | * configure i2c attached devices | ||
166 | */ | ||
167 | static void em28xx_wake_i2c(struct em28xx *dev) | ||
168 | { | ||
169 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); | ||
170 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, | ||
171 | INPUT(dev->ctl_input)->vmux, 0, 0); | ||
172 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); | ||
173 | } | ||
174 | |||
175 | static int em28xx_colorlevels_set_default(struct em28xx *dev) | ||
176 | { | ||
177 | em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT); | ||
178 | em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT); | ||
179 | em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT); | ||
180 | em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT); | ||
181 | em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT); | ||
182 | em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT); | ||
183 | |||
184 | em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); | ||
185 | em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); | ||
186 | em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); | ||
187 | em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); | ||
188 | em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); | ||
189 | em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); | ||
190 | return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); | ||
191 | } | ||
192 | |||
193 | static int em28xx_set_outfmt(struct em28xx *dev) | ||
194 | { | ||
195 | int ret; | ||
196 | u8 fmt, vinctrl; | ||
197 | |||
198 | fmt = dev->format->reg; | ||
199 | if (!dev->is_em25xx) | ||
200 | fmt |= 0x20; | ||
201 | /* | ||
202 | * NOTE: it's not clear if this is really needed ! | ||
203 | * The datasheets say bit 5 is a reserved bit and devices seem to work | ||
204 | * fine without it. But the Windows driver sets it for em2710/50+em28xx | ||
205 | * devices and we've always been setting it, too. | ||
206 | * | ||
207 | * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set, | ||
208 | * it's likely used for an additional (compressed ?) format there. | ||
209 | */ | ||
210 | ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt); | ||
211 | if (ret < 0) | ||
212 | return ret; | ||
213 | |||
214 | ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); | ||
215 | if (ret < 0) | ||
216 | return ret; | ||
217 | |||
218 | vinctrl = dev->vinctl; | ||
219 | if (em28xx_vbi_supported(dev) == 1) { | ||
220 | vinctrl |= EM28XX_VINCTRL_VBI_RAW; | ||
221 | em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); | ||
222 | em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4); | ||
223 | em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height); | ||
224 | if (dev->norm & V4L2_STD_525_60) { | ||
225 | /* NTSC */ | ||
226 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); | ||
227 | } else if (dev->norm & V4L2_STD_625_50) { | ||
228 | /* PAL */ | ||
229 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); | ||
234 | } | ||
235 | |||
236 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, | ||
237 | u8 ymin, u8 ymax) | ||
238 | { | ||
239 | em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n", | ||
240 | xmin, ymin, xmax, ymax); | ||
241 | |||
242 | em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); | ||
243 | em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); | ||
244 | em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); | ||
245 | return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); | ||
246 | } | ||
247 | |||
248 | static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, | ||
249 | u16 width, u16 height) | ||
250 | { | ||
251 | u8 cwidth = width >> 2; | ||
252 | u8 cheight = height >> 2; | ||
253 | u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01); | ||
254 | /* NOTE: size limit: 2047x1023 = 2MPix */ | ||
255 | |||
256 | em28xx_videodbg("capture area set to (%d,%d): %dx%d\n", | ||
257 | hstart, vstart, | ||
258 | ((overflow & 2) << 9 | cwidth << 2), | ||
259 | ((overflow & 1) << 10 | cheight << 2)); | ||
260 | |||
261 | em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); | ||
262 | em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); | ||
263 | em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); | ||
264 | em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); | ||
265 | em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); | ||
266 | |||
267 | /* FIXME: function/meaning of these registers ? */ | ||
268 | /* FIXME: align width+height to multiples of 4 ?! */ | ||
269 | if (dev->is_em25xx) { | ||
270 | em28xx_write_reg(dev, 0x34, width >> 4); | ||
271 | em28xx_write_reg(dev, 0x35, height >> 4); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) | ||
276 | { | ||
277 | u8 mode; | ||
278 | /* the em2800 scaler only supports scaling down to 50% */ | ||
279 | |||
280 | if (dev->board.is_em2800) { | ||
281 | mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); | ||
282 | } else { | ||
283 | u8 buf[2]; | ||
284 | |||
285 | buf[0] = h; | ||
286 | buf[1] = h >> 8; | ||
287 | em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); | ||
288 | |||
289 | buf[0] = v; | ||
290 | buf[1] = v >> 8; | ||
291 | em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); | ||
292 | /* it seems that both H and V scalers must be active | ||
293 | to work correctly */ | ||
294 | mode = (h || v) ? 0x30 : 0x00; | ||
295 | } | ||
296 | return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); | ||
297 | } | ||
298 | |||
299 | /* FIXME: this only function read values from dev */ | ||
300 | static int em28xx_resolution_set(struct em28xx *dev) | ||
301 | { | ||
302 | int width, height; | ||
303 | width = norm_maxw(dev); | ||
304 | height = norm_maxh(dev); | ||
305 | |||
306 | /* Properly setup VBI */ | ||
307 | dev->vbi_width = 720; | ||
308 | if (dev->norm & V4L2_STD_525_60) | ||
309 | dev->vbi_height = 12; | ||
310 | else | ||
311 | dev->vbi_height = 18; | ||
312 | |||
313 | em28xx_set_outfmt(dev); | ||
314 | |||
315 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); | ||
316 | |||
317 | /* If we don't set the start position to 2 in VBI mode, we end up | ||
318 | with line 20/21 being YUYV encoded instead of being in 8-bit | ||
319 | greyscale. The core of the issue is that line 21 (and line 23 for | ||
320 | PAL WSS) are inside of active video region, and as a result they | ||
321 | get the pixelformatting associated with that area. So by cropping | ||
322 | it out, we end up with the same format as the rest of the VBI | ||
323 | region */ | ||
324 | if (em28xx_vbi_supported(dev) == 1) | ||
325 | em28xx_capture_area_set(dev, 0, 2, width, height); | ||
326 | else | ||
327 | em28xx_capture_area_set(dev, 0, 0, width, height); | ||
328 | |||
329 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); | ||
330 | } | ||
331 | |||
332 | /* Set USB alternate setting for analog video */ | ||
333 | static int em28xx_set_alternate(struct em28xx *dev) | ||
334 | { | ||
335 | int errCode; | ||
336 | int i; | ||
337 | unsigned int min_pkt_size = dev->width * 2 + 4; | ||
338 | |||
339 | /* NOTE: for isoc transfers, only alt settings > 0 are allowed | ||
340 | bulk transfers seem to work only with alt=0 ! */ | ||
341 | dev->alt = 0; | ||
342 | if ((alt > 0) && (alt < dev->num_alt)) { | ||
343 | em28xx_videodbg("alternate forced to %d\n", dev->alt); | ||
344 | dev->alt = alt; | ||
345 | goto set_alt; | ||
346 | } | ||
347 | if (dev->analog_xfer_bulk) | ||
348 | goto set_alt; | ||
349 | |||
350 | /* When image size is bigger than a certain value, | ||
351 | the frame size should be increased, otherwise, only | ||
352 | green screen will be received. | ||
353 | */ | ||
354 | if (dev->width * 2 * dev->height > 720 * 240 * 2) | ||
355 | min_pkt_size *= 2; | ||
356 | |||
357 | for (i = 0; i < dev->num_alt; i++) { | ||
358 | /* stop when the selected alt setting offers enough bandwidth */ | ||
359 | if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { | ||
360 | dev->alt = i; | ||
361 | break; | ||
362 | /* otherwise make sure that we end up with the maximum bandwidth | ||
363 | because the min_pkt_size equation might be wrong... | ||
364 | */ | ||
365 | } else if (dev->alt_max_pkt_size_isoc[i] > | ||
366 | dev->alt_max_pkt_size_isoc[dev->alt]) | ||
367 | dev->alt = i; | ||
368 | } | ||
369 | |||
370 | set_alt: | ||
371 | /* NOTE: for bulk transfers, we need to call usb_set_interface() | ||
372 | * even if the previous settings were the same. Otherwise streaming | ||
373 | * fails with all urbs having status = -EOVERFLOW ! */ | ||
374 | if (dev->analog_xfer_bulk) { | ||
375 | dev->max_pkt_size = 512; /* USB 2.0 spec */ | ||
376 | dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; | ||
377 | } else { /* isoc */ | ||
378 | em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n", | ||
379 | min_pkt_size, dev->alt); | ||
380 | dev->max_pkt_size = | ||
381 | dev->alt_max_pkt_size_isoc[dev->alt]; | ||
382 | dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; | ||
383 | } | ||
384 | em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n", | ||
385 | dev->alt, dev->max_pkt_size); | ||
386 | errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); | ||
387 | if (errCode < 0) { | ||
388 | em28xx_errdev("cannot change alternate number to %d (error=%i)\n", | ||
389 | dev->alt, errCode); | ||
390 | return errCode; | ||
391 | } | ||
392 | return 0; | ||
393 | } | ||
394 | |||
138 | /* ------------------------------------------------------------------ | 395 | /* ------------------------------------------------------------------ |
139 | DMA and thread functions | 396 | DMA and thread functions |
140 | ------------------------------------------------------------------*/ | 397 | ------------------------------------------------------------------*/ |
@@ -763,7 +1020,7 @@ static struct vb2_ops em28xx_video_qops = { | |||
763 | .wait_finish = vb2_ops_wait_finish, | 1020 | .wait_finish = vb2_ops_wait_finish, |
764 | }; | 1021 | }; |
765 | 1022 | ||
766 | int em28xx_vb2_setup(struct em28xx *dev) | 1023 | static int em28xx_vb2_setup(struct em28xx *dev) |
767 | { | 1024 | { |
768 | int rc; | 1025 | int rc; |
769 | struct vb2_queue *q; | 1026 | struct vb2_queue *q; |
@@ -831,7 +1088,7 @@ static void video_mux(struct em28xx *dev, int index) | |||
831 | em28xx_audio_analog_set(dev); | 1088 | em28xx_audio_analog_set(dev); |
832 | } | 1089 | } |
833 | 1090 | ||
834 | void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) | 1091 | static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) |
835 | { | 1092 | { |
836 | struct em28xx *dev = priv; | 1093 | struct em28xx *dev = priv; |
837 | 1094 | ||
@@ -890,7 +1147,7 @@ static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl) | |||
890 | return (ret < 0) ? ret : 0; | 1147 | return (ret < 0) ? ret : 0; |
891 | } | 1148 | } |
892 | 1149 | ||
893 | const struct v4l2_ctrl_ops em28xx_ctrl_ops = { | 1150 | static const struct v4l2_ctrl_ops em28xx_ctrl_ops = { |
894 | .s_ctrl = em28xx_s_ctrl, | 1151 | .s_ctrl = em28xx_s_ctrl, |
895 | }; | 1152 | }; |
896 | 1153 | ||
@@ -1368,7 +1625,7 @@ static int vidioc_g_register(struct file *file, void *priv, | |||
1368 | reg->val = ret; | 1625 | reg->val = ret; |
1369 | } else { | 1626 | } else { |
1370 | __le16 val = 0; | 1627 | __le16 val = 0; |
1371 | ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, | 1628 | ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, |
1372 | reg->reg, (char *)&val, 2); | 1629 | reg->reg, (char *)&val, 2); |
1373 | if (ret < 0) | 1630 | if (ret < 0) |
1374 | return ret; | 1631 | return ret; |
@@ -1570,6 +1827,10 @@ static int em28xx_v4l2_open(struct file *filp) | |||
1570 | case VFL_TYPE_VBI: | 1827 | case VFL_TYPE_VBI: |
1571 | fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; | 1828 | fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1572 | break; | 1829 | break; |
1830 | case VFL_TYPE_RADIO: | ||
1831 | break; | ||
1832 | default: | ||
1833 | return -EINVAL; | ||
1573 | } | 1834 | } |
1574 | 1835 | ||
1575 | em28xx_videodbg("open dev=%s type=%s users=%d\n", | 1836 | em28xx_videodbg("open dev=%s type=%s users=%d\n", |
@@ -1590,15 +1851,17 @@ static int em28xx_v4l2_open(struct file *filp) | |||
1590 | fh->type = fh_type; | 1851 | fh->type = fh_type; |
1591 | filp->private_data = fh; | 1852 | filp->private_data = fh; |
1592 | 1853 | ||
1593 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { | 1854 | if (dev->users == 0) { |
1594 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); | 1855 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); |
1595 | em28xx_resolution_set(dev); | ||
1596 | 1856 | ||
1597 | /* Needed, since GPIO might have disabled power of | 1857 | if (vdev->vfl_type != VFL_TYPE_RADIO) |
1598 | some i2c device | 1858 | em28xx_resolution_set(dev); |
1859 | |||
1860 | /* | ||
1861 | * Needed, since GPIO might have disabled power | ||
1862 | * of some i2c devices | ||
1599 | */ | 1863 | */ |
1600 | em28xx_wake_i2c(dev); | 1864 | em28xx_wake_i2c(dev); |
1601 | |||
1602 | } | 1865 | } |
1603 | 1866 | ||
1604 | if (vdev->vfl_type == VFL_TYPE_RADIO) { | 1867 | if (vdev->vfl_type == VFL_TYPE_RADIO) { |
@@ -1615,40 +1878,59 @@ static int em28xx_v4l2_open(struct file *filp) | |||
1615 | } | 1878 | } |
1616 | 1879 | ||
1617 | /* | 1880 | /* |
1618 | * em28xx_realease_resources() | 1881 | * em28xx_v4l2_fini() |
1619 | * unregisters the v4l2,i2c and usb devices | 1882 | * unregisters the v4l2,i2c and usb devices |
1620 | * called when the device gets disconected or at module unload | 1883 | * called when the device gets disconected or at module unload |
1621 | */ | 1884 | */ |
1622 | void em28xx_release_analog_resources(struct em28xx *dev) | 1885 | static int em28xx_v4l2_fini(struct em28xx *dev) |
1623 | { | 1886 | { |
1887 | if (dev->is_audio_only) { | ||
1888 | /* Shouldn't initialize IR for this interface */ | ||
1889 | return 0; | ||
1890 | } | ||
1891 | |||
1892 | if (!dev->has_video) { | ||
1893 | /* This device does not support the v4l2 extension */ | ||
1894 | return 0; | ||
1895 | } | ||
1624 | 1896 | ||
1625 | /*FIXME: I2C IR should be disconnected */ | 1897 | em28xx_info("Closing video extension"); |
1898 | |||
1899 | mutex_lock(&dev->lock); | ||
1900 | |||
1901 | v4l2_device_disconnect(&dev->v4l2_dev); | ||
1902 | |||
1903 | em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); | ||
1626 | 1904 | ||
1627 | if (dev->radio_dev) { | 1905 | if (dev->radio_dev) { |
1628 | if (video_is_registered(dev->radio_dev)) | 1906 | em28xx_info("V4L2 device %s deregistered\n", |
1629 | video_unregister_device(dev->radio_dev); | 1907 | video_device_node_name(dev->radio_dev)); |
1630 | else | 1908 | video_unregister_device(dev->radio_dev); |
1631 | video_device_release(dev->radio_dev); | ||
1632 | dev->radio_dev = NULL; | ||
1633 | } | 1909 | } |
1634 | if (dev->vbi_dev) { | 1910 | if (dev->vbi_dev) { |
1635 | em28xx_info("V4L2 device %s deregistered\n", | 1911 | em28xx_info("V4L2 device %s deregistered\n", |
1636 | video_device_node_name(dev->vbi_dev)); | 1912 | video_device_node_name(dev->vbi_dev)); |
1637 | if (video_is_registered(dev->vbi_dev)) | 1913 | video_unregister_device(dev->vbi_dev); |
1638 | video_unregister_device(dev->vbi_dev); | ||
1639 | else | ||
1640 | video_device_release(dev->vbi_dev); | ||
1641 | dev->vbi_dev = NULL; | ||
1642 | } | 1914 | } |
1643 | if (dev->vdev) { | 1915 | if (dev->vdev) { |
1644 | em28xx_info("V4L2 device %s deregistered\n", | 1916 | em28xx_info("V4L2 device %s deregistered\n", |
1645 | video_device_node_name(dev->vdev)); | 1917 | video_device_node_name(dev->vdev)); |
1646 | if (video_is_registered(dev->vdev)) | 1918 | video_unregister_device(dev->vdev); |
1647 | video_unregister_device(dev->vdev); | ||
1648 | else | ||
1649 | video_device_release(dev->vdev); | ||
1650 | dev->vdev = NULL; | ||
1651 | } | 1919 | } |
1920 | |||
1921 | if (dev->clk) { | ||
1922 | v4l2_clk_unregister_fixed(dev->clk); | ||
1923 | dev->clk = NULL; | ||
1924 | } | ||
1925 | |||
1926 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
1927 | v4l2_device_unregister(&dev->v4l2_dev); | ||
1928 | |||
1929 | if (dev->users) | ||
1930 | em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n"); | ||
1931 | mutex_unlock(&dev->lock); | ||
1932 | |||
1933 | return 0; | ||
1652 | } | 1934 | } |
1653 | 1935 | ||
1654 | /* | 1936 | /* |
@@ -1668,14 +1950,10 @@ static int em28xx_v4l2_close(struct file *filp) | |||
1668 | mutex_lock(&dev->lock); | 1950 | mutex_lock(&dev->lock); |
1669 | 1951 | ||
1670 | if (dev->users == 1) { | 1952 | if (dev->users == 1) { |
1671 | /* the device is already disconnect, | 1953 | /* free the remaining resources if device is disconnected */ |
1672 | free the remaining resources */ | ||
1673 | if (dev->disconnected) { | 1954 | if (dev->disconnected) { |
1674 | em28xx_release_resources(dev); | ||
1675 | kfree(dev->alt_max_pkt_size_isoc); | 1955 | kfree(dev->alt_max_pkt_size_isoc); |
1676 | mutex_unlock(&dev->lock); | 1956 | goto exit; |
1677 | kfree(dev); | ||
1678 | return 0; | ||
1679 | } | 1957 | } |
1680 | 1958 | ||
1681 | /* Save some power by putting tuner to sleep */ | 1959 | /* Save some power by putting tuner to sleep */ |
@@ -1694,11 +1972,29 @@ static int em28xx_v4l2_close(struct file *filp) | |||
1694 | } | 1972 | } |
1695 | } | 1973 | } |
1696 | 1974 | ||
1975 | exit: | ||
1697 | dev->users--; | 1976 | dev->users--; |
1698 | mutex_unlock(&dev->lock); | 1977 | mutex_unlock(&dev->lock); |
1699 | return 0; | 1978 | return 0; |
1700 | } | 1979 | } |
1701 | 1980 | ||
1981 | /* | ||
1982 | * em28xx_videodevice_release() | ||
1983 | * called when the last user of the video device exits and frees the memeory | ||
1984 | */ | ||
1985 | static void em28xx_videodevice_release(struct video_device *vdev) | ||
1986 | { | ||
1987 | struct em28xx *dev = video_get_drvdata(vdev); | ||
1988 | |||
1989 | video_device_release(vdev); | ||
1990 | if (vdev == dev->vdev) | ||
1991 | dev->vdev = NULL; | ||
1992 | else if (vdev == dev->vbi_dev) | ||
1993 | dev->vbi_dev = NULL; | ||
1994 | else if (vdev == dev->radio_dev) | ||
1995 | dev->radio_dev = NULL; | ||
1996 | } | ||
1997 | |||
1702 | static const struct v4l2_file_operations em28xx_v4l_fops = { | 1998 | static const struct v4l2_file_operations em28xx_v4l_fops = { |
1703 | .owner = THIS_MODULE, | 1999 | .owner = THIS_MODULE, |
1704 | .open = em28xx_v4l2_open, | 2000 | .open = em28xx_v4l2_open, |
@@ -1753,11 +2049,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1753 | }; | 2049 | }; |
1754 | 2050 | ||
1755 | static const struct video_device em28xx_video_template = { | 2051 | static const struct video_device em28xx_video_template = { |
1756 | .fops = &em28xx_v4l_fops, | 2052 | .fops = &em28xx_v4l_fops, |
1757 | .release = video_device_release_empty, | 2053 | .ioctl_ops = &video_ioctl_ops, |
1758 | .ioctl_ops = &video_ioctl_ops, | 2054 | .release = em28xx_videodevice_release, |
1759 | 2055 | .tvnorms = V4L2_STD_ALL, | |
1760 | .tvnorms = V4L2_STD_ALL, | ||
1761 | }; | 2056 | }; |
1762 | 2057 | ||
1763 | static const struct v4l2_file_operations radio_fops = { | 2058 | static const struct v4l2_file_operations radio_fops = { |
@@ -1783,14 +2078,30 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { | |||
1783 | }; | 2078 | }; |
1784 | 2079 | ||
1785 | static struct video_device em28xx_radio_template = { | 2080 | static struct video_device em28xx_radio_template = { |
1786 | .name = "em28xx-radio", | 2081 | .fops = &radio_fops, |
1787 | .fops = &radio_fops, | 2082 | .ioctl_ops = &radio_ioctl_ops, |
1788 | .ioctl_ops = &radio_ioctl_ops, | 2083 | .release = em28xx_videodevice_release, |
1789 | }; | 2084 | }; |
1790 | 2085 | ||
1791 | /******************************** usb interface ******************************/ | 2086 | /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ |
2087 | static unsigned short saa711x_addrs[] = { | ||
2088 | 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ | ||
2089 | 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ | ||
2090 | I2C_CLIENT_END }; | ||
1792 | 2091 | ||
2092 | static unsigned short tvp5150_addrs[] = { | ||
2093 | 0xb8 >> 1, | ||
2094 | 0xba >> 1, | ||
2095 | I2C_CLIENT_END | ||
2096 | }; | ||
1793 | 2097 | ||
2098 | static unsigned short msp3400_addrs[] = { | ||
2099 | 0x80 >> 1, | ||
2100 | 0x88 >> 1, | ||
2101 | I2C_CLIENT_END | ||
2102 | }; | ||
2103 | |||
2104 | /******************************** usb interface ******************************/ | ||
1794 | 2105 | ||
1795 | static struct video_device *em28xx_vdev_init(struct em28xx *dev, | 2106 | static struct video_device *em28xx_vdev_init(struct em28xx *dev, |
1796 | const struct video_device *template, | 2107 | const struct video_device *template, |
@@ -1817,14 +2128,198 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, | |||
1817 | return vfd; | 2128 | return vfd; |
1818 | } | 2129 | } |
1819 | 2130 | ||
1820 | int em28xx_register_analog_devices(struct em28xx *dev) | 2131 | static void em28xx_tuner_setup(struct em28xx *dev) |
2132 | { | ||
2133 | struct tuner_setup tun_setup; | ||
2134 | struct v4l2_frequency f; | ||
2135 | |||
2136 | if (dev->tuner_type == TUNER_ABSENT) | ||
2137 | return; | ||
2138 | |||
2139 | memset(&tun_setup, 0, sizeof(tun_setup)); | ||
2140 | |||
2141 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
2142 | tun_setup.tuner_callback = em28xx_tuner_callback; | ||
2143 | |||
2144 | if (dev->board.radio.type) { | ||
2145 | tun_setup.type = dev->board.radio.type; | ||
2146 | tun_setup.addr = dev->board.radio_addr; | ||
2147 | |||
2148 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2149 | } | ||
2150 | |||
2151 | if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { | ||
2152 | tun_setup.type = dev->tuner_type; | ||
2153 | tun_setup.addr = dev->tuner_addr; | ||
2154 | |||
2155 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2156 | } | ||
2157 | |||
2158 | if (dev->tda9887_conf) { | ||
2159 | struct v4l2_priv_tun_config tda9887_cfg; | ||
2160 | |||
2161 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
2162 | tda9887_cfg.priv = &dev->tda9887_conf; | ||
2163 | |||
2164 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg); | ||
2165 | } | ||
2166 | |||
2167 | if (dev->tuner_type == TUNER_XC2028) { | ||
2168 | struct v4l2_priv_tun_config xc2028_cfg; | ||
2169 | struct xc2028_ctrl ctl; | ||
2170 | |||
2171 | memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); | ||
2172 | memset(&ctl, 0, sizeof(ctl)); | ||
2173 | |||
2174 | em28xx_setup_xc3028(dev, &ctl); | ||
2175 | |||
2176 | xc2028_cfg.tuner = TUNER_XC2028; | ||
2177 | xc2028_cfg.priv = &ctl; | ||
2178 | |||
2179 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg); | ||
2180 | } | ||
2181 | |||
2182 | /* configure tuner */ | ||
2183 | f.tuner = 0; | ||
2184 | f.type = V4L2_TUNER_ANALOG_TV; | ||
2185 | f.frequency = 9076; /* just a magic number */ | ||
2186 | dev->ctl_freq = f.frequency; | ||
2187 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); | ||
2188 | } | ||
2189 | |||
2190 | static int em28xx_v4l2_init(struct em28xx *dev) | ||
1821 | { | 2191 | { |
1822 | u8 val; | 2192 | u8 val; |
1823 | int ret; | 2193 | int ret; |
1824 | unsigned int maxw; | 2194 | unsigned int maxw; |
2195 | struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; | ||
2196 | |||
2197 | if (dev->is_audio_only) { | ||
2198 | /* Shouldn't initialize IR for this interface */ | ||
2199 | return 0; | ||
2200 | } | ||
2201 | |||
2202 | if (!dev->has_video) { | ||
2203 | /* This device does not support the v4l2 extension */ | ||
2204 | return 0; | ||
2205 | } | ||
2206 | |||
2207 | em28xx_info("Registering V4L2 extension\n"); | ||
2208 | |||
2209 | mutex_lock(&dev->lock); | ||
2210 | |||
2211 | ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); | ||
2212 | if (ret < 0) { | ||
2213 | em28xx_errdev("Call to v4l2_device_register() failed!\n"); | ||
2214 | goto err; | ||
2215 | } | ||
2216 | |||
2217 | v4l2_ctrl_handler_init(hdl, 8); | ||
2218 | dev->v4l2_dev.ctrl_handler = hdl; | ||
2219 | |||
2220 | /* | ||
2221 | * Default format, used for tvp5150 or saa711x output formats | ||
2222 | */ | ||
2223 | dev->vinmode = 0x10; | ||
2224 | dev->vinctl = EM28XX_VINCTRL_INTERLACED | | ||
2225 | EM28XX_VINCTRL_CCIR656_ENABLE; | ||
2226 | |||
2227 | /* request some modules */ | ||
2228 | |||
2229 | if (dev->board.has_msp34xx) | ||
2230 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2231 | "msp3400", 0, msp3400_addrs); | ||
2232 | |||
2233 | if (dev->board.decoder == EM28XX_SAA711X) | ||
2234 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2235 | "saa7115_auto", 0, saa711x_addrs); | ||
2236 | |||
2237 | if (dev->board.decoder == EM28XX_TVP5150) | ||
2238 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2239 | "tvp5150", 0, tvp5150_addrs); | ||
2240 | |||
2241 | if (dev->board.adecoder == EM28XX_TVAUDIO) | ||
2242 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2243 | "tvaudio", dev->board.tvaudio_addr, NULL); | ||
2244 | |||
2245 | /* Initialize tuner and camera */ | ||
2246 | |||
2247 | if (dev->board.tuner_type != TUNER_ABSENT) { | ||
2248 | int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); | ||
2249 | |||
2250 | if (dev->board.radio.type) | ||
2251 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2252 | "tuner", dev->board.radio_addr, NULL); | ||
2253 | |||
2254 | if (has_demod) | ||
2255 | v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
2256 | &dev->i2c_adap[dev->def_i2c_bus], "tuner", | ||
2257 | 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | ||
2258 | if (dev->tuner_addr == 0) { | ||
2259 | enum v4l2_i2c_tuner_type type = | ||
2260 | has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; | ||
2261 | struct v4l2_subdev *sd; | ||
2262 | |||
2263 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
2264 | &dev->i2c_adap[dev->def_i2c_bus], "tuner", | ||
2265 | 0, v4l2_i2c_tuner_addrs(type)); | ||
2266 | |||
2267 | if (sd) | ||
2268 | dev->tuner_addr = v4l2_i2c_subdev_addr(sd); | ||
2269 | } else { | ||
2270 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2271 | "tuner", dev->tuner_addr, NULL); | ||
2272 | } | ||
2273 | } | ||
2274 | |||
2275 | em28xx_tuner_setup(dev); | ||
2276 | em28xx_init_camera(dev); | ||
2277 | |||
2278 | /* Configure audio */ | ||
2279 | ret = em28xx_audio_setup(dev); | ||
2280 | if (ret < 0) { | ||
2281 | em28xx_errdev("%s: Error while setting audio - error [%d]!\n", | ||
2282 | __func__, ret); | ||
2283 | goto unregister_dev; | ||
2284 | } | ||
2285 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { | ||
2286 | v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, | ||
2287 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | ||
2288 | v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, | ||
2289 | V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f); | ||
2290 | } else { | ||
2291 | /* install the em28xx notify callback */ | ||
2292 | v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE), | ||
2293 | em28xx_ctrl_notify, dev); | ||
2294 | v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME), | ||
2295 | em28xx_ctrl_notify, dev); | ||
2296 | } | ||
2297 | |||
2298 | /* wake i2c devices */ | ||
2299 | em28xx_wake_i2c(dev); | ||
2300 | |||
2301 | /* init video dma queues */ | ||
2302 | INIT_LIST_HEAD(&dev->vidq.active); | ||
2303 | INIT_LIST_HEAD(&dev->vbiq.active); | ||
1825 | 2304 | ||
1826 | printk(KERN_INFO "%s: v4l2 driver version %s\n", | 2305 | if (dev->board.has_msp34xx) { |
1827 | dev->name, EM28XX_VERSION); | 2306 | /* Send a reset to other chips via gpio */ |
2307 | ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); | ||
2308 | if (ret < 0) { | ||
2309 | em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", | ||
2310 | __func__, ret); | ||
2311 | goto unregister_dev; | ||
2312 | } | ||
2313 | msleep(3); | ||
2314 | |||
2315 | ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); | ||
2316 | if (ret < 0) { | ||
2317 | em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", | ||
2318 | __func__, ret); | ||
2319 | goto unregister_dev; | ||
2320 | } | ||
2321 | msleep(3); | ||
2322 | } | ||
1828 | 2323 | ||
1829 | /* set default norm */ | 2324 | /* set default norm */ |
1830 | dev->norm = V4L2_STD_PAL; | 2325 | dev->norm = V4L2_STD_PAL; |
@@ -1888,14 +2383,16 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1888 | /* Reset image controls */ | 2383 | /* Reset image controls */ |
1889 | em28xx_colorlevels_set_default(dev); | 2384 | em28xx_colorlevels_set_default(dev); |
1890 | v4l2_ctrl_handler_setup(&dev->ctrl_handler); | 2385 | v4l2_ctrl_handler_setup(&dev->ctrl_handler); |
1891 | if (dev->ctrl_handler.error) | 2386 | ret = dev->ctrl_handler.error; |
1892 | return dev->ctrl_handler.error; | 2387 | if (ret) |
2388 | goto unregister_dev; | ||
1893 | 2389 | ||
1894 | /* allocate and fill video video_device struct */ | 2390 | /* allocate and fill video video_device struct */ |
1895 | dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); | 2391 | dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); |
1896 | if (!dev->vdev) { | 2392 | if (!dev->vdev) { |
1897 | em28xx_errdev("cannot allocate video_device.\n"); | 2393 | em28xx_errdev("cannot allocate video_device.\n"); |
1898 | return -ENODEV; | 2394 | ret = -ENODEV; |
2395 | goto unregister_dev; | ||
1899 | } | 2396 | } |
1900 | dev->vdev->queue = &dev->vb_vidq; | 2397 | dev->vdev->queue = &dev->vb_vidq; |
1901 | dev->vdev->queue->lock = &dev->vb_queue_lock; | 2398 | dev->vdev->queue->lock = &dev->vb_queue_lock; |
@@ -1925,7 +2422,7 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1925 | if (ret) { | 2422 | if (ret) { |
1926 | em28xx_errdev("unable to register video device (error=%i).\n", | 2423 | em28xx_errdev("unable to register video device (error=%i).\n", |
1927 | ret); | 2424 | ret); |
1928 | return ret; | 2425 | goto unregister_dev; |
1929 | } | 2426 | } |
1930 | 2427 | ||
1931 | /* Allocate and fill vbi video_device struct */ | 2428 | /* Allocate and fill vbi video_device struct */ |
@@ -1954,7 +2451,7 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1954 | vbi_nr[dev->devno]); | 2451 | vbi_nr[dev->devno]); |
1955 | if (ret < 0) { | 2452 | if (ret < 0) { |
1956 | em28xx_errdev("unable to register vbi device\n"); | 2453 | em28xx_errdev("unable to register vbi device\n"); |
1957 | return ret; | 2454 | goto unregister_dev; |
1958 | } | 2455 | } |
1959 | } | 2456 | } |
1960 | 2457 | ||
@@ -1963,13 +2460,14 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1963 | "radio"); | 2460 | "radio"); |
1964 | if (!dev->radio_dev) { | 2461 | if (!dev->radio_dev) { |
1965 | em28xx_errdev("cannot allocate video_device.\n"); | 2462 | em28xx_errdev("cannot allocate video_device.\n"); |
1966 | return -ENODEV; | 2463 | ret = -ENODEV; |
2464 | goto unregister_dev; | ||
1967 | } | 2465 | } |
1968 | ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, | 2466 | ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, |
1969 | radio_nr[dev->devno]); | 2467 | radio_nr[dev->devno]); |
1970 | if (ret < 0) { | 2468 | if (ret < 0) { |
1971 | em28xx_errdev("can't register radio device\n"); | 2469 | em28xx_errdev("can't register radio device\n"); |
1972 | return ret; | 2470 | goto unregister_dev; |
1973 | } | 2471 | } |
1974 | em28xx_info("Registered radio device as %s\n", | 2472 | em28xx_info("Registered radio device as %s\n", |
1975 | video_device_node_name(dev->radio_dev)); | 2473 | video_device_node_name(dev->radio_dev)); |
@@ -1982,5 +2480,41 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1982 | em28xx_info("V4L2 VBI device registered as %s\n", | 2480 | em28xx_info("V4L2 VBI device registered as %s\n", |
1983 | video_device_node_name(dev->vbi_dev)); | 2481 | video_device_node_name(dev->vbi_dev)); |
1984 | 2482 | ||
2483 | /* Save some power by putting tuner to sleep */ | ||
2484 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); | ||
2485 | |||
2486 | /* initialize videobuf2 stuff */ | ||
2487 | em28xx_vb2_setup(dev); | ||
2488 | |||
2489 | em28xx_info("V4L2 extension successfully initialized\n"); | ||
2490 | |||
2491 | mutex_unlock(&dev->lock); | ||
1985 | return 0; | 2492 | return 0; |
2493 | |||
2494 | unregister_dev: | ||
2495 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
2496 | v4l2_device_unregister(&dev->v4l2_dev); | ||
2497 | err: | ||
2498 | mutex_unlock(&dev->lock); | ||
2499 | return ret; | ||
2500 | } | ||
2501 | |||
2502 | static struct em28xx_ops v4l2_ops = { | ||
2503 | .id = EM28XX_V4L2, | ||
2504 | .name = "Em28xx v4l2 Extension", | ||
2505 | .init = em28xx_v4l2_init, | ||
2506 | .fini = em28xx_v4l2_fini, | ||
2507 | }; | ||
2508 | |||
2509 | static int __init em28xx_video_register(void) | ||
2510 | { | ||
2511 | return em28xx_register_extension(&v4l2_ops); | ||
2512 | } | ||
2513 | |||
2514 | static void __exit em28xx_video_unregister(void) | ||
2515 | { | ||
2516 | em28xx_unregister_extension(&v4l2_ops); | ||
1986 | } | 2517 | } |
2518 | |||
2519 | module_init(em28xx_video_register); | ||
2520 | module_exit(em28xx_video_unregister); | ||
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index f8726ad5d0a8..32d8a4bb7961 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h | |||
@@ -26,6 +26,9 @@ | |||
26 | #ifndef _EM28XX_H | 26 | #ifndef _EM28XX_H |
27 | #define _EM28XX_H | 27 | #define _EM28XX_H |
28 | 28 | ||
29 | #define EM28XX_VERSION "0.2.1" | ||
30 | #define DRIVER_DESC "Empia em28xx device driver" | ||
31 | |||
29 | #include <linux/workqueue.h> | 32 | #include <linux/workqueue.h> |
30 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
31 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
@@ -132,6 +135,8 @@ | |||
132 | #define EM2884_BOARD_C3TECH_DIGITAL_DUO 88 | 135 | #define EM2884_BOARD_C3TECH_DIGITAL_DUO 88 |
133 | #define EM2874_BOARD_DELOCK_61959 89 | 136 | #define EM2874_BOARD_DELOCK_61959 89 |
134 | #define EM2874_BOARD_KWORLD_UB435Q_V2 90 | 137 | #define EM2874_BOARD_KWORLD_UB435Q_V2 90 |
138 | #define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE 91 | ||
139 | #define EM28178_BOARD_PCTV_461E 92 | ||
135 | 140 | ||
136 | /* Limits minimum and default number of buffers */ | 141 | /* Limits minimum and default number of buffers */ |
137 | #define EM28XX_MIN_BUF 4 | 142 | #define EM28XX_MIN_BUF 4 |
@@ -178,8 +183,27 @@ | |||
178 | 183 | ||
179 | #define EM28XX_INTERLACED_DEFAULT 1 | 184 | #define EM28XX_INTERLACED_DEFAULT 1 |
180 | 185 | ||
181 | /* time in msecs to wait for i2c writes to finish */ | 186 | /* |
182 | #define EM2800_I2C_XFER_TIMEOUT 20 | 187 | * Time in msecs to wait for i2c xfers to finish. |
188 | * 35ms is the maximum time a SMBUS device could wait when | ||
189 | * clock stretching is used. As the transfer itself will take | ||
190 | * some time to happen, set it to 35 ms. | ||
191 | * | ||
192 | * Ok, I2C doesn't specify any limit. So, eventually, we may need | ||
193 | * to increase this timeout. | ||
194 | * | ||
195 | * FIXME: this assumes that an I2C message is not longer than 1ms. | ||
196 | * This is actually dependent on the I2C bus speed, although most | ||
197 | * devices use a 100kHz clock. So, this assumtion is true most of | ||
198 | * the time. | ||
199 | */ | ||
200 | #define EM28XX_I2C_XFER_TIMEOUT 36 | ||
201 | |||
202 | /* time in msecs to wait for AC97 xfers to finish */ | ||
203 | #define EM28XX_AC97_XFER_TIMEOUT 100 | ||
204 | |||
205 | /* max. number of button state polling addresses */ | ||
206 | #define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5 | ||
183 | 207 | ||
184 | enum em28xx_mode { | 208 | enum em28xx_mode { |
185 | EM28XX_SUSPEND, | 209 | EM28XX_SUSPEND, |
@@ -287,8 +311,7 @@ struct em28xx_audio_mode { | |||
287 | 311 | ||
288 | unsigned int has_audio:1; | 312 | unsigned int has_audio:1; |
289 | 313 | ||
290 | unsigned int i2s_3rates:1; | 314 | u8 i2s_samplerates; |
291 | unsigned int i2s_5rates:1; | ||
292 | }; | 315 | }; |
293 | 316 | ||
294 | /* em28xx has two audio inputs: tuner and line in. | 317 | /* em28xx has two audio inputs: tuner and line in. |
@@ -374,6 +397,33 @@ enum em28xx_adecoder { | |||
374 | EM28XX_TVAUDIO, | 397 | EM28XX_TVAUDIO, |
375 | }; | 398 | }; |
376 | 399 | ||
400 | enum em28xx_led_role { | ||
401 | EM28XX_LED_ANALOG_CAPTURING = 0, | ||
402 | EM28XX_LED_ILLUMINATION, | ||
403 | EM28XX_NUM_LED_ROLES, /* must be the last */ | ||
404 | }; | ||
405 | |||
406 | struct em28xx_led { | ||
407 | enum em28xx_led_role role; | ||
408 | u8 gpio_reg; | ||
409 | u8 gpio_mask; | ||
410 | bool inverted; | ||
411 | }; | ||
412 | |||
413 | enum em28xx_button_role { | ||
414 | EM28XX_BUTTON_SNAPSHOT = 0, | ||
415 | EM28XX_BUTTON_ILLUMINATION, | ||
416 | EM28XX_NUM_BUTTON_ROLES, /* must be the last */ | ||
417 | }; | ||
418 | |||
419 | struct em28xx_button { | ||
420 | enum em28xx_button_role role; | ||
421 | u8 reg_r; | ||
422 | u8 reg_clearing; | ||
423 | u8 mask; | ||
424 | bool inverted; | ||
425 | }; | ||
426 | |||
377 | struct em28xx_board { | 427 | struct em28xx_board { |
378 | char *name; | 428 | char *name; |
379 | int vchannels; | 429 | int vchannels; |
@@ -395,7 +445,6 @@ struct em28xx_board { | |||
395 | unsigned int mts_firmware:1; | 445 | unsigned int mts_firmware:1; |
396 | unsigned int max_range_640_480:1; | 446 | unsigned int max_range_640_480:1; |
397 | unsigned int has_dvb:1; | 447 | unsigned int has_dvb:1; |
398 | unsigned int has_snapshot_button:1; | ||
399 | unsigned int is_webcam:1; | 448 | unsigned int is_webcam:1; |
400 | unsigned int valid:1; | 449 | unsigned int valid:1; |
401 | unsigned int has_ir_i2c:1; | 450 | unsigned int has_ir_i2c:1; |
@@ -410,6 +459,12 @@ struct em28xx_board { | |||
410 | struct em28xx_input input[MAX_EM28XX_INPUT]; | 459 | struct em28xx_input input[MAX_EM28XX_INPUT]; |
411 | struct em28xx_input radio; | 460 | struct em28xx_input radio; |
412 | char *ir_codes; | 461 | char *ir_codes; |
462 | |||
463 | /* LEDs that need to be controlled explicitly */ | ||
464 | struct em28xx_led *leds; | ||
465 | |||
466 | /* Buttons */ | ||
467 | struct em28xx_button *buttons; | ||
413 | }; | 468 | }; |
414 | 469 | ||
415 | struct em28xx_eeprom { | 470 | struct em28xx_eeprom { |
@@ -426,15 +481,13 @@ struct em28xx_eeprom { | |||
426 | u8 string_idx_table; | 481 | u8 string_idx_table; |
427 | }; | 482 | }; |
428 | 483 | ||
429 | #define EM28XX_AUDIO_BUFS 5 | ||
430 | #define EM28XX_NUM_AUDIO_PACKETS 64 | ||
431 | #define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ | ||
432 | #define EM28XX_CAPTURE_STREAM_EN 1 | 484 | #define EM28XX_CAPTURE_STREAM_EN 1 |
433 | 485 | ||
434 | /* em28xx extensions */ | 486 | /* em28xx extensions */ |
435 | #define EM28XX_AUDIO 0x10 | 487 | #define EM28XX_AUDIO 0x10 |
436 | #define EM28XX_DVB 0x20 | 488 | #define EM28XX_DVB 0x20 |
437 | #define EM28XX_RC 0x30 | 489 | #define EM28XX_RC 0x30 |
490 | #define EM28XX_V4L2 0x40 | ||
438 | 491 | ||
439 | /* em28xx resource types (used for res_get/res_lock etc */ | 492 | /* em28xx resource types (used for res_get/res_lock etc */ |
440 | #define EM28XX_RESOURCE_VIDEO 0x01 | 493 | #define EM28XX_RESOURCE_VIDEO 0x01 |
@@ -442,8 +495,9 @@ struct em28xx_eeprom { | |||
442 | 495 | ||
443 | struct em28xx_audio { | 496 | struct em28xx_audio { |
444 | char name[50]; | 497 | char name[50]; |
445 | char *transfer_buffer[EM28XX_AUDIO_BUFS]; | 498 | unsigned num_urb; |
446 | struct urb *urb[EM28XX_AUDIO_BUFS]; | 499 | char **transfer_buffer; |
500 | struct urb **urb; | ||
447 | struct usb_device *udev; | 501 | struct usb_device *udev; |
448 | unsigned int capture_transfer_done; | 502 | unsigned int capture_transfer_done; |
449 | struct snd_pcm_substream *capture_pcm_substream; | 503 | struct snd_pcm_substream *capture_pcm_substream; |
@@ -451,6 +505,8 @@ struct em28xx_audio { | |||
451 | unsigned int hwptr_done_capture; | 505 | unsigned int hwptr_done_capture; |
452 | struct snd_card *sndcard; | 506 | struct snd_card *sndcard; |
453 | 507 | ||
508 | size_t period; | ||
509 | |||
454 | int users; | 510 | int users; |
455 | spinlock_t slock; | 511 | spinlock_t slock; |
456 | }; | 512 | }; |
@@ -485,11 +541,13 @@ struct em28xx { | |||
485 | int model; /* index in the device_data struct */ | 541 | int model; /* index in the device_data struct */ |
486 | int devno; /* marks the number of this device */ | 542 | int devno; /* marks the number of this device */ |
487 | enum em28xx_chip_id chip_id; | 543 | enum em28xx_chip_id chip_id; |
488 | unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ | ||
489 | 544 | ||
545 | unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ | ||
490 | unsigned char disconnected:1; /* device has been diconnected */ | 546 | unsigned char disconnected:1; /* device has been diconnected */ |
491 | 547 | unsigned int has_video:1; | |
492 | int audio_ifnum; | 548 | unsigned int has_audio_class:1; |
549 | unsigned int has_alsa_audio:1; | ||
550 | unsigned int is_audio_only:1; | ||
493 | 551 | ||
494 | struct v4l2_device v4l2_dev; | 552 | struct v4l2_device v4l2_dev; |
495 | struct v4l2_ctrl_handler ctrl_handler; | 553 | struct v4l2_ctrl_handler ctrl_handler; |
@@ -507,10 +565,6 @@ struct em28xx { | |||
507 | /* Vinmode/Vinctl used at the driver */ | 565 | /* Vinmode/Vinctl used at the driver */ |
508 | int vinmode, vinctl; | 566 | int vinmode, vinctl; |
509 | 567 | ||
510 | unsigned int has_audio_class:1; | ||
511 | unsigned int has_alsa_audio:1; | ||
512 | unsigned int is_audio_only:1; | ||
513 | |||
514 | /* Controls audio streaming */ | 568 | /* Controls audio streaming */ |
515 | struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ | 569 | struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ |
516 | atomic_t stream_started; /* stream should be running if true */ | 570 | atomic_t stream_started; /* stream should be running if true */ |
@@ -608,6 +662,7 @@ struct em28xx { | |||
608 | 662 | ||
609 | /* usb transfer */ | 663 | /* usb transfer */ |
610 | struct usb_device *udev; /* the usb device */ | 664 | struct usb_device *udev; /* the usb device */ |
665 | u8 ifnum; /* number of the assigned usb interface */ | ||
611 | u8 analog_ep_isoc; /* address of isoc endpoint for analog */ | 666 | u8 analog_ep_isoc; /* address of isoc endpoint for analog */ |
612 | u8 analog_ep_bulk; /* address of bulk endpoint for analog */ | 667 | u8 analog_ep_bulk; /* address of bulk endpoint for analog */ |
613 | u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ | 668 | u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ |
@@ -639,10 +694,15 @@ struct em28xx { | |||
639 | 694 | ||
640 | enum em28xx_mode mode; | 695 | enum em28xx_mode mode; |
641 | 696 | ||
642 | /* Snapshot button */ | 697 | /* Button state polling */ |
698 | struct delayed_work buttons_query_work; | ||
699 | u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; | ||
700 | u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; | ||
701 | u8 num_button_polling_addresses; | ||
702 | u16 button_polling_interval; /* [ms] */ | ||
703 | /* Snapshot button input device */ | ||
643 | char snapshot_button_path[30]; /* path of the input dev */ | 704 | char snapshot_button_path[30]; /* path of the input dev */ |
644 | struct input_dev *sbutton_input_dev; | 705 | struct input_dev *sbutton_input_dev; |
645 | struct delayed_work sbutton_query_work; | ||
646 | 706 | ||
647 | struct em28xx_dvb *dvb; | 707 | struct em28xx_dvb *dvb; |
648 | }; | 708 | }; |
@@ -672,6 +732,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); | |||
672 | int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); | 732 | int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); |
673 | int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, | 733 | int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, |
674 | u8 bitmask); | 734 | u8 bitmask); |
735 | int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask); | ||
675 | 736 | ||
676 | int em28xx_read_ac97(struct em28xx *dev, u8 reg); | 737 | int em28xx_read_ac97(struct em28xx *dev, u8 reg); |
677 | int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); | 738 | int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); |
@@ -679,12 +740,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); | |||
679 | int em28xx_audio_analog_set(struct em28xx *dev); | 740 | int em28xx_audio_analog_set(struct em28xx *dev); |
680 | int em28xx_audio_setup(struct em28xx *dev); | 741 | int em28xx_audio_setup(struct em28xx *dev); |
681 | 742 | ||
682 | int em28xx_colorlevels_set_default(struct em28xx *dev); | 743 | const struct em28xx_led *em28xx_find_led(struct em28xx *dev, |
744 | enum em28xx_led_role role); | ||
683 | int em28xx_capture_start(struct em28xx *dev, int start); | 745 | int em28xx_capture_start(struct em28xx *dev, int start); |
684 | int em28xx_vbi_supported(struct em28xx *dev); | ||
685 | int em28xx_set_outfmt(struct em28xx *dev); | ||
686 | int em28xx_resolution_set(struct em28xx *dev); | ||
687 | int em28xx_set_alternate(struct em28xx *dev); | ||
688 | int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, | 746 | int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, |
689 | int num_bufs, int max_pkt_size, int packet_multiplier); | 747 | int num_bufs, int max_pkt_size, int packet_multiplier); |
690 | int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, | 748 | int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, |
@@ -696,30 +754,18 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode); | |||
696 | void em28xx_stop_urbs(struct em28xx *dev); | 754 | void em28xx_stop_urbs(struct em28xx *dev); |
697 | int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); | 755 | int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); |
698 | int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); | 756 | int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); |
699 | void em28xx_wake_i2c(struct em28xx *dev); | ||
700 | int em28xx_register_extension(struct em28xx_ops *dev); | 757 | int em28xx_register_extension(struct em28xx_ops *dev); |
701 | void em28xx_unregister_extension(struct em28xx_ops *dev); | 758 | void em28xx_unregister_extension(struct em28xx_ops *dev); |
702 | void em28xx_init_extension(struct em28xx *dev); | 759 | void em28xx_init_extension(struct em28xx *dev); |
703 | void em28xx_close_extension(struct em28xx *dev); | 760 | void em28xx_close_extension(struct em28xx *dev); |
704 | 761 | ||
705 | /* Provided by em28xx-video.c */ | ||
706 | int em28xx_vb2_setup(struct em28xx *dev); | ||
707 | int em28xx_register_analog_devices(struct em28xx *dev); | ||
708 | void em28xx_release_analog_resources(struct em28xx *dev); | ||
709 | void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv); | ||
710 | int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); | ||
711 | int em28xx_stop_vbi_streaming(struct vb2_queue *vq); | ||
712 | extern const struct v4l2_ctrl_ops em28xx_ctrl_ops; | ||
713 | |||
714 | /* Provided by em28xx-cards.c */ | 762 | /* Provided by em28xx-cards.c */ |
715 | extern struct em28xx_board em28xx_boards[]; | 763 | extern struct em28xx_board em28xx_boards[]; |
716 | extern struct usb_device_id em28xx_id_table[]; | 764 | extern struct usb_device_id em28xx_id_table[]; |
717 | int em28xx_tuner_callback(void *ptr, int component, int command, int arg); | 765 | int em28xx_tuner_callback(void *ptr, int component, int command, int arg); |
766 | void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl); | ||
718 | void em28xx_release_resources(struct em28xx *dev); | 767 | void em28xx_release_resources(struct em28xx *dev); |
719 | 768 | ||
720 | /* Provided by em28xx-vbi.c */ | ||
721 | extern struct vb2_ops em28xx_vbi_qops; | ||
722 | |||
723 | /* Provided by em28xx-camera.c */ | 769 | /* Provided by em28xx-camera.c */ |
724 | int em28xx_detect_sensor(struct em28xx *dev); | 770 | int em28xx_detect_sensor(struct em28xx *dev); |
725 | int em28xx_init_camera(struct em28xx *dev); | 771 | int em28xx_init_camera(struct em28xx *dev); |
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 78c9bc8e7f56..abf365ab025d 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c | |||
@@ -1078,7 +1078,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1078 | /* register webcam snapshot button input device */ | 1078 | /* register webcam snapshot button input device */ |
1079 | pdev->button_dev = input_allocate_device(); | 1079 | pdev->button_dev = input_allocate_device(); |
1080 | if (!pdev->button_dev) { | 1080 | if (!pdev->button_dev) { |
1081 | PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); | ||
1082 | rc = -ENOMEM; | 1081 | rc = -ENOMEM; |
1083 | goto err_video_unreg; | 1082 | goto err_video_unreg; |
1084 | } | 1083 | } |
diff --git a/drivers/media/usb/sn9c102/Kconfig b/drivers/media/usb/sn9c102/Kconfig deleted file mode 100644 index 6ebaf2940d06..000000000000 --- a/drivers/media/usb/sn9c102/Kconfig +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | config USB_SN9C102 | ||
2 | tristate "USB SN9C1xx PC Camera Controller support (DEPRECATED)" | ||
3 | depends on VIDEO_V4L2 | ||
4 | ---help--- | ||
5 | This driver is DEPRECATED please use the gspca sonixb and | ||
6 | sonixj modules instead. | ||
7 | |||
8 | Say Y here if you want support for cameras based on SONiX SN9C101, | ||
9 | SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. | ||
10 | |||
11 | See <file:Documentation/video4linux/sn9c102.txt> for more info. | ||
12 | |||
13 | To compile this driver as a module, choose M here: the | ||
14 | module will be called sn9c102. | ||
diff --git a/drivers/media/usb/sn9c102/Makefile b/drivers/media/usb/sn9c102/Makefile deleted file mode 100644 index 7ecd5a90c7c9..000000000000 --- a/drivers/media/usb/sn9c102/Makefile +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | sn9c102-objs := sn9c102_core.o \ | ||
2 | sn9c102_hv7131d.o \ | ||
3 | sn9c102_hv7131r.o \ | ||
4 | sn9c102_mi0343.o \ | ||
5 | sn9c102_mi0360.o \ | ||
6 | sn9c102_mt9v111.o \ | ||
7 | sn9c102_ov7630.o \ | ||
8 | sn9c102_ov7660.o \ | ||
9 | sn9c102_pas106b.o \ | ||
10 | sn9c102_pas202bcb.o \ | ||
11 | sn9c102_tas5110c1b.o \ | ||
12 | sn9c102_tas5110d.o \ | ||
13 | sn9c102_tas5130d1b.o | ||
14 | |||
15 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102.h b/drivers/media/usb/sn9c102/sn9c102.h deleted file mode 100644 index 8a917f060503..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102.h +++ /dev/null | |||
@@ -1,214 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for SN9C1xx PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_H_ | ||
22 | #define _SN9C102_H_ | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <media/v4l2-common.h> | ||
27 | #include <media/v4l2-ioctl.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/list.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/types.h> | ||
35 | #include <linux/param.h> | ||
36 | #include <linux/rwsem.h> | ||
37 | #include <linux/mutex.h> | ||
38 | #include <linux/string.h> | ||
39 | #include <linux/stddef.h> | ||
40 | #include <linux/kref.h> | ||
41 | |||
42 | #include "sn9c102_config.h" | ||
43 | #include "sn9c102_sensor.h" | ||
44 | #include "sn9c102_devtable.h" | ||
45 | |||
46 | |||
47 | enum sn9c102_frame_state { | ||
48 | F_UNUSED, | ||
49 | F_QUEUED, | ||
50 | F_GRABBING, | ||
51 | F_DONE, | ||
52 | F_ERROR, | ||
53 | }; | ||
54 | |||
55 | struct sn9c102_frame_t { | ||
56 | void* bufmem; | ||
57 | struct v4l2_buffer buf; | ||
58 | enum sn9c102_frame_state state; | ||
59 | struct list_head frame; | ||
60 | unsigned long vma_use_count; | ||
61 | }; | ||
62 | |||
63 | enum sn9c102_dev_state { | ||
64 | DEV_INITIALIZED = 0x01, | ||
65 | DEV_DISCONNECTED = 0x02, | ||
66 | DEV_MISCONFIGURED = 0x04, | ||
67 | }; | ||
68 | |||
69 | enum sn9c102_io_method { | ||
70 | IO_NONE, | ||
71 | IO_READ, | ||
72 | IO_MMAP, | ||
73 | }; | ||
74 | |||
75 | enum sn9c102_stream_state { | ||
76 | STREAM_OFF, | ||
77 | STREAM_INTERRUPT, | ||
78 | STREAM_ON, | ||
79 | }; | ||
80 | |||
81 | typedef char sn9c102_sof_header_t[62]; | ||
82 | |||
83 | struct sn9c102_sof_t { | ||
84 | sn9c102_sof_header_t header; | ||
85 | u16 bytesread; | ||
86 | }; | ||
87 | |||
88 | struct sn9c102_sysfs_attr { | ||
89 | u16 reg, i2c_reg; | ||
90 | sn9c102_sof_header_t frame_header; | ||
91 | }; | ||
92 | |||
93 | struct sn9c102_module_param { | ||
94 | u8 force_munmap; | ||
95 | u16 frame_timeout; | ||
96 | }; | ||
97 | |||
98 | static DEFINE_MUTEX(sn9c102_sysfs_lock); | ||
99 | static DECLARE_RWSEM(sn9c102_dev_lock); | ||
100 | |||
101 | struct sn9c102_device { | ||
102 | struct video_device* v4ldev; | ||
103 | |||
104 | struct v4l2_device v4l2_dev; | ||
105 | |||
106 | enum sn9c102_bridge bridge; | ||
107 | struct sn9c102_sensor sensor; | ||
108 | |||
109 | struct usb_device* usbdev; | ||
110 | struct urb* urb[SN9C102_URBS]; | ||
111 | void* transfer_buffer[SN9C102_URBS]; | ||
112 | u8* control_buffer; | ||
113 | |||
114 | struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; | ||
115 | struct list_head inqueue, outqueue; | ||
116 | u32 frame_count, nbuffers, nreadbuffers; | ||
117 | |||
118 | enum sn9c102_io_method io; | ||
119 | enum sn9c102_stream_state stream; | ||
120 | |||
121 | struct v4l2_jpegcompression compression; | ||
122 | |||
123 | struct sn9c102_sysfs_attr sysfs; | ||
124 | struct sn9c102_sof_t sof; | ||
125 | u16 reg[384]; | ||
126 | |||
127 | struct sn9c102_module_param module_param; | ||
128 | |||
129 | struct kref kref; | ||
130 | enum sn9c102_dev_state state; | ||
131 | u8 users; | ||
132 | |||
133 | struct completion probe; | ||
134 | struct mutex open_mutex, fileop_mutex; | ||
135 | spinlock_t queue_lock; | ||
136 | wait_queue_head_t wait_open, wait_frame, wait_stream; | ||
137 | }; | ||
138 | |||
139 | /*****************************************************************************/ | ||
140 | |||
141 | struct sn9c102_device* | ||
142 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) | ||
143 | { | ||
144 | return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; | ||
145 | } | ||
146 | |||
147 | |||
148 | void | ||
149 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
150 | const struct sn9c102_sensor* sensor) | ||
151 | { | ||
152 | memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); | ||
153 | } | ||
154 | |||
155 | |||
156 | enum sn9c102_bridge | ||
157 | sn9c102_get_bridge(struct sn9c102_device* cam) | ||
158 | { | ||
159 | return cam->bridge; | ||
160 | } | ||
161 | |||
162 | |||
163 | struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam) | ||
164 | { | ||
165 | return &cam->sensor; | ||
166 | } | ||
167 | |||
168 | /*****************************************************************************/ | ||
169 | |||
170 | #undef DBG | ||
171 | #undef KDBG | ||
172 | #ifdef SN9C102_DEBUG | ||
173 | # define DBG(level, fmt, args...) \ | ||
174 | do { \ | ||
175 | if (debug >= (level)) { \ | ||
176 | if ((level) == 1) \ | ||
177 | dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
178 | else if ((level) == 2) \ | ||
179 | dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
180 | else if ((level) >= 3) \ | ||
181 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
182 | __func__, __LINE__ , ## args); \ | ||
183 | } \ | ||
184 | } while (0) | ||
185 | # define V4LDBG(level, name, cmd) \ | ||
186 | do { \ | ||
187 | if (debug >= (level)) \ | ||
188 | v4l_printk_ioctl(name, cmd); \ | ||
189 | } while (0) | ||
190 | # define KDBG(level, fmt, args...) \ | ||
191 | do { \ | ||
192 | if (debug >= (level)) { \ | ||
193 | if ((level) == 1 || (level) == 2) \ | ||
194 | pr_info("sn9c102: " fmt "\n", ## args); \ | ||
195 | else if ((level) == 3) \ | ||
196 | pr_debug("sn9c102: [%s:%d] " fmt "\n", \ | ||
197 | __func__, __LINE__ , ## args); \ | ||
198 | } \ | ||
199 | } while (0) | ||
200 | #else | ||
201 | # define DBG(level, fmt, args...) do {;} while(0) | ||
202 | # define V4LDBG(level, name, cmd) do {;} while(0) | ||
203 | # define KDBG(level, fmt, args...) do {;} while(0) | ||
204 | #endif | ||
205 | |||
206 | #undef PDBG | ||
207 | #define PDBG(fmt, args...) \ | ||
208 | dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \ | ||
209 | __LINE__ , ## args) | ||
210 | |||
211 | #undef PDBGG | ||
212 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | ||
213 | |||
214 | #endif /* _SN9C102_H_ */ | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_config.h b/drivers/media/usb/sn9c102/sn9c102_config.h deleted file mode 100644 index 0f4e0378b071..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_config.h +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_CONFIG_H_ | ||
22 | #define _SN9C102_CONFIG_H_ | ||
23 | |||
24 | #include <linux/types.h> | ||
25 | #include <linux/jiffies.h> | ||
26 | |||
27 | #define SN9C102_DEBUG | ||
28 | #define SN9C102_DEBUG_LEVEL 2 | ||
29 | #define SN9C102_MAX_DEVICES 64 | ||
30 | #define SN9C102_PRESERVE_IMGSCALE 0 | ||
31 | #define SN9C102_FORCE_MUNMAP 0 | ||
32 | #define SN9C102_MAX_FRAMES 32 | ||
33 | #define SN9C102_URBS 2 | ||
34 | #define SN9C102_ISO_PACKETS 7 | ||
35 | #define SN9C102_ALTERNATE_SETTING 8 | ||
36 | #define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) | ||
37 | #define SN9C102_CTRL_TIMEOUT 300 | ||
38 | #define SN9C102_FRAME_TIMEOUT 0 | ||
39 | |||
40 | /*****************************************************************************/ | ||
41 | |||
42 | static const u8 SN9C102_Y_QTABLE0[64] = { | ||
43 | 8, 5, 5, 8, 12, 20, 25, 30, | ||
44 | 6, 6, 7, 9, 13, 29, 30, 27, | ||
45 | 7, 6, 8, 12, 20, 28, 34, 28, | ||
46 | 7, 8, 11, 14, 25, 43, 40, 31, | ||
47 | 9, 11, 18, 28, 34, 54, 51, 38, | ||
48 | 12, 17, 27, 32, 40, 52, 56, 46, | ||
49 | 24, 32, 39, 43, 51, 60, 60, 50, | ||
50 | 36, 46, 47, 49, 56, 50, 51, 49 | ||
51 | }; | ||
52 | |||
53 | static const u8 SN9C102_UV_QTABLE0[64] = { | ||
54 | 8, 9, 12, 23, 49, 49, 49, 49, | ||
55 | 9, 10, 13, 33, 49, 49, 49, 49, | ||
56 | 12, 13, 28, 49, 49, 49, 49, 49, | ||
57 | 23, 33, 49, 49, 49, 49, 49, 49, | ||
58 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
59 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
60 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
61 | 49, 49, 49, 49, 49, 49, 49, 49 | ||
62 | }; | ||
63 | |||
64 | static const u8 SN9C102_Y_QTABLE1[64] = { | ||
65 | 16, 11, 10, 16, 24, 40, 51, 61, | ||
66 | 12, 12, 14, 19, 26, 58, 60, 55, | ||
67 | 14, 13, 16, 24, 40, 57, 69, 56, | ||
68 | 14, 17, 22, 29, 51, 87, 80, 62, | ||
69 | 18, 22, 37, 56, 68, 109, 103, 77, | ||
70 | 24, 35, 55, 64, 81, 104, 113, 92, | ||
71 | 49, 64, 78, 87, 103, 121, 120, 101, | ||
72 | 72, 92, 95, 98, 112, 100, 103, 99 | ||
73 | }; | ||
74 | |||
75 | static const u8 SN9C102_UV_QTABLE1[64] = { | ||
76 | 17, 18, 24, 47, 99, 99, 99, 99, | ||
77 | 18, 21, 26, 66, 99, 99, 99, 99, | ||
78 | 24, 26, 56, 99, 99, 99, 99, 99, | ||
79 | 47, 66, 99, 99, 99, 99, 99, 99, | ||
80 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
81 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
82 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
83 | 99, 99, 99, 99, 99, 99, 99, 99 | ||
84 | }; | ||
85 | |||
86 | #endif /* _SN9C102_CONFIG_H_ */ | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c deleted file mode 100644 index 2cb44de2b92c..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_core.c +++ /dev/null | |||
@@ -1,3434 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for SN9C1xx PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/param.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/compiler.h> | ||
31 | #include <linux/ioctl.h> | ||
32 | #include <linux/poll.h> | ||
33 | #include <linux/stat.h> | ||
34 | #include <linux/mm.h> | ||
35 | #include <linux/vmalloc.h> | ||
36 | #include <linux/version.h> | ||
37 | #include <linux/page-flags.h> | ||
38 | #include <asm/byteorder.h> | ||
39 | #include <asm/page.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | #include "sn9c102.h" | ||
43 | |||
44 | /*****************************************************************************/ | ||
45 | |||
46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" | ||
47 | #define SN9C102_MODULE_ALIAS "sn9c1xx" | ||
48 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" | ||
49 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
50 | #define SN9C102_MODULE_LICENSE "GPL" | ||
51 | #define SN9C102_MODULE_VERSION "1:1.48" | ||
52 | |||
53 | /*****************************************************************************/ | ||
54 | |||
55 | MODULE_DEVICE_TABLE(usb, sn9c102_id_table); | ||
56 | |||
57 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); | ||
58 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); | ||
59 | MODULE_ALIAS(SN9C102_MODULE_ALIAS); | ||
60 | MODULE_VERSION(SN9C102_MODULE_VERSION); | ||
61 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); | ||
62 | |||
63 | static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; | ||
64 | module_param_array(video_nr, short, NULL, 0444); | ||
65 | MODULE_PARM_DESC(video_nr, | ||
66 | " <-1|n[,...]>" | ||
67 | "\nSpecify V4L2 minor mode number." | ||
68 | "\n-1 = use next available (default)" | ||
69 | "\n n = use minor number n (integer >= 0)" | ||
70 | "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) | ||
71 | " cameras this way." | ||
72 | "\nFor example:" | ||
73 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
74 | "\nthe second camera and use auto for the first" | ||
75 | "\none and for every other camera." | ||
76 | "\n"); | ||
77 | |||
78 | static bool force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = | ||
79 | SN9C102_FORCE_MUNMAP}; | ||
80 | module_param_array(force_munmap, bool, NULL, 0444); | ||
81 | MODULE_PARM_DESC(force_munmap, | ||
82 | " <0|1[,...]>" | ||
83 | "\nForce the application to unmap previously" | ||
84 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or" | ||
85 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support" | ||
86 | "\nthis feature. This parameter is specific for each" | ||
87 | "\ndetected camera." | ||
88 | "\n0 = do not force memory unmapping" | ||
89 | "\n1 = force memory unmapping (save memory)" | ||
90 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
91 | "\n"); | ||
92 | |||
93 | static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = | ||
94 | SN9C102_FRAME_TIMEOUT}; | ||
95 | module_param_array(frame_timeout, uint, NULL, 0644); | ||
96 | MODULE_PARM_DESC(frame_timeout, | ||
97 | " <0|n[,...]>" | ||
98 | "\nTimeout for a video frame in seconds before" | ||
99 | "\nreturning an I/O error; 0 for infinity." | ||
100 | "\nThis parameter is specific for each detected camera." | ||
101 | "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." | ||
102 | "\n"); | ||
103 | |||
104 | #ifdef SN9C102_DEBUG | ||
105 | static unsigned short debug = SN9C102_DEBUG_LEVEL; | ||
106 | module_param(debug, ushort, 0644); | ||
107 | MODULE_PARM_DESC(debug, | ||
108 | " <n>" | ||
109 | "\nDebugging information level, from 0 to 3:" | ||
110 | "\n0 = none (use carefully)" | ||
111 | "\n1 = critical errors" | ||
112 | "\n2 = significant informations" | ||
113 | "\n3 = more verbose messages" | ||
114 | "\nLevel 3 is useful for testing only." | ||
115 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." | ||
116 | "\n"); | ||
117 | #endif | ||
118 | |||
119 | /* | ||
120 | Add the probe entries to this table. Be sure to add the entry in the right | ||
121 | place, since, on failure, the next probing routine is called according to | ||
122 | the order of the list below, from top to bottom. | ||
123 | */ | ||
124 | static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = { | ||
125 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ | ||
126 | &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ | ||
127 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ | ||
128 | &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ | ||
129 | &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ | ||
130 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ | ||
131 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ | ||
132 | &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ | ||
133 | &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ | ||
134 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ | ||
135 | &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ | ||
136 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ | ||
137 | }; | ||
138 | |||
139 | /*****************************************************************************/ | ||
140 | |||
141 | static u32 | ||
142 | sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | ||
143 | enum sn9c102_io_method io) | ||
144 | { | ||
145 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | ||
146 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | ||
147 | size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? | ||
148 | (p->width * p->height * p->priv) / 8 : | ||
149 | (r->width * r->height * p->priv) / 8; | ||
150 | void* buff = NULL; | ||
151 | u32 i; | ||
152 | |||
153 | if (count > SN9C102_MAX_FRAMES) | ||
154 | count = SN9C102_MAX_FRAMES; | ||
155 | |||
156 | if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120) | ||
157 | imagesize += 589 + 2; /* length of JPEG header + EOI marker */ | ||
158 | |||
159 | cam->nbuffers = count; | ||
160 | while (cam->nbuffers > 0) { | ||
161 | if ((buff = vmalloc_32_user(cam->nbuffers * | ||
162 | PAGE_ALIGN(imagesize)))) | ||
163 | break; | ||
164 | cam->nbuffers--; | ||
165 | } | ||
166 | |||
167 | for (i = 0; i < cam->nbuffers; i++) { | ||
168 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
169 | cam->frame[i].buf.index = i; | ||
170 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
171 | cam->frame[i].buf.length = imagesize; | ||
172 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
173 | cam->frame[i].buf.sequence = 0; | ||
174 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
175 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
176 | cam->frame[i].buf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
177 | } | ||
178 | |||
179 | return cam->nbuffers; | ||
180 | } | ||
181 | |||
182 | |||
183 | static void sn9c102_release_buffers(struct sn9c102_device* cam) | ||
184 | { | ||
185 | if (cam->nbuffers) { | ||
186 | vfree(cam->frame[0].bufmem); | ||
187 | cam->nbuffers = 0; | ||
188 | } | ||
189 | cam->frame_current = NULL; | ||
190 | } | ||
191 | |||
192 | |||
193 | static void sn9c102_empty_framequeues(struct sn9c102_device* cam) | ||
194 | { | ||
195 | u32 i; | ||
196 | |||
197 | INIT_LIST_HEAD(&cam->inqueue); | ||
198 | INIT_LIST_HEAD(&cam->outqueue); | ||
199 | |||
200 | for (i = 0; i < SN9C102_MAX_FRAMES; i++) { | ||
201 | cam->frame[i].state = F_UNUSED; | ||
202 | cam->frame[i].buf.bytesused = 0; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | |||
207 | static void sn9c102_requeue_outqueue(struct sn9c102_device* cam) | ||
208 | { | ||
209 | struct sn9c102_frame_t *i; | ||
210 | |||
211 | list_for_each_entry(i, &cam->outqueue, frame) { | ||
212 | i->state = F_QUEUED; | ||
213 | list_add(&i->frame, &cam->inqueue); | ||
214 | } | ||
215 | |||
216 | INIT_LIST_HEAD(&cam->outqueue); | ||
217 | } | ||
218 | |||
219 | |||
220 | static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) | ||
221 | { | ||
222 | unsigned long lock_flags; | ||
223 | u32 i; | ||
224 | |||
225 | for (i = 0; i < cam->nbuffers; i++) | ||
226 | if (cam->frame[i].state == F_UNUSED) { | ||
227 | cam->frame[i].state = F_QUEUED; | ||
228 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
229 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
230 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /*****************************************************************************/ | ||
235 | |||
236 | /* | ||
237 | Write a sequence of count value/register pairs. Returns -1 after the first | ||
238 | failed write, or 0 for no errors. | ||
239 | */ | ||
240 | int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2], | ||
241 | int count) | ||
242 | { | ||
243 | struct usb_device* udev = cam->usbdev; | ||
244 | u8* buff = cam->control_buffer; | ||
245 | int i, res; | ||
246 | |||
247 | for (i = 0; i < count; i++) { | ||
248 | u8 index = valreg[i][1]; | ||
249 | |||
250 | /* | ||
251 | index is a u8, so it must be <256 and can't be out of range. | ||
252 | If we put in a check anyway, gcc annoys us with a warning | ||
253 | hat our check is useless. People get all uppity when they | ||
254 | see warnings in the kernel compile. | ||
255 | */ | ||
256 | |||
257 | *buff = valreg[i][0]; | ||
258 | |||
259 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, | ||
260 | 0x41, index, 0, buff, 1, | ||
261 | SN9C102_CTRL_TIMEOUT); | ||
262 | |||
263 | if (res < 0) { | ||
264 | DBG(3, "Failed to write a register (value 0x%02X, " | ||
265 | "index 0x%02X, error %d)", *buff, index, res); | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | cam->reg[index] = *buff; | ||
270 | } | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | |||
276 | int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) | ||
277 | { | ||
278 | struct usb_device* udev = cam->usbdev; | ||
279 | u8* buff = cam->control_buffer; | ||
280 | int res; | ||
281 | |||
282 | if (index >= ARRAY_SIZE(cam->reg)) | ||
283 | return -1; | ||
284 | |||
285 | *buff = value; | ||
286 | |||
287 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
288 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
289 | if (res < 0) { | ||
290 | DBG(3, "Failed to write a register (value 0x%02X, index " | ||
291 | "0x%02X, error %d)", value, index, res); | ||
292 | return -1; | ||
293 | } | ||
294 | |||
295 | cam->reg[index] = value; | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | |||
301 | /* NOTE: with the SN9C10[123] reading some registers always returns 0 */ | ||
302 | int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) | ||
303 | { | ||
304 | struct usb_device* udev = cam->usbdev; | ||
305 | u8* buff = cam->control_buffer; | ||
306 | int res; | ||
307 | |||
308 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
309 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
310 | if (res < 0) | ||
311 | DBG(3, "Failed to read a register (index 0x%02X, error %d)", | ||
312 | index, res); | ||
313 | |||
314 | return (res >= 0) ? (int)(*buff) : -1; | ||
315 | } | ||
316 | |||
317 | |||
318 | int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) | ||
319 | { | ||
320 | if (index >= ARRAY_SIZE(cam->reg)) | ||
321 | return -1; | ||
322 | |||
323 | return cam->reg[index]; | ||
324 | } | ||
325 | |||
326 | |||
327 | static int | ||
328 | sn9c102_i2c_wait(struct sn9c102_device* cam, | ||
329 | const struct sn9c102_sensor* sensor) | ||
330 | { | ||
331 | int i, r; | ||
332 | |||
333 | for (i = 1; i <= 5; i++) { | ||
334 | r = sn9c102_read_reg(cam, 0x08); | ||
335 | if (r < 0) | ||
336 | return -EIO; | ||
337 | if (r & 0x04) | ||
338 | return 0; | ||
339 | if (sensor->frequency & SN9C102_I2C_400KHZ) | ||
340 | udelay(5*16); | ||
341 | else | ||
342 | udelay(16*16); | ||
343 | } | ||
344 | return -EBUSY; | ||
345 | } | ||
346 | |||
347 | |||
348 | static int | ||
349 | sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, | ||
350 | const struct sn9c102_sensor* sensor) | ||
351 | { | ||
352 | int r , err = 0; | ||
353 | |||
354 | r = sn9c102_read_reg(cam, 0x08); | ||
355 | if (r < 0) | ||
356 | err += r; | ||
357 | |||
358 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { | ||
359 | if (!(r & 0x08)) | ||
360 | err += -1; | ||
361 | } else { | ||
362 | if (r & 0x08) | ||
363 | err += -1; | ||
364 | } | ||
365 | |||
366 | return err ? -EIO : 0; | ||
367 | } | ||
368 | |||
369 | |||
370 | static int | ||
371 | sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, | ||
372 | const struct sn9c102_sensor* sensor) | ||
373 | { | ||
374 | int r; | ||
375 | r = sn9c102_read_reg(cam, 0x08); | ||
376 | return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; | ||
377 | } | ||
378 | |||
379 | |||
380 | int | ||
381 | sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
382 | const struct sn9c102_sensor* sensor, u8 data0, | ||
383 | u8 data1, u8 n, u8 buffer[]) | ||
384 | { | ||
385 | struct usb_device* udev = cam->usbdev; | ||
386 | u8* data = cam->control_buffer; | ||
387 | int i = 0, err = 0, res; | ||
388 | |||
389 | /* Write cycle */ | ||
390 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
391 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; | ||
392 | data[1] = data0; /* I2C slave id */ | ||
393 | data[2] = data1; /* address */ | ||
394 | data[7] = 0x10; | ||
395 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
396 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
397 | if (res < 0) | ||
398 | err += res; | ||
399 | |||
400 | err += sn9c102_i2c_wait(cam, sensor); | ||
401 | |||
402 | /* Read cycle - n bytes */ | ||
403 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
404 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | | ||
405 | (n << 4) | 0x02; | ||
406 | data[1] = data0; | ||
407 | data[7] = 0x10; | ||
408 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
409 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
410 | if (res < 0) | ||
411 | err += res; | ||
412 | |||
413 | err += sn9c102_i2c_wait(cam, sensor); | ||
414 | |||
415 | /* The first read byte will be placed in data[4] */ | ||
416 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
417 | 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); | ||
418 | if (res < 0) | ||
419 | err += res; | ||
420 | |||
421 | err += sn9c102_i2c_detect_read_error(cam, sensor); | ||
422 | |||
423 | PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1, | ||
424 | data[4]); | ||
425 | |||
426 | if (err) { | ||
427 | DBG(3, "I2C read failed for %s image sensor", sensor->name); | ||
428 | return -1; | ||
429 | } | ||
430 | |||
431 | if (buffer) | ||
432 | for (i = 0; i < n && i < 5; i++) | ||
433 | buffer[n-i-1] = data[4-i]; | ||
434 | |||
435 | return (int)data[4]; | ||
436 | } | ||
437 | |||
438 | |||
439 | int | ||
440 | sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
441 | const struct sn9c102_sensor* sensor, u8 n, u8 data0, | ||
442 | u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) | ||
443 | { | ||
444 | struct usb_device* udev = cam->usbdev; | ||
445 | u8* data = cam->control_buffer; | ||
446 | int err = 0, res; | ||
447 | |||
448 | /* Write cycle. It usually is address + value */ | ||
449 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
450 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | ||
451 | | ((n - 1) << 4); | ||
452 | data[1] = data0; | ||
453 | data[2] = data1; | ||
454 | data[3] = data2; | ||
455 | data[4] = data3; | ||
456 | data[5] = data4; | ||
457 | data[6] = data5; | ||
458 | data[7] = 0x17; | ||
459 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
460 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
461 | if (res < 0) | ||
462 | err += res; | ||
463 | |||
464 | err += sn9c102_i2c_wait(cam, sensor); | ||
465 | err += sn9c102_i2c_detect_write_error(cam, sensor); | ||
466 | |||
467 | if (err) | ||
468 | DBG(3, "I2C write failed for %s image sensor", sensor->name); | ||
469 | |||
470 | PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " | ||
471 | "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", | ||
472 | n, data0, data1, data2, data3, data4, data5); | ||
473 | |||
474 | return err ? -1 : 0; | ||
475 | } | ||
476 | |||
477 | |||
478 | int | ||
479 | sn9c102_i2c_try_read(struct sn9c102_device* cam, | ||
480 | const struct sn9c102_sensor* sensor, u8 address) | ||
481 | { | ||
482 | return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id, | ||
483 | address, 1, NULL); | ||
484 | } | ||
485 | |||
486 | |||
487 | static int sn9c102_i2c_try_write(struct sn9c102_device* cam, | ||
488 | const struct sn9c102_sensor* sensor, | ||
489 | u8 address, u8 value) | ||
490 | { | ||
491 | return sn9c102_i2c_try_raw_write(cam, sensor, 3, | ||
492 | sensor->i2c_slave_id, address, | ||
493 | value, 0, 0, 0); | ||
494 | } | ||
495 | |||
496 | |||
497 | int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) | ||
498 | { | ||
499 | return sn9c102_i2c_try_read(cam, &cam->sensor, address); | ||
500 | } | ||
501 | |||
502 | |||
503 | int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) | ||
504 | { | ||
505 | return sn9c102_i2c_try_write(cam, &cam->sensor, address, value); | ||
506 | } | ||
507 | |||
508 | /*****************************************************************************/ | ||
509 | |||
510 | static size_t sn9c102_sof_length(struct sn9c102_device* cam) | ||
511 | { | ||
512 | switch (cam->bridge) { | ||
513 | case BRIDGE_SN9C101: | ||
514 | case BRIDGE_SN9C102: | ||
515 | return 12; | ||
516 | case BRIDGE_SN9C103: | ||
517 | return 18; | ||
518 | case BRIDGE_SN9C105: | ||
519 | case BRIDGE_SN9C120: | ||
520 | return 62; | ||
521 | } | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | |||
527 | static void* | ||
528 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
529 | { | ||
530 | static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; | ||
531 | const char *m = mem; | ||
532 | size_t soflen = 0, i, j; | ||
533 | |||
534 | soflen = sn9c102_sof_length(cam); | ||
535 | |||
536 | for (i = 0; i < len; i++) { | ||
537 | size_t b; | ||
538 | |||
539 | /* Read the variable part of the header */ | ||
540 | if (unlikely(cam->sof.bytesread >= sizeof(marker))) { | ||
541 | cam->sof.header[cam->sof.bytesread] = *(m+i); | ||
542 | if (++cam->sof.bytesread == soflen) { | ||
543 | cam->sof.bytesread = 0; | ||
544 | return mem + i; | ||
545 | } | ||
546 | continue; | ||
547 | } | ||
548 | |||
549 | /* Search for the SOF marker (fixed part) in the header */ | ||
550 | for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) { | ||
551 | if (unlikely(i+j == len)) | ||
552 | return NULL; | ||
553 | if (*(m+i+j) == marker[cam->sof.bytesread]) { | ||
554 | cam->sof.header[cam->sof.bytesread] = *(m+i+j); | ||
555 | if (++cam->sof.bytesread == sizeof(marker)) { | ||
556 | PDBGG("Bytes to analyze: %zd. SOF " | ||
557 | "starts at byte #%zd", len, i); | ||
558 | i += j+1; | ||
559 | break; | ||
560 | } | ||
561 | } else { | ||
562 | cam->sof.bytesread = 0; | ||
563 | break; | ||
564 | } | ||
565 | } | ||
566 | } | ||
567 | |||
568 | return NULL; | ||
569 | } | ||
570 | |||
571 | |||
572 | static void* | ||
573 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
574 | { | ||
575 | static const u8 eof_header[4][4] = { | ||
576 | {0x00, 0x00, 0x00, 0x00}, | ||
577 | {0x40, 0x00, 0x00, 0x00}, | ||
578 | {0x80, 0x00, 0x00, 0x00}, | ||
579 | {0xc0, 0x00, 0x00, 0x00}, | ||
580 | }; | ||
581 | size_t i, j; | ||
582 | |||
583 | /* The EOF header does not exist in compressed data */ | ||
584 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || | ||
585 | cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
586 | return NULL; | ||
587 | |||
588 | /* | ||
589 | The EOF header might cross the packet boundary, but this is not a | ||
590 | problem, since the end of a frame is determined by checking its size | ||
591 | in the first place. | ||
592 | */ | ||
593 | for (i = 0; (len >= 4) && (i <= len - 4); i++) | ||
594 | for (j = 0; j < ARRAY_SIZE(eof_header); j++) | ||
595 | if (!memcmp(mem + i, eof_header[j], 4)) | ||
596 | return mem + i; | ||
597 | |||
598 | return NULL; | ||
599 | } | ||
600 | |||
601 | |||
602 | static void | ||
603 | sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) | ||
604 | { | ||
605 | static const u8 jpeg_header[589] = { | ||
606 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, | ||
607 | 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, | ||
608 | 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, | ||
609 | 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16, | ||
610 | 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16, | ||
611 | 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29, | ||
612 | 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29, | ||
613 | 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a, | ||
614 | 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28, | ||
615 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
616 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
617 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
618 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, | ||
619 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2, | ||
620 | 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
621 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, | ||
622 | 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, | ||
623 | 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
624 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, | ||
625 | 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, | ||
626 | 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, | ||
627 | 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, | ||
628 | 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, | ||
629 | 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, | ||
630 | 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, | ||
631 | 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, | ||
632 | 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, | ||
633 | 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, | ||
634 | 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, | ||
635 | 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, | ||
636 | 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, | ||
637 | 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, | ||
638 | 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, | ||
639 | 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, | ||
640 | 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, | ||
641 | 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, | ||
642 | 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, | ||
643 | 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, | ||
644 | 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, | ||
645 | 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, | ||
646 | 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, | ||
647 | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, | ||
648 | 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, | ||
649 | 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, | ||
650 | 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, | ||
651 | 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, | ||
652 | 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, | ||
653 | 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, | ||
654 | 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | ||
655 | 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, | ||
656 | 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, | ||
657 | 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, | ||
658 | 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, | ||
659 | 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, | ||
660 | 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, | ||
661 | 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11, | ||
662 | 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02, | ||
663 | 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, | ||
664 | 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 | ||
665 | }; | ||
666 | u8 *pos = f->bufmem; | ||
667 | |||
668 | memcpy(pos, jpeg_header, sizeof(jpeg_header)); | ||
669 | *(pos + 6) = 0x00; | ||
670 | *(pos + 7 + 64) = 0x01; | ||
671 | if (cam->compression.quality == 0) { | ||
672 | memcpy(pos + 7, SN9C102_Y_QTABLE0, 64); | ||
673 | memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64); | ||
674 | } else if (cam->compression.quality == 1) { | ||
675 | memcpy(pos + 7, SN9C102_Y_QTABLE1, 64); | ||
676 | memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64); | ||
677 | } | ||
678 | *(pos + 564) = cam->sensor.pix_format.width & 0xFF; | ||
679 | *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF; | ||
680 | *(pos + 562) = cam->sensor.pix_format.height & 0xFF; | ||
681 | *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF; | ||
682 | *(pos + 567) = 0x21; | ||
683 | |||
684 | f->buf.bytesused += sizeof(jpeg_header); | ||
685 | } | ||
686 | |||
687 | |||
688 | static void sn9c102_urb_complete(struct urb *urb) | ||
689 | { | ||
690 | struct sn9c102_device* cam = urb->context; | ||
691 | struct sn9c102_frame_t** f; | ||
692 | size_t imagesize, soflen; | ||
693 | u8 i; | ||
694 | int err = 0; | ||
695 | |||
696 | if (urb->status == -ENOENT) | ||
697 | return; | ||
698 | |||
699 | f = &cam->frame_current; | ||
700 | |||
701 | if (cam->stream == STREAM_INTERRUPT) { | ||
702 | cam->stream = STREAM_OFF; | ||
703 | if ((*f)) | ||
704 | (*f)->state = F_QUEUED; | ||
705 | cam->sof.bytesread = 0; | ||
706 | DBG(3, "Stream interrupted by application"); | ||
707 | wake_up(&cam->wait_stream); | ||
708 | } | ||
709 | |||
710 | if (cam->state & DEV_DISCONNECTED) | ||
711 | return; | ||
712 | |||
713 | if (cam->state & DEV_MISCONFIGURED) { | ||
714 | wake_up_interruptible(&cam->wait_frame); | ||
715 | return; | ||
716 | } | ||
717 | |||
718 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
719 | goto resubmit_urb; | ||
720 | |||
721 | if (!(*f)) | ||
722 | (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, | ||
723 | frame); | ||
724 | |||
725 | imagesize = (cam->sensor.pix_format.width * | ||
726 | cam->sensor.pix_format.height * | ||
727 | cam->sensor.pix_format.priv) / 8; | ||
728 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
729 | imagesize += 589; /* length of jpeg header */ | ||
730 | soflen = sn9c102_sof_length(cam); | ||
731 | |||
732 | for (i = 0; i < urb->number_of_packets; i++) { | ||
733 | unsigned int img, len, status; | ||
734 | void *pos, *sof, *eof; | ||
735 | |||
736 | len = urb->iso_frame_desc[i].actual_length; | ||
737 | status = urb->iso_frame_desc[i].status; | ||
738 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
739 | |||
740 | if (status) { | ||
741 | DBG(3, "Error in isochronous frame"); | ||
742 | (*f)->state = F_ERROR; | ||
743 | cam->sof.bytesread = 0; | ||
744 | continue; | ||
745 | } | ||
746 | |||
747 | PDBGG("Isochrnous frame: length %u, #%u i", len, i); | ||
748 | |||
749 | redo: | ||
750 | sof = sn9c102_find_sof_header(cam, pos, len); | ||
751 | if (likely(!sof)) { | ||
752 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
753 | if ((*f)->state == F_GRABBING) { | ||
754 | end_of_frame: | ||
755 | img = len; | ||
756 | |||
757 | if (eof) | ||
758 | img = (eof > pos) ? eof - pos - 1 : 0; | ||
759 | |||
760 | if ((*f)->buf.bytesused + img > imagesize) { | ||
761 | u32 b; | ||
762 | b = (*f)->buf.bytesused + img - | ||
763 | imagesize; | ||
764 | img = imagesize - (*f)->buf.bytesused; | ||
765 | PDBGG("Expected EOF not found: video " | ||
766 | "frame cut"); | ||
767 | if (eof) | ||
768 | DBG(3, "Exceeded limit: +%u " | ||
769 | "bytes", (unsigned)(b)); | ||
770 | } | ||
771 | |||
772 | memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, | ||
773 | img); | ||
774 | |||
775 | if ((*f)->buf.bytesused == 0) | ||
776 | v4l2_get_timestamp( | ||
777 | &(*f)->buf.timestamp); | ||
778 | |||
779 | (*f)->buf.bytesused += img; | ||
780 | |||
781 | if ((*f)->buf.bytesused == imagesize || | ||
782 | ((cam->sensor.pix_format.pixelformat == | ||
783 | V4L2_PIX_FMT_SN9C10X || | ||
784 | cam->sensor.pix_format.pixelformat == | ||
785 | V4L2_PIX_FMT_JPEG) && eof)) { | ||
786 | u32 b; | ||
787 | |||
788 | b = (*f)->buf.bytesused; | ||
789 | (*f)->state = F_DONE; | ||
790 | (*f)->buf.sequence= ++cam->frame_count; | ||
791 | |||
792 | spin_lock(&cam->queue_lock); | ||
793 | list_move_tail(&(*f)->frame, | ||
794 | &cam->outqueue); | ||
795 | if (!list_empty(&cam->inqueue)) | ||
796 | (*f) = list_entry( | ||
797 | cam->inqueue.next, | ||
798 | struct sn9c102_frame_t, | ||
799 | frame ); | ||
800 | else | ||
801 | (*f) = NULL; | ||
802 | spin_unlock(&cam->queue_lock); | ||
803 | |||
804 | memcpy(cam->sysfs.frame_header, | ||
805 | cam->sof.header, soflen); | ||
806 | |||
807 | DBG(3, "Video frame captured: %lu " | ||
808 | "bytes", (unsigned long)(b)); | ||
809 | |||
810 | if (!(*f)) | ||
811 | goto resubmit_urb; | ||
812 | |||
813 | } else if (eof) { | ||
814 | (*f)->state = F_ERROR; | ||
815 | DBG(3, "Not expected EOF after %lu " | ||
816 | "bytes of image data", | ||
817 | (unsigned long) | ||
818 | ((*f)->buf.bytesused)); | ||
819 | } | ||
820 | |||
821 | if (sof) /* (1) */ | ||
822 | goto start_of_frame; | ||
823 | |||
824 | } else if (eof) { | ||
825 | DBG(3, "EOF without SOF"); | ||
826 | continue; | ||
827 | |||
828 | } else { | ||
829 | PDBGG("Ignoring pointless isochronous frame"); | ||
830 | continue; | ||
831 | } | ||
832 | |||
833 | } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { | ||
834 | start_of_frame: | ||
835 | (*f)->state = F_GRABBING; | ||
836 | (*f)->buf.bytesused = 0; | ||
837 | len -= (sof - pos); | ||
838 | pos = sof; | ||
839 | if (cam->sensor.pix_format.pixelformat == | ||
840 | V4L2_PIX_FMT_JPEG) | ||
841 | sn9c102_write_jpegheader(cam, (*f)); | ||
842 | DBG(3, "SOF detected: new video frame"); | ||
843 | if (len) | ||
844 | goto redo; | ||
845 | |||
846 | } else if ((*f)->state == F_GRABBING) { | ||
847 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
848 | if (eof && eof < sof) | ||
849 | goto end_of_frame; /* (1) */ | ||
850 | else { | ||
851 | if (cam->sensor.pix_format.pixelformat == | ||
852 | V4L2_PIX_FMT_SN9C10X || | ||
853 | cam->sensor.pix_format.pixelformat == | ||
854 | V4L2_PIX_FMT_JPEG) { | ||
855 | if (sof - pos >= soflen) { | ||
856 | eof = sof - soflen; | ||
857 | } else { /* remove header */ | ||
858 | eof = pos; | ||
859 | (*f)->buf.bytesused -= | ||
860 | (soflen - (sof - pos)); | ||
861 | } | ||
862 | goto end_of_frame; | ||
863 | } else { | ||
864 | DBG(3, "SOF before expected EOF after " | ||
865 | "%lu bytes of image data", | ||
866 | (unsigned long) | ||
867 | ((*f)->buf.bytesused)); | ||
868 | goto start_of_frame; | ||
869 | } | ||
870 | } | ||
871 | } | ||
872 | } | ||
873 | |||
874 | resubmit_urb: | ||
875 | urb->dev = cam->usbdev; | ||
876 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
877 | if (err < 0 && err != -EPERM) { | ||
878 | cam->state |= DEV_MISCONFIGURED; | ||
879 | DBG(1, "usb_submit_urb() failed"); | ||
880 | } | ||
881 | |||
882 | wake_up_interruptible(&cam->wait_frame); | ||
883 | } | ||
884 | |||
885 | |||
886 | static int sn9c102_start_transfer(struct sn9c102_device* cam) | ||
887 | { | ||
888 | struct usb_device *udev = cam->usbdev; | ||
889 | struct urb* urb; | ||
890 | struct usb_host_interface* altsetting = usb_altnum_to_altsetting( | ||
891 | usb_ifnum_to_if(udev, 0), | ||
892 | SN9C102_ALTERNATE_SETTING); | ||
893 | const unsigned int psz = le16_to_cpu(altsetting-> | ||
894 | endpoint[0].desc.wMaxPacketSize); | ||
895 | s8 i, j; | ||
896 | int err = 0; | ||
897 | |||
898 | for (i = 0; i < SN9C102_URBS; i++) { | ||
899 | cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz, | ||
900 | GFP_KERNEL); | ||
901 | if (!cam->transfer_buffer[i]) { | ||
902 | err = -ENOMEM; | ||
903 | DBG(1, "Not enough memory"); | ||
904 | goto free_buffers; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | for (i = 0; i < SN9C102_URBS; i++) { | ||
909 | urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); | ||
910 | cam->urb[i] = urb; | ||
911 | if (!urb) { | ||
912 | err = -ENOMEM; | ||
913 | DBG(1, "usb_alloc_urb() failed"); | ||
914 | goto free_urbs; | ||
915 | } | ||
916 | urb->dev = udev; | ||
917 | urb->context = cam; | ||
918 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
919 | urb->transfer_flags = URB_ISO_ASAP; | ||
920 | urb->number_of_packets = SN9C102_ISO_PACKETS; | ||
921 | urb->complete = sn9c102_urb_complete; | ||
922 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
923 | urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; | ||
924 | urb->interval = 1; | ||
925 | for (j = 0; j < SN9C102_ISO_PACKETS; j++) { | ||
926 | urb->iso_frame_desc[j].offset = psz * j; | ||
927 | urb->iso_frame_desc[j].length = psz; | ||
928 | } | ||
929 | } | ||
930 | |||
931 | /* Enable video */ | ||
932 | if (!(cam->reg[0x01] & 0x04)) { | ||
933 | err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); | ||
934 | if (err) { | ||
935 | err = -EIO; | ||
936 | DBG(1, "I/O hardware error"); | ||
937 | goto free_urbs; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); | ||
942 | if (err) { | ||
943 | DBG(1, "usb_set_interface() failed"); | ||
944 | goto free_urbs; | ||
945 | } | ||
946 | |||
947 | cam->frame_current = NULL; | ||
948 | cam->sof.bytesread = 0; | ||
949 | |||
950 | for (i = 0; i < SN9C102_URBS; i++) { | ||
951 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
952 | if (err) { | ||
953 | for (j = i-1; j >= 0; j--) | ||
954 | usb_kill_urb(cam->urb[j]); | ||
955 | DBG(1, "usb_submit_urb() failed, error %d", err); | ||
956 | goto free_urbs; | ||
957 | } | ||
958 | } | ||
959 | |||
960 | return 0; | ||
961 | |||
962 | free_urbs: | ||
963 | for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) | ||
964 | usb_free_urb(cam->urb[i]); | ||
965 | |||
966 | free_buffers: | ||
967 | for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) | ||
968 | kfree(cam->transfer_buffer[i]); | ||
969 | |||
970 | return err; | ||
971 | } | ||
972 | |||
973 | |||
974 | static int sn9c102_stop_transfer(struct sn9c102_device* cam) | ||
975 | { | ||
976 | struct usb_device *udev = cam->usbdev; | ||
977 | s8 i; | ||
978 | int err = 0; | ||
979 | |||
980 | if (cam->state & DEV_DISCONNECTED) | ||
981 | return 0; | ||
982 | |||
983 | for (i = SN9C102_URBS-1; i >= 0; i--) { | ||
984 | usb_kill_urb(cam->urb[i]); | ||
985 | usb_free_urb(cam->urb[i]); | ||
986 | kfree(cam->transfer_buffer[i]); | ||
987 | } | ||
988 | |||
989 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
990 | if (err) | ||
991 | DBG(3, "usb_set_interface() failed"); | ||
992 | |||
993 | return err; | ||
994 | } | ||
995 | |||
996 | |||
997 | static int sn9c102_stream_interrupt(struct sn9c102_device* cam) | ||
998 | { | ||
999 | cam->stream = STREAM_INTERRUPT; | ||
1000 | wait_event_timeout(cam->wait_stream, | ||
1001 | (cam->stream == STREAM_OFF) || | ||
1002 | (cam->state & DEV_DISCONNECTED), | ||
1003 | SN9C102_URB_TIMEOUT); | ||
1004 | if (cam->state & DEV_DISCONNECTED) | ||
1005 | return -ENODEV; | ||
1006 | else if (cam->stream != STREAM_OFF) { | ||
1007 | cam->state |= DEV_MISCONFIGURED; | ||
1008 | DBG(1, "URB timeout reached. The camera is misconfigured. " | ||
1009 | "To use it, close and open %s again.", | ||
1010 | video_device_node_name(cam->v4ldev)); | ||
1011 | return -EIO; | ||
1012 | } | ||
1013 | |||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
1017 | /*****************************************************************************/ | ||
1018 | |||
1019 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1020 | static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) | ||
1021 | { | ||
1022 | char str[7]; | ||
1023 | char* endp; | ||
1024 | unsigned long val; | ||
1025 | |||
1026 | if (len < 6) { | ||
1027 | strncpy(str, buff, len); | ||
1028 | str[len] = '\0'; | ||
1029 | } else { | ||
1030 | strncpy(str, buff, 6); | ||
1031 | str[6] = '\0'; | ||
1032 | } | ||
1033 | |||
1034 | val = simple_strtoul(str, &endp, 0); | ||
1035 | |||
1036 | *count = 0; | ||
1037 | if (val <= 0xffff) | ||
1038 | *count = (ssize_t)(endp - str); | ||
1039 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) | ||
1040 | *count += 1; | ||
1041 | |||
1042 | return (u16)val; | ||
1043 | } | ||
1044 | |||
1045 | /* | ||
1046 | NOTE 1: being inside one of the following methods implies that the v4l | ||
1047 | device exists for sure (see kobjects and reference counters) | ||
1048 | NOTE 2: buffers are PAGE_SIZE long | ||
1049 | */ | ||
1050 | |||
1051 | static ssize_t sn9c102_show_reg(struct device* cd, | ||
1052 | struct device_attribute *attr, char* buf) | ||
1053 | { | ||
1054 | struct sn9c102_device* cam; | ||
1055 | ssize_t count; | ||
1056 | |||
1057 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1058 | return -ERESTARTSYS; | ||
1059 | |||
1060 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1061 | if (!cam) { | ||
1062 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1063 | return -ENODEV; | ||
1064 | } | ||
1065 | |||
1066 | count = sprintf(buf, "%u\n", cam->sysfs.reg); | ||
1067 | |||
1068 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1069 | |||
1070 | return count; | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | static ssize_t | ||
1075 | sn9c102_store_reg(struct device* cd, struct device_attribute *attr, | ||
1076 | const char* buf, size_t len) | ||
1077 | { | ||
1078 | struct sn9c102_device* cam; | ||
1079 | u16 index; | ||
1080 | ssize_t count; | ||
1081 | |||
1082 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1083 | return -ERESTARTSYS; | ||
1084 | |||
1085 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1086 | if (!cam) { | ||
1087 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1088 | return -ENODEV; | ||
1089 | } | ||
1090 | |||
1091 | index = sn9c102_strtou16(buf, len, &count); | ||
1092 | if (index >= ARRAY_SIZE(cam->reg) || !count) { | ||
1093 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1094 | return -EINVAL; | ||
1095 | } | ||
1096 | |||
1097 | cam->sysfs.reg = index; | ||
1098 | |||
1099 | DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg); | ||
1100 | DBG(3, "Written bytes: %zd", count); | ||
1101 | |||
1102 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1103 | |||
1104 | return count; | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | static ssize_t sn9c102_show_val(struct device* cd, | ||
1109 | struct device_attribute *attr, char* buf) | ||
1110 | { | ||
1111 | struct sn9c102_device* cam; | ||
1112 | ssize_t count; | ||
1113 | int val; | ||
1114 | |||
1115 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1116 | return -ERESTARTSYS; | ||
1117 | |||
1118 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1119 | if (!cam) { | ||
1120 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1121 | return -ENODEV; | ||
1122 | } | ||
1123 | |||
1124 | if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { | ||
1125 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1126 | return -EIO; | ||
1127 | } | ||
1128 | |||
1129 | count = sprintf(buf, "%d\n", val); | ||
1130 | |||
1131 | DBG(3, "Read bytes: %zd, value: %d", count, val); | ||
1132 | |||
1133 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1134 | |||
1135 | return count; | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | static ssize_t | ||
1140 | sn9c102_store_val(struct device* cd, struct device_attribute *attr, | ||
1141 | const char* buf, size_t len) | ||
1142 | { | ||
1143 | struct sn9c102_device* cam; | ||
1144 | u16 value; | ||
1145 | ssize_t count; | ||
1146 | int err; | ||
1147 | |||
1148 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1149 | return -ERESTARTSYS; | ||
1150 | |||
1151 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1152 | if (!cam) { | ||
1153 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1154 | return -ENODEV; | ||
1155 | } | ||
1156 | |||
1157 | value = sn9c102_strtou16(buf, len, &count); | ||
1158 | if (!count) { | ||
1159 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1160 | return -EINVAL; | ||
1161 | } | ||
1162 | |||
1163 | err = sn9c102_write_reg(cam, value, cam->sysfs.reg); | ||
1164 | if (err) { | ||
1165 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1166 | return -EIO; | ||
1167 | } | ||
1168 | |||
1169 | DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X", | ||
1170 | cam->sysfs.reg, value); | ||
1171 | DBG(3, "Written bytes: %zd", count); | ||
1172 | |||
1173 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1174 | |||
1175 | return count; | ||
1176 | } | ||
1177 | |||
1178 | |||
1179 | static ssize_t sn9c102_show_i2c_reg(struct device* cd, | ||
1180 | struct device_attribute *attr, char* buf) | ||
1181 | { | ||
1182 | struct sn9c102_device* cam; | ||
1183 | ssize_t count; | ||
1184 | |||
1185 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1186 | return -ERESTARTSYS; | ||
1187 | |||
1188 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1189 | if (!cam) { | ||
1190 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1191 | return -ENODEV; | ||
1192 | } | ||
1193 | |||
1194 | count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); | ||
1195 | |||
1196 | DBG(3, "Read bytes: %zd", count); | ||
1197 | |||
1198 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1199 | |||
1200 | return count; | ||
1201 | } | ||
1202 | |||
1203 | |||
1204 | static ssize_t | ||
1205 | sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, | ||
1206 | const char* buf, size_t len) | ||
1207 | { | ||
1208 | struct sn9c102_device* cam; | ||
1209 | u16 index; | ||
1210 | ssize_t count; | ||
1211 | |||
1212 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1213 | return -ERESTARTSYS; | ||
1214 | |||
1215 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1216 | if (!cam) { | ||
1217 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1218 | return -ENODEV; | ||
1219 | } | ||
1220 | |||
1221 | index = sn9c102_strtou16(buf, len, &count); | ||
1222 | if (!count) { | ||
1223 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1224 | return -EINVAL; | ||
1225 | } | ||
1226 | |||
1227 | cam->sysfs.i2c_reg = index; | ||
1228 | |||
1229 | DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); | ||
1230 | DBG(3, "Written bytes: %zd", count); | ||
1231 | |||
1232 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1233 | |||
1234 | return count; | ||
1235 | } | ||
1236 | |||
1237 | |||
1238 | static ssize_t sn9c102_show_i2c_val(struct device* cd, | ||
1239 | struct device_attribute *attr, char* buf) | ||
1240 | { | ||
1241 | struct sn9c102_device* cam; | ||
1242 | ssize_t count; | ||
1243 | int val; | ||
1244 | |||
1245 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1246 | return -ERESTARTSYS; | ||
1247 | |||
1248 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1249 | if (!cam) { | ||
1250 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1251 | return -ENODEV; | ||
1252 | } | ||
1253 | |||
1254 | if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) { | ||
1255 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1256 | return -ENOSYS; | ||
1257 | } | ||
1258 | |||
1259 | if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { | ||
1260 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1261 | return -EIO; | ||
1262 | } | ||
1263 | |||
1264 | count = sprintf(buf, "%d\n", val); | ||
1265 | |||
1266 | DBG(3, "Read bytes: %zd, value: %d", count, val); | ||
1267 | |||
1268 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1269 | |||
1270 | return count; | ||
1271 | } | ||
1272 | |||
1273 | |||
1274 | static ssize_t | ||
1275 | sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, | ||
1276 | const char* buf, size_t len) | ||
1277 | { | ||
1278 | struct sn9c102_device* cam; | ||
1279 | u16 value; | ||
1280 | ssize_t count; | ||
1281 | int err; | ||
1282 | |||
1283 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1284 | return -ERESTARTSYS; | ||
1285 | |||
1286 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1287 | if (!cam) { | ||
1288 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1289 | return -ENODEV; | ||
1290 | } | ||
1291 | |||
1292 | if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) { | ||
1293 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1294 | return -ENOSYS; | ||
1295 | } | ||
1296 | |||
1297 | value = sn9c102_strtou16(buf, len, &count); | ||
1298 | if (!count) { | ||
1299 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1300 | return -EINVAL; | ||
1301 | } | ||
1302 | |||
1303 | err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); | ||
1304 | if (err) { | ||
1305 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1306 | return -EIO; | ||
1307 | } | ||
1308 | |||
1309 | DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", | ||
1310 | cam->sysfs.i2c_reg, value); | ||
1311 | DBG(3, "Written bytes: %zd", count); | ||
1312 | |||
1313 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1314 | |||
1315 | return count; | ||
1316 | } | ||
1317 | |||
1318 | |||
1319 | static ssize_t | ||
1320 | sn9c102_store_green(struct device* cd, struct device_attribute *attr, | ||
1321 | const char* buf, size_t len) | ||
1322 | { | ||
1323 | struct sn9c102_device* cam; | ||
1324 | enum sn9c102_bridge bridge; | ||
1325 | ssize_t res = 0; | ||
1326 | u16 value; | ||
1327 | ssize_t count; | ||
1328 | |||
1329 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1330 | return -ERESTARTSYS; | ||
1331 | |||
1332 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1333 | if (!cam) { | ||
1334 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1335 | return -ENODEV; | ||
1336 | } | ||
1337 | |||
1338 | bridge = cam->bridge; | ||
1339 | |||
1340 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1341 | |||
1342 | value = sn9c102_strtou16(buf, len, &count); | ||
1343 | if (!count) | ||
1344 | return -EINVAL; | ||
1345 | |||
1346 | switch (bridge) { | ||
1347 | case BRIDGE_SN9C101: | ||
1348 | case BRIDGE_SN9C102: | ||
1349 | if (value > 0x0f) | ||
1350 | return -EINVAL; | ||
1351 | if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0) | ||
1352 | res = sn9c102_store_val(cd, attr, buf, len); | ||
1353 | break; | ||
1354 | case BRIDGE_SN9C103: | ||
1355 | case BRIDGE_SN9C105: | ||
1356 | case BRIDGE_SN9C120: | ||
1357 | if (value > 0x7f) | ||
1358 | return -EINVAL; | ||
1359 | if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0) | ||
1360 | res = sn9c102_store_val(cd, attr, buf, len); | ||
1361 | break; | ||
1362 | } | ||
1363 | |||
1364 | return res; | ||
1365 | } | ||
1366 | |||
1367 | |||
1368 | static ssize_t | ||
1369 | sn9c102_store_blue(struct device* cd, struct device_attribute *attr, | ||
1370 | const char* buf, size_t len) | ||
1371 | { | ||
1372 | ssize_t res = 0; | ||
1373 | u16 value; | ||
1374 | ssize_t count; | ||
1375 | |||
1376 | value = sn9c102_strtou16(buf, len, &count); | ||
1377 | if (!count || value > 0x7f) | ||
1378 | return -EINVAL; | ||
1379 | |||
1380 | if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0) | ||
1381 | res = sn9c102_store_val(cd, attr, buf, len); | ||
1382 | |||
1383 | return res; | ||
1384 | } | ||
1385 | |||
1386 | |||
1387 | static ssize_t | ||
1388 | sn9c102_store_red(struct device* cd, struct device_attribute *attr, | ||
1389 | const char* buf, size_t len) | ||
1390 | { | ||
1391 | ssize_t res = 0; | ||
1392 | u16 value; | ||
1393 | ssize_t count; | ||
1394 | |||
1395 | value = sn9c102_strtou16(buf, len, &count); | ||
1396 | if (!count || value > 0x7f) | ||
1397 | return -EINVAL; | ||
1398 | |||
1399 | if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0) | ||
1400 | res = sn9c102_store_val(cd, attr, buf, len); | ||
1401 | |||
1402 | return res; | ||
1403 | } | ||
1404 | |||
1405 | |||
1406 | static ssize_t sn9c102_show_frame_header(struct device* cd, | ||
1407 | struct device_attribute *attr, | ||
1408 | char* buf) | ||
1409 | { | ||
1410 | struct sn9c102_device* cam; | ||
1411 | ssize_t count; | ||
1412 | |||
1413 | cam = video_get_drvdata(container_of(cd, struct video_device, dev)); | ||
1414 | if (!cam) | ||
1415 | return -ENODEV; | ||
1416 | |||
1417 | count = sizeof(cam->sysfs.frame_header); | ||
1418 | memcpy(buf, cam->sysfs.frame_header, count); | ||
1419 | |||
1420 | DBG(3, "Frame header, read bytes: %zd", count); | ||
1421 | |||
1422 | return count; | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg); | ||
1427 | static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val); | ||
1428 | static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, | ||
1429 | sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); | ||
1430 | static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, | ||
1431 | sn9c102_show_i2c_val, sn9c102_store_i2c_val); | ||
1432 | static DEVICE_ATTR(green, S_IWUSR, NULL, sn9c102_store_green); | ||
1433 | static DEVICE_ATTR(blue, S_IWUSR, NULL, sn9c102_store_blue); | ||
1434 | static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red); | ||
1435 | static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); | ||
1436 | |||
1437 | |||
1438 | static int sn9c102_create_sysfs(struct sn9c102_device* cam) | ||
1439 | { | ||
1440 | struct device *dev = &(cam->v4ldev->dev); | ||
1441 | int err = 0; | ||
1442 | |||
1443 | if ((err = device_create_file(dev, &dev_attr_reg))) | ||
1444 | goto err_out; | ||
1445 | if ((err = device_create_file(dev, &dev_attr_val))) | ||
1446 | goto err_reg; | ||
1447 | if ((err = device_create_file(dev, &dev_attr_frame_header))) | ||
1448 | goto err_val; | ||
1449 | |||
1450 | if (cam->sensor.sysfs_ops) { | ||
1451 | if ((err = device_create_file(dev, &dev_attr_i2c_reg))) | ||
1452 | goto err_frame_header; | ||
1453 | if ((err = device_create_file(dev, &dev_attr_i2c_val))) | ||
1454 | goto err_i2c_reg; | ||
1455 | } | ||
1456 | |||
1457 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { | ||
1458 | if ((err = device_create_file(dev, &dev_attr_green))) | ||
1459 | goto err_i2c_val; | ||
1460 | } else { | ||
1461 | if ((err = device_create_file(dev, &dev_attr_blue))) | ||
1462 | goto err_i2c_val; | ||
1463 | if ((err = device_create_file(dev, &dev_attr_red))) | ||
1464 | goto err_blue; | ||
1465 | } | ||
1466 | |||
1467 | return 0; | ||
1468 | |||
1469 | err_blue: | ||
1470 | device_remove_file(dev, &dev_attr_blue); | ||
1471 | err_i2c_val: | ||
1472 | if (cam->sensor.sysfs_ops) | ||
1473 | device_remove_file(dev, &dev_attr_i2c_val); | ||
1474 | err_i2c_reg: | ||
1475 | if (cam->sensor.sysfs_ops) | ||
1476 | device_remove_file(dev, &dev_attr_i2c_reg); | ||
1477 | err_frame_header: | ||
1478 | device_remove_file(dev, &dev_attr_frame_header); | ||
1479 | err_val: | ||
1480 | device_remove_file(dev, &dev_attr_val); | ||
1481 | err_reg: | ||
1482 | device_remove_file(dev, &dev_attr_reg); | ||
1483 | err_out: | ||
1484 | return err; | ||
1485 | } | ||
1486 | #endif /* CONFIG_VIDEO_ADV_DEBUG */ | ||
1487 | |||
1488 | /*****************************************************************************/ | ||
1489 | |||
1490 | static int | ||
1491 | sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) | ||
1492 | { | ||
1493 | int err = 0; | ||
1494 | |||
1495 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || | ||
1496 | pix->pixelformat == V4L2_PIX_FMT_JPEG) { | ||
1497 | switch (cam->bridge) { | ||
1498 | case BRIDGE_SN9C101: | ||
1499 | case BRIDGE_SN9C102: | ||
1500 | case BRIDGE_SN9C103: | ||
1501 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, | ||
1502 | 0x18); | ||
1503 | break; | ||
1504 | case BRIDGE_SN9C105: | ||
1505 | case BRIDGE_SN9C120: | ||
1506 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, | ||
1507 | 0x18); | ||
1508 | break; | ||
1509 | } | ||
1510 | } else { | ||
1511 | switch (cam->bridge) { | ||
1512 | case BRIDGE_SN9C101: | ||
1513 | case BRIDGE_SN9C102: | ||
1514 | case BRIDGE_SN9C103: | ||
1515 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, | ||
1516 | 0x18); | ||
1517 | break; | ||
1518 | case BRIDGE_SN9C105: | ||
1519 | case BRIDGE_SN9C120: | ||
1520 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, | ||
1521 | 0x18); | ||
1522 | break; | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1526 | return err ? -EIO : 0; | ||
1527 | } | ||
1528 | |||
1529 | |||
1530 | static int | ||
1531 | sn9c102_set_compression(struct sn9c102_device* cam, | ||
1532 | struct v4l2_jpegcompression* compression) | ||
1533 | { | ||
1534 | int i, err = 0; | ||
1535 | |||
1536 | switch (cam->bridge) { | ||
1537 | case BRIDGE_SN9C101: | ||
1538 | case BRIDGE_SN9C102: | ||
1539 | case BRIDGE_SN9C103: | ||
1540 | if (compression->quality == 0) | ||
1541 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, | ||
1542 | 0x17); | ||
1543 | else if (compression->quality == 1) | ||
1544 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, | ||
1545 | 0x17); | ||
1546 | break; | ||
1547 | case BRIDGE_SN9C105: | ||
1548 | case BRIDGE_SN9C120: | ||
1549 | if (compression->quality == 0) { | ||
1550 | for (i = 0; i <= 63; i++) { | ||
1551 | err += sn9c102_write_reg(cam, | ||
1552 | SN9C102_Y_QTABLE1[i], | ||
1553 | 0x100 + i); | ||
1554 | err += sn9c102_write_reg(cam, | ||
1555 | SN9C102_UV_QTABLE1[i], | ||
1556 | 0x140 + i); | ||
1557 | } | ||
1558 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, | ||
1559 | 0x18); | ||
1560 | } else if (compression->quality == 1) { | ||
1561 | for (i = 0; i <= 63; i++) { | ||
1562 | err += sn9c102_write_reg(cam, | ||
1563 | SN9C102_Y_QTABLE1[i], | ||
1564 | 0x100 + i); | ||
1565 | err += sn9c102_write_reg(cam, | ||
1566 | SN9C102_UV_QTABLE1[i], | ||
1567 | 0x140 + i); | ||
1568 | } | ||
1569 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40, | ||
1570 | 0x18); | ||
1571 | } | ||
1572 | break; | ||
1573 | } | ||
1574 | |||
1575 | return err ? -EIO : 0; | ||
1576 | } | ||
1577 | |||
1578 | |||
1579 | static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) | ||
1580 | { | ||
1581 | u8 r = 0; | ||
1582 | int err = 0; | ||
1583 | |||
1584 | if (scale == 1) | ||
1585 | r = cam->reg[0x18] & 0xcf; | ||
1586 | else if (scale == 2) { | ||
1587 | r = cam->reg[0x18] & 0xcf; | ||
1588 | r |= 0x10; | ||
1589 | } else if (scale == 4) | ||
1590 | r = cam->reg[0x18] | 0x20; | ||
1591 | |||
1592 | err += sn9c102_write_reg(cam, r, 0x18); | ||
1593 | if (err) | ||
1594 | return -EIO; | ||
1595 | |||
1596 | PDBGG("Scaling factor: %u", scale); | ||
1597 | |||
1598 | return 0; | ||
1599 | } | ||
1600 | |||
1601 | |||
1602 | static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) | ||
1603 | { | ||
1604 | struct sn9c102_sensor* s = &cam->sensor; | ||
1605 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), | ||
1606 | v_start = (u8)(rect->top - s->cropcap.bounds.top), | ||
1607 | h_size = (u8)(rect->width / 16), | ||
1608 | v_size = (u8)(rect->height / 16); | ||
1609 | int err = 0; | ||
1610 | |||
1611 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
1612 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
1613 | err += sn9c102_write_reg(cam, h_size, 0x15); | ||
1614 | err += sn9c102_write_reg(cam, v_size, 0x16); | ||
1615 | if (err) | ||
1616 | return -EIO; | ||
1617 | |||
1618 | PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " | ||
1619 | "%u %u %u %u", h_start, v_start, h_size, v_size); | ||
1620 | |||
1621 | return 0; | ||
1622 | } | ||
1623 | |||
1624 | |||
1625 | static int sn9c102_init(struct sn9c102_device* cam) | ||
1626 | { | ||
1627 | struct sn9c102_sensor* s = &cam->sensor; | ||
1628 | struct v4l2_control ctrl; | ||
1629 | struct v4l2_queryctrl *qctrl; | ||
1630 | struct v4l2_rect* rect; | ||
1631 | u8 i = 0; | ||
1632 | int err = 0; | ||
1633 | |||
1634 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1635 | mutex_init(&cam->open_mutex); | ||
1636 | init_waitqueue_head(&cam->wait_open); | ||
1637 | qctrl = s->qctrl; | ||
1638 | rect = &(s->cropcap.defrect); | ||
1639 | } else { /* use current values */ | ||
1640 | qctrl = s->_qctrl; | ||
1641 | rect = &(s->_rect); | ||
1642 | } | ||
1643 | |||
1644 | err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); | ||
1645 | err += sn9c102_set_crop(cam, rect); | ||
1646 | if (err) | ||
1647 | return err; | ||
1648 | |||
1649 | if (s->init) { | ||
1650 | err = s->init(cam); | ||
1651 | if (err) { | ||
1652 | DBG(3, "Sensor initialization failed"); | ||
1653 | return err; | ||
1654 | } | ||
1655 | } | ||
1656 | |||
1657 | if (!(cam->state & DEV_INITIALIZED)) | ||
1658 | if (cam->bridge == BRIDGE_SN9C101 || | ||
1659 | cam->bridge == BRIDGE_SN9C102 || | ||
1660 | cam->bridge == BRIDGE_SN9C103) { | ||
1661 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
1662 | s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8; | ||
1663 | cam->compression.quality = cam->reg[0x17] & 0x01 ? | ||
1664 | 0 : 1; | ||
1665 | } else { | ||
1666 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
1667 | s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG; | ||
1668 | cam->compression.quality = cam->reg[0x18] & 0x40 ? | ||
1669 | 0 : 1; | ||
1670 | err += sn9c102_set_compression(cam, &cam->compression); | ||
1671 | } | ||
1672 | else | ||
1673 | err += sn9c102_set_compression(cam, &cam->compression); | ||
1674 | err += sn9c102_set_pix_format(cam, &s->pix_format); | ||
1675 | if (s->set_pix_format) | ||
1676 | err += s->set_pix_format(cam, &s->pix_format); | ||
1677 | if (err) | ||
1678 | return err; | ||
1679 | |||
1680 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || | ||
1681 | s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
1682 | DBG(3, "Compressed video format is active, quality %d", | ||
1683 | cam->compression.quality); | ||
1684 | else | ||
1685 | DBG(3, "Uncompressed video format is active"); | ||
1686 | |||
1687 | if (s->set_crop) | ||
1688 | if ((err = s->set_crop(cam, rect))) { | ||
1689 | DBG(3, "set_crop() failed"); | ||
1690 | return err; | ||
1691 | } | ||
1692 | |||
1693 | if (s->set_ctrl) { | ||
1694 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1695 | if (s->qctrl[i].id != 0 && | ||
1696 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
1697 | ctrl.id = s->qctrl[i].id; | ||
1698 | ctrl.value = qctrl[i].default_value; | ||
1699 | err = s->set_ctrl(cam, &ctrl); | ||
1700 | if (err) { | ||
1701 | DBG(3, "Set %s control failed", | ||
1702 | s->qctrl[i].name); | ||
1703 | return err; | ||
1704 | } | ||
1705 | DBG(3, "Image sensor supports '%s' control", | ||
1706 | s->qctrl[i].name); | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1711 | mutex_init(&cam->fileop_mutex); | ||
1712 | spin_lock_init(&cam->queue_lock); | ||
1713 | init_waitqueue_head(&cam->wait_frame); | ||
1714 | init_waitqueue_head(&cam->wait_stream); | ||
1715 | cam->nreadbuffers = 2; | ||
1716 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
1717 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
1718 | sizeof(struct v4l2_rect)); | ||
1719 | cam->state |= DEV_INITIALIZED; | ||
1720 | } | ||
1721 | |||
1722 | DBG(2, "Initialization succeeded"); | ||
1723 | return 0; | ||
1724 | } | ||
1725 | |||
1726 | /*****************************************************************************/ | ||
1727 | |||
1728 | static void sn9c102_release_resources(struct kref *kref) | ||
1729 | { | ||
1730 | struct sn9c102_device *cam; | ||
1731 | |||
1732 | mutex_lock(&sn9c102_sysfs_lock); | ||
1733 | |||
1734 | cam = container_of(kref, struct sn9c102_device, kref); | ||
1735 | |||
1736 | DBG(2, "V4L2 device %s deregistered", | ||
1737 | video_device_node_name(cam->v4ldev)); | ||
1738 | video_set_drvdata(cam->v4ldev, NULL); | ||
1739 | video_unregister_device(cam->v4ldev); | ||
1740 | v4l2_device_unregister(&cam->v4l2_dev); | ||
1741 | usb_put_dev(cam->usbdev); | ||
1742 | kfree(cam->control_buffer); | ||
1743 | kfree(cam); | ||
1744 | |||
1745 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1746 | |||
1747 | } | ||
1748 | |||
1749 | |||
1750 | static int sn9c102_open(struct file *filp) | ||
1751 | { | ||
1752 | struct sn9c102_device* cam; | ||
1753 | int err = 0; | ||
1754 | |||
1755 | /* | ||
1756 | A read_trylock() in open() is the only safe way to prevent race | ||
1757 | conditions with disconnect(), one close() and multiple (not | ||
1758 | necessarily simultaneous) attempts to open(). For example, it | ||
1759 | prevents from waiting for a second access, while the device | ||
1760 | structure is being deallocated, after a possible disconnect() and | ||
1761 | during a following close() holding the write lock: given that, after | ||
1762 | this deallocation, no access will be possible anymore, using the | ||
1763 | non-trylock version would have let open() gain the access to the | ||
1764 | device structure improperly. | ||
1765 | For this reason the lock must also not be per-device. | ||
1766 | */ | ||
1767 | if (!down_read_trylock(&sn9c102_dev_lock)) | ||
1768 | return -ERESTARTSYS; | ||
1769 | |||
1770 | cam = video_drvdata(filp); | ||
1771 | |||
1772 | if (wait_for_completion_interruptible(&cam->probe)) { | ||
1773 | up_read(&sn9c102_dev_lock); | ||
1774 | return -ERESTARTSYS; | ||
1775 | } | ||
1776 | |||
1777 | kref_get(&cam->kref); | ||
1778 | |||
1779 | /* | ||
1780 | Make sure to isolate all the simultaneous opens. | ||
1781 | */ | ||
1782 | if (mutex_lock_interruptible(&cam->open_mutex)) { | ||
1783 | kref_put(&cam->kref, sn9c102_release_resources); | ||
1784 | up_read(&sn9c102_dev_lock); | ||
1785 | return -ERESTARTSYS; | ||
1786 | } | ||
1787 | |||
1788 | if (cam->state & DEV_DISCONNECTED) { | ||
1789 | DBG(1, "Device not present"); | ||
1790 | err = -ENODEV; | ||
1791 | goto out; | ||
1792 | } | ||
1793 | |||
1794 | if (cam->users) { | ||
1795 | DBG(2, "Device %s is already in use", | ||
1796 | video_device_node_name(cam->v4ldev)); | ||
1797 | DBG(3, "Simultaneous opens are not supported"); | ||
1798 | /* | ||
1799 | open() must follow the open flags and should block | ||
1800 | eventually while the device is in use. | ||
1801 | */ | ||
1802 | if ((filp->f_flags & O_NONBLOCK) || | ||
1803 | (filp->f_flags & O_NDELAY)) { | ||
1804 | err = -EWOULDBLOCK; | ||
1805 | goto out; | ||
1806 | } | ||
1807 | DBG(2, "A blocking open() has been requested. Wait for the " | ||
1808 | "device to be released..."); | ||
1809 | up_read(&sn9c102_dev_lock); | ||
1810 | /* | ||
1811 | We will not release the "open_mutex" lock, so that only one | ||
1812 | process can be in the wait queue below. This way the process | ||
1813 | will be sleeping while holding the lock, without losing its | ||
1814 | priority after any wake_up(). | ||
1815 | */ | ||
1816 | err = wait_event_interruptible_exclusive(cam->wait_open, | ||
1817 | (cam->state & DEV_DISCONNECTED) | ||
1818 | || !cam->users); | ||
1819 | down_read(&sn9c102_dev_lock); | ||
1820 | if (err) | ||
1821 | goto out; | ||
1822 | if (cam->state & DEV_DISCONNECTED) { | ||
1823 | err = -ENODEV; | ||
1824 | goto out; | ||
1825 | } | ||
1826 | } | ||
1827 | |||
1828 | if (cam->state & DEV_MISCONFIGURED) { | ||
1829 | err = sn9c102_init(cam); | ||
1830 | if (err) { | ||
1831 | DBG(1, "Initialization failed again. " | ||
1832 | "I will retry on next open()."); | ||
1833 | goto out; | ||
1834 | } | ||
1835 | cam->state &= ~DEV_MISCONFIGURED; | ||
1836 | } | ||
1837 | |||
1838 | if ((err = sn9c102_start_transfer(cam))) | ||
1839 | goto out; | ||
1840 | |||
1841 | filp->private_data = cam; | ||
1842 | cam->users++; | ||
1843 | cam->io = IO_NONE; | ||
1844 | cam->stream = STREAM_OFF; | ||
1845 | cam->nbuffers = 0; | ||
1846 | cam->frame_count = 0; | ||
1847 | sn9c102_empty_framequeues(cam); | ||
1848 | |||
1849 | DBG(3, "Video device %s is open", video_device_node_name(cam->v4ldev)); | ||
1850 | |||
1851 | out: | ||
1852 | mutex_unlock(&cam->open_mutex); | ||
1853 | if (err) | ||
1854 | kref_put(&cam->kref, sn9c102_release_resources); | ||
1855 | |||
1856 | up_read(&sn9c102_dev_lock); | ||
1857 | return err; | ||
1858 | } | ||
1859 | |||
1860 | |||
1861 | static int sn9c102_release(struct file *filp) | ||
1862 | { | ||
1863 | struct sn9c102_device* cam; | ||
1864 | |||
1865 | down_write(&sn9c102_dev_lock); | ||
1866 | |||
1867 | cam = video_drvdata(filp); | ||
1868 | |||
1869 | sn9c102_stop_transfer(cam); | ||
1870 | sn9c102_release_buffers(cam); | ||
1871 | cam->users--; | ||
1872 | wake_up_interruptible_nr(&cam->wait_open, 1); | ||
1873 | |||
1874 | DBG(3, "Video device %s closed", video_device_node_name(cam->v4ldev)); | ||
1875 | |||
1876 | kref_put(&cam->kref, sn9c102_release_resources); | ||
1877 | |||
1878 | up_write(&sn9c102_dev_lock); | ||
1879 | |||
1880 | return 0; | ||
1881 | } | ||
1882 | |||
1883 | |||
1884 | static ssize_t | ||
1885 | sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
1886 | { | ||
1887 | struct sn9c102_device *cam = video_drvdata(filp); | ||
1888 | struct sn9c102_frame_t* f, * i; | ||
1889 | unsigned long lock_flags; | ||
1890 | long timeout; | ||
1891 | int err = 0; | ||
1892 | |||
1893 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1894 | return -ERESTARTSYS; | ||
1895 | |||
1896 | if (cam->state & DEV_DISCONNECTED) { | ||
1897 | DBG(1, "Device not present"); | ||
1898 | mutex_unlock(&cam->fileop_mutex); | ||
1899 | return -ENODEV; | ||
1900 | } | ||
1901 | |||
1902 | if (cam->state & DEV_MISCONFIGURED) { | ||
1903 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1904 | "again."); | ||
1905 | mutex_unlock(&cam->fileop_mutex); | ||
1906 | return -EIO; | ||
1907 | } | ||
1908 | |||
1909 | if (cam->io == IO_MMAP) { | ||
1910 | DBG(3, "Close and open the device again to choose " | ||
1911 | "the read method"); | ||
1912 | mutex_unlock(&cam->fileop_mutex); | ||
1913 | return -EBUSY; | ||
1914 | } | ||
1915 | |||
1916 | if (cam->io == IO_NONE) { | ||
1917 | if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { | ||
1918 | DBG(1, "read() failed, not enough memory"); | ||
1919 | mutex_unlock(&cam->fileop_mutex); | ||
1920 | return -ENOMEM; | ||
1921 | } | ||
1922 | cam->io = IO_READ; | ||
1923 | cam->stream = STREAM_ON; | ||
1924 | } | ||
1925 | |||
1926 | if (list_empty(&cam->inqueue)) { | ||
1927 | if (!list_empty(&cam->outqueue)) | ||
1928 | sn9c102_empty_framequeues(cam); | ||
1929 | sn9c102_queue_unusedframes(cam); | ||
1930 | } | ||
1931 | |||
1932 | if (!count) { | ||
1933 | mutex_unlock(&cam->fileop_mutex); | ||
1934 | return 0; | ||
1935 | } | ||
1936 | |||
1937 | if (list_empty(&cam->outqueue)) { | ||
1938 | if (filp->f_flags & O_NONBLOCK) { | ||
1939 | mutex_unlock(&cam->fileop_mutex); | ||
1940 | return -EAGAIN; | ||
1941 | } | ||
1942 | if (!cam->module_param.frame_timeout) { | ||
1943 | err = wait_event_interruptible | ||
1944 | ( cam->wait_frame, | ||
1945 | (!list_empty(&cam->outqueue)) || | ||
1946 | (cam->state & DEV_DISCONNECTED) || | ||
1947 | (cam->state & DEV_MISCONFIGURED) ); | ||
1948 | if (err) { | ||
1949 | mutex_unlock(&cam->fileop_mutex); | ||
1950 | return err; | ||
1951 | } | ||
1952 | } else { | ||
1953 | timeout = wait_event_interruptible_timeout | ||
1954 | ( cam->wait_frame, | ||
1955 | (!list_empty(&cam->outqueue)) || | ||
1956 | (cam->state & DEV_DISCONNECTED) || | ||
1957 | (cam->state & DEV_MISCONFIGURED), | ||
1958 | msecs_to_jiffies( | ||
1959 | cam->module_param.frame_timeout * 1000 | ||
1960 | ) | ||
1961 | ); | ||
1962 | if (timeout < 0) { | ||
1963 | mutex_unlock(&cam->fileop_mutex); | ||
1964 | return timeout; | ||
1965 | } else if (timeout == 0 && | ||
1966 | !(cam->state & DEV_DISCONNECTED)) { | ||
1967 | DBG(1, "Video frame timeout elapsed"); | ||
1968 | mutex_unlock(&cam->fileop_mutex); | ||
1969 | return -EIO; | ||
1970 | } | ||
1971 | } | ||
1972 | if (cam->state & DEV_DISCONNECTED) { | ||
1973 | mutex_unlock(&cam->fileop_mutex); | ||
1974 | return -ENODEV; | ||
1975 | } | ||
1976 | if (cam->state & DEV_MISCONFIGURED) { | ||
1977 | mutex_unlock(&cam->fileop_mutex); | ||
1978 | return -EIO; | ||
1979 | } | ||
1980 | } | ||
1981 | |||
1982 | f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); | ||
1983 | |||
1984 | if (count > f->buf.bytesused) | ||
1985 | count = f->buf.bytesused; | ||
1986 | |||
1987 | if (copy_to_user(buf, f->bufmem, count)) { | ||
1988 | err = -EFAULT; | ||
1989 | goto exit; | ||
1990 | } | ||
1991 | *f_pos += count; | ||
1992 | |||
1993 | exit: | ||
1994 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1995 | list_for_each_entry(i, &cam->outqueue, frame) | ||
1996 | i->state = F_UNUSED; | ||
1997 | INIT_LIST_HEAD(&cam->outqueue); | ||
1998 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1999 | |||
2000 | sn9c102_queue_unusedframes(cam); | ||
2001 | |||
2002 | PDBGG("Frame #%lu, bytes read: %zu", | ||
2003 | (unsigned long)f->buf.index, count); | ||
2004 | |||
2005 | mutex_unlock(&cam->fileop_mutex); | ||
2006 | |||
2007 | return count; | ||
2008 | } | ||
2009 | |||
2010 | |||
2011 | static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) | ||
2012 | { | ||
2013 | struct sn9c102_device *cam = video_drvdata(filp); | ||
2014 | struct sn9c102_frame_t* f; | ||
2015 | unsigned long lock_flags; | ||
2016 | unsigned int mask = 0; | ||
2017 | |||
2018 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
2019 | return POLLERR; | ||
2020 | |||
2021 | if (cam->state & DEV_DISCONNECTED) { | ||
2022 | DBG(1, "Device not present"); | ||
2023 | goto error; | ||
2024 | } | ||
2025 | |||
2026 | if (cam->state & DEV_MISCONFIGURED) { | ||
2027 | DBG(1, "The camera is misconfigured. Close and open it " | ||
2028 | "again."); | ||
2029 | goto error; | ||
2030 | } | ||
2031 | |||
2032 | if (cam->io == IO_NONE) { | ||
2033 | if (!sn9c102_request_buffers(cam, cam->nreadbuffers, | ||
2034 | IO_READ)) { | ||
2035 | DBG(1, "poll() failed, not enough memory"); | ||
2036 | goto error; | ||
2037 | } | ||
2038 | cam->io = IO_READ; | ||
2039 | cam->stream = STREAM_ON; | ||
2040 | } | ||
2041 | |||
2042 | if (cam->io == IO_READ) { | ||
2043 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2044 | list_for_each_entry(f, &cam->outqueue, frame) | ||
2045 | f->state = F_UNUSED; | ||
2046 | INIT_LIST_HEAD(&cam->outqueue); | ||
2047 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2048 | sn9c102_queue_unusedframes(cam); | ||
2049 | } | ||
2050 | |||
2051 | poll_wait(filp, &cam->wait_frame, wait); | ||
2052 | |||
2053 | if (!list_empty(&cam->outqueue)) | ||
2054 | mask |= POLLIN | POLLRDNORM; | ||
2055 | |||
2056 | mutex_unlock(&cam->fileop_mutex); | ||
2057 | |||
2058 | return mask; | ||
2059 | |||
2060 | error: | ||
2061 | mutex_unlock(&cam->fileop_mutex); | ||
2062 | return POLLERR; | ||
2063 | } | ||
2064 | |||
2065 | |||
2066 | static void sn9c102_vm_open(struct vm_area_struct* vma) | ||
2067 | { | ||
2068 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
2069 | f->vma_use_count++; | ||
2070 | } | ||
2071 | |||
2072 | |||
2073 | static void sn9c102_vm_close(struct vm_area_struct* vma) | ||
2074 | { | ||
2075 | /* NOTE: buffers are not freed here */ | ||
2076 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
2077 | f->vma_use_count--; | ||
2078 | } | ||
2079 | |||
2080 | |||
2081 | static const struct vm_operations_struct sn9c102_vm_ops = { | ||
2082 | .open = sn9c102_vm_open, | ||
2083 | .close = sn9c102_vm_close, | ||
2084 | }; | ||
2085 | |||
2086 | |||
2087 | static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) | ||
2088 | { | ||
2089 | struct sn9c102_device *cam = video_drvdata(filp); | ||
2090 | unsigned long size = vma->vm_end - vma->vm_start, | ||
2091 | start = vma->vm_start; | ||
2092 | void *pos; | ||
2093 | u32 i; | ||
2094 | |||
2095 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
2096 | return -ERESTARTSYS; | ||
2097 | |||
2098 | if (cam->state & DEV_DISCONNECTED) { | ||
2099 | DBG(1, "Device not present"); | ||
2100 | mutex_unlock(&cam->fileop_mutex); | ||
2101 | return -ENODEV; | ||
2102 | } | ||
2103 | |||
2104 | if (cam->state & DEV_MISCONFIGURED) { | ||
2105 | DBG(1, "The camera is misconfigured. Close and open it " | ||
2106 | "again."); | ||
2107 | mutex_unlock(&cam->fileop_mutex); | ||
2108 | return -EIO; | ||
2109 | } | ||
2110 | |||
2111 | if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { | ||
2112 | mutex_unlock(&cam->fileop_mutex); | ||
2113 | return -EACCES; | ||
2114 | } | ||
2115 | |||
2116 | if (cam->io != IO_MMAP || | ||
2117 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
2118 | mutex_unlock(&cam->fileop_mutex); | ||
2119 | return -EINVAL; | ||
2120 | } | ||
2121 | |||
2122 | for (i = 0; i < cam->nbuffers; i++) { | ||
2123 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
2124 | break; | ||
2125 | } | ||
2126 | if (i == cam->nbuffers) { | ||
2127 | mutex_unlock(&cam->fileop_mutex); | ||
2128 | return -EINVAL; | ||
2129 | } | ||
2130 | |||
2131 | vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; | ||
2132 | |||
2133 | pos = cam->frame[i].bufmem; | ||
2134 | while (size > 0) { /* size is page-aligned */ | ||
2135 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | ||
2136 | mutex_unlock(&cam->fileop_mutex); | ||
2137 | return -EAGAIN; | ||
2138 | } | ||
2139 | start += PAGE_SIZE; | ||
2140 | pos += PAGE_SIZE; | ||
2141 | size -= PAGE_SIZE; | ||
2142 | } | ||
2143 | |||
2144 | vma->vm_ops = &sn9c102_vm_ops; | ||
2145 | vma->vm_private_data = &cam->frame[i]; | ||
2146 | sn9c102_vm_open(vma); | ||
2147 | |||
2148 | mutex_unlock(&cam->fileop_mutex); | ||
2149 | |||
2150 | return 0; | ||
2151 | } | ||
2152 | |||
2153 | /*****************************************************************************/ | ||
2154 | |||
2155 | static int | ||
2156 | sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) | ||
2157 | { | ||
2158 | struct v4l2_capability cap = { | ||
2159 | .driver = "sn9c102", | ||
2160 | .version = LINUX_VERSION_CODE, | ||
2161 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
2162 | V4L2_CAP_STREAMING, | ||
2163 | }; | ||
2164 | |||
2165 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
2166 | if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) | ||
2167 | strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), | ||
2168 | sizeof(cap.bus_info)); | ||
2169 | |||
2170 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
2171 | return -EFAULT; | ||
2172 | |||
2173 | return 0; | ||
2174 | } | ||
2175 | |||
2176 | |||
2177 | static int | ||
2178 | sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) | ||
2179 | { | ||
2180 | struct v4l2_input i; | ||
2181 | |||
2182 | if (copy_from_user(&i, arg, sizeof(i))) | ||
2183 | return -EFAULT; | ||
2184 | |||
2185 | if (i.index) | ||
2186 | return -EINVAL; | ||
2187 | |||
2188 | memset(&i, 0, sizeof(i)); | ||
2189 | strcpy(i.name, "Camera"); | ||
2190 | i.type = V4L2_INPUT_TYPE_CAMERA; | ||
2191 | i.capabilities = V4L2_IN_CAP_STD; | ||
2192 | |||
2193 | if (copy_to_user(arg, &i, sizeof(i))) | ||
2194 | return -EFAULT; | ||
2195 | |||
2196 | return 0; | ||
2197 | } | ||
2198 | |||
2199 | |||
2200 | static int | ||
2201 | sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg) | ||
2202 | { | ||
2203 | int index = 0; | ||
2204 | |||
2205 | if (copy_to_user(arg, &index, sizeof(index))) | ||
2206 | return -EFAULT; | ||
2207 | |||
2208 | return 0; | ||
2209 | } | ||
2210 | |||
2211 | |||
2212 | static int | ||
2213 | sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg) | ||
2214 | { | ||
2215 | int index; | ||
2216 | |||
2217 | if (copy_from_user(&index, arg, sizeof(index))) | ||
2218 | return -EFAULT; | ||
2219 | |||
2220 | if (index != 0) | ||
2221 | return -EINVAL; | ||
2222 | |||
2223 | return 0; | ||
2224 | } | ||
2225 | |||
2226 | |||
2227 | static int | ||
2228 | sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
2229 | { | ||
2230 | struct sn9c102_sensor* s = &cam->sensor; | ||
2231 | struct v4l2_queryctrl qc; | ||
2232 | u8 i; | ||
2233 | |||
2234 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
2235 | return -EFAULT; | ||
2236 | |||
2237 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
2238 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
2239 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
2240 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
2241 | return -EFAULT; | ||
2242 | return 0; | ||
2243 | } | ||
2244 | |||
2245 | return -EINVAL; | ||
2246 | } | ||
2247 | |||
2248 | |||
2249 | static int | ||
2250 | sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
2251 | { | ||
2252 | struct sn9c102_sensor* s = &cam->sensor; | ||
2253 | struct v4l2_control ctrl; | ||
2254 | int err = 0; | ||
2255 | u8 i; | ||
2256 | |||
2257 | if (!s->get_ctrl && !s->set_ctrl) | ||
2258 | return -EINVAL; | ||
2259 | |||
2260 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
2261 | return -EFAULT; | ||
2262 | |||
2263 | if (!s->get_ctrl) { | ||
2264 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
2265 | if (ctrl.id && ctrl.id == s->qctrl[i].id) { | ||
2266 | ctrl.value = s->_qctrl[i].default_value; | ||
2267 | goto exit; | ||
2268 | } | ||
2269 | return -EINVAL; | ||
2270 | } else | ||
2271 | err = s->get_ctrl(cam, &ctrl); | ||
2272 | |||
2273 | exit: | ||
2274 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
2275 | return -EFAULT; | ||
2276 | |||
2277 | PDBGG("VIDIOC_G_CTRL: id %lu, value %lu", | ||
2278 | (unsigned long)ctrl.id, (unsigned long)ctrl.value); | ||
2279 | |||
2280 | return err; | ||
2281 | } | ||
2282 | |||
2283 | |||
2284 | static int | ||
2285 | sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
2286 | { | ||
2287 | struct sn9c102_sensor* s = &cam->sensor; | ||
2288 | struct v4l2_control ctrl; | ||
2289 | u8 i; | ||
2290 | int err = 0; | ||
2291 | |||
2292 | if (!s->set_ctrl) | ||
2293 | return -EINVAL; | ||
2294 | |||
2295 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
2296 | return -EFAULT; | ||
2297 | |||
2298 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) { | ||
2299 | if (ctrl.id == s->qctrl[i].id) { | ||
2300 | if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) | ||
2301 | return -EINVAL; | ||
2302 | if (ctrl.value < s->qctrl[i].minimum || | ||
2303 | ctrl.value > s->qctrl[i].maximum) | ||
2304 | return -ERANGE; | ||
2305 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
2306 | break; | ||
2307 | } | ||
2308 | } | ||
2309 | if (i == ARRAY_SIZE(s->qctrl)) | ||
2310 | return -EINVAL; | ||
2311 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
2312 | return err; | ||
2313 | |||
2314 | s->_qctrl[i].default_value = ctrl.value; | ||
2315 | |||
2316 | PDBGG("VIDIOC_S_CTRL: id %lu, value %lu", | ||
2317 | (unsigned long)ctrl.id, (unsigned long)ctrl.value); | ||
2318 | |||
2319 | return 0; | ||
2320 | } | ||
2321 | |||
2322 | |||
2323 | static int | ||
2324 | sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) | ||
2325 | { | ||
2326 | struct v4l2_cropcap* cc = &(cam->sensor.cropcap); | ||
2327 | |||
2328 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
2329 | cc->pixelaspect.numerator = 1; | ||
2330 | cc->pixelaspect.denominator = 1; | ||
2331 | |||
2332 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
2333 | return -EFAULT; | ||
2334 | |||
2335 | return 0; | ||
2336 | } | ||
2337 | |||
2338 | |||
2339 | static int | ||
2340 | sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) | ||
2341 | { | ||
2342 | struct sn9c102_sensor* s = &cam->sensor; | ||
2343 | struct v4l2_crop crop = { | ||
2344 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
2345 | }; | ||
2346 | |||
2347 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
2348 | |||
2349 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
2350 | return -EFAULT; | ||
2351 | |||
2352 | return 0; | ||
2353 | } | ||
2354 | |||
2355 | |||
2356 | static int | ||
2357 | sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | ||
2358 | { | ||
2359 | struct sn9c102_sensor* s = &cam->sensor; | ||
2360 | struct v4l2_crop crop; | ||
2361 | struct v4l2_rect* rect; | ||
2362 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
2363 | struct v4l2_pix_format* pix_format = &(s->pix_format); | ||
2364 | u8 scale; | ||
2365 | const enum sn9c102_stream_state stream = cam->stream; | ||
2366 | const u32 nbuffers = cam->nbuffers; | ||
2367 | u32 i; | ||
2368 | int err = 0; | ||
2369 | |||
2370 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
2371 | return -EFAULT; | ||
2372 | |||
2373 | rect = &(crop.c); | ||
2374 | |||
2375 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2376 | return -EINVAL; | ||
2377 | |||
2378 | if (cam->module_param.force_munmap) | ||
2379 | for (i = 0; i < cam->nbuffers; i++) | ||
2380 | if (cam->frame[i].vma_use_count) { | ||
2381 | DBG(3, "VIDIOC_S_CROP failed. " | ||
2382 | "Unmap the buffers first."); | ||
2383 | return -EBUSY; | ||
2384 | } | ||
2385 | |||
2386 | /* Preserve R,G or B origin */ | ||
2387 | rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; | ||
2388 | rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; | ||
2389 | |||
2390 | if (rect->width < 16) | ||
2391 | rect->width = 16; | ||
2392 | if (rect->height < 16) | ||
2393 | rect->height = 16; | ||
2394 | if (rect->width > bounds->width) | ||
2395 | rect->width = bounds->width; | ||
2396 | if (rect->height > bounds->height) | ||
2397 | rect->height = bounds->height; | ||
2398 | if (rect->left < bounds->left) | ||
2399 | rect->left = bounds->left; | ||
2400 | if (rect->top < bounds->top) | ||
2401 | rect->top = bounds->top; | ||
2402 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
2403 | rect->left = bounds->left+bounds->width - rect->width; | ||
2404 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
2405 | rect->top = bounds->top+bounds->height - rect->height; | ||
2406 | |||
2407 | rect->width &= ~15L; | ||
2408 | rect->height &= ~15L; | ||
2409 | |||
2410 | if (SN9C102_PRESERVE_IMGSCALE) { | ||
2411 | /* Calculate the actual scaling factor */ | ||
2412 | u32 a, b; | ||
2413 | a = rect->width * rect->height; | ||
2414 | b = pix_format->width * pix_format->height; | ||
2415 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
2416 | } else | ||
2417 | scale = 1; | ||
2418 | |||
2419 | if (cam->stream == STREAM_ON) | ||
2420 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2421 | return err; | ||
2422 | |||
2423 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
2424 | cam->stream = stream; | ||
2425 | return -EFAULT; | ||
2426 | } | ||
2427 | |||
2428 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
2429 | sn9c102_release_buffers(cam); | ||
2430 | |||
2431 | err = sn9c102_set_crop(cam, rect); | ||
2432 | if (s->set_crop) | ||
2433 | err += s->set_crop(cam, rect); | ||
2434 | err += sn9c102_set_scale(cam, scale); | ||
2435 | |||
2436 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2437 | cam->state |= DEV_MISCONFIGURED; | ||
2438 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | ||
2439 | "use the camera, close and open %s again.", | ||
2440 | video_device_node_name(cam->v4ldev)); | ||
2441 | return -EIO; | ||
2442 | } | ||
2443 | |||
2444 | s->pix_format.width = rect->width/scale; | ||
2445 | s->pix_format.height = rect->height/scale; | ||
2446 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
2447 | |||
2448 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
2449 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | ||
2450 | cam->state |= DEV_MISCONFIGURED; | ||
2451 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | ||
2452 | "use the camera, close and open %s again.", | ||
2453 | video_device_node_name(cam->v4ldev)); | ||
2454 | return -ENOMEM; | ||
2455 | } | ||
2456 | |||
2457 | if (cam->io == IO_READ) | ||
2458 | sn9c102_empty_framequeues(cam); | ||
2459 | else if (cam->module_param.force_munmap) | ||
2460 | sn9c102_requeue_outqueue(cam); | ||
2461 | |||
2462 | cam->stream = stream; | ||
2463 | |||
2464 | return 0; | ||
2465 | } | ||
2466 | |||
2467 | |||
2468 | static int | ||
2469 | sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg) | ||
2470 | { | ||
2471 | struct v4l2_frmsizeenum frmsize; | ||
2472 | |||
2473 | if (copy_from_user(&frmsize, arg, sizeof(frmsize))) | ||
2474 | return -EFAULT; | ||
2475 | |||
2476 | if (frmsize.index != 0) | ||
2477 | return -EINVAL; | ||
2478 | |||
2479 | switch (cam->bridge) { | ||
2480 | case BRIDGE_SN9C101: | ||
2481 | case BRIDGE_SN9C102: | ||
2482 | case BRIDGE_SN9C103: | ||
2483 | if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X && | ||
2484 | frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) | ||
2485 | return -EINVAL; | ||
2486 | break; | ||
2487 | case BRIDGE_SN9C105: | ||
2488 | case BRIDGE_SN9C120: | ||
2489 | if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG && | ||
2490 | frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) | ||
2491 | return -EINVAL; | ||
2492 | break; | ||
2493 | } | ||
2494 | |||
2495 | frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE; | ||
2496 | frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16; | ||
2497 | frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16; | ||
2498 | frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width; | ||
2499 | frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height; | ||
2500 | memset(&frmsize.reserved, 0, sizeof(frmsize.reserved)); | ||
2501 | |||
2502 | if (copy_to_user(arg, &frmsize, sizeof(frmsize))) | ||
2503 | return -EFAULT; | ||
2504 | |||
2505 | return 0; | ||
2506 | } | ||
2507 | |||
2508 | |||
2509 | static int | ||
2510 | sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) | ||
2511 | { | ||
2512 | struct v4l2_fmtdesc fmtd; | ||
2513 | |||
2514 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
2515 | return -EFAULT; | ||
2516 | |||
2517 | if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2518 | return -EINVAL; | ||
2519 | |||
2520 | if (fmtd.index == 0) { | ||
2521 | strcpy(fmtd.description, "bayer rgb"); | ||
2522 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
2523 | } else if (fmtd.index == 1) { | ||
2524 | switch (cam->bridge) { | ||
2525 | case BRIDGE_SN9C101: | ||
2526 | case BRIDGE_SN9C102: | ||
2527 | case BRIDGE_SN9C103: | ||
2528 | strcpy(fmtd.description, "compressed"); | ||
2529 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; | ||
2530 | break; | ||
2531 | case BRIDGE_SN9C105: | ||
2532 | case BRIDGE_SN9C120: | ||
2533 | strcpy(fmtd.description, "JPEG"); | ||
2534 | fmtd.pixelformat = V4L2_PIX_FMT_JPEG; | ||
2535 | break; | ||
2536 | } | ||
2537 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
2538 | } else | ||
2539 | return -EINVAL; | ||
2540 | |||
2541 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
2542 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
2543 | |||
2544 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
2545 | return -EFAULT; | ||
2546 | |||
2547 | return 0; | ||
2548 | } | ||
2549 | |||
2550 | |||
2551 | static int | ||
2552 | sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) | ||
2553 | { | ||
2554 | struct v4l2_format format; | ||
2555 | struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); | ||
2556 | |||
2557 | if (copy_from_user(&format, arg, sizeof(format))) | ||
2558 | return -EFAULT; | ||
2559 | |||
2560 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2561 | return -EINVAL; | ||
2562 | |||
2563 | pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? | ||
2564 | V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; | ||
2565 | pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X || | ||
2566 | pfmt->pixelformat == V4L2_PIX_FMT_JPEG) | ||
2567 | ? 0 : (pfmt->width * pfmt->priv) / 8; | ||
2568 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
2569 | pfmt->field = V4L2_FIELD_NONE; | ||
2570 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
2571 | |||
2572 | if (copy_to_user(arg, &format, sizeof(format))) | ||
2573 | return -EFAULT; | ||
2574 | |||
2575 | return 0; | ||
2576 | } | ||
2577 | |||
2578 | |||
2579 | static int | ||
2580 | sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | ||
2581 | void __user * arg) | ||
2582 | { | ||
2583 | struct sn9c102_sensor* s = &cam->sensor; | ||
2584 | struct v4l2_format format; | ||
2585 | struct v4l2_pix_format* pix; | ||
2586 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
2587 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
2588 | struct v4l2_rect rect; | ||
2589 | u8 scale; | ||
2590 | const enum sn9c102_stream_state stream = cam->stream; | ||
2591 | const u32 nbuffers = cam->nbuffers; | ||
2592 | u32 i; | ||
2593 | int err = 0; | ||
2594 | |||
2595 | if (copy_from_user(&format, arg, sizeof(format))) | ||
2596 | return -EFAULT; | ||
2597 | |||
2598 | pix = &(format.fmt.pix); | ||
2599 | |||
2600 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2601 | return -EINVAL; | ||
2602 | |||
2603 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
2604 | |||
2605 | { /* calculate the actual scaling factor */ | ||
2606 | u32 a, b; | ||
2607 | a = rect.width * rect.height; | ||
2608 | b = pix->width * pix->height; | ||
2609 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
2610 | } | ||
2611 | |||
2612 | rect.width = scale * pix->width; | ||
2613 | rect.height = scale * pix->height; | ||
2614 | |||
2615 | if (rect.width < 16) | ||
2616 | rect.width = 16; | ||
2617 | if (rect.height < 16) | ||
2618 | rect.height = 16; | ||
2619 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
2620 | rect.width = bounds->left + bounds->width - rect.left; | ||
2621 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
2622 | rect.height = bounds->top + bounds->height - rect.top; | ||
2623 | |||
2624 | rect.width &= ~15L; | ||
2625 | rect.height &= ~15L; | ||
2626 | |||
2627 | { /* adjust the scaling factor */ | ||
2628 | u32 a, b; | ||
2629 | a = rect.width * rect.height; | ||
2630 | b = pix->width * pix->height; | ||
2631 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
2632 | } | ||
2633 | |||
2634 | pix->width = rect.width / scale; | ||
2635 | pix->height = rect.height / scale; | ||
2636 | |||
2637 | switch (cam->bridge) { | ||
2638 | case BRIDGE_SN9C101: | ||
2639 | case BRIDGE_SN9C102: | ||
2640 | case BRIDGE_SN9C103: | ||
2641 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && | ||
2642 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
2643 | pix->pixelformat = pfmt->pixelformat; | ||
2644 | break; | ||
2645 | case BRIDGE_SN9C105: | ||
2646 | case BRIDGE_SN9C120: | ||
2647 | if (pix->pixelformat != V4L2_PIX_FMT_JPEG && | ||
2648 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
2649 | pix->pixelformat = pfmt->pixelformat; | ||
2650 | break; | ||
2651 | } | ||
2652 | pix->priv = pfmt->priv; /* bpp */ | ||
2653 | pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ? | ||
2654 | V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; | ||
2655 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || | ||
2656 | pix->pixelformat == V4L2_PIX_FMT_JPEG) | ||
2657 | ? 0 : (pix->width * pix->priv) / 8; | ||
2658 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
2659 | pix->field = V4L2_FIELD_NONE; | ||
2660 | |||
2661 | if (cmd == VIDIOC_TRY_FMT) { | ||
2662 | if (copy_to_user(arg, &format, sizeof(format))) | ||
2663 | return -EFAULT; | ||
2664 | return 0; | ||
2665 | } | ||
2666 | |||
2667 | if (cam->module_param.force_munmap) | ||
2668 | for (i = 0; i < cam->nbuffers; i++) | ||
2669 | if (cam->frame[i].vma_use_count) { | ||
2670 | DBG(3, "VIDIOC_S_FMT failed. Unmap the " | ||
2671 | "buffers first."); | ||
2672 | return -EBUSY; | ||
2673 | } | ||
2674 | |||
2675 | if (cam->stream == STREAM_ON) | ||
2676 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2677 | return err; | ||
2678 | |||
2679 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
2680 | cam->stream = stream; | ||
2681 | return -EFAULT; | ||
2682 | } | ||
2683 | |||
2684 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
2685 | sn9c102_release_buffers(cam); | ||
2686 | |||
2687 | err += sn9c102_set_pix_format(cam, pix); | ||
2688 | err += sn9c102_set_crop(cam, &rect); | ||
2689 | if (s->set_pix_format) | ||
2690 | err += s->set_pix_format(cam, pix); | ||
2691 | if (s->set_crop) | ||
2692 | err += s->set_crop(cam, &rect); | ||
2693 | err += sn9c102_set_scale(cam, scale); | ||
2694 | |||
2695 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2696 | cam->state |= DEV_MISCONFIGURED; | ||
2697 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | ||
2698 | "use the camera, close and open %s again.", | ||
2699 | video_device_node_name(cam->v4ldev)); | ||
2700 | return -EIO; | ||
2701 | } | ||
2702 | |||
2703 | memcpy(pfmt, pix, sizeof(*pix)); | ||
2704 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
2705 | |||
2706 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
2707 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | ||
2708 | cam->state |= DEV_MISCONFIGURED; | ||
2709 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | ||
2710 | "use the camera, close and open %s again.", | ||
2711 | video_device_node_name(cam->v4ldev)); | ||
2712 | return -ENOMEM; | ||
2713 | } | ||
2714 | |||
2715 | if (cam->io == IO_READ) | ||
2716 | sn9c102_empty_framequeues(cam); | ||
2717 | else if (cam->module_param.force_munmap) | ||
2718 | sn9c102_requeue_outqueue(cam); | ||
2719 | |||
2720 | cam->stream = stream; | ||
2721 | |||
2722 | return 0; | ||
2723 | } | ||
2724 | |||
2725 | |||
2726 | static int | ||
2727 | sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) | ||
2728 | { | ||
2729 | if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) | ||
2730 | return -EFAULT; | ||
2731 | |||
2732 | return 0; | ||
2733 | } | ||
2734 | |||
2735 | |||
2736 | static int | ||
2737 | sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) | ||
2738 | { | ||
2739 | struct v4l2_jpegcompression jc; | ||
2740 | const enum sn9c102_stream_state stream = cam->stream; | ||
2741 | int err = 0; | ||
2742 | |||
2743 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
2744 | return -EFAULT; | ||
2745 | |||
2746 | if (jc.quality != 0 && jc.quality != 1) | ||
2747 | return -EINVAL; | ||
2748 | |||
2749 | if (cam->stream == STREAM_ON) | ||
2750 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2751 | return err; | ||
2752 | |||
2753 | err += sn9c102_set_compression(cam, &jc); | ||
2754 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2755 | cam->state |= DEV_MISCONFIGURED; | ||
2756 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware problems. " | ||
2757 | "To use the camera, close and open %s again.", | ||
2758 | video_device_node_name(cam->v4ldev)); | ||
2759 | return -EIO; | ||
2760 | } | ||
2761 | |||
2762 | cam->compression.quality = jc.quality; | ||
2763 | |||
2764 | cam->stream = stream; | ||
2765 | |||
2766 | return 0; | ||
2767 | } | ||
2768 | |||
2769 | |||
2770 | static int | ||
2771 | sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) | ||
2772 | { | ||
2773 | struct v4l2_requestbuffers rb; | ||
2774 | u32 i; | ||
2775 | int err; | ||
2776 | |||
2777 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
2778 | return -EFAULT; | ||
2779 | |||
2780 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2781 | rb.memory != V4L2_MEMORY_MMAP) | ||
2782 | return -EINVAL; | ||
2783 | |||
2784 | if (cam->io == IO_READ) { | ||
2785 | DBG(3, "Close and open the device again to choose the mmap " | ||
2786 | "I/O method"); | ||
2787 | return -EBUSY; | ||
2788 | } | ||
2789 | |||
2790 | for (i = 0; i < cam->nbuffers; i++) | ||
2791 | if (cam->frame[i].vma_use_count) { | ||
2792 | DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " | ||
2793 | "still mapped."); | ||
2794 | return -EBUSY; | ||
2795 | } | ||
2796 | |||
2797 | if (cam->stream == STREAM_ON) | ||
2798 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2799 | return err; | ||
2800 | |||
2801 | sn9c102_empty_framequeues(cam); | ||
2802 | |||
2803 | sn9c102_release_buffers(cam); | ||
2804 | if (rb.count) | ||
2805 | rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP); | ||
2806 | |||
2807 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
2808 | sn9c102_release_buffers(cam); | ||
2809 | cam->io = IO_NONE; | ||
2810 | return -EFAULT; | ||
2811 | } | ||
2812 | |||
2813 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
2814 | |||
2815 | return 0; | ||
2816 | } | ||
2817 | |||
2818 | |||
2819 | static int | ||
2820 | sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg) | ||
2821 | { | ||
2822 | struct v4l2_buffer b; | ||
2823 | |||
2824 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2825 | return -EFAULT; | ||
2826 | |||
2827 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2828 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2829 | return -EINVAL; | ||
2830 | |||
2831 | b = cam->frame[b.index].buf; | ||
2832 | |||
2833 | if (cam->frame[b.index].vma_use_count) | ||
2834 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2835 | |||
2836 | if (cam->frame[b.index].state == F_DONE) | ||
2837 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
2838 | else if (cam->frame[b.index].state != F_UNUSED) | ||
2839 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
2840 | |||
2841 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2842 | return -EFAULT; | ||
2843 | |||
2844 | return 0; | ||
2845 | } | ||
2846 | |||
2847 | |||
2848 | static int | ||
2849 | sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg) | ||
2850 | { | ||
2851 | struct v4l2_buffer b; | ||
2852 | unsigned long lock_flags; | ||
2853 | |||
2854 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2855 | return -EFAULT; | ||
2856 | |||
2857 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2858 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2859 | return -EINVAL; | ||
2860 | |||
2861 | if (cam->frame[b.index].state != F_UNUSED) | ||
2862 | return -EINVAL; | ||
2863 | |||
2864 | cam->frame[b.index].state = F_QUEUED; | ||
2865 | |||
2866 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2867 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
2868 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2869 | |||
2870 | PDBGG("Frame #%lu queued", (unsigned long)b.index); | ||
2871 | |||
2872 | return 0; | ||
2873 | } | ||
2874 | |||
2875 | |||
2876 | static int | ||
2877 | sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | ||
2878 | void __user * arg) | ||
2879 | { | ||
2880 | struct v4l2_buffer b; | ||
2881 | struct sn9c102_frame_t *f; | ||
2882 | unsigned long lock_flags; | ||
2883 | long timeout; | ||
2884 | int err = 0; | ||
2885 | |||
2886 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2887 | return -EFAULT; | ||
2888 | |||
2889 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2890 | return -EINVAL; | ||
2891 | |||
2892 | if (list_empty(&cam->outqueue)) { | ||
2893 | if (cam->stream == STREAM_OFF) | ||
2894 | return -EINVAL; | ||
2895 | if (filp->f_flags & O_NONBLOCK) | ||
2896 | return -EAGAIN; | ||
2897 | if (!cam->module_param.frame_timeout) { | ||
2898 | err = wait_event_interruptible | ||
2899 | ( cam->wait_frame, | ||
2900 | (!list_empty(&cam->outqueue)) || | ||
2901 | (cam->state & DEV_DISCONNECTED) || | ||
2902 | (cam->state & DEV_MISCONFIGURED) ); | ||
2903 | if (err) | ||
2904 | return err; | ||
2905 | } else { | ||
2906 | timeout = wait_event_interruptible_timeout | ||
2907 | ( cam->wait_frame, | ||
2908 | (!list_empty(&cam->outqueue)) || | ||
2909 | (cam->state & DEV_DISCONNECTED) || | ||
2910 | (cam->state & DEV_MISCONFIGURED), | ||
2911 | cam->module_param.frame_timeout * | ||
2912 | 1000 * msecs_to_jiffies(1) ); | ||
2913 | if (timeout < 0) | ||
2914 | return timeout; | ||
2915 | else if (timeout == 0 && | ||
2916 | !(cam->state & DEV_DISCONNECTED)) { | ||
2917 | DBG(1, "Video frame timeout elapsed"); | ||
2918 | return -EIO; | ||
2919 | } | ||
2920 | } | ||
2921 | if (cam->state & DEV_DISCONNECTED) | ||
2922 | return -ENODEV; | ||
2923 | if (cam->state & DEV_MISCONFIGURED) | ||
2924 | return -EIO; | ||
2925 | } | ||
2926 | |||
2927 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2928 | f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); | ||
2929 | list_del(cam->outqueue.next); | ||
2930 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2931 | |||
2932 | f->state = F_UNUSED; | ||
2933 | |||
2934 | b = f->buf; | ||
2935 | if (f->vma_use_count) | ||
2936 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2937 | |||
2938 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2939 | return -EFAULT; | ||
2940 | |||
2941 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); | ||
2942 | |||
2943 | return 0; | ||
2944 | } | ||
2945 | |||
2946 | |||
2947 | static int | ||
2948 | sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) | ||
2949 | { | ||
2950 | int type; | ||
2951 | |||
2952 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2953 | return -EFAULT; | ||
2954 | |||
2955 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2956 | return -EINVAL; | ||
2957 | |||
2958 | cam->stream = STREAM_ON; | ||
2959 | |||
2960 | DBG(3, "Stream on"); | ||
2961 | |||
2962 | return 0; | ||
2963 | } | ||
2964 | |||
2965 | |||
2966 | static int | ||
2967 | sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg) | ||
2968 | { | ||
2969 | int type, err; | ||
2970 | |||
2971 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2972 | return -EFAULT; | ||
2973 | |||
2974 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2975 | return -EINVAL; | ||
2976 | |||
2977 | if (cam->stream == STREAM_ON) | ||
2978 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2979 | return err; | ||
2980 | |||
2981 | sn9c102_empty_framequeues(cam); | ||
2982 | |||
2983 | DBG(3, "Stream off"); | ||
2984 | |||
2985 | return 0; | ||
2986 | } | ||
2987 | |||
2988 | |||
2989 | static int | ||
2990 | sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg) | ||
2991 | { | ||
2992 | struct v4l2_streamparm sp; | ||
2993 | |||
2994 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
2995 | return -EFAULT; | ||
2996 | |||
2997 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2998 | return -EINVAL; | ||
2999 | |||
3000 | sp.parm.capture.extendedmode = 0; | ||
3001 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
3002 | |||
3003 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
3004 | return -EFAULT; | ||
3005 | |||
3006 | return 0; | ||
3007 | } | ||
3008 | |||
3009 | |||
3010 | static int | ||
3011 | sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg) | ||
3012 | { | ||
3013 | struct v4l2_streamparm sp; | ||
3014 | |||
3015 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
3016 | return -EFAULT; | ||
3017 | |||
3018 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
3019 | return -EINVAL; | ||
3020 | |||
3021 | sp.parm.capture.extendedmode = 0; | ||
3022 | |||
3023 | if (sp.parm.capture.readbuffers == 0) | ||
3024 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
3025 | |||
3026 | if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES) | ||
3027 | sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES; | ||
3028 | |||
3029 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
3030 | return -EFAULT; | ||
3031 | |||
3032 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
3033 | |||
3034 | return 0; | ||
3035 | } | ||
3036 | |||
3037 | |||
3038 | static int | ||
3039 | sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg) | ||
3040 | { | ||
3041 | struct v4l2_audio audio; | ||
3042 | |||
3043 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
3044 | return -EINVAL; | ||
3045 | |||
3046 | if (copy_from_user(&audio, arg, sizeof(audio))) | ||
3047 | return -EFAULT; | ||
3048 | |||
3049 | if (audio.index != 0) | ||
3050 | return -EINVAL; | ||
3051 | |||
3052 | strcpy(audio.name, "Microphone"); | ||
3053 | audio.capability = 0; | ||
3054 | audio.mode = 0; | ||
3055 | |||
3056 | if (copy_to_user(arg, &audio, sizeof(audio))) | ||
3057 | return -EFAULT; | ||
3058 | |||
3059 | return 0; | ||
3060 | } | ||
3061 | |||
3062 | |||
3063 | static int | ||
3064 | sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg) | ||
3065 | { | ||
3066 | struct v4l2_audio audio; | ||
3067 | |||
3068 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
3069 | return -EINVAL; | ||
3070 | |||
3071 | if (copy_from_user(&audio, arg, sizeof(audio))) | ||
3072 | return -EFAULT; | ||
3073 | |||
3074 | memset(&audio, 0, sizeof(audio)); | ||
3075 | strcpy(audio.name, "Microphone"); | ||
3076 | |||
3077 | if (copy_to_user(arg, &audio, sizeof(audio))) | ||
3078 | return -EFAULT; | ||
3079 | |||
3080 | return 0; | ||
3081 | } | ||
3082 | |||
3083 | |||
3084 | static int | ||
3085 | sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg) | ||
3086 | { | ||
3087 | struct v4l2_audio audio; | ||
3088 | |||
3089 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
3090 | return -EINVAL; | ||
3091 | |||
3092 | if (copy_from_user(&audio, arg, sizeof(audio))) | ||
3093 | return -EFAULT; | ||
3094 | |||
3095 | if (audio.index != 0) | ||
3096 | return -EINVAL; | ||
3097 | |||
3098 | return 0; | ||
3099 | } | ||
3100 | |||
3101 | |||
3102 | static long sn9c102_ioctl_v4l2(struct file *filp, | ||
3103 | unsigned int cmd, void __user *arg) | ||
3104 | { | ||
3105 | struct sn9c102_device *cam = video_drvdata(filp); | ||
3106 | |||
3107 | switch (cmd) { | ||
3108 | |||
3109 | case VIDIOC_QUERYCAP: | ||
3110 | return sn9c102_vidioc_querycap(cam, arg); | ||
3111 | |||
3112 | case VIDIOC_ENUMINPUT: | ||
3113 | return sn9c102_vidioc_enuminput(cam, arg); | ||
3114 | |||
3115 | case VIDIOC_G_INPUT: | ||
3116 | return sn9c102_vidioc_g_input(cam, arg); | ||
3117 | |||
3118 | case VIDIOC_S_INPUT: | ||
3119 | return sn9c102_vidioc_s_input(cam, arg); | ||
3120 | |||
3121 | case VIDIOC_QUERYCTRL: | ||
3122 | return sn9c102_vidioc_query_ctrl(cam, arg); | ||
3123 | |||
3124 | case VIDIOC_G_CTRL: | ||
3125 | return sn9c102_vidioc_g_ctrl(cam, arg); | ||
3126 | |||
3127 | case VIDIOC_S_CTRL: | ||
3128 | return sn9c102_vidioc_s_ctrl(cam, arg); | ||
3129 | |||
3130 | case VIDIOC_CROPCAP: | ||
3131 | return sn9c102_vidioc_cropcap(cam, arg); | ||
3132 | |||
3133 | case VIDIOC_G_CROP: | ||
3134 | return sn9c102_vidioc_g_crop(cam, arg); | ||
3135 | |||
3136 | case VIDIOC_S_CROP: | ||
3137 | return sn9c102_vidioc_s_crop(cam, arg); | ||
3138 | |||
3139 | case VIDIOC_ENUM_FRAMESIZES: | ||
3140 | return sn9c102_vidioc_enum_framesizes(cam, arg); | ||
3141 | |||
3142 | case VIDIOC_ENUM_FMT: | ||
3143 | return sn9c102_vidioc_enum_fmt(cam, arg); | ||
3144 | |||
3145 | case VIDIOC_G_FMT: | ||
3146 | return sn9c102_vidioc_g_fmt(cam, arg); | ||
3147 | |||
3148 | case VIDIOC_TRY_FMT: | ||
3149 | case VIDIOC_S_FMT: | ||
3150 | return sn9c102_vidioc_try_s_fmt(cam, cmd, arg); | ||
3151 | |||
3152 | case VIDIOC_G_JPEGCOMP: | ||
3153 | return sn9c102_vidioc_g_jpegcomp(cam, arg); | ||
3154 | |||
3155 | case VIDIOC_S_JPEGCOMP: | ||
3156 | return sn9c102_vidioc_s_jpegcomp(cam, arg); | ||
3157 | |||
3158 | case VIDIOC_REQBUFS: | ||
3159 | return sn9c102_vidioc_reqbufs(cam, arg); | ||
3160 | |||
3161 | case VIDIOC_QUERYBUF: | ||
3162 | return sn9c102_vidioc_querybuf(cam, arg); | ||
3163 | |||
3164 | case VIDIOC_QBUF: | ||
3165 | return sn9c102_vidioc_qbuf(cam, arg); | ||
3166 | |||
3167 | case VIDIOC_DQBUF: | ||
3168 | return sn9c102_vidioc_dqbuf(cam, filp, arg); | ||
3169 | |||
3170 | case VIDIOC_STREAMON: | ||
3171 | return sn9c102_vidioc_streamon(cam, arg); | ||
3172 | |||
3173 | case VIDIOC_STREAMOFF: | ||
3174 | return sn9c102_vidioc_streamoff(cam, arg); | ||
3175 | |||
3176 | case VIDIOC_G_PARM: | ||
3177 | return sn9c102_vidioc_g_parm(cam, arg); | ||
3178 | |||
3179 | case VIDIOC_S_PARM: | ||
3180 | return sn9c102_vidioc_s_parm(cam, arg); | ||
3181 | |||
3182 | case VIDIOC_ENUMAUDIO: | ||
3183 | return sn9c102_vidioc_enumaudio(cam, arg); | ||
3184 | |||
3185 | case VIDIOC_G_AUDIO: | ||
3186 | return sn9c102_vidioc_g_audio(cam, arg); | ||
3187 | |||
3188 | case VIDIOC_S_AUDIO: | ||
3189 | return sn9c102_vidioc_s_audio(cam, arg); | ||
3190 | |||
3191 | default: | ||
3192 | return -ENOTTY; | ||
3193 | |||
3194 | } | ||
3195 | } | ||
3196 | |||
3197 | |||
3198 | static long sn9c102_ioctl(struct file *filp, | ||
3199 | unsigned int cmd, unsigned long arg) | ||
3200 | { | ||
3201 | struct sn9c102_device *cam = video_drvdata(filp); | ||
3202 | int err = 0; | ||
3203 | |||
3204 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
3205 | return -ERESTARTSYS; | ||
3206 | |||
3207 | if (cam->state & DEV_DISCONNECTED) { | ||
3208 | DBG(1, "Device not present"); | ||
3209 | mutex_unlock(&cam->fileop_mutex); | ||
3210 | return -ENODEV; | ||
3211 | } | ||
3212 | |||
3213 | if (cam->state & DEV_MISCONFIGURED) { | ||
3214 | DBG(1, "The camera is misconfigured. Close and open it " | ||
3215 | "again."); | ||
3216 | mutex_unlock(&cam->fileop_mutex); | ||
3217 | return -EIO; | ||
3218 | } | ||
3219 | |||
3220 | V4LDBG(3, "sn9c102", cmd); | ||
3221 | |||
3222 | err = sn9c102_ioctl_v4l2(filp, cmd, (void __user *)arg); | ||
3223 | |||
3224 | mutex_unlock(&cam->fileop_mutex); | ||
3225 | |||
3226 | return err; | ||
3227 | } | ||
3228 | |||
3229 | /*****************************************************************************/ | ||
3230 | |||
3231 | static const struct v4l2_file_operations sn9c102_fops = { | ||
3232 | .owner = THIS_MODULE, | ||
3233 | .open = sn9c102_open, | ||
3234 | .release = sn9c102_release, | ||
3235 | .unlocked_ioctl = sn9c102_ioctl, | ||
3236 | .read = sn9c102_read, | ||
3237 | .poll = sn9c102_poll, | ||
3238 | .mmap = sn9c102_mmap, | ||
3239 | }; | ||
3240 | |||
3241 | /*****************************************************************************/ | ||
3242 | |||
3243 | /* It exists a single interface only. We do not need to validate anything. */ | ||
3244 | static int | ||
3245 | sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
3246 | { | ||
3247 | struct usb_device *udev = interface_to_usbdev(intf); | ||
3248 | struct sn9c102_device* cam; | ||
3249 | static unsigned int dev_nr; | ||
3250 | unsigned int i; | ||
3251 | int err = 0, r; | ||
3252 | |||
3253 | if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) | ||
3254 | return -ENOMEM; | ||
3255 | |||
3256 | cam->usbdev = udev; | ||
3257 | |||
3258 | /* register v4l2_device early so it can be used for printks */ | ||
3259 | if (v4l2_device_register(&intf->dev, &cam->v4l2_dev)) { | ||
3260 | dev_err(&intf->dev, "v4l2_device_register failed\n"); | ||
3261 | err = -ENOMEM; | ||
3262 | goto fail; | ||
3263 | } | ||
3264 | |||
3265 | if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { | ||
3266 | DBG(1, "kzalloc() failed"); | ||
3267 | err = -ENOMEM; | ||
3268 | goto fail; | ||
3269 | } | ||
3270 | |||
3271 | if (!(cam->v4ldev = video_device_alloc())) { | ||
3272 | DBG(1, "video_device_alloc() failed"); | ||
3273 | err = -ENOMEM; | ||
3274 | goto fail; | ||
3275 | } | ||
3276 | |||
3277 | r = sn9c102_read_reg(cam, 0x00); | ||
3278 | if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { | ||
3279 | DBG(1, "Sorry, this is not a SN9C1xx-based camera " | ||
3280 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | ||
3281 | err = -ENODEV; | ||
3282 | goto fail; | ||
3283 | } | ||
3284 | |||
3285 | cam->bridge = id->driver_info; | ||
3286 | switch (cam->bridge) { | ||
3287 | case BRIDGE_SN9C101: | ||
3288 | case BRIDGE_SN9C102: | ||
3289 | DBG(2, "SN9C10[12] PC Camera Controller detected " | ||
3290 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | ||
3291 | break; | ||
3292 | case BRIDGE_SN9C103: | ||
3293 | DBG(2, "SN9C103 PC Camera Controller detected " | ||
3294 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | ||
3295 | break; | ||
3296 | case BRIDGE_SN9C105: | ||
3297 | DBG(2, "SN9C105 PC Camera Controller detected " | ||
3298 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | ||
3299 | break; | ||
3300 | case BRIDGE_SN9C120: | ||
3301 | DBG(2, "SN9C120 PC Camera Controller detected " | ||
3302 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | ||
3303 | break; | ||
3304 | } | ||
3305 | |||
3306 | for (i = 0; i < ARRAY_SIZE(sn9c102_sensor_table); i++) { | ||
3307 | err = sn9c102_sensor_table[i](cam); | ||
3308 | if (!err) | ||
3309 | break; | ||
3310 | } | ||
3311 | |||
3312 | if (!err) { | ||
3313 | DBG(2, "%s image sensor detected", cam->sensor.name); | ||
3314 | DBG(3, "Support for %s maintained by %s", | ||
3315 | cam->sensor.name, cam->sensor.maintainer); | ||
3316 | } else { | ||
3317 | DBG(1, "No supported image sensor detected for this bridge"); | ||
3318 | err = -ENODEV; | ||
3319 | goto fail; | ||
3320 | } | ||
3321 | |||
3322 | if (!(cam->bridge & cam->sensor.supported_bridge)) { | ||
3323 | DBG(1, "Bridge not supported"); | ||
3324 | err = -ENODEV; | ||
3325 | goto fail; | ||
3326 | } | ||
3327 | |||
3328 | if (sn9c102_init(cam)) { | ||
3329 | DBG(1, "Initialization failed. I will retry on open()."); | ||
3330 | cam->state |= DEV_MISCONFIGURED; | ||
3331 | } | ||
3332 | |||
3333 | strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); | ||
3334 | cam->v4ldev->fops = &sn9c102_fops; | ||
3335 | cam->v4ldev->release = video_device_release; | ||
3336 | cam->v4ldev->v4l2_dev = &cam->v4l2_dev; | ||
3337 | |||
3338 | init_completion(&cam->probe); | ||
3339 | |||
3340 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
3341 | video_nr[dev_nr]); | ||
3342 | if (err) { | ||
3343 | DBG(1, "V4L2 device registration failed"); | ||
3344 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
3345 | DBG(1, "Free /dev/videoX node not found"); | ||
3346 | video_nr[dev_nr] = -1; | ||
3347 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
3348 | complete_all(&cam->probe); | ||
3349 | goto fail; | ||
3350 | } | ||
3351 | |||
3352 | DBG(2, "V4L2 device registered as %s", | ||
3353 | video_device_node_name(cam->v4ldev)); | ||
3354 | |||
3355 | video_set_drvdata(cam->v4ldev, cam); | ||
3356 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
3357 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | ||
3358 | |||
3359 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
3360 | |||
3361 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
3362 | err = sn9c102_create_sysfs(cam); | ||
3363 | if (!err) | ||
3364 | DBG(2, "Optional device control through 'sysfs' " | ||
3365 | "interface ready"); | ||
3366 | else | ||
3367 | DBG(2, "Failed to create optional 'sysfs' interface for " | ||
3368 | "device controlling. Error #%d", err); | ||
3369 | #else | ||
3370 | DBG(2, "Optional device control through 'sysfs' interface disabled"); | ||
3371 | DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " | ||
3372 | "configuration option to enable it."); | ||
3373 | #endif | ||
3374 | |||
3375 | usb_set_intfdata(intf, cam); | ||
3376 | kref_init(&cam->kref); | ||
3377 | usb_get_dev(cam->usbdev); | ||
3378 | |||
3379 | complete_all(&cam->probe); | ||
3380 | |||
3381 | return 0; | ||
3382 | |||
3383 | fail: | ||
3384 | if (cam) { | ||
3385 | kfree(cam->control_buffer); | ||
3386 | if (cam->v4ldev) | ||
3387 | video_device_release(cam->v4ldev); | ||
3388 | v4l2_device_unregister(&cam->v4l2_dev); | ||
3389 | kfree(cam); | ||
3390 | } | ||
3391 | return err; | ||
3392 | } | ||
3393 | |||
3394 | |||
3395 | static void sn9c102_usb_disconnect(struct usb_interface* intf) | ||
3396 | { | ||
3397 | struct sn9c102_device* cam; | ||
3398 | |||
3399 | down_write(&sn9c102_dev_lock); | ||
3400 | |||
3401 | cam = usb_get_intfdata(intf); | ||
3402 | |||
3403 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | ||
3404 | |||
3405 | if (cam->users) { | ||
3406 | DBG(2, "Device %s is open! Deregistration and memory " | ||
3407 | "deallocation are deferred.", | ||
3408 | video_device_node_name(cam->v4ldev)); | ||
3409 | cam->state |= DEV_MISCONFIGURED; | ||
3410 | sn9c102_stop_transfer(cam); | ||
3411 | cam->state |= DEV_DISCONNECTED; | ||
3412 | wake_up_interruptible(&cam->wait_frame); | ||
3413 | wake_up(&cam->wait_stream); | ||
3414 | } else | ||
3415 | cam->state |= DEV_DISCONNECTED; | ||
3416 | |||
3417 | wake_up_interruptible_all(&cam->wait_open); | ||
3418 | |||
3419 | v4l2_device_disconnect(&cam->v4l2_dev); | ||
3420 | |||
3421 | kref_put(&cam->kref, sn9c102_release_resources); | ||
3422 | |||
3423 | up_write(&sn9c102_dev_lock); | ||
3424 | } | ||
3425 | |||
3426 | |||
3427 | static struct usb_driver sn9c102_usb_driver = { | ||
3428 | .name = "sn9c102", | ||
3429 | .id_table = sn9c102_id_table, | ||
3430 | .probe = sn9c102_usb_probe, | ||
3431 | .disconnect = sn9c102_usb_disconnect, | ||
3432 | }; | ||
3433 | |||
3434 | module_usb_driver(sn9c102_usb_driver); | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_devtable.h b/drivers/media/usb/sn9c102/sn9c102_devtable.h deleted file mode 100644 index b3d2cc729657..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_devtable.h +++ /dev/null | |||
@@ -1,147 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Table of device identifiers of the SN9C1xx PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_DEVTABLE_H_ | ||
22 | #define _SN9C102_DEVTABLE_H_ | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | |||
26 | struct sn9c102_device; | ||
27 | |||
28 | /* | ||
29 | Each SN9C1xx camera has proper PID/VID identifiers. | ||
30 | SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to | ||
31 | handle the video class interface. | ||
32 | */ | ||
33 | #define SN9C102_USB_DEVICE(vend, prod, bridge) \ | ||
34 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
35 | USB_DEVICE_ID_MATCH_INT_CLASS, \ | ||
36 | .idVendor = (vend), \ | ||
37 | .idProduct = (prod), \ | ||
38 | .bInterfaceClass = 0xff, \ | ||
39 | .driver_info = (bridge) | ||
40 | |||
41 | static const struct usb_device_id sn9c102_id_table[] = { | ||
42 | /* SN9C101 and SN9C102 */ | ||
43 | #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE | ||
44 | { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), }, | ||
45 | { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), }, | ||
46 | { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), }, | ||
47 | { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, | ||
48 | { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, | ||
49 | /* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */ | ||
50 | { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, | ||
51 | #endif | ||
52 | { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, | ||
53 | { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, | ||
54 | #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE | ||
55 | { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), }, | ||
56 | { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, | ||
57 | { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, | ||
58 | #endif | ||
59 | { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */ | ||
60 | #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE | ||
61 | { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, | ||
62 | /* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ | ||
63 | { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, | ||
64 | #endif | ||
65 | { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */ | ||
66 | /* SN9C103 */ | ||
67 | /* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */ | ||
68 | { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */ | ||
69 | #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE | ||
70 | /* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */ | ||
71 | /* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */ | ||
72 | /* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */ | ||
73 | /* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */ | ||
74 | { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, | ||
75 | /* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */ | ||
76 | { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, | ||
77 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */ | ||
78 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */ | ||
79 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */ | ||
80 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */ | ||
81 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */ | ||
82 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */ | ||
83 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */ | ||
84 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */ | ||
85 | { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, | ||
86 | { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, | ||
87 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */ | ||
88 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */ | ||
89 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */ | ||
90 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */ | ||
91 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */ | ||
92 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */ | ||
93 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */ | ||
94 | #endif | ||
95 | /* SN9C105 */ | ||
96 | #if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE | ||
97 | { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, | ||
98 | { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), }, | ||
99 | { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, | ||
100 | { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, | ||
101 | { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, | ||
102 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */ | ||
103 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */ | ||
104 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */ | ||
105 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */ | ||
106 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */ | ||
107 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */ | ||
108 | /* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */ | ||
109 | { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, | ||
110 | { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, | ||
111 | { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, | ||
112 | /* SN9C120 */ | ||
113 | { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), }, | ||
114 | /* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */ | ||
115 | /* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */ | ||
116 | /* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */ | ||
117 | { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, | ||
118 | /* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ | ||
119 | { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, | ||
120 | { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, | ||
121 | { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, | ||
122 | { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, | ||
123 | #endif | ||
124 | { } | ||
125 | }; | ||
126 | |||
127 | /* | ||
128 | Probing functions: on success, you must attach the sensor to the camera | ||
129 | by calling sn9c102_attach_sensor(). | ||
130 | To enable the I2C communication, you might need to perform a really basic | ||
131 | initialization of the SN9C1XX chip. | ||
132 | Functions must return 0 on success, the appropriate error otherwise. | ||
133 | */ | ||
134 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); | ||
135 | extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); | ||
136 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); | ||
137 | extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); | ||
138 | extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam); | ||
139 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); | ||
140 | extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); | ||
141 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); | ||
142 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); | ||
143 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); | ||
144 | extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); | ||
145 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | ||
146 | |||
147 | #endif /* _SN9C102_DEVTABLE_H_ */ | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_hv7131d.c b/drivers/media/usb/sn9c102/sn9c102_hv7131d.c deleted file mode 100644 index 2dce5c908c8e..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_hv7131d.c +++ /dev/null | |||
@@ -1,264 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int hv7131d_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | int err; | ||
29 | |||
30 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, | ||
31 | {0x00, 0x14}, {0x60, 0x17}, | ||
32 | {0x0e, 0x18}, {0xf2, 0x19}); | ||
33 | |||
34 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
35 | err += sn9c102_i2c_write(cam, 0x02, 0x00); | ||
36 | err += sn9c102_i2c_write(cam, 0x28, 0x00); | ||
37 | |||
38 | return err; | ||
39 | } | ||
40 | |||
41 | |||
42 | static int hv7131d_get_ctrl(struct sn9c102_device* cam, | ||
43 | struct v4l2_control* ctrl) | ||
44 | { | ||
45 | switch (ctrl->id) { | ||
46 | case V4L2_CID_EXPOSURE: | ||
47 | { | ||
48 | int r1 = sn9c102_i2c_read(cam, 0x26), | ||
49 | r2 = sn9c102_i2c_read(cam, 0x27); | ||
50 | if (r1 < 0 || r2 < 0) | ||
51 | return -EIO; | ||
52 | ctrl->value = (r1 << 8) | (r2 & 0xff); | ||
53 | } | ||
54 | return 0; | ||
55 | case V4L2_CID_RED_BALANCE: | ||
56 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) | ||
57 | return -EIO; | ||
58 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
59 | return 0; | ||
60 | case V4L2_CID_BLUE_BALANCE: | ||
61 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) | ||
62 | return -EIO; | ||
63 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
64 | return 0; | ||
65 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
66 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) | ||
67 | return -EIO; | ||
68 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
69 | return 0; | ||
70 | case SN9C102_V4L2_CID_RESET_LEVEL: | ||
71 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) | ||
72 | return -EIO; | ||
73 | ctrl->value &= 0x3f; | ||
74 | return 0; | ||
75 | case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: | ||
76 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0) | ||
77 | return -EIO; | ||
78 | ctrl->value &= 0x07; | ||
79 | return 0; | ||
80 | default: | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | |||
86 | static int hv7131d_set_ctrl(struct sn9c102_device* cam, | ||
87 | const struct v4l2_control* ctrl) | ||
88 | { | ||
89 | int err = 0; | ||
90 | |||
91 | switch (ctrl->id) { | ||
92 | case V4L2_CID_EXPOSURE: | ||
93 | err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8); | ||
94 | err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff); | ||
95 | break; | ||
96 | case V4L2_CID_RED_BALANCE: | ||
97 | err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value); | ||
98 | break; | ||
99 | case V4L2_CID_BLUE_BALANCE: | ||
100 | err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value); | ||
101 | break; | ||
102 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
103 | err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value); | ||
104 | break; | ||
105 | case SN9C102_V4L2_CID_RESET_LEVEL: | ||
106 | err += sn9c102_i2c_write(cam, 0x30, ctrl->value); | ||
107 | break; | ||
108 | case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: | ||
109 | err += sn9c102_i2c_write(cam, 0x34, ctrl->value); | ||
110 | break; | ||
111 | default: | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | return err ? -EIO : 0; | ||
116 | } | ||
117 | |||
118 | |||
119 | static int hv7131d_set_crop(struct sn9c102_device* cam, | ||
120 | const struct v4l2_rect* rect) | ||
121 | { | ||
122 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
123 | int err = 0; | ||
124 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, | ||
125 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | ||
126 | |||
127 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
128 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
129 | |||
130 | return err; | ||
131 | } | ||
132 | |||
133 | |||
134 | static int hv7131d_set_pix_format(struct sn9c102_device* cam, | ||
135 | const struct v4l2_pix_format* pix) | ||
136 | { | ||
137 | int err = 0; | ||
138 | |||
139 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
140 | err += sn9c102_write_reg(cam, 0x42, 0x19); | ||
141 | else | ||
142 | err += sn9c102_write_reg(cam, 0xf2, 0x19); | ||
143 | |||
144 | return err; | ||
145 | } | ||
146 | |||
147 | |||
148 | static const struct sn9c102_sensor hv7131d = { | ||
149 | .name = "HV7131D", | ||
150 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
151 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
152 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
153 | .frequency = SN9C102_I2C_100KHZ, | ||
154 | .interface = SN9C102_I2C_2WIRES, | ||
155 | .i2c_slave_id = 0x11, | ||
156 | .init = &hv7131d_init, | ||
157 | .qctrl = { | ||
158 | { | ||
159 | .id = V4L2_CID_EXPOSURE, | ||
160 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
161 | .name = "exposure", | ||
162 | .minimum = 0x0250, | ||
163 | .maximum = 0xffff, | ||
164 | .step = 0x0001, | ||
165 | .default_value = 0x0250, | ||
166 | .flags = 0, | ||
167 | }, | ||
168 | { | ||
169 | .id = V4L2_CID_RED_BALANCE, | ||
170 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
171 | .name = "red balance", | ||
172 | .minimum = 0x00, | ||
173 | .maximum = 0x3f, | ||
174 | .step = 0x01, | ||
175 | .default_value = 0x00, | ||
176 | .flags = 0, | ||
177 | }, | ||
178 | { | ||
179 | .id = V4L2_CID_BLUE_BALANCE, | ||
180 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
181 | .name = "blue balance", | ||
182 | .minimum = 0x00, | ||
183 | .maximum = 0x3f, | ||
184 | .step = 0x01, | ||
185 | .default_value = 0x20, | ||
186 | .flags = 0, | ||
187 | }, | ||
188 | { | ||
189 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
190 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
191 | .name = "green balance", | ||
192 | .minimum = 0x00, | ||
193 | .maximum = 0x3f, | ||
194 | .step = 0x01, | ||
195 | .default_value = 0x1e, | ||
196 | .flags = 0, | ||
197 | }, | ||
198 | { | ||
199 | .id = SN9C102_V4L2_CID_RESET_LEVEL, | ||
200 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
201 | .name = "reset level", | ||
202 | .minimum = 0x19, | ||
203 | .maximum = 0x3f, | ||
204 | .step = 0x01, | ||
205 | .default_value = 0x30, | ||
206 | .flags = 0, | ||
207 | }, | ||
208 | { | ||
209 | .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE, | ||
210 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
211 | .name = "pixel bias voltage", | ||
212 | .minimum = 0x00, | ||
213 | .maximum = 0x07, | ||
214 | .step = 0x01, | ||
215 | .default_value = 0x02, | ||
216 | .flags = 0, | ||
217 | }, | ||
218 | }, | ||
219 | .get_ctrl = &hv7131d_get_ctrl, | ||
220 | .set_ctrl = &hv7131d_set_ctrl, | ||
221 | .cropcap = { | ||
222 | .bounds = { | ||
223 | .left = 0, | ||
224 | .top = 0, | ||
225 | .width = 640, | ||
226 | .height = 480, | ||
227 | }, | ||
228 | .defrect = { | ||
229 | .left = 0, | ||
230 | .top = 0, | ||
231 | .width = 640, | ||
232 | .height = 480, | ||
233 | }, | ||
234 | }, | ||
235 | .set_crop = &hv7131d_set_crop, | ||
236 | .pix_format = { | ||
237 | .width = 640, | ||
238 | .height = 480, | ||
239 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
240 | .priv = 8, | ||
241 | }, | ||
242 | .set_pix_format = &hv7131d_set_pix_format | ||
243 | }; | ||
244 | |||
245 | |||
246 | int sn9c102_probe_hv7131d(struct sn9c102_device* cam) | ||
247 | { | ||
248 | int r0 = 0, r1 = 0, err; | ||
249 | |||
250 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, | ||
251 | {0x28, 0x17}); | ||
252 | |||
253 | r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00); | ||
254 | r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01); | ||
255 | if (err || r0 < 0 || r1 < 0) | ||
256 | return -EIO; | ||
257 | |||
258 | if ((r0 != 0x00 && r0 != 0x01) || r1 != 0x04) | ||
259 | return -ENODEV; | ||
260 | |||
261 | sn9c102_attach_sensor(cam, &hv7131d); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_hv7131r.c b/drivers/media/usb/sn9c102/sn9c102_hv7131r.c deleted file mode 100644 index 4295887ff609..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_hv7131r.c +++ /dev/null | |||
@@ -1,363 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int hv7131r_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | int err = 0; | ||
29 | |||
30 | switch (sn9c102_get_bridge(cam)) { | ||
31 | case BRIDGE_SN9C103: | ||
32 | err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04}, | ||
33 | {0x20, 0x05}, {0x20, 0x06}, | ||
34 | {0x03, 0x10}, {0x00, 0x14}, | ||
35 | {0x60, 0x17}, {0x0a, 0x18}, | ||
36 | {0xf0, 0x19}, {0x1d, 0x1a}, | ||
37 | {0x10, 0x1b}, {0x02, 0x1c}, | ||
38 | {0x03, 0x1d}, {0x0f, 0x1e}, | ||
39 | {0x0c, 0x1f}, {0x00, 0x20}, | ||
40 | {0x10, 0x21}, {0x20, 0x22}, | ||
41 | {0x30, 0x23}, {0x40, 0x24}, | ||
42 | {0x50, 0x25}, {0x60, 0x26}, | ||
43 | {0x70, 0x27}, {0x80, 0x28}, | ||
44 | {0x90, 0x29}, {0xa0, 0x2a}, | ||
45 | {0xb0, 0x2b}, {0xc0, 0x2c}, | ||
46 | {0xd0, 0x2d}, {0xe0, 0x2e}, | ||
47 | {0xf0, 0x2f}, {0xff, 0x30}); | ||
48 | break; | ||
49 | case BRIDGE_SN9C105: | ||
50 | case BRIDGE_SN9C120: | ||
51 | err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, | ||
52 | {0x00, 0x03}, {0x1a, 0x04}, | ||
53 | {0x44, 0x05}, {0x3e, 0x06}, | ||
54 | {0x1a, 0x07}, {0x03, 0x10}, | ||
55 | {0x08, 0x14}, {0xa3, 0x17}, | ||
56 | {0x4b, 0x18}, {0x00, 0x19}, | ||
57 | {0x1d, 0x1a}, {0x10, 0x1b}, | ||
58 | {0x02, 0x1c}, {0x03, 0x1d}, | ||
59 | {0x0f, 0x1e}, {0x0c, 0x1f}, | ||
60 | {0x00, 0x20}, {0x29, 0x21}, | ||
61 | {0x40, 0x22}, {0x54, 0x23}, | ||
62 | {0x66, 0x24}, {0x76, 0x25}, | ||
63 | {0x85, 0x26}, {0x94, 0x27}, | ||
64 | {0xa1, 0x28}, {0xae, 0x29}, | ||
65 | {0xbb, 0x2a}, {0xc7, 0x2b}, | ||
66 | {0xd3, 0x2c}, {0xde, 0x2d}, | ||
67 | {0xea, 0x2e}, {0xf4, 0x2f}, | ||
68 | {0xff, 0x30}, {0x00, 0x3F}, | ||
69 | {0xC7, 0x40}, {0x01, 0x41}, | ||
70 | {0x44, 0x42}, {0x00, 0x43}, | ||
71 | {0x44, 0x44}, {0x00, 0x45}, | ||
72 | {0x44, 0x46}, {0x00, 0x47}, | ||
73 | {0xC7, 0x48}, {0x01, 0x49}, | ||
74 | {0xC7, 0x4A}, {0x01, 0x4B}, | ||
75 | {0xC7, 0x4C}, {0x01, 0x4D}, | ||
76 | {0x44, 0x4E}, {0x00, 0x4F}, | ||
77 | {0x44, 0x50}, {0x00, 0x51}, | ||
78 | {0x44, 0x52}, {0x00, 0x53}, | ||
79 | {0xC7, 0x54}, {0x01, 0x55}, | ||
80 | {0xC7, 0x56}, {0x01, 0x57}, | ||
81 | {0xC7, 0x58}, {0x01, 0x59}, | ||
82 | {0x44, 0x5A}, {0x00, 0x5B}, | ||
83 | {0x44, 0x5C}, {0x00, 0x5D}, | ||
84 | {0x44, 0x5E}, {0x00, 0x5F}, | ||
85 | {0xC7, 0x60}, {0x01, 0x61}, | ||
86 | {0xC7, 0x62}, {0x01, 0x63}, | ||
87 | {0xC7, 0x64}, {0x01, 0x65}, | ||
88 | {0x44, 0x66}, {0x00, 0x67}, | ||
89 | {0x44, 0x68}, {0x00, 0x69}, | ||
90 | {0x44, 0x6A}, {0x00, 0x6B}, | ||
91 | {0xC7, 0x6C}, {0x01, 0x6D}, | ||
92 | {0xC7, 0x6E}, {0x01, 0x6F}, | ||
93 | {0xC7, 0x70}, {0x01, 0x71}, | ||
94 | {0x44, 0x72}, {0x00, 0x73}, | ||
95 | {0x44, 0x74}, {0x00, 0x75}, | ||
96 | {0x44, 0x76}, {0x00, 0x77}, | ||
97 | {0xC7, 0x78}, {0x01, 0x79}, | ||
98 | {0xC7, 0x7A}, {0x01, 0x7B}, | ||
99 | {0xC7, 0x7C}, {0x01, 0x7D}, | ||
100 | {0x44, 0x7E}, {0x00, 0x7F}, | ||
101 | {0x14, 0x84}, {0x00, 0x85}, | ||
102 | {0x27, 0x86}, {0x00, 0x87}, | ||
103 | {0x07, 0x88}, {0x00, 0x89}, | ||
104 | {0xEC, 0x8A}, {0x0f, 0x8B}, | ||
105 | {0xD8, 0x8C}, {0x0f, 0x8D}, | ||
106 | {0x3D, 0x8E}, {0x00, 0x8F}, | ||
107 | {0x3D, 0x90}, {0x00, 0x91}, | ||
108 | {0xCD, 0x92}, {0x0f, 0x93}, | ||
109 | {0xf7, 0x94}, {0x0f, 0x95}, | ||
110 | {0x0C, 0x96}, {0x00, 0x97}, | ||
111 | {0x00, 0x98}, {0x66, 0x99}, | ||
112 | {0x05, 0x9A}, {0x00, 0x9B}, | ||
113 | {0x04, 0x9C}, {0x00, 0x9D}, | ||
114 | {0x08, 0x9E}, {0x00, 0x9F}, | ||
115 | {0x2D, 0xC0}, {0x2D, 0xC1}, | ||
116 | {0x3A, 0xC2}, {0x05, 0xC3}, | ||
117 | {0x04, 0xC4}, {0x3F, 0xC5}, | ||
118 | {0x00, 0xC6}, {0x00, 0xC7}, | ||
119 | {0x50, 0xC8}, {0x3C, 0xC9}, | ||
120 | {0x28, 0xCA}, {0xD8, 0xCB}, | ||
121 | {0x14, 0xCC}, {0xEC, 0xCD}, | ||
122 | {0x32, 0xCE}, {0xDD, 0xCF}, | ||
123 | {0x32, 0xD0}, {0xDD, 0xD1}, | ||
124 | {0x6A, 0xD2}, {0x50, 0xD3}, | ||
125 | {0x00, 0xD4}, {0x00, 0xD5}, | ||
126 | {0x00, 0xD6}); | ||
127 | break; | ||
128 | default: | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | err += sn9c102_i2c_write(cam, 0x20, 0x00); | ||
133 | err += sn9c102_i2c_write(cam, 0x21, 0xd6); | ||
134 | err += sn9c102_i2c_write(cam, 0x25, 0x06); | ||
135 | |||
136 | return err; | ||
137 | } | ||
138 | |||
139 | |||
140 | static int hv7131r_get_ctrl(struct sn9c102_device* cam, | ||
141 | struct v4l2_control* ctrl) | ||
142 | { | ||
143 | switch (ctrl->id) { | ||
144 | case V4L2_CID_GAIN: | ||
145 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) | ||
146 | return -EIO; | ||
147 | return 0; | ||
148 | case V4L2_CID_RED_BALANCE: | ||
149 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) | ||
150 | return -EIO; | ||
151 | ctrl->value = ctrl->value & 0x3f; | ||
152 | return 0; | ||
153 | case V4L2_CID_BLUE_BALANCE: | ||
154 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) | ||
155 | return -EIO; | ||
156 | ctrl->value = ctrl->value & 0x3f; | ||
157 | return 0; | ||
158 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
159 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) | ||
160 | return -EIO; | ||
161 | ctrl->value = ctrl->value & 0x3f; | ||
162 | return 0; | ||
163 | case V4L2_CID_BLACK_LEVEL: | ||
164 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0) | ||
165 | return -EIO; | ||
166 | ctrl->value = (ctrl->value & 0x08) ? 1 : 0; | ||
167 | return 0; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
174 | static int hv7131r_set_ctrl(struct sn9c102_device* cam, | ||
175 | const struct v4l2_control* ctrl) | ||
176 | { | ||
177 | int err = 0; | ||
178 | |||
179 | switch (ctrl->id) { | ||
180 | case V4L2_CID_GAIN: | ||
181 | err += sn9c102_i2c_write(cam, 0x30, ctrl->value); | ||
182 | break; | ||
183 | case V4L2_CID_RED_BALANCE: | ||
184 | err += sn9c102_i2c_write(cam, 0x31, ctrl->value); | ||
185 | break; | ||
186 | case V4L2_CID_BLUE_BALANCE: | ||
187 | err += sn9c102_i2c_write(cam, 0x33, ctrl->value); | ||
188 | break; | ||
189 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
190 | err += sn9c102_i2c_write(cam, 0x32, ctrl->value); | ||
191 | break; | ||
192 | case V4L2_CID_BLACK_LEVEL: | ||
193 | { | ||
194 | int r = sn9c102_i2c_read(cam, 0x01); | ||
195 | if (r < 0) | ||
196 | return -EIO; | ||
197 | err += sn9c102_i2c_write(cam, 0x01, | ||
198 | (ctrl->value<<3) | (r&0xf7)); | ||
199 | } | ||
200 | break; | ||
201 | default: | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | |||
205 | return err ? -EIO : 0; | ||
206 | } | ||
207 | |||
208 | |||
209 | static int hv7131r_set_crop(struct sn9c102_device* cam, | ||
210 | const struct v4l2_rect* rect) | ||
211 | { | ||
212 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
213 | int err = 0; | ||
214 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, | ||
215 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
216 | |||
217 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
218 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
219 | |||
220 | return err; | ||
221 | } | ||
222 | |||
223 | |||
224 | static int hv7131r_set_pix_format(struct sn9c102_device* cam, | ||
225 | const struct v4l2_pix_format* pix) | ||
226 | { | ||
227 | int err = 0; | ||
228 | |||
229 | switch (sn9c102_get_bridge(cam)) { | ||
230 | case BRIDGE_SN9C103: | ||
231 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
232 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
233 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
234 | } else { | ||
235 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
236 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
237 | } | ||
238 | break; | ||
239 | case BRIDGE_SN9C105: | ||
240 | case BRIDGE_SN9C120: | ||
241 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
242 | err += sn9c102_write_reg(cam, 0xa5, 0x17); | ||
243 | err += sn9c102_i2c_write(cam, 0x01, 0x24); | ||
244 | } else { | ||
245 | err += sn9c102_write_reg(cam, 0xa3, 0x17); | ||
246 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
247 | } | ||
248 | break; | ||
249 | default: | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | return err; | ||
254 | } | ||
255 | |||
256 | |||
257 | static const struct sn9c102_sensor hv7131r = { | ||
258 | .name = "HV7131R", | ||
259 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
260 | .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
261 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
262 | .frequency = SN9C102_I2C_100KHZ, | ||
263 | .interface = SN9C102_I2C_2WIRES, | ||
264 | .i2c_slave_id = 0x11, | ||
265 | .init = &hv7131r_init, | ||
266 | .qctrl = { | ||
267 | { | ||
268 | .id = V4L2_CID_GAIN, | ||
269 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
270 | .name = "global gain", | ||
271 | .minimum = 0x00, | ||
272 | .maximum = 0xff, | ||
273 | .step = 0x01, | ||
274 | .default_value = 0x40, | ||
275 | .flags = 0, | ||
276 | }, | ||
277 | { | ||
278 | .id = V4L2_CID_RED_BALANCE, | ||
279 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
280 | .name = "red balance", | ||
281 | .minimum = 0x00, | ||
282 | .maximum = 0x3f, | ||
283 | .step = 0x01, | ||
284 | .default_value = 0x08, | ||
285 | .flags = 0, | ||
286 | }, | ||
287 | { | ||
288 | .id = V4L2_CID_BLUE_BALANCE, | ||
289 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
290 | .name = "blue balance", | ||
291 | .minimum = 0x00, | ||
292 | .maximum = 0x3f, | ||
293 | .step = 0x01, | ||
294 | .default_value = 0x1a, | ||
295 | .flags = 0, | ||
296 | }, | ||
297 | { | ||
298 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
299 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
300 | .name = "green balance", | ||
301 | .minimum = 0x00, | ||
302 | .maximum = 0x3f, | ||
303 | .step = 0x01, | ||
304 | .default_value = 0x2f, | ||
305 | .flags = 0, | ||
306 | }, | ||
307 | { | ||
308 | .id = V4L2_CID_BLACK_LEVEL, | ||
309 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
310 | .name = "auto black level compensation", | ||
311 | .minimum = 0x00, | ||
312 | .maximum = 0x01, | ||
313 | .step = 0x01, | ||
314 | .default_value = 0x00, | ||
315 | .flags = 0, | ||
316 | }, | ||
317 | }, | ||
318 | .get_ctrl = &hv7131r_get_ctrl, | ||
319 | .set_ctrl = &hv7131r_set_ctrl, | ||
320 | .cropcap = { | ||
321 | .bounds = { | ||
322 | .left = 0, | ||
323 | .top = 0, | ||
324 | .width = 640, | ||
325 | .height = 480, | ||
326 | }, | ||
327 | .defrect = { | ||
328 | .left = 0, | ||
329 | .top = 0, | ||
330 | .width = 640, | ||
331 | .height = 480, | ||
332 | }, | ||
333 | }, | ||
334 | .set_crop = &hv7131r_set_crop, | ||
335 | .pix_format = { | ||
336 | .width = 640, | ||
337 | .height = 480, | ||
338 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
339 | .priv = 8, | ||
340 | }, | ||
341 | .set_pix_format = &hv7131r_set_pix_format | ||
342 | }; | ||
343 | |||
344 | |||
345 | int sn9c102_probe_hv7131r(struct sn9c102_device* cam) | ||
346 | { | ||
347 | int devid, err; | ||
348 | |||
349 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02}, | ||
350 | {0x34, 0x01}, {0x20, 0x17}, | ||
351 | {0x34, 0x01}, {0x46, 0x01}); | ||
352 | |||
353 | devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00); | ||
354 | if (err || devid < 0) | ||
355 | return -EIO; | ||
356 | |||
357 | if (devid != 0x02) | ||
358 | return -ENODEV; | ||
359 | |||
360 | sn9c102_attach_sensor(cam, &hv7131r); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_mi0343.c b/drivers/media/usb/sn9c102/sn9c102_mi0343.c deleted file mode 100644 index 1f5b09bec89c..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_mi0343.c +++ /dev/null | |||
@@ -1,352 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int mi0343_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
29 | int err = 0; | ||
30 | |||
31 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, | ||
32 | {0x0a, 0x14}, {0x40, 0x01}, | ||
33 | {0x20, 0x17}, {0x07, 0x18}, | ||
34 | {0xa0, 0x19}); | ||
35 | |||
36 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
37 | 0x00, 0x01, 0, 0); | ||
38 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
39 | 0x00, 0x00, 0, 0); | ||
40 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, | ||
41 | 0x01, 0xe1, 0, 0); | ||
42 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, | ||
43 | 0x02, 0x81, 0, 0); | ||
44 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, | ||
45 | 0x00, 0x17, 0, 0); | ||
46 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, | ||
47 | 0x00, 0x11, 0, 0); | ||
48 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, | ||
49 | 0x04, 0x9a, 0, 0); | ||
50 | |||
51 | return err; | ||
52 | } | ||
53 | |||
54 | |||
55 | static int mi0343_get_ctrl(struct sn9c102_device* cam, | ||
56 | struct v4l2_control* ctrl) | ||
57 | { | ||
58 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
59 | u8 data[2]; | ||
60 | |||
61 | switch (ctrl->id) { | ||
62 | case V4L2_CID_EXPOSURE: | ||
63 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, | ||
64 | data) < 0) | ||
65 | return -EIO; | ||
66 | ctrl->value = data[0]; | ||
67 | return 0; | ||
68 | case V4L2_CID_GAIN: | ||
69 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, | ||
70 | data) < 0) | ||
71 | return -EIO; | ||
72 | break; | ||
73 | case V4L2_CID_HFLIP: | ||
74 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, | ||
75 | data) < 0) | ||
76 | return -EIO; | ||
77 | ctrl->value = data[1] & 0x20 ? 1 : 0; | ||
78 | return 0; | ||
79 | case V4L2_CID_VFLIP: | ||
80 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, | ||
81 | data) < 0) | ||
82 | return -EIO; | ||
83 | ctrl->value = data[1] & 0x80 ? 1 : 0; | ||
84 | return 0; | ||
85 | case V4L2_CID_RED_BALANCE: | ||
86 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, | ||
87 | data) < 0) | ||
88 | return -EIO; | ||
89 | break; | ||
90 | case V4L2_CID_BLUE_BALANCE: | ||
91 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, | ||
92 | data) < 0) | ||
93 | return -EIO; | ||
94 | break; | ||
95 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
96 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, | ||
97 | data) < 0) | ||
98 | return -EIO; | ||
99 | break; | ||
100 | default: | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | switch (ctrl->id) { | ||
105 | case V4L2_CID_GAIN: | ||
106 | case V4L2_CID_RED_BALANCE: | ||
107 | case V4L2_CID_BLUE_BALANCE: | ||
108 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
109 | ctrl->value = data[1] | (data[0] << 8); | ||
110 | if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) | ||
111 | ctrl->value -= 0x10; | ||
112 | else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) | ||
113 | ctrl->value -= 0x60; | ||
114 | else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff) | ||
115 | ctrl->value -= 0xe0; | ||
116 | } | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | |||
122 | static int mi0343_set_ctrl(struct sn9c102_device* cam, | ||
123 | const struct v4l2_control* ctrl) | ||
124 | { | ||
125 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
126 | u16 reg = 0; | ||
127 | int err = 0; | ||
128 | |||
129 | switch (ctrl->id) { | ||
130 | case V4L2_CID_GAIN: | ||
131 | case V4L2_CID_RED_BALANCE: | ||
132 | case V4L2_CID_BLUE_BALANCE: | ||
133 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
134 | if (ctrl->value <= (0x3f-0x10)) | ||
135 | reg = 0x10 + ctrl->value; | ||
136 | else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60))) | ||
137 | reg = 0x60 + (ctrl->value - (0x3f-0x10)); | ||
138 | else | ||
139 | reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60)); | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | switch (ctrl->id) { | ||
144 | case V4L2_CID_EXPOSURE: | ||
145 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
146 | 0x09, ctrl->value, 0x00, | ||
147 | 0, 0); | ||
148 | break; | ||
149 | case V4L2_CID_GAIN: | ||
150 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
151 | 0x35, reg >> 8, reg & 0xff, | ||
152 | 0, 0); | ||
153 | break; | ||
154 | case V4L2_CID_HFLIP: | ||
155 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
156 | 0x20, ctrl->value ? 0x40:0x00, | ||
157 | ctrl->value ? 0x20:0x00, | ||
158 | 0, 0); | ||
159 | break; | ||
160 | case V4L2_CID_VFLIP: | ||
161 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
162 | 0x20, ctrl->value ? 0x80:0x00, | ||
163 | ctrl->value ? 0x80:0x00, | ||
164 | 0, 0); | ||
165 | break; | ||
166 | case V4L2_CID_RED_BALANCE: | ||
167 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
168 | 0x2d, reg >> 8, reg & 0xff, | ||
169 | 0, 0); | ||
170 | break; | ||
171 | case V4L2_CID_BLUE_BALANCE: | ||
172 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
173 | 0x2c, reg >> 8, reg & 0xff, | ||
174 | 0, 0); | ||
175 | break; | ||
176 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
177 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
178 | 0x2b, reg >> 8, reg & 0xff, | ||
179 | 0, 0); | ||
180 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
181 | 0x2e, reg >> 8, reg & 0xff, | ||
182 | 0, 0); | ||
183 | break; | ||
184 | default: | ||
185 | return -EINVAL; | ||
186 | } | ||
187 | |||
188 | return err ? -EIO : 0; | ||
189 | } | ||
190 | |||
191 | |||
192 | static int mi0343_set_crop(struct sn9c102_device* cam, | ||
193 | const struct v4l2_rect* rect) | ||
194 | { | ||
195 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
196 | int err = 0; | ||
197 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, | ||
198 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | ||
199 | |||
200 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
201 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
202 | |||
203 | return err; | ||
204 | } | ||
205 | |||
206 | |||
207 | static int mi0343_set_pix_format(struct sn9c102_device* cam, | ||
208 | const struct v4l2_pix_format* pix) | ||
209 | { | ||
210 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
211 | int err = 0; | ||
212 | |||
213 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { | ||
214 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
215 | 0x0a, 0x00, 0x03, 0, 0); | ||
216 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
217 | } else { | ||
218 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
219 | 0x0a, 0x00, 0x05, 0, 0); | ||
220 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
221 | } | ||
222 | |||
223 | return err; | ||
224 | } | ||
225 | |||
226 | |||
227 | static const struct sn9c102_sensor mi0343 = { | ||
228 | .name = "MI-0343", | ||
229 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
230 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
231 | .frequency = SN9C102_I2C_100KHZ, | ||
232 | .interface = SN9C102_I2C_2WIRES, | ||
233 | .i2c_slave_id = 0x5d, | ||
234 | .init = &mi0343_init, | ||
235 | .qctrl = { | ||
236 | { | ||
237 | .id = V4L2_CID_EXPOSURE, | ||
238 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
239 | .name = "exposure", | ||
240 | .minimum = 0x00, | ||
241 | .maximum = 0x0f, | ||
242 | .step = 0x01, | ||
243 | .default_value = 0x06, | ||
244 | .flags = 0, | ||
245 | }, | ||
246 | { | ||
247 | .id = V4L2_CID_GAIN, | ||
248 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
249 | .name = "global gain", | ||
250 | .minimum = 0x00, | ||
251 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/ | ||
252 | .step = 0x01, | ||
253 | .default_value = 0x00, | ||
254 | .flags = 0, | ||
255 | }, | ||
256 | { | ||
257 | .id = V4L2_CID_HFLIP, | ||
258 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
259 | .name = "horizontal mirror", | ||
260 | .minimum = 0, | ||
261 | .maximum = 1, | ||
262 | .step = 1, | ||
263 | .default_value = 0, | ||
264 | .flags = 0, | ||
265 | }, | ||
266 | { | ||
267 | .id = V4L2_CID_VFLIP, | ||
268 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
269 | .name = "vertical mirror", | ||
270 | .minimum = 0, | ||
271 | .maximum = 1, | ||
272 | .step = 1, | ||
273 | .default_value = 0, | ||
274 | .flags = 0, | ||
275 | }, | ||
276 | { | ||
277 | .id = V4L2_CID_RED_BALANCE, | ||
278 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
279 | .name = "red balance", | ||
280 | .minimum = 0x00, | ||
281 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), | ||
282 | .step = 0x01, | ||
283 | .default_value = 0x00, | ||
284 | .flags = 0, | ||
285 | }, | ||
286 | { | ||
287 | .id = V4L2_CID_BLUE_BALANCE, | ||
288 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
289 | .name = "blue balance", | ||
290 | .minimum = 0x00, | ||
291 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), | ||
292 | .step = 0x01, | ||
293 | .default_value = 0x00, | ||
294 | .flags = 0, | ||
295 | }, | ||
296 | { | ||
297 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
298 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
299 | .name = "green balance", | ||
300 | .minimum = 0x00, | ||
301 | .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)), | ||
302 | .step = 0x01, | ||
303 | .default_value = 0x00, | ||
304 | .flags = 0, | ||
305 | }, | ||
306 | }, | ||
307 | .get_ctrl = &mi0343_get_ctrl, | ||
308 | .set_ctrl = &mi0343_set_ctrl, | ||
309 | .cropcap = { | ||
310 | .bounds = { | ||
311 | .left = 0, | ||
312 | .top = 0, | ||
313 | .width = 640, | ||
314 | .height = 480, | ||
315 | }, | ||
316 | .defrect = { | ||
317 | .left = 0, | ||
318 | .top = 0, | ||
319 | .width = 640, | ||
320 | .height = 480, | ||
321 | }, | ||
322 | }, | ||
323 | .set_crop = &mi0343_set_crop, | ||
324 | .pix_format = { | ||
325 | .width = 640, | ||
326 | .height = 480, | ||
327 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
328 | .priv = 8, | ||
329 | }, | ||
330 | .set_pix_format = &mi0343_set_pix_format | ||
331 | }; | ||
332 | |||
333 | |||
334 | int sn9c102_probe_mi0343(struct sn9c102_device* cam) | ||
335 | { | ||
336 | u8 data[2]; | ||
337 | |||
338 | if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, | ||
339 | {0x28, 0x17})) | ||
340 | return -EIO; | ||
341 | |||
342 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, | ||
343 | 2, data) < 0) | ||
344 | return -EIO; | ||
345 | |||
346 | if (data[1] != 0x42 || data[0] != 0xe3) | ||
347 | return -ENODEV; | ||
348 | |||
349 | sn9c102_attach_sensor(cam, &mi0343); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_mi0360.c b/drivers/media/usb/sn9c102/sn9c102_mi0360.c deleted file mode 100644 index d973fc1973d9..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_mi0360.c +++ /dev/null | |||
@@ -1,453 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int mi0360_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
29 | int err = 0; | ||
30 | |||
31 | switch (sn9c102_get_bridge(cam)) { | ||
32 | case BRIDGE_SN9C103: | ||
33 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, | ||
34 | {0x0a, 0x14}, {0x40, 0x01}, | ||
35 | {0x20, 0x17}, {0x07, 0x18}, | ||
36 | {0xa0, 0x19}, {0x02, 0x1c}, | ||
37 | {0x03, 0x1d}, {0x0f, 0x1e}, | ||
38 | {0x0c, 0x1f}, {0x00, 0x20}, | ||
39 | {0x10, 0x21}, {0x20, 0x22}, | ||
40 | {0x30, 0x23}, {0x40, 0x24}, | ||
41 | {0x50, 0x25}, {0x60, 0x26}, | ||
42 | {0x70, 0x27}, {0x80, 0x28}, | ||
43 | {0x90, 0x29}, {0xa0, 0x2a}, | ||
44 | {0xb0, 0x2b}, {0xc0, 0x2c}, | ||
45 | {0xd0, 0x2d}, {0xe0, 0x2e}, | ||
46 | {0xf0, 0x2f}, {0xff, 0x30}); | ||
47 | break; | ||
48 | case BRIDGE_SN9C105: | ||
49 | case BRIDGE_SN9C120: | ||
50 | err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, | ||
51 | {0x00, 0x03}, {0x1a, 0x04}, | ||
52 | {0x50, 0x05}, {0x20, 0x06}, | ||
53 | {0x10, 0x07}, {0x03, 0x10}, | ||
54 | {0x08, 0x14}, {0xa2, 0x17}, | ||
55 | {0x47, 0x18}, {0x00, 0x19}, | ||
56 | {0x1d, 0x1a}, {0x10, 0x1b}, | ||
57 | {0x02, 0x1c}, {0x03, 0x1d}, | ||
58 | {0x0f, 0x1e}, {0x0c, 0x1f}, | ||
59 | {0x00, 0x20}, {0x29, 0x21}, | ||
60 | {0x40, 0x22}, {0x54, 0x23}, | ||
61 | {0x66, 0x24}, {0x76, 0x25}, | ||
62 | {0x85, 0x26}, {0x94, 0x27}, | ||
63 | {0xa1, 0x28}, {0xae, 0x29}, | ||
64 | {0xbb, 0x2a}, {0xc7, 0x2b}, | ||
65 | {0xd3, 0x2c}, {0xde, 0x2d}, | ||
66 | {0xea, 0x2e}, {0xf4, 0x2f}, | ||
67 | {0xff, 0x30}, {0x00, 0x3F}, | ||
68 | {0xC7, 0x40}, {0x01, 0x41}, | ||
69 | {0x44, 0x42}, {0x00, 0x43}, | ||
70 | {0x44, 0x44}, {0x00, 0x45}, | ||
71 | {0x44, 0x46}, {0x00, 0x47}, | ||
72 | {0xC7, 0x48}, {0x01, 0x49}, | ||
73 | {0xC7, 0x4A}, {0x01, 0x4B}, | ||
74 | {0xC7, 0x4C}, {0x01, 0x4D}, | ||
75 | {0x44, 0x4E}, {0x00, 0x4F}, | ||
76 | {0x44, 0x50}, {0x00, 0x51}, | ||
77 | {0x44, 0x52}, {0x00, 0x53}, | ||
78 | {0xC7, 0x54}, {0x01, 0x55}, | ||
79 | {0xC7, 0x56}, {0x01, 0x57}, | ||
80 | {0xC7, 0x58}, {0x01, 0x59}, | ||
81 | {0x44, 0x5A}, {0x00, 0x5B}, | ||
82 | {0x44, 0x5C}, {0x00, 0x5D}, | ||
83 | {0x44, 0x5E}, {0x00, 0x5F}, | ||
84 | {0xC7, 0x60}, {0x01, 0x61}, | ||
85 | {0xC7, 0x62}, {0x01, 0x63}, | ||
86 | {0xC7, 0x64}, {0x01, 0x65}, | ||
87 | {0x44, 0x66}, {0x00, 0x67}, | ||
88 | {0x44, 0x68}, {0x00, 0x69}, | ||
89 | {0x44, 0x6A}, {0x00, 0x6B}, | ||
90 | {0xC7, 0x6C}, {0x01, 0x6D}, | ||
91 | {0xC7, 0x6E}, {0x01, 0x6F}, | ||
92 | {0xC7, 0x70}, {0x01, 0x71}, | ||
93 | {0x44, 0x72}, {0x00, 0x73}, | ||
94 | {0x44, 0x74}, {0x00, 0x75}, | ||
95 | {0x44, 0x76}, {0x00, 0x77}, | ||
96 | {0xC7, 0x78}, {0x01, 0x79}, | ||
97 | {0xC7, 0x7A}, {0x01, 0x7B}, | ||
98 | {0xC7, 0x7C}, {0x01, 0x7D}, | ||
99 | {0x44, 0x7E}, {0x00, 0x7F}, | ||
100 | {0x14, 0x84}, {0x00, 0x85}, | ||
101 | {0x27, 0x86}, {0x00, 0x87}, | ||
102 | {0x07, 0x88}, {0x00, 0x89}, | ||
103 | {0xEC, 0x8A}, {0x0f, 0x8B}, | ||
104 | {0xD8, 0x8C}, {0x0f, 0x8D}, | ||
105 | {0x3D, 0x8E}, {0x00, 0x8F}, | ||
106 | {0x3D, 0x90}, {0x00, 0x91}, | ||
107 | {0xCD, 0x92}, {0x0f, 0x93}, | ||
108 | {0xf7, 0x94}, {0x0f, 0x95}, | ||
109 | {0x0C, 0x96}, {0x00, 0x97}, | ||
110 | {0x00, 0x98}, {0x66, 0x99}, | ||
111 | {0x05, 0x9A}, {0x00, 0x9B}, | ||
112 | {0x04, 0x9C}, {0x00, 0x9D}, | ||
113 | {0x08, 0x9E}, {0x00, 0x9F}, | ||
114 | {0x2D, 0xC0}, {0x2D, 0xC1}, | ||
115 | {0x3A, 0xC2}, {0x05, 0xC3}, | ||
116 | {0x04, 0xC4}, {0x3F, 0xC5}, | ||
117 | {0x00, 0xC6}, {0x00, 0xC7}, | ||
118 | {0x50, 0xC8}, {0x3C, 0xC9}, | ||
119 | {0x28, 0xCA}, {0xD8, 0xCB}, | ||
120 | {0x14, 0xCC}, {0xEC, 0xCD}, | ||
121 | {0x32, 0xCE}, {0xDD, 0xCF}, | ||
122 | {0x32, 0xD0}, {0xDD, 0xD1}, | ||
123 | {0x6A, 0xD2}, {0x50, 0xD3}, | ||
124 | {0x00, 0xD4}, {0x00, 0xD5}, | ||
125 | {0x00, 0xD6}); | ||
126 | break; | ||
127 | default: | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
132 | 0x00, 0x01, 0, 0); | ||
133 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
134 | 0x00, 0x00, 0, 0); | ||
135 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, | ||
136 | 0x01, 0xe1, 0, 0); | ||
137 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, | ||
138 | 0x02, 0x81, 0, 0); | ||
139 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, | ||
140 | 0x00, 0x17, 0, 0); | ||
141 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, | ||
142 | 0x00, 0x11, 0, 0); | ||
143 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, | ||
144 | 0x04, 0x9a, 0, 0); | ||
145 | |||
146 | return err; | ||
147 | } | ||
148 | |||
149 | |||
150 | static int mi0360_get_ctrl(struct sn9c102_device* cam, | ||
151 | struct v4l2_control* ctrl) | ||
152 | { | ||
153 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
154 | u8 data[2]; | ||
155 | |||
156 | switch (ctrl->id) { | ||
157 | case V4L2_CID_EXPOSURE: | ||
158 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, | ||
159 | data) < 0) | ||
160 | return -EIO; | ||
161 | ctrl->value = data[0]; | ||
162 | return 0; | ||
163 | case V4L2_CID_GAIN: | ||
164 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, | ||
165 | data) < 0) | ||
166 | return -EIO; | ||
167 | ctrl->value = data[1]; | ||
168 | return 0; | ||
169 | case V4L2_CID_RED_BALANCE: | ||
170 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, | ||
171 | data) < 0) | ||
172 | return -EIO; | ||
173 | ctrl->value = data[1]; | ||
174 | return 0; | ||
175 | case V4L2_CID_BLUE_BALANCE: | ||
176 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, | ||
177 | data) < 0) | ||
178 | return -EIO; | ||
179 | ctrl->value = data[1]; | ||
180 | return 0; | ||
181 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
182 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, | ||
183 | data) < 0) | ||
184 | return -EIO; | ||
185 | ctrl->value = data[1]; | ||
186 | return 0; | ||
187 | case V4L2_CID_HFLIP: | ||
188 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, | ||
189 | data) < 0) | ||
190 | return -EIO; | ||
191 | ctrl->value = data[1] & 0x20 ? 1 : 0; | ||
192 | return 0; | ||
193 | case V4L2_CID_VFLIP: | ||
194 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, | ||
195 | data) < 0) | ||
196 | return -EIO; | ||
197 | ctrl->value = data[1] & 0x80 ? 1 : 0; | ||
198 | return 0; | ||
199 | default: | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | |||
207 | static int mi0360_set_ctrl(struct sn9c102_device* cam, | ||
208 | const struct v4l2_control* ctrl) | ||
209 | { | ||
210 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
211 | int err = 0; | ||
212 | |||
213 | switch (ctrl->id) { | ||
214 | case V4L2_CID_EXPOSURE: | ||
215 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
216 | 0x09, ctrl->value, 0x00, | ||
217 | 0, 0); | ||
218 | break; | ||
219 | case V4L2_CID_GAIN: | ||
220 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
221 | 0x35, 0x03, ctrl->value, | ||
222 | 0, 0); | ||
223 | break; | ||
224 | case V4L2_CID_RED_BALANCE: | ||
225 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
226 | 0x2c, 0x03, ctrl->value, | ||
227 | 0, 0); | ||
228 | break; | ||
229 | case V4L2_CID_BLUE_BALANCE: | ||
230 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
231 | 0x2d, 0x03, ctrl->value, | ||
232 | 0, 0); | ||
233 | break; | ||
234 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
235 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
236 | 0x2b, 0x03, ctrl->value, | ||
237 | 0, 0); | ||
238 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
239 | 0x2e, 0x03, ctrl->value, | ||
240 | 0, 0); | ||
241 | break; | ||
242 | case V4L2_CID_HFLIP: | ||
243 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
244 | 0x20, ctrl->value ? 0x40:0x00, | ||
245 | ctrl->value ? 0x20:0x00, | ||
246 | 0, 0); | ||
247 | break; | ||
248 | case V4L2_CID_VFLIP: | ||
249 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
250 | 0x20, ctrl->value ? 0x80:0x00, | ||
251 | ctrl->value ? 0x80:0x00, | ||
252 | 0, 0); | ||
253 | break; | ||
254 | default: | ||
255 | return -EINVAL; | ||
256 | } | ||
257 | |||
258 | return err ? -EIO : 0; | ||
259 | } | ||
260 | |||
261 | |||
262 | static int mi0360_set_crop(struct sn9c102_device* cam, | ||
263 | const struct v4l2_rect* rect) | ||
264 | { | ||
265 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
266 | int err = 0; | ||
267 | u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
268 | |||
269 | switch (sn9c102_get_bridge(cam)) { | ||
270 | case BRIDGE_SN9C103: | ||
271 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0; | ||
272 | break; | ||
273 | case BRIDGE_SN9C105: | ||
274 | case BRIDGE_SN9C120: | ||
275 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; | ||
276 | break; | ||
277 | default: | ||
278 | break; | ||
279 | } | ||
280 | |||
281 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
282 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
283 | |||
284 | return err; | ||
285 | } | ||
286 | |||
287 | |||
288 | static int mi0360_set_pix_format(struct sn9c102_device* cam, | ||
289 | const struct v4l2_pix_format* pix) | ||
290 | { | ||
291 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
292 | int err = 0; | ||
293 | |||
294 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
295 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
296 | 0x0a, 0x00, 0x05, 0, 0); | ||
297 | err += sn9c102_write_reg(cam, 0x60, 0x19); | ||
298 | if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || | ||
299 | sn9c102_get_bridge(cam) == BRIDGE_SN9C120) | ||
300 | err += sn9c102_write_reg(cam, 0xa6, 0x17); | ||
301 | } else { | ||
302 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
303 | 0x0a, 0x00, 0x02, 0, 0); | ||
304 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
305 | if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || | ||
306 | sn9c102_get_bridge(cam) == BRIDGE_SN9C120) | ||
307 | err += sn9c102_write_reg(cam, 0xa2, 0x17); | ||
308 | } | ||
309 | |||
310 | return err; | ||
311 | } | ||
312 | |||
313 | |||
314 | static const struct sn9c102_sensor mi0360 = { | ||
315 | .name = "MI-0360", | ||
316 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
317 | .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
318 | .frequency = SN9C102_I2C_100KHZ, | ||
319 | .interface = SN9C102_I2C_2WIRES, | ||
320 | .i2c_slave_id = 0x5d, | ||
321 | .init = &mi0360_init, | ||
322 | .qctrl = { | ||
323 | { | ||
324 | .id = V4L2_CID_EXPOSURE, | ||
325 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
326 | .name = "exposure", | ||
327 | .minimum = 0x00, | ||
328 | .maximum = 0x0f, | ||
329 | .step = 0x01, | ||
330 | .default_value = 0x05, | ||
331 | .flags = 0, | ||
332 | }, | ||
333 | { | ||
334 | .id = V4L2_CID_GAIN, | ||
335 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
336 | .name = "global gain", | ||
337 | .minimum = 0x00, | ||
338 | .maximum = 0x7f, | ||
339 | .step = 0x01, | ||
340 | .default_value = 0x25, | ||
341 | .flags = 0, | ||
342 | }, | ||
343 | { | ||
344 | .id = V4L2_CID_HFLIP, | ||
345 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
346 | .name = "horizontal mirror", | ||
347 | .minimum = 0, | ||
348 | .maximum = 1, | ||
349 | .step = 1, | ||
350 | .default_value = 0, | ||
351 | .flags = 0, | ||
352 | }, | ||
353 | { | ||
354 | .id = V4L2_CID_VFLIP, | ||
355 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
356 | .name = "vertical mirror", | ||
357 | .minimum = 0, | ||
358 | .maximum = 1, | ||
359 | .step = 1, | ||
360 | .default_value = 0, | ||
361 | .flags = 0, | ||
362 | }, | ||
363 | { | ||
364 | .id = V4L2_CID_BLUE_BALANCE, | ||
365 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
366 | .name = "blue balance", | ||
367 | .minimum = 0x00, | ||
368 | .maximum = 0x7f, | ||
369 | .step = 0x01, | ||
370 | .default_value = 0x0f, | ||
371 | .flags = 0, | ||
372 | }, | ||
373 | { | ||
374 | .id = V4L2_CID_RED_BALANCE, | ||
375 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
376 | .name = "red balance", | ||
377 | .minimum = 0x00, | ||
378 | .maximum = 0x7f, | ||
379 | .step = 0x01, | ||
380 | .default_value = 0x32, | ||
381 | .flags = 0, | ||
382 | }, | ||
383 | { | ||
384 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
385 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
386 | .name = "green balance", | ||
387 | .minimum = 0x00, | ||
388 | .maximum = 0x7f, | ||
389 | .step = 0x01, | ||
390 | .default_value = 0x25, | ||
391 | .flags = 0, | ||
392 | }, | ||
393 | }, | ||
394 | .get_ctrl = &mi0360_get_ctrl, | ||
395 | .set_ctrl = &mi0360_set_ctrl, | ||
396 | .cropcap = { | ||
397 | .bounds = { | ||
398 | .left = 0, | ||
399 | .top = 0, | ||
400 | .width = 640, | ||
401 | .height = 480, | ||
402 | }, | ||
403 | .defrect = { | ||
404 | .left = 0, | ||
405 | .top = 0, | ||
406 | .width = 640, | ||
407 | .height = 480, | ||
408 | }, | ||
409 | }, | ||
410 | .set_crop = &mi0360_set_crop, | ||
411 | .pix_format = { | ||
412 | .width = 640, | ||
413 | .height = 480, | ||
414 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
415 | .priv = 8, | ||
416 | }, | ||
417 | .set_pix_format = &mi0360_set_pix_format | ||
418 | }; | ||
419 | |||
420 | |||
421 | int sn9c102_probe_mi0360(struct sn9c102_device* cam) | ||
422 | { | ||
423 | |||
424 | u8 data[2]; | ||
425 | |||
426 | switch (sn9c102_get_bridge(cam)) { | ||
427 | case BRIDGE_SN9C103: | ||
428 | if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, | ||
429 | {0x28, 0x17})) | ||
430 | return -EIO; | ||
431 | break; | ||
432 | case BRIDGE_SN9C105: | ||
433 | case BRIDGE_SN9C120: | ||
434 | if (sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, | ||
435 | {0x01, 0x01}, {0x00, 0x01}, | ||
436 | {0x28, 0x17})) | ||
437 | return -EIO; | ||
438 | break; | ||
439 | default: | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, | ||
444 | 2, data) < 0) | ||
445 | return -EIO; | ||
446 | |||
447 | if (data[0] != 0x82 || data[1] != 0x43) | ||
448 | return -ENODEV; | ||
449 | |||
450 | sn9c102_attach_sensor(cam, &mi0360); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_mt9v111.c b/drivers/media/usb/sn9c102/sn9c102_mt9v111.c deleted file mode 100644 index 95986eb492e4..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_mt9v111.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int mt9v111_init(struct sn9c102_device *cam) | ||
27 | { | ||
28 | struct sn9c102_sensor *s = sn9c102_get_sensor(cam); | ||
29 | int err = 0; | ||
30 | |||
31 | err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, | ||
32 | {0x00, 0x03}, {0x1a, 0x04}, | ||
33 | {0x1f, 0x05}, {0x20, 0x06}, | ||
34 | {0x1f, 0x07}, {0x81, 0x08}, | ||
35 | {0x5c, 0x09}, {0x00, 0x0a}, | ||
36 | {0x00, 0x0b}, {0x00, 0x0c}, | ||
37 | {0x00, 0x0d}, {0x00, 0x0e}, | ||
38 | {0x00, 0x0f}, {0x03, 0x10}, | ||
39 | {0x00, 0x11}, {0x00, 0x12}, | ||
40 | {0x02, 0x13}, {0x14, 0x14}, | ||
41 | {0x28, 0x15}, {0x1e, 0x16}, | ||
42 | {0xe2, 0x17}, {0x06, 0x18}, | ||
43 | {0x00, 0x19}, {0x00, 0x1a}, | ||
44 | {0x00, 0x1b}, {0x08, 0x20}, | ||
45 | {0x39, 0x21}, {0x51, 0x22}, | ||
46 | {0x63, 0x23}, {0x73, 0x24}, | ||
47 | {0x82, 0x25}, {0x8f, 0x26}, | ||
48 | {0x9b, 0x27}, {0xa7, 0x28}, | ||
49 | {0xb1, 0x29}, {0xbc, 0x2a}, | ||
50 | {0xc6, 0x2b}, {0xcf, 0x2c}, | ||
51 | {0xd8, 0x2d}, {0xe1, 0x2e}, | ||
52 | {0xea, 0x2f}, {0xf2, 0x30}, | ||
53 | {0x13, 0x84}, {0x00, 0x85}, | ||
54 | {0x25, 0x86}, {0x00, 0x87}, | ||
55 | {0x07, 0x88}, {0x00, 0x89}, | ||
56 | {0xee, 0x8a}, {0x0f, 0x8b}, | ||
57 | {0xe5, 0x8c}, {0x0f, 0x8d}, | ||
58 | {0x2e, 0x8e}, {0x00, 0x8f}, | ||
59 | {0x30, 0x90}, {0x00, 0x91}, | ||
60 | {0xd4, 0x92}, {0x0f, 0x93}, | ||
61 | {0xfc, 0x94}, {0x0f, 0x95}, | ||
62 | {0x14, 0x96}, {0x00, 0x97}, | ||
63 | {0x00, 0x98}, {0x60, 0x99}, | ||
64 | {0x07, 0x9a}, {0x40, 0x9b}, | ||
65 | {0x20, 0x9c}, {0x00, 0x9d}, | ||
66 | {0x00, 0x9e}, {0x00, 0x9f}, | ||
67 | {0x2d, 0xc0}, {0x2d, 0xc1}, | ||
68 | {0x3a, 0xc2}, {0x05, 0xc3}, | ||
69 | {0x04, 0xc4}, {0x3f, 0xc5}, | ||
70 | {0x00, 0xc6}, {0x00, 0xc7}, | ||
71 | {0x50, 0xc8}, {0x3c, 0xc9}, | ||
72 | {0x28, 0xca}, {0xd8, 0xcb}, | ||
73 | {0x14, 0xcc}, {0xec, 0xcd}, | ||
74 | {0x32, 0xce}, {0xdd, 0xcf}, | ||
75 | {0x2d, 0xd0}, {0xdd, 0xd1}, | ||
76 | {0x6a, 0xd2}, {0x50, 0xd3}, | ||
77 | {0x60, 0xd4}, {0x00, 0xd5}, | ||
78 | {0x00, 0xd6}); | ||
79 | |||
80 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, | ||
81 | 0x00, 0x01, 0, 0); | ||
82 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
83 | 0x00, 0x01, 0, 0); | ||
84 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
85 | 0x00, 0x00, 0, 0); | ||
86 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, | ||
87 | 0x04, 0x80, 0, 0); | ||
88 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, | ||
89 | 0x00, 0x04, 0, 0); | ||
90 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, | ||
91 | 0x00, 0x08, 0, 0); | ||
92 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02, | ||
93 | 0x00, 0x16, 0, 0); | ||
94 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, | ||
95 | 0x01, 0xe7, 0, 0); | ||
96 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, | ||
97 | 0x02, 0x87, 0, 0); | ||
98 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, | ||
99 | 0x00, 0x40, 0, 0); | ||
100 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, | ||
101 | 0x00, 0x09, 0, 0); | ||
102 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07, | ||
103 | 0x30, 0x02, 0, 0); | ||
104 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c, | ||
105 | 0x00, 0x00, 0, 0); | ||
106 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12, | ||
107 | 0x00, 0xb0, 0, 0); | ||
108 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13, | ||
109 | 0x00, 0x7c, 0, 0); | ||
110 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e, | ||
111 | 0x00, 0x00, 0, 0); | ||
112 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, | ||
113 | 0x00, 0x00, 0, 0); | ||
114 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, | ||
115 | 0x00, 0x00, 0, 0); | ||
116 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, | ||
117 | 0x00, 0x04, 0, 0); | ||
118 | |||
119 | return err; | ||
120 | } | ||
121 | |||
122 | static int mt9v111_get_ctrl(struct sn9c102_device *cam, | ||
123 | struct v4l2_control *ctrl) | ||
124 | { | ||
125 | struct sn9c102_sensor *s = sn9c102_get_sensor(cam); | ||
126 | u8 data[2]; | ||
127 | int err = 0; | ||
128 | |||
129 | switch (ctrl->id) { | ||
130 | case V4L2_CID_VFLIP: | ||
131 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, | ||
132 | data) < 0) | ||
133 | return -EIO; | ||
134 | ctrl->value = data[1] & 0x80 ? 1 : 0; | ||
135 | return 0; | ||
136 | default: | ||
137 | return -EINVAL; | ||
138 | } | ||
139 | |||
140 | return err ? -EIO : 0; | ||
141 | } | ||
142 | |||
143 | static int mt9v111_set_ctrl(struct sn9c102_device *cam, | ||
144 | const struct v4l2_control *ctrl) | ||
145 | { | ||
146 | struct sn9c102_sensor *s = sn9c102_get_sensor(cam); | ||
147 | int err = 0; | ||
148 | |||
149 | switch (ctrl->id) { | ||
150 | case V4L2_CID_VFLIP: | ||
151 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
152 | 0x20, | ||
153 | ctrl->value ? 0x80 : 0x00, | ||
154 | ctrl->value ? 0x80 : 0x00, 0, | ||
155 | 0); | ||
156 | break; | ||
157 | default: | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | return err ? -EIO : 0; | ||
162 | } | ||
163 | |||
164 | static int mt9v111_set_crop(struct sn9c102_device *cam, | ||
165 | const struct v4l2_rect *rect) | ||
166 | { | ||
167 | struct sn9c102_sensor *s = sn9c102_get_sensor(cam); | ||
168 | int err = 0; | ||
169 | u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2; | ||
170 | |||
171 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
172 | |||
173 | return err; | ||
174 | } | ||
175 | |||
176 | static int mt9v111_set_pix_format(struct sn9c102_device *cam, | ||
177 | const struct v4l2_pix_format *pix) | ||
178 | { | ||
179 | int err = 0; | ||
180 | |||
181 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
182 | err += sn9c102_write_reg(cam, 0xb4, 0x17); | ||
183 | } else { | ||
184 | err += sn9c102_write_reg(cam, 0xe2, 0x17); | ||
185 | } | ||
186 | |||
187 | return err; | ||
188 | } | ||
189 | |||
190 | |||
191 | static const struct sn9c102_sensor mt9v111 = { | ||
192 | .name = "MT9V111", | ||
193 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
194 | .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
195 | .frequency = SN9C102_I2C_100KHZ, | ||
196 | .interface = SN9C102_I2C_2WIRES, | ||
197 | .i2c_slave_id = 0x5c, | ||
198 | .init = &mt9v111_init, | ||
199 | .qctrl = { | ||
200 | { | ||
201 | .id = V4L2_CID_VFLIP, | ||
202 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
203 | .name = "vertical mirror", | ||
204 | .minimum = 0, | ||
205 | .maximum = 1, | ||
206 | .step = 1, | ||
207 | .default_value = 0, | ||
208 | .flags = 0, | ||
209 | }, | ||
210 | }, | ||
211 | .get_ctrl = &mt9v111_get_ctrl, | ||
212 | .set_ctrl = &mt9v111_set_ctrl, | ||
213 | .cropcap = { | ||
214 | .bounds = { | ||
215 | .left = 0, | ||
216 | .top = 0, | ||
217 | .width = 640, | ||
218 | .height = 480, | ||
219 | }, | ||
220 | .defrect = { | ||
221 | .left = 0, | ||
222 | .top = 0, | ||
223 | .width = 640, | ||
224 | .height = 480, | ||
225 | }, | ||
226 | }, | ||
227 | .set_crop = &mt9v111_set_crop, | ||
228 | .pix_format = { | ||
229 | .width = 640, | ||
230 | .height = 480, | ||
231 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
232 | .priv = 8, | ||
233 | }, | ||
234 | .set_pix_format = &mt9v111_set_pix_format | ||
235 | }; | ||
236 | |||
237 | |||
238 | int sn9c102_probe_mt9v111(struct sn9c102_device *cam) | ||
239 | { | ||
240 | u8 data[2]; | ||
241 | int err = 0; | ||
242 | |||
243 | err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, | ||
244 | {0x29, 0x01}, {0x42, 0x17}, | ||
245 | {0x62, 0x17}, {0x08, 0x01}); | ||
246 | err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4, | ||
247 | mt9v111.i2c_slave_id, 0x01, 0x00, | ||
248 | 0x04, 0, 0); | ||
249 | if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111, | ||
250 | mt9v111.i2c_slave_id, 0x36, 2, | ||
251 | data) < 0) | ||
252 | return -EIO; | ||
253 | |||
254 | if (data[0] != 0x82 || data[1] != 0x3a) | ||
255 | return -ENODEV; | ||
256 | |||
257 | sn9c102_attach_sensor(cam, &mt9v111); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_ov7630.c b/drivers/media/usb/sn9c102/sn9c102_ov7630.c deleted file mode 100644 index 803712c29f02..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_ov7630.c +++ /dev/null | |||
@@ -1,626 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int ov7630_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | int err = 0; | ||
29 | |||
30 | switch (sn9c102_get_bridge(cam)) { | ||
31 | case BRIDGE_SN9C101: | ||
32 | case BRIDGE_SN9C102: | ||
33 | err = sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, | ||
34 | {0x0f, 0x18}, {0x50, 0x19}); | ||
35 | |||
36 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); | ||
37 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); | ||
38 | err += sn9c102_i2c_write(cam, 0x11, 0x00); | ||
39 | err += sn9c102_i2c_write(cam, 0x15, 0x35); | ||
40 | err += sn9c102_i2c_write(cam, 0x16, 0x03); | ||
41 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); | ||
42 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); | ||
43 | err += sn9c102_i2c_write(cam, 0x19, 0x06); | ||
44 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); | ||
45 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | ||
46 | err += sn9c102_i2c_write(cam, 0x20, 0x44); | ||
47 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | ||
48 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | ||
49 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | ||
50 | err += sn9c102_i2c_write(cam, 0x28, 0x20); | ||
51 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | ||
52 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); | ||
53 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | ||
54 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | ||
55 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); | ||
56 | err += sn9c102_i2c_write(cam, 0x61, 0x42); | ||
57 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | ||
58 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | ||
59 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); | ||
60 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); | ||
61 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | ||
62 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | ||
63 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | ||
64 | break; | ||
65 | case BRIDGE_SN9C103: | ||
66 | err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, | ||
67 | {0x1a, 0x04}, {0x20, 0x05}, | ||
68 | {0x20, 0x06}, {0x20, 0x07}, | ||
69 | {0x03, 0x10}, {0x0a, 0x14}, | ||
70 | {0x60, 0x17}, {0x0f, 0x18}, | ||
71 | {0x50, 0x19}, {0x1d, 0x1a}, | ||
72 | {0x10, 0x1b}, {0x02, 0x1c}, | ||
73 | {0x03, 0x1d}, {0x0f, 0x1e}, | ||
74 | {0x0c, 0x1f}, {0x00, 0x20}, | ||
75 | {0x10, 0x21}, {0x20, 0x22}, | ||
76 | {0x30, 0x23}, {0x40, 0x24}, | ||
77 | {0x50, 0x25}, {0x60, 0x26}, | ||
78 | {0x70, 0x27}, {0x80, 0x28}, | ||
79 | {0x90, 0x29}, {0xa0, 0x2a}, | ||
80 | {0xb0, 0x2b}, {0xc0, 0x2c}, | ||
81 | {0xd0, 0x2d}, {0xe0, 0x2e}, | ||
82 | {0xf0, 0x2f}, {0xff, 0x30}); | ||
83 | |||
84 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); | ||
85 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); | ||
86 | err += sn9c102_i2c_write(cam, 0x15, 0x34); | ||
87 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
88 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | ||
89 | err += sn9c102_i2c_write(cam, 0x20, 0x44); | ||
90 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | ||
91 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | ||
92 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | ||
93 | err += sn9c102_i2c_write(cam, 0x28, 0x20); | ||
94 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | ||
95 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); | ||
96 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | ||
97 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | ||
98 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); | ||
99 | err += sn9c102_i2c_write(cam, 0x61, 0x42); | ||
100 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | ||
101 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | ||
102 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); | ||
103 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); | ||
104 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | ||
105 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | ||
106 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | ||
107 | break; | ||
108 | case BRIDGE_SN9C105: | ||
109 | case BRIDGE_SN9C120: | ||
110 | err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, | ||
111 | {0x1a, 0x04}, {0x03, 0x10}, | ||
112 | {0x0a, 0x14}, {0xe2, 0x17}, | ||
113 | {0x0b, 0x18}, {0x00, 0x19}, | ||
114 | {0x1d, 0x1a}, {0x10, 0x1b}, | ||
115 | {0x02, 0x1c}, {0x03, 0x1d}, | ||
116 | {0x0f, 0x1e}, {0x0c, 0x1f}, | ||
117 | {0x00, 0x20}, {0x24, 0x21}, | ||
118 | {0x3b, 0x22}, {0x47, 0x23}, | ||
119 | {0x60, 0x24}, {0x71, 0x25}, | ||
120 | {0x80, 0x26}, {0x8f, 0x27}, | ||
121 | {0x9d, 0x28}, {0xaa, 0x29}, | ||
122 | {0xb8, 0x2a}, {0xc4, 0x2b}, | ||
123 | {0xd1, 0x2c}, {0xdd, 0x2d}, | ||
124 | {0xe8, 0x2e}, {0xf4, 0x2f}, | ||
125 | {0xff, 0x30}, {0x00, 0x3f}, | ||
126 | {0xc7, 0x40}, {0x01, 0x41}, | ||
127 | {0x44, 0x42}, {0x00, 0x43}, | ||
128 | {0x44, 0x44}, {0x00, 0x45}, | ||
129 | {0x44, 0x46}, {0x00, 0x47}, | ||
130 | {0xc7, 0x48}, {0x01, 0x49}, | ||
131 | {0xc7, 0x4a}, {0x01, 0x4b}, | ||
132 | {0xc7, 0x4c}, {0x01, 0x4d}, | ||
133 | {0x44, 0x4e}, {0x00, 0x4f}, | ||
134 | {0x44, 0x50}, {0x00, 0x51}, | ||
135 | {0x44, 0x52}, {0x00, 0x53}, | ||
136 | {0xc7, 0x54}, {0x01, 0x55}, | ||
137 | {0xc7, 0x56}, {0x01, 0x57}, | ||
138 | {0xc7, 0x58}, {0x01, 0x59}, | ||
139 | {0x44, 0x5a}, {0x00, 0x5b}, | ||
140 | {0x44, 0x5c}, {0x00, 0x5d}, | ||
141 | {0x44, 0x5e}, {0x00, 0x5f}, | ||
142 | {0xc7, 0x60}, {0x01, 0x61}, | ||
143 | {0xc7, 0x62}, {0x01, 0x63}, | ||
144 | {0xc7, 0x64}, {0x01, 0x65}, | ||
145 | {0x44, 0x66}, {0x00, 0x67}, | ||
146 | {0x44, 0x68}, {0x00, 0x69}, | ||
147 | {0x44, 0x6a}, {0x00, 0x6b}, | ||
148 | {0xc7, 0x6c}, {0x01, 0x6d}, | ||
149 | {0xc7, 0x6e}, {0x01, 0x6f}, | ||
150 | {0xc7, 0x70}, {0x01, 0x71}, | ||
151 | {0x44, 0x72}, {0x00, 0x73}, | ||
152 | {0x44, 0x74}, {0x00, 0x75}, | ||
153 | {0x44, 0x76}, {0x00, 0x77}, | ||
154 | {0xc7, 0x78}, {0x01, 0x79}, | ||
155 | {0xc7, 0x7a}, {0x01, 0x7b}, | ||
156 | {0xc7, 0x7c}, {0x01, 0x7d}, | ||
157 | {0x44, 0x7e}, {0x00, 0x7f}, | ||
158 | {0x17, 0x84}, {0x00, 0x85}, | ||
159 | {0x2e, 0x86}, {0x00, 0x87}, | ||
160 | {0x09, 0x88}, {0x00, 0x89}, | ||
161 | {0xe8, 0x8a}, {0x0f, 0x8b}, | ||
162 | {0xda, 0x8c}, {0x0f, 0x8d}, | ||
163 | {0x40, 0x8e}, {0x00, 0x8f}, | ||
164 | {0x37, 0x90}, {0x00, 0x91}, | ||
165 | {0xcf, 0x92}, {0x0f, 0x93}, | ||
166 | {0xfa, 0x94}, {0x0f, 0x95}, | ||
167 | {0x00, 0x96}, {0x00, 0x97}, | ||
168 | {0x00, 0x98}, {0x66, 0x99}, | ||
169 | {0x00, 0x9a}, {0x40, 0x9b}, | ||
170 | {0x20, 0x9c}, {0x00, 0x9d}, | ||
171 | {0x00, 0x9e}, {0x00, 0x9f}, | ||
172 | {0x2d, 0xc0}, {0x2d, 0xc1}, | ||
173 | {0x3a, 0xc2}, {0x00, 0xc3}, | ||
174 | {0x04, 0xc4}, {0x3f, 0xc5}, | ||
175 | {0x00, 0xc6}, {0x00, 0xc7}, | ||
176 | {0x50, 0xc8}, {0x3c, 0xc9}, | ||
177 | {0x28, 0xca}, {0xd8, 0xcb}, | ||
178 | {0x14, 0xcc}, {0xec, 0xcd}, | ||
179 | {0x32, 0xce}, {0xdd, 0xcf}, | ||
180 | {0x32, 0xd0}, {0xdd, 0xd1}, | ||
181 | {0x6a, 0xd2}, {0x50, 0xd3}, | ||
182 | {0x60, 0xd4}, {0x00, 0xd5}, | ||
183 | {0x00, 0xd6}); | ||
184 | |||
185 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | ||
186 | err += sn9c102_i2c_write(cam, 0x12, 0x48); | ||
187 | err += sn9c102_i2c_write(cam, 0x01, 0x80); | ||
188 | err += sn9c102_i2c_write(cam, 0x02, 0x80); | ||
189 | err += sn9c102_i2c_write(cam, 0x03, 0x80); | ||
190 | err += sn9c102_i2c_write(cam, 0x04, 0x10); | ||
191 | err += sn9c102_i2c_write(cam, 0x05, 0x20); | ||
192 | err += sn9c102_i2c_write(cam, 0x06, 0x80); | ||
193 | err += sn9c102_i2c_write(cam, 0x11, 0x00); | ||
194 | err += sn9c102_i2c_write(cam, 0x0c, 0x20); | ||
195 | err += sn9c102_i2c_write(cam, 0x0d, 0x20); | ||
196 | err += sn9c102_i2c_write(cam, 0x15, 0x80); | ||
197 | err += sn9c102_i2c_write(cam, 0x16, 0x03); | ||
198 | err += sn9c102_i2c_write(cam, 0x17, 0x1b); | ||
199 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); | ||
200 | err += sn9c102_i2c_write(cam, 0x19, 0x05); | ||
201 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); | ||
202 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | ||
203 | err += sn9c102_i2c_write(cam, 0x21, 0x1b); | ||
204 | err += sn9c102_i2c_write(cam, 0x22, 0x00); | ||
205 | err += sn9c102_i2c_write(cam, 0x23, 0xde); | ||
206 | err += sn9c102_i2c_write(cam, 0x24, 0x10); | ||
207 | err += sn9c102_i2c_write(cam, 0x25, 0x8a); | ||
208 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | ||
209 | err += sn9c102_i2c_write(cam, 0x27, 0xca); | ||
210 | err += sn9c102_i2c_write(cam, 0x28, 0xa2); | ||
211 | err += sn9c102_i2c_write(cam, 0x29, 0x74); | ||
212 | err += sn9c102_i2c_write(cam, 0x2a, 0x88); | ||
213 | err += sn9c102_i2c_write(cam, 0x2b, 0x34); | ||
214 | err += sn9c102_i2c_write(cam, 0x2c, 0x88); | ||
215 | err += sn9c102_i2c_write(cam, 0x2e, 0x00); | ||
216 | err += sn9c102_i2c_write(cam, 0x2f, 0x00); | ||
217 | err += sn9c102_i2c_write(cam, 0x30, 0x00); | ||
218 | err += sn9c102_i2c_write(cam, 0x32, 0xc2); | ||
219 | err += sn9c102_i2c_write(cam, 0x33, 0x08); | ||
220 | err += sn9c102_i2c_write(cam, 0x4c, 0x40); | ||
221 | err += sn9c102_i2c_write(cam, 0x4d, 0xf3); | ||
222 | err += sn9c102_i2c_write(cam, 0x60, 0x05); | ||
223 | err += sn9c102_i2c_write(cam, 0x61, 0x40); | ||
224 | err += sn9c102_i2c_write(cam, 0x62, 0x12); | ||
225 | err += sn9c102_i2c_write(cam, 0x63, 0x57); | ||
226 | err += sn9c102_i2c_write(cam, 0x64, 0x73); | ||
227 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | ||
228 | err += sn9c102_i2c_write(cam, 0x66, 0x55); | ||
229 | err += sn9c102_i2c_write(cam, 0x67, 0x01); | ||
230 | err += sn9c102_i2c_write(cam, 0x68, 0xac); | ||
231 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | ||
232 | err += sn9c102_i2c_write(cam, 0x6f, 0x1f); | ||
233 | err += sn9c102_i2c_write(cam, 0x70, 0x01); | ||
234 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | ||
235 | err += sn9c102_i2c_write(cam, 0x72, 0x10); | ||
236 | err += sn9c102_i2c_write(cam, 0x73, 0x50); | ||
237 | err += sn9c102_i2c_write(cam, 0x74, 0x20); | ||
238 | err += sn9c102_i2c_write(cam, 0x76, 0x01); | ||
239 | err += sn9c102_i2c_write(cam, 0x77, 0xf3); | ||
240 | err += sn9c102_i2c_write(cam, 0x78, 0x90); | ||
241 | err += sn9c102_i2c_write(cam, 0x79, 0x98); | ||
242 | err += sn9c102_i2c_write(cam, 0x7a, 0x98); | ||
243 | err += sn9c102_i2c_write(cam, 0x7b, 0x00); | ||
244 | err += sn9c102_i2c_write(cam, 0x7c, 0x38); | ||
245 | err += sn9c102_i2c_write(cam, 0x7d, 0xff); | ||
246 | break; | ||
247 | default: | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | return err; | ||
252 | } | ||
253 | |||
254 | |||
255 | static int ov7630_get_ctrl(struct sn9c102_device* cam, | ||
256 | struct v4l2_control* ctrl) | ||
257 | { | ||
258 | enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); | ||
259 | int err = 0; | ||
260 | |||
261 | switch (ctrl->id) { | ||
262 | case V4L2_CID_EXPOSURE: | ||
263 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) | ||
264 | return -EIO; | ||
265 | break; | ||
266 | case V4L2_CID_RED_BALANCE: | ||
267 | if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) | ||
268 | ctrl->value = sn9c102_pread_reg(cam, 0x05); | ||
269 | else | ||
270 | ctrl->value = sn9c102_pread_reg(cam, 0x07); | ||
271 | break; | ||
272 | case V4L2_CID_BLUE_BALANCE: | ||
273 | ctrl->value = sn9c102_pread_reg(cam, 0x06); | ||
274 | break; | ||
275 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
276 | if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) | ||
277 | ctrl->value = sn9c102_pread_reg(cam, 0x07); | ||
278 | else | ||
279 | ctrl->value = sn9c102_pread_reg(cam, 0x05); | ||
280 | break; | ||
281 | break; | ||
282 | case V4L2_CID_GAIN: | ||
283 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) | ||
284 | return -EIO; | ||
285 | ctrl->value &= 0x3f; | ||
286 | break; | ||
287 | case V4L2_CID_DO_WHITE_BALANCE: | ||
288 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
289 | return -EIO; | ||
290 | ctrl->value &= 0x3f; | ||
291 | break; | ||
292 | case V4L2_CID_WHITENESS: | ||
293 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0) | ||
294 | return -EIO; | ||
295 | ctrl->value &= 0x3f; | ||
296 | break; | ||
297 | case V4L2_CID_AUTOGAIN: | ||
298 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) | ||
299 | return -EIO; | ||
300 | ctrl->value &= 0x01; | ||
301 | break; | ||
302 | case V4L2_CID_VFLIP: | ||
303 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0) | ||
304 | return -EIO; | ||
305 | ctrl->value = (ctrl->value & 0x80) ? 1 : 0; | ||
306 | break; | ||
307 | case SN9C102_V4L2_CID_GAMMA: | ||
308 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0) | ||
309 | return -EIO; | ||
310 | ctrl->value = (ctrl->value & 0x02) ? 1 : 0; | ||
311 | break; | ||
312 | case SN9C102_V4L2_CID_BAND_FILTER: | ||
313 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0) | ||
314 | return -EIO; | ||
315 | ctrl->value = (ctrl->value & 0x02) ? 1 : 0; | ||
316 | break; | ||
317 | default: | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | return err ? -EIO : 0; | ||
322 | } | ||
323 | |||
324 | |||
325 | static int ov7630_set_ctrl(struct sn9c102_device* cam, | ||
326 | const struct v4l2_control* ctrl) | ||
327 | { | ||
328 | enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); | ||
329 | int err = 0; | ||
330 | |||
331 | switch (ctrl->id) { | ||
332 | case V4L2_CID_EXPOSURE: | ||
333 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
334 | break; | ||
335 | case V4L2_CID_RED_BALANCE: | ||
336 | if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) | ||
337 | err += sn9c102_write_reg(cam, ctrl->value, 0x05); | ||
338 | else | ||
339 | err += sn9c102_write_reg(cam, ctrl->value, 0x07); | ||
340 | break; | ||
341 | case V4L2_CID_BLUE_BALANCE: | ||
342 | err += sn9c102_write_reg(cam, ctrl->value, 0x06); | ||
343 | break; | ||
344 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
345 | if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) | ||
346 | err += sn9c102_write_reg(cam, ctrl->value, 0x07); | ||
347 | else | ||
348 | err += sn9c102_write_reg(cam, ctrl->value, 0x05); | ||
349 | break; | ||
350 | case V4L2_CID_GAIN: | ||
351 | err += sn9c102_i2c_write(cam, 0x00, ctrl->value); | ||
352 | break; | ||
353 | case V4L2_CID_DO_WHITE_BALANCE: | ||
354 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
355 | break; | ||
356 | case V4L2_CID_WHITENESS: | ||
357 | err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); | ||
358 | break; | ||
359 | case V4L2_CID_AUTOGAIN: | ||
360 | err += sn9c102_i2c_write(cam, 0x13, ctrl->value | | ||
361 | (ctrl->value << 1)); | ||
362 | break; | ||
363 | case V4L2_CID_VFLIP: | ||
364 | err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); | ||
365 | break; | ||
366 | case SN9C102_V4L2_CID_GAMMA: | ||
367 | err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2); | ||
368 | break; | ||
369 | case SN9C102_V4L2_CID_BAND_FILTER: | ||
370 | err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); | ||
371 | break; | ||
372 | default: | ||
373 | return -EINVAL; | ||
374 | } | ||
375 | |||
376 | return err ? -EIO : 0; | ||
377 | } | ||
378 | |||
379 | |||
380 | static int ov7630_set_crop(struct sn9c102_device* cam, | ||
381 | const struct v4l2_rect* rect) | ||
382 | { | ||
383 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
384 | int err = 0; | ||
385 | u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
386 | |||
387 | switch (sn9c102_get_bridge(cam)) { | ||
388 | case BRIDGE_SN9C101: | ||
389 | case BRIDGE_SN9C102: | ||
390 | case BRIDGE_SN9C103: | ||
391 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; | ||
392 | break; | ||
393 | case BRIDGE_SN9C105: | ||
394 | case BRIDGE_SN9C120: | ||
395 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; | ||
396 | break; | ||
397 | default: | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
402 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
403 | |||
404 | return err; | ||
405 | } | ||
406 | |||
407 | |||
408 | static int ov7630_set_pix_format(struct sn9c102_device* cam, | ||
409 | const struct v4l2_pix_format* pix) | ||
410 | { | ||
411 | int err = 0; | ||
412 | |||
413 | switch (sn9c102_get_bridge(cam)) { | ||
414 | case BRIDGE_SN9C101: | ||
415 | case BRIDGE_SN9C102: | ||
416 | case BRIDGE_SN9C103: | ||
417 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) | ||
418 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
419 | else | ||
420 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
421 | break; | ||
422 | case BRIDGE_SN9C105: | ||
423 | case BRIDGE_SN9C120: | ||
424 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
425 | err += sn9c102_write_reg(cam, 0xe5, 0x17); | ||
426 | err += sn9c102_i2c_write(cam, 0x11, 0x04); | ||
427 | } else { | ||
428 | err += sn9c102_write_reg(cam, 0xe2, 0x17); | ||
429 | err += sn9c102_i2c_write(cam, 0x11, 0x02); | ||
430 | } | ||
431 | break; | ||
432 | default: | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | return err; | ||
437 | } | ||
438 | |||
439 | |||
440 | static const struct sn9c102_sensor ov7630 = { | ||
441 | .name = "OV7630", | ||
442 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
443 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 | | ||
444 | BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
445 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
446 | .frequency = SN9C102_I2C_100KHZ, | ||
447 | .interface = SN9C102_I2C_2WIRES, | ||
448 | .i2c_slave_id = 0x21, | ||
449 | .init = &ov7630_init, | ||
450 | .qctrl = { | ||
451 | { | ||
452 | .id = V4L2_CID_GAIN, | ||
453 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
454 | .name = "global gain", | ||
455 | .minimum = 0x00, | ||
456 | .maximum = 0x3f, | ||
457 | .step = 0x01, | ||
458 | .default_value = 0x14, | ||
459 | .flags = 0, | ||
460 | }, | ||
461 | { | ||
462 | .id = V4L2_CID_EXPOSURE, | ||
463 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
464 | .name = "exposure", | ||
465 | .minimum = 0x00, | ||
466 | .maximum = 0xff, | ||
467 | .step = 0x01, | ||
468 | .default_value = 0x60, | ||
469 | .flags = 0, | ||
470 | }, | ||
471 | { | ||
472 | .id = V4L2_CID_WHITENESS, | ||
473 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
474 | .name = "white balance background: red", | ||
475 | .minimum = 0x00, | ||
476 | .maximum = 0x3f, | ||
477 | .step = 0x01, | ||
478 | .default_value = 0x20, | ||
479 | .flags = 0, | ||
480 | }, | ||
481 | { | ||
482 | .id = V4L2_CID_DO_WHITE_BALANCE, | ||
483 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
484 | .name = "white balance background: blue", | ||
485 | .minimum = 0x00, | ||
486 | .maximum = 0x3f, | ||
487 | .step = 0x01, | ||
488 | .default_value = 0x20, | ||
489 | .flags = 0, | ||
490 | }, | ||
491 | { | ||
492 | .id = V4L2_CID_RED_BALANCE, | ||
493 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
494 | .name = "red balance", | ||
495 | .minimum = 0x00, | ||
496 | .maximum = 0x7f, | ||
497 | .step = 0x01, | ||
498 | .default_value = 0x20, | ||
499 | .flags = 0, | ||
500 | }, | ||
501 | { | ||
502 | .id = V4L2_CID_BLUE_BALANCE, | ||
503 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
504 | .name = "blue balance", | ||
505 | .minimum = 0x00, | ||
506 | .maximum = 0x7f, | ||
507 | .step = 0x01, | ||
508 | .default_value = 0x20, | ||
509 | .flags = 0, | ||
510 | }, | ||
511 | { | ||
512 | .id = V4L2_CID_AUTOGAIN, | ||
513 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
514 | .name = "auto adjust", | ||
515 | .minimum = 0x00, | ||
516 | .maximum = 0x01, | ||
517 | .step = 0x01, | ||
518 | .default_value = 0x00, | ||
519 | .flags = 0, | ||
520 | }, | ||
521 | { | ||
522 | .id = V4L2_CID_VFLIP, | ||
523 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
524 | .name = "vertical flip", | ||
525 | .minimum = 0x00, | ||
526 | .maximum = 0x01, | ||
527 | .step = 0x01, | ||
528 | .default_value = 0x01, | ||
529 | .flags = 0, | ||
530 | }, | ||
531 | { | ||
532 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
533 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
534 | .name = "green balance", | ||
535 | .minimum = 0x00, | ||
536 | .maximum = 0x7f, | ||
537 | .step = 0x01, | ||
538 | .default_value = 0x20, | ||
539 | .flags = 0, | ||
540 | }, | ||
541 | { | ||
542 | .id = SN9C102_V4L2_CID_BAND_FILTER, | ||
543 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
544 | .name = "band filter", | ||
545 | .minimum = 0x00, | ||
546 | .maximum = 0x01, | ||
547 | .step = 0x01, | ||
548 | .default_value = 0x00, | ||
549 | .flags = 0, | ||
550 | }, | ||
551 | { | ||
552 | .id = SN9C102_V4L2_CID_GAMMA, | ||
553 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
554 | .name = "rgb gamma", | ||
555 | .minimum = 0x00, | ||
556 | .maximum = 0x01, | ||
557 | .step = 0x01, | ||
558 | .default_value = 0x00, | ||
559 | .flags = 0, | ||
560 | }, | ||
561 | }, | ||
562 | .get_ctrl = &ov7630_get_ctrl, | ||
563 | .set_ctrl = &ov7630_set_ctrl, | ||
564 | .cropcap = { | ||
565 | .bounds = { | ||
566 | .left = 0, | ||
567 | .top = 0, | ||
568 | .width = 640, | ||
569 | .height = 480, | ||
570 | }, | ||
571 | .defrect = { | ||
572 | .left = 0, | ||
573 | .top = 0, | ||
574 | .width = 640, | ||
575 | .height = 480, | ||
576 | }, | ||
577 | }, | ||
578 | .set_crop = &ov7630_set_crop, | ||
579 | .pix_format = { | ||
580 | .width = 640, | ||
581 | .height = 480, | ||
582 | .pixelformat = V4L2_PIX_FMT_SN9C10X, | ||
583 | .priv = 8, | ||
584 | }, | ||
585 | .set_pix_format = &ov7630_set_pix_format | ||
586 | }; | ||
587 | |||
588 | |||
589 | int sn9c102_probe_ov7630(struct sn9c102_device* cam) | ||
590 | { | ||
591 | int pid, ver, err = 0; | ||
592 | |||
593 | switch (sn9c102_get_bridge(cam)) { | ||
594 | case BRIDGE_SN9C101: | ||
595 | case BRIDGE_SN9C102: | ||
596 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, | ||
597 | {0x28, 0x17}); | ||
598 | break; | ||
599 | case BRIDGE_SN9C103: /* do _not_ change anything! */ | ||
600 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x42, 0x01}, | ||
601 | {0x28, 0x17}, {0x44, 0x02}); | ||
602 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); | ||
603 | if (err || pid < 0) /* try a different initialization */ | ||
604 | err += sn9c102_write_const_regs(cam, {0x01, 0x01}, | ||
605 | {0x00, 0x01}); | ||
606 | break; | ||
607 | case BRIDGE_SN9C105: | ||
608 | case BRIDGE_SN9C120: | ||
609 | err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, | ||
610 | {0x29, 0x01}, {0x74, 0x02}, | ||
611 | {0x0e, 0x01}, {0x44, 0x01}); | ||
612 | break; | ||
613 | default: | ||
614 | break; | ||
615 | } | ||
616 | |||
617 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); | ||
618 | ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b); | ||
619 | if (err || pid < 0 || ver < 0) | ||
620 | return -EIO; | ||
621 | if (pid != 0x76 || ver != 0x31) | ||
622 | return -ENODEV; | ||
623 | sn9c102_attach_sensor(cam, &ov7630); | ||
624 | |||
625 | return 0; | ||
626 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_ov7660.c b/drivers/media/usb/sn9c102/sn9c102_ov7660.c deleted file mode 100644 index 7977795d342b..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_ov7660.c +++ /dev/null | |||
@@ -1,538 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int ov7660_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | int err = 0; | ||
29 | |||
30 | err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, | ||
31 | {0x1a, 0x04}, {0x03, 0x10}, | ||
32 | {0x08, 0x14}, {0x20, 0x17}, | ||
33 | {0x8b, 0x18}, {0x00, 0x19}, | ||
34 | {0x1d, 0x1a}, {0x10, 0x1b}, | ||
35 | {0x02, 0x1c}, {0x03, 0x1d}, | ||
36 | {0x0f, 0x1e}, {0x0c, 0x1f}, | ||
37 | {0x00, 0x20}, {0x29, 0x21}, | ||
38 | {0x40, 0x22}, {0x54, 0x23}, | ||
39 | {0x66, 0x24}, {0x76, 0x25}, | ||
40 | {0x85, 0x26}, {0x94, 0x27}, | ||
41 | {0xa1, 0x28}, {0xae, 0x29}, | ||
42 | {0xbb, 0x2a}, {0xc7, 0x2b}, | ||
43 | {0xd3, 0x2c}, {0xde, 0x2d}, | ||
44 | {0xea, 0x2e}, {0xf4, 0x2f}, | ||
45 | {0xff, 0x30}, {0x00, 0x3f}, | ||
46 | {0xc7, 0x40}, {0x01, 0x41}, | ||
47 | {0x44, 0x42}, {0x00, 0x43}, | ||
48 | {0x44, 0x44}, {0x00, 0x45}, | ||
49 | {0x44, 0x46}, {0x00, 0x47}, | ||
50 | {0xc7, 0x48}, {0x01, 0x49}, | ||
51 | {0xc7, 0x4a}, {0x01, 0x4b}, | ||
52 | {0xc7, 0x4c}, {0x01, 0x4d}, | ||
53 | {0x44, 0x4e}, {0x00, 0x4f}, | ||
54 | {0x44, 0x50}, {0x00, 0x51}, | ||
55 | {0x44, 0x52}, {0x00, 0x53}, | ||
56 | {0xc7, 0x54}, {0x01, 0x55}, | ||
57 | {0xc7, 0x56}, {0x01, 0x57}, | ||
58 | {0xc7, 0x58}, {0x01, 0x59}, | ||
59 | {0x44, 0x5a}, {0x00, 0x5b}, | ||
60 | {0x44, 0x5c}, {0x00, 0x5d}, | ||
61 | {0x44, 0x5e}, {0x00, 0x5f}, | ||
62 | {0xc7, 0x60}, {0x01, 0x61}, | ||
63 | {0xc7, 0x62}, {0x01, 0x63}, | ||
64 | {0xc7, 0x64}, {0x01, 0x65}, | ||
65 | {0x44, 0x66}, {0x00, 0x67}, | ||
66 | {0x44, 0x68}, {0x00, 0x69}, | ||
67 | {0x44, 0x6a}, {0x00, 0x6b}, | ||
68 | {0xc7, 0x6c}, {0x01, 0x6d}, | ||
69 | {0xc7, 0x6e}, {0x01, 0x6f}, | ||
70 | {0xc7, 0x70}, {0x01, 0x71}, | ||
71 | {0x44, 0x72}, {0x00, 0x73}, | ||
72 | {0x44, 0x74}, {0x00, 0x75}, | ||
73 | {0x44, 0x76}, {0x00, 0x77}, | ||
74 | {0xc7, 0x78}, {0x01, 0x79}, | ||
75 | {0xc7, 0x7a}, {0x01, 0x7b}, | ||
76 | {0xc7, 0x7c}, {0x01, 0x7d}, | ||
77 | {0x44, 0x7e}, {0x00, 0x7f}, | ||
78 | {0x14, 0x84}, {0x00, 0x85}, | ||
79 | {0x27, 0x86}, {0x00, 0x87}, | ||
80 | {0x07, 0x88}, {0x00, 0x89}, | ||
81 | {0xec, 0x8a}, {0x0f, 0x8b}, | ||
82 | {0xd8, 0x8c}, {0x0f, 0x8d}, | ||
83 | {0x3d, 0x8e}, {0x00, 0x8f}, | ||
84 | {0x3d, 0x90}, {0x00, 0x91}, | ||
85 | {0xcd, 0x92}, {0x0f, 0x93}, | ||
86 | {0xf7, 0x94}, {0x0f, 0x95}, | ||
87 | {0x0c, 0x96}, {0x00, 0x97}, | ||
88 | {0x00, 0x98}, {0x66, 0x99}, | ||
89 | {0x05, 0x9a}, {0x00, 0x9b}, | ||
90 | {0x04, 0x9c}, {0x00, 0x9d}, | ||
91 | {0x08, 0x9e}, {0x00, 0x9f}, | ||
92 | {0x2d, 0xc0}, {0x2d, 0xc1}, | ||
93 | {0x3a, 0xc2}, {0x05, 0xc3}, | ||
94 | {0x04, 0xc4}, {0x3f, 0xc5}, | ||
95 | {0x00, 0xc6}, {0x00, 0xc7}, | ||
96 | {0x50, 0xc8}, {0x3C, 0xc9}, | ||
97 | {0x28, 0xca}, {0xd8, 0xcb}, | ||
98 | {0x14, 0xcc}, {0xec, 0xcd}, | ||
99 | {0x32, 0xce}, {0xdd, 0xcf}, | ||
100 | {0x32, 0xd0}, {0xdd, 0xd1}, | ||
101 | {0x6a, 0xd2}, {0x50, 0xd3}, | ||
102 | {0x00, 0xd4}, {0x00, 0xd5}, | ||
103 | {0x00, 0xd6}); | ||
104 | |||
105 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | ||
106 | err += sn9c102_i2c_write(cam, 0x11, 0x09); | ||
107 | err += sn9c102_i2c_write(cam, 0x00, 0x0A); | ||
108 | err += sn9c102_i2c_write(cam, 0x01, 0x80); | ||
109 | err += sn9c102_i2c_write(cam, 0x02, 0x80); | ||
110 | err += sn9c102_i2c_write(cam, 0x03, 0x00); | ||
111 | err += sn9c102_i2c_write(cam, 0x04, 0x00); | ||
112 | err += sn9c102_i2c_write(cam, 0x05, 0x08); | ||
113 | err += sn9c102_i2c_write(cam, 0x06, 0x0B); | ||
114 | err += sn9c102_i2c_write(cam, 0x07, 0x00); | ||
115 | err += sn9c102_i2c_write(cam, 0x08, 0x1C); | ||
116 | err += sn9c102_i2c_write(cam, 0x09, 0x01); | ||
117 | err += sn9c102_i2c_write(cam, 0x0A, 0x76); | ||
118 | err += sn9c102_i2c_write(cam, 0x0B, 0x60); | ||
119 | err += sn9c102_i2c_write(cam, 0x0C, 0x00); | ||
120 | err += sn9c102_i2c_write(cam, 0x0D, 0x08); | ||
121 | err += sn9c102_i2c_write(cam, 0x0E, 0x04); | ||
122 | err += sn9c102_i2c_write(cam, 0x0F, 0x6F); | ||
123 | err += sn9c102_i2c_write(cam, 0x10, 0x20); | ||
124 | err += sn9c102_i2c_write(cam, 0x11, 0x03); | ||
125 | err += sn9c102_i2c_write(cam, 0x12, 0x05); | ||
126 | err += sn9c102_i2c_write(cam, 0x13, 0xC7); | ||
127 | err += sn9c102_i2c_write(cam, 0x14, 0x2C); | ||
128 | err += sn9c102_i2c_write(cam, 0x15, 0x00); | ||
129 | err += sn9c102_i2c_write(cam, 0x16, 0x02); | ||
130 | err += sn9c102_i2c_write(cam, 0x17, 0x10); | ||
131 | err += sn9c102_i2c_write(cam, 0x18, 0x60); | ||
132 | err += sn9c102_i2c_write(cam, 0x19, 0x02); | ||
133 | err += sn9c102_i2c_write(cam, 0x1A, 0x7B); | ||
134 | err += sn9c102_i2c_write(cam, 0x1B, 0x02); | ||
135 | err += sn9c102_i2c_write(cam, 0x1C, 0x7F); | ||
136 | err += sn9c102_i2c_write(cam, 0x1D, 0xA2); | ||
137 | err += sn9c102_i2c_write(cam, 0x1E, 0x01); | ||
138 | err += sn9c102_i2c_write(cam, 0x1F, 0x0E); | ||
139 | err += sn9c102_i2c_write(cam, 0x20, 0x05); | ||
140 | err += sn9c102_i2c_write(cam, 0x21, 0x05); | ||
141 | err += sn9c102_i2c_write(cam, 0x22, 0x05); | ||
142 | err += sn9c102_i2c_write(cam, 0x23, 0x05); | ||
143 | err += sn9c102_i2c_write(cam, 0x24, 0x68); | ||
144 | err += sn9c102_i2c_write(cam, 0x25, 0x58); | ||
145 | err += sn9c102_i2c_write(cam, 0x26, 0xD4); | ||
146 | err += sn9c102_i2c_write(cam, 0x27, 0x80); | ||
147 | err += sn9c102_i2c_write(cam, 0x28, 0x80); | ||
148 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | ||
149 | err += sn9c102_i2c_write(cam, 0x2A, 0x00); | ||
150 | err += sn9c102_i2c_write(cam, 0x2B, 0x00); | ||
151 | err += sn9c102_i2c_write(cam, 0x2C, 0x80); | ||
152 | err += sn9c102_i2c_write(cam, 0x2D, 0x00); | ||
153 | err += sn9c102_i2c_write(cam, 0x2E, 0x00); | ||
154 | err += sn9c102_i2c_write(cam, 0x2F, 0x0E); | ||
155 | err += sn9c102_i2c_write(cam, 0x30, 0x08); | ||
156 | err += sn9c102_i2c_write(cam, 0x31, 0x30); | ||
157 | err += sn9c102_i2c_write(cam, 0x32, 0xB4); | ||
158 | err += sn9c102_i2c_write(cam, 0x33, 0x00); | ||
159 | err += sn9c102_i2c_write(cam, 0x34, 0x07); | ||
160 | err += sn9c102_i2c_write(cam, 0x35, 0x84); | ||
161 | err += sn9c102_i2c_write(cam, 0x36, 0x00); | ||
162 | err += sn9c102_i2c_write(cam, 0x37, 0x0C); | ||
163 | err += sn9c102_i2c_write(cam, 0x38, 0x02); | ||
164 | err += sn9c102_i2c_write(cam, 0x39, 0x43); | ||
165 | err += sn9c102_i2c_write(cam, 0x3A, 0x00); | ||
166 | err += sn9c102_i2c_write(cam, 0x3B, 0x0A); | ||
167 | err += sn9c102_i2c_write(cam, 0x3C, 0x6C); | ||
168 | err += sn9c102_i2c_write(cam, 0x3D, 0x99); | ||
169 | err += sn9c102_i2c_write(cam, 0x3E, 0x0E); | ||
170 | err += sn9c102_i2c_write(cam, 0x3F, 0x41); | ||
171 | err += sn9c102_i2c_write(cam, 0x40, 0xC1); | ||
172 | err += sn9c102_i2c_write(cam, 0x41, 0x22); | ||
173 | err += sn9c102_i2c_write(cam, 0x42, 0x08); | ||
174 | err += sn9c102_i2c_write(cam, 0x43, 0xF0); | ||
175 | err += sn9c102_i2c_write(cam, 0x44, 0x10); | ||
176 | err += sn9c102_i2c_write(cam, 0x45, 0x78); | ||
177 | err += sn9c102_i2c_write(cam, 0x46, 0xA8); | ||
178 | err += sn9c102_i2c_write(cam, 0x47, 0x60); | ||
179 | err += sn9c102_i2c_write(cam, 0x48, 0x80); | ||
180 | err += sn9c102_i2c_write(cam, 0x49, 0x00); | ||
181 | err += sn9c102_i2c_write(cam, 0x4A, 0x00); | ||
182 | err += sn9c102_i2c_write(cam, 0x4B, 0x00); | ||
183 | err += sn9c102_i2c_write(cam, 0x4C, 0x00); | ||
184 | err += sn9c102_i2c_write(cam, 0x4D, 0x00); | ||
185 | err += sn9c102_i2c_write(cam, 0x4E, 0x00); | ||
186 | err += sn9c102_i2c_write(cam, 0x4F, 0x46); | ||
187 | err += sn9c102_i2c_write(cam, 0x50, 0x36); | ||
188 | err += sn9c102_i2c_write(cam, 0x51, 0x0F); | ||
189 | err += sn9c102_i2c_write(cam, 0x52, 0x17); | ||
190 | err += sn9c102_i2c_write(cam, 0x53, 0x7F); | ||
191 | err += sn9c102_i2c_write(cam, 0x54, 0x96); | ||
192 | err += sn9c102_i2c_write(cam, 0x55, 0x40); | ||
193 | err += sn9c102_i2c_write(cam, 0x56, 0x40); | ||
194 | err += sn9c102_i2c_write(cam, 0x57, 0x40); | ||
195 | err += sn9c102_i2c_write(cam, 0x58, 0x0F); | ||
196 | err += sn9c102_i2c_write(cam, 0x59, 0xBA); | ||
197 | err += sn9c102_i2c_write(cam, 0x5A, 0x9A); | ||
198 | err += sn9c102_i2c_write(cam, 0x5B, 0x22); | ||
199 | err += sn9c102_i2c_write(cam, 0x5C, 0xB9); | ||
200 | err += sn9c102_i2c_write(cam, 0x5D, 0x9B); | ||
201 | err += sn9c102_i2c_write(cam, 0x5E, 0x10); | ||
202 | err += sn9c102_i2c_write(cam, 0x5F, 0xF0); | ||
203 | err += sn9c102_i2c_write(cam, 0x60, 0x05); | ||
204 | err += sn9c102_i2c_write(cam, 0x61, 0x60); | ||
205 | err += sn9c102_i2c_write(cam, 0x62, 0x00); | ||
206 | err += sn9c102_i2c_write(cam, 0x63, 0x00); | ||
207 | err += sn9c102_i2c_write(cam, 0x64, 0x50); | ||
208 | err += sn9c102_i2c_write(cam, 0x65, 0x30); | ||
209 | err += sn9c102_i2c_write(cam, 0x66, 0x00); | ||
210 | err += sn9c102_i2c_write(cam, 0x67, 0x80); | ||
211 | err += sn9c102_i2c_write(cam, 0x68, 0x7A); | ||
212 | err += sn9c102_i2c_write(cam, 0x69, 0x90); | ||
213 | err += sn9c102_i2c_write(cam, 0x6A, 0x80); | ||
214 | err += sn9c102_i2c_write(cam, 0x6B, 0x0A); | ||
215 | err += sn9c102_i2c_write(cam, 0x6C, 0x30); | ||
216 | err += sn9c102_i2c_write(cam, 0x6D, 0x48); | ||
217 | err += sn9c102_i2c_write(cam, 0x6E, 0x80); | ||
218 | err += sn9c102_i2c_write(cam, 0x6F, 0x74); | ||
219 | err += sn9c102_i2c_write(cam, 0x70, 0x64); | ||
220 | err += sn9c102_i2c_write(cam, 0x71, 0x60); | ||
221 | err += sn9c102_i2c_write(cam, 0x72, 0x5C); | ||
222 | err += sn9c102_i2c_write(cam, 0x73, 0x58); | ||
223 | err += sn9c102_i2c_write(cam, 0x74, 0x54); | ||
224 | err += sn9c102_i2c_write(cam, 0x75, 0x4C); | ||
225 | err += sn9c102_i2c_write(cam, 0x76, 0x40); | ||
226 | err += sn9c102_i2c_write(cam, 0x77, 0x38); | ||
227 | err += sn9c102_i2c_write(cam, 0x78, 0x34); | ||
228 | err += sn9c102_i2c_write(cam, 0x79, 0x30); | ||
229 | err += sn9c102_i2c_write(cam, 0x7A, 0x2F); | ||
230 | err += sn9c102_i2c_write(cam, 0x7B, 0x2B); | ||
231 | err += sn9c102_i2c_write(cam, 0x7C, 0x03); | ||
232 | err += sn9c102_i2c_write(cam, 0x7D, 0x07); | ||
233 | err += sn9c102_i2c_write(cam, 0x7E, 0x17); | ||
234 | err += sn9c102_i2c_write(cam, 0x7F, 0x34); | ||
235 | err += sn9c102_i2c_write(cam, 0x80, 0x41); | ||
236 | err += sn9c102_i2c_write(cam, 0x81, 0x4D); | ||
237 | err += sn9c102_i2c_write(cam, 0x82, 0x58); | ||
238 | err += sn9c102_i2c_write(cam, 0x83, 0x63); | ||
239 | err += sn9c102_i2c_write(cam, 0x84, 0x6E); | ||
240 | err += sn9c102_i2c_write(cam, 0x85, 0x77); | ||
241 | err += sn9c102_i2c_write(cam, 0x86, 0x87); | ||
242 | err += sn9c102_i2c_write(cam, 0x87, 0x95); | ||
243 | err += sn9c102_i2c_write(cam, 0x88, 0xAF); | ||
244 | err += sn9c102_i2c_write(cam, 0x89, 0xC7); | ||
245 | err += sn9c102_i2c_write(cam, 0x8A, 0xDF); | ||
246 | err += sn9c102_i2c_write(cam, 0x8B, 0x99); | ||
247 | err += sn9c102_i2c_write(cam, 0x8C, 0x99); | ||
248 | err += sn9c102_i2c_write(cam, 0x8D, 0xCF); | ||
249 | err += sn9c102_i2c_write(cam, 0x8E, 0x20); | ||
250 | err += sn9c102_i2c_write(cam, 0x8F, 0x26); | ||
251 | err += sn9c102_i2c_write(cam, 0x90, 0x10); | ||
252 | err += sn9c102_i2c_write(cam, 0x91, 0x0C); | ||
253 | err += sn9c102_i2c_write(cam, 0x92, 0x25); | ||
254 | err += sn9c102_i2c_write(cam, 0x93, 0x00); | ||
255 | err += sn9c102_i2c_write(cam, 0x94, 0x50); | ||
256 | err += sn9c102_i2c_write(cam, 0x95, 0x50); | ||
257 | err += sn9c102_i2c_write(cam, 0x96, 0x00); | ||
258 | err += sn9c102_i2c_write(cam, 0x97, 0x01); | ||
259 | err += sn9c102_i2c_write(cam, 0x98, 0x10); | ||
260 | err += sn9c102_i2c_write(cam, 0x99, 0x40); | ||
261 | err += sn9c102_i2c_write(cam, 0x9A, 0x40); | ||
262 | err += sn9c102_i2c_write(cam, 0x9B, 0x20); | ||
263 | err += sn9c102_i2c_write(cam, 0x9C, 0x00); | ||
264 | err += sn9c102_i2c_write(cam, 0x9D, 0x99); | ||
265 | err += sn9c102_i2c_write(cam, 0x9E, 0x7F); | ||
266 | err += sn9c102_i2c_write(cam, 0x9F, 0x00); | ||
267 | err += sn9c102_i2c_write(cam, 0xA0, 0x00); | ||
268 | err += sn9c102_i2c_write(cam, 0xA1, 0x00); | ||
269 | |||
270 | return err; | ||
271 | } | ||
272 | |||
273 | |||
274 | static int ov7660_get_ctrl(struct sn9c102_device* cam, | ||
275 | struct v4l2_control* ctrl) | ||
276 | { | ||
277 | int err = 0; | ||
278 | |||
279 | switch (ctrl->id) { | ||
280 | case V4L2_CID_EXPOSURE: | ||
281 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) | ||
282 | return -EIO; | ||
283 | break; | ||
284 | case V4L2_CID_DO_WHITE_BALANCE: | ||
285 | if ((ctrl->value = sn9c102_read_reg(cam, 0x02)) < 0) | ||
286 | return -EIO; | ||
287 | ctrl->value = (ctrl->value & 0x04) ? 1 : 0; | ||
288 | break; | ||
289 | case V4L2_CID_RED_BALANCE: | ||
290 | if ((ctrl->value = sn9c102_read_reg(cam, 0x05)) < 0) | ||
291 | return -EIO; | ||
292 | ctrl->value &= 0x7f; | ||
293 | break; | ||
294 | case V4L2_CID_BLUE_BALANCE: | ||
295 | if ((ctrl->value = sn9c102_read_reg(cam, 0x06)) < 0) | ||
296 | return -EIO; | ||
297 | ctrl->value &= 0x7f; | ||
298 | break; | ||
299 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
300 | if ((ctrl->value = sn9c102_read_reg(cam, 0x07)) < 0) | ||
301 | return -EIO; | ||
302 | ctrl->value &= 0x7f; | ||
303 | break; | ||
304 | case SN9C102_V4L2_CID_BAND_FILTER: | ||
305 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x3b)) < 0) | ||
306 | return -EIO; | ||
307 | ctrl->value &= 0x08; | ||
308 | break; | ||
309 | case V4L2_CID_GAIN: | ||
310 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) | ||
311 | return -EIO; | ||
312 | ctrl->value &= 0x1f; | ||
313 | break; | ||
314 | case V4L2_CID_AUTOGAIN: | ||
315 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) | ||
316 | return -EIO; | ||
317 | ctrl->value &= 0x01; | ||
318 | break; | ||
319 | default: | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | return err ? -EIO : 0; | ||
324 | } | ||
325 | |||
326 | |||
327 | static int ov7660_set_ctrl(struct sn9c102_device* cam, | ||
328 | const struct v4l2_control* ctrl) | ||
329 | { | ||
330 | int err = 0; | ||
331 | |||
332 | switch (ctrl->id) { | ||
333 | case V4L2_CID_EXPOSURE: | ||
334 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
335 | break; | ||
336 | case V4L2_CID_DO_WHITE_BALANCE: | ||
337 | err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02); | ||
338 | break; | ||
339 | case V4L2_CID_RED_BALANCE: | ||
340 | err += sn9c102_write_reg(cam, ctrl->value, 0x05); | ||
341 | break; | ||
342 | case V4L2_CID_BLUE_BALANCE: | ||
343 | err += sn9c102_write_reg(cam, ctrl->value, 0x06); | ||
344 | break; | ||
345 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
346 | err += sn9c102_write_reg(cam, ctrl->value, 0x07); | ||
347 | break; | ||
348 | case SN9C102_V4L2_CID_BAND_FILTER: | ||
349 | err += sn9c102_i2c_write(cam, ctrl->value << 3, 0x3b); | ||
350 | break; | ||
351 | case V4L2_CID_GAIN: | ||
352 | err += sn9c102_i2c_write(cam, 0x00, 0x60 + ctrl->value); | ||
353 | break; | ||
354 | case V4L2_CID_AUTOGAIN: | ||
355 | err += sn9c102_i2c_write(cam, 0x13, 0xc0 | | ||
356 | (ctrl->value * 0x07)); | ||
357 | break; | ||
358 | default: | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | |||
362 | return err ? -EIO : 0; | ||
363 | } | ||
364 | |||
365 | |||
366 | static int ov7660_set_crop(struct sn9c102_device* cam, | ||
367 | const struct v4l2_rect* rect) | ||
368 | { | ||
369 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
370 | int err = 0; | ||
371 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, | ||
372 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
373 | |||
374 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
375 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
376 | |||
377 | return err; | ||
378 | } | ||
379 | |||
380 | |||
381 | static int ov7660_set_pix_format(struct sn9c102_device* cam, | ||
382 | const struct v4l2_pix_format* pix) | ||
383 | { | ||
384 | int r0, err = 0; | ||
385 | |||
386 | r0 = sn9c102_pread_reg(cam, 0x01); | ||
387 | |||
388 | if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { | ||
389 | err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); | ||
390 | err += sn9c102_write_reg(cam, 0xa2, 0x17); | ||
391 | err += sn9c102_i2c_write(cam, 0x11, 0x00); | ||
392 | } else { | ||
393 | err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); | ||
394 | err += sn9c102_write_reg(cam, 0xa2, 0x17); | ||
395 | err += sn9c102_i2c_write(cam, 0x11, 0x0d); | ||
396 | } | ||
397 | |||
398 | return err; | ||
399 | } | ||
400 | |||
401 | |||
402 | static const struct sn9c102_sensor ov7660 = { | ||
403 | .name = "OV7660", | ||
404 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
405 | .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
406 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
407 | .frequency = SN9C102_I2C_100KHZ, | ||
408 | .interface = SN9C102_I2C_2WIRES, | ||
409 | .i2c_slave_id = 0x21, | ||
410 | .init = &ov7660_init, | ||
411 | .qctrl = { | ||
412 | { | ||
413 | .id = V4L2_CID_GAIN, | ||
414 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
415 | .name = "global gain", | ||
416 | .minimum = 0x00, | ||
417 | .maximum = 0x1f, | ||
418 | .step = 0x01, | ||
419 | .default_value = 0x09, | ||
420 | .flags = 0, | ||
421 | }, | ||
422 | { | ||
423 | .id = V4L2_CID_EXPOSURE, | ||
424 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
425 | .name = "exposure", | ||
426 | .minimum = 0x00, | ||
427 | .maximum = 0xff, | ||
428 | .step = 0x01, | ||
429 | .default_value = 0x27, | ||
430 | .flags = 0, | ||
431 | }, | ||
432 | { | ||
433 | .id = V4L2_CID_DO_WHITE_BALANCE, | ||
434 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
435 | .name = "night mode", | ||
436 | .minimum = 0x00, | ||
437 | .maximum = 0x01, | ||
438 | .step = 0x01, | ||
439 | .default_value = 0x00, | ||
440 | .flags = 0, | ||
441 | }, | ||
442 | { | ||
443 | .id = V4L2_CID_RED_BALANCE, | ||
444 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
445 | .name = "red balance", | ||
446 | .minimum = 0x00, | ||
447 | .maximum = 0x7f, | ||
448 | .step = 0x01, | ||
449 | .default_value = 0x14, | ||
450 | .flags = 0, | ||
451 | }, | ||
452 | { | ||
453 | .id = V4L2_CID_BLUE_BALANCE, | ||
454 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
455 | .name = "blue balance", | ||
456 | .minimum = 0x00, | ||
457 | .maximum = 0x7f, | ||
458 | .step = 0x01, | ||
459 | .default_value = 0x14, | ||
460 | .flags = 0, | ||
461 | }, | ||
462 | { | ||
463 | .id = V4L2_CID_AUTOGAIN, | ||
464 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
465 | .name = "auto adjust", | ||
466 | .minimum = 0x00, | ||
467 | .maximum = 0x01, | ||
468 | .step = 0x01, | ||
469 | .default_value = 0x01, | ||
470 | .flags = 0, | ||
471 | }, | ||
472 | { | ||
473 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
474 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
475 | .name = "green balance", | ||
476 | .minimum = 0x00, | ||
477 | .maximum = 0x7f, | ||
478 | .step = 0x01, | ||
479 | .default_value = 0x14, | ||
480 | .flags = 0, | ||
481 | }, | ||
482 | { | ||
483 | .id = SN9C102_V4L2_CID_BAND_FILTER, | ||
484 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
485 | .name = "band filter", | ||
486 | .minimum = 0x00, | ||
487 | .maximum = 0x01, | ||
488 | .step = 0x01, | ||
489 | .default_value = 0x00, | ||
490 | .flags = 0, | ||
491 | }, | ||
492 | }, | ||
493 | .get_ctrl = &ov7660_get_ctrl, | ||
494 | .set_ctrl = &ov7660_set_ctrl, | ||
495 | .cropcap = { | ||
496 | .bounds = { | ||
497 | .left = 0, | ||
498 | .top = 0, | ||
499 | .width = 640, | ||
500 | .height = 480, | ||
501 | }, | ||
502 | .defrect = { | ||
503 | .left = 0, | ||
504 | .top = 0, | ||
505 | .width = 640, | ||
506 | .height = 480, | ||
507 | }, | ||
508 | }, | ||
509 | .set_crop = &ov7660_set_crop, | ||
510 | .pix_format = { | ||
511 | .width = 640, | ||
512 | .height = 480, | ||
513 | .pixelformat = V4L2_PIX_FMT_JPEG, | ||
514 | .priv = 8, | ||
515 | }, | ||
516 | .set_pix_format = &ov7660_set_pix_format | ||
517 | }; | ||
518 | |||
519 | |||
520 | int sn9c102_probe_ov7660(struct sn9c102_device* cam) | ||
521 | { | ||
522 | int pid, ver, err; | ||
523 | |||
524 | err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, | ||
525 | {0x01, 0x01}, {0x00, 0x01}, | ||
526 | {0x28, 0x17}); | ||
527 | |||
528 | pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); | ||
529 | ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); | ||
530 | if (err || pid < 0 || ver < 0) | ||
531 | return -EIO; | ||
532 | if (pid != 0x76 || ver != 0x60) | ||
533 | return -ENODEV; | ||
534 | |||
535 | sn9c102_attach_sensor(cam, &ov7660); | ||
536 | |||
537 | return 0; | ||
538 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_pas106b.c b/drivers/media/usb/sn9c102/sn9c102_pas106b.c deleted file mode 100644 index 81cd969c1b7b..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_pas106b.c +++ /dev/null | |||
@@ -1,302 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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/delay.h> | ||
23 | #include "sn9c102_sensor.h" | ||
24 | #include "sn9c102_devtable.h" | ||
25 | |||
26 | |||
27 | static int pas106b_init(struct sn9c102_device* cam) | ||
28 | { | ||
29 | int err = 0; | ||
30 | |||
31 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, | ||
32 | {0x00, 0x14}, {0x20, 0x17}, | ||
33 | {0x20, 0x19}, {0x09, 0x18}); | ||
34 | |||
35 | err += sn9c102_i2c_write(cam, 0x02, 0x0c); | ||
36 | err += sn9c102_i2c_write(cam, 0x05, 0x5a); | ||
37 | err += sn9c102_i2c_write(cam, 0x06, 0x88); | ||
38 | err += sn9c102_i2c_write(cam, 0x07, 0x80); | ||
39 | err += sn9c102_i2c_write(cam, 0x10, 0x06); | ||
40 | err += sn9c102_i2c_write(cam, 0x11, 0x06); | ||
41 | err += sn9c102_i2c_write(cam, 0x12, 0x00); | ||
42 | err += sn9c102_i2c_write(cam, 0x14, 0x02); | ||
43 | err += sn9c102_i2c_write(cam, 0x13, 0x01); | ||
44 | |||
45 | msleep(400); | ||
46 | |||
47 | return err; | ||
48 | } | ||
49 | |||
50 | |||
51 | static int pas106b_get_ctrl(struct sn9c102_device* cam, | ||
52 | struct v4l2_control* ctrl) | ||
53 | { | ||
54 | switch (ctrl->id) { | ||
55 | case V4L2_CID_EXPOSURE: | ||
56 | { | ||
57 | int r1 = sn9c102_i2c_read(cam, 0x03), | ||
58 | r2 = sn9c102_i2c_read(cam, 0x04); | ||
59 | if (r1 < 0 || r2 < 0) | ||
60 | return -EIO; | ||
61 | ctrl->value = (r1 << 4) | (r2 & 0x0f); | ||
62 | } | ||
63 | return 0; | ||
64 | case V4L2_CID_RED_BALANCE: | ||
65 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
66 | return -EIO; | ||
67 | ctrl->value &= 0x1f; | ||
68 | return 0; | ||
69 | case V4L2_CID_BLUE_BALANCE: | ||
70 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) | ||
71 | return -EIO; | ||
72 | ctrl->value &= 0x1f; | ||
73 | return 0; | ||
74 | case V4L2_CID_GAIN: | ||
75 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) | ||
76 | return -EIO; | ||
77 | ctrl->value &= 0x1f; | ||
78 | return 0; | ||
79 | case V4L2_CID_CONTRAST: | ||
80 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) | ||
81 | return -EIO; | ||
82 | ctrl->value &= 0x07; | ||
83 | return 0; | ||
84 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
85 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0) | ||
86 | return -EIO; | ||
87 | ctrl->value = (ctrl->value & 0x1f) << 1; | ||
88 | return 0; | ||
89 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
90 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) | ||
91 | return -EIO; | ||
92 | ctrl->value &= 0xf8; | ||
93 | return 0; | ||
94 | default: | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | |||
100 | static int pas106b_set_ctrl(struct sn9c102_device* cam, | ||
101 | const struct v4l2_control* ctrl) | ||
102 | { | ||
103 | int err = 0; | ||
104 | |||
105 | switch (ctrl->id) { | ||
106 | case V4L2_CID_EXPOSURE: | ||
107 | err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4); | ||
108 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f); | ||
109 | break; | ||
110 | case V4L2_CID_RED_BALANCE: | ||
111 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
112 | break; | ||
113 | case V4L2_CID_BLUE_BALANCE: | ||
114 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
115 | break; | ||
116 | case V4L2_CID_GAIN: | ||
117 | err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); | ||
118 | break; | ||
119 | case V4L2_CID_CONTRAST: | ||
120 | err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); | ||
121 | break; | ||
122 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
123 | err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1); | ||
124 | err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1); | ||
125 | break; | ||
126 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
127 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3); | ||
128 | break; | ||
129 | default: | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | err += sn9c102_i2c_write(cam, 0x13, 0x01); | ||
133 | |||
134 | return err ? -EIO : 0; | ||
135 | } | ||
136 | |||
137 | |||
138 | static int pas106b_set_crop(struct sn9c102_device* cam, | ||
139 | const struct v4l2_rect* rect) | ||
140 | { | ||
141 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
142 | int err = 0; | ||
143 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, | ||
144 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
145 | |||
146 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
147 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
148 | |||
149 | return err; | ||
150 | } | ||
151 | |||
152 | |||
153 | static int pas106b_set_pix_format(struct sn9c102_device* cam, | ||
154 | const struct v4l2_pix_format* pix) | ||
155 | { | ||
156 | int err = 0; | ||
157 | |||
158 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
159 | err += sn9c102_write_reg(cam, 0x2c, 0x17); | ||
160 | else | ||
161 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
162 | |||
163 | return err; | ||
164 | } | ||
165 | |||
166 | |||
167 | static const struct sn9c102_sensor pas106b = { | ||
168 | .name = "PAS106B", | ||
169 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
170 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
171 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
172 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
173 | .interface = SN9C102_I2C_2WIRES, | ||
174 | .i2c_slave_id = 0x40, | ||
175 | .init = &pas106b_init, | ||
176 | .qctrl = { | ||
177 | { | ||
178 | .id = V4L2_CID_EXPOSURE, | ||
179 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
180 | .name = "exposure", | ||
181 | .minimum = 0x125, | ||
182 | .maximum = 0xfff, | ||
183 | .step = 0x001, | ||
184 | .default_value = 0x140, | ||
185 | .flags = 0, | ||
186 | }, | ||
187 | { | ||
188 | .id = V4L2_CID_GAIN, | ||
189 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
190 | .name = "global gain", | ||
191 | .minimum = 0x00, | ||
192 | .maximum = 0x1f, | ||
193 | .step = 0x01, | ||
194 | .default_value = 0x0d, | ||
195 | .flags = 0, | ||
196 | }, | ||
197 | { | ||
198 | .id = V4L2_CID_CONTRAST, | ||
199 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
200 | .name = "contrast", | ||
201 | .minimum = 0x00, | ||
202 | .maximum = 0x07, | ||
203 | .step = 0x01, | ||
204 | .default_value = 0x00, /* 0x00~0x03 have same effect */ | ||
205 | .flags = 0, | ||
206 | }, | ||
207 | { | ||
208 | .id = V4L2_CID_RED_BALANCE, | ||
209 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
210 | .name = "red balance", | ||
211 | .minimum = 0x00, | ||
212 | .maximum = 0x1f, | ||
213 | .step = 0x01, | ||
214 | .default_value = 0x04, | ||
215 | .flags = 0, | ||
216 | }, | ||
217 | { | ||
218 | .id = V4L2_CID_BLUE_BALANCE, | ||
219 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
220 | .name = "blue balance", | ||
221 | .minimum = 0x00, | ||
222 | .maximum = 0x1f, | ||
223 | .step = 0x01, | ||
224 | .default_value = 0x06, | ||
225 | .flags = 0, | ||
226 | }, | ||
227 | { | ||
228 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
229 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
230 | .name = "green balance", | ||
231 | .minimum = 0x00, | ||
232 | .maximum = 0x3e, | ||
233 | .step = 0x02, | ||
234 | .default_value = 0x02, | ||
235 | .flags = 0, | ||
236 | }, | ||
237 | { | ||
238 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
239 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
240 | .name = "DAC magnitude", | ||
241 | .minimum = 0x00, | ||
242 | .maximum = 0x1f, | ||
243 | .step = 0x01, | ||
244 | .default_value = 0x01, | ||
245 | .flags = 0, | ||
246 | }, | ||
247 | }, | ||
248 | .get_ctrl = &pas106b_get_ctrl, | ||
249 | .set_ctrl = &pas106b_set_ctrl, | ||
250 | .cropcap = { | ||
251 | .bounds = { | ||
252 | .left = 0, | ||
253 | .top = 0, | ||
254 | .width = 352, | ||
255 | .height = 288, | ||
256 | }, | ||
257 | .defrect = { | ||
258 | .left = 0, | ||
259 | .top = 0, | ||
260 | .width = 352, | ||
261 | .height = 288, | ||
262 | }, | ||
263 | }, | ||
264 | .set_crop = &pas106b_set_crop, | ||
265 | .pix_format = { | ||
266 | .width = 352, | ||
267 | .height = 288, | ||
268 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
269 | .priv = 8, /* we use this field as 'bits per pixel' */ | ||
270 | }, | ||
271 | .set_pix_format = &pas106b_set_pix_format | ||
272 | }; | ||
273 | |||
274 | |||
275 | int sn9c102_probe_pas106b(struct sn9c102_device* cam) | ||
276 | { | ||
277 | int r0 = 0, r1 = 0; | ||
278 | unsigned int pid = 0; | ||
279 | |||
280 | /* | ||
281 | Minimal initialization to enable the I2C communication | ||
282 | NOTE: do NOT change the values! | ||
283 | */ | ||
284 | if (sn9c102_write_const_regs(cam, | ||
285 | {0x01, 0x01}, /* sensor power down */ | ||
286 | {0x00, 0x01}, /* sensor power on */ | ||
287 | {0x28, 0x17})) /* sensor clock at 24 MHz */ | ||
288 | return -EIO; | ||
289 | |||
290 | r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00); | ||
291 | r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01); | ||
292 | if (r0 < 0 || r1 < 0) | ||
293 | return -EIO; | ||
294 | |||
295 | pid = (r0 << 11) | ((r1 & 0xf0) >> 4); | ||
296 | if (pid != 0x007) | ||
297 | return -ENODEV; | ||
298 | |||
299 | sn9c102_attach_sensor(cam, &pas106b); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c b/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c deleted file mode 100644 index 2e86fdc86989..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c +++ /dev/null | |||
@@ -1,335 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * | ||
6 | * <medaglia@undl.org.br> * | ||
7 | * * | ||
8 | * Support for SN9C103, DAC Magnitude, exposure and green gain controls * | ||
9 | * added by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
10 | * * | ||
11 | * This program is free software; you can redistribute it and/or modify * | ||
12 | * it under the terms of the GNU General Public License as published by * | ||
13 | * the Free Software Foundation; either version 2 of the License, or * | ||
14 | * (at your option) any later version. * | ||
15 | * * | ||
16 | * This program is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
19 | * GNU General Public License for more details. * | ||
20 | * * | ||
21 | * You should have received a copy of the GNU General Public License * | ||
22 | * along with this program; if not, write to the Free Software * | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
24 | ***************************************************************************/ | ||
25 | |||
26 | #include <linux/delay.h> | ||
27 | #include "sn9c102_sensor.h" | ||
28 | #include "sn9c102_devtable.h" | ||
29 | |||
30 | |||
31 | static int pas202bcb_init(struct sn9c102_device* cam) | ||
32 | { | ||
33 | int err = 0; | ||
34 | |||
35 | switch (sn9c102_get_bridge(cam)) { | ||
36 | case BRIDGE_SN9C101: | ||
37 | case BRIDGE_SN9C102: | ||
38 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, | ||
39 | {0x00, 0x14}, {0x20, 0x17}, | ||
40 | {0x30, 0x19}, {0x09, 0x18}); | ||
41 | break; | ||
42 | case BRIDGE_SN9C103: | ||
43 | err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, | ||
44 | {0x1a, 0x04}, {0x20, 0x05}, | ||
45 | {0x20, 0x06}, {0x20, 0x07}, | ||
46 | {0x00, 0x10}, {0x00, 0x11}, | ||
47 | {0x00, 0x14}, {0x20, 0x17}, | ||
48 | {0x30, 0x19}, {0x09, 0x18}, | ||
49 | {0x02, 0x1c}, {0x03, 0x1d}, | ||
50 | {0x0f, 0x1e}, {0x0c, 0x1f}, | ||
51 | {0x00, 0x20}, {0x10, 0x21}, | ||
52 | {0x20, 0x22}, {0x30, 0x23}, | ||
53 | {0x40, 0x24}, {0x50, 0x25}, | ||
54 | {0x60, 0x26}, {0x70, 0x27}, | ||
55 | {0x80, 0x28}, {0x90, 0x29}, | ||
56 | {0xa0, 0x2a}, {0xb0, 0x2b}, | ||
57 | {0xc0, 0x2c}, {0xd0, 0x2d}, | ||
58 | {0xe0, 0x2e}, {0xf0, 0x2f}, | ||
59 | {0xff, 0x30}); | ||
60 | break; | ||
61 | default: | ||
62 | break; | ||
63 | } | ||
64 | |||
65 | err += sn9c102_i2c_write(cam, 0x02, 0x14); | ||
66 | err += sn9c102_i2c_write(cam, 0x03, 0x40); | ||
67 | err += sn9c102_i2c_write(cam, 0x0d, 0x2c); | ||
68 | err += sn9c102_i2c_write(cam, 0x0e, 0x01); | ||
69 | err += sn9c102_i2c_write(cam, 0x0f, 0xa9); | ||
70 | err += sn9c102_i2c_write(cam, 0x10, 0x08); | ||
71 | err += sn9c102_i2c_write(cam, 0x13, 0x63); | ||
72 | err += sn9c102_i2c_write(cam, 0x15, 0x70); | ||
73 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
74 | |||
75 | msleep(400); | ||
76 | |||
77 | return err; | ||
78 | } | ||
79 | |||
80 | |||
81 | static int pas202bcb_get_ctrl(struct sn9c102_device* cam, | ||
82 | struct v4l2_control* ctrl) | ||
83 | { | ||
84 | switch (ctrl->id) { | ||
85 | case V4L2_CID_EXPOSURE: | ||
86 | { | ||
87 | int r1 = sn9c102_i2c_read(cam, 0x04), | ||
88 | r2 = sn9c102_i2c_read(cam, 0x05); | ||
89 | if (r1 < 0 || r2 < 0) | ||
90 | return -EIO; | ||
91 | ctrl->value = (r1 << 6) | (r2 & 0x3f); | ||
92 | } | ||
93 | return 0; | ||
94 | case V4L2_CID_RED_BALANCE: | ||
95 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) | ||
96 | return -EIO; | ||
97 | ctrl->value &= 0x0f; | ||
98 | return 0; | ||
99 | case V4L2_CID_BLUE_BALANCE: | ||
100 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) | ||
101 | return -EIO; | ||
102 | ctrl->value &= 0x0f; | ||
103 | return 0; | ||
104 | case V4L2_CID_GAIN: | ||
105 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) | ||
106 | return -EIO; | ||
107 | ctrl->value &= 0x1f; | ||
108 | return 0; | ||
109 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
110 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) | ||
111 | return -EIO; | ||
112 | ctrl->value &= 0x0f; | ||
113 | return 0; | ||
114 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
115 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
116 | return -EIO; | ||
117 | return 0; | ||
118 | default: | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | |||
124 | static int pas202bcb_set_pix_format(struct sn9c102_device* cam, | ||
125 | const struct v4l2_pix_format* pix) | ||
126 | { | ||
127 | int err = 0; | ||
128 | |||
129 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
130 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
131 | else | ||
132 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
133 | |||
134 | return err; | ||
135 | } | ||
136 | |||
137 | |||
138 | static int pas202bcb_set_ctrl(struct sn9c102_device* cam, | ||
139 | const struct v4l2_control* ctrl) | ||
140 | { | ||
141 | int err = 0; | ||
142 | |||
143 | switch (ctrl->id) { | ||
144 | case V4L2_CID_EXPOSURE: | ||
145 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); | ||
146 | err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); | ||
147 | break; | ||
148 | case V4L2_CID_RED_BALANCE: | ||
149 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
150 | break; | ||
151 | case V4L2_CID_BLUE_BALANCE: | ||
152 | err += sn9c102_i2c_write(cam, 0x07, ctrl->value); | ||
153 | break; | ||
154 | case V4L2_CID_GAIN: | ||
155 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
156 | break; | ||
157 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
158 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value); | ||
159 | break; | ||
160 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
161 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
162 | break; | ||
163 | default: | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
167 | |||
168 | return err ? -EIO : 0; | ||
169 | } | ||
170 | |||
171 | |||
172 | static int pas202bcb_set_crop(struct sn9c102_device* cam, | ||
173 | const struct v4l2_rect* rect) | ||
174 | { | ||
175 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
176 | int err = 0; | ||
177 | u8 h_start = 0, | ||
178 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
179 | |||
180 | switch (sn9c102_get_bridge(cam)) { | ||
181 | case BRIDGE_SN9C101: | ||
182 | case BRIDGE_SN9C102: | ||
183 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; | ||
184 | break; | ||
185 | case BRIDGE_SN9C103: | ||
186 | h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3; | ||
187 | break; | ||
188 | default: | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
193 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
194 | |||
195 | return err; | ||
196 | } | ||
197 | |||
198 | |||
199 | static const struct sn9c102_sensor pas202bcb = { | ||
200 | .name = "PAS202BCB", | ||
201 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
202 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | ||
203 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
204 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
205 | .interface = SN9C102_I2C_2WIRES, | ||
206 | .i2c_slave_id = 0x40, | ||
207 | .init = &pas202bcb_init, | ||
208 | .qctrl = { | ||
209 | { | ||
210 | .id = V4L2_CID_EXPOSURE, | ||
211 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
212 | .name = "exposure", | ||
213 | .minimum = 0x01e5, | ||
214 | .maximum = 0x3fff, | ||
215 | .step = 0x0001, | ||
216 | .default_value = 0x01e5, | ||
217 | .flags = 0, | ||
218 | }, | ||
219 | { | ||
220 | .id = V4L2_CID_GAIN, | ||
221 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
222 | .name = "global gain", | ||
223 | .minimum = 0x00, | ||
224 | .maximum = 0x1f, | ||
225 | .step = 0x01, | ||
226 | .default_value = 0x0b, | ||
227 | .flags = 0, | ||
228 | }, | ||
229 | { | ||
230 | .id = V4L2_CID_RED_BALANCE, | ||
231 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
232 | .name = "red balance", | ||
233 | .minimum = 0x00, | ||
234 | .maximum = 0x0f, | ||
235 | .step = 0x01, | ||
236 | .default_value = 0x00, | ||
237 | .flags = 0, | ||
238 | }, | ||
239 | { | ||
240 | .id = V4L2_CID_BLUE_BALANCE, | ||
241 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
242 | .name = "blue balance", | ||
243 | .minimum = 0x00, | ||
244 | .maximum = 0x0f, | ||
245 | .step = 0x01, | ||
246 | .default_value = 0x05, | ||
247 | .flags = 0, | ||
248 | }, | ||
249 | { | ||
250 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
251 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
252 | .name = "green balance", | ||
253 | .minimum = 0x00, | ||
254 | .maximum = 0x0f, | ||
255 | .step = 0x01, | ||
256 | .default_value = 0x00, | ||
257 | .flags = 0, | ||
258 | }, | ||
259 | { | ||
260 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
261 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
262 | .name = "DAC magnitude", | ||
263 | .minimum = 0x00, | ||
264 | .maximum = 0xff, | ||
265 | .step = 0x01, | ||
266 | .default_value = 0x04, | ||
267 | .flags = 0, | ||
268 | }, | ||
269 | }, | ||
270 | .get_ctrl = &pas202bcb_get_ctrl, | ||
271 | .set_ctrl = &pas202bcb_set_ctrl, | ||
272 | .cropcap = { | ||
273 | .bounds = { | ||
274 | .left = 0, | ||
275 | .top = 0, | ||
276 | .width = 640, | ||
277 | .height = 480, | ||
278 | }, | ||
279 | .defrect = { | ||
280 | .left = 0, | ||
281 | .top = 0, | ||
282 | .width = 640, | ||
283 | .height = 480, | ||
284 | }, | ||
285 | }, | ||
286 | .set_crop = &pas202bcb_set_crop, | ||
287 | .pix_format = { | ||
288 | .width = 640, | ||
289 | .height = 480, | ||
290 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
291 | .priv = 8, | ||
292 | }, | ||
293 | .set_pix_format = &pas202bcb_set_pix_format | ||
294 | }; | ||
295 | |||
296 | |||
297 | int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) | ||
298 | { | ||
299 | int r0 = 0, r1 = 0, err = 0; | ||
300 | unsigned int pid = 0; | ||
301 | |||
302 | /* | ||
303 | * Minimal initialization to enable the I2C communication | ||
304 | * NOTE: do NOT change the values! | ||
305 | */ | ||
306 | switch (sn9c102_get_bridge(cam)) { | ||
307 | case BRIDGE_SN9C101: | ||
308 | case BRIDGE_SN9C102: | ||
309 | err = sn9c102_write_const_regs(cam, | ||
310 | {0x01, 0x01}, /* power down */ | ||
311 | {0x40, 0x01}, /* power on */ | ||
312 | {0x28, 0x17});/* clock 24 MHz */ | ||
313 | break; | ||
314 | case BRIDGE_SN9C103: /* do _not_ change anything! */ | ||
315 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x01}, | ||
316 | {0x44, 0x02}, {0x29, 0x17}); | ||
317 | break; | ||
318 | default: | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); | ||
323 | r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); | ||
324 | |||
325 | if (err || r0 < 0 || r1 < 0) | ||
326 | return -EIO; | ||
327 | |||
328 | pid = (r0 << 4) | ((r1 & 0xf0) >> 4); | ||
329 | if (pid != 0x017) | ||
330 | return -ENODEV; | ||
331 | |||
332 | sn9c102_attach_sensor(cam, &pas202bcb); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_sensor.h b/drivers/media/usb/sn9c102/sn9c102_sensor.h deleted file mode 100644 index 3679970dba2c..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_sensor.h +++ /dev/null | |||
@@ -1,307 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * API for image sensors connected to the SN9C1xx PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_SENSOR_H_ | ||
22 | #define _SN9C102_SENSOR_H_ | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/stddef.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <asm/types.h> | ||
30 | |||
31 | struct sn9c102_device; | ||
32 | struct sn9c102_sensor; | ||
33 | |||
34 | /*****************************************************************************/ | ||
35 | |||
36 | /* | ||
37 | OVERVIEW. | ||
38 | This is a small interface that allows you to add support for any CCD/CMOS | ||
39 | image sensors connected to the SN9C1XX bridges. The entire API is documented | ||
40 | below. In the most general case, to support a sensor there are three steps | ||
41 | you have to follow: | ||
42 | 1) define the main "sn9c102_sensor" structure by setting the basic fields; | ||
43 | 2) write a probing function to be called by the core module when the USB | ||
44 | camera is recognized, then add both the USB ids and the name of that | ||
45 | function to the two corresponding tables in sn9c102_devtable.h; | ||
46 | 3) implement the methods that you want/need (and fill the rest of the main | ||
47 | structure accordingly). | ||
48 | "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do | ||
49 | NOT need to touch the source code of the core module for the things to work | ||
50 | properly, unless you find bugs or flaws in it. Finally, do not forget to | ||
51 | read the V4L2 API for completeness. | ||
52 | */ | ||
53 | |||
54 | /*****************************************************************************/ | ||
55 | |||
56 | enum sn9c102_bridge { | ||
57 | BRIDGE_SN9C101 = 0x01, | ||
58 | BRIDGE_SN9C102 = 0x02, | ||
59 | BRIDGE_SN9C103 = 0x04, | ||
60 | BRIDGE_SN9C105 = 0x08, | ||
61 | BRIDGE_SN9C120 = 0x10, | ||
62 | }; | ||
63 | |||
64 | /* Return the bridge name */ | ||
65 | enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam); | ||
66 | |||
67 | /* Return a pointer the sensor struct attached to the camera */ | ||
68 | struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam); | ||
69 | |||
70 | /* Identify a device */ | ||
71 | extern struct sn9c102_device* | ||
72 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); | ||
73 | |||
74 | /* Attach a probed sensor to the camera. */ | ||
75 | extern void | ||
76 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
77 | const struct sn9c102_sensor* sensor); | ||
78 | |||
79 | /* | ||
80 | Read/write routines: they always return -1 on error, 0 or the read value | ||
81 | otherwise. NOTE that a real read operation is not supported by the SN9C1XX | ||
82 | chip for some of its registers. To work around this problem, a pseudo-read | ||
83 | call is provided instead: it returns the last successfully written value | ||
84 | on the register (0 if it has never been written), the usual -1 on error. | ||
85 | */ | ||
86 | |||
87 | /* The "try" I2C I/O versions are used when probing the sensor */ | ||
88 | extern int sn9c102_i2c_try_read(struct sn9c102_device*, | ||
89 | const struct sn9c102_sensor*, u8 address); | ||
90 | |||
91 | /* | ||
92 | These must be used if and only if the sensor doesn't implement the standard | ||
93 | I2C protocol. There are a number of good reasons why you must use the | ||
94 | single-byte versions of these functions: do not abuse. The first function | ||
95 | writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX | ||
96 | chip. The second one programs the registers 0x09 and 0x10 with data0 and | ||
97 | data1, and places the n bytes read from the sensor register table in the | ||
98 | buffer pointed by 'buffer'. Both the functions return -1 on error; the write | ||
99 | version returns 0 on success, while the read version returns the first read | ||
100 | byte. | ||
101 | */ | ||
102 | extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
103 | const struct sn9c102_sensor* sensor, u8 n, | ||
104 | u8 data0, u8 data1, u8 data2, u8 data3, | ||
105 | u8 data4, u8 data5); | ||
106 | extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
107 | const struct sn9c102_sensor* sensor, | ||
108 | u8 data0, u8 data1, u8 n, u8 buffer[]); | ||
109 | |||
110 | /* To be used after the sensor struct has been attached to the camera struct */ | ||
111 | extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); | ||
112 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); | ||
113 | |||
114 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ | ||
115 | extern int sn9c102_read_reg(struct sn9c102_device*, u16 index); | ||
116 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); | ||
117 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | ||
118 | extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2], | ||
119 | int count); | ||
120 | /* | ||
121 | Write multiple registers with constant values. For example: | ||
122 | sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18}); | ||
123 | Register addresses must be < 256. | ||
124 | */ | ||
125 | #define sn9c102_write_const_regs(sn9c102_device, data...) \ | ||
126 | ({ static const u8 _valreg[][2] = {data}; \ | ||
127 | sn9c102_write_regs(sn9c102_device, _valreg, ARRAY_SIZE(_valreg)); }) | ||
128 | |||
129 | /*****************************************************************************/ | ||
130 | |||
131 | enum sn9c102_i2c_sysfs_ops { | ||
132 | SN9C102_I2C_READ = 0x01, | ||
133 | SN9C102_I2C_WRITE = 0x02, | ||
134 | }; | ||
135 | |||
136 | enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ | ||
137 | SN9C102_I2C_100KHZ = 0x01, | ||
138 | SN9C102_I2C_400KHZ = 0x02, | ||
139 | }; | ||
140 | |||
141 | enum sn9c102_i2c_interface { | ||
142 | SN9C102_I2C_2WIRES, | ||
143 | SN9C102_I2C_3WIRES, | ||
144 | }; | ||
145 | |||
146 | #define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10) | ||
147 | |||
148 | struct sn9c102_sensor { | ||
149 | char name[32], /* sensor name */ | ||
150 | maintainer[64]; /* name of the maintainer <email> */ | ||
151 | |||
152 | enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */ | ||
153 | |||
154 | /* Supported operations through the 'sysfs' interface */ | ||
155 | enum sn9c102_i2c_sysfs_ops sysfs_ops; | ||
156 | |||
157 | /* | ||
158 | These sensor capabilities must be provided if the SN9C1XX controller | ||
159 | needs to communicate through the sensor serial interface by using | ||
160 | at least one of the i2c functions available. | ||
161 | */ | ||
162 | enum sn9c102_i2c_frequency frequency; | ||
163 | enum sn9c102_i2c_interface interface; | ||
164 | |||
165 | /* | ||
166 | This identifier must be provided if the image sensor implements | ||
167 | the standard I2C protocol. | ||
168 | */ | ||
169 | u8 i2c_slave_id; /* reg. 0x09 */ | ||
170 | |||
171 | /* | ||
172 | NOTE: Where not noted,most of the functions below are not mandatory. | ||
173 | Set to null if you do not implement them. If implemented, | ||
174 | they must return 0 on success, the proper error otherwise. | ||
175 | */ | ||
176 | |||
177 | int (*init)(struct sn9c102_device* cam); | ||
178 | /* | ||
179 | This function will be called after the sensor has been attached. | ||
180 | It should be used to initialize the sensor only, but may also | ||
181 | configure part of the SN9C1XX chip if necessary. You don't need to | ||
182 | setup picture settings like brightness, contrast, etc.. here, if | ||
183 | the corresponding controls are implemented (see below), since | ||
184 | they are adjusted in the core driver by calling the set_ctrl() | ||
185 | method after init(), where the arguments are the default values | ||
186 | specified in the v4l2_queryctrl list of supported controls; | ||
187 | Same suggestions apply for other settings, _if_ the corresponding | ||
188 | methods are present; if not, the initialization must configure the | ||
189 | sensor according to the default configuration structures below. | ||
190 | */ | ||
191 | |||
192 | struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; | ||
193 | /* | ||
194 | Optional list of default controls, defined as indicated in the | ||
195 | V4L2 API. Menu type controls are not handled by this interface. | ||
196 | */ | ||
197 | |||
198 | int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); | ||
199 | int (*set_ctrl)(struct sn9c102_device* cam, | ||
200 | const struct v4l2_control* ctrl); | ||
201 | /* | ||
202 | You must implement at least the set_ctrl method if you have defined | ||
203 | the list above. The returned value must follow the V4L2 | ||
204 | specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER | ||
205 | are not supported by this driver, so do not implement them. Also, | ||
206 | you don't have to check whether the passed values are out of bounds, | ||
207 | given that this is done by the core module. | ||
208 | */ | ||
209 | |||
210 | struct v4l2_cropcap cropcap; | ||
211 | /* | ||
212 | Think the image sensor as a grid of R,G,B monochromatic pixels | ||
213 | disposed according to a particular Bayer pattern, which describes | ||
214 | the complete array of pixels, from (0,0) to (xmax, ymax). We will | ||
215 | use this coordinate system from now on. It is assumed the sensor | ||
216 | chip can be programmed to capture/transmit a subsection of that | ||
217 | array of pixels: we will call this subsection "active window". | ||
218 | It is not always true that the largest achievable active window can | ||
219 | cover the whole array of pixels. The V4L2 API defines another | ||
220 | area called "source rectangle", which, in turn, is a subrectangle of | ||
221 | the active window. The SN9C1XX chip is always programmed to read the | ||
222 | source rectangle. | ||
223 | The bounds of both the active window and the source rectangle are | ||
224 | specified in the cropcap substructures 'bounds' and 'defrect'. | ||
225 | By default, the source rectangle should cover the largest possible | ||
226 | area. Again, it is not always true that the largest source rectangle | ||
227 | can cover the entire active window, although it is a rare case for | ||
228 | the hardware we have. The bounds of the source rectangle _must_ be | ||
229 | multiple of 16 and must use the same coordinate system as indicated | ||
230 | before; their centers shall align initially. | ||
231 | If necessary, the sensor chip must be initialized during init() to | ||
232 | set the bounds of the active sensor window; however, by default, it | ||
233 | usually covers the largest achievable area (maxwidth x maxheight) | ||
234 | of pixels, so no particular initialization is needed, if you have | ||
235 | defined the correct default bounds in the structures. | ||
236 | See the V4L2 API for further details. | ||
237 | NOTE: once you have defined the bounds of the active window | ||
238 | (struct cropcap.bounds) you must not change them.anymore. | ||
239 | Only 'bounds' and 'defrect' fields are mandatory, other fields | ||
240 | will be ignored. | ||
241 | */ | ||
242 | |||
243 | int (*set_crop)(struct sn9c102_device* cam, | ||
244 | const struct v4l2_rect* rect); | ||
245 | /* | ||
246 | To be called on VIDIOC_C_SETCROP. The core module always calls a | ||
247 | default routine which configures the appropriate SN9C1XX regs (also | ||
248 | scaling), but you may need to override/adjust specific stuff. | ||
249 | 'rect' contains width and height values that are multiple of 16: in | ||
250 | case you override the default function, you always have to program | ||
251 | the chip to match those values; on error return the corresponding | ||
252 | error code without rolling back. | ||
253 | NOTE: in case, you must program the SN9C1XX chip to get rid of | ||
254 | blank pixels or blank lines at the _start_ of each line or | ||
255 | frame after each HSYNC or VSYNC, so that the image starts with | ||
256 | real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, | ||
257 | V_SIZE you don't have to care about blank pixels or blank | ||
258 | lines at the end of each line or frame). | ||
259 | */ | ||
260 | |||
261 | struct v4l2_pix_format pix_format; | ||
262 | /* | ||
263 | What you have to define here are: 1) initial 'width' and 'height' of | ||
264 | the target rectangle 2) the initial 'pixelformat', which can be | ||
265 | either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video) | ||
266 | or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate | ||
267 | the number of bits per pixel for uncompressed video, 8 or 9 (despite | ||
268 | the current value of 'pixelformat'). | ||
269 | NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 | ||
270 | of cropcap.defrect.width and cropcap.defrect.height. I | ||
271 | suggest 1/1. | ||
272 | NOTE 2: The initial compression quality is defined by the first bit | ||
273 | of reg 0x17 during the initialization of the image sensor. | ||
274 | NOTE 3: as said above, you have to program the SN9C1XX chip to get | ||
275 | rid of any blank pixels, so that the output of the sensor | ||
276 | matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). | ||
277 | */ | ||
278 | |||
279 | int (*set_pix_format)(struct sn9c102_device* cam, | ||
280 | const struct v4l2_pix_format* pix); | ||
281 | /* | ||
282 | To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to | ||
283 | SN9C10X pixel format or viceversa. On error return the corresponding | ||
284 | error code without rolling back. | ||
285 | */ | ||
286 | |||
287 | /* | ||
288 | Do NOT write to the data below, it's READ ONLY. It is used by the | ||
289 | core module to store successfully updated values of the above | ||
290 | settings, for rollbacks..etc..in case of errors during atomic I/O | ||
291 | */ | ||
292 | struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; | ||
293 | struct v4l2_rect _rect; | ||
294 | }; | ||
295 | |||
296 | /*****************************************************************************/ | ||
297 | |||
298 | /* Private ioctl's for control settings supported by some image sensors */ | ||
299 | #define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0) | ||
300 | #define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1) | ||
301 | #define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2) | ||
302 | #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3) | ||
303 | #define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4) | ||
304 | #define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5) | ||
305 | #define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6) | ||
306 | |||
307 | #endif /* _SN9C102_SENSOR_H_ */ | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c deleted file mode 100644 index 04cdfdde8564..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c +++ /dev/null | |||
@@ -1,154 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int tas5110c1b_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | int err = 0; | ||
29 | |||
30 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01}, | ||
31 | {0x00, 0x10}, {0x00, 0x11}, | ||
32 | {0x0a, 0x14}, {0x60, 0x17}, | ||
33 | {0x06, 0x18}, {0xfb, 0x19}); | ||
34 | |||
35 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); | ||
36 | |||
37 | return err; | ||
38 | } | ||
39 | |||
40 | |||
41 | static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, | ||
42 | const struct v4l2_control* ctrl) | ||
43 | { | ||
44 | int err = 0; | ||
45 | |||
46 | switch (ctrl->id) { | ||
47 | case V4L2_CID_GAIN: | ||
48 | err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); | ||
49 | break; | ||
50 | default: | ||
51 | return -EINVAL; | ||
52 | } | ||
53 | |||
54 | return err ? -EIO : 0; | ||
55 | } | ||
56 | |||
57 | |||
58 | static int tas5110c1b_set_crop(struct sn9c102_device* cam, | ||
59 | const struct v4l2_rect* rect) | ||
60 | { | ||
61 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
62 | int err = 0; | ||
63 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | ||
64 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | ||
65 | |||
66 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
67 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
68 | |||
69 | /* Don't change ! */ | ||
70 | err += sn9c102_write_reg(cam, 0x14, 0x1a); | ||
71 | err += sn9c102_write_reg(cam, 0x0a, 0x1b); | ||
72 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
73 | |||
74 | return err; | ||
75 | } | ||
76 | |||
77 | |||
78 | static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, | ||
79 | const struct v4l2_pix_format* pix) | ||
80 | { | ||
81 | int err = 0; | ||
82 | |||
83 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
84 | err += sn9c102_write_reg(cam, 0x2b, 0x19); | ||
85 | else | ||
86 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
87 | |||
88 | return err; | ||
89 | } | ||
90 | |||
91 | |||
92 | static const struct sn9c102_sensor tas5110c1b = { | ||
93 | .name = "TAS5110C1B", | ||
94 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
95 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
96 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
97 | .frequency = SN9C102_I2C_100KHZ, | ||
98 | .interface = SN9C102_I2C_3WIRES, | ||
99 | .init = &tas5110c1b_init, | ||
100 | .qctrl = { | ||
101 | { | ||
102 | .id = V4L2_CID_GAIN, | ||
103 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
104 | .name = "global gain", | ||
105 | .minimum = 0x00, | ||
106 | .maximum = 0xf6, | ||
107 | .step = 0x01, | ||
108 | .default_value = 0x40, | ||
109 | .flags = 0, | ||
110 | }, | ||
111 | }, | ||
112 | .set_ctrl = &tas5110c1b_set_ctrl, | ||
113 | .cropcap = { | ||
114 | .bounds = { | ||
115 | .left = 0, | ||
116 | .top = 0, | ||
117 | .width = 352, | ||
118 | .height = 288, | ||
119 | }, | ||
120 | .defrect = { | ||
121 | .left = 0, | ||
122 | .top = 0, | ||
123 | .width = 352, | ||
124 | .height = 288, | ||
125 | }, | ||
126 | }, | ||
127 | .set_crop = &tas5110c1b_set_crop, | ||
128 | .pix_format = { | ||
129 | .width = 352, | ||
130 | .height = 288, | ||
131 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
132 | .priv = 8, | ||
133 | }, | ||
134 | .set_pix_format = &tas5110c1b_set_pix_format | ||
135 | }; | ||
136 | |||
137 | |||
138 | int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) | ||
139 | { | ||
140 | const struct usb_device_id tas5110c1b_id_table[] = { | ||
141 | { USB_DEVICE(0x0c45, 0x6001), }, | ||
142 | { USB_DEVICE(0x0c45, 0x6005), }, | ||
143 | { USB_DEVICE(0x0c45, 0x60ab), }, | ||
144 | { } | ||
145 | }; | ||
146 | |||
147 | /* Sensor detection is based on USB pid/vid */ | ||
148 | if (!sn9c102_match_id(cam, tas5110c1b_id_table)) | ||
149 | return -ENODEV; | ||
150 | |||
151 | sn9c102_attach_sensor(cam, &tas5110c1b); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5110d.c b/drivers/media/usb/sn9c102/sn9c102_tas5110d.c deleted file mode 100644 index 9372e6f9fcff..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_tas5110d.c +++ /dev/null | |||
@@ -1,119 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int tas5110d_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | int err; | ||
29 | |||
30 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01}, | ||
31 | {0x0a, 0x14}, {0x60, 0x17}, | ||
32 | {0x06, 0x18}, {0xfb, 0x19}); | ||
33 | |||
34 | err += sn9c102_i2c_write(cam, 0x9a, 0xca); | ||
35 | |||
36 | return err; | ||
37 | } | ||
38 | |||
39 | |||
40 | static int tas5110d_set_crop(struct sn9c102_device* cam, | ||
41 | const struct v4l2_rect* rect) | ||
42 | { | ||
43 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
44 | int err = 0; | ||
45 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | ||
46 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | ||
47 | |||
48 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
49 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
50 | |||
51 | err += sn9c102_write_reg(cam, 0x14, 0x1a); | ||
52 | err += sn9c102_write_reg(cam, 0x0a, 0x1b); | ||
53 | |||
54 | return err; | ||
55 | } | ||
56 | |||
57 | |||
58 | static int tas5110d_set_pix_format(struct sn9c102_device* cam, | ||
59 | const struct v4l2_pix_format* pix) | ||
60 | { | ||
61 | int err = 0; | ||
62 | |||
63 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
64 | err += sn9c102_write_reg(cam, 0x3b, 0x19); | ||
65 | else | ||
66 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
67 | |||
68 | return err; | ||
69 | } | ||
70 | |||
71 | |||
72 | static const struct sn9c102_sensor tas5110d = { | ||
73 | .name = "TAS5110D", | ||
74 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
75 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
76 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
77 | .frequency = SN9C102_I2C_100KHZ, | ||
78 | .interface = SN9C102_I2C_2WIRES, | ||
79 | .i2c_slave_id = 0x61, | ||
80 | .init = &tas5110d_init, | ||
81 | .cropcap = { | ||
82 | .bounds = { | ||
83 | .left = 0, | ||
84 | .top = 0, | ||
85 | .width = 352, | ||
86 | .height = 288, | ||
87 | }, | ||
88 | .defrect = { | ||
89 | .left = 0, | ||
90 | .top = 0, | ||
91 | .width = 352, | ||
92 | .height = 288, | ||
93 | }, | ||
94 | }, | ||
95 | .set_crop = &tas5110d_set_crop, | ||
96 | .pix_format = { | ||
97 | .width = 352, | ||
98 | .height = 288, | ||
99 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
100 | .priv = 8, | ||
101 | }, | ||
102 | .set_pix_format = &tas5110d_set_pix_format | ||
103 | }; | ||
104 | |||
105 | |||
106 | int sn9c102_probe_tas5110d(struct sn9c102_device* cam) | ||
107 | { | ||
108 | const struct usb_device_id tas5110d_id_table[] = { | ||
109 | { USB_DEVICE(0x0c45, 0x6007), }, | ||
110 | { } | ||
111 | }; | ||
112 | |||
113 | if (!sn9c102_match_id(cam, tas5110d_id_table)) | ||
114 | return -ENODEV; | ||
115 | |||
116 | sn9c102_attach_sensor(cam, &tas5110d); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c deleted file mode 100644 index a30bbc4389f5..000000000000 --- a/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
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 "sn9c102_sensor.h" | ||
23 | #include "sn9c102_devtable.h" | ||
24 | |||
25 | |||
26 | static int tas5130d1b_init(struct sn9c102_device* cam) | ||
27 | { | ||
28 | int err; | ||
29 | |||
30 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17}, | ||
31 | {0x04, 0x01}, {0x01, 0x10}, | ||
32 | {0x00, 0x11}, {0x00, 0x14}, | ||
33 | {0x60, 0x17}, {0x07, 0x18}); | ||
34 | |||
35 | return err; | ||
36 | } | ||
37 | |||
38 | |||
39 | static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, | ||
40 | const struct v4l2_control* ctrl) | ||
41 | { | ||
42 | int err = 0; | ||
43 | |||
44 | switch (ctrl->id) { | ||
45 | case V4L2_CID_GAIN: | ||
46 | err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); | ||
47 | break; | ||
48 | case V4L2_CID_EXPOSURE: | ||
49 | err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); | ||
50 | break; | ||
51 | default: | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | return err ? -EIO : 0; | ||
56 | } | ||
57 | |||
58 | |||
59 | static int tas5130d1b_set_crop(struct sn9c102_device* cam, | ||
60 | const struct v4l2_rect* rect) | ||
61 | { | ||
62 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
63 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, | ||
64 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; | ||
65 | int err = 0; | ||
66 | |||
67 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
68 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
69 | |||
70 | /* Do NOT change! */ | ||
71 | err += sn9c102_write_reg(cam, 0x1f, 0x1a); | ||
72 | err += sn9c102_write_reg(cam, 0x1a, 0x1b); | ||
73 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
74 | |||
75 | return err; | ||
76 | } | ||
77 | |||
78 | |||
79 | static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, | ||
80 | const struct v4l2_pix_format* pix) | ||
81 | { | ||
82 | int err = 0; | ||
83 | |||
84 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
85 | err += sn9c102_write_reg(cam, 0x63, 0x19); | ||
86 | else | ||
87 | err += sn9c102_write_reg(cam, 0xf3, 0x19); | ||
88 | |||
89 | return err; | ||
90 | } | ||
91 | |||
92 | |||
93 | static const struct sn9c102_sensor tas5130d1b = { | ||
94 | .name = "TAS5130D1B", | ||
95 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
96 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
97 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
98 | .frequency = SN9C102_I2C_100KHZ, | ||
99 | .interface = SN9C102_I2C_3WIRES, | ||
100 | .init = &tas5130d1b_init, | ||
101 | .qctrl = { | ||
102 | { | ||
103 | .id = V4L2_CID_GAIN, | ||
104 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
105 | .name = "global gain", | ||
106 | .minimum = 0x00, | ||
107 | .maximum = 0xf6, | ||
108 | .step = 0x02, | ||
109 | .default_value = 0x00, | ||
110 | .flags = 0, | ||
111 | }, | ||
112 | { | ||
113 | .id = V4L2_CID_EXPOSURE, | ||
114 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
115 | .name = "exposure", | ||
116 | .minimum = 0x00, | ||
117 | .maximum = 0x47, | ||
118 | .step = 0x01, | ||
119 | .default_value = 0x00, | ||
120 | .flags = 0, | ||
121 | }, | ||
122 | }, | ||
123 | .set_ctrl = &tas5130d1b_set_ctrl, | ||
124 | .cropcap = { | ||
125 | .bounds = { | ||
126 | .left = 0, | ||
127 | .top = 0, | ||
128 | .width = 640, | ||
129 | .height = 480, | ||
130 | }, | ||
131 | .defrect = { | ||
132 | .left = 0, | ||
133 | .top = 0, | ||
134 | .width = 640, | ||
135 | .height = 480, | ||
136 | }, | ||
137 | }, | ||
138 | .set_crop = &tas5130d1b_set_crop, | ||
139 | .pix_format = { | ||
140 | .width = 640, | ||
141 | .height = 480, | ||
142 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
143 | .priv = 8, | ||
144 | }, | ||
145 | .set_pix_format = &tas5130d1b_set_pix_format | ||
146 | }; | ||
147 | |||
148 | |||
149 | int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) | ||
150 | { | ||
151 | const struct usb_device_id tas5130d1b_id_table[] = { | ||
152 | { USB_DEVICE(0x0c45, 0x6024), }, | ||
153 | { USB_DEVICE(0x0c45, 0x6025), }, | ||
154 | { USB_DEVICE(0x0c45, 0x60aa), }, | ||
155 | { } | ||
156 | }; | ||
157 | |||
158 | /* Sensor detection is based on USB pid/vid */ | ||
159 | if (!sn9c102_match_id(cam, tas5130d1b_id_table)) | ||
160 | return -ENODEV; | ||
161 | |||
162 | sn9c102_attach_sensor(cam, &tas5130d1b); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 8c05565a240e..2189bfb2e828 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig | |||
@@ -83,14 +83,3 @@ config VIDEOBUF2_DMA_SG | |||
83 | #depends on HAS_DMA | 83 | #depends on HAS_DMA |
84 | select VIDEOBUF2_CORE | 84 | select VIDEOBUF2_CORE |
85 | select VIDEOBUF2_MEMOPS | 85 | select VIDEOBUF2_MEMOPS |
86 | |||
87 | config VIDEO_V4L2_INT_DEVICE | ||
88 | tristate "V4L2 int device (DEPRECATED)" | ||
89 | depends on VIDEO_V4L2 | ||
90 | ---help--- | ||
91 | An early framework for a hardware-independent interface for | ||
92 | image sensors and bridges etc. Currently used by omap24xxcam and | ||
93 | tcm825x drivers that should be converted to V4L2 subdev. | ||
94 | |||
95 | Do not use for new developments. | ||
96 | |||
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 1a85eee581f8..c6ae7bad951e 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile | |||
@@ -15,7 +15,6 @@ ifeq ($(CONFIG_OF),y) | |||
15 | endif | 15 | endif |
16 | 16 | ||
17 | obj-$(CONFIG_VIDEO_V4L2) += videodev.o | 17 | obj-$(CONFIG_VIDEO_V4L2) += videodev.o |
18 | obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o | ||
19 | obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o | 18 | obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o |
20 | obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o | 19 | obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o |
21 | 20 | ||
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index fb46790d0eca..6ff002bd5909 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c | |||
@@ -745,6 +745,11 @@ const char *v4l2_ctrl_get_name(u32 id) | |||
745 | case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: return "VPX Deblocking Effect Control"; | 745 | case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: return "VPX Deblocking Effect Control"; |
746 | case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: return "VPX Golden Frame Refresh Period"; | 746 | case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: return "VPX Golden Frame Refresh Period"; |
747 | case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: return "VPX Golden Frame Indicator"; | 747 | case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: return "VPX Golden Frame Indicator"; |
748 | case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: return "VPX Minimum QP Value"; | ||
749 | case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: return "VPX Maximum QP Value"; | ||
750 | case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: return "VPX I-Frame QP Value"; | ||
751 | case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value"; | ||
752 | case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: return "VPX Profile"; | ||
748 | 753 | ||
749 | /* CAMERA controls */ | 754 | /* CAMERA controls */ |
750 | /* Keep the order of the 'case's the same as in videodev2.h! */ | 755 | /* Keep the order of the 'case's the same as in videodev2.h! */ |
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index b5aaaac427ad..0a30dbf3d05c 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c | |||
@@ -872,8 +872,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, | |||
872 | 872 | ||
873 | /* Should not happen since we thought this minor was free */ | 873 | /* Should not happen since we thought this minor was free */ |
874 | WARN_ON(video_device[vdev->minor] != NULL); | 874 | WARN_ON(video_device[vdev->minor] != NULL); |
875 | video_device[vdev->minor] = vdev; | ||
876 | vdev->index = get_index(vdev); | 875 | vdev->index = get_index(vdev); |
876 | video_device[vdev->minor] = vdev; | ||
877 | mutex_unlock(&videodev_lock); | 877 | mutex_unlock(&videodev_lock); |
878 | 878 | ||
879 | if (vdev->ioctl_ops) | 879 | if (vdev->ioctl_ops) |
diff --git a/drivers/media/v4l2-core/v4l2-int-device.c b/drivers/media/v4l2-core/v4l2-int-device.c deleted file mode 100644 index f4473494af7a..000000000000 --- a/drivers/media/v4l2-core/v4l2-int-device.c +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/media/video/v4l2-int-device.c | ||
3 | * | ||
4 | * V4L2 internal ioctl interface. | ||
5 | * | ||
6 | * Copyright (C) 2007 Nokia Corporation. | ||
7 | * | ||
8 | * Contact: Sakari Ailus <sakari.ailus@nokia.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 | ||
12 | * version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * 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., 51 Franklin St, Fifth Floor, Boston, MA | ||
22 | * 02110-1301 USA | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/sort.h> | ||
28 | #include <linux/string.h> | ||
29 | #include <linux/module.h> | ||
30 | |||
31 | #include <media/v4l2-int-device.h> | ||
32 | |||
33 | static DEFINE_MUTEX(mutex); | ||
34 | static LIST_HEAD(int_list); | ||
35 | |||
36 | void v4l2_int_device_try_attach_all(void) | ||
37 | { | ||
38 | struct v4l2_int_device *m, *s; | ||
39 | |||
40 | list_for_each_entry(m, &int_list, head) { | ||
41 | if (m->type != v4l2_int_type_master) | ||
42 | continue; | ||
43 | |||
44 | list_for_each_entry(s, &int_list, head) { | ||
45 | if (s->type != v4l2_int_type_slave) | ||
46 | continue; | ||
47 | |||
48 | /* Slave is connected? */ | ||
49 | if (s->u.slave->master) | ||
50 | continue; | ||
51 | |||
52 | /* Slave wants to attach to master? */ | ||
53 | if (s->u.slave->attach_to[0] != 0 | ||
54 | && strncmp(m->name, s->u.slave->attach_to, | ||
55 | V4L2NAMESIZE)) | ||
56 | continue; | ||
57 | |||
58 | if (!try_module_get(m->module)) | ||
59 | continue; | ||
60 | |||
61 | s->u.slave->master = m; | ||
62 | if (m->u.master->attach(s)) { | ||
63 | s->u.slave->master = NULL; | ||
64 | module_put(m->module); | ||
65 | continue; | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all); | ||
71 | |||
72 | static int ioctl_sort_cmp(const void *a, const void *b) | ||
73 | { | ||
74 | const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; | ||
75 | |||
76 | if (d1->num > d2->num) | ||
77 | return 1; | ||
78 | |||
79 | if (d1->num < d2->num) | ||
80 | return -1; | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | int v4l2_int_device_register(struct v4l2_int_device *d) | ||
86 | { | ||
87 | if (d->type == v4l2_int_type_slave) | ||
88 | sort(d->u.slave->ioctls, d->u.slave->num_ioctls, | ||
89 | sizeof(struct v4l2_int_ioctl_desc), | ||
90 | &ioctl_sort_cmp, NULL); | ||
91 | mutex_lock(&mutex); | ||
92 | list_add(&d->head, &int_list); | ||
93 | v4l2_int_device_try_attach_all(); | ||
94 | mutex_unlock(&mutex); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(v4l2_int_device_register); | ||
99 | |||
100 | void v4l2_int_device_unregister(struct v4l2_int_device *d) | ||
101 | { | ||
102 | mutex_lock(&mutex); | ||
103 | list_del(&d->head); | ||
104 | if (d->type == v4l2_int_type_slave | ||
105 | && d->u.slave->master != NULL) { | ||
106 | d->u.slave->master->u.master->detach(d); | ||
107 | module_put(d->u.slave->master->module); | ||
108 | d->u.slave->master = NULL; | ||
109 | } | ||
110 | mutex_unlock(&mutex); | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); | ||
113 | |||
114 | /* Adapted from search_extable in extable.c. */ | ||
115 | static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, | ||
116 | v4l2_int_ioctl_func *no_such_ioctl) | ||
117 | { | ||
118 | const struct v4l2_int_ioctl_desc *first = slave->ioctls; | ||
119 | const struct v4l2_int_ioctl_desc *last = | ||
120 | first + slave->num_ioctls - 1; | ||
121 | |||
122 | while (first <= last) { | ||
123 | const struct v4l2_int_ioctl_desc *mid; | ||
124 | |||
125 | mid = (last - first) / 2 + first; | ||
126 | |||
127 | if (mid->num < cmd) | ||
128 | first = mid + 1; | ||
129 | else if (mid->num > cmd) | ||
130 | last = mid - 1; | ||
131 | else | ||
132 | return mid->func; | ||
133 | } | ||
134 | |||
135 | return no_such_ioctl; | ||
136 | } | ||
137 | |||
138 | static int no_such_ioctl_0(struct v4l2_int_device *d) | ||
139 | { | ||
140 | return -ENOIOCTLCMD; | ||
141 | } | ||
142 | |||
143 | int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) | ||
144 | { | ||
145 | return ((v4l2_int_ioctl_func_0 *) | ||
146 | find_ioctl(d->u.slave, cmd, | ||
147 | (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); | ||
148 | } | ||
149 | EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0); | ||
150 | |||
151 | static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) | ||
152 | { | ||
153 | return -ENOIOCTLCMD; | ||
154 | } | ||
155 | |||
156 | int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) | ||
157 | { | ||
158 | return ((v4l2_int_ioctl_func_1 *) | ||
159 | find_ioctl(d->u.slave, cmd, | ||
160 | (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); | ||
161 | } | ||
162 | EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1); | ||
163 | |||
164 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 68e6b5e912ff..707aef705a47 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <media/v4l2-device.h> | 28 | #include <media/v4l2-device.h> |
29 | #include <media/videobuf2-core.h> | 29 | #include <media/videobuf2-core.h> |
30 | 30 | ||
31 | #define CREATE_TRACE_POINTS | ||
32 | #include <trace/events/v4l2.h> | ||
33 | |||
31 | /* Zero out the end of the struct pointed to by p. Everything after, but | 34 | /* Zero out the end of the struct pointed to by p. Everything after, but |
32 | * not including, the specified field is cleared. */ | 35 | * not including, the specified field is cleared. */ |
33 | #define CLEAR_AFTER_FIELD(p, field) \ | 36 | #define CLEAR_AFTER_FIELD(p, field) \ |
@@ -2338,6 +2341,12 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | |||
2338 | err = func(file, cmd, parg); | 2341 | err = func(file, cmd, parg); |
2339 | if (err == -ENOIOCTLCMD) | 2342 | if (err == -ENOIOCTLCMD) |
2340 | err = -ENOTTY; | 2343 | err = -ENOTTY; |
2344 | if (err == 0) { | ||
2345 | if (cmd == VIDIOC_DQBUF) | ||
2346 | trace_v4l2_dqbuf(video_devdata(file)->minor, parg); | ||
2347 | else if (cmd == VIDIOC_QBUF) | ||
2348 | trace_v4l2_qbuf(video_devdata(file)->minor, parg); | ||
2349 | } | ||
2341 | 2350 | ||
2342 | if (has_array_args) { | 2351 | if (has_array_args) { |
2343 | *kernel_ptr = user_ptr; | 2352 | *kernel_ptr = user_ptr; |
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 73035ee0f4de..178ce96556c6 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c | |||
@@ -558,6 +558,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
558 | 558 | ||
559 | if (m2m_ctx->m2m_dev->m2m_ops->unlock) | 559 | if (m2m_ctx->m2m_dev->m2m_ops->unlock) |
560 | m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv); | 560 | m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv); |
561 | else if (m2m_ctx->q_lock) | ||
562 | mutex_unlock(m2m_ctx->q_lock); | ||
561 | 563 | ||
562 | if (list_empty(&src_q->done_list)) | 564 | if (list_empty(&src_q->done_list)) |
563 | poll_wait(file, &src_q->done_wq, wait); | 565 | poll_wait(file, &src_q->done_wq, wait); |
@@ -566,6 +568,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
566 | 568 | ||
567 | if (m2m_ctx->m2m_dev->m2m_ops->lock) | 569 | if (m2m_ctx->m2m_dev->m2m_ops->lock) |
568 | m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv); | 570 | m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv); |
571 | else if (m2m_ctx->q_lock) | ||
572 | mutex_lock(m2m_ctx->q_lock); | ||
569 | 573 | ||
570 | spin_lock_irqsave(&src_q->done_lock, flags); | 574 | spin_lock_irqsave(&src_q->done_lock, flags); |
571 | if (!list_empty(&src_q->done_list)) | 575 | if (!list_empty(&src_q->done_list)) |
@@ -693,6 +697,13 @@ struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev, | |||
693 | 697 | ||
694 | if (ret) | 698 | if (ret) |
695 | goto err; | 699 | goto err; |
700 | /* | ||
701 | * If both queues use same mutex assign it as the common buffer | ||
702 | * queues lock to the m2m context. This lock is used in the | ||
703 | * v4l2_m2m_ioctl_* helpers. | ||
704 | */ | ||
705 | if (out_q_ctx->q.lock == cap_q_ctx->q.lock) | ||
706 | m2m_ctx->q_lock = out_q_ctx->q.lock; | ||
696 | 707 | ||
697 | return m2m_ctx; | 708 | return m2m_ctx; |
698 | err: | 709 | err: |
@@ -740,3 +751,118 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb) | |||
740 | } | 751 | } |
741 | EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); | 752 | EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); |
742 | 753 | ||
754 | /* Videobuf2 ioctl helpers */ | ||
755 | |||
756 | int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv, | ||
757 | struct v4l2_requestbuffers *rb) | ||
758 | { | ||
759 | struct v4l2_fh *fh = file->private_data; | ||
760 | |||
761 | return v4l2_m2m_reqbufs(file, fh->m2m_ctx, rb); | ||
762 | } | ||
763 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_reqbufs); | ||
764 | |||
765 | int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv, | ||
766 | struct v4l2_create_buffers *create) | ||
767 | { | ||
768 | struct v4l2_fh *fh = file->private_data; | ||
769 | |||
770 | return v4l2_m2m_create_bufs(file, fh->m2m_ctx, create); | ||
771 | } | ||
772 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs); | ||
773 | |||
774 | int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv, | ||
775 | struct v4l2_buffer *buf) | ||
776 | { | ||
777 | struct v4l2_fh *fh = file->private_data; | ||
778 | |||
779 | return v4l2_m2m_querybuf(file, fh->m2m_ctx, buf); | ||
780 | } | ||
781 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_querybuf); | ||
782 | |||
783 | int v4l2_m2m_ioctl_qbuf(struct file *file, void *priv, | ||
784 | struct v4l2_buffer *buf) | ||
785 | { | ||
786 | struct v4l2_fh *fh = file->private_data; | ||
787 | |||
788 | return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf); | ||
789 | } | ||
790 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_qbuf); | ||
791 | |||
792 | int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv, | ||
793 | struct v4l2_buffer *buf) | ||
794 | { | ||
795 | struct v4l2_fh *fh = file->private_data; | ||
796 | |||
797 | return v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf); | ||
798 | } | ||
799 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_dqbuf); | ||
800 | |||
801 | int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv, | ||
802 | struct v4l2_exportbuffer *eb) | ||
803 | { | ||
804 | struct v4l2_fh *fh = file->private_data; | ||
805 | |||
806 | return v4l2_m2m_expbuf(file, fh->m2m_ctx, eb); | ||
807 | } | ||
808 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_expbuf); | ||
809 | |||
810 | int v4l2_m2m_ioctl_streamon(struct file *file, void *priv, | ||
811 | enum v4l2_buf_type type) | ||
812 | { | ||
813 | struct v4l2_fh *fh = file->private_data; | ||
814 | |||
815 | return v4l2_m2m_streamon(file, fh->m2m_ctx, type); | ||
816 | } | ||
817 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamon); | ||
818 | |||
819 | int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv, | ||
820 | enum v4l2_buf_type type) | ||
821 | { | ||
822 | struct v4l2_fh *fh = file->private_data; | ||
823 | |||
824 | return v4l2_m2m_streamoff(file, fh->m2m_ctx, type); | ||
825 | } | ||
826 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff); | ||
827 | |||
828 | /* | ||
829 | * v4l2_file_operations helpers. It is assumed here same lock is used | ||
830 | * for the output and the capture buffer queue. | ||
831 | */ | ||
832 | |||
833 | int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma) | ||
834 | { | ||
835 | struct v4l2_fh *fh = file->private_data; | ||
836 | struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx; | ||
837 | int ret; | ||
838 | |||
839 | if (m2m_ctx->q_lock && mutex_lock_interruptible(m2m_ctx->q_lock)) | ||
840 | return -ERESTARTSYS; | ||
841 | |||
842 | ret = v4l2_m2m_mmap(file, m2m_ctx, vma); | ||
843 | |||
844 | if (m2m_ctx->q_lock) | ||
845 | mutex_unlock(m2m_ctx->q_lock); | ||
846 | |||
847 | return ret; | ||
848 | } | ||
849 | EXPORT_SYMBOL_GPL(v4l2_m2m_fop_mmap); | ||
850 | |||
851 | unsigned int v4l2_m2m_fop_poll(struct file *file, poll_table *wait) | ||
852 | { | ||
853 | struct v4l2_fh *fh = file->private_data; | ||
854 | struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx; | ||
855 | unsigned int ret; | ||
856 | |||
857 | if (m2m_ctx->q_lock) | ||
858 | mutex_lock(m2m_ctx->q_lock); | ||
859 | |||
860 | ret = v4l2_m2m_poll(file, m2m_ctx, wait); | ||
861 | |||
862 | if (m2m_ctx->q_lock) | ||
863 | mutex_unlock(m2m_ctx->q_lock); | ||
864 | |||
865 | return ret; | ||
866 | } | ||
867 | EXPORT_SYMBOL_GPL(v4l2_m2m_fop_poll); | ||
868 | |||
diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index a6478dca0cde..42e3e8a5e361 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c | |||
@@ -121,9 +121,11 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, | |||
121 | * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the | 121 | * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the |
122 | * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. | 122 | * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. |
123 | * The caller should hold a reference to @node. | 123 | * The caller should hold a reference to @node. |
124 | * | ||
125 | * Return: 0. | ||
124 | */ | 126 | */ |
125 | void v4l2_of_parse_endpoint(const struct device_node *node, | 127 | int v4l2_of_parse_endpoint(const struct device_node *node, |
126 | struct v4l2_of_endpoint *endpoint) | 128 | struct v4l2_of_endpoint *endpoint) |
127 | { | 129 | { |
128 | struct device_node *port_node = of_get_parent(node); | 130 | struct device_node *port_node = of_get_parent(node); |
129 | 131 | ||
@@ -146,6 +148,8 @@ void v4l2_of_parse_endpoint(const struct device_node *node, | |||
146 | v4l2_of_parse_parallel_bus(node, endpoint); | 148 | v4l2_of_parse_parallel_bus(node, endpoint); |
147 | 149 | ||
148 | of_node_put(port_node); | 150 | of_node_put(port_node); |
151 | |||
152 | return 0; | ||
149 | } | 153 | } |
150 | EXPORT_SYMBOL(v4l2_of_parse_endpoint); | 154 | EXPORT_SYMBOL(v4l2_of_parse_endpoint); |
151 | 155 | ||
@@ -262,6 +266,6 @@ struct device_node *v4l2_of_get_remote_port(const struct device_node *node) | |||
262 | np = of_parse_phandle(node, "remote-endpoint", 0); | 266 | np = of_parse_phandle(node, "remote-endpoint", 0); |
263 | if (!np) | 267 | if (!np) |
264 | return NULL; | 268 | return NULL; |
265 | return of_get_parent(np); | 269 | return of_get_next_parent(np); |
266 | } | 270 | } |
267 | EXPORT_SYMBOL(v4l2_of_get_remote_port); | 271 | EXPORT_SYMBOL(v4l2_of_get_remote_port); |
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 0edc165f418d..5a5fb7f09b7b 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -298,10 +298,28 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) | |||
298 | * related information, if no buffers are left return the queue to an | 298 | * related information, if no buffers are left return the queue to an |
299 | * uninitialized state. Might be called even if the queue has already been freed. | 299 | * uninitialized state. Might be called even if the queue has already been freed. |
300 | */ | 300 | */ |
301 | static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) | 301 | static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) |
302 | { | 302 | { |
303 | unsigned int buffer; | 303 | unsigned int buffer; |
304 | 304 | ||
305 | /* | ||
306 | * Sanity check: when preparing a buffer the queue lock is released for | ||
307 | * a short while (see __buf_prepare for the details), which would allow | ||
308 | * a race with a reqbufs which can call this function. Removing the | ||
309 | * buffers from underneath __buf_prepare is obviously a bad idea, so we | ||
310 | * check if any of the buffers is in the state PREPARING, and if so we | ||
311 | * just return -EAGAIN. | ||
312 | */ | ||
313 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; | ||
314 | ++buffer) { | ||
315 | if (q->bufs[buffer] == NULL) | ||
316 | continue; | ||
317 | if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) { | ||
318 | dprintk(1, "reqbufs: preparing buffers, cannot free\n"); | ||
319 | return -EAGAIN; | ||
320 | } | ||
321 | } | ||
322 | |||
305 | /* Call driver-provided cleanup function for each buffer, if provided */ | 323 | /* Call driver-provided cleanup function for each buffer, if provided */ |
306 | if (q->ops->buf_cleanup) { | 324 | if (q->ops->buf_cleanup) { |
307 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; | 325 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
@@ -326,6 +344,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) | |||
326 | if (!q->num_buffers) | 344 | if (!q->num_buffers) |
327 | q->memory = 0; | 345 | q->memory = 0; |
328 | INIT_LIST_HEAD(&q->queued_list); | 346 | INIT_LIST_HEAD(&q->queued_list); |
347 | return 0; | ||
329 | } | 348 | } |
330 | 349 | ||
331 | /** | 350 | /** |
@@ -481,6 +500,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
481 | case VB2_BUF_STATE_PREPARED: | 500 | case VB2_BUF_STATE_PREPARED: |
482 | b->flags |= V4L2_BUF_FLAG_PREPARED; | 501 | b->flags |= V4L2_BUF_FLAG_PREPARED; |
483 | break; | 502 | break; |
503 | case VB2_BUF_STATE_PREPARING: | ||
484 | case VB2_BUF_STATE_DEQUEUED: | 504 | case VB2_BUF_STATE_DEQUEUED: |
485 | /* nothing */ | 505 | /* nothing */ |
486 | break; | 506 | break; |
@@ -657,7 +677,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
657 | return -EBUSY; | 677 | return -EBUSY; |
658 | } | 678 | } |
659 | 679 | ||
660 | __vb2_queue_free(q, q->num_buffers); | 680 | ret = __vb2_queue_free(q, q->num_buffers); |
681 | if (ret) | ||
682 | return ret; | ||
661 | 683 | ||
662 | /* | 684 | /* |
663 | * In case of REQBUFS(0) return immediately without calling | 685 | * In case of REQBUFS(0) return immediately without calling |
@@ -1116,7 +1138,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
1116 | int ret; | 1138 | int ret; |
1117 | int write = !V4L2_TYPE_IS_OUTPUT(q->type); | 1139 | int write = !V4L2_TYPE_IS_OUTPUT(q->type); |
1118 | 1140 | ||
1119 | /* Verify and copy relevant information provided by the userspace */ | 1141 | /* Copy relevant information provided by the userspace */ |
1120 | __fill_vb2_buffer(vb, b, planes); | 1142 | __fill_vb2_buffer(vb, b, planes); |
1121 | 1143 | ||
1122 | for (plane = 0; plane < vb->num_planes; ++plane) { | 1144 | for (plane = 0; plane < vb->num_planes; ++plane) { |
@@ -1135,6 +1157,8 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
1135 | 1157 | ||
1136 | if (planes[plane].length < planes[plane].data_offset + | 1158 | if (planes[plane].length < planes[plane].data_offset + |
1137 | q->plane_sizes[plane]) { | 1159 | q->plane_sizes[plane]) { |
1160 | dprintk(1, "qbuf: invalid dmabuf length for plane %d\n", | ||
1161 | plane); | ||
1138 | ret = -EINVAL; | 1162 | ret = -EINVAL; |
1139 | goto err; | 1163 | goto err; |
1140 | } | 1164 | } |
@@ -1226,6 +1250,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) | |||
1226 | static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) | 1250 | static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
1227 | { | 1251 | { |
1228 | struct vb2_queue *q = vb->vb2_queue; | 1252 | struct vb2_queue *q = vb->vb2_queue; |
1253 | struct rw_semaphore *mmap_sem; | ||
1229 | int ret; | 1254 | int ret; |
1230 | 1255 | ||
1231 | ret = __verify_length(vb, b); | 1256 | ret = __verify_length(vb, b); |
@@ -1235,12 +1260,32 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
1235 | return ret; | 1260 | return ret; |
1236 | } | 1261 | } |
1237 | 1262 | ||
1263 | vb->state = VB2_BUF_STATE_PREPARING; | ||
1238 | switch (q->memory) { | 1264 | switch (q->memory) { |
1239 | case V4L2_MEMORY_MMAP: | 1265 | case V4L2_MEMORY_MMAP: |
1240 | ret = __qbuf_mmap(vb, b); | 1266 | ret = __qbuf_mmap(vb, b); |
1241 | break; | 1267 | break; |
1242 | case V4L2_MEMORY_USERPTR: | 1268 | case V4L2_MEMORY_USERPTR: |
1269 | /* | ||
1270 | * In case of user pointer buffers vb2 allocators need to get | ||
1271 | * direct access to userspace pages. This requires getting | ||
1272 | * the mmap semaphore for read access in the current process | ||
1273 | * structure. The same semaphore is taken before calling mmap | ||
1274 | * operation, while both qbuf/prepare_buf and mmap are called | ||
1275 | * by the driver or v4l2 core with the driver's lock held. | ||
1276 | * To avoid an AB-BA deadlock (mmap_sem then driver's lock in | ||
1277 | * mmap and driver's lock then mmap_sem in qbuf/prepare_buf), | ||
1278 | * the videobuf2 core releases the driver's lock, takes | ||
1279 | * mmap_sem and then takes the driver's lock again. | ||
1280 | */ | ||
1281 | mmap_sem = ¤t->mm->mmap_sem; | ||
1282 | call_qop(q, wait_prepare, q); | ||
1283 | down_read(mmap_sem); | ||
1284 | call_qop(q, wait_finish, q); | ||
1285 | |||
1243 | ret = __qbuf_userptr(vb, b); | 1286 | ret = __qbuf_userptr(vb, b); |
1287 | |||
1288 | up_read(mmap_sem); | ||
1244 | break; | 1289 | break; |
1245 | case V4L2_MEMORY_DMABUF: | 1290 | case V4L2_MEMORY_DMABUF: |
1246 | ret = __qbuf_dmabuf(vb, b); | 1291 | ret = __qbuf_dmabuf(vb, b); |
@@ -1254,105 +1299,36 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
1254 | ret = call_qop(q, buf_prepare, vb); | 1299 | ret = call_qop(q, buf_prepare, vb); |
1255 | if (ret) | 1300 | if (ret) |
1256 | dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); | 1301 | dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); |
1257 | else | 1302 | vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED; |
1258 | vb->state = VB2_BUF_STATE_PREPARED; | ||
1259 | 1303 | ||
1260 | return ret; | 1304 | return ret; |
1261 | } | 1305 | } |
1262 | 1306 | ||
1263 | static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b, | 1307 | static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b, |
1264 | const char *opname, | 1308 | const char *opname) |
1265 | int (*handler)(struct vb2_queue *, | ||
1266 | struct v4l2_buffer *, | ||
1267 | struct vb2_buffer *)) | ||
1268 | { | 1309 | { |
1269 | struct rw_semaphore *mmap_sem = NULL; | ||
1270 | struct vb2_buffer *vb; | ||
1271 | int ret; | ||
1272 | |||
1273 | /* | ||
1274 | * In case of user pointer buffers vb2 allocators need to get direct | ||
1275 | * access to userspace pages. This requires getting the mmap semaphore | ||
1276 | * for read access in the current process structure. The same semaphore | ||
1277 | * is taken before calling mmap operation, while both qbuf/prepare_buf | ||
1278 | * and mmap are called by the driver or v4l2 core with the driver's lock | ||
1279 | * held. To avoid an AB-BA deadlock (mmap_sem then driver's lock in mmap | ||
1280 | * and driver's lock then mmap_sem in qbuf/prepare_buf) the videobuf2 | ||
1281 | * core releases the driver's lock, takes mmap_sem and then takes the | ||
1282 | * driver's lock again. | ||
1283 | * | ||
1284 | * To avoid racing with other vb2 calls, which might be called after | ||
1285 | * releasing the driver's lock, this operation is performed at the | ||
1286 | * beginning of qbuf/prepare_buf processing. This way the queue status | ||
1287 | * is consistent after getting the driver's lock back. | ||
1288 | */ | ||
1289 | if (q->memory == V4L2_MEMORY_USERPTR) { | ||
1290 | mmap_sem = ¤t->mm->mmap_sem; | ||
1291 | call_qop(q, wait_prepare, q); | ||
1292 | down_read(mmap_sem); | ||
1293 | call_qop(q, wait_finish, q); | ||
1294 | } | ||
1295 | |||
1296 | if (q->fileio) { | ||
1297 | dprintk(1, "%s(): file io in progress\n", opname); | ||
1298 | ret = -EBUSY; | ||
1299 | goto unlock; | ||
1300 | } | ||
1301 | |||
1302 | if (b->type != q->type) { | 1310 | if (b->type != q->type) { |
1303 | dprintk(1, "%s(): invalid buffer type\n", opname); | 1311 | dprintk(1, "%s(): invalid buffer type\n", opname); |
1304 | ret = -EINVAL; | 1312 | return -EINVAL; |
1305 | goto unlock; | ||
1306 | } | 1313 | } |
1307 | 1314 | ||
1308 | if (b->index >= q->num_buffers) { | 1315 | if (b->index >= q->num_buffers) { |
1309 | dprintk(1, "%s(): buffer index out of range\n", opname); | 1316 | dprintk(1, "%s(): buffer index out of range\n", opname); |
1310 | ret = -EINVAL; | 1317 | return -EINVAL; |
1311 | goto unlock; | ||
1312 | } | 1318 | } |
1313 | 1319 | ||
1314 | vb = q->bufs[b->index]; | 1320 | if (q->bufs[b->index] == NULL) { |
1315 | if (NULL == vb) { | ||
1316 | /* Should never happen */ | 1321 | /* Should never happen */ |
1317 | dprintk(1, "%s(): buffer is NULL\n", opname); | 1322 | dprintk(1, "%s(): buffer is NULL\n", opname); |
1318 | ret = -EINVAL; | 1323 | return -EINVAL; |
1319 | goto unlock; | ||
1320 | } | 1324 | } |
1321 | 1325 | ||
1322 | if (b->memory != q->memory) { | 1326 | if (b->memory != q->memory) { |
1323 | dprintk(1, "%s(): invalid memory type\n", opname); | 1327 | dprintk(1, "%s(): invalid memory type\n", opname); |
1324 | ret = -EINVAL; | ||
1325 | goto unlock; | ||
1326 | } | ||
1327 | |||
1328 | ret = __verify_planes_array(vb, b); | ||
1329 | if (ret) | ||
1330 | goto unlock; | ||
1331 | |||
1332 | ret = handler(q, b, vb); | ||
1333 | if (ret) | ||
1334 | goto unlock; | ||
1335 | |||
1336 | /* Fill buffer information for the userspace */ | ||
1337 | __fill_v4l2_buffer(vb, b); | ||
1338 | |||
1339 | dprintk(1, "%s() of buffer %d succeeded\n", opname, vb->v4l2_buf.index); | ||
1340 | unlock: | ||
1341 | if (mmap_sem) | ||
1342 | up_read(mmap_sem); | ||
1343 | return ret; | ||
1344 | } | ||
1345 | |||
1346 | static int __vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b, | ||
1347 | struct vb2_buffer *vb) | ||
1348 | { | ||
1349 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | ||
1350 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, | ||
1351 | vb->state); | ||
1352 | return -EINVAL; | 1328 | return -EINVAL; |
1353 | } | 1329 | } |
1354 | 1330 | ||
1355 | return __buf_prepare(vb, b); | 1331 | return __verify_planes_array(q->bufs[b->index], b); |
1356 | } | 1332 | } |
1357 | 1333 | ||
1358 | /** | 1334 | /** |
@@ -1372,22 +1348,95 @@ static int __vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b, | |||
1372 | */ | 1348 | */ |
1373 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) | 1349 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) |
1374 | { | 1350 | { |
1375 | return vb2_queue_or_prepare_buf(q, b, "prepare_buf", __vb2_prepare_buf); | 1351 | struct vb2_buffer *vb; |
1352 | int ret; | ||
1353 | |||
1354 | if (q->fileio) { | ||
1355 | dprintk(1, "%s(): file io in progress\n", __func__); | ||
1356 | return -EBUSY; | ||
1357 | } | ||
1358 | |||
1359 | ret = vb2_queue_or_prepare_buf(q, b, "prepare_buf"); | ||
1360 | if (ret) | ||
1361 | return ret; | ||
1362 | |||
1363 | vb = q->bufs[b->index]; | ||
1364 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | ||
1365 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, | ||
1366 | vb->state); | ||
1367 | return -EINVAL; | ||
1368 | } | ||
1369 | |||
1370 | ret = __buf_prepare(vb, b); | ||
1371 | if (!ret) { | ||
1372 | /* Fill buffer information for the userspace */ | ||
1373 | __fill_v4l2_buffer(vb, b); | ||
1374 | |||
1375 | dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index); | ||
1376 | } | ||
1377 | return ret; | ||
1376 | } | 1378 | } |
1377 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); | 1379 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); |
1378 | 1380 | ||
1379 | static int __vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b, | 1381 | /** |
1380 | struct vb2_buffer *vb) | 1382 | * vb2_start_streaming() - Attempt to start streaming. |
1383 | * @q: videobuf2 queue | ||
1384 | * | ||
1385 | * If there are not enough buffers, then retry_start_streaming is set to | ||
1386 | * 1 and 0 is returned. The next time a buffer is queued and | ||
1387 | * retry_start_streaming is 1, this function will be called again to | ||
1388 | * retry starting the DMA engine. | ||
1389 | */ | ||
1390 | static int vb2_start_streaming(struct vb2_queue *q) | ||
1381 | { | 1391 | { |
1382 | int ret; | 1392 | int ret; |
1383 | 1393 | ||
1394 | /* Tell the driver to start streaming */ | ||
1395 | ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); | ||
1396 | |||
1397 | /* | ||
1398 | * If there are not enough buffers queued to start streaming, then | ||
1399 | * the start_streaming operation will return -ENOBUFS and you have to | ||
1400 | * retry when the next buffer is queued. | ||
1401 | */ | ||
1402 | if (ret == -ENOBUFS) { | ||
1403 | dprintk(1, "qbuf: not enough buffers, retry when more buffers are queued.\n"); | ||
1404 | q->retry_start_streaming = 1; | ||
1405 | return 0; | ||
1406 | } | ||
1407 | if (ret) | ||
1408 | dprintk(1, "qbuf: driver refused to start streaming\n"); | ||
1409 | else | ||
1410 | q->retry_start_streaming = 0; | ||
1411 | return ret; | ||
1412 | } | ||
1413 | |||
1414 | static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | ||
1415 | { | ||
1416 | int ret = vb2_queue_or_prepare_buf(q, b, "qbuf"); | ||
1417 | struct vb2_buffer *vb; | ||
1418 | |||
1419 | if (ret) | ||
1420 | return ret; | ||
1421 | |||
1422 | vb = q->bufs[b->index]; | ||
1423 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | ||
1424 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, | ||
1425 | vb->state); | ||
1426 | return -EINVAL; | ||
1427 | } | ||
1428 | |||
1384 | switch (vb->state) { | 1429 | switch (vb->state) { |
1385 | case VB2_BUF_STATE_DEQUEUED: | 1430 | case VB2_BUF_STATE_DEQUEUED: |
1386 | ret = __buf_prepare(vb, b); | 1431 | ret = __buf_prepare(vb, b); |
1387 | if (ret) | 1432 | if (ret) |
1388 | return ret; | 1433 | return ret; |
1434 | break; | ||
1389 | case VB2_BUF_STATE_PREPARED: | 1435 | case VB2_BUF_STATE_PREPARED: |
1390 | break; | 1436 | break; |
1437 | case VB2_BUF_STATE_PREPARING: | ||
1438 | dprintk(1, "qbuf: buffer still being prepared\n"); | ||
1439 | return -EINVAL; | ||
1391 | default: | 1440 | default: |
1392 | dprintk(1, "qbuf: buffer already in use\n"); | 1441 | dprintk(1, "qbuf: buffer already in use\n"); |
1393 | return -EINVAL; | 1442 | return -EINVAL; |
@@ -1407,6 +1456,16 @@ static int __vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b, | |||
1407 | if (q->streaming) | 1456 | if (q->streaming) |
1408 | __enqueue_in_driver(vb); | 1457 | __enqueue_in_driver(vb); |
1409 | 1458 | ||
1459 | /* Fill buffer information for the userspace */ | ||
1460 | __fill_v4l2_buffer(vb, b); | ||
1461 | |||
1462 | if (q->retry_start_streaming) { | ||
1463 | ret = vb2_start_streaming(q); | ||
1464 | if (ret) | ||
1465 | return ret; | ||
1466 | } | ||
1467 | |||
1468 | dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index); | ||
1410 | return 0; | 1469 | return 0; |
1411 | } | 1470 | } |
1412 | 1471 | ||
@@ -1429,7 +1488,12 @@ static int __vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b, | |||
1429 | */ | 1488 | */ |
1430 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | 1489 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) |
1431 | { | 1490 | { |
1432 | return vb2_queue_or_prepare_buf(q, b, "qbuf", __vb2_qbuf); | 1491 | if (q->fileio) { |
1492 | dprintk(1, "%s(): file io in progress\n", __func__); | ||
1493 | return -EBUSY; | ||
1494 | } | ||
1495 | |||
1496 | return vb2_internal_qbuf(q, b); | ||
1433 | } | 1497 | } |
1434 | EXPORT_SYMBOL_GPL(vb2_qbuf); | 1498 | EXPORT_SYMBOL_GPL(vb2_qbuf); |
1435 | 1499 | ||
@@ -1550,7 +1614,8 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q) | |||
1550 | return -EINVAL; | 1614 | return -EINVAL; |
1551 | } | 1615 | } |
1552 | 1616 | ||
1553 | wait_event(q->done_wq, !atomic_read(&q->queued_count)); | 1617 | if (!q->retry_start_streaming) |
1618 | wait_event(q->done_wq, !atomic_read(&q->queued_count)); | ||
1554 | return 0; | 1619 | return 0; |
1555 | } | 1620 | } |
1556 | EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); | 1621 | EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); |
@@ -1579,37 +1644,11 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) | |||
1579 | } | 1644 | } |
1580 | } | 1645 | } |
1581 | 1646 | ||
1582 | /** | 1647 | static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) |
1583 | * vb2_dqbuf() - Dequeue a buffer to the userspace | ||
1584 | * @q: videobuf2 queue | ||
1585 | * @b: buffer structure passed from userspace to vidioc_dqbuf handler | ||
1586 | * in driver | ||
1587 | * @nonblocking: if true, this call will not sleep waiting for a buffer if no | ||
1588 | * buffers ready for dequeuing are present. Normally the driver | ||
1589 | * would be passing (file->f_flags & O_NONBLOCK) here | ||
1590 | * | ||
1591 | * Should be called from vidioc_dqbuf ioctl handler of a driver. | ||
1592 | * This function: | ||
1593 | * 1) verifies the passed buffer, | ||
1594 | * 2) calls buf_finish callback in the driver (if provided), in which | ||
1595 | * driver can perform any additional operations that may be required before | ||
1596 | * returning the buffer to userspace, such as cache sync, | ||
1597 | * 3) the buffer struct members are filled with relevant information for | ||
1598 | * the userspace. | ||
1599 | * | ||
1600 | * The return values from this function are intended to be directly returned | ||
1601 | * from vidioc_dqbuf handler in driver. | ||
1602 | */ | ||
1603 | int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) | ||
1604 | { | 1648 | { |
1605 | struct vb2_buffer *vb = NULL; | 1649 | struct vb2_buffer *vb = NULL; |
1606 | int ret; | 1650 | int ret; |
1607 | 1651 | ||
1608 | if (q->fileio) { | ||
1609 | dprintk(1, "dqbuf: file io in progress\n"); | ||
1610 | return -EBUSY; | ||
1611 | } | ||
1612 | |||
1613 | if (b->type != q->type) { | 1652 | if (b->type != q->type) { |
1614 | dprintk(1, "dqbuf: invalid buffer type\n"); | 1653 | dprintk(1, "dqbuf: invalid buffer type\n"); |
1615 | return -EINVAL; | 1654 | return -EINVAL; |
@@ -1648,6 +1687,36 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) | |||
1648 | 1687 | ||
1649 | return 0; | 1688 | return 0; |
1650 | } | 1689 | } |
1690 | |||
1691 | /** | ||
1692 | * vb2_dqbuf() - Dequeue a buffer to the userspace | ||
1693 | * @q: videobuf2 queue | ||
1694 | * @b: buffer structure passed from userspace to vidioc_dqbuf handler | ||
1695 | * in driver | ||
1696 | * @nonblocking: if true, this call will not sleep waiting for a buffer if no | ||
1697 | * buffers ready for dequeuing are present. Normally the driver | ||
1698 | * would be passing (file->f_flags & O_NONBLOCK) here | ||
1699 | * | ||
1700 | * Should be called from vidioc_dqbuf ioctl handler of a driver. | ||
1701 | * This function: | ||
1702 | * 1) verifies the passed buffer, | ||
1703 | * 2) calls buf_finish callback in the driver (if provided), in which | ||
1704 | * driver can perform any additional operations that may be required before | ||
1705 | * returning the buffer to userspace, such as cache sync, | ||
1706 | * 3) the buffer struct members are filled with relevant information for | ||
1707 | * the userspace. | ||
1708 | * | ||
1709 | * The return values from this function are intended to be directly returned | ||
1710 | * from vidioc_dqbuf handler in driver. | ||
1711 | */ | ||
1712 | int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) | ||
1713 | { | ||
1714 | if (q->fileio) { | ||
1715 | dprintk(1, "dqbuf: file io in progress\n"); | ||
1716 | return -EBUSY; | ||
1717 | } | ||
1718 | return vb2_internal_dqbuf(q, b, nonblocking); | ||
1719 | } | ||
1651 | EXPORT_SYMBOL_GPL(vb2_dqbuf); | 1720 | EXPORT_SYMBOL_GPL(vb2_dqbuf); |
1652 | 1721 | ||
1653 | /** | 1722 | /** |
@@ -1660,6 +1729,11 @@ static void __vb2_queue_cancel(struct vb2_queue *q) | |||
1660 | { | 1729 | { |
1661 | unsigned int i; | 1730 | unsigned int i; |
1662 | 1731 | ||
1732 | if (q->retry_start_streaming) { | ||
1733 | q->retry_start_streaming = 0; | ||
1734 | q->streaming = 0; | ||
1735 | } | ||
1736 | |||
1663 | /* | 1737 | /* |
1664 | * Tell driver to stop all transactions and release all queued | 1738 | * Tell driver to stop all transactions and release all queued |
1665 | * buffers. | 1739 | * buffers. |
@@ -1687,37 +1761,19 @@ static void __vb2_queue_cancel(struct vb2_queue *q) | |||
1687 | __vb2_dqbuf(q->bufs[i]); | 1761 | __vb2_dqbuf(q->bufs[i]); |
1688 | } | 1762 | } |
1689 | 1763 | ||
1690 | /** | 1764 | static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) |
1691 | * vb2_streamon - start streaming | ||
1692 | * @q: videobuf2 queue | ||
1693 | * @type: type argument passed from userspace to vidioc_streamon handler | ||
1694 | * | ||
1695 | * Should be called from vidioc_streamon handler of a driver. | ||
1696 | * This function: | ||
1697 | * 1) verifies current state | ||
1698 | * 2) passes any previously queued buffers to the driver and starts streaming | ||
1699 | * | ||
1700 | * The return values from this function are intended to be directly returned | ||
1701 | * from vidioc_streamon handler in the driver. | ||
1702 | */ | ||
1703 | int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) | ||
1704 | { | 1765 | { |
1705 | struct vb2_buffer *vb; | 1766 | struct vb2_buffer *vb; |
1706 | int ret; | 1767 | int ret; |
1707 | 1768 | ||
1708 | if (q->fileio) { | ||
1709 | dprintk(1, "streamon: file io in progress\n"); | ||
1710 | return -EBUSY; | ||
1711 | } | ||
1712 | |||
1713 | if (type != q->type) { | 1769 | if (type != q->type) { |
1714 | dprintk(1, "streamon: invalid stream type\n"); | 1770 | dprintk(1, "streamon: invalid stream type\n"); |
1715 | return -EINVAL; | 1771 | return -EINVAL; |
1716 | } | 1772 | } |
1717 | 1773 | ||
1718 | if (q->streaming) { | 1774 | if (q->streaming) { |
1719 | dprintk(1, "streamon: already streaming\n"); | 1775 | dprintk(3, "streamon successful: already streaming\n"); |
1720 | return -EBUSY; | 1776 | return 0; |
1721 | } | 1777 | } |
1722 | 1778 | ||
1723 | /* | 1779 | /* |
@@ -1727,12 +1783,9 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) | |||
1727 | list_for_each_entry(vb, &q->queued_list, queued_entry) | 1783 | list_for_each_entry(vb, &q->queued_list, queued_entry) |
1728 | __enqueue_in_driver(vb); | 1784 | __enqueue_in_driver(vb); |
1729 | 1785 | ||
1730 | /* | 1786 | /* Tell driver to start streaming. */ |
1731 | * Let driver notice that streaming state has been enabled. | 1787 | ret = vb2_start_streaming(q); |
1732 | */ | ||
1733 | ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); | ||
1734 | if (ret) { | 1788 | if (ret) { |
1735 | dprintk(1, "streamon: driver refused to start streaming\n"); | ||
1736 | __vb2_queue_cancel(q); | 1789 | __vb2_queue_cancel(q); |
1737 | return ret; | 1790 | return ret; |
1738 | } | 1791 | } |
@@ -1742,39 +1795,40 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) | |||
1742 | dprintk(3, "Streamon successful\n"); | 1795 | dprintk(3, "Streamon successful\n"); |
1743 | return 0; | 1796 | return 0; |
1744 | } | 1797 | } |
1745 | EXPORT_SYMBOL_GPL(vb2_streamon); | ||
1746 | |||
1747 | 1798 | ||
1748 | /** | 1799 | /** |
1749 | * vb2_streamoff - stop streaming | 1800 | * vb2_streamon - start streaming |
1750 | * @q: videobuf2 queue | 1801 | * @q: videobuf2 queue |
1751 | * @type: type argument passed from userspace to vidioc_streamoff handler | 1802 | * @type: type argument passed from userspace to vidioc_streamon handler |
1752 | * | 1803 | * |
1753 | * Should be called from vidioc_streamoff handler of a driver. | 1804 | * Should be called from vidioc_streamon handler of a driver. |
1754 | * This function: | 1805 | * This function: |
1755 | * 1) verifies current state, | 1806 | * 1) verifies current state |
1756 | * 2) stop streaming and dequeues any queued buffers, including those previously | 1807 | * 2) passes any previously queued buffers to the driver and starts streaming |
1757 | * passed to the driver (after waiting for the driver to finish). | ||
1758 | * | 1808 | * |
1759 | * This call can be used for pausing playback. | ||
1760 | * The return values from this function are intended to be directly returned | 1809 | * The return values from this function are intended to be directly returned |
1761 | * from vidioc_streamoff handler in the driver | 1810 | * from vidioc_streamon handler in the driver. |
1762 | */ | 1811 | */ |
1763 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) | 1812 | int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) |
1764 | { | 1813 | { |
1765 | if (q->fileio) { | 1814 | if (q->fileio) { |
1766 | dprintk(1, "streamoff: file io in progress\n"); | 1815 | dprintk(1, "streamon: file io in progress\n"); |
1767 | return -EBUSY; | 1816 | return -EBUSY; |
1768 | } | 1817 | } |
1818 | return vb2_internal_streamon(q, type); | ||
1819 | } | ||
1820 | EXPORT_SYMBOL_GPL(vb2_streamon); | ||
1769 | 1821 | ||
1822 | static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) | ||
1823 | { | ||
1770 | if (type != q->type) { | 1824 | if (type != q->type) { |
1771 | dprintk(1, "streamoff: invalid stream type\n"); | 1825 | dprintk(1, "streamoff: invalid stream type\n"); |
1772 | return -EINVAL; | 1826 | return -EINVAL; |
1773 | } | 1827 | } |
1774 | 1828 | ||
1775 | if (!q->streaming) { | 1829 | if (!q->streaming) { |
1776 | dprintk(1, "streamoff: not streaming\n"); | 1830 | dprintk(3, "streamoff successful: not streaming\n"); |
1777 | return -EINVAL; | 1831 | return 0; |
1778 | } | 1832 | } |
1779 | 1833 | ||
1780 | /* | 1834 | /* |
@@ -1786,6 +1840,30 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) | |||
1786 | dprintk(3, "Streamoff successful\n"); | 1840 | dprintk(3, "Streamoff successful\n"); |
1787 | return 0; | 1841 | return 0; |
1788 | } | 1842 | } |
1843 | |||
1844 | /** | ||
1845 | * vb2_streamoff - stop streaming | ||
1846 | * @q: videobuf2 queue | ||
1847 | * @type: type argument passed from userspace to vidioc_streamoff handler | ||
1848 | * | ||
1849 | * Should be called from vidioc_streamoff handler of a driver. | ||
1850 | * This function: | ||
1851 | * 1) verifies current state, | ||
1852 | * 2) stop streaming and dequeues any queued buffers, including those previously | ||
1853 | * passed to the driver (after waiting for the driver to finish). | ||
1854 | * | ||
1855 | * This call can be used for pausing playback. | ||
1856 | * The return values from this function are intended to be directly returned | ||
1857 | * from vidioc_streamoff handler in the driver | ||
1858 | */ | ||
1859 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) | ||
1860 | { | ||
1861 | if (q->fileio) { | ||
1862 | dprintk(1, "streamoff: file io in progress\n"); | ||
1863 | return -EBUSY; | ||
1864 | } | ||
1865 | return vb2_internal_streamoff(q, type); | ||
1866 | } | ||
1789 | EXPORT_SYMBOL_GPL(vb2_streamoff); | 1867 | EXPORT_SYMBOL_GPL(vb2_streamoff); |
1790 | 1868 | ||
1791 | /** | 1869 | /** |
@@ -2277,15 +2355,16 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) | |||
2277 | goto err_reqbufs; | 2355 | goto err_reqbufs; |
2278 | fileio->bufs[i].queued = 1; | 2356 | fileio->bufs[i].queued = 1; |
2279 | } | 2357 | } |
2280 | 2358 | fileio->index = q->num_buffers; | |
2281 | /* | ||
2282 | * Start streaming. | ||
2283 | */ | ||
2284 | ret = vb2_streamon(q, q->type); | ||
2285 | if (ret) | ||
2286 | goto err_reqbufs; | ||
2287 | } | 2359 | } |
2288 | 2360 | ||
2361 | /* | ||
2362 | * Start streaming. | ||
2363 | */ | ||
2364 | ret = vb2_streamon(q, q->type); | ||
2365 | if (ret) | ||
2366 | goto err_reqbufs; | ||
2367 | |||
2289 | q->fileio = fileio; | 2368 | q->fileio = fileio; |
2290 | 2369 | ||
2291 | return ret; | 2370 | return ret; |
@@ -2308,13 +2387,8 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q) | |||
2308 | struct vb2_fileio_data *fileio = q->fileio; | 2387 | struct vb2_fileio_data *fileio = q->fileio; |
2309 | 2388 | ||
2310 | if (fileio) { | 2389 | if (fileio) { |
2311 | /* | 2390 | vb2_internal_streamoff(q, q->type); |
2312 | * Hack fileio context to enable direct calls to vb2 ioctl | ||
2313 | * interface. | ||
2314 | */ | ||
2315 | q->fileio = NULL; | 2391 | q->fileio = NULL; |
2316 | |||
2317 | vb2_streamoff(q, q->type); | ||
2318 | fileio->req.count = 0; | 2392 | fileio->req.count = 0; |
2319 | vb2_reqbufs(q, &fileio->req); | 2393 | vb2_reqbufs(q, &fileio->req); |
2320 | kfree(fileio); | 2394 | kfree(fileio); |
@@ -2358,39 +2432,34 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ | |||
2358 | fileio = q->fileio; | 2432 | fileio = q->fileio; |
2359 | 2433 | ||
2360 | /* | 2434 | /* |
2361 | * Hack fileio context to enable direct calls to vb2 ioctl interface. | ||
2362 | * The pointer will be restored before returning from this function. | ||
2363 | */ | ||
2364 | q->fileio = NULL; | ||
2365 | |||
2366 | index = fileio->index; | ||
2367 | buf = &fileio->bufs[index]; | ||
2368 | |||
2369 | /* | ||
2370 | * Check if we need to dequeue the buffer. | 2435 | * Check if we need to dequeue the buffer. |
2371 | */ | 2436 | */ |
2372 | if (buf->queued) { | 2437 | index = fileio->index; |
2373 | struct vb2_buffer *vb; | 2438 | if (index >= q->num_buffers) { |
2374 | |||
2375 | /* | 2439 | /* |
2376 | * Call vb2_dqbuf to get buffer back. | 2440 | * Call vb2_dqbuf to get buffer back. |
2377 | */ | 2441 | */ |
2378 | memset(&fileio->b, 0, sizeof(fileio->b)); | 2442 | memset(&fileio->b, 0, sizeof(fileio->b)); |
2379 | fileio->b.type = q->type; | 2443 | fileio->b.type = q->type; |
2380 | fileio->b.memory = q->memory; | 2444 | fileio->b.memory = q->memory; |
2381 | fileio->b.index = index; | 2445 | ret = vb2_internal_dqbuf(q, &fileio->b, nonblock); |
2382 | ret = vb2_dqbuf(q, &fileio->b, nonblock); | ||
2383 | dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); | 2446 | dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); |
2384 | if (ret) | 2447 | if (ret) |
2385 | goto end; | 2448 | return ret; |
2386 | fileio->dq_count += 1; | 2449 | fileio->dq_count += 1; |
2387 | 2450 | ||
2451 | index = fileio->b.index; | ||
2452 | buf = &fileio->bufs[index]; | ||
2453 | |||
2388 | /* | 2454 | /* |
2389 | * Get number of bytes filled by the driver | 2455 | * Get number of bytes filled by the driver |
2390 | */ | 2456 | */ |
2391 | vb = q->bufs[index]; | 2457 | buf->pos = 0; |
2392 | buf->size = vb2_get_plane_payload(vb, 0); | ||
2393 | buf->queued = 0; | 2458 | buf->queued = 0; |
2459 | buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) | ||
2460 | : vb2_plane_size(q->bufs[index], 0); | ||
2461 | } else { | ||
2462 | buf = &fileio->bufs[index]; | ||
2394 | } | 2463 | } |
2395 | 2464 | ||
2396 | /* | 2465 | /* |
@@ -2412,8 +2481,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ | |||
2412 | ret = copy_from_user(buf->vaddr + buf->pos, data, count); | 2481 | ret = copy_from_user(buf->vaddr + buf->pos, data, count); |
2413 | if (ret) { | 2482 | if (ret) { |
2414 | dprintk(3, "file io: error copying data\n"); | 2483 | dprintk(3, "file io: error copying data\n"); |
2415 | ret = -EFAULT; | 2484 | return -EFAULT; |
2416 | goto end; | ||
2417 | } | 2485 | } |
2418 | 2486 | ||
2419 | /* | 2487 | /* |
@@ -2433,10 +2501,6 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ | |||
2433 | if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) && | 2501 | if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) && |
2434 | fileio->dq_count == 1) { | 2502 | fileio->dq_count == 1) { |
2435 | dprintk(3, "file io: read limit reached\n"); | 2503 | dprintk(3, "file io: read limit reached\n"); |
2436 | /* | ||
2437 | * Restore fileio pointer and release the context. | ||
2438 | */ | ||
2439 | q->fileio = fileio; | ||
2440 | return __vb2_cleanup_fileio(q); | 2504 | return __vb2_cleanup_fileio(q); |
2441 | } | 2505 | } |
2442 | 2506 | ||
@@ -2448,32 +2512,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ | |||
2448 | fileio->b.memory = q->memory; | 2512 | fileio->b.memory = q->memory; |
2449 | fileio->b.index = index; | 2513 | fileio->b.index = index; |
2450 | fileio->b.bytesused = buf->pos; | 2514 | fileio->b.bytesused = buf->pos; |
2451 | ret = vb2_qbuf(q, &fileio->b); | 2515 | ret = vb2_internal_qbuf(q, &fileio->b); |
2452 | dprintk(5, "file io: vb2_dbuf result: %d\n", ret); | 2516 | dprintk(5, "file io: vb2_dbuf result: %d\n", ret); |
2453 | if (ret) | 2517 | if (ret) |
2454 | goto end; | 2518 | return ret; |
2455 | 2519 | ||
2456 | /* | 2520 | /* |
2457 | * Buffer has been queued, update the status | 2521 | * Buffer has been queued, update the status |
2458 | */ | 2522 | */ |
2459 | buf->pos = 0; | 2523 | buf->pos = 0; |
2460 | buf->queued = 1; | 2524 | buf->queued = 1; |
2461 | buf->size = q->bufs[0]->v4l2_planes[0].length; | 2525 | buf->size = vb2_plane_size(q->bufs[index], 0); |
2462 | fileio->q_count += 1; | 2526 | fileio->q_count += 1; |
2463 | 2527 | if (fileio->index < q->num_buffers) | |
2464 | /* | 2528 | fileio->index++; |
2465 | * Switch to the next buffer | ||
2466 | */ | ||
2467 | fileio->index = (index + 1) % q->num_buffers; | ||
2468 | |||
2469 | /* | ||
2470 | * Start streaming if required. | ||
2471 | */ | ||
2472 | if (!read && !q->streaming) { | ||
2473 | ret = vb2_streamon(q, q->type); | ||
2474 | if (ret) | ||
2475 | goto end; | ||
2476 | } | ||
2477 | } | 2529 | } |
2478 | 2530 | ||
2479 | /* | 2531 | /* |
@@ -2481,11 +2533,6 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ | |||
2481 | */ | 2533 | */ |
2482 | if (ret == 0) | 2534 | if (ret == 0) |
2483 | ret = count; | 2535 | ret = count; |
2484 | end: | ||
2485 | /* | ||
2486 | * Restore the fileio context and block vb2 ioctl interface. | ||
2487 | */ | ||
2488 | q->fileio = fileio; | ||
2489 | return ret; | 2536 | return ret; |
2490 | } | 2537 | } |
2491 | 2538 | ||
@@ -2649,16 +2696,29 @@ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) | |||
2649 | } | 2696 | } |
2650 | EXPORT_SYMBOL_GPL(vb2_fop_mmap); | 2697 | EXPORT_SYMBOL_GPL(vb2_fop_mmap); |
2651 | 2698 | ||
2652 | int vb2_fop_release(struct file *file) | 2699 | int _vb2_fop_release(struct file *file, struct mutex *lock) |
2653 | { | 2700 | { |
2654 | struct video_device *vdev = video_devdata(file); | 2701 | struct video_device *vdev = video_devdata(file); |
2655 | 2702 | ||
2656 | if (file->private_data == vdev->queue->owner) { | 2703 | if (file->private_data == vdev->queue->owner) { |
2704 | if (lock) | ||
2705 | mutex_lock(lock); | ||
2657 | vb2_queue_release(vdev->queue); | 2706 | vb2_queue_release(vdev->queue); |
2658 | vdev->queue->owner = NULL; | 2707 | vdev->queue->owner = NULL; |
2708 | if (lock) | ||
2709 | mutex_unlock(lock); | ||
2659 | } | 2710 | } |
2660 | return v4l2_fh_release(file); | 2711 | return v4l2_fh_release(file); |
2661 | } | 2712 | } |
2713 | EXPORT_SYMBOL_GPL(_vb2_fop_release); | ||
2714 | |||
2715 | int vb2_fop_release(struct file *file) | ||
2716 | { | ||
2717 | struct video_device *vdev = video_devdata(file); | ||
2718 | struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; | ||
2719 | |||
2720 | return _vb2_fop_release(file, lock); | ||
2721 | } | ||
2662 | EXPORT_SYMBOL_GPL(vb2_fop_release); | 2722 | EXPORT_SYMBOL_GPL(vb2_fop_release); |
2663 | 2723 | ||
2664 | ssize_t vb2_fop_write(struct file *file, const char __user *buf, | 2724 | ssize_t vb2_fop_write(struct file *file, const char __user *buf, |
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 0d3a8ffe47a3..c779f210d2c6 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c | |||
@@ -40,6 +40,7 @@ struct vb2_dma_sg_buf { | |||
40 | unsigned int num_pages; | 40 | unsigned int num_pages; |
41 | atomic_t refcount; | 41 | atomic_t refcount; |
42 | struct vb2_vmarea_handler handler; | 42 | struct vb2_vmarea_handler handler; |
43 | struct vm_area_struct *vma; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | static void vb2_dma_sg_put(void *buf_priv); | 46 | static void vb2_dma_sg_put(void *buf_priv); |
@@ -155,12 +156,18 @@ static void vb2_dma_sg_put(void *buf_priv) | |||
155 | } | 156 | } |
156 | } | 157 | } |
157 | 158 | ||
159 | static inline int vma_is_io(struct vm_area_struct *vma) | ||
160 | { | ||
161 | return !!(vma->vm_flags & (VM_IO | VM_PFNMAP)); | ||
162 | } | ||
163 | |||
158 | static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, | 164 | static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, |
159 | unsigned long size, int write) | 165 | unsigned long size, int write) |
160 | { | 166 | { |
161 | struct vb2_dma_sg_buf *buf; | 167 | struct vb2_dma_sg_buf *buf; |
162 | unsigned long first, last; | 168 | unsigned long first, last; |
163 | int num_pages_from_user; | 169 | int num_pages_from_user; |
170 | struct vm_area_struct *vma; | ||
164 | 171 | ||
165 | buf = kzalloc(sizeof *buf, GFP_KERNEL); | 172 | buf = kzalloc(sizeof *buf, GFP_KERNEL); |
166 | if (!buf) | 173 | if (!buf) |
@@ -180,7 +187,38 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, | |||
180 | if (!buf->pages) | 187 | if (!buf->pages) |
181 | goto userptr_fail_alloc_pages; | 188 | goto userptr_fail_alloc_pages; |
182 | 189 | ||
183 | num_pages_from_user = get_user_pages(current, current->mm, | 190 | vma = find_vma(current->mm, vaddr); |
191 | if (!vma) { | ||
192 | dprintk(1, "no vma for address %lu\n", vaddr); | ||
193 | goto userptr_fail_find_vma; | ||
194 | } | ||
195 | |||
196 | if (vma->vm_end < vaddr + size) { | ||
197 | dprintk(1, "vma at %lu is too small for %lu bytes\n", | ||
198 | vaddr, size); | ||
199 | goto userptr_fail_find_vma; | ||
200 | } | ||
201 | |||
202 | buf->vma = vb2_get_vma(vma); | ||
203 | if (!buf->vma) { | ||
204 | dprintk(1, "failed to copy vma\n"); | ||
205 | goto userptr_fail_find_vma; | ||
206 | } | ||
207 | |||
208 | if (vma_is_io(buf->vma)) { | ||
209 | for (num_pages_from_user = 0; | ||
210 | num_pages_from_user < buf->num_pages; | ||
211 | ++num_pages_from_user, vaddr += PAGE_SIZE) { | ||
212 | unsigned long pfn; | ||
213 | |||
214 | if (follow_pfn(buf->vma, vaddr, &pfn)) { | ||
215 | dprintk(1, "no page for address %lu\n", vaddr); | ||
216 | break; | ||
217 | } | ||
218 | buf->pages[num_pages_from_user] = pfn_to_page(pfn); | ||
219 | } | ||
220 | } else | ||
221 | num_pages_from_user = get_user_pages(current, current->mm, | ||
184 | vaddr & PAGE_MASK, | 222 | vaddr & PAGE_MASK, |
185 | buf->num_pages, | 223 | buf->num_pages, |
186 | write, | 224 | write, |
@@ -200,9 +238,12 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, | |||
200 | userptr_fail_alloc_table_from_pages: | 238 | userptr_fail_alloc_table_from_pages: |
201 | userptr_fail_get_user_pages: | 239 | userptr_fail_get_user_pages: |
202 | dprintk(1, "get_user_pages requested/got: %d/%d]\n", | 240 | dprintk(1, "get_user_pages requested/got: %d/%d]\n", |
203 | num_pages_from_user, buf->num_pages); | 241 | buf->num_pages, num_pages_from_user); |
204 | while (--num_pages_from_user >= 0) | 242 | if (!vma_is_io(buf->vma)) |
205 | put_page(buf->pages[num_pages_from_user]); | 243 | while (--num_pages_from_user >= 0) |
244 | put_page(buf->pages[num_pages_from_user]); | ||
245 | vb2_put_vma(buf->vma); | ||
246 | userptr_fail_find_vma: | ||
206 | kfree(buf->pages); | 247 | kfree(buf->pages); |
207 | userptr_fail_alloc_pages: | 248 | userptr_fail_alloc_pages: |
208 | kfree(buf); | 249 | kfree(buf); |
@@ -226,9 +267,11 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) | |||
226 | while (--i >= 0) { | 267 | while (--i >= 0) { |
227 | if (buf->write) | 268 | if (buf->write) |
228 | set_page_dirty_lock(buf->pages[i]); | 269 | set_page_dirty_lock(buf->pages[i]); |
229 | put_page(buf->pages[i]); | 270 | if (!vma_is_io(buf->vma)) |
271 | put_page(buf->pages[i]); | ||
230 | } | 272 | } |
231 | kfree(buf->pages); | 273 | kfree(buf->pages); |
274 | vb2_put_vma(buf->vma); | ||
232 | kfree(buf); | 275 | kfree(buf); |
233 | } | 276 | } |
234 | 277 | ||